1
/****************************************************************************
3
** Copyright (C) 2016 The Qt Company Ltd.
4
** Contact: https://www.qt.io/licensing/
6
** This file is part of the QtWidgets module of the Qt Toolkit.
8
** $QT_BEGIN_LICENSE:LGPL$
9
** Commercial License Usage
10
** Licensees holding valid commercial Qt licenses may use this file in
11
** accordance with the commercial license agreement provided with the
12
** Software or, alternatively, in accordance with the terms contained in
13
** a written agreement between you and The Qt Company. For licensing terms
14
** and conditions see https://www.qt.io/terms-conditions. For further
15
** information use the contact form at https://www.qt.io/contact-us.
17
** GNU Lesser General Public License Usage
18
** Alternatively, this file may be used under the terms of the GNU Lesser
19
** General Public License version 3 as published by the Free Software
20
** Foundation and appearing in the file LICENSE.LGPL3 included in the
21
** packaging of this file. Please review the following information to
22
** ensure the GNU Lesser General Public License version 3 requirements
23
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25
** GNU General Public License Usage
26
** Alternatively, this file may be used under the terms of the GNU
27
** General Public License version 2.0 or (at your option) the GNU General
28
** Public license version 3 or any later version approved by the KDE Free
29
** Qt Foundation. The licenses are as published by the Free Software
30
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31
** included in the packaging of this file. Please review the following
32
** information to ensure the GNU General Public License requirements will
33
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34
** https://www.gnu.org/licenses/gpl-3.0.html.
38
****************************************************************************/
46
#include "qpixmapfilter_p.h"
47
#include "qvarlengtharray.h"
49
#include "private/qguiapplication_p.h"
50
#include "private/qpaintengineex_p.h"
51
#include "private/qpaintengine_raster_p.h"
53
#include "private/qmath_p.h"
54
#include "private/qmemrotate_p.h"
55
#include "private/qdrawhelper_p.h"
57
#ifndef QT_NO_GRAPHICSEFFECT
60
class QPixmapFilterPrivate : public QObjectPrivate
62
Q_DECLARE_PUBLIC(QPixmapFilter)
64
QPixmapFilter::FilterType type;
72
\brief The QPixmapFilter class provides the basic functionality for
73
pixmap filter classes. Pixmap filter can be for example colorize or blur.
75
QPixmapFilter is the base class for every pixmap filter. QPixmapFilter is
76
an abstract class and cannot itself be instantiated. It provides a standard
77
interface for filter processing.
83
\enum QPixmapFilter::FilterType
87
This enum describes the types of filter that can be applied to pixmaps.
89
\value ConvolutionFilter A filter that is used to calculate the convolution
90
of the image with a kernel. See
91
QPixmapConvolutionFilter for more information.
92
\value ColorizeFilter A filter that is used to change the overall color
93
of an image. See QPixmapColorizeFilter for more
95
\value DropShadowFilter A filter that is used to add a drop shadow to an
96
image. See QPixmapDropShadowFilter for more
98
\value BlurFilter A filter that is used to blur an image using
99
a simple blur radius. See QPixmapBlurFilter
100
for more information.
102
\value UserFilter The first filter type that can be used for
103
application-specific purposes.
108
Constructs a default QPixmapFilter with the given \a type.
110
This constructor should be used when subclassing QPixmapFilter to
111
create custom user filters.
115
QPixmapFilter::QPixmapFilter(FilterType type, QObject *parent)
116
: QObject(*new QPixmapFilterPrivate, parent)
118
d_func()->type = type;
126
QPixmapFilter::QPixmapFilter(QPixmapFilterPrivate&d, QPixmapFilter::FilterType type, QObject *parent)
129
d_func()->type = type;
134
Destroys the pixmap filter.
138
QPixmapFilter::~QPixmapFilter()
143
Returns the type of the filter. All standard pixmap filter classes
144
are associated with a unique value.
148
QPixmapFilter::FilterType QPixmapFilter::type() const
150
Q_D(const QPixmapFilter);
155
Returns the bounding rectangle that is affected by the pixmap
156
filter if the filter is applied to the specified \a rect.
160
QRectF QPixmapFilter::boundingRectFor(const QRectF &rect) const
166
\fn void QPixmapFilter::draw(QPainter *painter, const QPointF &p, const QPixmap &src, const QRectF& srcRect) const
168
Uses \a painter to draw filtered result of \a src at the point
169
specified by \a p. If \a srcRect is specified the it will
170
be used as a source rectangle to only draw a part of the source.
172
draw() will affect the area which boundingRectFor() returns.
178
\class QPixmapConvolutionFilter
182
\brief The QPixmapConvolutionFilter class provides convolution
183
filtering for pixmaps.
185
QPixmapConvolutionFilter implements a convolution pixmap filter,
186
which is applied when \l{QPixmapFilter::}{draw()} is called. A
187
convolution filter lets you distort an image by setting the values
188
of a matrix of qreal values called its
189
\l{setConvolutionKernel()}{kernel}. The matrix's values are
190
usually between -1.0 and 1.0.
193
In convolution filtering, the pixel value is calculated from the
194
neighboring pixels based on the weighting convolution kernel.
195
This needs explaining to be useful.
199
\snippet code/src_gui_image_qpixmapfilter.cpp 1
201
\sa {Pixmap Filters Example}, QPixmapColorizeFilter, QPixmapDropShadowFilter
207
class QPixmapConvolutionFilterPrivate : public QPixmapFilterPrivate
210
QPixmapConvolutionFilterPrivate(): convolutionKernel(0), kernelWidth(0), kernelHeight(0), convoluteAlpha(false) {}
211
~QPixmapConvolutionFilterPrivate() {
212
delete[] convolutionKernel;
215
qreal *convolutionKernel;
223
Constructs a pixmap convolution filter.
225
By default there is no convolution kernel.
229
QPixmapConvolutionFilter::QPixmapConvolutionFilter(QObject *parent)
230
: QPixmapFilter(*new QPixmapConvolutionFilterPrivate, ConvolutionFilter, parent)
232
Q_D(QPixmapConvolutionFilter);
233
d->convoluteAlpha = true;
237
Destructor of pixmap convolution filter.
241
QPixmapConvolutionFilter::~QPixmapConvolutionFilter()
246
Sets convolution kernel with the given number of \a rows and \a columns.
247
Values from \a kernel are copied to internal data structure.
249
To preserve the intensity of the pixmap, the sum of all the
250
values in the convolution kernel should add up to 1.0. A sum
251
greater than 1.0 produces a lighter result and a sum less than 1.0
252
produces a darker and transparent result.
256
void QPixmapConvolutionFilter::setConvolutionKernel(const qreal *kernel, int rows, int columns)
258
Q_D(QPixmapConvolutionFilter);
259
delete [] d->convolutionKernel;
260
d->convolutionKernel = new qreal[rows * columns];
261
memcpy(d->convolutionKernel, kernel, sizeof(qreal) * rows * columns);
262
d->kernelWidth = columns;
263
d->kernelHeight = rows;
267
Gets the convolution kernel data.
271
const qreal *QPixmapConvolutionFilter::convolutionKernel() const
273
Q_D(const QPixmapConvolutionFilter);
274
return d->convolutionKernel;
278
Gets the number of rows in the convolution kernel.
282
int QPixmapConvolutionFilter::rows() const
284
Q_D(const QPixmapConvolutionFilter);
285
return d->kernelHeight;
289
Gets the number of columns in the convolution kernel.
293
int QPixmapConvolutionFilter::columns() const
295
Q_D(const QPixmapConvolutionFilter);
296
return d->kernelWidth;
303
QRectF QPixmapConvolutionFilter::boundingRectFor(const QRectF &rect) const
305
Q_D(const QPixmapConvolutionFilter);
306
return rect.adjusted(-d->kernelWidth / 2, -d->kernelHeight / 2, (d->kernelWidth - 1) / 2, (d->kernelHeight - 1) / 2);
309
// Convolutes the image
310
static void convolute(
313
const QImage &srcImage,
314
const QRectF &srcRect,
315
QPainter::CompositionMode mode,
320
const QImage processImage = (srcImage.format() != QImage::Format_ARGB32_Premultiplied ) ? srcImage.convertToFormat(QImage::Format_ARGB32_Premultiplied) : srcImage;
321
// TODO: support also other formats directly without copying
323
int *fixedKernel = new int[kernelWidth*kernelHeight];
324
for(int i = 0; i < kernelWidth*kernelHeight; i++)
326
fixedKernel[i] = (int)(65536 * kernel[i]);
328
QRectF trect = srcRect.isNull() ? processImage.rect() : srcRect;
330
QRectF bounded = trect.adjusted(-kernelWidth / 2, -kernelHeight / 2, (kernelWidth - 1) / 2, (kernelHeight - 1) / 2);
331
QRect rect = bounded.toAlignedRect();
332
QRect targetRect = rect.intersected(destImage->rect());
334
QRectF srect = srcRect.isNull() ? processImage.rect() : srcRect;
335
QRectF sbounded = srect.adjusted(-kernelWidth / 2, -kernelHeight / 2, (kernelWidth - 1) / 2, (kernelHeight - 1) / 2);
336
QPoint srcStartPoint = sbounded.toAlignedRect().topLeft()+(targetRect.topLeft()-rect.topLeft());
338
const uint *sourceStart = (const uint*)processImage.scanLine(0);
339
uint *outputStart = (uint*)destImage->scanLine(0);
341
int yk = srcStartPoint.y();
342
for (int y = targetRect.top(); y <= targetRect.bottom(); y++) {
343
uint* output = outputStart + (destImage->bytesPerLine()/sizeof(uint))*y+targetRect.left();
344
int xk = srcStartPoint.x();
345
for(int x = targetRect.left(); x <= targetRect.right(); x++) {
351
// some out of bounds pre-checking to avoid inner-loop ifs
352
int kernely = -kernelHeight/2;
354
int endy = kernelHeight;
355
if(yk+kernely+endy >= srcImage.height())
356
endy = kernelHeight-((yk+kernely+endy)-srcImage.height())-1;
358
starty = -(yk+kernely);
360
int kernelx = -kernelWidth/2;
362
int endx = kernelWidth;
363
if(xk+kernelx+endx >= srcImage.width())
364
endx = kernelWidth-((xk+kernelx+endx)-srcImage.width())-1;
366
startx = -(xk+kernelx);
368
for (int ys = starty; ys < endy; ys ++) {
369
const uint *pix = sourceStart + (processImage.bytesPerLine()/sizeof(uint))*(yk+kernely+ys) + ((xk+kernelx+startx));
370
const uint *endPix = pix+endx-startx;
371
int kernelPos = ys*kernelWidth+startx;
372
while (pix < endPix) {
373
int factor = fixedKernel[kernelPos++];
374
a += (((*pix) & 0xff000000)>>24) * factor;
375
r += (((*pix) & 0x00ff0000)>>16) * factor;
376
g += (((*pix) & 0x0000ff00)>>8 ) * factor;
377
b += (((*pix) & 0x000000ff) ) * factor;
382
r = qBound((int)0, r >> 16, (int)255);
383
g = qBound((int)0, g >> 16, (int)255);
384
b = qBound((int)0, b >> 16, (int)255);
385
a = qBound((int)0, a >> 16, (int)255);
386
// composition mode checking could be moved outside of loop
387
if(mode == QPainter::CompositionMode_Source) {
388
uint color = (a<<24)+(r<<16)+(g<<8)+b;
391
uint current = *output;
392
uchar ca = (current&0xff000000)>>24;
393
uchar cr = (current&0x00ff0000)>>16;
394
uchar cg = (current&0x0000ff00)>>8;
395
uchar cb = (current&0x000000ff);
397
(((ca*(255-a) >> 8)+a) << 24)+
398
(((cr*(255-a) >> 8)+r) << 16)+
399
(((cg*(255-a) >> 8)+g) << 8)+
400
(((cb*(255-a) >> 8)+b));
407
delete[] fixedKernel;
413
void QPixmapConvolutionFilter::draw(QPainter *painter, const QPointF &p, const QPixmap &src, const QRectF& srcRect) const
415
Q_D(const QPixmapConvolutionFilter);
416
if (!painter->isActive())
419
if(d->kernelWidth<=0 || d->kernelHeight <= 0)
425
// raster implementation
428
if (painter->paintEngine()->paintDevice()->devType() == QInternal::Image) {
429
target = static_cast<QImage *>(painter->paintEngine()->paintDevice());
431
QTransform mat = painter->combinedTransform();
433
if (mat.type() > QTransform::TxTranslate) {
434
// Disabled because of transformation...
437
QRasterPaintEngine *pe = static_cast<QRasterPaintEngine *>(painter->paintEngine());
438
if (pe->clipType() == QRasterPaintEngine::ComplexClip)
439
// disabled because of complex clipping...
442
QRectF clip = pe->clipBoundingRect();
443
QRectF rect = boundingRectFor(srcRect.isEmpty() ? src.rect() : srcRect);
444
QTransform x = painter->deviceTransform();
445
if (!clip.contains(rect.translated(x.dx() + p.x(), x.dy() + p.y()))) {
454
QTransform x = painter->deviceTransform();
455
QPointF offset(x.dx(), x.dy());
457
convolute(target, p+offset, src.toImage(), srcRect, QPainter::CompositionMode_SourceOver, d->convolutionKernel, d->kernelWidth, d->kernelHeight);
459
QRect srect = srcRect.isNull() ? src.rect() : srcRect.toRect();
460
QRect rect = boundingRectFor(srect).toRect();
461
QImage result = QImage(rect.size(), QImage::Format_ARGB32_Premultiplied);
462
QPoint offset = srect.topLeft() - rect.topLeft();
467
QPainter::CompositionMode_Source,
468
d->convolutionKernel,
471
painter->drawImage(p - offset, result);
476
\class QPixmapBlurFilter
480
\brief The QPixmapBlurFilter class provides blur filtering
483
QPixmapBlurFilter implements a blur pixmap filter,
484
which is applied when \l{QPixmapFilter::}{draw()} is called.
486
The filter lets you specialize the radius of the blur as well
487
as hints as to whether to prefer performance or quality.
489
By default, the blur effect is produced by applying an exponential
490
filter generated from the specified blurRadius(). Paint engines
491
may override this with a custom blur that is faster on the
494
\sa {Pixmap Filters Example}, QPixmapConvolutionFilter, QPixmapDropShadowFilter
499
class QPixmapBlurFilterPrivate : public QPixmapFilterPrivate
502
QPixmapBlurFilterPrivate() : radius(5), hints(QGraphicsBlurEffect::PerformanceHint) {}
505
QGraphicsBlurEffect::BlurHints hints;
510
Constructs a pixmap blur filter.
514
QPixmapBlurFilter::QPixmapBlurFilter(QObject *parent)
515
: QPixmapFilter(*new QPixmapBlurFilterPrivate, BlurFilter, parent)
520
Destructor of pixmap blur filter.
524
QPixmapBlurFilter::~QPixmapBlurFilter()
529
Sets the radius of the blur filter. Higher radius produces increased blurriness.
533
void QPixmapBlurFilter::setRadius(qreal radius)
535
Q_D(QPixmapBlurFilter);
540
Gets the radius of the blur filter.
544
qreal QPixmapBlurFilter::radius() const
546
Q_D(const QPixmapBlurFilter);
551
Setting the blur hints to PerformanceHint causes the implementation
552
to trade off visual quality to blur the image faster. Setting the
553
blur hints to QualityHint causes the implementation to improve
554
visual quality at the expense of speed.
556
AnimationHint causes the implementation to optimize for animating
557
the blur radius, possibly by caching blurred versions of the source
560
The implementation is free to ignore this value if it only has a single
565
void QPixmapBlurFilter::setBlurHints(QGraphicsBlurEffect::BlurHints hints)
567
Q_D(QPixmapBlurFilter);
572
Gets the blur hints of the blur filter.
576
QGraphicsBlurEffect::BlurHints QPixmapBlurFilter::blurHints() const
578
Q_D(const QPixmapBlurFilter);
582
const qreal radiusScale = qreal(2.5);
587
QRectF QPixmapBlurFilter::boundingRectFor(const QRectF &rect) const
589
Q_D(const QPixmapBlurFilter);
590
const qreal delta = radiusScale * d->radius + 1;
591
return rect.adjusted(-delta, -delta, delta, delta);
595
inline int qt_static_shift(int value)
600
return value << (uint(shift) & 0x1f);
602
return value >> (uint(-shift) & 0x1f);
605
template<int aprec, int zprec>
606
inline void qt_blurinner(uchar *bptr, int &zR, int &zG, int &zB, int &zA, int alpha)
608
QRgb *pixel = (QRgb *)bptr;
610
#define Z_MASK (0xff << zprec)
611
const int A_zprec = qt_static_shift<zprec - 24>(*pixel) & Z_MASK;
612
const int R_zprec = qt_static_shift<zprec - 16>(*pixel) & Z_MASK;
613
const int G_zprec = qt_static_shift<zprec - 8>(*pixel) & Z_MASK;
614
const int B_zprec = qt_static_shift<zprec>(*pixel) & Z_MASK;
617
const int zR_zprec = zR >> aprec;
618
const int zG_zprec = zG >> aprec;
619
const int zB_zprec = zB >> aprec;
620
const int zA_zprec = zA >> aprec;
622
zR += alpha * (R_zprec - zR_zprec);
623
zG += alpha * (G_zprec - zG_zprec);
624
zB += alpha * (B_zprec - zB_zprec);
625
zA += alpha * (A_zprec - zA_zprec);
627
#define ZA_MASK (0xff << (zprec + aprec))
629
qt_static_shift<24 - zprec - aprec>(zA & ZA_MASK)
630
| qt_static_shift<16 - zprec - aprec>(zR & ZA_MASK)
631
| qt_static_shift<8 - zprec - aprec>(zG & ZA_MASK)
632
| qt_static_shift<-zprec - aprec>(zB & ZA_MASK);
636
const int alphaIndex = (QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3);
638
template<int aprec, int zprec>
639
inline void qt_blurinner_alphaOnly(uchar *bptr, int &z, int alpha)
641
const int A_zprec = int(*(bptr)) << zprec;
642
const int z_zprec = z >> aprec;
643
z += alpha * (A_zprec - z_zprec);
644
*(bptr) = z >> (zprec + aprec);
647
template<int aprec, int zprec, bool alphaOnly>
648
inline void qt_blurrow(QImage & im, int line, int alpha)
650
uchar *bptr = im.scanLine(line);
652
int zR = 0, zG = 0, zB = 0, zA = 0;
654
if (alphaOnly && im.format() != QImage::Format_Indexed8)
657
const int stride = im.depth() >> 3;
658
const int im_width = im.width();
659
for (int index = 0; index < im_width; ++index) {
661
qt_blurinner_alphaOnly<aprec, zprec>(bptr, zA, alpha);
663
qt_blurinner<aprec, zprec>(bptr, zR, zG, zB, zA, alpha);
669
for (int index = im_width - 2; index >= 0; --index) {
672
qt_blurinner_alphaOnly<aprec, zprec>(bptr, zA, alpha);
674
qt_blurinner<aprec, zprec>(bptr, zR, zG, zB, zA, alpha);
679
* expblur(QImage &img, int radius)
681
* Based on exponential blur algorithm by Jani Huhtanen
683
* In-place blur of image 'img' with kernel
684
* of approximate radius 'radius'.
686
* Blurs with two sided exponential impulse
689
* aprec = precision of alpha parameter
690
* in fixed-point format 0.aprec
692
* zprec = precision of state parameters
693
* zR,zG,zB and zA in fp format 8.zprec
695
template <int aprec, int zprec, bool alphaOnly>
696
void expblur(QImage &img, qreal radius, bool improvedQuality = false, int transposed = 0)
698
// halve the radius if we're using two passes
700
radius *= qreal(0.5);
702
Q_ASSERT(img.format() == QImage::Format_ARGB32_Premultiplied
703
|| img.format() == QImage::Format_RGB32
704
|| img.format() == QImage::Format_Indexed8
705
|| img.format() == QImage::Format_Grayscale8);
707
// choose the alpha such that pixels at radius distance from a fully
708
// saturated pixel will have an alpha component of no greater than
709
// the cutOffIntensity
710
const qreal cutOffIntensity = 2;
711
int alpha = radius <= qreal(1e-5)
713
: qRound((1<<aprec)*(1 - qPow(cutOffIntensity * (1 / qreal(255)), 1 / radius)));
715
int img_height = img.height();
716
for (int row = 0; row < img_height; ++row) {
717
for (int i = 0; i <= int(improvedQuality); ++i)
718
qt_blurrow<aprec, zprec, alphaOnly>(img, row, alpha);
721
QImage temp(img.height(), img.width(), img.format());
722
if (transposed >= 0) {
723
if (img.depth() == 8) {
724
qt_memrotate270(reinterpret_cast<const quint8*>(img.bits()),
725
img.width(), img.height(), img.bytesPerLine(),
726
reinterpret_cast<quint8*>(temp.bits()),
727
temp.bytesPerLine());
729
qt_memrotate270(reinterpret_cast<const quint32*>(img.bits()),
730
img.width(), img.height(), img.bytesPerLine(),
731
reinterpret_cast<quint32*>(temp.bits()),
732
temp.bytesPerLine());
735
if (img.depth() == 8) {
736
qt_memrotate90(reinterpret_cast<const quint8*>(img.bits()),
737
img.width(), img.height(), img.bytesPerLine(),
738
reinterpret_cast<quint8*>(temp.bits()),
739
temp.bytesPerLine());
741
qt_memrotate90(reinterpret_cast<const quint32*>(img.bits()),
742
img.width(), img.height(), img.bytesPerLine(),
743
reinterpret_cast<quint32*>(temp.bits()),
744
temp.bytesPerLine());
748
img_height = temp.height();
749
for (int row = 0; row < img_height; ++row) {
750
for (int i = 0; i <= int(improvedQuality); ++i)
751
qt_blurrow<aprec, zprec, alphaOnly>(temp, row, alpha);
754
if (transposed == 0) {
755
if (img.depth() == 8) {
756
qt_memrotate90(reinterpret_cast<const quint8*>(temp.bits()),
757
temp.width(), temp.height(), temp.bytesPerLine(),
758
reinterpret_cast<quint8*>(img.bits()),
761
qt_memrotate90(reinterpret_cast<const quint32*>(temp.bits()),
762
temp.width(), temp.height(), temp.bytesPerLine(),
763
reinterpret_cast<quint32*>(img.bits()),
770
#define AVG(a,b) ( ((((a)^(b)) & 0xfefefefeUL) >> 1) + ((a)&(b)) )
771
#define AVG16(a,b) ( ((((a)^(b)) & 0xf7deUL) >> 1) + ((a)&(b)) )
773
Q_WIDGETS_EXPORT QImage qt_halfScaled(const QImage &source)
775
if (source.width() < 2 || source.height() < 2)
778
QImage srcImage = source;
780
if (source.format() == QImage::Format_Indexed8 || source.format() == QImage::Format_Grayscale8) {
782
QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
784
const uchar *src = reinterpret_cast<const uchar*>(const_cast<const QImage &>(srcImage).bits());
785
int sx = srcImage.bytesPerLine();
788
uchar *dst = reinterpret_cast<uchar*>(dest.bits());
789
int dx = dest.bytesPerLine();
790
int ww = dest.width();
791
int hh = dest.height();
793
for (int y = hh; y; --y, dst += dx, src += sx2) {
794
const uchar *p1 = src;
795
const uchar *p2 = src + sx;
797
for (int x = ww; x; --x, ++q, p1 += 2, p2 += 2)
798
*q = ((int(p1[0]) + int(p1[1]) + int(p2[0]) + int(p2[1])) + 2) >> 2;
802
} else if (source.format() == QImage::Format_ARGB8565_Premultiplied) {
803
QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
805
const uchar *src = reinterpret_cast<const uchar*>(const_cast<const QImage &>(srcImage).bits());
806
int sx = srcImage.bytesPerLine();
809
uchar *dst = reinterpret_cast<uchar*>(dest.bits());
810
int dx = dest.bytesPerLine();
811
int ww = dest.width();
812
int hh = dest.height();
814
for (int y = hh; y; --y, dst += dx, src += sx2) {
815
const uchar *p1 = src;
816
const uchar *p2 = src + sx;
818
for (int x = ww; x; --x, q += 3, p1 += 6, p2 += 6) {
820
q[0] = AVG(AVG(p1[0], p1[3]), AVG(p2[0], p2[3]));
822
const quint16 p16_1 = (p1[2] << 8) | p1[1];
823
const quint16 p16_2 = (p1[5] << 8) | p1[4];
824
const quint16 p16_3 = (p2[2] << 8) | p2[1];
825
const quint16 p16_4 = (p2[5] << 8) | p2[4];
826
const quint16 result = AVG16(AVG16(p16_1, p16_2), AVG16(p16_3, p16_4));
827
q[1] = result & 0xff;
833
} else if (source.format() != QImage::Format_ARGB32_Premultiplied
834
&& source.format() != QImage::Format_RGB32)
836
srcImage = source.convertToFormat(QImage::Format_ARGB32_Premultiplied);
839
QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
841
const quint32 *src = reinterpret_cast<const quint32*>(const_cast<const QImage &>(srcImage).bits());
842
int sx = srcImage.bytesPerLine() >> 2;
845
quint32 *dst = reinterpret_cast<quint32*>(dest.bits());
846
int dx = dest.bytesPerLine() >> 2;
847
int ww = dest.width();
848
int hh = dest.height();
850
for (int y = hh; y; --y, dst += dx, src += sx2) {
851
const quint32 *p1 = src;
852
const quint32 *p2 = src + sx;
854
for (int x = ww; x; --x, q++, p1 += 2, p2 += 2)
855
*q = AVG(AVG(p1[0], p1[1]), AVG(p2[0], p2[1]));
861
Q_WIDGETS_EXPORT void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius, bool quality, bool alphaOnly, int transposed = 0)
863
if (blurImage.format() != QImage::Format_ARGB32_Premultiplied
864
&& blurImage.format() != QImage::Format_RGB32)
866
blurImage = blurImage.convertToFormat(QImage::Format_ARGB32_Premultiplied);
870
if (radius >= 4 && blurImage.width() >= 2 && blurImage.height() >= 2) {
871
blurImage = qt_halfScaled(blurImage);
873
radius *= qreal(0.5);
877
expblur<12, 10, true>(blurImage, radius, quality, transposed);
879
expblur<12, 10, false>(blurImage, radius, quality, transposed);
882
p->scale(scale, scale);
883
p->setRenderHint(QPainter::SmoothPixmapTransform);
884
p->drawImage(QRect(0, 0, blurImage.width(), blurImage.height()), blurImage);
888
Q_WIDGETS_EXPORT void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed = 0)
890
if (blurImage.format() == QImage::Format_Indexed8 || blurImage.format() == QImage::Format_Grayscale8)
891
expblur<12, 10, true>(blurImage, radius, quality, transposed);
893
expblur<12, 10, false>(blurImage, radius, quality, transposed);
896
Q_GUI_EXPORT extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale);
901
void QPixmapBlurFilter::draw(QPainter *painter, const QPointF &p, const QPixmap &src, const QRectF &rect) const
903
Q_D(const QPixmapBlurFilter);
904
if (!painter->isActive())
910
QRectF srcRect = rect;
911
if (srcRect.isNull())
912
srcRect = src.rect();
914
if (d->radius <= 1) {
915
painter->drawPixmap(srcRect.translated(p), src, srcRect);
919
qreal scaledRadius = radiusScale * d->radius;
921
if (qt_scaleForTransform(painter->transform(), &scale))
922
scaledRadius /= scale;
927
if (srcRect == src.rect()) {
928
srcImage = src.toImage();
930
QRect rect = srcRect.toAlignedRect().intersected(src.rect());
931
srcImage = src.copy(rect).toImage();
934
QTransform transform = painter->worldTransform();
935
painter->translate(p);
936
qt_blurImage(painter, srcImage, scaledRadius, (d->hints & QGraphicsBlurEffect::QualityHint), false);
937
painter->setWorldTransform(transform);
940
// grayscales the image to dest (could be same). If rect isn't defined
941
// destination image size is used to determine the dimension of grayscaling
943
static void grayscale(const QImage &image, QImage &dest, const QRect& rect = QRect())
945
QRect destRect = rect;
946
QRect srcRect = rect;
948
srcRect = dest.rect();
949
destRect = dest.rect();
951
if (&image != &dest) {
952
destRect.moveTo(QPoint(0, 0));
955
const unsigned int *data = (const unsigned int *)image.bits();
956
unsigned int *outData = (unsigned int *)dest.bits();
958
if (dest.size() == image.size() && image.rect() == srcRect) {
959
// a bit faster loop for grayscaling everything
960
int pixels = dest.width() * dest.height();
961
for (int i = 0; i < pixels; ++i) {
962
int val = qGray(data[i]);
963
outData[i] = qRgba(val, val, val, qAlpha(data[i]));
966
int yd = destRect.top();
967
for (int y = srcRect.top(); y <= srcRect.bottom() && y < image.height(); y++) {
968
data = (const unsigned int*)image.scanLine(y);
969
outData = (unsigned int*)dest.scanLine(yd++);
970
int xd = destRect.left();
971
for (int x = srcRect.left(); x <= srcRect.right() && x < image.width(); x++) {
972
int val = qGray(data[x]);
973
outData[xd++] = qRgba(val, val, val, qAlpha(data[x]));
980
\class QPixmapColorizeFilter
984
\brief The QPixmapColorizeFilter class provides colorizing
985
filtering for pixmaps.
987
A colorize filter gives the pixmap a tint of its color(). The
988
filter first grayscales the pixmap and then converts those to
989
colorized values using QPainter::CompositionMode_Screen with the
990
chosen color. The alpha-channel is not changed.
993
\snippet code/src_gui_image_qpixmapfilter.cpp 0
995
\sa QPainter::CompositionMode
999
class QPixmapColorizeFilterPrivate : public QPixmapFilterPrivate
1001
Q_DECLARE_PUBLIC(QPixmapColorizeFilter)
1006
quint32 alphaBlend : 1;
1007
quint32 padding : 30;
1011
Constructs an pixmap colorize filter.
1013
Default color value for colorizing is QColor(0, 0, 192).
1017
QPixmapColorizeFilter::QPixmapColorizeFilter(QObject *parent)
1018
: QPixmapFilter(*new QPixmapColorizeFilterPrivate, ColorizeFilter, parent)
1020
Q_D(QPixmapColorizeFilter);
1021
d->color = QColor(0, 0, 192);
1022
d->strength = qreal(1);
1024
d->alphaBlend = false;
1030
QPixmapColorizeFilter::~QPixmapColorizeFilter()
1032
// was inline until Qt 5.6, so essentially
1033
// must stay empty until ### Qt 6
1037
Gets the color of the colorize filter.
1041
QColor QPixmapColorizeFilter::color() const
1043
Q_D(const QPixmapColorizeFilter);
1048
Sets the color of the colorize filter to the \a color specified.
1052
void QPixmapColorizeFilter::setColor(const QColor &color)
1054
Q_D(QPixmapColorizeFilter);
1059
Gets the strength of the colorize filter, 1.0 means full colorized while
1060
0.0 equals to no filtering at all.
1064
qreal QPixmapColorizeFilter::strength() const
1066
Q_D(const QPixmapColorizeFilter);
1071
Sets the strength of the colorize filter to \a strength.
1075
void QPixmapColorizeFilter::setStrength(qreal strength)
1077
Q_D(QPixmapColorizeFilter);
1078
d->strength = qBound(qreal(0), strength, qreal(1));
1079
d->opaque = !qFuzzyIsNull(d->strength);
1080
d->alphaBlend = !qFuzzyIsNull(d->strength - 1);
1086
void QPixmapColorizeFilter::draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const
1088
Q_D(const QPixmapColorizeFilter);
1093
// raster implementation
1096
painter->drawPixmap(dest, src, srcRect);
1103
if (srcRect.isNull()) {
1104
srcImage = src.toImage();
1105
srcImage = srcImage.convertToFormat(srcImage.hasAlphaChannel() ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32);
1106
destImage = QImage(srcImage.size(), srcImage.format());
1108
QRect rect = srcRect.toAlignedRect().intersected(src.rect());
1110
srcImage = src.copy(rect).toImage();
1111
srcImage = srcImage.convertToFormat(srcImage.hasAlphaChannel() ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32);
1112
destImage = QImage(rect.size(), srcImage.format());
1116
QPainter destPainter(&destImage);
1117
grayscale(srcImage, destImage, srcImage.rect());
1118
destPainter.setCompositionMode(QPainter::CompositionMode_Screen);
1119
destPainter.fillRect(srcImage.rect(), d->color);
1122
if (d->alphaBlend) {
1123
// alpha blending srcImage and destImage
1124
QImage buffer = srcImage;
1125
QPainter bufPainter(&buffer);
1126
bufPainter.setOpacity(d->strength);
1127
bufPainter.drawImage(0, 0, destImage);
1132
if (srcImage.hasAlphaChannel())
1133
destImage.setAlphaChannel(srcImage.alphaChannel());
1135
painter->drawImage(dest, destImage);
1138
class QPixmapDropShadowFilterPrivate : public QPixmapFilterPrivate
1141
QPixmapDropShadowFilterPrivate()
1142
: offset(8, 8), color(63, 63, 63, 180), radius(1) {}
1150
\class QPixmapDropShadowFilter
1154
\brief The QPixmapDropShadowFilter class is a convenience class
1155
for drawing pixmaps with drop shadows.
1157
The drop shadow is produced by taking a copy of the source pixmap
1158
and applying a color to the copy using a
1159
QPainter::CompositionMode_DestinationIn operation. This produces a
1160
homogeneously-colored pixmap which is then drawn using a
1161
QPixmapConvolutionFilter at an offset. The original pixmap is
1164
The QPixmapDropShadowFilter class provides some customization
1165
options to specify how the drop shadow should appear. The color of
1166
the drop shadow can be modified using the setColor() function, the
1167
drop shadow offset can be modified using the setOffset() function,
1168
and the blur radius of the drop shadow can be changed through the
1169
setBlurRadius() function.
1171
By default, the drop shadow is a dark gray shadow, blurred with a
1172
radius of 1 at an offset of 8 pixels towards the lower right.
1175
\snippet code/src_gui_image_qpixmapfilter.cpp 2
1177
\sa QPixmapColorizeFilter, QPixmapConvolutionFilter
1183
Constructs drop shadow filter.
1187
QPixmapDropShadowFilter::QPixmapDropShadowFilter(QObject *parent)
1188
: QPixmapFilter(*new QPixmapDropShadowFilterPrivate, DropShadowFilter, parent)
1193
Destroys drop shadow filter.
1197
QPixmapDropShadowFilter::~QPixmapDropShadowFilter()
1202
Returns the radius in pixels of the blur on the drop shadow.
1204
A smaller radius results in a sharper shadow.
1206
\sa color(), offset()
1210
qreal QPixmapDropShadowFilter::blurRadius() const
1212
Q_D(const QPixmapDropShadowFilter);
1217
Sets the radius in pixels of the blur on the drop shadow to the \a radius specified.
1219
Using a smaller radius results in a sharper shadow.
1221
\sa setColor(), setOffset()
1225
void QPixmapDropShadowFilter::setBlurRadius(qreal radius)
1227
Q_D(QPixmapDropShadowFilter);
1232
Returns the color of the drop shadow.
1234
\sa blurRadius(), offset()
1238
QColor QPixmapDropShadowFilter::color() const
1240
Q_D(const QPixmapDropShadowFilter);
1245
Sets the color of the drop shadow to the \a color specified.
1247
\sa setBlurRadius(), setOffset()
1251
void QPixmapDropShadowFilter::setColor(const QColor &color)
1253
Q_D(QPixmapDropShadowFilter);
1258
Returns the shadow offset in pixels.
1260
\sa blurRadius(), color()
1264
QPointF QPixmapDropShadowFilter::offset() const
1266
Q_D(const QPixmapDropShadowFilter);
1271
Sets the shadow offset in pixels to the \a offset specified.
1273
\sa setBlurRadius(), setColor()
1277
void QPixmapDropShadowFilter::setOffset(const QPointF &offset)
1279
Q_D(QPixmapDropShadowFilter);
1284
\fn void QPixmapDropShadowFilter::setOffset(qreal dx, qreal dy)
1287
Sets the shadow offset in pixels to be the displacement specified by the
1288
horizontal \a dx and vertical \a dy coordinates.
1290
\sa setBlurRadius(), setColor()
1298
QRectF QPixmapDropShadowFilter::boundingRectFor(const QRectF &rect) const
1300
Q_D(const QPixmapDropShadowFilter);
1301
return rect.united(rect.translated(d->offset).adjusted(-d->radius, -d->radius, d->radius, d->radius));
1307
void QPixmapDropShadowFilter::draw(QPainter *p,
1310
const QRectF &src) const
1312
Q_D(const QPixmapDropShadowFilter);
1317
QImage tmp(px.size(), QImage::Format_ARGB32_Premultiplied);
1319
QPainter tmpPainter(&tmp);
1320
tmpPainter.setCompositionMode(QPainter::CompositionMode_Source);
1321
tmpPainter.drawPixmap(d->offset, px);
1324
// blur the alpha channel
1325
QImage blurred(tmp.size(), QImage::Format_ARGB32_Premultiplied);
1327
QPainter blurPainter(&blurred);
1328
qt_blurImage(&blurPainter, tmp, d->radius, false, true);
1333
// blacken the image...
1334
tmpPainter.begin(&tmp);
1335
tmpPainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
1336
tmpPainter.fillRect(tmp.rect(), d->color);
1339
// draw the blurred drop shadow...
1340
p->drawImage(pos, tmp);
1342
// Draw the actual pixmap...
1343
p->drawPixmap(pos, px, src);
1348
#include "moc_qpixmapfilter_p.cpp"
1350
#endif //QT_NO_GRAPHICSEFFECT