Implement support for 16bpc image formats

Adds support for 16bit per color image formats in QImage. This makes it
possible to read and write 16bpc PNGs, and take full advantage of the
16bpc paint engine.

[ChangeLog][QtGui][QImage] QImage now supports 64bit image formats with
16 bits per color channel, compatible with 16bpc PNG or RGBA16 OpenGL
formats.

Task-number: QTBUG-45858
Change-Id: Icd28bd5868a6efcf65cb5bd56031d42941e04099
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
This commit is contained in:
Allan Sandfeld Jensen 2016-12-07 14:37:12 +01:00
parent 1c623bc6d1
commit 9c9f98f2ff
20 changed files with 1920 additions and 492 deletions

View File

@ -277,6 +277,16 @@ bool QImageData::checkForAlphaPixels() const
bits += bytes_per_line;
}
} break;
case QImage::Format_RGBA64:
case QImage::Format_RGBA64_Premultiplied: {
uchar *bits = data;
for (int y=0; y<height && !has_alpha_pixels; ++y) {
for (int x=0; x<width; ++x) {
has_alpha_pixels |= !(((QRgba64 *)bits)[x].isOpaque());
}
bits += bytes_per_line;
}
} break;
case QImage::Format_RGB32:
case QImage::Format_RGB16:
@ -288,6 +298,7 @@ bool QImageData::checkForAlphaPixels() const
case QImage::Format_BGR30:
case QImage::Format_RGB30:
case QImage::Format_Grayscale8:
case QImage::Format_RGBX64:
break;
case QImage::Format_Invalid:
case QImage::NImageFormats:
@ -651,11 +662,7 @@ bool QImageData::checkForAlphaPixels() const
/*!
\enum QImage::Format
The following image formats are available in Qt. Values from Format_ARGB8565_Premultiplied
to Format_ARGB4444_Premultiplied were added in Qt 4.4. Values Format_RGBX8888, Format_RGBA8888
and Format_RGBA8888_Premultiplied were added in Qt 5.2. Values Format_BGR30, Format_A2BGR30_Premultiplied,
Format_RGB30, Format_A2RGB30_Premultiplied were added in Qt 5.4. Format_Alpha8 and Format_Grayscale8
were added in Qt 5.5.
The following image formats are available in Qt.
See the notes after the table.
\value Format_Invalid The image is invalid.
@ -699,29 +706,32 @@ bool QImageData::checkForAlphaPixels() const
\value Format_ARGB4444_Premultiplied The image is stored using a
premultiplied 16-bit ARGB format (4-4-4-4).
\value Format_RGBX8888 The image is stored using a 32-bit byte-ordered RGB(x) format (8-8-8-8).
This is the same as the Format_RGBA8888 except alpha must always be 255.
This is the same as the Format_RGBA8888 except alpha must always be 255. (added in Qt 5.2)
\value Format_RGBA8888 The image is stored using a 32-bit byte-ordered RGBA format (8-8-8-8).
Unlike ARGB32 this is a byte-ordered format, which means the 32bit
encoding differs between big endian and little endian architectures,
being respectively (0xRRGGBBAA) and (0xAABBGGRR). The order of the colors
is the same on any architecture if read as bytes 0xRR,0xGG,0xBB,0xAA.
is the same on any architecture if read as bytes 0xRR,0xGG,0xBB,0xAA. (added in Qt 5.2)
\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).
\value Format_Alpha8 The image is stored using an 8-bit alpha only format.
\value Format_Grayscale8 The image is stored using an 8-bit grayscale format.
premultiplied 32-bit byte-ordered RGBA format (8-8-8-8). (added in Qt 5.2)
\value Format_BGR30 The image is stored using a 32-bit BGR format (x-10-10-10). (added in Qt 5.4)
\value Format_A2BGR30_Premultiplied The image is stored using a 32-bit premultiplied ABGR format (2-10-10-10). (added in Qt 5.4)
\value Format_RGB30 The image is stored using a 32-bit RGB format (x-10-10-10). (added in Qt 5.4)
\value Format_A2RGB30_Premultiplied The image is stored using a 32-bit premultiplied ARGB format (2-10-10-10). (added in Qt 5.4)
\value Format_Alpha8 The image is stored using an 8-bit alpha only format. (added in Qt 5.5)
\value Format_Grayscale8 The image is stored using an 8-bit grayscale format. (added in Qt 5.5)
\value Format_RGBX64 The image is stored using a 64-bit halfword-ordered RGB(x) format (16-16-16-16).
This is the same as the Format_RGBX64 except alpha must always be 65535. (added in Qt 5.12)
\value Format_RGBA64 The image is stored using a 64-bit halfword-ordered RGBA format (16-16-16-16). (added in Qt 5.12)
\value Format_RGBA64_Premultiplied The image is stored using a premultiplied 64-bit halfword-ordered
RGBA format (16-16-16-16). (added in Qt 5.12)
\note Drawing into a QImage with QImage::Format_Indexed8 is not
supported.
\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.
\note Avoid most rendering directly to most of these formats using QPainter. Rendering
is best optimized to the \c Format_RGB32 and \c Format_ARGB32_Premultiplied formats, and secondarily for rendering to the
\c Format_RGB16, \c Format_RGBX8888, \c Format_RGBA8888_Premultiplied, \c Format_RGBX64 and \c Format_RGBA64_Premultiplied formats
\sa format(), convertToFormat()
*/
@ -1708,6 +1718,10 @@ void QImage::fill(uint pixel)
qt_rectfill<quint24>(reinterpret_cast<quint24*>(d->data), pixel,
0, 0, d->width, d->height, d->bytes_per_line);
return;
} else if (d->depth == 64) {
qt_rectfill<quint64>(reinterpret_cast<quint64*>(d->data), QRgba64::fromArgb32(pixel),
0, 0, d->width, d->height, d->bytes_per_line);
return;
}
if (d->format == Format_RGB32)
@ -1815,6 +1829,12 @@ void QImage::fill(const QColor &color)
else
fill((uint) 0);
break;
case QImage::Format_RGBX64:
case QImage::Format_RGBA64:
case QImage::Format_RGBA64_Premultiplied:
qt_rectfill<quint64>(reinterpret_cast<quint64*>(d->data), color.rgba64(),
0, 0, d->width, d->height, d->bytes_per_line);
break;
default: {
QPainter p(this);
p.setCompositionMode(QPainter::CompositionMode_Source);
@ -1838,7 +1858,8 @@ void QImage::fill(const QColor &color)
changed.
If the image has a premultiplied alpha channel, the image is first
converted to ARGB32 to be inverted and then converted back.
converted to an unpremultiplied image format to be inverted and
then converted back.
\sa {QImage#Image Transformations}{Image Transformations}
*/
@ -1857,8 +1878,13 @@ void QImage::invertPixels(InvertMode mode)
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) {
if (!d->convertInPlace(QImage::Format_RGBA64, 0))
*this = convertToFormat(QImage::Format_RGBA64);
} else {
if (!d->convertInPlace(QImage::Format_ARGB32, 0))
*this = convertToFormat(QImage::Format_ARGB32);
}
}
if (depth() < 32) {
@ -1871,6 +1897,20 @@ void QImage::invertPixels(InvertMode mode)
*sl++ ^= 0xff;
sl += pad;
}
}
else if (depth() == 64) {
quint16 *p = (quint16*)d->data;
quint16 *end = (quint16*)(d->data + d->nbytes);
quint16 xorbits = 0xffff;
while (p < end) {
*p++ ^= xorbits;
*p++ ^= xorbits;
*p++ ^= xorbits;
if (mode == InvertRgba)
*p++ ^= xorbits;
else
p++;
}
} else {
quint32 *p = (quint32*)d->data;
quint32 *end = (quint32*)(d->data + d->nbytes);
@ -1987,6 +2027,26 @@ QImage::Format QImage::format() const
\sa {Image Formats}
*/
static bool highColorPrecision(QImage::Format format)
{
// Formats with higher color precision than ARGB32_Premultiplied.
switch (format) {
case QImage::Format_ARGB32:
case QImage::Format_RGBA8888:
case QImage::Format_BGR30:
case QImage::Format_RGB30:
case QImage::Format_A2BGR30_Premultiplied:
case QImage::Format_A2RGB30_Premultiplied:
case QImage::Format_RGBX64:
case QImage::Format_RGBA64:
case QImage::Format_RGBA64_Premultiplied:
return true;
default:
break;
}
return false;
}
/*!
\internal
*/
@ -1999,8 +2059,18 @@ QImage QImage::convertToFormat_helper(Format format, Qt::ImageConversionFlags fl
return QImage();
Image_Converter converter = qimage_converter_map[d->format][format];
if (!converter && format > QImage::Format_Indexed8 && d->format > QImage::Format_Indexed8)
converter = convert_generic;
if (!converter && format > QImage::Format_Indexed8 && d->format > QImage::Format_Indexed8) {
if (highColorPrecision(format) && highColorPrecision(d->format)) {
// Convert over RGBA64_Premultiplied
if (format == QImage::Format_RGBA64_Premultiplied)
converter = convert_generic_to_rgb64;
else {
Q_ASSERT(d->format != QImage::Format_RGBA64_Premultiplied);
return convertToFormat(Format_RGBA64_Premultiplied, flags).convertToFormat(format, flags);
}
} else
converter = convert_generic;
}
if (converter) {
QImage image(d->width, d->height, format);
@ -2298,6 +2368,10 @@ QRgb QImage::pixel(int x, int y) const
return qConvertA2rgb30ToArgb32<PixelOrderRGB>(reinterpret_cast<const quint32 *>(s)[x]);
case Format_RGB16:
return qConvertRgb16To32(reinterpret_cast<const quint16 *>(s)[x]);
case Format_RGBX64:
case Format_RGBA64: // Match ARGB32 behavior.
case Format_RGBA64_Premultiplied:
return reinterpret_cast<const QRgba64 *>(s)[x].toArgb32();
default:
break;
}
@ -2447,6 +2521,11 @@ QColor QImage::pixelColor(int x, int y) const
case Format_A2RGB30_Premultiplied:
c = qConvertA2rgb30ToRgb64<PixelOrderRGB>(reinterpret_cast<const quint32 *>(s)[x]);
break;
case Format_RGBX64:
case Format_RGBA64:
case Format_RGBA64_Premultiplied:
c = reinterpret_cast<const QRgba64 *>(s)[x];
break;
default:
c = QRgba64::fromArgb32(pixel(x, y));
break;
@ -2517,6 +2596,14 @@ void QImage::setPixelColor(int x, int y, const QColor &color)
case Format_A2RGB30_Premultiplied:
((uint *)s)[x] = qConvertRgb64ToRgb30<PixelOrderRGB>(c);
return;
case Format_RGBX64:
((QRgba64 *)s)[x] = color.rgba64();
((QRgba64 *)s)[x].setAlpha(65535);
return;
case Format_RGBA64:
case Format_RGBA64_Premultiplied:
((QRgba64 *)s)[x] = color.rgba64();
return;
default:
setPixel(x, y, c.toArgb32());
return;
@ -3100,6 +3187,9 @@ inline void do_mirror(QImageData *dst, QImageData *src, bool horizontal, bool ve
}
switch (depth) {
case 64:
do_mirror_data<quint64>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
break;
case 32:
do_mirror_data<quint32>(dst, src, dstX0, dstY0, dstXIncr, dstYIncr, w, h);
break;
@ -3308,6 +3398,23 @@ QImage QImage::rgbSwapped_helper() const
}
}
break;
case Format_RGBX64:
case Format_RGBA64:
case Format_RGBA64_Premultiplied:
res = QImage(d->width, d->height, d->format);
QIMAGE_SANITYCHECK_MEMORY(res);
for (int i = 0; i < d->height; i++) {
QRgba64 *q = reinterpret_cast<QRgba64 *>(res.scanLine(i));
const QRgba64 *p = reinterpret_cast<const QRgba64 *>(constScanLine(i));
const QRgba64 *end = p + d->width;
while (p < end) {
QRgba64 c = *p;
*q = QRgba64::fromRgba64(c.blue(), c.green(), c.red(), c.alpha());
p++;
q++;
}
}
break;
default:
res = QImage(d->width, d->height, d->format);
rgbSwapped_generic(d->width, d->height, this, &res, &qPixelLayouts[d->format]);
@ -3400,6 +3507,19 @@ void QImage::rgbSwapped_inplace()
}
}
break;
case Format_RGBX64:
case Format_RGBA64:
case Format_RGBA64_Premultiplied:
for (int i = 0; i < d->height; i++) {
QRgba64 *p = reinterpret_cast<QRgba64 *>(scanLine(i));
QRgba64 *end = p + d->width;
while (p < end) {
QRgba64 c = *p;
*p = QRgba64::fromRgba64(c.blue(), c.green(), c.red(), c.alpha());
p++;
}
}
break;
default:
rgbSwapped_generic(d->width, d->height, this, this, &qPixelLayouts[d->format]);
break;
@ -4473,6 +4593,9 @@ int QImage::bitPlaneCount() const
case QImage::Format_RGB444:
bpc = 12;
break;
case QImage::Format_RGBX64:
bpc = 48;
break;
default:
bpc = qt_depthForFormat(d->format);
break;
@ -5171,6 +5294,45 @@ static Q_CONSTEXPR QPixelFormat pixelformats[] = {
/*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
/*INTERPRETATION*/ QPixelFormat::UnsignedByte,
/*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
//QImage::Format_RGBX64:
QPixelFormat(QPixelFormat::RGB,
/*RED*/ 16,
/*GREEN*/ 16,
/*BLUE*/ 16,
/*FOURTH*/ 0,
/*FIFTH*/ 0,
/*ALPHA*/ 16,
/*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
/*ALPHA POSITION*/ QPixelFormat::AtEnd,
/*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
/*INTERPRETATION*/ QPixelFormat::UnsignedShort,
/*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
//QImage::Format_RGBA64:
QPixelFormat(QPixelFormat::RGB,
/*RED*/ 16,
/*GREEN*/ 16,
/*BLUE*/ 16,
/*FOURTH*/ 0,
/*FIFTH*/ 0,
/*ALPHA*/ 16,
/*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
/*ALPHA POSITION*/ QPixelFormat::AtEnd,
/*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
/*INTERPRETATION*/ QPixelFormat::UnsignedShort,
/*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
//QImage::Format_RGBA64_Premultiplied:
QPixelFormat(QPixelFormat::RGB,
/*RED*/ 16,
/*GREEN*/ 16,
/*BLUE*/ 16,
/*FOURTH*/ 0,
/*FIFTH*/ 0,
/*ALPHA*/ 16,
/*ALPHA USAGE*/ QPixelFormat::UsesAlpha,
/*ALPHA POSITION*/ QPixelFormat::AtEnd,
/*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
/*INTERPRETATION*/ QPixelFormat::UnsignedShort,
/*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
};
Q_STATIC_ASSERT(sizeof(pixelformats) / sizeof(*pixelformats) == QImage::NImageFormats);

View File

@ -125,6 +125,9 @@ public:
Format_A2RGB30_Premultiplied,
Format_Alpha8,
Format_Grayscale8,
Format_RGBX64,
Format_RGBA64,
Format_RGBA64_Premultiplied,
#if 0
// reserved for future use
Format_Grayscale16,

View File

@ -179,7 +179,7 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio
store = storeRGB32FromARGB32PM;
}
}
if ((src->format == QImage::Format_ARGB32 || src->format == QImage::Format_RGBA8888) &&
if (srcLayout->hasAlphaChannel && !srcLayout->premultiplied &&
!destLayout->hasAlphaChannel && destLayout->storeFromRGB32) {
// Avoid unnecessary premultiply and unpremultiply when converting from unpremultiplied src format.
fetch = qPixelLayouts[src->format + 1].fetchToARGB32PM;
@ -212,6 +212,26 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio
}
}
void convert_generic_to_rgb64(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
{
Q_ASSERT(dest->format == QImage::Format_RGBA64_Premultiplied);
Q_ASSERT(src->format > QImage::Format_Indexed8);
const QPixelLayout *srcLayout = &qPixelLayouts[src->format];
const uchar *srcData = src->data;
uchar *destData = dest->data;
const FetchAndConvertPixelsFunc64 fetch = srcLayout->fetchToRGBA64PM;
for (int y = 0; y < src->height; ++y) {
const QRgba64 *ptr = fetch((QRgba64*)destData, srcData, 0, src->width, nullptr, nullptr);
if (ptr != (const QRgba64*)destData) {
memcpy(destData, ptr, dest->bytes_per_line);
}
srcData += src->bytes_per_line;
destData += dest->bytes_per_line;
}
}
bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::ImageConversionFlags flags)
{
// Cannot be used with indexed formats or between formats with different pixel depths.
@ -226,6 +246,8 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im
const QPixelLayout *destLayout = &qPixelLayouts[dst_format];
uchar *srcData = data->data;
Q_ASSERT(srcLayout->bpp == destLayout->bpp);
Q_ASSERT(srcLayout->bpp != QPixelLayout::BPP64);
FetchAndConvertPixelsFunc fetch = srcLayout->fetchToARGB32PM;
ConvertAndStorePixelsFunc store = destLayout->storeFromARGB32PM;
if (!srcLayout->hasAlphaChannel && destLayout->storeFromRGB32) {
@ -243,7 +265,7 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im
store = storeRGB32FromARGB32PM;
}
}
if ((data->format == QImage::Format_ARGB32 || data->format == QImage::Format_RGBA8888) &&
if (srcLayout->hasAlphaChannel && !srcLayout->premultiplied &&
!destLayout->hasAlphaChannel && destLayout->storeFromRGB32) {
// Avoid unnecessary premultiply and unpremultiply when converting from unpremultiplied src format.
fetch = qPixelLayouts[data->format + 1].fetchToARGB32PM;
@ -282,20 +304,15 @@ static void convert_passthrough(QImageData *dest, const QImageData *src, Qt::Ima
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;
const int src_bpl = src->bytes_per_line;
const int dest_bpl = dest->bytes_per_line;
const uchar *src_data = src->data;
uchar *dest_data = 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;
memcpy(dest_data, src_data, src_bpl);
src_data += src_bpl;
dest_data += dest_bpl;
}
}
@ -1138,6 +1155,270 @@ static bool mask_alpha_converter_rgbx_inplace(QImageData *data, Qt::ImageConvers
#endif
}
template<bool RGBA>
static void convert_RGBA64_to_ARGB32(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
{
Q_ASSERT(src->format == QImage::Format_RGBA64);
Q_ASSERT(RGBA || dest->format == QImage::Format_ARGB32);
Q_ASSERT(!RGBA || dest->format == QImage::Format_RGBA8888);
Q_ASSERT(src->width == dest->width);
Q_ASSERT(src->height == dest->height);
const uchar *srcData = src->data;
uchar *destData = dest->data;
for (int i = 0; i < src->height; ++i) {
uint *d = reinterpret_cast<uint *>(destData);
const QRgba64 *s = reinterpret_cast<const QRgba64 *>(srcData);
qt_convertRGBA64ToARGB32<RGBA>(d, s, src->width);
srcData += src->bytes_per_line;
destData += dest->bytes_per_line;
}
}
template<bool RGBA>
static void convert_RGBA64PM_to_ARGB32(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
{
Q_ASSERT(src->format == QImage::Format_RGBA64_Premultiplied);
Q_ASSERT(RGBA || dest->format == QImage::Format_ARGB32);
Q_ASSERT(!RGBA || dest->format == QImage::Format_RGBA8888);
Q_ASSERT(src->width == dest->width);
Q_ASSERT(src->height == dest->height);
const int src_pad = (src->bytes_per_line >> 3) - src->width;
const int dest_pad = (dest->bytes_per_line >> 2) - dest->width;
const QRgba64 *src_data = reinterpret_cast<const QRgba64 *>(src->data);
uint *dest_data = reinterpret_cast<uint *>(dest->data);
for (int i = 0; i < src->height; ++i) {
const QRgba64 *end = src_data + src->width;
while (src_data < end) {
QRgba64 s = src_data->unpremultiplied();
*dest_data = RGBA ? ARGB2RGBA(s.toArgb32()) : s.toArgb32();
++src_data;
++dest_data;
}
src_data += src_pad;
dest_data += dest_pad;
}
}
template<bool RGBA>
static void convert_ARGB32_to_RGBA64(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
{
Q_ASSERT(RGBA || src->format == QImage::Format_ARGB32);
Q_ASSERT(!RGBA || src->format == QImage::Format_RGBA8888);
Q_ASSERT(dest->format == QImage::Format_RGBA64);
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 >> 3) - dest->width;
const uint *src_data = reinterpret_cast<const uint *>(src->data);
QRgba64 *dest_data = reinterpret_cast<QRgba64 *>(dest->data);
for (int i = 0; i < src->height; ++i) {
const uint *end = src_data + src->width;
while (src_data < end) {
if (RGBA)
*dest_data = QRgba64::fromArgb32(RGBA2ARGB(*src_data));
else
*dest_data = QRgba64::fromArgb32(*src_data);
++src_data;
++dest_data;
}
src_data += src_pad;
dest_data += dest_pad;
}
}
template<QtPixelOrder PixelOrder>
static void convert_RGBA64PM_to_RGB30(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
{
Q_ASSERT(src->format == QImage::Format_RGBA64_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 >> 3) - src->width;
const int dest_pad = (dest->bytes_per_line >> 2) - dest->width;
const QRgba64 *src_data = reinterpret_cast<const QRgba64 *>(src->data);
uint *dest_data = reinterpret_cast<uint *>(dest->data);
for (int i = 0; i < src->height; ++i) {
const QRgba64 *end = src_data + src->width;
while (src_data < end) {
*dest_data = 0xc0000000 | qConvertRgb64ToRgb30<PixelOrder>(src_data->unpremultiplied());
++src_data;
++dest_data;
}
src_data += src_pad;
dest_data += dest_pad;
}
}
template<QtPixelOrder PixelOrder>
static void convert_RGBA64PM_to_A2RGB30(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
{
Q_ASSERT(src->format == QImage::Format_RGBA64_Premultiplied);
Q_ASSERT(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 >> 3) - src->width;
const int dest_pad = (dest->bytes_per_line >> 2) - dest->width;
const QRgba64 *src_data = reinterpret_cast<const QRgba64 *>(src->data);
uint *dest_data = reinterpret_cast<uint *>(dest->data);
for (int i = 0; i < src->height; ++i) {
const QRgba64 *end = src_data + src->width;
while (src_data < end) {
*dest_data = qConvertRgb64ToRgb30<PixelOrder>(*src_data);
++src_data;
++dest_data;
}
src_data += src_pad;
dest_data += dest_pad;
}
}
static void convert_RGBA64_to_RGBx64(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
{
Q_ASSERT(src->format == QImage::Format_RGBA64);
Q_ASSERT(dest->format == QImage::Format_RGBX64);
Q_ASSERT(src->width == dest->width);
Q_ASSERT(src->height == dest->height);
const int src_pad = (src->bytes_per_line >> 3) - src->width;
const int dest_pad = (dest->bytes_per_line >> 3) - dest->width;
const QRgba64 *src_data = reinterpret_cast<const QRgba64 *>(src->data);
QRgba64 *dest_data = reinterpret_cast<QRgba64 *>(dest->data);
for (int i = 0; i < src->height; ++i) {
const QRgba64 *end = src_data + src->width;
while (src_data < end) {
*dest_data = *src_data;
dest_data->setAlpha(65535);
++src_data;
++dest_data;
}
src_data += src_pad;
dest_data += dest_pad;
}
}
static bool convert_RGBA64_to_RGBx64_inplace(QImageData *data, Qt::ImageConversionFlags)
{
Q_ASSERT(data->format == QImage::Format_RGBA64);
const int pad = (data->bytes_per_line >> 3) - data->width;
QRgba64 *rgb_data = reinterpret_cast<QRgba64 *>(data->data);
for (int i = 0; i < data->height; ++i) {
const QRgba64 *end = rgb_data + data->width;
while (rgb_data < end) {
rgb_data->setAlpha(65535);
++rgb_data;
}
rgb_data += pad;
}
data->format = QImage::Format_RGBX64;
return true;
}
static void convert_RGBA64_to_RGBA64PM(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
{
Q_ASSERT(src->format == QImage::Format_RGBA64);
Q_ASSERT(dest->format == QImage::Format_RGBA64_Premultiplied);
Q_ASSERT(src->width == dest->width);
Q_ASSERT(src->height == dest->height);
const int src_pad = (src->bytes_per_line >> 3) - src->width;
const int dest_pad = (dest->bytes_per_line >> 3) - dest->width;
const QRgba64 *src_data = reinterpret_cast<const QRgba64 *>(src->data);
QRgba64 *dest_data = reinterpret_cast<QRgba64 *>(dest->data);
for (int i = 0; i < src->height; ++i) {
const QRgba64 *end = src_data + src->width;
while (src_data < end) {
*dest_data = src_data->premultiplied();
++src_data;
++dest_data;
}
src_data += src_pad;
dest_data += dest_pad;
}
}
static bool convert_RGBA64_to_RGBA64PM_inplace(QImageData *data, Qt::ImageConversionFlags)
{
Q_ASSERT(data->format == QImage::Format_RGBA64);
const int pad = (data->bytes_per_line >> 3) - data->width;
QRgba64 *rgb_data = reinterpret_cast<QRgba64 *>(data->data);
for (int i = 0; i < data->height; ++i) {
const QRgba64 *end = rgb_data + data->width;
while (rgb_data < end) {
*rgb_data = rgb_data->premultiplied();
++rgb_data;
}
rgb_data += pad;
}
data->format = QImage::Format_RGBA64_Premultiplied;
return true;
}
template<bool MaskAlpha>
static void convert_RGBA64PM_to_RGBA64(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
{
Q_ASSERT(src->format == QImage::Format_RGBA64_Premultiplied);
Q_ASSERT(dest->format == QImage::Format_RGBA64 || dest->format == QImage::Format_RGBX64);
Q_ASSERT(src->width == dest->width);
Q_ASSERT(src->height == dest->height);
const int src_pad = (src->bytes_per_line >> 3) - src->width;
const int dest_pad = (dest->bytes_per_line >> 3) - dest->width;
const QRgba64 *src_data = reinterpret_cast<const QRgba64 *>(src->data);
QRgba64 *dest_data = reinterpret_cast<QRgba64 *>(dest->data);
for (int i = 0; i < src->height; ++i) {
const QRgba64 *end = src_data + src->width;
while (src_data < end) {
*dest_data = src_data->unpremultiplied();
if (MaskAlpha)
dest_data->setAlpha(65535);
++src_data;
++dest_data;
}
src_data += src_pad;
dest_data += dest_pad;
}
}
template<bool MaskAlpha>
static bool convert_RGBA64PM_to_RGBA64_inplace(QImageData *data, Qt::ImageConversionFlags)
{
Q_ASSERT(data->format == QImage::Format_RGBA64_Premultiplied);
const int pad = (data->bytes_per_line >> 3) - data->width;
QRgba64 *rgb_data = reinterpret_cast<QRgba64 *>(data->data);
for (int i = 0; i < data->height; ++i) {
const QRgba64 *end = rgb_data + data->width;
while (rgb_data < end) {
*rgb_data = rgb_data->unpremultiplied();
if (MaskAlpha)
rgb_data->setAlpha(65535);
++rgb_data;
}
rgb_data += pad;
}
data->format = MaskAlpha ? QImage::Format_RGBX64 : QImage::Format_RGBA64;
return true;
}
static QVector<QRgb> fix_color_table(const QVector<QRgb> &ctbl, QImage::Format format)
{
QVector<QRgb> colorTable = ctbl;
@ -1982,7 +2263,7 @@ static bool convert_Grayscale8_to_Indexed8_inplace(QImageData *data, Qt::ImageCo
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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
},
{
0,
@ -2003,7 +2284,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_Mono
{
@ -2025,7 +2306,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_MonoLSB
{
@ -2050,6 +2331,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0, 0, 0, 0, 0,
convert_Indexed8_to_Alpha8,
convert_Indexed8_to_Grayscale8,
0, 0, 0
}, // Format_Indexed8
{
@ -2076,7 +2358,8 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
convert_RGB_to_RGB30<PixelOrderRGB>,
0,
0, 0
0, 0,
0, 0, 0
}, // Format_RGB32
{
@ -2103,7 +2386,10 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
convert_RGB_to_RGB30<PixelOrderRGB>,
0,
0, 0
0, 0,
0,
convert_ARGB32_to_RGBA64<false>,
0
}, // Format_ARGB32
{
@ -2126,11 +2412,9 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
convert_ARGB_to_RGBA,
0,
0,
0,
0,
0, 0
0, 0, 0, 0,
0, 0,
0, 0, 0
}, // Format_ARGB32_Premultiplied
{
@ -2152,7 +2436,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_RGB16
{
@ -2174,7 +2458,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_ARGB8565_Premultiplied
{
@ -2196,7 +2480,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_RGB666
{
@ -2218,7 +2502,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_ARGB6666_Premultiplied
{
@ -2240,7 +2524,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_RGB555
{
@ -2262,7 +2546,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_ARGB8555_Premultiplied
{
@ -2285,7 +2569,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
convert_RGB888_to_RGB<true>,
convert_RGB888_to_RGB<true>,
convert_RGB888_to_RGB<true>,
0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_RGB888
{
@ -2307,7 +2591,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_RGB444
{
@ -2328,7 +2612,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_ARGB4444_Premultiplied
{
0,
@ -2348,9 +2632,11 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
mask_alpha_converter_RGBx,
mask_alpha_converter_RGBx,
0, 0, 0, 0, 0, 0
convert_passthrough,
convert_passthrough,
0, 0, 0, 0,
0, 0,
0, 0, 0
}, // Format_RGBX8888
{
0,
@ -2372,7 +2658,10 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
mask_alpha_converter_RGBx,
0,
0,
0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0,
0,
convert_ARGB32_to_RGBA64<true>,
0
}, // Format_RGBA8888
{
@ -2394,7 +2683,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_RGBA8888_Premultiplied
{
@ -2421,7 +2710,8 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
convert_passthrough,
convert_BGR30_to_RGB30,
convert_BGR30_to_RGB30,
0, 0
0, 0,
0, 0, 0
}, // Format_BGR30
{
0,
@ -2447,7 +2737,8 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
convert_A2RGB30_PM_to_RGB30<true>,
convert_BGR30_to_RGB30,
0, 0
0, 0,
0, 0, 0
}, // Format_BGR30A2_Premultiplied
{
0,
@ -2473,7 +2764,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
convert_BGR30_to_RGB30,
0,
convert_passthrough,
0, 0
0, 0, 0, 0, 0
}, // Format_RGB30
{
0,
@ -2499,7 +2790,8 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
convert_BGR30_to_RGB30,
convert_A2RGB30_PM_to_RGB30<false>,
0,
0, 0
0, 0,
0, 0, 0
}, // Format_RGB30A2_Premultiplied
{
0,
@ -2519,7 +2811,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
0, 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_Alpha8
{
0,
@ -2539,20 +2831,81 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
0, 0, 0, 0, 0, 0, 0
} // Format_Grayscale8
0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_Grayscale8
{
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, // self
convert_passthrough,
convert_passthrough
}, // Format_RGBX64
{
0,
0,
0,
0,
0,
convert_RGBA64_to_ARGB32<false>,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
convert_RGBA64_to_ARGB32<true>,
0,
0, 0, 0, 0,
0, 0,
convert_RGBA64_to_RGBx64,
0, // self
convert_RGBA64_to_RGBA64PM
}, // Format_RGBA64
{
0,
0,
0,
0,
0,
convert_RGBA64PM_to_ARGB32<false>,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
convert_RGBA64PM_to_ARGB32<true>,
0,
convert_RGBA64PM_to_RGB30<PixelOrderBGR>,
convert_RGBA64PM_to_A2RGB30<PixelOrderBGR>,
convert_RGBA64PM_to_RGB30<PixelOrderRGB>,
convert_RGBA64PM_to_A2RGB30<PixelOrderRGB>,
0, 0,
convert_RGBA64PM_to_RGBA64<true>,
convert_RGBA64PM_to_RGBA64<false>,
0 // self
} // Format_RGBA64_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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_MonoLSB
{
0,
@ -2576,6 +2929,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
0, 0, 0, 0, 0,
convert_Indexed8_to_Alpha8_inplace,
convert_Indexed8_to_Grayscale8_inplace,
0, 0, 0
}, // Format_Indexed8
{
0,
@ -2601,7 +2955,8 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
0,
convert_RGB_to_RGB30_inplace<PixelOrderRGB>,
0,
0, 0
0, 0,
0, 0, 0
}, // Format_RGB32
{
0,
@ -2627,7 +2982,8 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
0,
convert_RGB_to_RGB30_inplace<PixelOrderRGB>,
0,
0, 0
0, 0,
0, 0, 0
}, // Format_ARGB32
{
0,
@ -2649,38 +3005,36 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
0,
0,
convert_ARGB_to_RGBA_inplace<QImage::Format_RGBA8888_Premultiplied>,
0,
0,
0,
0,
0, 0
0, 0, 0, 0,
0, 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, 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, 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, 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, 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, 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, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_ARGB4444_Premultiplied
{
0,
@ -2702,7 +3056,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
0,
convert_passthrough_inplace<QImage::Format_RGBA8888>,
convert_passthrough_inplace<QImage::Format_RGBA8888_Premultiplied>,
0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_RGBX8888
{
0,
@ -2724,7 +3078,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
mask_alpha_converter_rgbx_inplace,
0,
0,
0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_RGBA8888
{
0,
@ -2746,7 +3100,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
0,
0,
0,
0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_RGBA8888_Premultiplied
{
0,
@ -2772,7 +3126,8 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
convert_passthrough_inplace<QImage::Format_A2BGR30_Premultiplied>,
convert_BGR30_to_RGB30_inplace,
convert_BGR30_to_A2RGB30_inplace,
0, 0
0, 0,
0, 0, 0
}, // Format_BGR30
{
0,
@ -2798,7 +3153,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
0, // self
convert_A2RGB30_PM_to_RGB30_inplace<true>,
convert_BGR30_to_RGB30_inplace,
0, 0
0, 0, 0, 0, 0
}, // Format_BGR30A2_Premultiplied
{
0,
@ -2824,7 +3179,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
convert_BGR30_to_A2RGB30_inplace,
0, // self
convert_passthrough_inplace<QImage::Format_A2RGB30_Premultiplied>,
0, 0
0, 0, 0, 0, 0
}, // Format_RGB30
{
0,
@ -2850,7 +3205,8 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
convert_BGR30_to_RGB30_inplace,
convert_A2RGB30_PM_to_RGB30_inplace<false>,
0, // self
0, 0
0, 0,
0, 0, 0
}, // Format_RGB30A2_Premultiplied
{
0,
@ -2872,11 +3228,10 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
0,
0,
0,
0, 0, 0, 0,
0, // self
0,
0,
0,
0,
0, 0
0, 0, 0
}, // Format_Alpha8
{
0,
@ -2898,12 +3253,29 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
0,
0,
0,
0, 0, 0, 0,
0,
0,
0,
0,
0, 0
} // Format_Grayscale8
0, // self
0, 0, 0
}, // Format_Grayscale8
{
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, // self
convert_passthrough_inplace<QImage::Format_RGBA64>,
convert_passthrough_inplace<QImage::Format_RGBA64_Premultiplied>,
}, // Format_RGBX64
{
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,
convert_RGBA64_to_RGBx64_inplace,
0, // self
convert_RGBA64_to_RGBA64PM_inplace
}, // Format_RGBA64
{
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,
convert_RGBA64PM_to_RGBA64_inplace<true>,
convert_RGBA64PM_to_RGBA64_inplace<false>,
0 // self
} // Format_RGBA64_Premultiplied
};
static void qInitImageConversions()

View File

@ -113,6 +113,7 @@ extern Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImag
extern InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QImage::NImageFormats];
void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags);
void convert_generic_to_rgb64(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags);
bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::ImageConversionFlags);
void dither_to_Mono(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags, bool fromalpha);
@ -164,6 +165,11 @@ inline int qt_depthForFormat(QImage::Format format)
case QImage::Format_RGB888:
depth = 24;
break;
case QImage::Format_RGBX64:
case QImage::Format_RGBA64:
case QImage::Format_RGBA64_Premultiplied:
depth = 64;
break;
}
return depth;
}
@ -190,6 +196,9 @@ inline QImage::Format qt_opaqueVersion(QImage::Format format)
return QImage::Format_BGR30;
case QImage::Format_A2RGB30_Premultiplied:
return QImage::Format_RGB30;
case QImage::Format_RGBA64:
case QImage::Format_RGBA64_Premultiplied:
return QImage::Format_RGBX64;
case QImage::Format_ARGB32_Premultiplied:
case QImage::Format_ARGB32:
default:
@ -214,6 +223,8 @@ inline QImage::Format qt_alphaVersion(QImage::Format format)
return QImage::Format_A2BGR30_Premultiplied;
case QImage::Format_RGB30:
return QImage::Format_A2RGB30_Premultiplied;
case QImage::Format_RGBX64:
return QImage::Format_RGBA64_Premultiplied;
default:
break;
}

View File

@ -352,6 +352,24 @@ void setup_qt(QImage& image, png_structp png_ptr, png_infop info_ptr, QSize scal
);
i++;
}
// Qt==ARGB==Big(ARGB)==Little(BGRA)
if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) {
png_set_bgr(png_ptr);
}
} else if (bit_depth == 16 && (color_type & PNG_COLOR_MASK_COLOR)) {
QImage::Format format = QImage::Format_RGBA64;
if (!(color_type & PNG_COLOR_MASK_ALPHA) && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
png_set_filler(png_ptr, 0xffff, PNG_FILLER_AFTER);
format = QImage::Format_RGBX64;
}
if (image.size() != QSize(width, height) || image.format() != format) {
image = QImage(width, height, format);
if (image.isNull())
return;
}
png_read_update_info(png_ptr, info_ptr);
if (QSysInfo::ByteOrder == QSysInfo::LittleEndian)
png_set_swap(png_ptr);
} else {
// 32-bit
if (bit_depth == 16)
@ -388,12 +406,12 @@ void setup_qt(QImage& image, png_structp png_ptr, png_infop info_ptr, QSize scal
if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
png_set_swap_alpha(png_ptr);
png_read_update_info(png_ptr, info_ptr);
}
// Qt==ARGB==Big(ARGB)==Little(BGRA)
if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) {
png_set_bgr(png_ptr);
}
// Qt==ARGB==Big(ARGB)==Little(BGRA)
if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) {
png_set_bgr(png_ptr);
png_read_update_info(png_ptr, info_ptr);
}
}
@ -678,6 +696,10 @@ QImage::Format QPngHandlerPrivate::readImageFormat()
{
// 1-bit and 8-bit color
format = bit_depth == 1 ? QImage::Format_Mono : QImage::Format_Indexed8;
} else if (bit_depth == 16 && (color_type & PNG_COLOR_MASK_COLOR)) {
format = QImage::Format_RGBA64;
if (!(color_type & PNG_COLOR_MASK_ALPHA) && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
format = QImage::Format_RGBX64;
} else {
// 32-bit
format = QImage::Format_ARGB32;
@ -843,8 +865,24 @@ bool QPNGImageWriter::writeImage(const QImage& image, volatile int quality_in, c
else
color_type = PNG_COLOR_TYPE_RGB;
int bpc = 0;
switch (image.format()) {
case QImage::Format_Mono:
case QImage::Format_MonoLSB:
bpc = 1;
break;
case QImage::Format_RGBX64:
case QImage::Format_RGBA64:
case QImage::Format_RGBA64_Premultiplied:
bpc = 16;
break;
default:
bpc = 8;
break;
}
png_set_IHDR(png_ptr, info_ptr, image.width(), image.height(),
image.depth() == 1 ? 1 : 8, // per channel
bpc, // per channel
color_type, 0, 0, 0); // sets #channels
if (gamma != 0.0) {
@ -880,13 +918,31 @@ bool QPNGImageWriter::writeImage(const QImage& image, volatile int quality_in, c
// Swap ARGB to RGBA (normal PNG format) before saving on
// BigEndian machines
if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
png_set_swap_alpha(png_ptr);
switch (image.format()) {
case QImage::Format_RGBX8888:
case QImage::Format_RGBA8888:
case QImage::Format_RGBX64:
case QImage::Format_RGBA64:
case QImage::Format_RGBA64_Premultiplied:
break;
default:
png_set_swap_alpha(png_ptr);
}
}
// Qt==ARGB==Big(ARGB)==Little(BGRA). But RGB888 is RGB regardless
if (QSysInfo::ByteOrder == QSysInfo::LittleEndian
&& image.format() != QImage::Format_RGB888) {
png_set_bgr(png_ptr);
if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) {
switch (image.format()) {
case QImage::Format_RGB888:
case QImage::Format_RGBX8888:
case QImage::Format_RGBA8888:
case QImage::Format_RGBX64:
case QImage::Format_RGBA64:
case QImage::Format_RGBA64_Premultiplied:
break;
default:
png_set_bgr(png_ptr);
}
}
if (off_x || off_y) {
@ -909,10 +965,32 @@ bool QPNGImageWriter::writeImage(const QImage& image, volatile int quality_in, c
if (image.depth() != 1)
png_set_packing(png_ptr);
if (color_type == PNG_COLOR_TYPE_RGB && image.format() != QImage::Format_RGB888)
png_set_filler(png_ptr, 0,
QSysInfo::ByteOrder == QSysInfo::BigEndian ?
PNG_FILLER_BEFORE : PNG_FILLER_AFTER);
if (color_type == PNG_COLOR_TYPE_RGB) {
switch (image.format()) {
case QImage::Format_RGB888:
break;
case QImage::Format_RGBX8888:
case QImage::Format_RGBX64:
png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
break;
default:
png_set_filler(png_ptr, 0,
QSysInfo::ByteOrder == QSysInfo::BigEndian ?
PNG_FILLER_BEFORE : PNG_FILLER_AFTER);
}
}
if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) {
switch (image.format()) {
case QImage::Format_RGBX64:
case QImage::Format_RGBA64:
case QImage::Format_RGBA64_Premultiplied:
png_set_swap(png_ptr);
break;
default:
break;
}
}
if (looping >= 0 && frames_written == 0) {
uchar data[13] = "NETSCAPE2.0";
@ -940,6 +1018,10 @@ bool QPNGImageWriter::writeImage(const QImage& image, volatile int quality_in, c
case QImage::Format_RGB32:
case QImage::Format_ARGB32:
case QImage::Format_RGB888:
case QImage::Format_RGBX8888:
case QImage::Format_RGBA8888:
case QImage::Format_RGBX64:
case QImage::Format_RGBA64:
{
png_bytep* row_pointers = new png_bytep[height];
for (int y=0; y<height; y++)
@ -948,6 +1030,17 @@ bool QPNGImageWriter::writeImage(const QImage& image, volatile int quality_in, c
delete [] row_pointers;
}
break;
case QImage::Format_RGBA64_Premultiplied:
{
QImage row;
png_bytep row_pointers[1];
for (int y=0; y<height; y++) {
row = image.copy(0, y, width, 1).convertToFormat(QImage::Format_RGBA64);
row_pointers[0] = const_cast<png_bytep>(row.constScanLine(0));
png_write_rows(png_ptr, row_pointers, 1);
}
}
break;
default:
{
QImage::Format fmt = image.hasAlphaChannel() ? QImage::Format_ARGB32 : QImage::Format_RGB32;

View File

@ -106,6 +106,10 @@ QT_BEGIN_NAMESPACE
#define GL_RGB10 0x8052
#endif
#ifndef GL_RGB16
#define GL_RGB16 0x8054
#endif
#ifndef GL_RGBA8
#define GL_RGBA8 0x8058
#endif
@ -114,6 +118,10 @@ QT_BEGIN_NAMESPACE
#define GL_RGB10_A2 0x8059
#endif
#ifndef GL_RGBA16
#define GL_RGBA16 0x805B
#endif
#ifndef GL_BGRA
#define GL_BGRA 0x80E1
#endif
@ -127,6 +135,7 @@ QT_BEGIN_NAMESPACE
#endif
/*!
\class QOpenGLFramebufferObjectFormat
\brief The QOpenGLFramebufferObjectFormat class specifies the format of an OpenGL
@ -522,6 +531,8 @@ void QOpenGLFramebufferObjectPrivate::initTexture(int idx)
GLuint pixelType = GL_UNSIGNED_BYTE;
if (color.internalFormat == GL_RGB10_A2 || color.internalFormat == GL_RGB10)
pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
else if (color.internalFormat == GL_RGB16 || color.internalFormat == GL_RGBA16)
pixelType = GL_UNSIGNED_SHORT;
funcs.glTexImage2D(target, 0, color.internalFormat, color.size.width(), color.size.height(), 0,
GL_RGBA, pixelType, NULL);
@ -1304,6 +1315,14 @@ static inline QImage qt_gl_read_framebuffer_rgb10a2(const QSize &size, bool incl
return img;
}
static inline QImage qt_gl_read_framebuffer_rgba16(const QSize &size, bool include_alpha, QOpenGLContext *context)
{
// We assume OpenGL 1.2+ or ES 3.0+ here.
QImage img(size, include_alpha ? QImage::Format_RGBA64_Premultiplied : QImage::Format_RGBX64);
context->functions()->glReadPixels(0, 0, size.width(), size.height(), GL_RGBA, GL_UNSIGNED_SHORT, img.bits());
return img;
}
static QImage qt_gl_read_framebuffer(const QSize &size, GLenum internal_format, bool include_alpha, bool flip)
{
QOpenGLContext *ctx = QOpenGLContext::currentContext();
@ -1318,6 +1337,10 @@ static QImage qt_gl_read_framebuffer(const QSize &size, GLenum internal_format,
return qt_gl_read_framebuffer_rgb10a2(size, false, ctx).mirrored(false, flip);
case GL_RGB10_A2:
return qt_gl_read_framebuffer_rgb10a2(size, include_alpha, ctx).mirrored(false, flip);
case GL_RGB16:
return qt_gl_read_framebuffer_rgba16(size, false, ctx).mirrored(false, flip);
case GL_RGBA16:
return qt_gl_read_framebuffer_rgba16(size, include_alpha, ctx).mirrored(false, flip);
case GL_RGBA:
case GL_RGBA8:
default:
@ -1346,7 +1369,8 @@ Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format,
is used only when internalTextureFormat() is set to \c GL_RGB. Since Qt 5.2
the function will fall back to premultiplied RGBA8888 or RGBx8888 when
reading to (A)RGB32 is not supported, and this includes OpenGL ES. Since Qt
5.4 an A2BGR30 image is returned if the internal format is RGB10_A2.
5.4 an A2BGR30 image is returned if the internal format is RGB10_A2, and since
Qt 5.12 a RGBA64 image is return if the internal format is RGBA16.
If the rendering in the framebuffer was not done with premultiplied alpha in mind,
create a wrapper QImage with a non-premultiplied format. This is necessary before

View File

@ -1567,6 +1567,7 @@ void QOpenGL2PaintEngineEx::drawImage(const QRectF& dest, const QImage& image, c
switch (image.format()) {
case QImage::Format_RGBA8888:
case QImage::Format_ARGB32:
case QImage::Format_RGBA64:
d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::NonPremultipliedImageSrc);
bindOption = 0;
break;

View File

@ -61,6 +61,10 @@
#define GL_RGB10_A2 0x8059
#endif
#ifndef GL_RGBA16
#define GL_RGBA16 0x805B
#endif
#ifndef GL_BGRA
#define GL_BGRA 0x80E1
#endif
@ -193,6 +197,15 @@ qsizetype QOpenGLTextureUploader::textureImage(GLenum target, const QImage &imag
pixelType = GL_UNSIGNED_BYTE;
targetFormat = image.format();
break;
case QImage::Format_RGBX64:
case QImage::Format_RGBA64:
case QImage::Format_RGBA64_Premultiplied:
externalFormat = internalFormat = GL_RGBA;
if (isOpenGL12orBetter || (context->isOpenGLES() && context->format().majorVersion() >= 3))
internalFormat = GL_RGBA16;
pixelType = GL_UNSIGNED_SHORT;
targetFormat = image.format();
break;
case QImage::Format_Indexed8:
if (sRgbBinding) {
// Always needs conversion
@ -262,11 +275,15 @@ qsizetype QOpenGLTextureUploader::textureImage(GLenum target, const QImage &imag
targetFormat = QImage::Format_ARGB32_Premultiplied;
else if (targetFormat == QImage::Format_RGBA8888)
targetFormat = QImage::Format_RGBA8888_Premultiplied;
else if (targetFormat == QImage::Format_RGBA64)
targetFormat = QImage::Format_RGBA64_Premultiplied;
} else {
if (targetFormat == QImage::Format_ARGB32_Premultiplied)
targetFormat = QImage::Format_ARGB32;
else if (targetFormat == QImage::Format_RGBA8888_Premultiplied)
targetFormat = QImage::Format_RGBA8888;
else if (targetFormat == QImage::Format_RGBA64_Premultiplied)
targetFormat = QImage::Format_RGBA64;
}
if (sRgbBinding) {

File diff suppressed because it is too large Load Diff

View File

@ -1143,6 +1143,8 @@ static Q_ALWAYS_INLINE const uint *qt_convertRGBA8888ToARGB32PM(uint *buffer, co
return buffer;
}
template<bool RGBA> void qt_convertRGBA64ToARGB32(uint *dst, const QRgba64 *src, int count);
const uint qt_bayer_matrix[16][16] = {
{ 0x1, 0xc0, 0x30, 0xf0, 0xc, 0xcc, 0x3c, 0xfc,
0x3, 0xc3, 0x33, 0xf3, 0xf, 0xcf, 0x3f, 0xff},
@ -1232,9 +1234,15 @@ typedef const uint *(QT_FASTCALL *FetchAndConvertPixelsFunc)(uint *buffer, const
typedef void (QT_FASTCALL *ConvertAndStorePixelsFunc)(uchar *dest, const uint *src, int index, int count,
const QVector<QRgb> *clut, QDitherInfo *dither);
typedef const QRgba64 *(QT_FASTCALL *FetchAndConvertPixelsFunc64)(QRgba64 *buffer, const uchar *src, int index, int count,
const QVector<QRgb> *clut, QDitherInfo *dither);
typedef void (QT_FASTCALL *ConvertAndStorePixelsFunc64)(uchar *dest, const QRgba64 *src, int index, int count,
const QVector<QRgb> *clut, QDitherInfo *dither);
typedef void (QT_FASTCALL *ConvertFunc)(uint *buffer, int count, const QVector<QRgb> *clut);
typedef const QRgba64 *(QT_FASTCALL *ConvertFunc64)(QRgba64 *buffer, const uint *src, int count,
const QVector<QRgb> *clut, QDitherInfo *dither);
typedef void (QT_FASTCALL *Convert64Func)(quint64 *buffer, int count, const QVector<QRgb> *clut);
typedef const QRgba64 *(QT_FASTCALL *ConvertTo64Func)(QRgba64 *buffer, const uint *src, int count,
const QVector<QRgb> *clut, QDitherInfo *dither);
typedef void (QT_FASTCALL *RbSwapFunc)(uchar *dst, const uchar *src, int count);
@ -1249,6 +1257,7 @@ struct QPixelLayout
BPP16,
BPP24,
BPP32,
BPP64,
BPPCount
};
@ -1257,17 +1266,19 @@ struct QPixelLayout
BPP bpp;
RbSwapFunc rbSwap;
ConvertFunc convertToARGB32PM;
ConvertFunc64 convertToARGB64PM;
ConvertTo64Func convertToRGBA64PM;
FetchAndConvertPixelsFunc fetchToARGB32PM;
FetchAndConvertPixelsFunc64 fetchToRGBA64PM;
ConvertAndStorePixelsFunc storeFromARGB32PM;
ConvertAndStorePixelsFunc storeFromRGB32;
};
extern ConvertAndStorePixelsFunc64 qStoreFromRGBA64PM[QImage::NImageFormats];
extern QPixelLayout qPixelLayouts[QImage::NImageFormats];
extern MemRotateFunc qMemRotateFunctions[QPixelLayout::BPPCount][3];
QT_END_NAMESPACE
#endif // QDRAWHELPER_P_H

View File

@ -332,6 +332,20 @@ void QT_FASTCALL destStore64RGBA8888_sse4(QRasterBuffer *rasterBuffer, int x, in
convertARGBFromRGBA64PM_sse4<true>(dest, buffer, length);
}
void QT_FASTCALL storeARGB32FromRGBA64PM_sse4(uchar *dest, const QRgba64 *src, int index, int count,
const QVector<QRgb> *, QDitherInfo *)
{
uint *d = (uint*)dest + index;
convertARGBFromRGBA64PM_sse4<false>(d, src, count);
}
void QT_FASTCALL storeRGBA8888FromRGBA64PM_sse4(uchar *dest, const QRgba64 *src, int index, int count,
const QVector<QRgb> *, QDitherInfo *)
{
uint *d = (uint*)dest + index;
convertARGBFromRGBA64PM_sse4<true>(d, src, count);
}
template
void QT_FASTCALL storeA2RGB30PMFromARGB32PM_sse4<PixelOrderBGR>(uchar *dest, const uint *src, int index, int count,
const QVector<QRgb> *, QDitherInfo *);

View File

@ -239,6 +239,12 @@ inline void qt_memrotate90_template<quint32>(const quint32 *src, int w, int h, i
qt_memrotate90_tiled_unpacked(src, w, h, sstride, dest, dstride);
}
template <>
inline void qt_memrotate90_template<quint64>(const quint64 *src, int w, int h, int sstride, quint64 *dest, int dstride)
{
qt_memrotate90_tiled_unpacked(src, w, h, sstride, dest, dstride);
}
template <class T>
Q_STATIC_TEMPLATE_FUNCTION
inline void qt_memrotate180_template(const T *src, int w, int h, int sstride, T *dest, int dstride)
@ -275,6 +281,12 @@ inline void qt_memrotate270_template<quint32>(const quint32 *src, int w, int h,
qt_memrotate270_tiled_unpacked(src, w, h, sstride, dest, dstride);
}
template <>
inline void qt_memrotate270_template<quint64>(const quint64 *src, int w, int h, int sstride, quint64 *dest, int dstride)
{
qt_memrotate270_tiled_unpacked(src, w, h, sstride, dest, dstride);
}
#define QT_IMPL_MEMROTATE(type) \
Q_GUI_EXPORT void qt_memrotate90(const type *src, int w, int h, int sstride, \
type *dest, int dstride) \
@ -309,9 +321,7 @@ Q_GUI_EXPORT void qt_memrotate270(const type *src, int w, int h, int sstride, \
qt_memrotate270_tiled_unpacked(src, w, h, sstride, dest, dstride); \
}
QT_IMPL_MEMROTATE(quint64)
QT_IMPL_MEMROTATE(quint32)
QT_IMPL_MEMROTATE(quint16)
QT_IMPL_MEMROTATE(quint24)
@ -377,6 +387,22 @@ void qt_memrotate270_32(const uchar *srcPixels, int w, int h, int sbpl, uchar *d
qt_memrotate270((const uint *)srcPixels, w, h, sbpl, (uint *)destPixels, dbpl);
}
void qt_memrotate90_64(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
{
qt_memrotate90((const quint64 *)srcPixels, w, h, sbpl, (quint64 *)destPixels, dbpl);
}
void qt_memrotate180_64(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
{
qt_memrotate180((const quint64 *)srcPixels, w, h, sbpl, (quint64 *)destPixels, dbpl);
}
void qt_memrotate270_64(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
{
qt_memrotate270((const quint64 *)srcPixels, w, h, sbpl, (quint64 *)destPixels, dbpl);
}
MemRotateFunc qMemRotateFunctions[QPixelLayout::BPPCount][3] =
// 90, 180, 270
{
@ -387,6 +413,7 @@ MemRotateFunc qMemRotateFunctions[QPixelLayout::BPPCount][3] =
{ qt_memrotate90_16, qt_memrotate180_16, qt_memrotate270_16 }, // BPP16,
{ qt_memrotate90_24, qt_memrotate180_24, qt_memrotate270_24 }, // BPP24
{ qt_memrotate90_32, qt_memrotate180_32, qt_memrotate270_32 }, // BPP32
{ qt_memrotate90_64, qt_memrotate180_64, qt_memrotate270_64 }, // BPP64
};
QT_END_NAMESPACE

View File

@ -65,6 +65,7 @@ QT_DECL_MEMROTATE(quint32);
QT_DECL_MEMROTATE(quint16);
QT_DECL_MEMROTATE(quint24);
QT_DECL_MEMROTATE(quint8);
QT_DECL_MEMROTATE(quint64);
#undef QT_DECL_MEMROTATE

View File

@ -291,6 +291,12 @@ static QLatin1String formatToString(QImage::Format format)
return QLatin1String("Alpha8");
case QImage::Format_Grayscale8:
return QLatin1String("Grayscale8");
case QImage::Format_RGBX64:
return QLatin1String("RGBx64");
case QImage::Format_RGBA64:
return QLatin1String("RGBA64");
case QImage::Format_RGBA64_Premultiplied:
return QLatin1String("RGBA64pm");
default:
break;
};
@ -2347,7 +2353,9 @@ void tst_QImage::rgbSwapped_data()
{
QTest::addColumn<QImage::Format>("format");
for (int i = QImage::Format_Indexed8; i < QImage::Format_Alpha8; ++i) {
for (int i = QImage::Format_Indexed8; i < QImage::NImageFormats; ++i) {
if (i == QImage::Format_Alpha8 || i == QImage::Format_Grayscale8)
continue;
QTest::addRow("%s", formatToString(QImage::Format(i)).data()) << QImage::Format(i);
}
}
@ -2515,14 +2523,7 @@ void tst_QImage::mirrored()
void tst_QImage::inplaceRgbSwapped_data()
{
QTest::addColumn<QImage::Format>("format");
QTest::newRow("Format_ARGB32_Premultiplied") << QImage::Format_ARGB32_Premultiplied;
QTest::newRow("Format_RGBA8888") << QImage::Format_RGBA8888;
QTest::newRow("Format_A2RGB30_Premultiplied") << QImage::Format_A2RGB30_Premultiplied;
QTest::newRow("Format_RGB888") << QImage::Format_RGB888;
QTest::newRow("Format_RGB16") << QImage::Format_RGB16;
QTest::newRow("Format_Indexed8") << QImage::Format_Indexed8;
rgbSwapped_data();
}
void tst_QImage::inplaceRgbSwapped()
@ -2553,9 +2554,9 @@ void tst_QImage::inplaceRgbSwapped()
for (int i = 0; i < imageSwapped.width(); ++i) {
QRgb referenceColor = testColor[i];
QRgb swappedColor = imageSwapped.pixel(i, 0);
QCOMPARE(qRed(swappedColor) & 0xf8, qBlue(referenceColor) & 0xf8);
QCOMPARE(qGreen(swappedColor) & 0xf8, qGreen(referenceColor) & 0xf8);
QCOMPARE(qBlue(swappedColor) & 0xf8, qRed(referenceColor) & 0xf8);
QCOMPARE(qRed(swappedColor) & 0xf0, qBlue(referenceColor) & 0xf0);
QCOMPARE(qGreen(swappedColor) & 0xf0, qGreen(referenceColor) & 0xf0);
QCOMPARE(qBlue(swappedColor) & 0xf0, qRed(referenceColor) & 0xf0);
}
QCOMPARE(imageSwapped.constScanLine(0), orginalPtr);
@ -2771,9 +2772,13 @@ void tst_QImage::genericRgbConversion_data()
QTest::addColumn<QImage::Format>("format");
QTest::addColumn<QImage::Format>("dest_format");
for (int i = QImage::Format_RGB32; i < QImage::Format_Alpha8; ++i) {
for (int i = QImage::Format_RGB32; i < QImage::NImageFormats; ++i) {
if (i == QImage::Format_Alpha8 || i == QImage::Format_Grayscale8)
continue;
const QLatin1String formatI = formatToString(QImage::Format(i));
for (int j = QImage::Format_RGB32; j < QImage::Format_Alpha8; ++j) {
for (int j = QImage::Format_RGB32; j < QImage::NImageFormats; ++j) {
if (j == QImage::Format_Alpha8 || j == QImage::Format_Grayscale8)
continue;
if (i == j)
continue;
QTest::addRow("%s -> %s", formatI.data(), formatToString(QImage::Format(j)).data())
@ -2810,8 +2815,12 @@ void tst_QImage::inplaceRgbConversion_data()
QTest::addColumn<QImage::Format>("format");
QTest::addColumn<QImage::Format>("dest_format");
for (int i = QImage::Format_RGB32; i < QImage::Format_Alpha8; ++i) {
for (int j = QImage::Format_RGB32; j < QImage::Format_Alpha8; ++j) {
for (int i = QImage::Format_RGB32; i < QImage::NImageFormats; ++i) {
if (i == QImage::Format_Alpha8 || i == QImage::Format_Grayscale8)
continue;
for (int j = QImage::Format_RGB32; j < QImage::NImageFormats; ++j) {
if (j == QImage::Format_Alpha8 || j == QImage::Format_Grayscale8)
continue;
if (i == j)
continue;
QTest::addRow("%s -> %s", formatToString(QImage::Format(i)).data(), formatToString(QImage::Format(j)).data())
@ -2844,10 +2853,10 @@ void tst_QImage::inplaceRgbConversion()
QCOMPARE(qGreen(convertedColor) & 0xF0, i * 16);
}
}
if (image.depth() == imageConverted.depth())
if (qt_depthForFormat(format) == qt_depthForFormat(dest_format))
QCOMPARE(imageConverted.constScanLine(0), originalPtr);
{
if (qt_depthForFormat(format) <= 32) {
// Test attempted inplace conversion of images created on existing buffer
static const quint32 readOnlyData[] = { 0xff0102ffU, 0xff0506ffU, 0xff0910ffU, 0xff1314ffU };
quint32 readWriteData[] = { 0xff0102ffU, 0xff0506ffU, 0xff0910ffU, 0xff1314ffU };
@ -2980,7 +2989,9 @@ void tst_QImage::invertPixelsRGB_data()
{
QTest::addColumn<QImage::Format>("image_format");
for (int i = QImage::Format_RGB32; i < QImage::Format_Alpha8; ++i) {
for (int i = QImage::Format_RGB32; i < QImage::NImageFormats; ++i) {
if (i == QImage::Format_Alpha8 || i == QImage::Format_Grayscale8)
continue;
QTest::addRow("%s", formatToString(QImage::Format(i)).data()) << QImage::Format(i);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -234,6 +234,7 @@ void tst_QImageReader::readImage_data()
QTest::newRow("BMP: high mask bit set") << QString("rgb32bf.bmp") << true << QByteArray("bmp");
QTest::newRow("XPM: marble") << QString("marble.xpm") << true << QByteArray("xpm");
QTest::newRow("PNG: kollada") << QString("kollada.png") << true << QByteArray("png");
QTest::newRow("PNG: kollada 16bpc") << QString("kollada-16bpc.png") << true << QByteArray("png");
QTest::newRow("PPM: teapot") << QString("teapot.ppm") << true << QByteArray("ppm");
QTest::newRow("PPM: runners") << QString("runners.ppm") << true << QByteArray("ppm");
QTest::newRow("PPM: test") << QString("test.ppm") << true << QByteArray("ppm");
@ -523,6 +524,7 @@ void tst_QImageReader::imageFormat_data()
QTest::newRow("bmp-4") << QString("test32v5.bmp") << QByteArray("bmp") << QImage::Format_RGB32;
QTest::newRow("png") << QString("kollada.png") << QByteArray("png") << QImage::Format_ARGB32;
QTest::newRow("png-2") << QString("YCbCr_cmyk.png") << QByteArray("png") << QImage::Format_RGB32;
QTest::newRow("png-3") << QString("kollada-16bpc.png") << QByteArray("png") << QImage::Format_RGBA64;
QTest::newRow("svg") << QString("rect.svg") << QByteArray("svg") << QImage::Format_ARGB32_Premultiplied;
QTest::newRow("svgz") << QString("rect.svgz") << QByteArray("svgz") << QImage::Format_ARGB32_Premultiplied;
}
@ -1850,6 +1852,8 @@ void tst_QImageReader::saveFormat_data()
QTest::newRow("Format_RGB888") << QImage::Format_RGB888;
QTest::newRow("Format_RGB444") << QImage::Format_RGB444;
QTest::newRow("Format_ARGB4444_Premultiplied") << QImage::Format_ARGB4444_Premultiplied;
QTest::newRow("Format_RGBA64") << QImage::Format_RGBA64;
QTest::newRow("Format_RGBA64_Premultiplied") << QImage::Format_RGBA64_Premultiplied;
}
void tst_QImageReader::saveFormat()

View File

@ -1091,6 +1091,7 @@ void tst_QPainter::fillRect_data()
QTest::newRow("argb32pm") << QImage::Format_ARGB32_Premultiplied;
QTest::newRow("rgba8888pm") << QImage::Format_RGBA8888_Premultiplied;
QTest::newRow("rgba64pm") << QImage::Format_RGBA64_Premultiplied;
}
void tst_QPainter::fillRect()
@ -2443,6 +2444,24 @@ void tst_QPainter::setOpacity_data()
QTest::newRow("A2RGB30P on RGB30") << QImage::Format_RGB30
<< QImage::Format_A2RGB30_Premultiplied;
QTest::newRow("RGBA64P on RGBA64P") << QImage::Format_RGBA64_Premultiplied
<< QImage::Format_RGBA64_Premultiplied;
QTest::newRow("RGBA64 on RGBA64") << QImage::Format_RGBA64
<< QImage::Format_RGBA64;
QTest::newRow("RGBx64 on RGBx64") << QImage::Format_RGBX64
<< QImage::Format_RGBX64;
QTest::newRow("RGBA64P on ARGB32P") << QImage::Format_ARGB32_Premultiplied
<< QImage::Format_RGBA64_Premultiplied;
QTest::newRow("RGBx64 on ARGB32P") << QImage::Format_ARGB32_Premultiplied
<< QImage::Format_RGBX64;
QTest::newRow("ARGB32P on RGBA64P") << QImage::Format_RGBA64_Premultiplied
<< QImage::Format_ARGB32_Premultiplied;
}
void tst_QPainter::setOpacity()
@ -3847,6 +3866,8 @@ void tst_QPainter::gradientPixelFormat_data()
QTest::newRow("rgbx8888") << QImage::Format_RGBX8888;
QTest::newRow("rgba8888") << QImage::Format_RGBA8888;
QTest::newRow("rgba8888_pm") << QImage::Format_RGBA8888_Premultiplied;
QTest::newRow("rgbx64") << QImage::Format_RGBX64;
QTest::newRow("rgba64_pm") << QImage::Format_RGBA64_Premultiplied;
}
void tst_QPainter::gradientPixelFormat()
@ -4784,7 +4805,19 @@ void tst_QPainter::blendARGBonRGB_data()
<< QPainter::CompositionMode_SourceIn << qRgba(255, 0, 0, 127) << 255 ;
QTest::newRow("ARGB_PM source-in ARGB32") << QImage::Format_ARGB32 << QImage::Format_ARGB32_Premultiplied
<< QPainter::CompositionMode_SourceIn << qRgba(127, 0, 0, 127) << 255;
// Only ARGB does inverse premultiply, on the rest over and source gives similar results:
QTest::newRow("ARGB over RGBA8888") << QImage::Format_RGBA8888 << QImage::Format_ARGB32
<< QPainter::CompositionMode_SourceOver << qRgba(255, 0, 0, 127) << 127;
QTest::newRow("ARGB_PM over RGBA8888") << QImage::Format_RGBA8888 << QImage::Format_ARGB32_Premultiplied
<< QPainter::CompositionMode_SourceOver << qRgba(127, 0, 0, 127) << 127;
QTest::newRow("ARGB source RGBA8888") << QImage::Format_RGBA8888 << QImage::Format_ARGB32
<< QPainter::CompositionMode_Source << qRgba(255, 0, 0, 127) << 255;
QTest::newRow("ARGB_PM source RGBA8888") << QImage::Format_RGBA8888 << QImage::Format_ARGB32_Premultiplied
<< QPainter::CompositionMode_Source << qRgba(127, 0, 0, 127) << 255;
QTest::newRow("ARGB source-in RGBA8888") << QImage::Format_RGBA8888 << QImage::Format_ARGB32
<< QPainter::CompositionMode_SourceIn << qRgba(255, 0, 0, 127) << 255;
QTest::newRow("ARGB_PM source-in RGBA8888") << QImage::Format_RGBA8888 << QImage::Format_ARGB32_Premultiplied
<< QPainter::CompositionMode_SourceIn << qRgba(127, 0, 0, 127) << 255;
// Only ARGB32 and RGBA8888 does inverse premultiply, on the rest over and source gives similar results:
QTest::newRow("ARGB over RGB32") << QImage::Format_RGB32 << QImage::Format_ARGB32
<< QPainter::CompositionMode_SourceOver << qRgba(255, 0, 0, 127) << 127;
QTest::newRow("ARGB_PM over RGB32") << QImage::Format_RGB32 << QImage::Format_ARGB32_Premultiplied
@ -4821,18 +4854,6 @@ void tst_QPainter::blendARGBonRGB_data()
<< QPainter::CompositionMode_SourceIn << qRgba(255, 0, 0, 127) << 127;
QTest::newRow("ARGB_PM source-in RGBx8888") << QImage::Format_RGBX8888 << QImage::Format_ARGB32_Premultiplied
<< QPainter::CompositionMode_SourceIn << qRgba(127, 0, 0, 127) << 127;
QTest::newRow("ARGB over RGBA8888") << QImage::Format_RGBA8888 << QImage::Format_ARGB32
<< QPainter::CompositionMode_SourceOver << qRgba(255, 0, 0, 127) << 127;
QTest::newRow("ARGB_PM over RGBA8888") << QImage::Format_RGBA8888 << QImage::Format_ARGB32_Premultiplied
<< QPainter::CompositionMode_SourceOver << qRgba(127, 0, 0, 127) << 127;
QTest::newRow("ARGB source RGBA8888") << QImage::Format_RGBA8888 << QImage::Format_ARGB32
<< QPainter::CompositionMode_Source << qRgba(255, 0, 0, 127) << 255;
QTest::newRow("ARGB_PM source RGBA8888") << QImage::Format_RGBA8888 << QImage::Format_ARGB32_Premultiplied
<< QPainter::CompositionMode_Source << qRgba(127, 0, 0, 127) << 255;
QTest::newRow("ARGB source-in RGBA8888") << QImage::Format_RGBA8888 << QImage::Format_ARGB32
<< QPainter::CompositionMode_SourceIn << qRgba(255, 0, 0, 127) << 255;
QTest::newRow("ARGB_PM source-in RGBA8888") << QImage::Format_RGBA8888 << QImage::Format_ARGB32_Premultiplied
<< QPainter::CompositionMode_SourceIn << qRgba(127, 0, 0, 127) << 255;
QTest::newRow("ARGB over RGB16") << QImage::Format_RGB16 << QImage::Format_ARGB32
<< QPainter::CompositionMode_SourceOver << qRgba(255, 0, 0, 127) << 123;
QTest::newRow("ARGB_PM over RGB16") << QImage::Format_RGB16 << QImage::Format_ARGB32_Premultiplied

View File

@ -82,6 +82,8 @@ private slots:
void fboRendering();
void fboRenderingRGB30_data();
void fboRenderingRGB30();
void fboRenderingRGB64_data();
void fboRenderingRGB64();
void fboHandleNulledAfterContextDestroyed();
void fboMRT();
void fboMRT_differentFormats();
@ -614,6 +616,10 @@ void tst_QOpenGL::fboRenderingRGB30_data()
#define GL_RGB10_A2 0x8059
#endif
#ifndef GL_RGBA16
#define GL_RGBA16 0x805B
#endif
#ifndef GL_FRAMEBUFFER_RENDERABLE
#define GL_FRAMEBUFFER_RENDERABLE 0x8289
#endif
@ -622,7 +628,7 @@ void tst_QOpenGL::fboRenderingRGB30_data()
#define GL_FULL_SUPPORT 0x82B7
#endif
static bool hasRGB10A2(QOpenGLContext *ctx)
static bool supportsInternalFboFormat(QOpenGLContext *ctx, int glFormat)
{
if (ctx->format().majorVersion() < 3)
return false;
@ -631,7 +637,7 @@ static bool hasRGB10A2(QOpenGLContext *ctx)
GLint value = -1;
QOpenGLFunctions_4_2_Core* vFuncs = ctx->versionFunctions<QOpenGLFunctions_4_2_Core>();
if (vFuncs && vFuncs->initializeOpenGLFunctions()) {
vFuncs->glGetInternalformativ(GL_TEXTURE_2D, GL_RGB10_A2, GL_FRAMEBUFFER_RENDERABLE, 1, &value);
vFuncs->glGetInternalformativ(GL_TEXTURE_2D, glFormat, GL_FRAMEBUFFER_RENDERABLE, 1, &value);
if (value != GL_FULL_SUPPORT)
return false;
}
@ -657,7 +663,7 @@ void tst_QOpenGL::fboRenderingRGB30()
if (!QOpenGLFramebufferObject::hasOpenGLFramebufferObjects())
QSKIP("QOpenGLFramebufferObject not supported on this platform");
if (!hasRGB10A2(&ctx))
if (!supportsInternalFboFormat(&ctx, GL_RGB10_A2))
QSKIP("An internal RGB30_A2 format is not guaranteed on this platform");
// No multisample with combined depth/stencil attachment:
@ -713,6 +719,71 @@ void tst_QOpenGL::fboRenderingRGB30()
QVERIFY(((pixel >> 20) & 0x3f) > 0);
}
void tst_QOpenGL::fboRenderingRGB64_data()
{
common_data();
}
void tst_QOpenGL::fboRenderingRGB64()
{
#if defined(Q_OS_LINUX) && defined(Q_CC_GNU) && !defined(__x86_64__)
QSKIP("QTBUG-22617");
#endif
QFETCH(int, surfaceClass);
QScopedPointer<QSurface> surface(createSurface(surfaceClass));
QOpenGLContext ctx;
QVERIFY(ctx.create());
QVERIFY(ctx.makeCurrent(surface.data()));
if (!QOpenGLFramebufferObject::hasOpenGLFramebufferObjects())
QSKIP("QOpenGLFramebufferObject not supported on this platform");
if (!supportsInternalFboFormat(&ctx, GL_RGBA16))
QSKIP("An internal RGBA16 format is not guaranteed on this platform");
// No multisample with combined depth/stencil attachment:
QOpenGLFramebufferObjectFormat fboFormat;
fboFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
fboFormat.setInternalTextureFormat(GL_RGBA16);
// Uncomplicate things by using POT:
const QSize size(256, 128);
QOpenGLFramebufferObject fbo(size, fboFormat);
if (fbo.attachment() != QOpenGLFramebufferObject::CombinedDepthStencil)
QSKIP("FBOs missing combined depth~stencil support");
QVERIFY(fbo.bind());
QPainter fboPainter;
QOpenGLPaintDevice device(fbo.width(), fbo.height());
bool painterBegun = fboPainter.begin(&device);
QVERIFY(painterBegun);
qt_opengl_draw_test_pattern(&fboPainter, fbo.width(), fbo.height());
fboPainter.end();
QImage fb = fbo.toImage();
QCOMPARE(fb.format(), QImage::Format_RGBA64_Premultiplied);
QCOMPARE(fb.size(), size);
qt_opengl_check_test_pattern(fb);
// Check rendering can handle precise 16 bit color values.
fboPainter.begin(&device);
fboPainter.fillRect(QRect(0, 0, 256, 128), QColor::fromRgba64(5, 1002, 8001, 65535));
fboPainter.end();
fb = fbo.toImage();
QRgba64 pixel = ((QRgba64*)fb.bits())[0];
QCOMPARE(pixel.red(), 5);
QCOMPARE(pixel.green(), 1002);
QCOMPARE(pixel.blue(), 8001);
}
void tst_QOpenGL::fboHandleNulledAfterContextDestroyed()
{
QWindow window;
@ -844,7 +915,7 @@ void tst_QOpenGL::fboMRT_differentFormats()
if (!f->hasOpenGLFeature(QOpenGLFunctions::MultipleRenderTargets))
QSKIP("Multiple render targets not supported on this platform");
if (!hasRGB10A2(&ctx))
if (!supportsInternalFboFormat(&ctx, GL_RGB10_A2))
QSKIP("RGB10_A2 not supported on this platform");
// 3 color attachments, same size, different internal format, depth/stencil.

View File

@ -177,6 +177,9 @@ const char *PaintCommands::imageFormatTable[] = {
"Format_A2RGB30_Premultiplied",
"Alpha8",
"Grayscale8",
"RGBx64",
"RGBA64",
"RGBA64_Premultiplied",
};
int PaintCommands::translateEnum(const char *table[], const QString &pattern, int limit)

View File

@ -649,6 +649,9 @@ void tst_QPainter::drawPixmapImage_data_helper(bool pixmaps)
"A2RGB30_pm",
"Alpha8",
"Grayscale8",
"RGBx64",
"RGBA64",
"RGBA64_pm",
};
const QImage::Format pixmapFormats[] = {