diff options
author | Allan Sandfeld Jensen <allan.jensen@digia.com> | 2014-07-24 15:54:58 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@digia.com> | 2014-07-31 20:16:09 +0200 |
commit | d8dc664b945d8832eab97c5df0e1ea47ebf895fd (patch) | |
tree | be9fe35ad391540c7fc8e328d22cc01b5e4592da /src/gui | |
parent | 1852ece715b6eefadd8c9bf048d5f8d147f08b5b (diff) |
Ensure valid data after QImage::invertPixels
QImage::invertPixels may produce invalid data after inversions of
images with premultiplied alpha, because the inverted colors will be
larger than the alpha.
This patch converts any image with a premultiplied alpha channel to
ARGB32 before inverting the pixels, and then back to the original
format after the inversion.
Support is added for correct inversion of RGBA8888 and RGB30 formats.
Task-number: QTBUG-39901
Change-Id: Ief24c55f495e67ef2ad6429b5b418d02963a64dd
Reviewed-by: Gunnar Sletta <gunnar.sletta@jollamobile.com>
Diffstat (limited to 'src/gui')
-rw-r--r-- | src/gui/image/qimage.cpp | 50 |
1 files changed, 47 insertions, 3 deletions
diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 8c7c446e96..0d10dd77d2 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -1806,6 +1806,9 @@ void QImage::fill(const QColor &color) is the case for a 1-bit image. Note that the color table is \e not changed. + If the image has a premultiplied alpha channel, the image is first + converted to ARGB32 to be inverted and then converted back. + \sa {QImage#Image Transformations}{Image Transformations} */ @@ -1820,8 +1823,15 @@ void QImage::invertPixels(InvertMode mode) if (!d) return; - if (depth() != 32) { - // number of used bytes pr line + QImage::Format originalFormat = d->format; + // Inverting premultiplied pixels would produce invalid image data. + if (hasAlphaChannel() && qPixelLayouts[d->format].premultiplied) { + if (!d->convertInPlace(QImage::Format_ARGB32, 0)) + *this = convertToFormat(QImage::Format_ARGB32); + } + + if (depth() < 32) { + // This assumes no alpha-channel as the only formats with non-premultipled alpha are 32bit. int bpl = (d->width * d->depth + 7) / 8; int pad = d->bytes_per_line - bpl; uchar *sl = d->data; @@ -1833,10 +1843,44 @@ void QImage::invertPixels(InvertMode mode) } else { quint32 *p = (quint32*)d->data; quint32 *end = (quint32*)(d->data + d->nbytes); - uint xorbits = (mode == InvertRgba) ? 0xffffffff : 0x00ffffff; + quint32 xorbits = 0xffffffff; + switch (d->format) { + case QImage::Format_RGBA8888: + if (mode == InvertRgba) + break; + // no break + case QImage::Format_RGBX8888: +#if Q_BYTE_ORDER == Q_BIG_ENDIAN + xorbits = 0xffffff00; + break; +#else + xorbits = 0x00ffffff; + break; +#endif + case QImage::Format_ARGB32: + if (mode == InvertRgba) + break; + // no break + case QImage::Format_RGB32: + xorbits = 0x00ffffff; + break; + case QImage::Format_BGR30: + case QImage::Format_RGB30: + xorbits = 0x3fffffff; + break; + default: + Q_UNREACHABLE(); + xorbits = 0; + break; + } while (p < end) *p++ ^= xorbits; } + + if (originalFormat != d->format) { + if (!d->convertInPlace(originalFormat, 0)) + *this = convertToFormat(originalFormat); + } } // Windows defines these |