File indexing completed on 2024-05-26 04:32:15

0001 /*
0002  *  SPDX-FileCopyrightText: 2019 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #ifndef LCMSRGBP2020PQCOLORSPACE_H
0008 #define LCMSRGBP2020PQCOLORSPACE_H
0009 
0010 
0011 #include <colorspaces/rgb_u8/RgbU8ColorSpace.h>
0012 #include <colorspaces/rgb_u16/RgbU16ColorSpace.h>
0013 
0014 #ifdef HAVE_OPENEXR
0015 #include <colorspaces/rgb_f16/RgbF16ColorSpace.h>
0016 #endif
0017 
0018 #include <colorspaces/rgb_f32/RgbF32ColorSpace.h>
0019 
0020 #include "KoColorConversionTransformationFactory.h"
0021 
0022 #include <LcmsRGBP2020PQColorSpaceTransformation.h>
0023 
0024 template <class T>
0025 struct ColorSpaceFromFactory {
0026 };
0027 
0028 template<>
0029 struct ColorSpaceFromFactory<RgbU8ColorSpaceFactory> {
0030   typedef RgbU8ColorSpace type;
0031 };
0032 
0033 template<>
0034 struct ColorSpaceFromFactory<RgbU16ColorSpaceFactory> {
0035   typedef RgbU16ColorSpace type;
0036 };
0037 
0038 #ifdef HAVE_OPENEXR
0039 template<>
0040 struct ColorSpaceFromFactory<RgbF16ColorSpaceFactory> {
0041   typedef RgbF16ColorSpace type;
0042 };
0043 #endif
0044 
0045 template<>
0046 struct ColorSpaceFromFactory<RgbF32ColorSpaceFactory> {
0047   typedef RgbF32ColorSpace type;
0048 };
0049 
0050 /**
0051  *  Define a singly linked list of supported bit depth traits
0052  */
0053 template<class T> struct NextTrait { using type = void; };
0054 template<> struct NextTrait<KoBgrU8Traits> { using type = KoBgrU16Traits; };
0055 
0056 #ifdef HAVE_OPENEXR
0057 template<> struct NextTrait<KoBgrU16Traits> { using type = KoRgbF16Traits; };
0058 template<> struct NextTrait<KoRgbF16Traits> { using type = KoRgbF32Traits; };
0059 #else
0060 template<> struct NextTrait<KoBgrU16Traits> { using type = KoRgbF32Traits; };
0061 #endif
0062 
0063 /**
0064  * Recursively add bit-depths conversions to the color space. We add only
0065  * **outgoing** conversions for every RGB color space. That is, every color
0066  * space has exactly three outgoing edges for color conversion.
0067  */
0068 template<typename ParentColorSpace, typename CurrentTraits>
0069 void addInternalConversion(QList<KoColorConversionTransformationFactory*> &list, CurrentTraits*)
0070 {
0071     // general case: add a converter and recurse for the next traits
0072     list << new LcmsScaleRGBP2020PQTransformationFactory<ParentColorSpace, CurrentTraits>();
0073 
0074     using NextTraits = typename NextTrait<CurrentTraits>::type;
0075     addInternalConversion<ParentColorSpace>(list, static_cast<NextTraits*>(0));
0076 }
0077 
0078 template<typename ParentColorSpace>
0079 void addInternalConversion(QList<KoColorConversionTransformationFactory*> &list, typename ParentColorSpace::ColorSpaceTraits*)
0080 {
0081     // exception: skip adding an edge to the same bit depth
0082 
0083     using CurrentTraits = typename ParentColorSpace::ColorSpaceTraits;
0084     using NextTraits = typename NextTrait<CurrentTraits>::type;
0085     addInternalConversion<ParentColorSpace>(list, static_cast<NextTraits*>(0));
0086 }
0087 
0088 template<typename ParentColorSpace>
0089 void addInternalConversion(QList<KoColorConversionTransformationFactory*> &, void*)
0090 {
0091     // stop recursion
0092 }
0093 
0094 template <class BaseColorSpaceFactory>
0095 class LcmsRGBP2020PQColorSpaceFactoryWrapper : public BaseColorSpaceFactory
0096 {
0097     typedef typename ColorSpaceFromFactory<BaseColorSpaceFactory>::type RelatedColorSpaceType;
0098 
0099     KoColorSpace *createColorSpace(const KoColorProfile *p) const override
0100     {
0101         return new RelatedColorSpaceType(this->name(), p->clone());
0102     }
0103 
0104     bool isHdr() const override {
0105         return this->colorDepthId() != Integer8BitsColorDepthID;
0106     }
0107 
0108     QList<KoColorConversionTransformationFactory *> colorConversionLinks() const override
0109     {
0110         QList<KoColorConversionTransformationFactory *> list;
0111 
0112         /**
0113          * We explicitly disable direct conversions to/from integer color spaces, because
0114          * they may cause the conversion system to choose them as an intermediate
0115          * color space for the conversion chain, e.g.
0116          * p709-g10 F32 -> p2020-g10 U16 -> Rec2020-pq U16, which is incorrect and loses
0117          * all the HDR data
0118          */
0119         list << new LcmsFromRGBP2020PQTransformationFactory<RelatedColorSpaceType, KoRgbF32Traits>();
0120         list << new LcmsToRGBP2020PQTransformationFactory<RelatedColorSpaceType, KoRgbF32Traits>();
0121 #ifdef HAVE_OPENEXR
0122         list << new LcmsFromRGBP2020PQTransformationFactory<RelatedColorSpaceType, KoRgbF16Traits>();
0123         list << new LcmsToRGBP2020PQTransformationFactory<RelatedColorSpaceType, KoRgbF16Traits>();
0124 #endif
0125 
0126 
0127         // internally, we can convert to RGB U8 if needed
0128         addInternalConversion<RelatedColorSpaceType>(list, static_cast<KoBgrU8Traits*>(0));
0129 
0130         return list;
0131     }
0132 };
0133 
0134 #endif // LCMSRGBP2020PQCOLORSPACE_H