Qt 4.8
qpixmapfilter.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
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 Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
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 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include <qglobal.h>
43 
44 #include <QDebug>
45 
46 #include "qpainter.h"
47 #include "qpixmap.h"
48 #include "qpixmapfilter_p.h"
49 #include "qvarlengtharray.h"
50 
51 #include "private/qapplication_p.h"
52 #include "private/qgraphicssystem_p.h"
53 #include "private/qpaintengineex_p.h"
54 #include "private/qpaintengine_raster_p.h"
55 #include "qmath.h"
56 #include "private/qmath_p.h"
57 #include "private/qmemrotate_p.h"
58 #include "private/qdrawhelper_p.h"
59 
60 #ifndef QT_NO_GRAPHICSEFFECT
62 
64 {
66 public:
68 };
69 
125  : QObject(*new QPixmapFilterPrivate, parent)
126 {
127  d_func()->type = type;
128 }
129 
130 
131 
136  : QObject(d, parent)
137 {
138  d_func()->type = type;
139 }
140 
141 
148 {
149 }
150 
158 {
159  Q_D(const QPixmapFilter);
160  return d->type;
161 }
162 
170 {
171  return rect;
172 }
173 
220 {
221 public:
222  QPixmapConvolutionFilterPrivate(): convolutionKernel(0), kernelWidth(0), kernelHeight(0), convoluteAlpha(false) {}
224  delete[] convolutionKernel;
225  }
226 
231 };
232 
233 
243 {
245  d->convoluteAlpha = true;
246 }
247 
254 {
255 }
256 
269 {
271  delete [] d->convolutionKernel;
272  d->convolutionKernel = new qreal[rows * columns];
273  memcpy(d->convolutionKernel, kernel, sizeof(qreal) * rows * columns);
274  d->kernelWidth = columns;
275  d->kernelHeight = rows;
276 }
277 
284 {
286  return d->convolutionKernel;
287 }
288 
295 {
297  return d->kernelHeight;
298 }
299 
306 {
308  return d->kernelWidth;
309 }
310 
311 
316 {
318  return rect.adjusted(-d->kernelWidth / 2, -d->kernelHeight / 2, (d->kernelWidth - 1) / 2, (d->kernelHeight - 1) / 2);
319 }
320 
321 // Convolutes the image
322 static void convolute(
323  QImage *destImage,
324  const QPointF &pos,
325  const QImage &srcImage,
326  const QRectF &srcRect,
328  qreal *kernel,
329  int kernelWidth,
330  int kernelHeight )
331 {
332  const QImage processImage = (srcImage.format() != QImage::Format_ARGB32_Premultiplied ) ? srcImage.convertToFormat(QImage::Format_ARGB32_Premultiplied) : srcImage;
333  // TODO: support also other formats directly without copying
334 
335  int *fixedKernel = new int[kernelWidth*kernelHeight];
336  for(int i = 0; i < kernelWidth*kernelHeight; i++)
337  {
338  fixedKernel[i] = (int)(65536 * kernel[i]);
339  }
340  QRectF trect = srcRect.isNull() ? processImage.rect() : srcRect;
341  trect.moveTo(pos);
342  QRectF bounded = trect.adjusted(-kernelWidth / 2, -kernelHeight / 2, (kernelWidth - 1) / 2, (kernelHeight - 1) / 2);
343  QRect rect = bounded.toAlignedRect();
344  QRect targetRect = rect.intersected(destImage->rect());
345 
346  QRectF srect = srcRect.isNull() ? processImage.rect() : srcRect;
347  QRectF sbounded = srect.adjusted(-kernelWidth / 2, -kernelHeight / 2, (kernelWidth - 1) / 2, (kernelHeight - 1) / 2);
348  QPoint srcStartPoint = sbounded.toAlignedRect().topLeft()+(targetRect.topLeft()-rect.topLeft());
349 
350  const uint *sourceStart = (uint*)processImage.scanLine(0);
351  uint *outputStart = (uint*)destImage->scanLine(0);
352 
353  int yk = srcStartPoint.y();
354  for (int y = targetRect.top(); y <= targetRect.bottom(); y++) {
355  uint* output = outputStart + (destImage->bytesPerLine()/sizeof(uint))*y+targetRect.left();
356  int xk = srcStartPoint.x();
357  for(int x = targetRect.left(); x <= targetRect.right(); x++) {
358  int r = 0;
359  int g = 0;
360  int b = 0;
361  int a = 0;
362 
363  // some out of bounds pre-checking to avoid inner-loop ifs
364  int kernely = -kernelHeight/2;
365  int starty = 0;
366  int endy = kernelHeight;
367  if(yk+kernely+endy >= srcImage.height())
368  endy = kernelHeight-((yk+kernely+endy)-srcImage.height())-1;
369  if(yk+kernely < 0)
370  starty = -(yk+kernely);
371 
372  int kernelx = -kernelWidth/2;
373  int startx = 0;
374  int endx = kernelWidth;
375  if(xk+kernelx+endx >= srcImage.width())
376  endx = kernelWidth-((xk+kernelx+endx)-srcImage.width())-1;
377  if(xk+kernelx < 0)
378  startx = -(xk+kernelx);
379 
380  for (int ys = starty; ys < endy; ys ++) {
381  const uint *pix = sourceStart + (processImage.bytesPerLine()/sizeof(uint))*(yk+kernely+ys) + ((xk+kernelx+startx));
382  const uint *endPix = pix+endx-startx;
383  int kernelPos = ys*kernelWidth+startx;
384  while (pix < endPix) {
385  int factor = fixedKernel[kernelPos++];
386  a += (((*pix) & 0xff000000)>>24) * factor;
387  r += (((*pix) & 0x00ff0000)>>16) * factor;
388  g += (((*pix) & 0x0000ff00)>>8 ) * factor;
389  b += (((*pix) & 0x000000ff) ) * factor;
390  pix++;
391  }
392  }
393 
394  r = qBound((int)0, r >> 16, (int)255);
395  g = qBound((int)0, g >> 16, (int)255);
396  b = qBound((int)0, b >> 16, (int)255);
397  a = qBound((int)0, a >> 16, (int)255);
398  // composition mode checking could be moved outside of loop
400  uint color = (a<<24)+(r<<16)+(g<<8)+b;
401  *output++ = color;
402  } else {
403  uint current = *output;
404  uchar ca = (current&0xff000000)>>24;
405  uchar cr = (current&0x00ff0000)>>16;
406  uchar cg = (current&0x0000ff00)>>8;
407  uchar cb = (current&0x000000ff);
408  uint color =
409  (((ca*(255-a) >> 8)+a) << 24)+
410  (((cr*(255-a) >> 8)+r) << 16)+
411  (((cg*(255-a) >> 8)+g) << 8)+
412  (((cb*(255-a) >> 8)+b));
413  *output++ = color;;
414  }
415  xk++;
416  }
417  yk++;
418  }
419  delete[] fixedKernel;
420 }
421 
425 void QPixmapConvolutionFilter::draw(QPainter *painter, const QPointF &p, const QPixmap &src, const QRectF& srcRect) const
426 {
428  if (!painter->isActive())
429  return;
430 
431  if(d->kernelWidth<=0 || d->kernelHeight <= 0)
432  return;
433 
434  if (src.isNull())
435  return;
436 
437  QPixmapFilter *filter = painter->paintEngine() && painter->paintEngine()->isExtended() ?
438  static_cast<QPaintEngineEx *>(painter->paintEngine())->pixmapFilter(type(), this) : 0;
439  QPixmapConvolutionFilter *convolutionFilter = static_cast<QPixmapConvolutionFilter*>(filter);
440  if (convolutionFilter) {
441  convolutionFilter->setConvolutionKernel(d->convolutionKernel, d->kernelWidth, d->kernelHeight);
442  convolutionFilter->d_func()->convoluteAlpha = d->convoluteAlpha;
443  convolutionFilter->draw(painter, p, src, srcRect);
444  return;
445  }
446 
447  // falling back to raster implementation
448 
449  QImage *target = 0;
450  if (painter->paintEngine()->paintDevice()->devType() == QInternal::Image) {
451  target = static_cast<QImage *>(painter->paintEngine()->paintDevice());
452 
453  QTransform mat = painter->combinedTransform();
454 
455  if (mat.type() > QTransform::TxTranslate) {
456  // Disabled because of transformation...
457  target = 0;
458  } else {
459  QRasterPaintEngine *pe = static_cast<QRasterPaintEngine *>(painter->paintEngine());
461  // disabled because of complex clipping...
462  target = 0;
463  else {
464  QRectF clip = pe->clipBoundingRect();
465  QRectF rect = boundingRectFor(srcRect.isEmpty() ? src.rect() : srcRect);
466  QTransform x = painter->deviceTransform();
467  if (!clip.contains(rect.translated(x.dx() + p.x(), x.dy() + p.y()))) {
468  target = 0;
469  }
470 
471  }
472  }
473  }
474 
475  if (target) {
476  QTransform x = painter->deviceTransform();
477  QPointF offset(x.dx(), x.dy());
478 
479  convolute(target, p+offset, src.toImage(), srcRect, QPainter::CompositionMode_SourceOver, d->convolutionKernel, d->kernelWidth, d->kernelHeight);
480  } else {
481  QRect srect = srcRect.isNull() ? src.rect() : srcRect.toRect();
482  QRect rect = boundingRectFor(srect).toRect();
484  QPoint offset = srect.topLeft() - rect.topLeft();
485  convolute(&result,
486  offset,
487  src.toImage(),
488  srect,
490  d->convolutionKernel,
491  d->kernelWidth,
492  d->kernelHeight);
493  painter->drawImage(p - offset, result);
494  }
495 }
496 
525 {
526 public:
527  QPixmapBlurFilterPrivate() : radius(5), hints(QGraphicsBlurEffect::PerformanceHint) {}
528 
530  QGraphicsBlurEffect::BlurHints hints;
531 };
532 
533 
541 {
542 }
543 
550 {
551 }
552 
559 {
561  d->radius = radius;
562 }
563 
570 {
571  Q_D(const QPixmapBlurFilter);
572  return d->radius;
573 }
574 
590 void QPixmapBlurFilter::setBlurHints(QGraphicsBlurEffect::BlurHints hints)
591 {
593  d->hints = hints;
594 }
595 
601 QGraphicsBlurEffect::BlurHints QPixmapBlurFilter::blurHints() const
602 {
603  Q_D(const QPixmapBlurFilter);
604  return d->hints;
605 }
606 
607 const qreal radiusScale = qreal(2.5);
608 
613 {
614  Q_D(const QPixmapBlurFilter);
615  const qreal delta = radiusScale * d->radius + 1;
616  return rect.adjusted(-delta, -delta, delta, delta);
617 }
618 
619 template <int shift>
620 inline int qt_static_shift(int value)
621 {
622  if (shift == 0)
623  return value;
624  else if (shift > 0)
625  return value << (uint(shift) & 0x1f);
626  else
627  return value >> (uint(-shift) & 0x1f);
628 }
629 
630 template<int aprec, int zprec>
631 inline void qt_blurinner(uchar *bptr, int &zR, int &zG, int &zB, int &zA, int alpha)
632 {
633  QRgb *pixel = (QRgb *)bptr;
634 
635 #define Z_MASK (0xff << zprec)
636  const int A_zprec = qt_static_shift<zprec - 24>(*pixel) & Z_MASK;
637  const int R_zprec = qt_static_shift<zprec - 16>(*pixel) & Z_MASK;
638  const int G_zprec = qt_static_shift<zprec - 8>(*pixel) & Z_MASK;
639  const int B_zprec = qt_static_shift<zprec>(*pixel) & Z_MASK;
640 #undef Z_MASK
641 
642  const int zR_zprec = zR >> aprec;
643  const int zG_zprec = zG >> aprec;
644  const int zB_zprec = zB >> aprec;
645  const int zA_zprec = zA >> aprec;
646 
647  zR += alpha * (R_zprec - zR_zprec);
648  zG += alpha * (G_zprec - zG_zprec);
649  zB += alpha * (B_zprec - zB_zprec);
650  zA += alpha * (A_zprec - zA_zprec);
651 
652 #define ZA_MASK (0xff << (zprec + aprec))
653  *pixel =
654  qt_static_shift<24 - zprec - aprec>(zA & ZA_MASK)
655  | qt_static_shift<16 - zprec - aprec>(zR & ZA_MASK)
656  | qt_static_shift<8 - zprec - aprec>(zG & ZA_MASK)
657  | qt_static_shift<-zprec - aprec>(zB & ZA_MASK);
658 #undef ZA_MASK
659 }
660 
661 const int alphaIndex = (QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3);
662 
663 template<int aprec, int zprec>
664 inline void qt_blurinner_alphaOnly(uchar *bptr, int &z, int alpha)
665 {
666  const int A_zprec = int(*(bptr)) << zprec;
667  const int z_zprec = z >> aprec;
668  z += alpha * (A_zprec - z_zprec);
669  *(bptr) = z >> (zprec + aprec);
670 }
671 
672 template<int aprec, int zprec, bool alphaOnly>
673 inline void qt_blurrow(QImage & im, int line, int alpha)
674 {
675  uchar *bptr = im.scanLine(line);
676 
677  int zR = 0, zG = 0, zB = 0, zA = 0;
678 
679  if (alphaOnly && im.format() != QImage::Format_Indexed8)
680  bptr += alphaIndex;
681 
682  const int stride = im.depth() >> 3;
683  const int im_width = im.width();
684  for (int index = 0; index < im_width; ++index) {
685  if (alphaOnly)
686  qt_blurinner_alphaOnly<aprec, zprec>(bptr, zA, alpha);
687  else
688  qt_blurinner<aprec, zprec>(bptr, zR, zG, zB, zA, alpha);
689  bptr += stride;
690  }
691 
692  bptr -= stride;
693 
694  for (int index = im_width - 2; index >= 0; --index) {
695  bptr -= stride;
696  if (alphaOnly)
697  qt_blurinner_alphaOnly<aprec, zprec>(bptr, zA, alpha);
698  else
699  qt_blurinner<aprec, zprec>(bptr, zR, zG, zB, zA, alpha);
700  }
701 }
702 
703 /*
704 * expblur(QImage &img, int radius)
705 *
706 * Based on exponential blur algorithm by Jani Huhtanen
707 *
708 * In-place blur of image 'img' with kernel
709 * of approximate radius 'radius'.
710 *
711 * Blurs with two sided exponential impulse
712 * response.
713 *
714 * aprec = precision of alpha parameter
715 * in fixed-point format 0.aprec
716 *
717 * zprec = precision of state parameters
718 * zR,zG,zB and zA in fp format 8.zprec
719 */
720 template <int aprec, int zprec, bool alphaOnly>
721 void expblur(QImage &img, qreal radius, bool improvedQuality = false, int transposed = 0)
722 {
723  // halve the radius if we're using two passes
724  if (improvedQuality)
725  radius *= qreal(0.5);
726 
728  || img.format() == QImage::Format_RGB32
729  || img.format() == QImage::Format_Indexed8);
730 
731  // choose the alpha such that pixels at radius distance from a fully
732  // saturated pixel will have an alpha component of no greater than
733  // the cutOffIntensity
734  const qreal cutOffIntensity = 2;
735  int alpha = radius <= qreal(1e-5)
736  ? ((1 << aprec)-1)
737  : qRound((1<<aprec)*(1 - qPow(cutOffIntensity * (1 / qreal(255)), 1 / radius)));
738 
739  int img_height = img.height();
740  for (int row = 0; row < img_height; ++row) {
741  for (int i = 0; i <= int(improvedQuality); ++i)
742  qt_blurrow<aprec, zprec, alphaOnly>(img, row, alpha);
743  }
744 
745  QImage temp(img.height(), img.width(), img.format());
746  if (transposed >= 0) {
747  if (img.depth() == 8) {
748  qt_memrotate270(reinterpret_cast<const quint8*>(img.bits()),
749  img.width(), img.height(), img.bytesPerLine(),
750  reinterpret_cast<quint8*>(temp.bits()),
751  temp.bytesPerLine());
752  } else {
753  qt_memrotate270(reinterpret_cast<const quint32*>(img.bits()),
754  img.width(), img.height(), img.bytesPerLine(),
755  reinterpret_cast<quint32*>(temp.bits()),
756  temp.bytesPerLine());
757  }
758  } else {
759  if (img.depth() == 8) {
760  qt_memrotate90(reinterpret_cast<const quint8*>(img.bits()),
761  img.width(), img.height(), img.bytesPerLine(),
762  reinterpret_cast<quint8*>(temp.bits()),
763  temp.bytesPerLine());
764  } else {
765  qt_memrotate90(reinterpret_cast<const quint32*>(img.bits()),
766  img.width(), img.height(), img.bytesPerLine(),
767  reinterpret_cast<quint32*>(temp.bits()),
768  temp.bytesPerLine());
769  }
770  }
771 
772  img_height = temp.height();
773  for (int row = 0; row < img_height; ++row) {
774  for (int i = 0; i <= int(improvedQuality); ++i)
775  qt_blurrow<aprec, zprec, alphaOnly>(temp, row, alpha);
776  }
777 
778  if (transposed == 0) {
779  if (img.depth() == 8) {
780  qt_memrotate90(reinterpret_cast<const quint8*>(temp.bits()),
781  temp.width(), temp.height(), temp.bytesPerLine(),
782  reinterpret_cast<quint8*>(img.bits()),
783  img.bytesPerLine());
784  } else {
785  qt_memrotate90(reinterpret_cast<const quint32*>(temp.bits()),
786  temp.width(), temp.height(), temp.bytesPerLine(),
787  reinterpret_cast<quint32*>(img.bits()),
788  img.bytesPerLine());
789  }
790  } else {
791  img = temp;
792  }
793 }
794 #define AVG(a,b) ( ((((a)^(b)) & 0xfefefefeUL) >> 1) + ((a)&(b)) )
795 #define AVG16(a,b) ( ((((a)^(b)) & 0xf7deUL) >> 1) + ((a)&(b)) )
796 
798 {
799  if (source.width() < 2 || source.height() < 2)
800  return QImage();
801 
802  QImage srcImage = source;
803 
804  if (source.format() == QImage::Format_Indexed8) {
805  // assumes grayscale
806  QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
807 
808  const uchar *src = reinterpret_cast<const uchar*>(const_cast<const QImage &>(srcImage).bits());
809  int sx = srcImage.bytesPerLine();
810  int sx2 = sx << 1;
811 
812  uchar *dst = reinterpret_cast<uchar*>(dest.bits());
813  int dx = dest.bytesPerLine();
814  int ww = dest.width();
815  int hh = dest.height();
816 
817  for (int y = hh; y; --y, dst += dx, src += sx2) {
818  const uchar *p1 = src;
819  const uchar *p2 = src + sx;
820  uchar *q = dst;
821  for (int x = ww; x; --x, ++q, p1 += 2, p2 += 2)
822  *q = ((int(p1[0]) + int(p1[1]) + int(p2[0]) + int(p2[1])) + 2) >> 2;
823  }
824 
825  return dest;
826  } else if (source.format() == QImage::Format_ARGB8565_Premultiplied) {
827  QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
828 
829  const uchar *src = reinterpret_cast<const uchar*>(const_cast<const QImage &>(srcImage).bits());
830  int sx = srcImage.bytesPerLine();
831  int sx2 = sx << 1;
832 
833  uchar *dst = reinterpret_cast<uchar*>(dest.bits());
834  int dx = dest.bytesPerLine();
835  int ww = dest.width();
836  int hh = dest.height();
837 
838  for (int y = hh; y; --y, dst += dx, src += sx2) {
839  const uchar *p1 = src;
840  const uchar *p2 = src + sx;
841  uchar *q = dst;
842  for (int x = ww; x; --x, q += 3, p1 += 6, p2 += 6) {
843  // alpha
844  q[0] = AVG(AVG(p1[0], p1[3]), AVG(p2[0], p2[3]));
845  // rgb
846  const quint16 p16_1 = (p1[2] << 8) | p1[1];
847  const quint16 p16_2 = (p1[5] << 8) | p1[4];
848  const quint16 p16_3 = (p2[2] << 8) | p2[1];
849  const quint16 p16_4 = (p2[5] << 8) | p2[4];
850  const quint16 result = AVG16(AVG16(p16_1, p16_2), AVG16(p16_3, p16_4));
851  q[1] = result & 0xff;
852  q[2] = result >> 8;
853  }
854  }
855 
856  return dest;
857  } else if (source.format() != QImage::Format_ARGB32_Premultiplied
858  && source.format() != QImage::Format_RGB32)
859  {
861  }
862 
863  QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
864 
865  const quint32 *src = reinterpret_cast<const quint32*>(const_cast<const QImage &>(srcImage).bits());
866  int sx = srcImage.bytesPerLine() >> 2;
867  int sx2 = sx << 1;
868 
869  quint32 *dst = reinterpret_cast<quint32*>(dest.bits());
870  int dx = dest.bytesPerLine() >> 2;
871  int ww = dest.width();
872  int hh = dest.height();
873 
874  for (int y = hh; y; --y, dst += dx, src += sx2) {
875  const quint32 *p1 = src;
876  const quint32 *p2 = src + sx;
877  quint32 *q = dst;
878  for (int x = ww; x; --x, q++, p1 += 2, p2 += 2)
879  *q = AVG(AVG(p1[0], p1[1]), AVG(p2[0], p2[1]));
880  }
881 
882  return dest;
883 }
884 
885 Q_GUI_EXPORT void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius, bool quality, bool alphaOnly, int transposed = 0)
886 {
888  && blurImage.format() != QImage::Format_RGB32)
889  {
891  }
892 
893  qreal scale = 1;
894  if (radius >= 4 && blurImage.width() >= 2 && blurImage.height() >= 2) {
895  blurImage = qt_halfScaled(blurImage);
896  scale = 2;
897  radius *= qreal(0.5);
898  }
899 
900  if (alphaOnly)
901  expblur<12, 10, true>(blurImage, radius, quality, transposed);
902  else
903  expblur<12, 10, false>(blurImage, radius, quality, transposed);
904 
905  if (p) {
906  p->scale(scale, scale);
908  p->drawImage(QRect(0, 0, blurImage.width(), blurImage.height()), blurImage);
909  }
910 }
911 
912 Q_GUI_EXPORT void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed = 0)
913 {
914  if (blurImage.format() == QImage::Format_Indexed8)
915  expblur<12, 10, true>(blurImage, radius, quality, transposed);
916  else
917  expblur<12, 10, false>(blurImage, radius, quality, transposed);
918 }
919 
920 Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale);
921 
925 void QPixmapBlurFilter::draw(QPainter *painter, const QPointF &p, const QPixmap &src, const QRectF &rect) const
926 {
927  Q_D(const QPixmapBlurFilter);
928  if (!painter->isActive())
929  return;
930 
931  if (src.isNull())
932  return;
933 
934  QRectF srcRect = rect;
935  if (srcRect.isNull())
936  srcRect = src.rect();
937 
938  if (d->radius <= 1) {
939  painter->drawPixmap(srcRect.translated(p), src, srcRect);
940  return;
941  }
942 
943  qreal scaledRadius = radiusScale * d->radius;
944  qreal scale;
945  if (qt_scaleForTransform(painter->transform(), &scale))
946  scaledRadius /= scale;
947 
948  QPixmapFilter *filter = painter->paintEngine() && painter->paintEngine()->isExtended() ?
949  static_cast<QPaintEngineEx *>(painter->paintEngine())->pixmapFilter(type(), this) : 0;
950  QPixmapBlurFilter *blurFilter = static_cast<QPixmapBlurFilter*>(filter);
951  if (blurFilter) {
952  blurFilter->setRadius(scaledRadius);
953  blurFilter->setBlurHints(d->hints);
954  blurFilter->draw(painter, p, src, srcRect);
955  return;
956  }
957 
958  QImage srcImage;
959  QImage destImage;
960 
961  if (srcRect == src.rect()) {
962  srcImage = src.toImage();
963  } else {
964  QRect rect = srcRect.toAlignedRect().intersected(src.rect());
965  srcImage = src.copy(rect).toImage();
966  }
967 
968  QTransform transform = painter->worldTransform();
969  painter->translate(p);
970  qt_blurImage(painter, srcImage, scaledRadius, (d->hints & QGraphicsBlurEffect::QualityHint), false);
971  painter->setWorldTransform(transform);
972 }
973 
974 // grayscales the image to dest (could be same). If rect isn't defined
975 // destination image size is used to determine the dimension of grayscaling
976 // process.
977 static void grayscale(const QImage &image, QImage &dest, const QRect& rect = QRect())
978 {
979  QRect destRect = rect;
980  QRect srcRect = rect;
981  if (rect.isNull()) {
982  srcRect = dest.rect();
983  destRect = dest.rect();
984  }
985  if (&image != &dest) {
986  destRect.moveTo(QPoint(0, 0));
987  }
988 
989  unsigned int *data = (unsigned int *)image.bits();
990  unsigned int *outData = (unsigned int *)dest.bits();
991 
992  if (dest.size() == image.size() && image.rect() == srcRect) {
993  // a bit faster loop for grayscaling everything
994  int pixels = dest.width() * dest.height();
995  for (int i = 0; i < pixels; ++i) {
996  int val = qGray(data[i]);
997  outData[i] = qRgba(val, val, val, qAlpha(data[i]));
998  }
999  } else {
1000  int yd = destRect.top();
1001  for (int y = srcRect.top(); y <= srcRect.bottom() && y < image.height(); y++) {
1002  data = (unsigned int*)image.scanLine(y);
1003  outData = (unsigned int*)dest.scanLine(yd++);
1004  int xd = destRect.left();
1005  for (int x = srcRect.left(); x <= srcRect.right() && x < image.width(); x++) {
1006  int val = qGray(data[x]);
1007  outData[xd++] = qRgba(val, val, val, qAlpha(data[x]));
1008  }
1009  }
1010  }
1011 }
1012 
1037 {
1039 public:
1045 };
1046 
1056 {
1058  d->color = QColor(0, 0, 192);
1059  d->strength = qreal(1);
1060  d->opaque = true;
1061  d->alphaBlend = false;
1062 }
1063 
1070 {
1071  Q_D(const QPixmapColorizeFilter);
1072  return d->color;
1073 }
1074 
1081 {
1083  d->color = color;
1084 }
1085 
1093 {
1094  Q_D(const QPixmapColorizeFilter);
1095  return d->strength;
1096 }
1097 
1104 {
1106  d->strength = qBound(qreal(0), strength, qreal(1));
1107  d->opaque = !qFuzzyIsNull(d->strength);
1108  d->alphaBlend = !qFuzzyIsNull(d->strength - 1);
1109 }
1110 
1114 void QPixmapColorizeFilter::draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const
1115 {
1116  Q_D(const QPixmapColorizeFilter);
1117 
1118  if (src.isNull())
1119  return;
1120 
1121  QPixmapFilter *filter = painter->paintEngine() && painter->paintEngine()->isExtended() ?
1122  static_cast<QPaintEngineEx *>(painter->paintEngine())->pixmapFilter(type(), this) : 0;
1123  QPixmapColorizeFilter *colorizeFilter = static_cast<QPixmapColorizeFilter*>(filter);
1124  if (colorizeFilter) {
1125  colorizeFilter->setColor(d->color);
1126  colorizeFilter->setStrength(d->strength);
1127  colorizeFilter->draw(painter, dest, src, srcRect);
1128  return;
1129  }
1130 
1131  // falling back to raster implementation
1132 
1133  if (!d->opaque) {
1134  painter->drawPixmap(dest, src, srcRect);
1135  return;
1136  }
1137 
1138  QImage srcImage;
1139  QImage destImage;
1140 
1141  if (srcRect.isNull()) {
1142  srcImage = src.toImage();
1144  destImage = QImage(srcImage.size(), srcImage.format());
1145  } else {
1146  QRect rect = srcRect.toAlignedRect().intersected(src.rect());
1147 
1148  srcImage = src.copy(rect).toImage();
1150  destImage = QImage(rect.size(), srcImage.format());
1151  }
1152 
1153  // do colorizing
1154  QPainter destPainter(&destImage);
1155  grayscale(srcImage, destImage, srcImage.rect());
1156  destPainter.setCompositionMode(QPainter::CompositionMode_Screen);
1157  destPainter.fillRect(srcImage.rect(), d->color);
1158  destPainter.end();
1159 
1160  if (d->alphaBlend) {
1161  // alpha blending srcImage and destImage
1162  QImage buffer = srcImage;
1163  QPainter bufPainter(&buffer);
1164  bufPainter.setOpacity(d->strength);
1165  bufPainter.drawImage(0, 0, destImage);
1166  bufPainter.end();
1167  destImage = buffer;
1168  }
1169 
1170  if (srcImage.hasAlphaChannel())
1171  destImage.setAlphaChannel(srcImage.alphaChannel());
1172 
1173  painter->drawImage(dest, destImage);
1174 }
1175 
1177 {
1178 public:
1180  : offset(8, 8), color(63, 63, 63, 180), radius(1) {}
1181 
1185 };
1186 
1230 {
1231 }
1232 
1239 {
1240 }
1241 
1252 {
1254  return d->radius;
1255 }
1256 
1267 {
1269  d->radius = radius;
1270 }
1271 
1280 {
1282  return d->color;
1283 }
1284 
1293 {
1295  d->color = color;
1296 }
1297 
1306 {
1308  return d->offset;
1309 }
1310 
1319 {
1321  d->offset = offset;
1322 }
1323 
1343 {
1345  return rect.united(rect.translated(d->offset).adjusted(-d->radius, -d->radius, d->radius, d->radius));
1346 }
1347 
1352  const QPointF &pos,
1353  const QPixmap &px,
1354  const QRectF &src) const
1355 {
1357 
1358  if (px.isNull())
1359  return;
1360 
1362  static_cast<QPaintEngineEx *>(p->paintEngine())->pixmapFilter(type(), this) : 0;
1363  QPixmapDropShadowFilter *dropShadowFilter = static_cast<QPixmapDropShadowFilter*>(filter);
1364  if (dropShadowFilter) {
1365  dropShadowFilter->setColor(d->color);
1366  dropShadowFilter->setBlurRadius(d->radius);
1367  dropShadowFilter->setOffset(d->offset);
1368  dropShadowFilter->draw(p, pos, px, src);
1369  return;
1370  }
1371 
1373  tmp.fill(0);
1374  QPainter tmpPainter(&tmp);
1376  tmpPainter.drawPixmap(d->offset, px);
1377  tmpPainter.end();
1378 
1379  // blur the alpha channel
1380  QImage blurred(tmp.size(), QImage::Format_ARGB32_Premultiplied);
1381  blurred.fill(0);
1382  QPainter blurPainter(&blurred);
1383  qt_blurImage(&blurPainter, tmp, d->radius, false, true);
1384  blurPainter.end();
1385 
1386  // blacken the image...
1387  QPainter blackenPainter(&blurred);
1389  blackenPainter.fillRect(blurred.rect(), d->color);
1390  blackenPainter.end();
1391 
1392  // draw the blurred drop shadow...
1393  p->drawImage(pos, blurred);
1394 
1395  // Draw the actual pixmap...
1396  p->drawPixmap(pos, px, src);
1397 }
1398 
1400 
1401 #endif //QT_NO_GRAPHICSEFFECT
qreal radius() const
Gets the radius of the blur filter.
The QPainter class performs low-level painting on widgets and other paint devices.
Definition: qpainter.h:86
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition: qcolor.h:67
double d
Definition: qnumeric_p.h:62
QRect toAlignedRect() const
Returns a QRect based on the values of this rectangle that is the smallest possible integer rectangle...
Definition: qrect.cpp:2817
void setColor(const QColor &color)
Sets the color of the drop shadow to the color specified.
QImage toImage() const
Converts the pixmap to a QImage.
Definition: qpixmap.cpp:542
qreal dy() const
Returns the vertical translation factor.
Definition: qtransform.h:277
void setConvolutionKernel(const qreal *matrix, int rows, int columns)
Sets convolution kernel with the given number of rows and columns.
static ShiftResult shift(const QBezier *orig, QBezier *shifted, qreal offset, qreal threshold)
Definition: qbezier.cpp:289
unsigned int QRgb
Definition: qrgb.h:53
void qt_blurinner_alphaOnly(uchar *bptr, int &z, int alpha)
double qreal
Definition: qglobal.h:1193
const QTransform & transform() const
Returns the world transformation matrix.
Definition: qpainter.cpp:9558
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
QPaintDevice * paintDevice() const
Returns the device that this engine is painting on, if painting is active; otherwise returns 0...
QPixmapBlurFilter(QObject *parent=0)
Constructs a pixmap blur filter.
QSize size() const
Returns the size of the pixmap.
Definition: qpixmap.cpp:661
CompositionMode
Defines the modes supported for digital image compositing.
Definition: qpainter.h:138
Q_GUI_EXPORT void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius, bool quality, bool alphaOnly, int transposed=0)
int qt_static_shift(int value)
QPixmapDropShadowFilter(QObject *parent=0)
Constructs drop shadow filter.
Q_GUI_EXPORT_INLINE int qAlpha(QRgb rgb)
Definition: qrgb.h:66
Q_GUI_EXPORT QImage qt_halfScaled(const QImage &source)
virtual ~QPixmapFilter()=0
Destroys the pixmap filter.
ClipType clipType() const
Returns the type of the clip currently set.
void qt_blurrow(QImage &im, int line, int alpha)
#define Q_GUI_EXPORT
Definition: qglobal.h:1450
virtual QRectF boundingRectFor(const QRectF &rect) const
Returns the bounding rectangle that is affected by the pixmap filter if the filter is applied to the ...
void fill(uint pixel)
Fills the entire image with the given pixelValue.
Definition: qimage.cpp:2032
Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale)
The QPointF class defines a point in the plane using floating point precision.
Definition: qpoint.h:214
QRect clipBoundingRect() const
Returns the bounding rect of the currently set clip.
FilterType type() const
Returns the type of the filter.
int left() const
Returns the x-coordinate of the rectangle&#39;s left edge.
Definition: qrect.h:240
QPixmapColorizeFilter(QObject *parent=0)
Constructs an pixmap colorize filter.
const int alphaIndex
bool hasAlphaChannel() const
Returns true if the image has a format that respects the alpha channel, otherwise returns false...
Definition: qimage.cpp:6495
int bytesPerLine() const
Returns the number of bytes per image scanline.
Definition: qimage.cpp:1812
long ASN1_INTEGER_get ASN1_INTEGER * a
QRect intersected(const QRect &other) const
Returns the intersection of this rectangle and the given rectangle.
Definition: qrect.h:481
bool isExtended() const
Returns true if the paint engine is a QPaintEngineEx derivative.
Definition: qpaintengine.h:234
void moveTo(int x, int t)
Moves the rectangle, leaving the top-left corner at the given position (x, y).
Definition: qrect.h:334
unsigned char quint8
Definition: qglobal.h:934
void setOffset(const QPointF &offset)
Sets the shadow offset in pixels to the offset specified.
int bottom() const
Returns the y-coordinate of the rectangle&#39;s bottom edge.
Definition: qrect.h:249
QRect rect() const
Returns the enclosing rectangle (0, 0, width(), height()) of the image.
Definition: qimage.cpp:1603
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
TransformationType type() const
Returns the transformation type of this matrix.
The QGraphicsBlurEffect class provides a blur effect.
#define Q_D(Class)
Definition: qglobal.h:2482
static void grayscale(const QImage &image, QImage &dest, const QRect &rect=QRect())
void Q_GUI_EXPORT qt_memrotate90(const quint32 *, int, int, int, quint32 *, int)
QRectF boundingRectFor(const QRectF &rect) const
virtual int devType() const
Definition: qpaintdevice.h:167
Format format() const
Returns the format of the image.
Definition: qimage.cpp:2305
void qt_blurinner(uchar *bptr, int &zR, int &zG, int &zB, int &zA, int alpha)
void setBlurHints(QGraphicsBlurEffect::BlurHints hints)
Setting the blur hints to PerformanceHint causes the implementation to trade off visual quality to bl...
qreal x() const
Returns the x-coordinate of this point.
Definition: qpoint.h:282
void setBlurRadius(qreal radius)
Sets the radius in pixels of the blur on the drop shadow to the radius specified. ...
bool contains(const QPointF &p) const
Returns true if the given point is inside or on the edge of the rectangle; otherwise returns false...
Definition: qrect.cpp:2349
~QPixmapConvolutionFilter()
Destructor of pixmap convolution filter.
QGraphicsBlurEffect::BlurHints hints
unsigned char uchar
Definition: qglobal.h:994
void setRenderHint(RenderHint hint, bool on=true)
Sets the given render hint on the painter if on is true; otherwise clears the render hint...
Definition: qpainter.cpp:7620
FilterType
This enum describes the types of filter that can be applied to pixmaps.
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
Q_GUI_EXPORT_INLINE QRgb qRgba(int r, int g, int b, int a)
Definition: qrgb.h:72
The QRectF class defines a rectangle in the plane using floating point precision. ...
Definition: qrect.h:511
QColor color() const
Gets the color of the colorize filter.
const qreal * convolutionKernel() const
Gets the convolution kernel data.
The QPixmapColorizeFilter class provides colorizing filtering for pixmaps.
void setStrength(qreal strength)
Sets the strength of the colorize filter to strength.
bool isActive() const
Returns true if begin() has been called and end() has not yet been called; otherwise returns false...
Definition: qpainter.cpp:1545
QSize size() const
Returns the size of the rectangle.
Definition: qrect.h:309
unsigned short quint16
Definition: qglobal.h:936
The QPixmapBlurFilter class provides blur filtering for pixmaps.
The QImage class provides a hardware-independent image representation that allows direct access to th...
Definition: qimage.h:87
static const char * data(const QByteArray &arr)
unsigned int uint
Definition: qglobal.h:996
const QTransform & deviceTransform() const
Returns the matrix that transforms from logical coordinates to device coordinates of the platform dep...
Definition: qpainter.cpp:9579
QPaintEngine * paintEngine() const
Returns the paint engine that the painter is currently operating on if the painter is active; otherwi...
Definition: qpainter.cpp:1991
QTransform combinedTransform() const
Returns the transformation matrix combining the current window/viewport and world transformation...
Definition: qpainter.cpp:9669
qreal blurRadius() const
Returns the radius in pixels of the blur on the drop shadow.
int depth() const
Returns the depth of the image.
Definition: qimage.cpp:1620
QRectF adjusted(qreal x1, qreal y1, qreal x2, qreal y2) const
Returns a new rectangle with dx1, dy1, dx2 and dy2 added respectively to the existing coordinates of ...
Definition: qrect.h:781
QPixmapConvolutionFilter(QObject *parent=0)
Constructs a pixmap convolution filter.
qreal qPow(qreal x, qreal y)
Definition: qmath.h:244
QRect toRect() const
Returns a QRect based on the values of this rectangle.
Definition: qrect.h:845
QImage alphaChannel() const
Returns the alpha channel of the image as a new grayscale QImage in which each pixel&#39;s red...
Definition: qimage.cpp:6430
#define AVG16(a, b)
void setColor(const QColor &color)
Sets the color of the colorize filter to the color specified.
QPixmapFilter::FilterType type
QSize size() const
Returns the size of the image, i.
Definition: qimage.cpp:1587
int rows() const
Gets the number of rows in the convolution kernel.
Q_GUI_EXPORT_INLINE int qGray(int r, int g, int b)
Definition: qrgb.h:75
uchar * bits()
Returns a pointer to the first pixel data.
Definition: qimage.cpp:1946
int top() const
Returns the y-coordinate of the rectangle&#39;s top edge.
Definition: qrect.h:243
int width() const
Returns the width of the image.
Definition: qimage.cpp:1557
QGraphicsBlurEffect::BlurHints blurHints() const
Gets the blur hints of the blur filter.
int columns() const
Gets the number of columns in the convolution kernel.
#define Q_DECLARE_PUBLIC(Class)
Definition: qglobal.h:2477
QImage convertToFormat(Format f, Qt::ImageConversionFlags flags=Qt::AutoColor) const Q_REQUIRED_RESULT
Returns a copy of the image in the given format.
Definition: qimage.cpp:3966
int right() const
Returns the x-coordinate of the rectangle&#39;s right edge.
Definition: qrect.h:246
const QTransform & worldTransform() const
Returns the world transformation matrix.
Definition: qpainter.cpp:9652
static void convolute(QImage *destImage, const QPointF &pos, const QImage &srcImage, const QRectF &srcRect, QPainter::CompositionMode mode, qreal *kernel, int kernelWidth, int kernelHeight)
void setCompositionMode(CompositionMode mode)
Sets the composition mode to the given mode.
Definition: qpainter.cpp:2422
QRectF boundingRectFor(const QRectF &rect) const
#define Z_MASK
void Q_GUI_QWS_EXPORT qt_memrotate270(const quint32 *, int, int, int, quint32 *, int)
QColor color() const
Returns the color of the drop shadow.
The QPixmapFilter class provides the basic functionality for pixmap filter classes.
~QPixmapDropShadowFilter()
Destroys drop shadow filter.
QObject * parent() const
Returns a pointer to the parent object.
Definition: qobject.h:273
#define AVG(a, b)
The QPoint class defines a point in the plane using integer precision.
Definition: qpoint.h:53
QRectF united(const QRectF &other) const
Returns the bounding rectangle of this rectangle and the given rectangle.
Definition: qrect.h:828
Q_DECL_CONSTEXPR const T & qBound(const T &min, const T &val, const T &max)
Definition: qglobal.h:1219
unsigned int quint32
Definition: qglobal.h:938
The QPixmapDropShadowFilter class is a convenience class for drawing pixmaps with drop shadows...
QRectF boundingRectFor(const QRectF &rect) const
The QRect class defines a rectangle in the plane using integer precision.
Definition: qrect.h:58
QFuture< void > filter(Sequence &sequence, FilterFunction filterFunction)
void setWorldTransform(const QTransform &matrix, bool combine=false)
Sets the world transformation matrix.
Definition: qpainter.cpp:9630
int height() const
Returns the height of the image.
Definition: qimage.cpp:1572
void moveTo(qreal x, qreal t)
Moves the rectangle, leaving the top-left corner at the given position (x, y).
Definition: qrect.h:728
qreal dx() const
Returns the horizontal translation factor.
Definition: qtransform.h:273
QRect rect() const
Returns the pixmap&#39;s enclosing rectangle.
Definition: qpixmap.cpp:676
int y() const
Returns the y coordinate of this point.
Definition: qpoint.h:131
void drawImage(const QRectF &targetRect, const QImage &image, const QRectF &sourceRect, Qt::ImageConversionFlags flags=Qt::AutoColor)
Definition: qpainter.cpp:5936
QPixmapFilter(QPixmapFilterPrivate &d, FilterType type, QObject *parent)
qreal y() const
Returns the y-coordinate of this point.
Definition: qpoint.h:287
quint16 index
The QPixmap class is an off-screen image representation that can be used as a paint device...
Definition: qpixmap.h:71
QObject * parent
Definition: qobject.h:92
The QPixmapConvolutionFilter class provides convolution filtering for pixmaps.
void scale(qreal sx, qreal sy)
Scales the coordinate system by ({sx}, {sy}).
Definition: qpainter.cpp:3234
void drawPixmap(const QRectF &targetRect, const QPixmap &pixmap, const QRectF &sourceRect)
Draws the rectangular portion source of the given pixmap into the given target in the paint device...
Definition: qpainter.cpp:5619
static Q_DECL_CONSTEXPR bool qFuzzyIsNull(double d)
Definition: qglobal.h:2043
void setRadius(qreal radius)
Sets the radius of the blur filter.
int x() const
Returns the x coordinate of this point.
Definition: qpoint.h:128
The QRasterPaintEngine class enables hardware acceleration of painting operations in Qt for Embedded ...
void setOpacity(qreal opacity)
Sets the opacity of the painter to opacity.
Definition: qpainter.cpp:2139
void setAlphaChannel(const QImage &alphaChannel)
Sets the alpha channel of this image to the given alphaChannel.
Definition: qimage.cpp:6329
bool isNull() const
Returns true if this is a null pixmap; otherwise returns false.
Definition: qpixmap.cpp:615
QRectF translated(qreal dx, qreal dy) const
Returns a copy of the rectangle that is translated dx along the x axis and dy along the y axis...
Definition: qrect.h:740
QPixmap copy(int x, int y, int width, int height) const
Returns a deep copy of the subset of the pixmap that is specified by the rectangle QRect( x...
Definition: qpixmap.h:302
bool isEmpty() const
Returns true if the rectangle is empty, otherwise returns false.
Definition: qrect.h:658
void draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect=QRectF()) const
qreal strength() const
Gets the strength of the colorize filter, 1.0 means full colorized while 0.0 equals to no filtering a...
void draw(QPainter *p, const QPointF &pos, const QPixmap &px, const QRectF &src=QRectF()) const
bool isNull() const
Returns true if the rectangle is a null rectangle, otherwise returns false.
Definition: qrect.h:655
#define ZA_MASK
QPointF offset() const
Returns the shadow offset in pixels.
void expblur(QImage &img, qreal radius, bool improvedQuality=false, int transposed=0)
Q_DECL_CONSTEXPR int qRound(qreal d)
Definition: qglobal.h:1203
void draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect=QRectF()) const
void draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect=QRectF()) const
bool end()
Ends painting.
Definition: qpainter.cpp:1929
uchar * scanLine(int)
Returns a pointer to the pixel data at the scanline with index i.
Definition: qimage.cpp:1886
void fillRect(const QRectF &, const QBrush &)
Fills the given rectangle with the brush specified.
Definition: qpainter.cpp:7420
~QPixmapBlurFilter()
Destructor of pixmap blur filter.
The QTransform class specifies 2D transformations of a coordinate system.
Definition: qtransform.h:65
const qreal radiusScale
QPoint topLeft() const
Returns the position of the rectangle&#39;s top-left corner.
Definition: qrect.h:288
void translate(const QPointF &offset)
Translates the coordinate system by the given offset; i.e.
Definition: qpainter.cpp:3311