diff --git a/tests/manual/colormanagement/CMakeLists.txt b/tests/manual/colormanagement/CMakeLists.txt new file mode 100644 index 00000000000..cc0dd8efe34 --- /dev/null +++ b/tests/manual/colormanagement/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +qt_internal_add_manual_test(colormanagement + SOURCES + main.cpp + LIBRARIES + Qt::Gui + Qt::GuiPrivate +) diff --git a/tests/manual/colormanagement/main.cpp b/tests/manual/colormanagement/main.cpp new file mode 100644 index 00000000000..e0c1e41f77f --- /dev/null +++ b/tests/manual/colormanagement/main.cpp @@ -0,0 +1,117 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include +#include + +QString debugDescription(const QColorSpace &colorSpace) +{ + QString str; + QDebug dbg(&str); + dbg << colorSpace; + return str; +} + +// The color space of our assets that we need to color match from. +// In real world apps this could be different for each QImage etc. +static const QColorSpace assetColorSpace = QColorSpace::AdobeRgb; + +class TestWindow : public QRasterWindow +{ +public: + using QRasterWindow::QRasterWindow; + TestWindow() + { + resize(900, 300); + setFlag(Qt::NoDropShadowWindowHint); + + // Moving a window to a different screen may not result + // in an automatic expose/paint event, as the window's + // content might still be valid on the new screen. In + // our case we know it's not, as we need to update the + // screen information we reflect in the paintEvent below. + QObject::connect(this, &QWindow::screenChanged, + this, qOverload<>(&QRasterWindow::update)); + } + + bool colorManaged = false; + +protected: + void paintEvent(QPaintEvent *) override + { + QPainter painter(this); + + auto requestedColorSpace = requestedFormat().colorSpace(); + auto windowColorSpace = format().colorSpace(); + auto screenColorSpace = screen()->handle()->colorSpace(); + + auto targetColorSpace = windowColorSpace; + if (!targetColorSpace.isValid()) { + qWarning("Window does not report color space! Using screen color space as target"); + targetColorSpace = screenColorSpace; + } + auto colorTransform = assetColorSpace.transformationToColorSpace(targetColorSpace); + + if (!colorManaged && requestedColorSpace.isValid() && !colorTransform.isIdentity()) { + qWarning() << "Requested" << requestedColorSpace << "but got" + << targetColorSpace << "and not prepared to do color matching"; + } + + QColor colors[] = { + QColor(Qt::red), + QColor(Qt::green), + QColor(Qt::blue), + QColor(Qt::cyan), + QColor(Qt::magenta), + QColor(Qt::yellow) + }; + qreal colorWidth = width() / qreal(std::size(colors)); + for (size_t i = 0; i < std::size(colors); ++i) { + QColor color = colors[i]; + if (colorManaged) + color = colorTransform.map(color); + + painter.fillRect(QRectF(colorWidth * i, 0, colorWidth, height()), color); + } + + QRect rect(0, 0, width(), height()); + painter.fillRect(rect.adjusted(20, 100, -20, -100), Qt::white); + painter.drawText(rect, Qt::AlignCenter, + QString("Assets: %1\nRequested: %2\nWindow: %3\nScreen: %4").arg( + debugDescription(assetColorSpace) + ).arg( + debugDescription(windowColorSpace) + ).arg( + debugDescription(windowColorSpace) + ).arg( + debugDescription(screenColorSpace) + )); + } +}; + +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + + TestWindow defaultColorSpaceWindow; + defaultColorSpaceWindow.setTitle(QString( + "Color-space unaware (pass-through, assuming surface/screen is %1)").arg( + assetColorSpace.description())); + defaultColorSpaceWindow.show(); + + TestWindow colorSpaceAwareWindow; + colorSpaceAwareWindow.setTitle(QString( + "Color-space aware (match %1 to surface)").arg(assetColorSpace.description())); + colorSpaceAwareWindow.colorManaged = true; + colorSpaceAwareWindow.show(); + + TestWindow explicitColorSpaceWindow; + explicitColorSpaceWindow.setTitle(QString( + "Explicit %1 surface").arg(assetColorSpace.description())); + auto format = explicitColorSpaceWindow.format(); + format.setColorSpace(assetColorSpace); + explicitColorSpaceWindow.setFormat(format); + explicitColorSpaceWindow.show(); + + return app.exec(); +}