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