File indexing completed on 2024-05-12 04:44:29

0001 // SPDX-FileCopyrightText: Lukas Sommer <sommerluk@gmail.com>
0002 // SPDX-License-Identifier: BSD-2-Clause OR MIT
0003 
0004 #ifndef CHROMAHUEIMAGEPARAMETERS_H
0005 #define CHROMAHUEIMAGEPARAMETERS_H
0006 
0007 #include <qglobal.h>
0008 #include <qmetatype.h>
0009 #include <qsharedpointer.h>
0010 #include <qvariant.h>
0011 
0012 namespace PerceptualColor
0013 {
0014 class AsyncImageRenderCallback;
0015 class RgbColorSpace;
0016 
0017 /** @internal
0018  *
0019  * @brief Parameters for an image of a chroma hue plane.
0020  *
0021  * For usage with @ref AsyncImageProvider.
0022  *
0023  * @warning The default constructor constructs an object with an empty
0024  * @ref rgbColorSpace. Before using this object, you should initialize
0025  * @ref rgbColorSpace.
0026  *
0027  * This is a cut through the gamut body. The cut is orthogonal to
0028  * the L axis, so it shows the a‑b diagram (speaking in terms of
0029  * LAB color model) respectively chroma‑hue diagram (speaking in terms
0030  * of LCH color model). The center of the coordinate system is in
0031  * the center of the image (floating point precision).
0032  *
0033  * Each pixel has the color that corresponds to the coordinate point <em>at
0034  * the middle</em> of the pixel for in-gamut coordinate points, and
0035  * a solid background color for out-of-gamut coordinate points.
0036  *
0037  * The <tt>QImage</tt> that is provided by this class has the
0038  * size <tt>QSize(@ref ChromaHueImageParameters::imageSizePhysical,
0039  * @ref ChromaHueImageParameters::imageSizePhysical)</tt>. There is an
0040  * imaginary circle in the center of the <tt>QImage</tt> with a distance
0041  * of @ref ChromaHueImageParameters::borderPhysical to the border of
0042  * the <tt>QImage</tt>. All pixels within this imaginary circle, plus an
0043  * overlap for safety, are calculated correctly. All other pixels
0044  * have arbitrary values. Therefore, when you paint this
0045  * image somewhere, you have to clip the painting to the imaginary circle.
0046  * Thanks to the overlap, there will be no rendering artefacts, regardless
0047  * of whether you render the circle with or without antialiasing.
0048  *
0049  * This type is declared as type to Qt’s type system via
0050  * <tt>Q_DECLARE_METATYPE</tt>. Depending on your use case (for
0051  * example if you want to use for <em>queued</em> signal-slot connections),
0052  * you might consider calling <tt>qRegisterMetaType()</tt> for
0053  * this type, once you have a QApplication object.
0054  *
0055  * @internal
0056  *
0057  * @todo Why does @ref ChromaHueImageParameters::render() not make everything
0058  * outside the circle transparent? Because it would look ugly without
0059  * antialiasing. And when we use antialiasing various times to cut of
0060  * unwanted artefacts, half-opaque pixel become quarter-opaque and so on,
0061  * so this would be ugly, too. However, we could use a single image to
0062  * work on, and for each interlacing pass result, create a copy and
0063  * apply the antialiased circle only to the copy. This would of course
0064  * require more memory. On the other hand: When calling
0065  * @ref AsyncImageRenderThread::deliverInterlacingPass() a signal will
0066  * be emitted, which will create a copy anyway… */
0067 struct ChromaHueImageParameters final {
0068 public:
0069     /** @brief The border size, measured in physical pixels. */
0070     qreal borderPhysical = 0;
0071     /** @brief The device pixel ratio as floating point. */
0072     qreal devicePixelRatioF = 1;
0073     /** @brief Image size, measured in physical pixels. */
0074     int imageSizePhysical = 0;
0075     /** @brief Lightness.
0076      *
0077      * This is the lightness (L) value in the LCH color model.
0078      *
0079      * Range: <tt>[0, 100]</tt> */
0080     qreal lightness = 50;
0081     /** @brief Pointer to @ref RgbColorSpace object
0082      *
0083      * @warning The default constructor constructs an object with an empty
0084      * @ref rgbColorSpace. Before using this object, you must initialize
0085      * @ref rgbColorSpace. */
0086     QSharedPointer<PerceptualColor::RgbColorSpace> rgbColorSpace = nullptr;
0087     [[nodiscard]] bool operator==(const ChromaHueImageParameters &other) const;
0088     [[nodiscard]] bool operator!=(const ChromaHueImageParameters &other) const;
0089 
0090     static void render(const QVariant &variantParameters, AsyncImageRenderCallback &callbackObject);
0091 };
0092 
0093 } // namespace PerceptualColor
0094 
0095 Q_DECLARE_METATYPE(PerceptualColor::ChromaHueImageParameters)
0096 
0097 #endif // CHROMAHUEIMAGEPARAMETERS_H