diff options
author | Rhys Weatherley <rhys.weatherley@nokia.com> | 2009-07-23 03:53:06 (GMT) |
---|---|---|
committer | Rhys Weatherley <rhys.weatherley@nokia.com> | 2009-07-23 03:53:06 (GMT) |
commit | 787f2252077434581101df64d0f0d576c26b7ce8 (patch) | |
tree | e0ff51ac86c3df457648f6857c4e8a54566140c2 /src/gui/image | |
parent | e0c84298b2d4ed0b8b564dd491e5687296b75ebc (diff) | |
download | Qt-787f2252077434581101df64d0f0d576c26b7ce8.zip Qt-787f2252077434581101df64d0f0d576c26b7ce8.tar.gz Qt-787f2252077434581101df64d0f0d576c26b7ce8.tar.bz2 |
Add QPixmapBlurFilter for non-convolution blur effects.
Reviewed-by: trustme
Diffstat (limited to 'src/gui/image')
-rw-r--r-- | src/gui/image/qpixmapfilter.cpp | 235 | ||||
-rw-r--r-- | src/gui/image/qpixmapfilter_p.h | 28 |
2 files changed, 263 insertions, 0 deletions
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 |