diff options
author | Allan Sandfeld Jensen <allan.jensen@digia.com> | 2014-05-26 12:07:18 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@digia.com> | 2014-07-04 14:03:46 +0200 |
commit | 3acd4b546ded7523f65d60cee6f3809113a91a16 (patch) | |
tree | ac526a90c4b39229ea5ec4c80b779ca8a4b66c24 /src/gui/image | |
parent | 715b41ce48c9dd78eec3223606e9ca5193cf5bad (diff) |
QImage support for RGB30 formats
Adds basic support for 10-bit per color channel formats to QImage
and the XCB plugin. This will make it possible to paint to and from
these formats, but only at 8-bit per color channel accuracy.
This also fixes Qt5 applications on X11 with native 30bit depth.
[ChangeLog][QtGui][QImage] Added support for 10-bit per color channel image formats.
Task-number: QTBUG-25998
Change-Id: I93ccd3c74bfbb0bd94b352476e5fe58a94119e1f
Reviewed-by: Gunnar Sletta <gunnar.sletta@jollamobile.com>
Diffstat (limited to 'src/gui/image')
-rw-r--r-- | src/gui/image/qbmphandler.cpp | 4 | ||||
-rw-r--r-- | src/gui/image/qimage.cpp | 147 | ||||
-rw-r--r-- | src/gui/image/qimage.h | 4 | ||||
-rw-r--r-- | src/gui/image/qimage_conversions.cpp | 603 | ||||
-rw-r--r-- | src/gui/image/qimage_p.h | 6 | ||||
-rw-r--r-- | src/gui/image/qpixmap.cpp | 3 | ||||
-rw-r--r-- | src/gui/image/qppmhandler.cpp | 4 |
7 files changed, 735 insertions, 36 deletions
diff --git a/src/gui/image/qbmphandler.cpp b/src/gui/image/qbmphandler.cpp index bb79a139b3..036d0615e3 100644 --- a/src/gui/image/qbmphandler.cpp +++ b/src/gui/image/qbmphandler.cpp @@ -798,6 +798,8 @@ bool QBmpHandler::write(const QImage &img) case QImage::Format_ARGB4444_Premultiplied: case QImage::Format_RGBA8888: case QImage::Format_RGBA8888_Premultiplied: + case QImage::Format_A2BGR30_Premultiplied: + case QImage::Format_A2RGB30_Premultiplied: image = img.convertToFormat(QImage::Format_ARGB32); break; case QImage::Format_RGB16: @@ -806,6 +808,8 @@ bool QBmpHandler::write(const QImage &img) case QImage::Format_RGB555: case QImage::Format_RGB444: case QImage::Format_RGBX8888: + case QImage::Format_BGR30: + case QImage::Format_RGB30: image = img.convertToFormat(QImage::Format_RGB32); break; default: diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index b0b6b27b71..d8c3a8c2eb 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -222,6 +222,16 @@ bool QImageData::checkForAlphaPixels() const } } break; + case QImage::Format_A2BGR30_Premultiplied: + case QImage::Format_A2RGB30_Premultiplied: { + uchar *bits = data; + for (int y=0; y<height && !has_alpha_pixels; ++y) { + for (int x=0; x<width; ++x) + has_alpha_pixels |= (((uint *)bits)[x] & 0xc0000000) != 0xc0000000; + bits += bytes_per_line; + } + } break; + case QImage::Format_ARGB8555_Premultiplied: case QImage::Format_ARGB8565_Premultiplied: { uchar *bits = data; @@ -701,6 +711,10 @@ bool QImageData::checkForAlphaPixels() const is the same on any architecture if read as bytes 0xRR,0xGG,0xBB,0xAA. \value Format_RGBA8888_Premultiplied The image is stored using a premultiplied 32-bit byte-ordered RGBA format (8-8-8-8). + \value Format_BGR30 The image is stored using a 32-bit BGR format (x-10-10-10). + \value Format_A2BGR30_Premultiplied The image is stored using a 32-bit premultiplied ABGR format (2-10-10-10). + \value Format_RGB30 The image is stored using a 32-bit RGB format (x-10-10-10). + \value Format_A2RGB30_Premultiplied The image is stored using a 32-bit premultiplied ARGB format (2-10-10-10). \note Drawing into a QImage with QImage::Format_Indexed8 is not supported. @@ -708,6 +722,9 @@ bool QImageData::checkForAlphaPixels() const \note Do not render into ARGB32 images using QPainter. Using QImage::Format_ARGB32_Premultiplied is significantly faster. + \note Formats with more than 8 bit per color channel will only be processed by the raster engine using 8 bit + per color. + \sa format(), convertToFormat() */ @@ -1670,6 +1687,8 @@ void QImage::fill(uint pixel) #else pixel |= 0x000000ff; #endif + if (d->format == Format_BGR30 || d->format == Format_RGB30) + pixel |= 0xc0000000; qt_rectfill<uint>(reinterpret_cast<uint*>(d->data), pixel, 0, 0, d->width, d->height, d->bytes_per_line); @@ -1736,6 +1755,14 @@ void QImage::fill(const QColor &color) case QImage::Format_RGBA8888_Premultiplied: fill(ARGB2RGBA(qPremultiply(color.rgba()))); break; + case QImage::Format_BGR30: + case QImage::Format_A2BGR30_Premultiplied: + fill(qConvertArgb32ToA2rgb30<PixelOrderBGR>(color.rgba())); + break; + case QImage::Format_RGB30: + case QImage::Format_A2RGB30_Premultiplied: + fill(qConvertArgb32ToA2rgb30<PixelOrderRGB>(color.rgba())); + break; case QImage::Format_RGB16: fill((uint) qConvertRgb32To16(color.rgba())); break; @@ -2142,6 +2169,12 @@ QRgb QImage::pixel(int x, int y) const case Format_RGBA8888: // Match ARGB32 behavior. case Format_RGBA8888_Premultiplied: return RGBA2ARGB(reinterpret_cast<const quint32 *>(s)[x]); + case Format_BGR30: + case Format_A2BGR30_Premultiplied: + return qConvertA2rgb30ToArgb32<PixelOrderBGR>(reinterpret_cast<const quint32 *>(s)[x]); + case Format_RGB30: + case Format_A2RGB30_Premultiplied: + return qConvertA2rgb30ToArgb32<PixelOrderRGB>(reinterpret_cast<const quint32 *>(s)[x]); case Format_RGB16: return qConvertRgb16To32(reinterpret_cast<const quint16 *>(s)[x]); default: @@ -2232,6 +2265,18 @@ void QImage::setPixel(int x, int y, uint index_or_rgb) case Format_RGBA8888_Premultiplied: ((uint *)s)[x] = ARGB2RGBA(index_or_rgb); return; + case Format_BGR30: + ((uint *)s)[x] = qConvertRgb32ToRgb30<PixelOrderBGR>(index_or_rgb); + return; + case Format_A2BGR30_Premultiplied: + ((uint *)s)[x] = qConvertArgb32ToA2rgb30<PixelOrderBGR>(index_or_rgb); + return; + case Format_RGB30: + ((uint *)s)[x] = qConvertRgb32ToRgb30<PixelOrderRGB>(index_or_rgb); + return; + case Format_A2RGB30_Premultiplied: + ((uint *)s)[x] = qConvertArgb32ToA2rgb30<PixelOrderRGB>(index_or_rgb); + return; case Format_Invalid: case NImageFormats: Q_ASSERT(false); @@ -2959,6 +3004,23 @@ QImage QImage::rgbSwapped_helper() const } } break; + case Format_BGR30: + case Format_A2BGR30_Premultiplied: + case Format_RGB30: + case Format_A2RGB30_Premultiplied: + res = QImage(d->width, d->height, d->format); + QIMAGE_SANITYCHECK_MEMORY(res); + for (int i = 0; i < d->height; i++) { + uint *q = (uint*)res.scanLine(i); + const uint *p = (const uint*)constScanLine(i); + const uint *end = p + d->width; + while (p < end) { + *q = qRgbSwapRgb30(*p); + p++; + q++; + } + } + break; default: res = QImage(d->width, d->height, d->format); rgbSwapped_generic(d->width, d->height, this, &res, &qPixelLayouts[d->format]); @@ -3019,6 +3081,19 @@ void QImage::rgbSwapped_inplace() } } break; + case Format_BGR30: + case Format_A2BGR30_Premultiplied: + case Format_RGB30: + case Format_A2RGB30_Premultiplied: + for (int i = 0; i < d->height; i++) { + uint *p = (uint*)scanLine(i); + uint *end = p + d->width; + while (p < end) { + *p = qRgbSwapRgb30(*p); + p++; + } + } + break; default: rgbSwapped_generic(d->width, d->height, this, this, &qPixelLayouts[d->format]); break; @@ -4044,6 +4119,8 @@ bool QImage::hasAlphaChannel() const || d->format == Format_ARGB4444_Premultiplied || d->format == Format_RGBA8888 || d->format == Format_RGBA8888_Premultiplied + || d->format == Format_A2BGR30_Premultiplied + || d->format == Format_A2RGB30_Premultiplied || (d->has_alpha_clut && (d->format == Format_Indexed8 || d->format == Format_Mono || d->format == Format_MonoLSB))); @@ -4069,6 +4146,10 @@ int QImage::bitPlaneCount() const switch (d->format) { case QImage::Format_Invalid: break; + case QImage::Format_BGR30: + case QImage::Format_RGB30: + bpc = 30; + break; case QImage::Format_RGB32: case QImage::Format_RGBX8888: bpc = 24; @@ -4122,6 +4203,10 @@ static QImage rotated90(const QImage &image) { case QImage::Format_RGBX8888: case QImage::Format_RGBA8888: case QImage::Format_RGBA8888_Premultiplied: + case QImage::Format_BGR30: + case QImage::Format_A2BGR30_Premultiplied: + case QImage::Format_RGB30: + case QImage::Format_A2RGB30_Premultiplied: qt_memrotate270(reinterpret_cast<const quint32*>(image.bits()), w, h, image.bytesPerLine(), reinterpret_cast<quint32*>(out.bits()), @@ -4184,6 +4269,10 @@ static QImage rotated270(const QImage &image) { case QImage::Format_RGBX8888: case QImage::Format_RGBA8888: case QImage::Format_RGBA8888_Premultiplied: + case QImage::Format_BGR30: + case QImage::Format_A2BGR30_Premultiplied: + case QImage::Format_RGB30: + case QImage::Format_A2RGB30_Premultiplied: qt_memrotate90(reinterpret_cast<const quint32*>(image.bits()), w, h, image.bytesPerLine(), reinterpret_cast<quint32*>(out.bits()), @@ -4332,6 +4421,12 @@ QImage QImage::transformed(const QTransform &matrix, Qt::TransformationMode mode case QImage::Format_RGBX8888: target_format = Format_RGBA8888_Premultiplied; break; + case QImage::Format_BGR30: + target_format = Format_A2BGR30_Premultiplied; + break; + case QImage::Format_RGB30: + target_format = Format_A2RGB30_Premultiplied; + break; default: target_format = Format_ARGB32_Premultiplied; break; @@ -4741,6 +4836,58 @@ static const QPixelFormat pixelformats[] = { /*PREMULTIPLIED*/ QPixelFormat::Premultiplied, /*INTERPRETATION*/ QPixelFormat::UnsignedByte, /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian), + //QImage::Format_BGR30: + QPixelFormat(QPixelFormat::BGR, + /*RED*/ 10, + /*GREEN*/ 10, + /*BLUE*/ 10, + /*FOURTH*/ 0, + /*FIFTH*/ 0, + /*ALPHA*/ 2, + /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha, + /*ALPHA POSITION*/ QPixelFormat::AtBeginning, + /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied, + /*INTERPRETATION*/ QPixelFormat::UnsignedInteger, + /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian), + //QImage::Format_A2BGR30_Premultiplied: + QPixelFormat(QPixelFormat::BGR, + /*RED*/ 10, + /*GREEN*/ 10, + /*BLUE*/ 10, + /*FOURTH*/ 0, + /*FIFTH*/ 0, + /*ALPHA*/ 2, + /*ALPHA USAGE*/ QPixelFormat::UsesAlpha, + /*ALPHA POSITION*/ QPixelFormat::AtBeginning, + /*PREMULTIPLIED*/ QPixelFormat::Premultiplied, + /*INTERPRETATION*/ QPixelFormat::UnsignedInteger, + /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian), + //QImage::Format_RGB30: + QPixelFormat(QPixelFormat::RGB, + /*RED*/ 10, + /*GREEN*/ 10, + /*BLUE*/ 10, + /*FOURTH*/ 0, + /*FIFTH*/ 0, + /*ALPHA*/ 2, + /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha, + /*ALPHA POSITION*/ QPixelFormat::AtBeginning, + /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied, + /*INTERPRETATION*/ QPixelFormat::UnsignedInteger, + /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian), + //QImage::Format_A2RGB30_Premultiplied: + QPixelFormat(QPixelFormat::RGB, + /*RED*/ 10, + /*GREEN*/ 10, + /*BLUE*/ 10, + /*FOURTH*/ 0, + /*FIFTH*/ 0, + /*ALPHA*/ 2, + /*ALPHA USAGE*/ QPixelFormat::UsesAlpha, + /*ALPHA POSITION*/ QPixelFormat::AtBeginning, + /*PREMULTIPLIED*/ QPixelFormat::Premultiplied, + /*INTERPRETATION*/ QPixelFormat::UnsignedInteger, + /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian), }; Q_STATIC_ASSERT(sizeof(pixelformats) / sizeof(*pixelformats) == QImage::NImageFormats); diff --git a/src/gui/image/qimage.h b/src/gui/image/qimage.h index 365a7873a4..62f9f5cce2 100644 --- a/src/gui/image/qimage.h +++ b/src/gui/image/qimage.h @@ -124,6 +124,10 @@ public: Format_Grayscale2, Format_Grayscale2LSB #endif + Format_BGR30, + Format_A2BGR30_Premultiplied, + Format_RGB30, + Format_A2RGB30_Premultiplied, #ifndef Q_QDOC NImageFormats #endif diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp index 11c4b6d504..195b56afbe 100644 --- a/src/gui/image/qimage_conversions.cpp +++ b/src/gui/image/qimage_conversions.cpp @@ -172,6 +172,35 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im return true; } +static void convert_passthrough(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const quint32 *src_data = (quint32 *) src->data; + quint32 *dest_data = (quint32 *) dest->data; + + for (int i = 0; i < src->height; ++i) { + const quint32 *end = src_data + src->width; + while (src_data < end) { + *dest_data = *src_data; + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +} + +template<QImage::Format Format> +static bool convert_passthrough_inplace(QImageData *data, Qt::ImageConversionFlags) +{ + data->format = Format; + return true; +} + static void convert_ARGB_to_ARGB_PM(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) { Q_ASSERT(src->format == QImage::Format_ARGB32 || src->format == QImage::Format_RGBA8888); @@ -404,6 +433,292 @@ static bool convert_RGBA_to_ARGB_PM_inplace(QImageData *data, Qt::ImageConversio return true; } +template<QtPixelOrder PixelOrder> +static void convert_RGB_to_RGB30(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + + Q_ASSERT(src->format == QImage::Format_RGB32 || src->format == QImage::Format_ARGB32); + Q_ASSERT(dest->format == QImage::Format_BGR30 || dest->format == QImage::Format_A2BGR30_Premultiplied + || dest->format == QImage::Format_RGB30 || dest->format == QImage::Format_A2RGB30_Premultiplied); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const quint32 *src_data = (quint32 *) src->data; + quint32 *dest_data = (quint32 *) dest->data; + + for (int i = 0; i < src->height; ++i) { + const quint32 *end = src_data + src->width; + while (src_data < end) { + *dest_data = qConvertRgb32ToRgb30<PixelOrder>(*src_data); + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +} + +template<QtPixelOrder PixelOrder> +static void convert_RGB30_to_RGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_BGR30 || src->format == QImage::Format_RGB30); + Q_ASSERT(dest->format == QImage::Format_RGB32 || dest->format == QImage::Format_ARGB32 || dest->format == QImage::Format_ARGB32_Premultiplied); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const quint32 *src_data = (quint32 *) src->data; + quint32 *dest_data = (quint32 *) dest->data; + + for (int i = 0; i < src->height; ++i) { + const quint32 *end = src_data + src->width; + while (src_data < end) { + *dest_data = qConvertA2rgb30ToArgb32<PixelOrder>(*src_data); + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +} + +template<QtPixelOrder PixelOrder> +static void convert_A2RGB30_PM_to_RGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_A2RGB30_Premultiplied || src->format == QImage::Format_A2BGR30_Premultiplied); + Q_ASSERT(dest->format == QImage::Format_RGB32); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const quint32 *src_data = (quint32 *) src->data; + quint32 *dest_data = (quint32 *) dest->data; + + for (int i = 0; i < src->height; ++i) { + const quint32 *end = src_data + src->width; + while (src_data < end) { + *dest_data = 0xff000000 | qUnpremultiply(qConvertA2rgb30ToArgb32<PixelOrder>(*src_data)); + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +} + +template<QtPixelOrder PixelOrder> +static void convert_ARGB_PM_to_RGB30(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_ARGB32_Premultiplied); + Q_ASSERT(dest->format == QImage::Format_BGR30 || dest->format == QImage::Format_RGB30); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const quint32 *src_data = (quint32 *) src->data; + quint32 *dest_data = (quint32 *) dest->data; + + for (int i = 0; i < src->height; ++i) { + const quint32 *end = src_data + src->width; + while (src_data < end) { + *dest_data = qConvertRgb32ToRgb30<PixelOrder>(qUnpremultiply(*src_data)); + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +} + +template<QtPixelOrder PixelOrder> +static void convert_ARGB_to_A2RGB30(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_ARGB32_Premultiplied); + Q_ASSERT(dest->format == QImage::Format_A2BGR30_Premultiplied || dest->format == QImage::Format_A2RGB30_Premultiplied); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const quint32 *src_data = (quint32 *) src->data; + quint32 *dest_data = (quint32 *) dest->data; + + for (int i = 0; i < src->height; ++i) { + const quint32 *end = src_data + src->width; + while (src_data < end) { + *dest_data = qConvertArgb32ToA2rgb30<PixelOrder>(*src_data); + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +} + +template<QtPixelOrder PixelOrder> +static void convert_A2RGB30_to_ARGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_A2BGR30_Premultiplied || src->format == QImage::Format_A2RGB30_Premultiplied); + Q_ASSERT(dest->format == QImage::Format_ARGB32_Premultiplied); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const quint32 *src_data = (quint32 *) src->data; + quint32 *dest_data = (quint32 *) dest->data; + + for (int i = 0; i < src->height; ++i) { + const quint32 *end = src_data + src->width; + while (src_data < end) { + *dest_data = qConvertA2rgb30ToArgb32<PixelOrder>(*src_data); + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +} + +static inline uint qUnpremultiplyRgb30(uint rgb30) +{ + const uint a = rgb30 >> 30; + switch (a) { + case 0: + return 0; + case 1: { + uint rgb = rgb30 & 0x3fffffff; + rgb *= 3; + return (a << 30) | rgb; + } + case 2: { + uint rgb = rgb30 & 0x3fffffff; + rgb += rgb >> 1; + return (a << 30) | rgb; + } + case 3: + return rgb30; + } + Q_UNREACHABLE(); + return 0; +} + +static void convert_A2RGB30_PM_to_RGB30(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_A2RGB30_Premultiplied || src->format == QImage::Format_A2BGR30_Premultiplied); + Q_ASSERT(dest->format == QImage::Format_RGB30 || dest->format == QImage::Format_BGR30); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const quint32 *src_data = (quint32 *) src->data; + quint32 *dest_data = (quint32 *) dest->data; + + for (int i = 0; i < src->height; ++i) { + const quint32 *end = src_data + src->width; + while (src_data < end) { + *dest_data = 0xc0000000 | qUnpremultiplyRgb30(*src_data); + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +} + +static bool convert_A2RGB30_PM_to_RGB30_inplace(QImageData *data, Qt::ImageConversionFlags) +{ + Q_ASSERT(data->format == QImage::Format_A2RGB30_Premultiplied || data->format == QImage::Format_A2BGR30_Premultiplied); + + const int pad = (data->bytes_per_line >> 2) - data->width; + uint *rgb_data = (uint *) data->data; + + for (int i = 0; i < data->height; ++i) { + const uint *end = rgb_data + data->width; + while (rgb_data < end) { + *rgb_data = 0xc0000000 | qUnpremultiplyRgb30(*rgb_data); + ++rgb_data; + } + rgb_data += pad; + } + + if (data->format == QImage::Format_A2RGB30_Premultiplied) + data->format = QImage::Format_RGB30; + else + data->format = QImage::Format_BGR30; + return true; +} + +static void convert_BGR30_to_RGB30(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags) +{ + Q_ASSERT(src->format == QImage::Format_RGB30 || src->format == QImage::Format_BGR30 || + src->format == QImage::Format_A2RGB30_Premultiplied || src->format == QImage::Format_A2BGR30_Premultiplied); + Q_ASSERT(dest->format == QImage::Format_RGB30 || dest->format == QImage::Format_BGR30 || + dest->format == QImage::Format_A2RGB30_Premultiplied || dest->format == QImage::Format_A2BGR30_Premultiplied); + Q_ASSERT(src->width == dest->width); + Q_ASSERT(src->height == dest->height); + + const int src_pad = (src->bytes_per_line >> 2) - src->width; + const int dest_pad = (dest->bytes_per_line >> 2) - dest->width; + const quint32 *src_data = (quint32 *) src->data; + quint32 *dest_data = (quint32 *) dest->data; + + for (int i = 0; i < src->height; ++i) { + const quint32 *end = src_data + src->width; + while (src_data < end) { + *dest_data = qRgbSwapRgb30(*src_data); + ++src_data; + ++dest_data; + } + src_data += src_pad; + dest_data += dest_pad; + } +} + +static bool convert_BGR30_to_RGB30_inplace(QImageData *data, Qt::ImageConversionFlags) +{ + Q_ASSERT(data->format == QImage::Format_RGB30 || data->format == QImage::Format_BGR30 || + data->format == QImage::Format_A2RGB30_Premultiplied || data->format == QImage::Format_A2BGR30_Premultiplied); + + const int pad = (data->bytes_per_line >> 2) - data->width; + uint *rgb_data = (uint *) data->data; + + for (int i = 0; i < data->height; ++i) { + const uint *end = rgb_data + data->width; + while (rgb_data < end) { + *rgb_data = qRgbSwapRgb30(*rgb_data); + ++rgb_data; + } + rgb_data += pad; + } + + switch (data->format) { + case QImage::Format_BGR30: + data->format = QImage::Format_RGB30; + break; + case QImage::Format_A2BGR30_Premultiplied: + data->format = QImage::Format_A2RGB30_Premultiplied; + break; + case QImage::Format_RGB30: + data->format = QImage::Format_BGR30; + break; + case QImage::Format_A2RGB30_Premultiplied: + data->format = QImage::Format_A2BGR30_Premultiplied; + break; + default: + Q_UNREACHABLE(); + data->format = QImage::Format_Invalid; + return false; + } + return true; +} + static bool convert_indexed8_to_ARGB_PM_inplace(QImageData *data, Qt::ImageConversionFlags) { Q_ASSERT(data->format == QImage::Format_Indexed8); @@ -1557,7 +1872,7 @@ static void convert_Mono_to_Indexed8(QImageData *dest, const QImageData *src, Qt Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormats] = { { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, @@ -1578,7 +1893,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0 + 0, 0, 0, 0, 0 }, // Format_Mono { @@ -1600,7 +1915,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0 + 0, 0, 0, 0, 0 }, // Format_MonoLSB { @@ -1622,7 +1937,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0 + 0, 0, 0, 0, 0 }, // Format_Indexed8 { @@ -1644,7 +1959,11 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, convert_RGB_to_RGBA, convert_RGB_to_RGBA, - convert_RGB_to_RGBA + convert_RGB_to_RGBA, + convert_RGB_to_RGB30<PixelOrderBGR>, + convert_RGB_to_RGB30<PixelOrderBGR>, + convert_RGB_to_RGB30<PixelOrderRGB>, + convert_RGB_to_RGB30<PixelOrderRGB>, }, // Format_RGB32 { @@ -1667,6 +1986,10 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat convert_ARGB_to_RGBx, convert_ARGB_to_RGBA, convert_ARGB_to_RGBA_PM, + convert_RGB_to_RGB30<PixelOrderBGR>, + 0, + convert_RGB_to_RGB30<PixelOrderRGB>, + 0, }, // Format_ARGB32 { @@ -1689,6 +2012,10 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat convert_ARGB_PM_to_RGBx, convert_ARGB_PM_to_RGBA, convert_ARGB_to_RGBA, + convert_ARGB_PM_to_RGB30<PixelOrderBGR>, + convert_ARGB_to_A2RGB30<PixelOrderBGR>, + convert_ARGB_PM_to_RGB30<PixelOrderRGB>, + convert_ARGB_to_A2RGB30<PixelOrderRGB>, }, // Format_ARGB32_Premultiplied { @@ -1710,7 +2037,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0 + 0, 0, 0, 0, 0 }, // Format_RGB16 { @@ -1732,7 +2059,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0 + 0, 0, 0, 0, 0 }, // Format_ARGB8565_Premultiplied { @@ -1754,7 +2081,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0 + 0, 0, 0, 0, 0 }, // Format_RGB666 { @@ -1776,7 +2103,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0 + 0, 0, 0, 0, 0 }, // Format_ARGB6666_Premultiplied { @@ -1798,7 +2125,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0 + 0, 0, 0, 0, 0 }, // Format_RGB555 { @@ -1820,7 +2147,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0 + 0, 0, 0, 0, 0 }, // Format_ARGB8555_Premultiplied { @@ -1842,7 +2169,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0 + 0, 0, 0, 0, 0 }, // Format_RGB888 { @@ -1864,7 +2191,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0 + 0, 0, 0, 0, 0 }, // Format_RGB444 { @@ -1885,7 +2212,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0, 0, - 0 + 0, 0, 0, 0, 0 }, // Format_ARGB4444_Premultiplied { 0, @@ -1907,6 +2234,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, mask_alpha_converter_RGBx, mask_alpha_converter_RGBx, + 0, 0, 0, 0 }, // Format_RGBX8888 { 0, @@ -1933,6 +2261,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0 #endif + 0, 0, 0, 0 }, // Format_RGBA8888 { @@ -1961,19 +2290,121 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat 0, 0 #endif - } // Format_RGBA8888_Premultiplied + 0, 0, 0, 0 + }, // Format_RGBA8888_Premultiplied + + { + 0, + 0, + 0, + 0, + convert_RGB30_to_RGB<PixelOrderBGR>, + convert_RGB30_to_RGB<PixelOrderBGR>, + convert_RGB30_to_RGB<PixelOrderBGR>, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + convert_passthrough, + convert_BGR30_to_RGB30, + convert_BGR30_to_RGB30 + }, // Format_BGR30 + { + 0, + 0, + 0, + 0, + convert_A2RGB30_PM_to_RGB<PixelOrderBGR>, + 0, + convert_A2RGB30_to_ARGB<PixelOrderBGR>, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + convert_A2RGB30_PM_to_RGB30, + 0, + 0, + convert_BGR30_to_RGB30 + }, // Format_BGR30A2_Premultiplied + { + 0, + 0, + 0, + 0, + convert_RGB30_to_RGB<PixelOrderRGB>, + convert_RGB30_to_RGB<PixelOrderRGB>, + convert_RGB30_to_RGB<PixelOrderRGB>, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + convert_BGR30_to_RGB30, + convert_BGR30_to_RGB30, + 0, + 0, + convert_passthrough, + }, // Format_RGB30 + { + 0, + 0, + 0, + 0, + convert_A2RGB30_PM_to_RGB<PixelOrderRGB>, + 0, + convert_A2RGB30_to_ARGB<PixelOrderRGB>, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + convert_BGR30_to_RGB30, + convert_A2RGB30_PM_to_RGB30, + 0, + }, // Format_RGB30A2_Premultiplied }; InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QImage::NImageFormats] = { { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_Mono { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_MonoLSB { 0, @@ -1994,7 +2425,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, 0, - 0, + 0, 0, 0, 0, 0 }, // Format_Indexed8 { 0, @@ -2015,7 +2446,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, 0, - 0, + 0, 0, 0, 0, 0 }, // Format_RGB32 { 0, @@ -2040,7 +2471,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, convert_ARGB_to_RGBA_inplace, - 0, + 0, 0, 0, 0, 0 }, // Format_ARGB32 { 0, @@ -2061,34 +2492,35 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, 0, - convert_ARGB_to_RGBA_inplace + convert_ARGB_to_RGBA_inplace, + 0, 0, 0, 0 }, // Format_ARGB32_Premultiplied { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB16 { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_ARGB8565_Premultiplied { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB666 { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_ARGB6666_Premultiplied { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB555 { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_ARGB8555_Premultiplied { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB888 { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_RGB444 { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Format_ARGB4444_Premultiplied { 0, @@ -2108,8 +2540,9 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, 0, - 0, - 0, + convert_passthrough_inplace<QImage::Format_RGBA8888>, + convert_passthrough_inplace<QImage::Format_RGBA8888_Premultiplied>, + 0, 0, 0, 0 }, // Format_RGBX8888 { 0, @@ -2131,6 +2564,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, 0, + 0, 0, 0, 0 }, // Format_RGBA8888 { 0, @@ -2152,7 +2586,108 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma 0, 0, 0, - } // Format_RGBA8888_Premultiplied + 0, 0, 0, 0 + }, // Format_RGBA8888_Premultiplied + { + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + convert_passthrough_inplace<QImage::Format_A2BGR30_Premultiplied>, + convert_BGR30_to_RGB30_inplace, + convert_BGR30_to_RGB30_inplace + }, // Format_BGR30 + { + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + convert_A2RGB30_PM_to_RGB30_inplace, + 0, + 0, + convert_BGR30_to_RGB30_inplace + }, // Format_BGR30A2_Premultiplied + { + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + convert_BGR30_to_RGB30_inplace, + convert_BGR30_to_RGB30_inplace, + 0, + convert_passthrough_inplace<QImage::Format_A2RGB30_Premultiplied> + }, // Format_RGB30 + { + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + convert_BGR30_to_RGB30_inplace, + convert_A2RGB30_PM_to_RGB30_inplace, + 0 + }, // Format_RGB30A2_Premultiplied }; void qInitImageConversions() diff --git a/src/gui/image/qimage_p.h b/src/gui/image/qimage_p.h index 81730b92f2..a22e207812 100644 --- a/src/gui/image/qimage_p.h +++ b/src/gui/image/qimage_p.h @@ -130,7 +130,7 @@ inline int qt_depthForFormat(QImage::Format format) switch(format) { case QImage::Format_Invalid: case QImage::NImageFormats: - Q_ASSERT(false); + Q_UNREACHABLE(); case QImage::Format_Mono: case QImage::Format_MonoLSB: depth = 1; @@ -144,6 +144,10 @@ inline int qt_depthForFormat(QImage::Format format) case QImage::Format_RGBX8888: case QImage::Format_RGBA8888: case QImage::Format_RGBA8888_Premultiplied: + case QImage::Format_BGR30: + case QImage::Format_A2BGR30_Premultiplied: + case QImage::Format_RGB30: + case QImage::Format_A2RGB30_Premultiplied: depth = 32; break; case QImage::Format_RGB555: diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp index c6d8d19bb1..f4222d2360 100644 --- a/src/gui/image/qpixmap.cpp +++ b/src/gui/image/qpixmap.cpp @@ -1511,7 +1511,8 @@ QBitmap QPixmap::mask() const return QBitmap(); const QImage img = toImage(); - const QImage image = (img.depth() < 32 ? img.convertToFormat(QImage::Format_ARGB32_Premultiplied) : img); + bool shouldConvert = (img.format() != QImage::Format_ARGB32 && img.format() != QImage::Format_ARGB32_Premultiplied); + const QImage image = (shouldConvert ? img.convertToFormat(QImage::Format_ARGB32_Premultiplied) : img); const int w = image.width(); const int h = image.height(); diff --git a/src/gui/image/qppmhandler.cpp b/src/gui/image/qppmhandler.cpp index 39f63a620c..64eaf7f19e 100644 --- a/src/gui/image/qppmhandler.cpp +++ b/src/gui/image/qppmhandler.cpp @@ -275,6 +275,8 @@ static bool write_pbm_image(QIODevice *out, const QImage &sourceImage, const QBy case QImage::Format_RGB888: case QImage::Format_RGB444: case QImage::Format_RGBX8888: + case QImage::Format_BGR30: + case QImage::Format_RGB30: image = image.convertToFormat(QImage::Format_RGB32); break; case QImage::Format_ARGB8565_Premultiplied: @@ -283,6 +285,8 @@ static bool write_pbm_image(QIODevice *out, const QImage &sourceImage, const QBy case QImage::Format_ARGB4444_Premultiplied: case QImage::Format_RGBA8888: case QImage::Format_RGBA8888_Premultiplied: + case QImage::Format_A2BGR30_Premultiplied: + case QImage::Format_A2RGB30_Premultiplied: image = image.convertToFormat(QImage::Format_ARGB32); break; default: |