Round evenly in INV_PREMUL
Currently INV_PREMUL rounds strictly down. While PREMUL rounds evenly. This patch adds 0x8000 to the intermediate results in INV_PREMUL before right shifting, thereby achieving even rounding. The rounding also makes PREMUL(INV_PREMUL()) into an identify operation, which means we can safely convert ARGB32PM to ARGB32 and back without ever losing color details. A test is added to verify this. Change-Id: I1267e109caddcff0c01d726cb5c1c1e9fa5f7996 Reviewed-by: Gunnar Sletta <gunnar.sletta@jollamobile.com>
This commit is contained in:
parent
fa83803119
commit
0226795cf3
@ -699,7 +699,8 @@ static Q_ALWAYS_INLINE uint INV_PREMUL(uint p) {
|
|||||||
return 0;
|
return 0;
|
||||||
// (p*(0x00ff00ff/alpha)) >> 16 == (p*255)/alpha for all p and alpha <= 256.
|
// (p*(0x00ff00ff/alpha)) >> 16 == (p*255)/alpha for all p and alpha <= 256.
|
||||||
const uint invAlpha = 0x00ff00ffU / alpha;
|
const uint invAlpha = 0x00ff00ffU / alpha;
|
||||||
return qRgba((qRed(p)*invAlpha)>>16, (qGreen(p)*invAlpha)>>16, (qBlue(p)*invAlpha)>>16, alpha);
|
// We add 0x8000 to get even rounding. The rounding also ensures that PREMUL(INV_PREMUL(p)) == p for all p.
|
||||||
|
return qRgba((qRed(p)*invAlpha + 0x8000)>>16, (qGreen(p)*invAlpha + 0x8000)>>16, (qBlue(p)*invAlpha + 0x8000)>>16, alpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct quint24 {
|
struct quint24 {
|
||||||
|
@ -166,6 +166,8 @@ private slots:
|
|||||||
void deepCopyWhenPaintingActive();
|
void deepCopyWhenPaintingActive();
|
||||||
void scaled_QTBUG19157();
|
void scaled_QTBUG19157();
|
||||||
|
|
||||||
|
void convertOverUnPreMul();
|
||||||
|
|
||||||
void cleanupFunctions();
|
void cleanupFunctions();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2422,6 +2424,26 @@ void tst_QImage::scaled_QTBUG19157()
|
|||||||
QVERIFY(!foo.isNull());
|
QVERIFY(!foo.isNull());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QImage::convertOverUnPreMul()
|
||||||
|
{
|
||||||
|
QImage image(256, 256, QImage::Format_ARGB32_Premultiplied);
|
||||||
|
|
||||||
|
for (int j = 0; j < 256; j++) {
|
||||||
|
for (int i = 0; i <= j; i++) {
|
||||||
|
image.setPixel(i, j, qRgba(i, i, i, j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QImage image2 = image.convertToFormat(QImage::Format_ARGB32).convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
||||||
|
|
||||||
|
for (int j = 0; j < 256; j++) {
|
||||||
|
for (int i = 0; i <= j; i++) {
|
||||||
|
QCOMPARE(qAlpha(image2.pixel(i, j)), qAlpha(image.pixel(i, j)));
|
||||||
|
QCOMPARE(qGray(image2.pixel(i, j)), qGray(image.pixel(i, j)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void cleanupFunction(void* info)
|
static void cleanupFunction(void* info)
|
||||||
{
|
{
|
||||||
bool *called = static_cast<bool*>(info);
|
bool *called = static_cast<bool*>(info);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user