File indexing completed on 2024-05-19 04:25:04
0001 /* 0002 * SPDX-FileCopyrightText: 2016 Dmitry Kazakov <dimula73@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include <kis_global.h> 0008 #include "kis_painting_tweaks.h" 0009 0010 #include <QPen> 0011 #include <QRegion> 0012 #include <QPainter> 0013 #include <QTransform> 0014 0015 #include "kis_debug.h" 0016 0017 0018 namespace KisPaintingTweaks { 0019 0020 QRegion safeClipRegion(const QPainter &painter) 0021 { 0022 const QTransform t = painter.transform(); 0023 0024 QRegion region = t.type() <= QTransform::TxScale ? 0025 painter.clipRegion() : 0026 QRegion(painter.clipBoundingRect().toAlignedRect()); 0027 0028 if (region.rectCount() > 1000) { 0029 qWarning() << "WARNING: KisPaintingTweaks::safeClipRegion: too many rectangles in the region!" << ppVar(region.rectCount()); 0030 region = QRegion(painter.clipBoundingRect().toAlignedRect()); 0031 } 0032 0033 return region; 0034 } 0035 0036 QRect safeClipBoundingRect(const QPainter &painter) 0037 { 0038 return painter.clipBoundingRect().toAlignedRect(); 0039 } 0040 0041 void initAntsPen(QPen *antsPen, QPen *outlinePen, 0042 int antLength, int antSpace) 0043 { 0044 QVector<qreal> antDashPattern; 0045 antDashPattern << antLength << antSpace; 0046 0047 *antsPen = QPen(Qt::CustomDashLine); 0048 antsPen->setDashPattern(antDashPattern); 0049 antsPen->setCosmetic(true); 0050 antsPen->setColor(Qt::black); 0051 0052 *outlinePen = QPen(Qt::SolidLine); 0053 outlinePen->setCosmetic(true); 0054 outlinePen->setColor(Qt::white); 0055 } 0056 0057 PenBrushSaver::PenBrushSaver(QPainter *painter) 0058 : m_painter(painter), 0059 m_pen(painter->pen()), 0060 m_brush(painter->brush()) 0061 { 0062 } 0063 0064 PenBrushSaver::PenBrushSaver(QPainter *painter, const QPen &pen, const QBrush &brush) 0065 : PenBrushSaver(painter) 0066 { 0067 m_painter->setPen(pen); 0068 m_painter->setBrush(brush); 0069 } 0070 0071 PenBrushSaver::PenBrushSaver(QPainter *painter, const QPair<QPen, QBrush> &pair) 0072 : PenBrushSaver(painter) 0073 { 0074 m_painter->setPen(pair.first); 0075 m_painter->setBrush(pair.second); 0076 } 0077 0078 PenBrushSaver::PenBrushSaver(QPainter *painter, const QPair<QPen, QBrush> &pair, allow_noop_t) 0079 : m_painter(painter) 0080 { 0081 if (m_painter) { 0082 m_pen = m_painter->pen(); 0083 m_brush = m_painter->brush(); 0084 m_painter->setPen(pair.first); 0085 m_painter->setBrush(pair.second); 0086 } 0087 } 0088 0089 PenBrushSaver::~PenBrushSaver() 0090 { 0091 if (m_painter) { 0092 m_painter->setPen(m_pen); 0093 m_painter->setBrush(m_brush); 0094 } 0095 } 0096 0097 QColor blendColors(const QColor &c1, const QColor &c2, qreal r1) 0098 { 0099 const qreal r2 = 1.0 - r1; 0100 0101 return QColor::fromRgbF( 0102 c1.redF() * r1 + c2.redF() * r2, 0103 c1.greenF() * r1 + c2.greenF() * r2, 0104 c1.blueF() * r1 + c2.blueF() * r2); 0105 } 0106 0107 qreal colorDifference(const QColor &c1, const QColor &c2) 0108 { 0109 const qreal dr = c1.redF() - c2.redF(); 0110 const qreal dg = c1.greenF() - c2.greenF(); 0111 const qreal db = c1.blueF() - c2.blueF(); 0112 0113 return std::sqrt(2 * pow2(dr) + 4 * pow2(dg) + 3 * pow2(db)); 0114 } 0115 0116 void dragColor(QColor *color, const QColor &baseColor, qreal threshold) 0117 { 0118 while (colorDifference(*color, baseColor) < threshold) { 0119 0120 QColor newColor = *color; 0121 0122 if (newColor.lightnessF() > baseColor.lightnessF()) { 0123 newColor = newColor.lighter(120); 0124 } else { 0125 newColor = newColor.darker(120); 0126 } 0127 0128 if (newColor == *color) { 0129 break; 0130 } 0131 0132 *color = newColor; 0133 } 0134 } 0135 0136 // This does a simplified linearization and calculates the luma. 0137 // Krita has the ability to precisely calculate this value, 0138 // but that seems overkill when all we want to know is whether 0139 // it passes a certain gray threshold. 0140 static QMap<qreal, qreal> sRgbTRCToLinear { 0141 {0.0, 0.0}, 0142 {0.1, 0.01002}, 0143 {0.2, 0.0331}, 0144 {0.3, 0.07324}, 0145 {0.4, 0.13287}, 0146 {0.5, 0.21404}, 0147 {0.6, 0.31855}, 0148 {0.7, 0.44799}, 0149 {0.8, 0.60383}, 0150 {0.9, 0.78741}, 0151 {1.0, 1.0} 0152 }; 0153 0154 static QMap<qreal, qreal> linearToSRGBTRC { 0155 {0.0, 0.0}, 0156 {0.01002, 0.1}, 0157 {0.0331, 0.2}, 0158 {0.07324, 0.3}, 0159 {0.13287, 0.4}, 0160 {0.21404, 0.5}, 0161 {0.31855, 0.6}, 0162 {0.44799, 0.7}, 0163 {0.60383, 0.8}, 0164 {0.78741, 0.9}, 0165 {1.0, 1.0} 0166 }; 0167 0168 qreal luminosityCoarse(const QColor &c, bool sRGBtrc) 0169 { 0170 qreal r = c.redF(); 0171 qreal g = c.greenF(); 0172 qreal b = c.blueF(); 0173 if (sRGBtrc) { 0174 if (r < 1.0) { 0175 r = sRgbTRCToLinear.upperBound(r).value(); 0176 } 0177 if (g < 1.0) { 0178 g = sRgbTRCToLinear.upperBound(g).value(); 0179 } 0180 if (b < 1.0) { 0181 b = sRgbTRCToLinear.upperBound(b).value(); 0182 } 0183 } 0184 qreal lumi = (r * .2126) + (g * .7152) + (b * .0722); 0185 if (sRGBtrc && lumi < 1.0) { 0186 lumi = linearToSRGBTRC.lowerBound(lumi).value(); 0187 } 0188 return lumi; 0189 } 0190 0191 }