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

0001 /*
0002  *  SPDX-FileCopyrightText: 2005 Adrian Page <adrian@pagenet.plus.com>
0003  *
0004  * SPDX-License-Identifier: LGPL-2.1-or-later
0005 */
0006 
0007 #include "KoCompositeOp.h"
0008 
0009 #include <klocalizedstring.h>
0010 #include <KoID.h>
0011 #include <QList>
0012 
0013 #include "KoColorSpace.h"
0014 #include "KoColorSpaceMaths.h"
0015 #include "KoCompositeOpRegistry.h"
0016 
0017 static QString compositeOpDisplayName(const QString &id)
0018 {
0019     return KoCompositeOpRegistry::instance().getCompositeOpDisplayName(id);
0020 }
0021 
0022 static QString categoryDisplayName(const QString &id)
0023 {
0024     return KoCompositeOpRegistry::instance().getCategoryDisplayName(id);
0025 }
0026 
0027 #define LAZY_STATIC_CATEGORY_DISPLAY_NAME(n) \
0028     []() { \
0029         static const QString name = categoryDisplayName(QStringLiteral(n)); \
0030         return name; \
0031     }()
0032 
0033 QString KoCompositeOp::categoryArithmetic() { return LAZY_STATIC_CATEGORY_DISPLAY_NAME("arithmetic"); }
0034 QString KoCompositeOp::categoryBinary()     { return LAZY_STATIC_CATEGORY_DISPLAY_NAME("binary");     }
0035 QString KoCompositeOp::categoryModulo()     { return LAZY_STATIC_CATEGORY_DISPLAY_NAME("modulo");     }
0036 QString KoCompositeOp::categoryNegative()   { return LAZY_STATIC_CATEGORY_DISPLAY_NAME("negative");   }
0037 QString KoCompositeOp::categoryLight()      { return LAZY_STATIC_CATEGORY_DISPLAY_NAME("light");      }
0038 QString KoCompositeOp::categoryDark()       { return LAZY_STATIC_CATEGORY_DISPLAY_NAME("dark");       }
0039 QString KoCompositeOp::categoryHSY()        { return LAZY_STATIC_CATEGORY_DISPLAY_NAME("hsy");        }
0040 QString KoCompositeOp::categoryHSI()        { return LAZY_STATIC_CATEGORY_DISPLAY_NAME("hsi");        }
0041 QString KoCompositeOp::categoryHSL()        { return LAZY_STATIC_CATEGORY_DISPLAY_NAME("hsl");        }
0042 QString KoCompositeOp::categoryHSV()        { return LAZY_STATIC_CATEGORY_DISPLAY_NAME("hsv");        }
0043 QString KoCompositeOp::categoryMix()        { return LAZY_STATIC_CATEGORY_DISPLAY_NAME("mix");        }
0044 QString KoCompositeOp::categoryMisc()       { return LAZY_STATIC_CATEGORY_DISPLAY_NAME("misc");       }
0045 QString KoCompositeOp::categoryQuadratic()  { return LAZY_STATIC_CATEGORY_DISPLAY_NAME("quadratic");  }
0046 
0047 KoCompositeOp::ParameterInfo::ParameterInfo()
0048     : opacity(1.0f)
0049     , flow(1.0f)
0050     , lastOpacity(&opacity)
0051 {
0052 }
0053 
0054 KoCompositeOp::ParameterInfo::ParameterInfo(const ParameterInfo &rhs)
0055 {
0056     copy(rhs);
0057 }
0058 
0059 KoCompositeOp::ParameterInfo& KoCompositeOp::ParameterInfo::operator=(const ParameterInfo &rhs)
0060 {
0061     copy(rhs);
0062     return *this;
0063 }
0064 
0065 void KoCompositeOp::ParameterInfo::setOpacityAndAverage(float _opacity, float _averageOpacity)
0066 {
0067     if (qFuzzyCompare(_opacity, _averageOpacity)) {
0068         opacity = _opacity;
0069         lastOpacity = &opacity;
0070     } else {
0071         opacity = _opacity;
0072         _lastOpacityData = _averageOpacity;
0073         lastOpacity = &_lastOpacityData;
0074     }
0075 }
0076 
0077 void KoCompositeOp::ParameterInfo::copy(const ParameterInfo &rhs)
0078 {
0079     dstRowStart = rhs.dstRowStart;
0080     dstRowStride = rhs.dstRowStride;
0081     srcRowStart = rhs.srcRowStart;
0082     srcRowStride = rhs.srcRowStride;
0083     maskRowStart = rhs.maskRowStart;
0084     maskRowStride = rhs.maskRowStride;
0085     rows = rhs.rows;
0086     cols = rhs.cols;
0087     opacity = rhs.opacity;
0088     flow = rhs.flow;
0089     _lastOpacityData = rhs._lastOpacityData;
0090     channelFlags = rhs.channelFlags;
0091 
0092     lastOpacity = rhs.lastOpacity == &rhs.opacity ?
0093         &opacity : &_lastOpacityData;
0094 }
0095 
0096 void KoCompositeOp::ParameterInfo::updateOpacityAndAverage(float value) {
0097     const float exponent = 0.1;
0098 
0099     opacity = value;
0100 
0101     if (*lastOpacity < opacity) {
0102         lastOpacity = &opacity;
0103     } else {
0104         _lastOpacityData = exponent * opacity + (1.0 - exponent) * (*lastOpacity);
0105         lastOpacity = &_lastOpacityData;
0106     }
0107 }
0108 
0109 struct Q_DECL_HIDDEN KoCompositeOp::Private {
0110     const KoColorSpace * colorSpace;
0111     QString id;
0112     QString description;
0113     QString category;
0114     QBitArray defaultChannelFlags;
0115 };
0116 
0117 KoCompositeOp::KoCompositeOp() : d(new Private)
0118 {
0119 
0120 }
0121 
0122 KoCompositeOp::~KoCompositeOp()
0123 {
0124     delete d;
0125 }
0126 
0127 KoCompositeOp::KoCompositeOp(const KoColorSpace * cs, const QString& id, const QString & category)
0128         : d(new Private)
0129 {
0130     d->colorSpace = cs;
0131     d->id = id;
0132     d->description = compositeOpDisplayName(id);
0133     d->category = category;
0134     if (d->category.isEmpty()) {
0135         d->category = categoryMisc();
0136     }
0137 }
0138 
0139 void KoCompositeOp::composite(quint8 *dstRowStart, qint32 dstRowStride,
0140                               const quint8 *srcRowStart, qint32 srcRowStride,
0141                               const quint8 *maskRowStart, qint32 maskRowStride,
0142                               qint32 rows, qint32 numColumns,
0143                               quint8 opacity, const QBitArray& channelFlags) const
0144 {
0145     KoCompositeOp::ParameterInfo params;
0146     params.dstRowStart   = dstRowStart;
0147     params.dstRowStride  = dstRowStride;
0148     params.srcRowStart   = srcRowStart;
0149     params.srcRowStride  = srcRowStride;
0150     params.maskRowStart  = maskRowStart;
0151     params.maskRowStride = maskRowStride;
0152     params.rows          = rows;
0153     params.cols          = numColumns;
0154     params.opacity       = float(opacity) / 255.0f;
0155     params.flow          = 1.0f;
0156     params.channelFlags  = channelFlags;
0157     composite(params);
0158 }
0159 
0160 void KoCompositeOp::composite(const KoCompositeOp::ParameterInfo& params) const
0161 {
0162     using namespace Arithmetic;
0163 
0164     composite(params.dstRowStart           , params.dstRowStride ,
0165               params.srcRowStart           , params.srcRowStride ,
0166               params.maskRowStart          , params.maskRowStride,
0167               params.rows                  , params.cols         ,
0168               scale<quint8>(params.opacity), params.channelFlags );
0169 }
0170 
0171 
0172 QString KoCompositeOp::category() const
0173 {
0174     return d->category;
0175 }
0176 
0177 QString KoCompositeOp::id() const
0178 {
0179     return d->id;
0180 }
0181 
0182 QString KoCompositeOp::description() const
0183 {
0184     return d->description;
0185 }
0186 
0187 const KoColorSpace * KoCompositeOp::colorSpace() const
0188 {
0189     return d->colorSpace;
0190 }