Fix accuracy of ARGB32->A2RGB30 conversions
It was converted over ARGB32PM, when it should have been directly converted to not lose accuracy, instead there was an unnecessary direct ARGB32->RGB30 conversion, which was converted to the necessary type. This also improves the selection of conversion over ARGB32PM or RGBA64PM for ARGB32 and RGBA8888 by using 32-bit conversion when alpha is not relevant. Change-Id: I5990d8a23b2909d3910d8c1213fa46477742b052 Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>bb10
parent
e6a0a945c5
commit
52a3f1b00c
|
|
@ -2060,27 +2060,6 @@ 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:
|
||||
case QImage::Format_Grayscale16:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
\internal
|
||||
*/
|
||||
|
|
@ -2092,9 +2071,11 @@ QImage QImage::convertToFormat_helper(Format format, Qt::ImageConversionFlags fl
|
|||
if (format == Format_Invalid || d->format == Format_Invalid)
|
||||
return QImage();
|
||||
|
||||
const QPixelLayout *destLayout = &qPixelLayouts[format];
|
||||
Image_Converter converter = qimage_converter_map[d->format][format];
|
||||
if (!converter && format > QImage::Format_Indexed8 && d->format > QImage::Format_Indexed8) {
|
||||
if (highColorPrecision(format) && highColorPrecision(d->format)) {
|
||||
if (qt_highColorPrecision(d->format, !destLayout->hasAlphaChannel)
|
||||
&& qt_highColorPrecision(format, !hasAlphaChannel())) {
|
||||
converter = convert_generic_to_rgb64;
|
||||
} else
|
||||
converter = convert_generic;
|
||||
|
|
|
|||
|
|
@ -260,10 +260,17 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im
|
|||
if (data->depth != qt_depthForFormat(dst_format))
|
||||
return false;
|
||||
|
||||
uint buf[BufferSize];
|
||||
uint *buffer = buf;
|
||||
const QPixelLayout *srcLayout = &qPixelLayouts[data->format];
|
||||
const QPixelLayout *destLayout = &qPixelLayouts[dst_format];
|
||||
|
||||
// The precision here is only ARGB32PM so don't convert between higher accuracy
|
||||
// formats (assert instead when we have a convert_generic_over_rgb64_inplace).
|
||||
if (qt_highColorPrecision(data->format, !destLayout->hasAlphaChannel)
|
||||
&& qt_highColorPrecision(dst_format, !srcLayout->hasAlphaChannel))
|
||||
return false;
|
||||
|
||||
uint buf[BufferSize];
|
||||
uint *buffer = buf;
|
||||
uchar *srcData = data->data;
|
||||
|
||||
Q_ASSERT(srcLayout->bpp == destLayout->bpp);
|
||||
|
|
@ -626,12 +633,13 @@ static bool convert_rgbswap_generic_inplace(QImageData *data, Qt::ImageConversio
|
|||
}
|
||||
|
||||
template<QtPixelOrder PixelOrder, bool RGBA>
|
||||
static void convert_RGB_to_RGB30(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
|
||||
static void convert_ARGB_to_A2RGB30(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
|
||||
{
|
||||
|
||||
Q_ASSERT(RGBA || src->format == QImage::Format_RGB32 || src->format == QImage::Format_ARGB32);
|
||||
Q_ASSERT(!RGBA || src->format == QImage::Format_RGBX8888 || src->format == QImage::Format_RGBA8888);
|
||||
Q_ASSERT(dest->format == QImage::Format_BGR30 || dest->format == QImage::Format_RGB30);
|
||||
Q_ASSERT(RGBA || src->format == QImage::Format_ARGB32);
|
||||
Q_ASSERT(!RGBA || src->format == QImage::Format_RGBA8888);
|
||||
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);
|
||||
|
||||
|
|
@ -646,7 +654,9 @@ static void convert_RGB_to_RGB30(QImageData *dest, const QImageData *src, Qt::Im
|
|||
QRgb c = *src_data;
|
||||
if (RGBA)
|
||||
c = RGBA2ARGB(c);
|
||||
*dest_data = qConvertRgb32ToRgb30<PixelOrder>(c);
|
||||
const uint alpha = (qAlpha(c) >> 6) * 85;
|
||||
c = BYTE_MUL(c, alpha);
|
||||
*dest_data = (qConvertRgb32ToRgb30<PixelOrder>(c) & 0x3fffffff) | (alpha << 30);
|
||||
++src_data;
|
||||
++dest_data;
|
||||
}
|
||||
|
|
@ -656,10 +666,10 @@ static void convert_RGB_to_RGB30(QImageData *dest, const QImageData *src, Qt::Im
|
|||
}
|
||||
|
||||
template<QtPixelOrder PixelOrder, bool RGBA>
|
||||
static bool convert_RGB_to_RGB30_inplace(QImageData *data, Qt::ImageConversionFlags)
|
||||
static bool convert_ARGB_to_A2RGB30_inplace(QImageData *data, Qt::ImageConversionFlags)
|
||||
{
|
||||
Q_ASSERT(RGBA || (data->format == QImage::Format_RGB32 || data->format == QImage::Format_ARGB32));
|
||||
Q_ASSERT(!RGBA || (data->format == QImage::Format_RGBX8888 || data->format == QImage::Format_RGBA8888));
|
||||
Q_ASSERT(RGBA || data->format == QImage::Format_ARGB32);
|
||||
Q_ASSERT(!RGBA || data->format == QImage::Format_RGBA8888);
|
||||
|
||||
const int pad = (data->bytes_per_line >> 2) - data->width;
|
||||
QRgb *rgb_data = (QRgb *) data->data;
|
||||
|
|
@ -670,13 +680,16 @@ static bool convert_RGB_to_RGB30_inplace(QImageData *data, Qt::ImageConversionFl
|
|||
QRgb c = *rgb_data;
|
||||
if (RGBA)
|
||||
c = RGBA2ARGB(c);
|
||||
*rgb_data = qConvertRgb32ToRgb30<PixelOrder>(c);
|
||||
const uint alpha = (qAlpha(c) >> 6) * 85;
|
||||
c = BYTE_MUL(c, alpha);
|
||||
*rgb_data = (qConvertRgb32ToRgb30<PixelOrder>(c) & 0x3fffffff) | (alpha << 30);
|
||||
++rgb_data;
|
||||
}
|
||||
rgb_data += pad;
|
||||
}
|
||||
|
||||
data->format = (PixelOrder == PixelOrderRGB) ? QImage::Format_RGB30 : QImage::Format_BGR30;
|
||||
data->format = (PixelOrder == PixelOrderRGB) ? QImage::Format_A2RGB30_Premultiplied
|
||||
: QImage::Format_A2BGR30_Premultiplied;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -2353,9 +2366,9 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
|
|||
0,
|
||||
0,
|
||||
0,
|
||||
convert_RGB_to_RGB30<PixelOrderBGR, false>,
|
||||
0,
|
||||
convert_RGB_to_RGB30<PixelOrderRGB, false>,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0, 0,
|
||||
0, 0, 0, 0, 0
|
||||
|
|
@ -2381,10 +2394,10 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
|
|||
convert_ARGB_to_RGBx,
|
||||
convert_ARGB_to_RGBA,
|
||||
0,
|
||||
convert_RGB_to_RGB30<PixelOrderBGR, false>,
|
||||
0,
|
||||
convert_RGB_to_RGB30<PixelOrderRGB, false>,
|
||||
convert_ARGB_to_A2RGB30<PixelOrderBGR, false>,
|
||||
0,
|
||||
convert_ARGB_to_A2RGB30<PixelOrderRGB, false>,
|
||||
0, 0,
|
||||
0,
|
||||
convert_ARGB32_to_RGBA64<false>,
|
||||
|
|
@ -2634,9 +2647,9 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
|
|||
0,
|
||||
convert_passthrough,
|
||||
convert_passthrough,
|
||||
convert_RGB_to_RGB30<PixelOrderBGR, true>,
|
||||
0,
|
||||
convert_RGB_to_RGB30<PixelOrderRGB, true>,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0, 0,
|
||||
0, 0, 0, 0, 0
|
||||
|
|
@ -2661,10 +2674,10 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
|
|||
mask_alpha_converter_RGBx,
|
||||
0,
|
||||
0,
|
||||
convert_RGB_to_RGB30<PixelOrderBGR, true>,
|
||||
0,
|
||||
convert_RGB_to_RGB30<PixelOrderRGB, true>,
|
||||
convert_ARGB_to_A2RGB30<PixelOrderBGR, true>,
|
||||
0,
|
||||
convert_ARGB_to_A2RGB30<PixelOrderRGB, true>,
|
||||
0, 0,
|
||||
0,
|
||||
convert_ARGB32_to_RGBA64<true>,
|
||||
|
|
@ -3017,9 +3030,9 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
|
|||
0,
|
||||
0,
|
||||
0,
|
||||
convert_RGB_to_RGB30_inplace<PixelOrderBGR, false>,
|
||||
0,
|
||||
convert_RGB_to_RGB30_inplace<PixelOrderRGB, false>,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0, 0,
|
||||
0, 0, 0, 0, 0
|
||||
|
|
@ -3044,10 +3057,10 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
|
|||
convert_ARGB_to_RGBA_inplace<QImage::Format_RGBX8888>,
|
||||
convert_ARGB_to_RGBA_inplace<QImage::Format_RGBA8888>,
|
||||
0,
|
||||
convert_RGB_to_RGB30_inplace<PixelOrderBGR, false>,
|
||||
0,
|
||||
convert_RGB_to_RGB30_inplace<PixelOrderRGB, false>,
|
||||
convert_ARGB_to_A2RGB30_inplace<PixelOrderBGR, false>,
|
||||
0,
|
||||
convert_ARGB_to_A2RGB30_inplace<PixelOrderRGB, false>,
|
||||
0, 0,
|
||||
0, 0, 0, 0, 0
|
||||
}, // Format_ARGB32
|
||||
|
|
@ -3123,9 +3136,9 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
|
|||
0,
|
||||
convert_passthrough_inplace<QImage::Format_RGBA8888>,
|
||||
convert_passthrough_inplace<QImage::Format_RGBA8888_Premultiplied>,
|
||||
convert_RGB_to_RGB30_inplace<PixelOrderBGR, true>,
|
||||
0,
|
||||
convert_RGB_to_RGB30_inplace<PixelOrderRGB, true>,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0, 0,
|
||||
0, 0, 0, 0, 0
|
||||
|
|
@ -3150,10 +3163,10 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
|
|||
mask_alpha_converter_rgbx_inplace,
|
||||
0,
|
||||
0,
|
||||
convert_RGB_to_RGB30_inplace<PixelOrderBGR, true>,
|
||||
0,
|
||||
convert_RGB_to_RGB30_inplace<PixelOrderRGB, true>,
|
||||
convert_ARGB_to_A2RGB30_inplace<PixelOrderBGR, true>,
|
||||
0,
|
||||
convert_ARGB_to_A2RGB30_inplace<PixelOrderRGB, true>,
|
||||
0, 0,
|
||||
0, 0, 0, 0, 0
|
||||
}, // Format_RGBA8888
|
||||
|
|
|
|||
|
|
@ -276,6 +276,29 @@ inline QImage::Format qt_alphaVersion(QImage::Format format)
|
|||
return QImage::Format_ARGB32_Premultiplied;
|
||||
}
|
||||
|
||||
inline bool qt_highColorPrecision(QImage::Format format, bool opaque = false)
|
||||
{
|
||||
// Formats with higher color precision than ARGB32_Premultiplied.
|
||||
switch (format) {
|
||||
case QImage::Format_ARGB32:
|
||||
case QImage::Format_RGBA8888:
|
||||
return !opaque;
|
||||
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:
|
||||
case QImage::Format_Grayscale16:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
inline QImage::Format qt_maybeAlphaVersionWithSameDepth(QImage::Format format)
|
||||
{
|
||||
const QImage::Format toFormat = qt_alphaVersion(format);
|
||||
|
|
|
|||
|
|
@ -924,6 +924,9 @@ void tst_QImage::convertToFormat_data()
|
|||
QTest::newRow("blue rgb30 -> argb32") << int(QImage::Format_RGB30) << 0xff0000ff
|
||||
<< int(QImage::Format_ARGB32) << 0xff0000ff;
|
||||
|
||||
QTest::newRow("semigray argb32 -> a2rgb30 pm") << int(QImage::Format_ARGB32) << 0x4c646565u
|
||||
<< int(QImage::Format_A2RGB30_Premultiplied) << 0x55212222u;
|
||||
|
||||
QTest::newRow("white gray8 -> argb pm") << int(QImage::Format_Grayscale8) << 0xfffffeffu
|
||||
<< int(QImage::Format_ARGB32_Premultiplied) << 0xfffefefeu;
|
||||
QTest::newRow("gray gray8 -> argb pm") << int(QImage::Format_Grayscale8) << 0xff565557u
|
||||
|
|
|
|||
Loading…
Reference in New Issue