File indexing completed on 2024-05-12 15:59:31

0001 /*
0002  *  SPDX-FileCopyrightText: 2007 Cyrille Berger <cberger@cberger.net>
0003  *
0004  * SPDX-License-Identifier: LGPL-2.1-or-later
0005 */
0006 
0007 #include "KoColorConversionAlphaTransformation.h"
0008 
0009 #include "KoColorSpace.h"
0010 #include "KoIntegerMaths.h"
0011 #include "KoColorSpaceTraits.h"
0012 #include "KoColorModelStandardIds.h"
0013 #include "KoColorModelStandardIdsUtils.h"
0014 
0015 /**
0016  * Converter from the alpha color space to any color space
0017  */
0018 template <typename alpha_channel_type>
0019 class KoColorConversionFromAlphaTransformation : public KoColorConversionTransformation
0020 {
0021 public:
0022     KoColorConversionFromAlphaTransformation(const KoColorSpace* srcCs, const KoColorSpace* dstCs,
0023                                              Intent renderingIntent,
0024                                              KoColorConversionTransformation::ConversionFlags conversionFlags)
0025         : KoColorConversionTransformation(srcCs, dstCs, renderingIntent, conversionFlags)
0026     {
0027     }
0028 
0029     void transform(const quint8 *src, quint8 *dst, qint32 nPixels) const override
0030     {
0031         const alpha_channel_type *srcPtr = reinterpret_cast<const alpha_channel_type*>(src);
0032 
0033         quint16 data[4];
0034         const qint32 pixelSize = dstColorSpace()->pixelSize();
0035 
0036         data[1] = UINT16_MAX / 2;   // a
0037         data[2] = UINT16_MAX / 2;   // b
0038         data[3] = UINT16_MAX;       // A
0039 
0040         while (nPixels > 0) {
0041             data[0] = KoColorSpaceMaths<alpha_channel_type, quint16>::scaleToA(*srcPtr); // L
0042             dstColorSpace()->fromLabA16((quint8*)data, dst, 1);
0043 
0044             srcPtr++;
0045             dst += pixelSize;
0046             nPixels--;
0047         }
0048     }
0049 };
0050 
0051 template <typename alpha_channel_type>
0052 class KoColorConversionAlphaToLab16Transformation : public KoColorConversionTransformation
0053 {
0054 public:
0055     KoColorConversionAlphaToLab16Transformation(const KoColorSpace* srcCs, const KoColorSpace* dstCs,
0056                                              Intent renderingIntent,
0057                                              KoColorConversionTransformation::ConversionFlags conversionFlags)
0058         : KoColorConversionTransformation(srcCs, dstCs, renderingIntent, conversionFlags)
0059     {
0060     }
0061 
0062     void transform(const quint8 *src, quint8 *dst, qint32 nPixels) const override
0063     {
0064         const alpha_channel_type *srcPtr = reinterpret_cast<const alpha_channel_type*>(src);
0065         quint16 *dstPtr = reinterpret_cast<quint16*>(dst);
0066 
0067         while (nPixels > 0) {
0068             dstPtr[0] = KoColorSpaceMaths<alpha_channel_type, quint16>::scaleToA(*srcPtr); // L
0069             dstPtr[1] = UINT16_MAX / 2;   // a
0070             dstPtr[2] = UINT16_MAX / 2;   // b
0071             dstPtr[3] = UINT16_MAX;       // A
0072 
0073             srcPtr++;
0074             dstPtr += 4;
0075             nPixels--;
0076         }
0077     }
0078 };
0079 
0080 
0081 template <typename alpha_channel_type, typename gray_channel_type>
0082 class KoColorConversionGrayAFromAlphaTransformation : public KoColorConversionTransformation
0083 {
0084 public:
0085     KoColorConversionGrayAFromAlphaTransformation(const KoColorSpace* srcCs,
0086                                                   const KoColorSpace* dstCs,
0087                                                   Intent renderingIntent,
0088                                                   KoColorConversionTransformation::ConversionFlags conversionFlags)
0089         : KoColorConversionTransformation(srcCs, dstCs, renderingIntent, conversionFlags)
0090     {
0091     }
0092     void transform(const quint8 *src, quint8 *dst, qint32 nPixels) const override {
0093         const alpha_channel_type *srcPtr = reinterpret_cast<const alpha_channel_type*>(src);
0094         gray_channel_type *dstPtr = reinterpret_cast<gray_channel_type*>(dst);
0095 
0096         while (nPixels > 0) {
0097             dstPtr[0] = KoColorSpaceMaths<alpha_channel_type, gray_channel_type>::scaleToA(*srcPtr);
0098             dstPtr[1] = KoColorSpaceMathsTraits<gray_channel_type>::unitValue;
0099 
0100             srcPtr++;
0101             dstPtr += 2;
0102             nPixels--;
0103         }
0104     }
0105 };
0106 
0107 //------ KoColorConversionFromAlphaTransformationFactoryImpl ------//
0108 
0109 template<typename alpha_channel_type>
0110 KoColorConversionFromAlphaTransformationFactoryImpl<alpha_channel_type>::
0111     KoColorConversionFromAlphaTransformationFactoryImpl(const QString& _dstModelId, const QString& _dstDepthId, const QString& _dstProfileName)
0112         : KoColorConversionTransformationFactory(AlphaColorModelID.id(),
0113                                                  colorDepthIdForChannelType<alpha_channel_type>().id(),
0114                                                  "default",
0115                                                  _dstModelId, _dstDepthId, _dstProfileName)
0116 {
0117 }
0118 
0119 template<typename alpha_channel_type>
0120 KoColorConversionTransformation*
0121 KoColorConversionFromAlphaTransformationFactoryImpl<alpha_channel_type>::
0122     createColorTransformation(const KoColorSpace* srcColorSpace,
0123                               const KoColorSpace* dstColorSpace,
0124                               KoColorConversionTransformation::Intent renderingIntent,
0125                               KoColorConversionTransformation::ConversionFlags conversionFlags) const
0126 {
0127     Q_ASSERT(canBeSource(srcColorSpace));
0128     Q_ASSERT(canBeDestination(dstColorSpace));
0129 
0130     if (dstColorSpace->colorModelId() == GrayAColorModelID &&
0131         dstColorSpace->colorDepthId() == Integer8BitsColorDepthID) {
0132         return new KoColorConversionGrayAFromAlphaTransformation<alpha_channel_type, quint8>(srcColorSpace, dstColorSpace, renderingIntent, conversionFlags);
0133 
0134     } else if (dstColorSpace->colorModelId() == GrayAColorModelID &&
0135                dstColorSpace->colorDepthId() == Integer16BitsColorDepthID) {
0136             return new KoColorConversionGrayAFromAlphaTransformation<alpha_channel_type, quint16>(srcColorSpace, dstColorSpace, renderingIntent, conversionFlags);
0137 
0138     #ifdef HAVE_OPENEXR
0139     } else if (dstColorSpace->colorModelId() == GrayAColorModelID &&
0140                dstColorSpace->colorDepthId() == Float16BitsColorDepthID) {
0141             return new KoColorConversionGrayAFromAlphaTransformation<alpha_channel_type, half>(srcColorSpace, dstColorSpace, renderingIntent, conversionFlags);
0142     #endif
0143 
0144     } else if (dstColorSpace->colorModelId() == GrayAColorModelID &&
0145                dstColorSpace->colorDepthId() == Float32BitsColorDepthID) {
0146             return new KoColorConversionGrayAFromAlphaTransformation<alpha_channel_type, float>(srcColorSpace, dstColorSpace, renderingIntent, conversionFlags);
0147 
0148     } else if (dstColorSpace->colorModelId() == LABAColorModelID &&
0149                dstColorSpace->colorDepthId() == Integer16BitsColorDepthID) {
0150             return new KoColorConversionAlphaToLab16Transformation<alpha_channel_type>(srcColorSpace, dstColorSpace, renderingIntent, conversionFlags);
0151 
0152     } else {
0153         return new KoColorConversionFromAlphaTransformation<alpha_channel_type>(srcColorSpace, dstColorSpace, renderingIntent, conversionFlags);
0154     }
0155 }
0156 
0157 template class KoColorConversionFromAlphaTransformationFactoryImpl<quint8>;
0158 template class KoColorConversionFromAlphaTransformationFactoryImpl<quint16>;
0159 #ifdef HAVE_OPENEXR
0160 template class KoColorConversionFromAlphaTransformationFactoryImpl<half>;
0161 #endif
0162 template class KoColorConversionFromAlphaTransformationFactoryImpl<float>;
0163 
0164 //------ KoColorConversionToAlphaTransformation ------//
0165 
0166 /**
0167  * Converter to the alpha color space to any color space
0168  */
0169 template <typename alpha_channel_type>
0170 class KoColorConversionToAlphaTransformation : public KoColorConversionTransformation
0171 {
0172 public:
0173     KoColorConversionToAlphaTransformation(const KoColorSpace* srcCs, const KoColorSpace* dstCs, Intent renderingIntent, ConversionFlags conversionFlags)
0174         : KoColorConversionTransformation(srcCs, dstCs, renderingIntent, conversionFlags)
0175     {
0176     }
0177 
0178     void transform(const quint8 *src, quint8 *dst, qint32 nPixels) const override {
0179         alpha_channel_type *dstPtr = reinterpret_cast<alpha_channel_type*>(dst);
0180 
0181         quint16 data[4];
0182         qint32 pixelSize = srcColorSpace()->pixelSize();
0183 
0184         while (nPixels > 0) {
0185             srcColorSpace()->toLabA16(src, (quint8*)data, 1);
0186             *dstPtr = KoColorSpaceMaths<quint16, alpha_channel_type>::scaleToA(UINT16_MULT(data[0], data[3])); // L * A
0187 
0188             src += pixelSize;
0189             dstPtr ++;
0190             nPixels --;
0191 
0192         }
0193     }
0194 };
0195 
0196 template <typename alpha_channel_type>
0197 class KoColorConversionLab16ToAlphaTransformation : public KoColorConversionTransformation
0198 {
0199 public:
0200     KoColorConversionLab16ToAlphaTransformation(const KoColorSpace* srcCs, const KoColorSpace* dstCs,
0201                                                 Intent renderingIntent,
0202                                                 KoColorConversionTransformation::ConversionFlags conversionFlags)
0203         : KoColorConversionTransformation(srcCs, dstCs, renderingIntent, conversionFlags)
0204     {
0205     }
0206 
0207     void transform(const quint8 *src, quint8 *dst, qint32 nPixels) const override
0208     {
0209         const quint16 *srcPtr = reinterpret_cast<const quint16*>(src);
0210         alpha_channel_type *dstPtr = reinterpret_cast<alpha_channel_type*>(dst);
0211 
0212         while (nPixels > 0) {
0213             *dstPtr = KoColorSpaceMaths<quint16, alpha_channel_type>::scaleToA(UINT16_MULT(srcPtr[0], srcPtr[3])); // L * A
0214 
0215             srcPtr += 4;
0216             dstPtr++;
0217             nPixels--;
0218         }
0219     }
0220 };
0221 
0222 
0223 //------ KoColorConversionGrayAU8ToAlphaTransformation ------//
0224 
0225 template <typename gray_channel_type, typename alpha_channel_type>
0226 class KoColorConversionGrayAToAlphaTransformation : public KoColorConversionTransformation
0227 {
0228 public:
0229     KoColorConversionGrayAToAlphaTransformation(const KoColorSpace* srcCs,
0230                                                   const KoColorSpace* dstCs,
0231                                                   Intent renderingIntent,
0232                                                   ConversionFlags conversionFlags)
0233         : KoColorConversionTransformation(srcCs, dstCs, renderingIntent, conversionFlags)
0234     {
0235     }
0236 
0237     void transform(const quint8 *src, quint8 *dst, qint32 nPixels) const override
0238     {
0239         const gray_channel_type *srcPtr = reinterpret_cast<const gray_channel_type*>(src);
0240         alpha_channel_type *dstPtr = reinterpret_cast<alpha_channel_type*>(dst);
0241 
0242         while (nPixels > 0) {
0243             *dstPtr = KoColorSpaceMaths<gray_channel_type, alpha_channel_type>::scaleToA(
0244                         KoColorSpaceMaths<gray_channel_type>::multiply(srcPtr[0], srcPtr[1]));
0245 
0246             srcPtr += 2;
0247             dstPtr++;
0248             nPixels --;
0249         }
0250     }
0251 };
0252 
0253 //------ KoColorConversionToAlphaTransformationFactoryImpl ------//
0254 
0255 template <typename alpha_channel_type>
0256 KoColorConversionToAlphaTransformationFactoryImpl<alpha_channel_type>::
0257     KoColorConversionToAlphaTransformationFactoryImpl(const QString& _srcModelId, const QString& _srcDepthId, const QString& _srcProfileName)
0258         : KoColorConversionTransformationFactory(_srcModelId, _srcDepthId, _srcProfileName,
0259                                                  AlphaColorModelID.id(), colorDepthIdForChannelType<alpha_channel_type>().id(), "default")
0260 {
0261 }
0262 
0263 template <typename alpha_channel_type>
0264 KoColorConversionTransformation*
0265 KoColorConversionToAlphaTransformationFactoryImpl<alpha_channel_type>::
0266     createColorTransformation(const KoColorSpace* srcColorSpace,
0267                               const KoColorSpace* dstColorSpace,
0268                               KoColorConversionTransformation::Intent renderingIntent,
0269                               KoColorConversionTransformation::ConversionFlags conversionFlags) const
0270 {
0271     Q_ASSERT(canBeSource(srcColorSpace));
0272     Q_ASSERT(canBeDestination(dstColorSpace));
0273 
0274     if (srcColorSpace->colorModelId() == GrayAColorModelID &&
0275         srcColorSpace->colorDepthId() == Integer8BitsColorDepthID) {
0276         return new KoColorConversionGrayAToAlphaTransformation<quint8, alpha_channel_type>(srcColorSpace, dstColorSpace, renderingIntent, conversionFlags);
0277 
0278     } else if (srcColorSpace->colorModelId() == GrayAColorModelID &&
0279                srcColorSpace->colorDepthId() == Integer16BitsColorDepthID) {
0280             return new KoColorConversionGrayAToAlphaTransformation<quint16, alpha_channel_type>(srcColorSpace, dstColorSpace, renderingIntent, conversionFlags);
0281 
0282 #ifdef HAVE_OPENEXR
0283     } else if (srcColorSpace->colorModelId() == GrayAColorModelID &&
0284                srcColorSpace->colorDepthId() == Float16BitsColorDepthID) {
0285             return new KoColorConversionGrayAToAlphaTransformation<half, alpha_channel_type>(srcColorSpace, dstColorSpace, renderingIntent, conversionFlags);
0286 #endif
0287 
0288     } else if (srcColorSpace->colorModelId() == GrayAColorModelID &&
0289                srcColorSpace->colorDepthId() == Float32BitsColorDepthID) {
0290             return new KoColorConversionGrayAToAlphaTransformation<float, alpha_channel_type>(srcColorSpace, dstColorSpace, renderingIntent, conversionFlags);
0291 
0292     } else if (srcColorSpace->colorModelId() == LABAColorModelID &&
0293                srcColorSpace->colorDepthId() == Integer16BitsColorDepthID) {
0294             return new KoColorConversionLab16ToAlphaTransformation<alpha_channel_type>(srcColorSpace, dstColorSpace, renderingIntent, conversionFlags);
0295 
0296     } else {
0297         return new KoColorConversionToAlphaTransformation<alpha_channel_type>(srcColorSpace, dstColorSpace, renderingIntent, conversionFlags);
0298     }
0299 }
0300 
0301 template class KoColorConversionToAlphaTransformationFactoryImpl<quint8>;
0302 template class KoColorConversionToAlphaTransformationFactoryImpl<quint16>;
0303 #ifdef HAVE_OPENEXR
0304 template class KoColorConversionToAlphaTransformationFactoryImpl<half>;
0305 #endif
0306 template class KoColorConversionToAlphaTransformationFactoryImpl<float>;