File indexing completed on 2024-05-19 04:24:17
0001 /* 0002 * SPDX-FileCopyrightText: 2020 Dmitry Kazakov <dimula73@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "KisColorfulBrush.h" 0008 0009 0010 KisColorfulBrush::KisColorfulBrush(const QString &filename) 0011 : KisScalingSizeBrush(filename) 0012 { 0013 } 0014 0015 #include <KoColorSpaceMaths.h> 0016 #include <KoColorSpaceTraits.h> 0017 0018 namespace { 0019 0020 qreal estimateImageAverage(const QImage &image) { 0021 qint64 lightnessSum = 0; 0022 qint64 alphaSum = 0; 0023 0024 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(image.format() == QImage::Format_ARGB32, 0.5); 0025 0026 for (int y = 0; y < image.height(); ++y) { 0027 const QRgb *pixel = reinterpret_cast<const QRgb*>(image.scanLine(y)); 0028 0029 for (int i = 0; i < image.width(); ++i) { 0030 lightnessSum += qRound(qGray(*pixel) * qAlpha(*pixel) / 255.0); 0031 alphaSum += qAlpha(*pixel); 0032 pixel++; 0033 } 0034 } 0035 0036 if (alphaSum == 0) { 0037 return 0; 0038 } 0039 return 255.0 * qreal(lightnessSum) / alphaSum; 0040 } 0041 0042 } 0043 0044 qreal KisColorfulBrush::estimatedSourceMidPoint() const 0045 { 0046 return estimateImageAverage(KisBrush::brushTipImage()); 0047 } 0048 0049 qreal KisColorfulBrush::adjustedMidPoint() const 0050 { 0051 return estimateImageAverage(this->brushTipImage()); 0052 } 0053 0054 bool KisColorfulBrush::autoAdjustMidPoint() const 0055 { 0056 return m_autoAdjustMidPoint; 0057 } 0058 0059 void KisColorfulBrush::setAutoAdjustMidPoint(bool autoAdjustMidPoint) 0060 { 0061 m_autoAdjustMidPoint = autoAdjustMidPoint; 0062 } 0063 0064 QImage KisColorfulBrush::brushTipImage() const 0065 { 0066 QImage image = KisBrush::brushTipImage(); 0067 if (isImageType() && brushApplication() != IMAGESTAMP) { 0068 0069 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(image.format() == QImage::Format_ARGB32, image); 0070 0071 const qreal adjustmentMidPoint = 0072 m_autoAdjustMidPoint ? 0073 estimateImageAverage(image) : 0074 m_adjustmentMidPoint; 0075 0076 if (qAbs(adjustmentMidPoint - 127.0) > 0.1 || 0077 !qFuzzyIsNull(m_brightnessAdjustment) || 0078 !qFuzzyIsNull(m_contrastAdjustment)) { 0079 0080 const int half = KoColorSpaceMathsTraits<quint8>::halfValue; 0081 const int unit = KoColorSpaceMathsTraits<quint8>::unitValue; 0082 0083 const qreal midX = adjustmentMidPoint; 0084 const qreal midY = m_brightnessAdjustment > 0 ? 0085 KoColorSpaceMaths<qreal>::blend(unit, half, m_brightnessAdjustment) : 0086 KoColorSpaceMaths<qreal>::blend(0, half, -m_brightnessAdjustment); 0087 0088 qreal loA = 0.0; 0089 qreal hiA = 0.0; 0090 0091 qreal loB = 0.0; 0092 qreal hiB = 255.0; 0093 0094 if (!qFuzzyCompare(m_contrastAdjustment, 1.0)) { 0095 if (m_contrastAdjustment > 0.0) { 0096 loA = midY / (1.0 - m_contrastAdjustment) / midX; 0097 hiA = (unit - midY) / (1.0 - m_contrastAdjustment) / (unit - midX); 0098 } else { 0099 loA = midY * (1.0 + m_contrastAdjustment) / midX; 0100 hiA = (unit - midY) * (1.0 + m_contrastAdjustment) / (unit - midX); 0101 } 0102 0103 loB = midY - midX * loA; 0104 hiB = midY - midX * hiA; 0105 } 0106 0107 for (int y = 0; y < image.height(); y++) { 0108 QRgb *pixel = reinterpret_cast<QRgb *>(image.scanLine(y)); 0109 for (int x = 0; x < image.width(); x++) { 0110 QRgb c = pixel[x]; 0111 0112 int v = qGray(c); 0113 0114 if (v >= midX) { 0115 v = qMin(unit, qRound(hiA * v + hiB)); 0116 } else { 0117 v = qMax(0, qRound(loA * v + loB)); 0118 } 0119 0120 pixel[x] = qRgba(v, v, v, qAlpha(c)); 0121 } 0122 } 0123 } else { 0124 for (int y = 0; y < image.height(); y++) { 0125 QRgb *pixel = reinterpret_cast<QRgb *>(image.scanLine(y)); 0126 for (int x = 0; x < image.width(); x++) { 0127 QRgb c = pixel[x]; 0128 0129 int v = qGray(c); 0130 pixel[x] = qRgba(v, v, v, qAlpha(c)); 0131 } 0132 } 0133 } 0134 } 0135 return image; 0136 } 0137 0138 void KisColorfulBrush::setAdjustmentMidPoint(quint8 value) 0139 { 0140 if (m_adjustmentMidPoint != value) { 0141 m_adjustmentMidPoint = value; 0142 clearBrushPyramid(); 0143 } 0144 } 0145 0146 void KisColorfulBrush::setBrightnessAdjustment(qreal value) 0147 { 0148 if (m_brightnessAdjustment != value) { 0149 m_brightnessAdjustment = value; 0150 clearBrushPyramid(); 0151 } 0152 } 0153 0154 void KisColorfulBrush::setContrastAdjustment(qreal value) 0155 { 0156 if (m_contrastAdjustment != value) { 0157 m_contrastAdjustment = value; 0158 clearBrushPyramid(); 0159 } 0160 } 0161 0162 bool KisColorfulBrush::isImageType() const 0163 { 0164 return brushType() == IMAGE || brushType() == PIPE_IMAGE; 0165 } 0166 0167 quint8 KisColorfulBrush::adjustmentMidPoint() const 0168 { 0169 return m_adjustmentMidPoint; 0170 } 0171 0172 qreal KisColorfulBrush::brightnessAdjustment() const 0173 { 0174 return m_brightnessAdjustment; 0175 } 0176 0177 qreal KisColorfulBrush::contrastAdjustment() const 0178 { 0179 return m_contrastAdjustment; 0180 } 0181 0182 #include <QDomElement> 0183 0184 void KisColorfulBrush::toXML(QDomDocument& d, QDomElement& e) const 0185 { 0186 // legacy setting, now 'brushApplication' is used instead 0187 e.setAttribute("ColorAsMask", QString::number((int)(brushApplication() != IMAGESTAMP))); 0188 0189 e.setAttribute("AdjustmentMidPoint", QString::number(m_adjustmentMidPoint)); 0190 e.setAttribute("BrightnessAdjustment", QString::number(m_brightnessAdjustment)); 0191 e.setAttribute("ContrastAdjustment", QString::number(m_contrastAdjustment)); 0192 e.setAttribute("AutoAdjustMidPoint", QString::number(m_autoAdjustMidPoint)); 0193 e.setAttribute("AdjustmentVersion", QString::number(2)); 0194 KisBrush::toXML(d, e); 0195 } 0196 0197 void KisColorfulBrush::setHasColorAndTransparency(bool value) 0198 { 0199 m_hasColorAndTransparency = value; 0200 } 0201 0202 bool KisColorfulBrush::hasColorAndTransparency() const 0203 { 0204 return m_hasColorAndTransparency; 0205 }