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 LCMSRGBP2020PQCOLORSPACETRANSFORMATION_H
0008 #define LCMSRGBP2020PQCOLORSPACETRANSFORMATION_H
0009 
0010 #include "KoAlwaysInline.h"
0011 #include "KoColorModelStandardIds.h"
0012 #include "KoColorSpaceMaths.h"
0013 #include "KoColorModelStandardIdsUtils.h"
0014 #include "KoColorConversionTransformationFactory.h"
0015 #include "KoColorTransferFunctions.h"
0016 
0017 #include <colorspaces/rgb_u8/RgbU8ColorSpace.h>
0018 #include <colorspaces/rgb_u16/RgbU16ColorSpace.h>
0019 #ifdef HAVE_OPENEXR
0020 #include <colorspaces/rgb_f16/RgbF16ColorSpace.h>
0021 #endif
0022 #include <colorspaces/rgb_f32/RgbF32ColorSpace.h>
0023 
0024 
0025 namespace
0026 {
0027 
0028 template <class T>
0029 struct DstTraitsForSource {
0030     typedef KoRgbF32Traits result;
0031 };
0032 
0033 /**
0034  * If half format is present, we use it instead
0035  */
0036 #ifdef HAVE_OPENEXR
0037 template <>
0038 struct DstTraitsForSource<KoBgrU16Traits> {
0039     typedef KoRgbF16Traits result;
0040 };
0041 
0042 template <>
0043 struct DstTraitsForSource<KoBgrU8Traits> {
0044     typedef KoRgbF16Traits result;
0045 };
0046 #endif
0047 
0048 template <typename src_channel_type,
0049           typename dst_channel_type>
0050 struct RemoveSmpte2048Policy {
0051     static ALWAYS_INLINE dst_channel_type process(src_channel_type value) {
0052         return
0053             KoColorSpaceMaths<float, dst_channel_type>::scaleToA(
0054             removeSmpte2048Curve(
0055             KoColorSpaceMaths<src_channel_type, float>::scaleToA(
0056             value)));
0057     }
0058 };
0059 
0060 template <typename src_channel_type,
0061           typename dst_channel_type>
0062 struct ApplySmpte2048Policy {
0063     static ALWAYS_INLINE dst_channel_type process(src_channel_type value) {
0064         return
0065             KoColorSpaceMaths<float, dst_channel_type>::scaleToA(
0066             applySmpte2048Curve(
0067             KoColorSpaceMaths<src_channel_type, float>::scaleToA(
0068             value)));
0069     }
0070 };
0071 
0072 template <typename src_channel_type,
0073           typename dst_channel_type>
0074 struct NoopPolicy {
0075     static ALWAYS_INLINE dst_channel_type process(src_channel_type value) {
0076         return KoColorSpaceMaths<src_channel_type, dst_channel_type>::scaleToA(value);
0077     }
0078 };
0079 
0080 }
0081 
0082 template<typename SrcCSTraits,
0083          typename DstCSTraits,
0084          template<typename, typename> class Policy>
0085 struct ApplyRgbShaper : public KoColorConversionTransformation
0086 {
0087     ApplyRgbShaper(const KoColorSpace* srcCs,
0088                    const KoColorSpace* dstCs,
0089                    Intent renderingIntent,
0090                    ConversionFlags conversionFlags)
0091         : KoColorConversionTransformation(srcCs,
0092                                           dstCs,
0093                                           renderingIntent,
0094                                           conversionFlags)
0095     {
0096     }
0097 
0098     void transform(const quint8 *src, quint8 *dst, qint32 nPixels) const override {
0099         KIS_ASSERT(src != dst);
0100 
0101         const typename SrcCSTraits::Pixel *srcPixel = reinterpret_cast<const typename SrcCSTraits::Pixel*>(src);
0102         typename DstCSTraits::Pixel *dstPixel = reinterpret_cast<typename DstCSTraits::Pixel*>(dst);
0103 
0104         typedef typename SrcCSTraits::channels_type src_channel_type;
0105         typedef typename DstCSTraits::channels_type dst_channel_type;
0106         typedef Policy<src_channel_type, dst_channel_type> ConcretePolicy;
0107 
0108         for (int i = 0; i < nPixels; i++) {
0109             dstPixel->red = ConcretePolicy::process(srcPixel->red);
0110             dstPixel->green = ConcretePolicy::process(srcPixel->green);
0111             dstPixel->blue = ConcretePolicy::process(srcPixel->blue);
0112             dstPixel->alpha =
0113                 KoColorSpaceMaths<src_channel_type, dst_channel_type>::scaleToA(
0114                 srcPixel->alpha);
0115 
0116             srcPixel++;
0117             dstPixel++;
0118         }
0119     }
0120 
0121 };
0122 
0123 template<class ParentColorSpace, class DstColorSpaceTraits = typename DstTraitsForSource<typename ParentColorSpace::ColorSpaceTraits>::result>
0124 class LcmsFromRGBP2020PQTransformationFactory : public KoColorConversionTransformationFactory
0125 {
0126 public:
0127     LcmsFromRGBP2020PQTransformationFactory()
0128         : KoColorConversionTransformationFactory(RGBAColorModelID.id(),
0129                                                  colorDepthIdForChannelType<typename ParentColorSpace::ColorSpaceTraits::channels_type>().id(),
0130                                                  "High Dynamic Range UHDTV Wide Color Gamut Display (Rec. 2020) - SMPTE ST 2084 PQ EOTF",
0131                                                  RGBAColorModelID.id(),
0132                                                  colorDepthIdForChannelType<typename DstColorSpaceTraits::channels_type>().id(),
0133                                                  "Rec2020-elle-V4-g10.icc")
0134     {
0135     }
0136 
0137     KoColorConversionTransformation* createColorTransformation(const KoColorSpace* srcColorSpace,
0138                                                                const KoColorSpace* dstColorSpace,
0139                                                                KoColorConversionTransformation::Intent renderingIntent,
0140                                                                KoColorConversionTransformation::ConversionFlags conversionFlags) const override
0141     {
0142         return new ApplyRgbShaper<
0143                 typename ParentColorSpace::ColorSpaceTraits,
0144                 DstColorSpaceTraits,
0145                 RemoveSmpte2048Policy>(srcColorSpace,
0146                                        dstColorSpace,
0147                                        renderingIntent,
0148                                        conversionFlags);
0149     }
0150 };
0151 
0152 template<class ParentColorSpace, class DstColorSpaceTraits = typename DstTraitsForSource<typename ParentColorSpace::ColorSpaceTraits>::result>
0153 class LcmsToRGBP2020PQTransformationFactory : public KoColorConversionTransformationFactory
0154 {
0155 public:
0156     LcmsToRGBP2020PQTransformationFactory()
0157         : KoColorConversionTransformationFactory(RGBAColorModelID.id(),
0158                                                  colorDepthIdForChannelType<typename DstColorSpaceTraits::channels_type>().id(),
0159                                                  "Rec2020-elle-V4-g10.icc",
0160                                                  RGBAColorModelID.id(),
0161                                                  colorDepthIdForChannelType<typename ParentColorSpace::ColorSpaceTraits::channels_type>().id(),
0162                                                  "High Dynamic Range UHDTV Wide Color Gamut Display (Rec. 2020) - SMPTE ST 2084 PQ EOTF")
0163     {
0164     }
0165 
0166     KoColorConversionTransformation* createColorTransformation(const KoColorSpace* srcColorSpace,
0167                                                                const KoColorSpace* dstColorSpace,
0168                                                                KoColorConversionTransformation::Intent renderingIntent,
0169                                                                KoColorConversionTransformation::ConversionFlags conversionFlags) const override
0170     {
0171         return new ApplyRgbShaper<
0172                 DstColorSpaceTraits,
0173                 typename ParentColorSpace::ColorSpaceTraits,
0174                 ApplySmpte2048Policy>(srcColorSpace,
0175                                       dstColorSpace,
0176                                       renderingIntent,
0177                                       conversionFlags);
0178     }
0179 };
0180 
0181 template<class ParentColorSpace, class DstColorSpaceTraits>
0182 class LcmsScaleRGBP2020PQTransformationFactory : public KoColorConversionTransformationFactory
0183 {
0184 public:
0185     LcmsScaleRGBP2020PQTransformationFactory()
0186         : KoColorConversionTransformationFactory(RGBAColorModelID.id(),
0187                                                  colorDepthIdForChannelType<typename ParentColorSpace::ColorSpaceTraits::channels_type>().id(),
0188                                                  "High Dynamic Range UHDTV Wide Color Gamut Display (Rec. 2020) - SMPTE ST 2084 PQ EOTF",
0189                                                  RGBAColorModelID.id(),
0190                                                  colorDepthIdForChannelType<typename DstColorSpaceTraits::channels_type>().id(),
0191                                                  "High Dynamic Range UHDTV Wide Color Gamut Display (Rec. 2020) - SMPTE ST 2084 PQ EOTF")
0192     {
0193         KIS_SAFE_ASSERT_RECOVER_NOOP(srcColorDepthId() != dstColorDepthId());
0194     }
0195 
0196     KoColorConversionTransformation* createColorTransformation(const KoColorSpace* srcColorSpace,
0197                                                                const KoColorSpace* dstColorSpace,
0198                                                                KoColorConversionTransformation::Intent renderingIntent,
0199                                                                KoColorConversionTransformation::ConversionFlags conversionFlags) const override
0200     {
0201         return new ApplyRgbShaper<
0202                 typename ParentColorSpace::ColorSpaceTraits,
0203                 DstColorSpaceTraits,
0204                 NoopPolicy>(srcColorSpace,
0205                             dstColorSpace,
0206                             renderingIntent,
0207                             conversionFlags);
0208     }
0209 };
0210 
0211 #endif // LCMSRGBP2020PQCOLORSPACETRANSFORMATION_H