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 }