summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRhys Weatherley <rhys.weatherley@nokia.com>2009-07-23 03:53:06 (GMT)
committerRhys Weatherley <rhys.weatherley@nokia.com>2009-07-23 03:53:06 (GMT)
commit787f2252077434581101df64d0f0d576c26b7ce8 (patch)
treee0ff51ac86c3df457648f6857c4e8a54566140c2 /src
parente0c84298b2d4ed0b8b564dd491e5687296b75ebc (diff)
downloadQt-787f2252077434581101df64d0f0d576c26b7ce8.zip
Qt-787f2252077434581101df64d0f0d576c26b7ce8.tar.gz
Qt-787f2252077434581101df64d0f0d576c26b7ce8.tar.bz2
Add QPixmapBlurFilter for non-convolution blur effects.
Reviewed-by: trustme
Diffstat (limited to 'src')
-rw-r--r--src/gui/graphicsview/qgraphicseffect.cpp28
-rw-r--r--src/gui/image/qpixmapfilter.cpp235
-rw-r--r--src/gui/image/qpixmapfilter_p.h28
3 files changed, 276 insertions, 15 deletions
diff --git a/src/gui/graphicsview/qgraphicseffect.cpp b/src/gui/graphicsview/qgraphicseffect.cpp
index a1519c4..6b1f12a 100644
--- a/src/gui/graphicsview/qgraphicseffect.cpp
+++ b/src/gui/graphicsview/qgraphicseffect.cpp
@@ -346,9 +346,15 @@ class QGraphicsBlurEffectPrivate : public QGraphicsEffectPrivate
Q_DECLARE_PUBLIC(QGraphicsBlurEffect)
public:
QGraphicsBlurEffectPrivate()
- : blurRadius(4) { }
+ {
+ filter = new QPixmapBlurFilter;
+ }
+ ~QGraphicsBlurEffectPrivate()
+ {
+ delete filter;
+ }
- int blurRadius;
+ QPixmapBlurFilter *filter;
};
QGraphicsBlurEffect::QGraphicsBlurEffect(QObject *parent)
@@ -428,22 +434,19 @@ static QImage blurred(const QImage& image, const QRect& rect, int radius)
int QGraphicsBlurEffect::blurRadius() const
{
Q_D(const QGraphicsBlurEffect);
- return d->blurRadius;
+ return int(d->filter->blurRadius());
}
void QGraphicsBlurEffect::setBlurRadius(int radius)
{
Q_D(QGraphicsBlurEffect);
- d->blurRadius = radius;
+ d->filter->setBlurRadius(radius);
}
QRectF QGraphicsBlurEffect::boundingRectFor(const QGraphicsItem *item)
{
Q_D(const QGraphicsBlurEffect);
- qreal delta = d->blurRadius * 3;
- QRectF blurRect = item->boundingRect();
- blurRect.adjust(-delta, -delta, delta, delta);
- return blurRect;
+ return d->filter->boundingRectFor(item->boundingRect());
}
void QGraphicsBlurEffect::drawItem(QGraphicsItem *item, QPainter *painter,
@@ -461,15 +464,10 @@ void QGraphicsBlurEffect::drawItem(QGraphicsItem *item, QPainter *painter,
if (!pixmap)
return;
- // blur routine
- int radius = d->blurRadius;
- QImage img = pixmap->toImage().convertToFormat(QImage::Format_ARGB32_Premultiplied);
- img = blurred(img, img.rect(), radius);
-
- // Draw using an untransformed painter.
+ // Draw the pixmap with the filter using an untransformed painter.
QTransform restoreTransform = painter->worldTransform();
painter->setWorldTransform(QTransform());
- painter->drawImage(deviceRect.topLeft() - QPointF(radius * 3, radius * 3), img);
+ d->filter->draw(painter, deviceRect.topLeft(), *pixmap, pixmap->rect());
painter->setWorldTransform(restoreTransform);
}
diff --git a/src/gui/image/qpixmapfilter.cpp b/src/gui/image/qpixmapfilter.cpp
index 184bd65..2b275a3 100644
--- a/src/gui/image/qpixmapfilter.cpp
+++ b/src/gui/image/qpixmapfilter.cpp
@@ -93,6 +93,9 @@ public:
\value DropShadowFilter A filter that is used to add a drop shadow to an
image. See QPixmapDropShadowFilter for more
information.
+ \value BlurFilter A filter that is used to blur an image using
+ a simple blur radius. See QPixmapBlurFilter
+ for more information.
\value UserFilter The first filter type that can be used for
application-specific purposes.
@@ -837,4 +840,236 @@ void QPixmapDropShadowFilter::draw(QPainter *p,
// Draw the actual pixmap...
p->drawPixmap(pos, px, src);
}
+
+/*!
+ \class QPixmapBlurFilter
+ \since 4.6
+ \ingroup multimedia
+
+ \brief The QPixmapBlurFilter class is a convenience class
+ for drawing pixmaps with blur effects.
+
+ By default, the blur effect is produced by applying an exponential
+ filter generated from the specified blurRadius(). Paint engines
+ may override this with a custom blur that is faster on the
+ underlying hardware.
+
+ \sa QPixmapConvolutionFilter
+
+ \internal
+ */
+
+class QPixmapBlurFilterPrivate : public QPixmapFilterPrivate
+{
+public:
+ QPixmapBlurFilterPrivate()
+ : quality(QPixmapBlurFilter::High), radius(1) {}
+
+ QPixmapBlurFilter::BlurQuality quality;
+ qreal radius;
+};
+
+/*!
+ Constructs blur filter and attaches it to \a parent.
+
+ \internal
+*/
+QPixmapBlurFilter::QPixmapBlurFilter(QObject *parent)
+ : QPixmapFilter(*new QPixmapBlurFilterPrivate, BlurFilter, parent)
+{
+ Q_D(QPixmapBlurFilter);
+ setBlurRadius(4);
+}
+
+/*!
+ Destroys blur filter.
+
+ \internal
+*/
+QPixmapBlurFilter::~QPixmapBlurFilter()
+{
+}
+
+/*!
+ \enum QPixmapFilter::BlurQuality
+ \since 4.6
+ \ingroup multimedia
+ This enum describes the quality of blur to apply to pixmaps.
+
+ \value Fast Blur faster, potentially losing some quality.
+ \value High Produce the best high-quality blur possible, even if slower.
+
+ \internal
+*/
+
+/*!
+ Returns the quality of the blur. The default value is High.
+
+ \sa blurRadius()
+ \internal
+*/
+QPixmapBlurFilter::BlurQuality QPixmapBlurFilter::blurQuality() const
+{
+ Q_D(const QPixmapBlurFilter);
+ return d->quality;
+}
+
+/*!
+ Sets the quality of the blur to the \a blurQuality specified.
+
+ Setting the quality to Faster causes the implementation to trade
+ off visual quality to blur the image faster. Setting the quality
+ to High causes the implementation to improve visual quality
+ at the expense of speed. The implementation is free to ignore
+ this value if it only has a single blur algorithm.
+
+ \sa setBlurRadius()
+ \internal
+*/
+void QPixmapBlurFilter::setBlurQuality(BlurQuality blurQuality)
+{
+ Q_D(QPixmapBlurFilter);
+ d->quality = blurQuality;
+}
+
+/*!
+ Returns the radius in pixels of the blur. The default value is 4.
+
+ A smaller radius results in a sharper image.
+
+ \sa blurQuality()
+ \internal
+*/
+qreal QPixmapBlurFilter::blurRadius() const
+{
+ Q_D(const QPixmapBlurFilter);
+ return d->radius;
+}
+
+/*!
+ Sets the radius in pixels of the blur to the \a radius specified.
+
+ Using a smaller radius results in a sharper image.
+
+ \sa setBlurQuality()
+ \internal
+*/
+void QPixmapBlurFilter::setBlurRadius(qreal blurRadius)
+{
+ Q_D(QPixmapBlurFilter);
+ d->radius = blurRadius;
+}
+
+/*!
+ \internal
+ */
+QRectF QPixmapBlurFilter::boundingRectFor(const QRectF &rect) const
+{
+ Q_D(const QPixmapBlurFilter);
+ qreal delta = d->radius * 3;
+ QRectF blurRect(rect);
+ blurRect.adjust(-delta, -delta, delta, delta);
+ return blurRect;
+}
+
+// Blur the image according to the blur radius
+// Based on exponential blur algorithm by Jani Huhtanen
+// (maximum radius is set to 16)
+static QImage blurred(const QImage& image, const QRect& rect, int radius)
+{
+ int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 };
+ int alpha = (radius < 1) ? 16 : (radius > 17) ? 1 : tab[radius-1];
+
+ QImage result = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
+ int r1 = rect.top();
+ int r2 = rect.bottom();
+ int c1 = rect.left();
+ int c2 = rect.right();
+
+ int bpl = result.bytesPerLine();
+ int rgba[4];
+ unsigned char* p;
+
+ for (int col = c1; col <= c2; col++) {
+ p = result.scanLine(r1) + col * 4;
+ for (int i = 0; i < 4; i++)
+ rgba[i] = p[i] << 4;
+
+ p += bpl;
+ for (int j = r1; j < r2; j++, p += bpl)
+ for (int i = 0; i < 4; i++)
+ p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
+ }
+
+ for (int row = r1; row <= r2; row++) {
+ p = result.scanLine(row) + c1 * 4;
+ for (int i = 0; i < 4; i++)
+ rgba[i] = p[i] << 4;
+
+ p += 4;
+ for (int j = c1; j < c2; j++, p += 4)
+ for (int i = 0; i < 4; i++)
+ p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
+ }
+
+ for (int col = c1; col <= c2; col++) {
+ p = result.scanLine(r2) + col * 4;
+ for (int i = 0; i < 4; i++)
+ rgba[i] = p[i] << 4;
+
+ p -= bpl;
+ for (int j = r1; j < r2; j++, p -= bpl)
+ for (int i = 0; i < 4; i++)
+ p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
+ }
+
+ for (int row = r1; row <= r2; row++) {
+ p = result.scanLine(row) + c2 * 4;
+ for (int i = 0; i < 4; i++)
+ rgba[i] = p[i] << 4;
+
+ p -= 4;
+ for (int j = c1; j < c2; j++, p -= 4)
+ for (int i = 0; i < 4; i++)
+ p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
+ }
+
+ return result;
+}
+
+/*!
+ \internal
+ */
+void QPixmapBlurFilter::draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const
+{
+ Q_D(const QPixmapBlurFilter);
+
+ QPixmapFilter *filter = painter->paintEngine() && painter->paintEngine()->isExtended() ?
+ static_cast<QPaintEngineEx *>(painter->paintEngine())->createPixmapFilter(type()) : 0;
+ QPixmapBlurFilter *blurFilter = static_cast<QPixmapBlurFilter*>(filter);
+ if (blurFilter) {
+ blurFilter->setBlurQuality(d->quality);
+ blurFilter->setBlurRadius(d->radius);
+ blurFilter->draw(painter, dest, src, srcRect);
+ delete blurFilter;
+ return;
+ }
+
+ QImage srcImage;
+ QImage destImage;
+
+ if (srcRect.isNull()) {
+ srcImage = src.toImage();
+ destImage = blurred(srcImage, srcImage.rect(), int(d->radius + 0.5));
+ } else {
+ QRect rect = srcRect.toAlignedRect().intersected(src.rect());
+
+ srcImage = src.copy(rect).toImage();
+ destImage = blurred(srcImage, srcImage.rect(), int(d->radius + 0.5));
+ }
+
+ qreal delta = d->radius * 3;
+ painter->drawImage(dest - QPointF(delta, delta), destImage);
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/image/qpixmapfilter_p.h b/src/gui/image/qpixmapfilter_p.h
index 51292b3..ca27cbf 100644
--- a/src/gui/image/qpixmapfilter_p.h
+++ b/src/gui/image/qpixmapfilter_p.h
@@ -78,6 +78,7 @@ public:
ConvolutionFilter,
ColorizeFilter,
DropShadowFilter,
+ BlurFilter,
UserFilter = 1024
};
@@ -158,6 +159,33 @@ public:
inline void setOffset(qreal dx, qreal dy) { setOffset(QPointF(dx, dy)); }
};
+class QPixmapBlurFilterPrivate;
+
+class Q_GUI_EXPORT QPixmapBlurFilter : public QPixmapFilter
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QPixmapBlurFilter)
+
+public:
+ QPixmapBlurFilter(QObject *parent = 0);
+ ~QPixmapBlurFilter();
+
+ enum BlurQuality
+ {
+ Fast,
+ High
+ };
+
+ BlurQuality blurQuality() const;
+ void setBlurQuality(BlurQuality blurQuality);
+
+ qreal blurRadius() const;
+ void setBlurRadius(qreal blurRadius);
+
+ QRectF boundingRectFor(const QRectF &rect) const;
+ void draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect = QRectF()) const;
+};
+
QT_END_NAMESPACE
QT_END_HEADER