File indexing completed on 2024-12-22 04:13:14
0001 /* 0002 * SPDX-FileCopyrightText: 2015 Wolthera van Hövell tot Westerflier <griffinvalley@gmail.com> 0003 * 0004 * Based on the Digikam CIE Tongue widget 0005 * SPDX-FileCopyrightText: 2006-2013 Gilles Caulier <caulier dot gilles at gmail dot com> 0006 * 0007 * Any source code are inspired from lprof project and 0008 * SPDX-FileCopyrightText: 1998-2001 Marti Maria 0009 * 0010 * SPDX-License-Identifier: GPL-2.0-or-later 0011 **/ 0012 #include <QPointF> 0013 #include <QPolygonF> 0014 #include <QPainter> 0015 #include <QPainterPath> 0016 #include <QPaintEvent> 0017 #include <QImage> 0018 #include <QTextStream> 0019 #include <cmath> 0020 #include <klocalizedstring.h> 0021 0022 0023 #include "kis_tone_curve_widget.h" 0024 0025 class Q_DECL_HIDDEN KisToneCurveWidget::Private 0026 { 0027 public: 0028 0029 bool profileDataAvailable {false}; 0030 bool needUpdatePixmap {false}; 0031 bool TRCGray {true}; 0032 bool TRCRGB {false}; 0033 0034 int xBias {0}; 0035 int yBias {0}; 0036 int pxcols {0}; 0037 int pxrows {0}; 0038 0039 QPolygonF ToneCurveGray; 0040 QPolygonF ToneCurveRed; 0041 QPolygonF ToneCurveGreen; 0042 QPolygonF ToneCurveBlue; 0043 0044 double gridside {0.0}; 0045 0046 QPainter painter; 0047 QPainter painter2; 0048 QPixmap pixmap; 0049 QPixmap curvemap; 0050 }; 0051 0052 KisToneCurveWidget::KisToneCurveWidget(QWidget *parent) : 0053 QWidget(parent), d(new Private) 0054 { 0055 /*this is a tone curve widget*/ 0056 } 0057 0058 KisToneCurveWidget::~KisToneCurveWidget() 0059 { 0060 delete d; 0061 } 0062 0063 void KisToneCurveWidget::setGreyscaleCurve(QPolygonF poly) 0064 { 0065 d->ToneCurveGray = poly; 0066 d->TRCGray = true; 0067 d->TRCRGB = false; 0068 d->profileDataAvailable = true; 0069 d->needUpdatePixmap = true; 0070 } 0071 0072 void KisToneCurveWidget::setRGBCurve(QPolygonF red, QPolygonF green, QPolygonF blue) 0073 { 0074 d->ToneCurveRed = red; 0075 d->ToneCurveGreen = green; 0076 d->ToneCurveBlue = blue; 0077 d->profileDataAvailable = true; 0078 d->TRCGray = false; 0079 d->TRCRGB = true; 0080 d->needUpdatePixmap = true; 0081 } 0082 void KisToneCurveWidget::setCMYKCurve(QPolygonF cyan, QPolygonF magenta, QPolygonF yellow, QPolygonF key) 0083 { 0084 d->ToneCurveRed = cyan; 0085 d->ToneCurveGreen = magenta; 0086 d->ToneCurveBlue = yellow; 0087 d->ToneCurveGray = key; 0088 d->profileDataAvailable = true; 0089 d->TRCGray = false; 0090 d->TRCRGB = false; 0091 d->needUpdatePixmap = true; 0092 } 0093 void KisToneCurveWidget::setProfileDataAvailable(bool dataAvailable) 0094 { 0095 d->profileDataAvailable = dataAvailable; 0096 } 0097 int KisToneCurveWidget::grids(double val) const 0098 { 0099 return (int) floor(val * d->gridside + 0.5); 0100 } 0101 0102 void KisToneCurveWidget::mapPoint(QPointF & xy) 0103 { 0104 QPointF dummy = xy; 0105 xy.setX( (int) floor((dummy.x() * (d->pxcols - 1)) + .5) + d->xBias); 0106 xy.setY( (int) floor(((d->pxrows - 1) - dummy.y() * (d->pxrows - 1)) + .5) ); 0107 } 0108 0109 void KisToneCurveWidget::biasedLine(int x1, int y1, int x2, int y2) 0110 { 0111 d->painter.drawLine(x1 + d->xBias, y1, x2 + d->xBias, y2); 0112 } 0113 0114 void KisToneCurveWidget::biasedText(int x, int y, const QString& txt) 0115 { 0116 d->painter.drawText(QPoint(d->xBias + x, y), txt); 0117 } 0118 0119 void KisToneCurveWidget::drawGrid() 0120 { 0121 d->painter.setOpacity(1.0); 0122 d->painter.setPen(qRgb(255, 255, 255)); 0123 biasedLine(0, 0, 0, d->pxrows - 1); 0124 biasedLine(0, d->pxrows-1, d->pxcols-1, d->pxrows - 1); 0125 0126 QFont font; 0127 font.setPointSize(6); 0128 d->painter.setFont(font); 0129 0130 for (int y = 1; y <= 9; y += 1) 0131 { 0132 QString s; 0133 int xstart = (y * (d->pxcols - 1)) / 10; 0134 int ystart = (y * (d->pxrows - 1)) / 10; 0135 0136 QTextStream(&s) << y; 0137 biasedLine(xstart, d->pxrows - grids(1), xstart, d->pxrows - grids(4)); 0138 biasedText(xstart - grids(11), d->pxrows + grids(15), s); 0139 0140 QTextStream(&s) << 10 - y; 0141 biasedLine(0, ystart, grids(3), ystart); 0142 biasedText(grids(-25), ystart + grids(5), s); 0143 } 0144 0145 d->painter.setPen(qRgb(128, 128, 128)); 0146 d->painter.setOpacity(0.5); 0147 0148 for (int y = 1; y <= 9; y += 1) 0149 { 0150 int xstart = (y * (d->pxcols - 1)) / 10; 0151 int ystart = (y * (d->pxrows - 1)) / 10; 0152 0153 biasedLine(xstart, grids(4), xstart, d->pxrows - grids(4) - 1); 0154 biasedLine(grids(7), ystart, d->pxcols-1-grids(7), ystart); 0155 } 0156 d->painter.setOpacity(1.0); 0157 d->painter.setOpacity(1.0); 0158 } 0159 0160 void KisToneCurveWidget::updatePixmap() 0161 { 0162 d->needUpdatePixmap = false; 0163 d->pixmap = QPixmap(size() * devicePixelRatioF()); 0164 d->pixmap.setDevicePixelRatio(devicePixelRatioF()); 0165 d->curvemap = QPixmap(size() * devicePixelRatioF()); 0166 d->curvemap.setDevicePixelRatio(devicePixelRatioF()); 0167 d->pixmap.fill(Qt::black); 0168 d->curvemap.fill(Qt::transparent); 0169 0170 d->painter.begin(&d->pixmap); 0171 0172 int pixcols = 0173 static_cast<int>(d->pixmap.width() / d->pixmap.devicePixelRatioF()); 0174 int pixrows = 0175 static_cast<int>(d->pixmap.height() / d->pixmap.devicePixelRatioF()); 0176 0177 d->gridside = (qMin(pixcols, pixrows)) / 512.0; 0178 d->xBias = grids(32); 0179 d->yBias = grids(20); 0180 d->pxcols = pixcols - d->xBias; 0181 d->pxrows = pixrows - d->yBias; 0182 0183 d->painter.setBackground(QBrush(qRgb(0, 0, 0))); 0184 QPointF start; 0185 drawGrid(); 0186 d->painter.setRenderHint(QPainter::Antialiasing); 0187 if (d->TRCGray && d->ToneCurveGray.size()>0){ 0188 QPainterPath path; 0189 start = d->ToneCurveGray.at(0); 0190 mapPoint(start); 0191 path.moveTo(start); 0192 foreach (QPointF Point, d->ToneCurveGray) { 0193 mapPoint(Point); 0194 path.lineTo(Point); 0195 } 0196 d->painter.setPen(qRgb(255, 255, 255)); 0197 d->painter.drawPath(path); 0198 } else if (d->TRCRGB && d->ToneCurveRed.size()>0 && d->ToneCurveGreen.size()>0 && d->ToneCurveBlue.size()>0){ 0199 d->painter.save(); 0200 d->painter.setCompositionMode(QPainter::CompositionMode_Screen); 0201 QPainterPath path; 0202 start = d->ToneCurveRed.at(0); 0203 mapPoint(start); 0204 path.moveTo(start); 0205 foreach (QPointF Point, d->ToneCurveRed) { 0206 mapPoint(Point); 0207 path.lineTo(Point); 0208 } 0209 d->painter.setPen(qRgb(255, 0, 0)); 0210 d->painter.drawPath(path); 0211 QPainterPath path2; 0212 start = d->ToneCurveGreen.at(0); 0213 mapPoint(start); 0214 path2.moveTo(start); 0215 foreach (QPointF Point, d->ToneCurveGreen) { 0216 mapPoint(Point); 0217 path2.lineTo(Point); 0218 } 0219 d->painter.setPen(qRgb(0, 255, 0)); 0220 d->painter.drawPath(path2); 0221 QPainterPath path3; 0222 start = d->ToneCurveBlue.at(0); 0223 mapPoint(start); 0224 path3.moveTo(start); 0225 foreach (QPointF Point, d->ToneCurveBlue) { 0226 mapPoint(Point); 0227 path3.lineTo(Point); 0228 } 0229 d->painter.setPen(qRgb(0, 0, 255)); 0230 d->painter.drawPath(path3); 0231 d->painter.restore(); 0232 } else { 0233 d->painter2.begin(&d->curvemap); 0234 d->painter2.setRenderHint(QPainter::Antialiasing); 0235 //d->painter2.setCompositionMode(QPainter::CompositionMode_Multiply); 0236 QPainterPath path; 0237 start = d->ToneCurveRed.at(0); 0238 mapPoint(start); 0239 path.moveTo(start); 0240 foreach (QPointF Point, d->ToneCurveRed) { 0241 mapPoint(Point); 0242 path.lineTo(Point); 0243 } 0244 d->painter2.setPen(qRgb(0, 255, 255)); 0245 d->painter2.drawPath(path); 0246 QPainterPath path2; 0247 start = d->ToneCurveGreen.at(0); 0248 mapPoint(start); 0249 path2.moveTo(start); 0250 foreach (QPointF Point, d->ToneCurveGreen) { 0251 mapPoint(Point); 0252 path2.lineTo(Point); 0253 } 0254 d->painter2.setPen(qRgb(255, 0, 255)); 0255 d->painter2.drawPath(path2); 0256 QPainterPath path3; 0257 start = d->ToneCurveBlue.at(0); 0258 mapPoint(start); 0259 path3.moveTo(start); 0260 foreach (QPointF Point, d->ToneCurveBlue) { 0261 mapPoint(Point); 0262 path3.lineTo(Point); 0263 } 0264 d->painter2.setPen(qRgb(255, 255, 0)); 0265 d->painter2.drawPath(path3); 0266 QPainterPath path4; 0267 start = d->ToneCurveGray.at(0); 0268 mapPoint(start); 0269 path4.moveTo(start); 0270 foreach (QPointF Point, d->ToneCurveGray) { 0271 mapPoint(Point); 0272 path4.lineTo(Point); 0273 } 0274 d->painter2.setPen(qRgb(80, 80, 80)); 0275 d->painter2.drawPath(path4); 0276 d->painter2.end(); 0277 d->painter.drawPixmap(d->xBias, 0, d->curvemap); 0278 } 0279 d->painter.end(); 0280 } 0281 0282 void KisToneCurveWidget::paintEvent(QPaintEvent*) 0283 { 0284 QPainter p(this); 0285 0286 // Widget is disable : drawing grayed frame. 0287 0288 if ( !isEnabled() ) 0289 { 0290 p.fillRect(0, 0, width(), height(), 0291 palette().color(QPalette::Disabled, QPalette::Window)); 0292 0293 QPen pen(palette().color(QPalette::Disabled, QPalette::WindowText)); 0294 pen.setStyle(Qt::SolidLine); 0295 pen.setWidth(1); 0296 0297 p.setPen(pen); 0298 p.drawRect(0, 0, width(), height()); 0299 0300 return; 0301 } 0302 0303 0304 // No profile data to show, or RAW file 0305 0306 if (!d->profileDataAvailable) 0307 { 0308 p.fillRect(0, 0, width(), height(), palette().color(QPalette::Active, QPalette::Window)); 0309 QPen pen(palette().color(QPalette::Active, QPalette::Text)); 0310 pen.setStyle(Qt::SolidLine); 0311 pen.setWidth(1); 0312 0313 p.setPen(pen); 0314 p.drawRect(0, 0, width(), height()); 0315 0316 p.setPen(Qt::red); 0317 p.drawText(0, 0, width(), height(), Qt::AlignCenter, 0318 i18n("No tone curve available...")); 0319 0320 return; 0321 } 0322 0323 // Create CIE tongue if needed 0324 if (d->needUpdatePixmap) 0325 { 0326 updatePixmap(); 0327 } 0328 0329 // draw prerendered tongue 0330 p.drawPixmap(0, 0, d->pixmap); 0331 } 0332 0333 void KisToneCurveWidget::resizeEvent(QResizeEvent* event) 0334 { 0335 QWidget::resizeEvent(event); 0336 d->needUpdatePixmap = true; 0337 }