diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2024-03-14 10:05:31 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2024-04-05 18:40:47 +0200 |
commit | 05b84673045a5f4432a6caa9bea08d8fba1e1a03 (patch) | |
tree | 68ecd72c6448dffe970f079120e5c6a14e4c4c63 /tests | |
parent | a786404036990c595e25122fae5f710f12bc397b (diff) |
Add color space model, making gray color spaces explicit
This also adds image conversion of both format and color space, which
will also be required later for conversions to CMYK formats and color
spaces.
Change-Id: I578c0a010ffcdb4df4cf9080c0621fac8bc342bf
Reviewed-by: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
Diffstat (limited to 'tests')
-rw-r--r-- | tests/auto/gui/image/qimage/tst_qimage.cpp | 78 | ||||
-rw-r--r-- | tests/auto/gui/painting/qcolorspace/tst_qcolorspace.cpp | 172 | ||||
-rw-r--r-- | tests/libfuzzer/gui/painting/qcolorspace/fromiccprofile/main.cpp | 6 |
3 files changed, 255 insertions, 1 deletions
diff --git a/tests/auto/gui/image/qimage/tst_qimage.cpp b/tests/auto/gui/image/qimage/tst_qimage.cpp index 3177fa84b1..1abca9e188 100644 --- a/tests/auto/gui/image/qimage/tst_qimage.cpp +++ b/tests/auto/gui/image/qimage/tst_qimage.cpp @@ -169,6 +169,9 @@ private slots: void largeInplaceRgbConversion_data(); void largeInplaceRgbConversion(); + void colorSpaceRgbConversion_data(); + void colorSpaceRgbConversion(); + void deepCopyWhenPaintingActive(); void scaled_QTBUG19157(); @@ -3244,6 +3247,81 @@ void tst_QImage::largeInplaceRgbConversion() } } +void tst_QImage::colorSpaceRgbConversion_data() +{ + QTest::addColumn<QImage::Format>("fromFormat"); + QTest::addColumn<QImage::Format>("toFormat"); + + // The various possible code paths for color space conversions compatible with RGB color spaces: + QImage::Format formats[] = { + QImage::Format_RGB32, + QImage::Format_ARGB32, + QImage::Format_ARGB32_Premultiplied, + QImage::Format_RGBX64, + QImage::Format_RGBA64, + QImage::Format_RGBA64_Premultiplied, + QImage::Format_RGBX32FPx4, + QImage::Format_RGBA32FPx4, + QImage::Format_RGBA32FPx4_Premultiplied, + QImage::Format_Grayscale8, + QImage::Format_Grayscale16, + }; + + for (auto fromFormat : formats) { + const QLatin1String formatI = formatToString(fromFormat); + for (auto toFormat : formats) { + QTest::addRow("%s -> %s", formatI.data(), formatToString(toFormat).data()) + << fromFormat << toFormat; + } + } +} + +void tst_QImage::colorSpaceRgbConversion() +{ + // Test that all color space conversions work + QFETCH(QImage::Format, fromFormat); + QFETCH(QImage::Format, toFormat); + + bool srcGrayscale = fromFormat == QImage::Format_Grayscale8 || fromFormat == QImage::Format_Grayscale16; + bool dstGrayscale = toFormat == QImage::Format_Grayscale8 || toFormat == QImage::Format_Grayscale16; + + QImage image(16, 16, fromFormat); + image.setColorSpace(QColorSpace::SRgb); + + for (int i = 0; i < image.height(); ++i) { + for (int j = 0; j < image.width(); ++j) { + if (srcGrayscale || dstGrayscale) + image.setPixel(j, i, qRgb((i + j) * 8, (i + j) * 8, (i + j) * 8)); + else + image.setPixel(j, i, qRgb(j * 16, i * 16, (i + j) * 8)); + } + } + + QImage imageConverted = image.convertedToColorSpace(QColorSpace::DisplayP3, toFormat); + QCOMPARE(imageConverted.format(), toFormat); + QCOMPARE(imageConverted.size(), image.size()); + if (dstGrayscale) { + int gray = 0; + for (int x = 0; x < image.width(); ++x) { + int newGray = qGray(imageConverted.pixel(x, 6)); + QCOMPARE_GE(newGray, gray); + gray = newGray; + } + } else { + int red = 0; + int blue = 0; + for (int x = 0; x < image.width(); ++x) { + int newRed = qRed(imageConverted.pixel(x, 5)); + int newBlue = qBlue(imageConverted.pixel(x, 7)); + QCOMPARE_GE(newBlue, blue); + QCOMPARE_GE(newRed, red); + blue = newBlue; + red = newRed; + } + } +} + + void tst_QImage::deepCopyWhenPaintingActive() { QImage image(64, 64, QImage::Format_ARGB32_Premultiplied); diff --git a/tests/auto/gui/painting/qcolorspace/tst_qcolorspace.cpp b/tests/auto/gui/painting/qcolorspace/tst_qcolorspace.cpp index 780c264f06..6cecf2ca70 100644 --- a/tests/auto/gui/painting/qcolorspace/tst_qcolorspace.cpp +++ b/tests/auto/gui/painting/qcolorspace/tst_qcolorspace.cpp @@ -42,9 +42,12 @@ private slots: void imageConversionOverLargerGamut(); void imageConversionOverLargerGamut2_data(); void imageConversionOverLargerGamut2(); + void imageConversionOverAnyGamutFP_data(); + void imageConversionOverAnyGamutFP(); + void imageConversionOverAnyGamutFP2_data(); + void imageConversionOverAnyGamutFP2(); void imageConversionOverNonThreeComponentMatrix_data(); void imageConversionOverNonThreeComponentMatrix(); - void loadImage(); void primaries(); @@ -63,6 +66,11 @@ private slots: void transferFunctionTable(); void description(); + void whitePoint_data(); + void whitePoint(); + void setWhitePoint(); + void grayColorSpace(); + void grayColorSpaceEffectivelySRgb(); }; tst_QColorSpace::tst_QColorSpace() @@ -530,6 +538,80 @@ void tst_QColorSpace::imageConversionOverLargerGamut2() QVERIFY(resultImage.pixelColor(0, 255).greenF() > 1.0f); } +void tst_QColorSpace::imageConversionOverAnyGamutFP_data() +{ + QTest::addColumn<QColorSpace::NamedColorSpace>("fromColorSpace"); + QTest::addColumn<QColorSpace::NamedColorSpace>("toColorSpace"); + + QTest::newRow("sRGB -> Display-P3") << QColorSpace::SRgb << QColorSpace::DisplayP3; + QTest::newRow("sRGB -> Adobe RGB") << QColorSpace::SRgb << QColorSpace::AdobeRgb; + QTest::newRow("sRGB -> ProPhoto RGB") << QColorSpace::SRgb << QColorSpace::ProPhotoRgb; + QTest::newRow("Adobe RGB -> sRGB") << QColorSpace::AdobeRgb << QColorSpace::SRgb; + QTest::newRow("Adobe RGB -> Display-P3") << QColorSpace::AdobeRgb << QColorSpace::DisplayP3; + QTest::newRow("Adobe RGB -> ProPhoto RGB") << QColorSpace::AdobeRgb << QColorSpace::ProPhotoRgb; + QTest::newRow("Display-P3 -> sRGB") << QColorSpace::DisplayP3 << QColorSpace::SRgb; + QTest::newRow("Display-P3 -> Adobe RGB") << QColorSpace::DisplayP3 << QColorSpace::AdobeRgb; + QTest::newRow("Display-P3 -> ProPhoto RGB") << QColorSpace::DisplayP3 << QColorSpace::ProPhotoRgb; +} + +void tst_QColorSpace::imageConversionOverAnyGamutFP() +{ + QFETCH(QColorSpace::NamedColorSpace, fromColorSpace); + QFETCH(QColorSpace::NamedColorSpace, toColorSpace); + + QColorSpace csfrom(fromColorSpace); + QColorSpace csto(toColorSpace); + csfrom.setTransferFunction(QColorSpace::TransferFunction::Linear); + csto.setTransferFunction(QColorSpace::TransferFunction::Linear); + + QImage testImage(256, 256, QImage::Format_RGBX32FPx4); + testImage.setColorSpace(csfrom); + for (int y = 0; y < 256; ++y) + for (int x = 0; x < 256; ++x) + testImage.setPixel(x, y, qRgb(x, y, 0)); + + QImage resultImage = testImage.convertedToColorSpace(csto); + resultImage.convertToColorSpace(csfrom); + + for (int y = 0; y < 256; ++y) { + for (int x = 0; x < 256; ++x) { + QCOMPARE(resultImage.pixel(x, y), testImage.pixel(x, y)); + } + } +} + +void tst_QColorSpace::imageConversionOverAnyGamutFP2_data() +{ + imageConversionOverAnyGamutFP_data(); +} + +void tst_QColorSpace::imageConversionOverAnyGamutFP2() +{ + QFETCH(QColorSpace::NamedColorSpace, fromColorSpace); + QFETCH(QColorSpace::NamedColorSpace, toColorSpace); + + // Same as imageConversionOverAnyGamutFP but using format switching transform + QColorSpace csfrom(fromColorSpace); + QColorSpace csto(toColorSpace); + csfrom.setTransferFunction(QColorSpace::TransferFunction::Linear); + csto.setTransferFunction(QColorSpace::TransferFunction::Linear); + + QImage testImage(256, 256, QImage::Format_RGB32); + testImage.setColorSpace(csfrom); + for (int y = 0; y < 256; ++y) + for (int x = 0; x < 256; ++x) + testImage.setPixel(x, y, qRgb(x, y, 0)); + + QImage resultImage = testImage.convertedToColorSpace(csto, QImage::Format_RGBX32FPx4); + resultImage.convertToColorSpace(csfrom, QImage::Format_RGB32); + + for (int y = 0; y < 256; ++y) { + for (int x = 0; x < 256; ++x) { + QCOMPARE(resultImage.pixel(x, y), testImage.pixel(x, y)); + } + } +} + void tst_QColorSpace::imageConversionOverNonThreeComponentMatrix_data() { QTest::addColumn<QColorSpace>("fromColorSpace"); @@ -569,6 +651,7 @@ void tst_QColorSpace::imageConversionOverNonThreeComponentMatrix() testImage.setPixel(x, y, qRgb(x, y, 0)); QImage resultImage = testImage.convertedToColorSpace(toColorSpace); + QCOMPARE(resultImage.size(), testImage.size()); for (int y = 0; y < 256; ++y) { int lastRed = 0; for (int x = 0; x < 256; ++x) { @@ -834,5 +917,92 @@ void tst_QColorSpace::description() QCOMPARE(srgb.description(), QLatin1String("Linear sRGB")); // Set to empty returns default behavior } +void tst_QColorSpace::whitePoint_data() +{ + QTest::addColumn<QColorSpace::NamedColorSpace>("namedColorSpace"); + QTest::addColumn<QPointF>("whitePoint"); + + QTest::newRow("sRGB") << QColorSpace::SRgb << QColorVector::D65Chromaticity(); + QTest::newRow("Adobe RGB") << QColorSpace::AdobeRgb << QColorVector::D65Chromaticity(); + QTest::newRow("Display-P3") << QColorSpace::DisplayP3 << QColorVector::D65Chromaticity(); + QTest::newRow("ProPhoto RGB") << QColorSpace::ProPhotoRgb << QColorVector::D50Chromaticity(); +} + +void tst_QColorSpace::whitePoint() +{ + QFETCH(QColorSpace::NamedColorSpace, namedColorSpace); + QFETCH(QPointF, whitePoint); + + QColorSpace colorSpace(namedColorSpace); + QPointF wpt = colorSpace.whitePoint(); + QCOMPARE_LE(qAbs(wpt.x() - whitePoint.x()), 0.0000001); + QCOMPARE_LE(qAbs(wpt.y() - whitePoint.y()), 0.0000001); +} + +void tst_QColorSpace::setWhitePoint() +{ + QColorSpace colorSpace(QColorSpace::SRgb); + colorSpace.setWhitePoint(QPointF(0.33, 0.33)); + QCOMPARE_NE(colorSpace, QColorSpace(QColorSpace::SRgb)); + colorSpace.setWhitePoint(QColorVector::D65Chromaticity()); + // Check our matrix manipulations returned us to where we came from + QCOMPARE(colorSpace, QColorSpace(QColorSpace::SRgb)); +} + +void tst_QColorSpace::grayColorSpace() +{ + QColorSpace spc; + QCOMPARE(spc.colorModel(), QColorSpace::ColorModel::Undefined); + QVERIFY(!spc.isValid()); + spc.setWhitePoint(QColorVector::D65Chromaticity()); + spc.setTransferFunction(QColorSpace::TransferFunction::SRgb); + QVERIFY(spc.isValid()); + QCOMPARE(spc.colorModel(), QColorSpace::ColorModel::Gray); + + QColorSpace spc2(QColorVector::D65Chromaticity(), QColorSpace::TransferFunction::SRgb); + QVERIFY(spc2.isValid()); + QCOMPARE(spc2.colorModel(), QColorSpace::ColorModel::Gray); + QCOMPARE(spc, spc2); + + QImage rgbImage(1, 8, QImage::Format_RGB32); + QImage grayImage(1, 255, QImage::Format_Grayscale8); + // RGB images can not have gray color space + rgbImage.setColorSpace(spc2); + grayImage.setColorSpace(spc2); + QCOMPARE_NE(rgbImage.colorSpace(), spc2); + QCOMPARE(grayImage.colorSpace(), spc2); + // But gray images can have RGB color space + rgbImage.setColorSpace(QColorSpace::SRgb); + grayImage.setColorSpace(QColorSpace::SRgb); + QCOMPARE(rgbImage.colorSpace(), QColorSpace(QColorSpace::SRgb)); + QCOMPARE(grayImage.colorSpace(), QColorSpace(QColorSpace::SRgb)); + + // While we can not set a grayscale color space on rgb image, we can convert to one + QImage grayImage2 = rgbImage.convertedToColorSpace(spc2); + QCOMPARE(grayImage2.colorSpace(), spc2); + QCOMPARE(grayImage2.format(), QImage::Format_Grayscale8); +} + +void tst_QColorSpace::grayColorSpaceEffectivelySRgb() +{ + // Test grayscale colorspace conversion by making a gray color space that should act like sRGB on gray values. + QColorSpace sRgb(QColorSpace::SRgb); + QColorSpace sRgbGray(QColorVector::D65Chromaticity(), QColorSpace::TransferFunction::SRgb); + + QImage grayImage1(256, 1, QImage::Format_Grayscale8); + QImage grayImage2(256, 1, QImage::Format_Grayscale8); + for (int i = 0; i < 256; ++i) { + grayImage1.bits()[i] = i; + grayImage2.bits()[i] = i; + } + grayImage1.setColorSpace(sRgb); + grayImage2.setColorSpace(sRgbGray); + + QImage rgbImage1 = grayImage1.convertedTo(QImage::Format_RGB32); + QImage rgbImage2 = grayImage2.convertedToColorSpace(sRgb, QImage::Format_RGB32); + + QCOMPARE(rgbImage1, rgbImage2); +} + QTEST_MAIN(tst_QColorSpace) #include "tst_qcolorspace.moc" diff --git a/tests/libfuzzer/gui/painting/qcolorspace/fromiccprofile/main.cpp b/tests/libfuzzer/gui/painting/qcolorspace/fromiccprofile/main.cpp index 3bd94785ef..5055b57229 100644 --- a/tests/libfuzzer/gui/painting/qcolorspace/fromiccprofile/main.cpp +++ b/tests/libfuzzer/gui/painting/qcolorspace/fromiccprofile/main.cpp @@ -5,6 +5,7 @@ #include <QGuiApplication> #include <QColorSpace> +#include <QImage> extern "C" int LLVMFuzzerTestOneInput(const char *data, size_t size) { // to reduce noise and increase speed @@ -28,7 +29,12 @@ extern "C" int LLVMFuzzerTestOneInput(const char *data, size_t size) { Q_UNUSED(b); QRgb color = 0xfaf8fa00; color = trans1.map(color); + QImage img(16, 2, cs.colorModel() == QColorSpace::ColorModel::Rgb ? QImage::Format_RGB32 : QImage::Format_Grayscale8); + img.setColorSpace(cs); + QImage img2 = img.convertedToColorSpace(QColorSpace::SRgb); if (cs.isValidTarget()) { + QImage img3 = img2.convertedToColorSpace(cs); + QColorTransform trans2 = QColorSpace(QColorSpace::SRgb).transformationToColorSpace(cs); bool a = (trans1 == trans2); Q_UNUSED(a); |