diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2016-12-07 14:37:12 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-08-11 14:12:48 +0000 |
commit | 9c9f98f2ff255da3e9a3ccdb81a82c53a105c8f9 (patch) | |
tree | 2f352bdf94b81d24271b7ce9e2bab3174ad0dff7 /tests/auto/gui | |
parent | 1c623bc6d1c0a7ca52d81ca72c64f36898b3e12c (diff) |
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>
Diffstat (limited to 'tests/auto/gui')
-rw-r--r-- | tests/auto/gui/image/qimage/tst_qimage.cpp | 49 | ||||
-rw-r--r-- | tests/auto/gui/image/qimagereader/images/kollada-16bpc.png | bin | 0 -> 24360 bytes | |||
-rw-r--r-- | tests/auto/gui/image/qimagereader/tst_qimagereader.cpp | 4 | ||||
-rw-r--r-- | tests/auto/gui/painting/qpainter/tst_qpainter.cpp | 47 | ||||
-rw-r--r-- | tests/auto/gui/qopengl/tst_qopengl.cpp | 79 |
5 files changed, 143 insertions, 36 deletions
diff --git a/tests/auto/gui/image/qimage/tst_qimage.cpp b/tests/auto/gui/image/qimage/tst_qimage.cpp index d32913b822..08aa00df56 100644 --- a/tests/auto/gui/image/qimage/tst_qimage.cpp +++ b/tests/auto/gui/image/qimage/tst_qimage.cpp @@ -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); } } diff --git a/tests/auto/gui/image/qimagereader/images/kollada-16bpc.png b/tests/auto/gui/image/qimagereader/images/kollada-16bpc.png Binary files differnew file mode 100644 index 0000000000..b99d5f8a6f --- /dev/null +++ b/tests/auto/gui/image/qimagereader/images/kollada-16bpc.png diff --git a/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp b/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp index 170f551dbf..0f8afe63b3 100644 --- a/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp +++ b/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp @@ -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() diff --git a/tests/auto/gui/painting/qpainter/tst_qpainter.cpp b/tests/auto/gui/painting/qpainter/tst_qpainter.cpp index 58ac025f0c..877306e8b8 100644 --- a/tests/auto/gui/painting/qpainter/tst_qpainter.cpp +++ b/tests/auto/gui/painting/qpainter/tst_qpainter.cpp @@ -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 diff --git a/tests/auto/gui/qopengl/tst_qopengl.cpp b/tests/auto/gui/qopengl/tst_qopengl.cpp index 5b1af9b6c9..f1360b9efe 100644 --- a/tests/auto/gui/qopengl/tst_qopengl.cpp +++ b/tests/auto/gui/qopengl/tst_qopengl.cpp @@ -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. |