Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_display_color_converter.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2014 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
8
9#include <QGlobalStatic>
10#include <QPointer>
11#include <QPalette>
12
13#include <KoColor.h>
15#include <KoColorSpaceMaths.h>
18#include <KoColorConversions.h>
19
21#include "kis_config_notifier.h"
23#include "kis_canvas2.h"
24#include "KisViewManager.h"
25#include "kis_image.h"
26#include "kis_node.h"
27#include "KisMainWindow.h"
28#include "KisPart.h"
29
30#include "kundo2command.h"
31#include "kis_config.h"
32#include "kis_paint_device.h"
33#include "kis_iterator_ng.h"
35#include "KisDisplayConfig.h"
36
37#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
38#include <QGuiApplication>
39#endif
40
42
43
45{
47 : q(_q),
48 resourceManager(_resourceManager),
49 nodeColorSpace(0),
50 paintingColorSpace(0),
51 displayFilter(0),
52 displayRenderer(new DisplayRenderer(_q, _resourceManager))
53 {
54 }
55
57
59
62
63 const KoColorProfile* inputImageProfile = 0;
64
65 mutable const KoColorSpace *cachedOcioInputColorSpace = 0;
66 mutable const KoColorSpace *cachedOcioOutputColorSpace = 0;
67 mutable const KoColorSpace *cachedQtWidgetsColorSpace = 0;
68 mutable const KoColorSpace *cachedOpenGLSurfaceColorSpace = 0;
69
70 // this color space will never change during the run of Krita
71 mutable const KoColorSpace *cachedIntermediateColorSpace = 0;
72
74 cachedOcioInputColorSpace = 0;
75 cachedOcioOutputColorSpace = 0;
76 cachedQtWidgetsColorSpace = 0;
77 cachedOpenGLSurfaceColorSpace = 0;
78
80 }
81
83 return multiSurfaceDisplayConfig.uiProfile;
84 }
85
87 return multiSurfaceDisplayConfig.canvasProfile;
88 }
89
91 return displayFilter && displayFilter->useInternalColorManagement() ?
92 openGLSurfaceProfile() : inputImageProfile;
93 }
94
96 return openGLSurfaceProfile();
97 }
98
100 return cachedOcioInputColorSpace
101 ? cachedOcioInputColorSpace
102 : (cachedOcioInputColorSpace =
104 colorSpace(
107 ocioInputProfile()));
108 }
109
111 return cachedOcioOutputColorSpace
112 ? cachedOcioOutputColorSpace
113 : (cachedOcioOutputColorSpace =
115 colorSpace(
118 ocioOutputProfile()));
119
120 }
121
123 return cachedQtWidgetsColorSpace
124 ? cachedQtWidgetsColorSpace
125 : (cachedQtWidgetsColorSpace =
127 colorSpace(
130 qtWidgetsProfile()));
131
132 }
133
134 const KoColorSpace* openGLSurfaceColorSpace(const KoID &bitDepthId) const {
135 return cachedOpenGLSurfaceColorSpace
136 ? cachedOpenGLSurfaceColorSpace
137 : (cachedOpenGLSurfaceColorSpace =
139 colorSpace(
141 bitDepthId.id(),
142 openGLSurfaceProfile()));
143 }
144
146 // the color space where we apply exposure and
147 // gamma should always be linear
148 return cachedIntermediateColorSpace
149 ? cachedIntermediateColorSpace
150 : (cachedIntermediateColorSpace =
152 colorSpace(
156 }
157
159
161
165
168
169 inline KoColor approximateFromQColor(const QColor &qcolor);
170 inline QColor approximateToQColor(const KoColor &color);
171
172 void slotCanvasResourceChanged(int key, const QVariant &v);
173 void slotUpdateCurrentNodeColorSpace();
174 void selectPaintingColorSpace();
175
176 void updateIntermediateFgColor(const KoColor &color);
177 void setCurrentNode(KisNodeSP node);
178 bool useOcio() const;
179 bool needsColorProofing(const KoColorSpace *srcColorSpace) const;
180
182 public:
183 DisplayRenderer(KisDisplayColorConverter *displayColorConverter, KoCanvasResourceProvider *resourceManager)
184 : m_displayColorConverter(displayColorConverter),
185 m_resourceManager(resourceManager)
186 {
187 displayColorConverter->connect(displayColorConverter, SIGNAL(displayConfigurationChanged()),
188 this, SIGNAL(displayConfigurationChanged()), Qt::UniqueConnection);
189 }
190
191 QImage toQImage(const KoColorSpace *srcColorSpace, const quint8 *data, QSize size, bool proofPaintColors = false) const override {
192 QImage result = m_displayColorConverter->toQImage(srcColorSpace, data, size, proofPaintColors);
193 return result;
194 }
195
196 QColor toQColor(const KoColor &c, bool proofToPaintColors = false) const override {
197 return m_displayColorConverter->toQColor(c, proofToPaintColors);
198 }
199
200 KoColor approximateFromRenderedQColor(const QColor &c) const override {
201 return m_displayColorConverter->approximateFromRenderedQColor(c);
202 }
203
204 KoColor fromHsv(int h, int s, int v, int a) const override {
205 return m_displayColorConverter->fromHsv(h, s, v, a);
206 }
207
208 void getHsv(const KoColor &srcColor, int *h, int *s, int *v, int *a) const override {
209 m_displayColorConverter->getHsv(srcColor, h, s, v, a);
210 }
211
212 qreal minVisibleFloatValue(const KoChannelInfo *chaninfo) const override {
213 return chaninfo->getUIMin();
214 }
215
216 qreal maxVisibleFloatValue(const KoChannelInfo *chaninfo) const override {
217 qreal maxValue = chaninfo->getUIMax();
218
219 if (m_resourceManager) {
220 qreal exposure = m_resourceManager->resource(KoCanvasResource::HdrExposure).value<qreal>();
221 // not sure if *= is what we want
222 maxValue *= std::pow(2.0, -exposure);
223 }
224
225 return maxValue;
226 }
227
228 const KoColorSpace* getPaintingColorSpace() const override {
229 return m_displayColorConverter->paintingColorSpace();
230 }
231
232 QColor convertColorToDisplayColorSpace(KoColor c) const override {
233 return m_displayColorConverter->convertColorToDisplayColorSpace(c);
234 }
235
236 QImage convertImageToDisplayColorSpace(const QImage source) const override {
237 // Limited to 8bit sRGB for now...
239 srcDevice->convertFromQImage(source, KoColorSpaceRegistry::instance()->p709SRGBProfile(), 0, 0);
240 QImage destination = m_displayColorConverter->convertImageToDisplayColorSpace(srcDevice);
241 destination.setDevicePixelRatio(source.devicePixelRatio());
242 return destination;
243 }
244
246 return m_displayColorConverter->handlePaletteForDisplayColorSpace();
247 }
248
249 QPalette systemPaletteForDisplayColorSpace() const override {
250 return m_displayColorConverter->systemPaletteForDisplayColorSpace();
251 }
252
253 private:
256 };
257
258 QScopedPointer<KoColorDisplayRendererInterface> displayRenderer;
259};
260
261KisDisplayColorConverter::KisDisplayColorConverter(KoCanvasResourceProvider *resourceManager, QObject *parent, bool reactOnThemeChange)
262 : QObject(parent),
263 m_d(new Private(this, resourceManager))
264{
265 connect(m_d->resourceManager, SIGNAL(canvasResourceChanged(int,QVariant)),
266 SLOT(slotCanvasResourceChanged(int,QVariant)));
267 connect(KisConfigNotifier::instance(), SIGNAL(configChanged()),
268 SLOT(selectPaintingColorSpace()));
269
270 m_d->inputImageProfile = KoColorSpaceRegistry::instance()->p709SRGBProfile();
271 m_d->paintingColorSpace = KoColorSpaceRegistry::instance()->rgb8();
272 m_d->setCurrentNode(0);
275 connect(this, SIGNAL(displayConfigurationChanged()), this, SLOT(updatePalettes()));
276
277 if(reactOnThemeChange)
278 connect(KisPart::instance()->currentMainwindow(), SIGNAL(themeChanged()), this, SLOT(updatePalettes()));
279}
280
282 : m_d(new Private(this, 0))
283{
285
286 m_d->inputImageProfile = KoColorSpaceRegistry::instance()->p709SRGBProfile();
287 m_d->paintingColorSpace = KoColorSpaceRegistry::instance()->rgb8();
288
289 m_d->setCurrentNode(0);
290}
291
295
297{
298 m_d->inputImageProfile =
300 cs->profile() :
302
303 m_d->notifyDisplayConfigurationChanged();
304}
305
306
311
316
321
323{
324 if (!paintingColorSpace || srcColorSpace == paintingColorSpace || *srcColorSpace == *paintingColorSpace) {
325 return false;
326 }
327 // TODO: ideally, we'd identify color profiles that only differ in transfer curves but
328 // define the same primaries/gamut and return false for them aswell
329 if (srcColorSpace->colorModelId() == paintingColorSpace->colorModelId()) {
330 const KoColorProfile *paintProfile = paintingColorSpace->profile();
331 const KoColorProfile *srcProfile = srcColorSpace->profile();
332 bool matchingProfiles = (paintProfile == srcProfile) ||
333 (paintProfile && srcProfile && *paintProfile == *srcProfile);
334 // unless we go float->int, the color spaces are considered compatible
335 if (matchingProfiles &&
336 (srcColorSpace->colorDepthId() == Integer8BitsColorDepthID ||
337 srcColorSpace->colorDepthId() == Integer16BitsColorDepthID ||
340 return false;
341 }
342 }
343 return true;
344}
345
347{
349
350 KoColor color = srcColor;
351 color.convertTo(intermediateColorSpace());
352 displayFilter->approximateForwardTransformation(color.data(), 1);
353 intermediateFgColor = color;
354}
355
357{
359 KisNodeSP currentNode = v.value<KisNodeWSP>();
360 setCurrentNode(currentNode);
361 } else if (useOcio() && key == KoCanvasResource::ForegroundColor) {
362 updateIntermediateFgColor(v.value<KoColor>());
363 }
364}
365
367{
368 setCurrentNode(connectedNode);
369}
370
372{
373 KisHandlePalette palette;
374 KoColor c;
375 c.fromQColor(palette.gradientFillColor);
377
378 c.fromQColor(palette.highlightColor);
380
383
384 c.fromQColor(palette.primaryColor);
386
387 c.fromQColor(palette.secondaryColor);
389
390 c.fromQColor(palette.selectionColor);
392
393 c.fromQColor(palette.white);
395
396 c.fromQColor(palette.black);
398
399 QPalette pal = qApp->palette();
400 for (int r = 0; r < QPalette::NColorRoles; r++) {
401 for (int cg = 0; cg < QPalette::NColorGroups; cg++) {
402 c.fromQColor(pal.brush(QPalette::ColorGroup(cg), QPalette::ColorRole(r)).color());
403 pal.setBrush(QPalette::ColorGroup(cg), QPalette::ColorRole(r), convertColorToDisplayColorSpace(c));
404 }
405 }
406
407 m_d->handlePalette = palette;
408 m_d->systemPalette = pal;
409}
410
412 return node->paintDevice() ? node->paintDevice() : node->original();
413}
414
416{
417 if (connectedNode) {
418 KisPaintDeviceSP device = findValidDevice(connectedNode);
419
420 if (device) {
421 q->disconnect(device, 0);
422 }
423 }
424
425 nodeColorSpace = 0;
426
427 if (node) {
428 KisPaintDeviceSP device = findValidDevice(node);
429
430 nodeColorSpace = device ?
432 node->colorSpace();
433
435
436 if (device) {
437 q->connect(device, SIGNAL(profileChanged(const KoColorProfile*)),
438 SLOT(slotUpdateCurrentNodeColorSpace()), Qt::UniqueConnection);
439 q->connect(device, SIGNAL(colorSpaceChanged(const KoColorSpace*)),
440 SLOT(slotUpdateCurrentNodeColorSpace()), Qt::UniqueConnection);
441 }
442
443 }
444
445 if (!nodeColorSpace) {
447 }
448
449 connectedNode = node;
450 selectPaintingColorSpace();
451}
452
454{
455 KisConfig cfg(true);
457
460 }
461
462 notifyDisplayConfigurationChanged();
463}
464
466{
467 KIS_SAFE_ASSERT_RECOVER(m_d->paintingColorSpace) {
469 }
470
471 return m_d->paintingColorSpace;
472}
473
475{
476 return m_d->nodeColorSpace;
477}
478
480{
481 if (m_d->multiSurfaceDisplayConfig == config) return;
482
483
484
485 m_d->multiSurfaceDisplayConfig = config;
486 m_d->notifyDisplayConfigurationChanged();
487}
488
490{
491 if (m_d->displayFilter && displayFilter &&
492 displayFilter->lockCurrentColorVisualRepresentation()) {
493
494 KoColor color(m_d->intermediateFgColor);
495 displayFilter->approximateInverseTransformation(color.data(), 1);
496 color.convertTo(m_d->paintingColorSpace);
497 m_d->resourceManager->setForegroundColor(color);
498 }
499
500 m_d->displayFilter = displayFilter;
501
502 if (m_d->displayFilter) {
503 m_d->updateIntermediateFgColor(
504 m_d->resourceManager->foregroundColor());
505 }
506
507
508 { // sanity check
509 // KisConfig cfg;
510 // KIS_ASSERT_RECOVER_NOOP(cfg.useOcio() == (bool) m_d->displayFilter);
511 }
512
513 m_d->selectPaintingColorSpace();
514}
515
517{
518 return m_d->multiSurfaceDisplayConfig.uiDisplayConfig();
519}
520
525
527{
528 return m_d->multiSurfaceDisplayConfig;
529}
530
532{
533 return m_d->multiSurfaceDisplayConfig.options();
534}
535
536QColor KisDisplayColorConverter::toQColor(const KoColor &srcColor, bool proofToPaintColors) const
537{
538 KoColor c(srcColor);
539
540 if (proofToPaintColors && m_d->needsColorProofing(c.colorSpace())) {
541 c.convertTo(m_d->paintingColorSpace, m_d->multiSurfaceDisplayConfig.intent, m_d->multiSurfaceDisplayConfig.conversionFlags);
542 }
543
544 if (m_d->useOcio()) {
545 KIS_ASSERT_RECOVER(m_d->ocioInputColorSpace()->pixelSize() == 16) {
546 return QColor(Qt::green);
547 }
548
549 c.convertTo(m_d->ocioInputColorSpace());
550 m_d->displayFilter->filter(c.data(), 1);
551 c.setProfile(m_d->ocioOutputProfile());
552 }
553
554 // we expect the display profile is rgb8, which is BGRA here
555 KIS_ASSERT_RECOVER(m_d->qtWidgetsColorSpace()->pixelSize() == 4) {
556 return QColor(Qt::red);
557 }
558
559 c.convertTo(m_d->qtWidgetsColorSpace(), m_d->multiSurfaceDisplayConfig.intent, m_d->multiSurfaceDisplayConfig.conversionFlags);
560 const quint8 *p = c.data();
561 return QColor(p[2], p[1], p[0], p[3]);
562}
563
565 const KoID &bitDepthId) const
566{
567 KoColor c(srcColor);
568
569 if (m_d->useOcio()) {
570 KIS_ASSERT_RECOVER(m_d->ocioInputColorSpace()->pixelSize() == 16) {
571 return srcColor;
572 }
573
574 c.convertTo(m_d->ocioInputColorSpace());
575 m_d->displayFilter->filter(c.data(), 1);
576 c.setProfile(m_d->ocioOutputProfile());
577 }
578
579 c.convertTo(m_d->openGLSurfaceColorSpace(bitDepthId), m_d->multiSurfaceDisplayConfig.intent, m_d->multiSurfaceDisplayConfig.conversionFlags);
580 return c;
581}
582
584{
585 const KoColorProfile *displayProfile = m_d->openGLSurfaceProfile();
586
587 return !m_d->useOcio() &&
589 (!!cs->profile() == !!displayProfile) &&
590 (!cs->profile() ||
591 cs->profile()->uniqueId() == displayProfile->uniqueId());
592}
593
594
596{
597 return m_d->approximateFromQColor(c);
598}
599
600QImage KisDisplayColorConverter::toQImage(KisPaintDeviceSP srcDevice, bool proofPaintColors) const
601{
602 KisPaintDeviceSP device = srcDevice;
603
604 QRect bounds = srcDevice->exactBounds();
605 if (bounds.isEmpty()) return QImage();
606
607 if (proofPaintColors && m_d->needsColorProofing(srcDevice->colorSpace())) {
608 srcDevice->convertTo(paintingColorSpace(), m_d->multiSurfaceDisplayConfig.intent, m_d->multiSurfaceDisplayConfig.conversionFlags);
609 }
610
611 if (m_d->useOcio()) {
612 KIS_ASSERT_RECOVER(m_d->ocioInputColorSpace()->pixelSize() == 16) {
613 return QImage();
614 }
615
616 device = new KisPaintDevice(*srcDevice);
617 device->convertTo(m_d->ocioInputColorSpace());
618
619 KisSequentialIterator it(device, bounds);
620 int numConseqPixels = it.nConseqPixels();
621 while (it.nextPixels(numConseqPixels)) {
622 numConseqPixels = it.nConseqPixels();
623 m_d->displayFilter->filter(it.rawData(), numConseqPixels);
624 }
625
626 device->setProfile(m_d->ocioOutputProfile(), 0);
627 }
628
629 // we expect the display profile is rgb8, which is BGRA here
630 KIS_ASSERT_RECOVER(m_d->qtWidgetsColorSpace()->pixelSize() == 4) {
631 return QImage();
632 }
633
634 return device->convertToQImage(m_d->qtWidgetsProfile(),
635 bounds,
636 m_d->multiSurfaceDisplayConfig.intent,
637 m_d->multiSurfaceDisplayConfig.conversionFlags);
638}
639
640QImage KisDisplayColorConverter::toQImage(const KoColorSpace *srcColorSpace, const quint8 *data, QSize size, bool proofPaintColors) const
641{
642 const int numPixels = size.width() * size.height();
643
644 const KoColorSpace *colorSpace = srcColorSpace;
645 const quint8 *pixels = data;
646
647 QScopedArrayPointer<quint8> proofBuffer;
648
649 if (proofPaintColors && m_d->needsColorProofing(srcColorSpace)) {
650 const int imageSize = numPixels * paintingColorSpace()->pixelSize();
651 proofBuffer.reset(new quint8[imageSize]);
652 colorSpace->convertPixelsTo(pixels, proofBuffer.data(),
654 numPixels,
655 m_d->multiSurfaceDisplayConfig.intent,
656 m_d->multiSurfaceDisplayConfig.conversionFlags);
657 colorSpace = paintingColorSpace();
658 pixels = proofBuffer.data();
659 }
660
661 QScopedArrayPointer<quint8> ocioBuffer;
662 if (m_d->useOcio()) {
663 const int imageSize = numPixels * m_d->ocioInputColorSpace()->pixelSize();
664 ocioBuffer.reset(new quint8[imageSize]);
665 colorSpace->convertPixelsTo(pixels, ocioBuffer.data(),
666 m_d->ocioInputColorSpace(),
667 numPixels,
668 m_d->multiSurfaceDisplayConfig.intent,
669 m_d->multiSurfaceDisplayConfig.conversionFlags);
670 m_d->displayFilter->filter(ocioBuffer.data(), numPixels);
671
672 return m_d->ocioOutputColorSpace()->convertToQImage(ocioBuffer.data(), size.width(), size.height(),
673 m_d->qtWidgetsProfile(),
674 m_d->multiSurfaceDisplayConfig.intent,
675 m_d->multiSurfaceDisplayConfig.conversionFlags);
676 }
677
678 return colorSpace->convertToQImage(pixels, size.width(), size.height(),
679 m_d->qtWidgetsProfile(),
680 m_d->multiSurfaceDisplayConfig.intent,
681 m_d->multiSurfaceDisplayConfig.conversionFlags);
682}
683
685 const KoColorSpace *dstColorSpace) const
686{
694 KIS_SAFE_ASSERT_RECOVER_RETURN(device->bounds().isValid());
695
696 if (m_d->useOcio()) {
697 KIS_ASSERT_RECOVER_RETURN(m_d->ocioInputColorSpace()->pixelSize() == 16);
698
699 device->convertTo(m_d->ocioInputColorSpace());
700 m_d->displayFilter->filter(device->data(), device->bounds().width() * device->bounds().height());
701 device->setProfile(m_d->ocioOutputProfile());
702 }
703
704 KIS_SAFE_ASSERT_RECOVER_RETURN(dstColorSpace);
705 device->convertTo(dstColorSpace);
706}
707
709{
710 KoColor newColor;
711 if (applyOcio) {
713 } else {
714 newColor = KoColor(color);
715 newColor.convertTo(m_d->openGLSurfaceColorSpace(Float32BitsColorDepthID), m_d->multiSurfaceDisplayConfig.intent, m_d->multiSurfaceDisplayConfig.conversionFlags);
716 }
717
720
721 QVector<float> norm(newColor.colorSpace()->channelCount());
722 newColor.colorSpace()->normalisedChannelsValue(newColor.data(), norm);
723
724 // sort into RGBA order... maybe a little overengineered.
725 QVector<float> sorted = norm;
726 for (int ch = 0; ch < norm.size(); ch++) {
727 const KoChannelInfo *info = newColor.colorSpace()->channels().at(ch);
728 sorted[info->displayPosition()] = norm[ch];
729 }
730
731 // We need to manually create a QColor here, because if we use KoColor.toQColor, the whole KoColor is first
732 // converted to sRGB before becoming a QColor, while we explicitely do not want that for our QColor.
733 // This is further complicated by the fact that QColors cannot have any (Q)ColorSpace metadata associated with it, unlike KoColor.
734 return QColor::fromRgbF(sorted[0], sorted[1], sorted[2], sorted[3]);
735}
736
738{
739 KisPaintDeviceSP conversionDevice = new KisPaintDevice(*srcDevice.data());
740 const QRect s = source.isValid()? source: conversionDevice->exactBounds();
741
742 if (m_d->useOcio() && applyOcio) {
743 KIS_ASSERT_RECOVER(m_d->ocioInputColorSpace()->pixelSize() == 16) {
744 return QImage();
745 }
746
747 conversionDevice->convertTo(m_d->ocioInputColorSpace());
748 KisSequentialIterator it(conversionDevice, s);
749 int numConseqPixels = it.nConseqPixels();
750 while (it.nextPixels(numConseqPixels)) {
751 numConseqPixels = it.nConseqPixels();
752 m_d->displayFilter->filter(it.rawData(), numConseqPixels);
753 }
754 conversionDevice->setProfile(m_d->ocioOutputProfile(), 0);
755 }
756
757 conversionDevice->convertTo(m_d->openGLSurfaceColorSpace(Float32BitsColorDepthID), m_d->multiSurfaceDisplayConfig.intent, m_d->multiSurfaceDisplayConfig.conversionFlags);
758 return conversionDevice->convertToQImage(m_d->openGLSurfaceProfile(), s, m_d->multiSurfaceDisplayConfig.intent, m_d->multiSurfaceDisplayConfig.conversionFlags);
759}
760
765
767{
768 return m_d->systemPalette;
769}
770
772{
773 if (!useOcio()) {
774 return KoColor(qcolor, paintingColorSpace);
775 } else {
776 KoColor color(qcolor, intermediateColorSpace());
777 displayFilter->approximateInverseTransformation(color.data(), 1);
779 return color;
780 }
781
782 qFatal("Must not be reachable");
783 return KoColor();
784}
785
787{
788 KoColor color(srcColor);
789
790 if (useOcio()) {
791 color.convertTo(intermediateColorSpace());
792 displayFilter->approximateForwardTransformation(color.data(), 1);
793 }
794
795 return color.toQColor();
796}
797
798
799KoColor KisDisplayColorConverter::fromHsv(int h, int s, int v, int a) const
800{
801 // generate HSV from sRGB!
802 QColor qcolor(QColor::fromHsv(h, s, v, a));
803 return m_d->approximateFromQColor(qcolor);
804}
805
806void KisDisplayColorConverter::getHsv(const KoColor &srcColor, int *h, int *s, int *v, int *a) const
807{
808 // we are going through sRGB here!
809 QColor color = m_d->approximateToQColor(srcColor);
810 color.getHsv(h, s, v, a);
811}
812
813KoColor KisDisplayColorConverter::fromHsvF(qreal h, qreal s, qreal v, qreal a)
814{
815 // generate HSV from sRGB!
816 QColor qcolor(QColor::fromHsvF(h, s, v, a));
817 return m_d->approximateFromQColor(qcolor);
818}
819
820void KisDisplayColorConverter::getHsvF(const KoColor &srcColor, qreal *h, qreal *s, qreal *v, qreal *a)
821{
822 // we are going through sRGB here!
823 QColor color = m_d->approximateToQColor(srcColor);
824#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
825 color.getHsvF(h, s, v, a);
826#else
827 float fH, fS, fV, fA;
828 fH = *h;
829 fS = *s;
830 fV = *v;
831 if (a) {
832 fA = *a;
833 }
834 color.getHsvF(&fH, &fS, &fV, &fA);
835 *h = fH;
836 *s = fS;
837 *v = fV;
838 if (a) {
839 *a = fA;
840 }
841#endif
842}
843
844KoColor KisDisplayColorConverter::fromHslF(qreal h, qreal s, qreal l, qreal a)
845{
846 // generate HSL from sRGB!
847 QColor qcolor(QColor::fromHslF(h, s, l, a));
848 if (!qcolor.isValid()) {
849 warnKrita << "Could not construct valid color from h" << h << "s" << s << "l" << l << "a" << a;
850 qcolor = Qt::black;
851 }
852 return m_d->approximateFromQColor(qcolor);
853
854}
855
856void KisDisplayColorConverter::getHslF(const KoColor &srcColor, qreal *h, qreal *s, qreal *l, qreal *a)
857{
858 // we are going through sRGB here!
859 QColor color = m_d->approximateToQColor(srcColor);
860#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
861 color.getHslF(h, s, l, a);
862#else
863 float fH, fS, fL, fA;
864 fH = *h;
865 fS = *s;
866 fL = *l;
867 if (a) {
868 fA = *a;
869 }
870 color.getHslF(&fH, &fS, &fL, &fA);
871 *h = fH;
872 *s = fS;
873 *l = fL;
874 if (a) {
875 *a = fA;
876 }
877#endif
878}
879
881{
882 // generate HSI from sRGB!
883 qreal r=0.0;
884 qreal g=0.0;
885 qreal b=0.0;
886 qreal a=1.0;
887 HSIToRGB(h, s, i, &r, &g, &b);
888 QColor qcolor;
889 qcolor.setRgbF(qBound(0.0,r,1.0), qBound(0.0,g,1.0), qBound(0.0,b,1.0), a);
890 return m_d->approximateFromQColor(qcolor);
891}
892
893void KisDisplayColorConverter::getHsiF(const KoColor &srcColor, qreal *h, qreal *s, qreal *i)
894{
895 // we are going through sRGB here!
896 QColor color = m_d->approximateToQColor(srcColor);
897 qreal r=color.redF();
898 qreal g=color.greenF();
899 qreal b=color.blueF();
900 RGBToHSI(r, g, b, h, s, i);
901}
902
903KoColor KisDisplayColorConverter::fromHsyF(qreal h, qreal s, qreal y, qreal R, qreal G, qreal B, qreal gamma)
904{
905 // generate HSL from sRGB!
906 QVector <qreal> channelValues(3);
907 y = pow(y, gamma);
908 HSYToRGB(h, s, y, &channelValues[0], &channelValues[1], &channelValues[2], R, G, B);
910 QColor qcolor;
911 qcolor.setRgbF(qBound(0.0,channelValues[0],1.0), qBound(0.0,channelValues[1],1.0), qBound(0.0,channelValues[2],1.0), 1.0);
912 return m_d->approximateFromQColor(qcolor);
913}
914
915void KisDisplayColorConverter::getHsyF(const KoColor &srcColor, qreal *h, qreal *s, qreal *y, qreal R, qreal G, qreal B, qreal gamma)
916{
917 // we are going through sRGB here!
918 QColor color = m_d->approximateToQColor(srcColor);
919 QVector <qreal> channelValues(3);
920 channelValues[0]=color.redF();
921 channelValues[1]=color.greenF();
922 channelValues[2]=color.blueF();
923 //TODO: if we're going to have KoColor here, remember to check whether the TRC of the profile exists...
925 RGBToHSY(channelValues[0], channelValues[1], channelValues[2], h, s, y, R, G, B);
926 *y = pow(*y, 1/gamma);
927}
928
929#include "moc_kis_display_color_converter.cpp"
const Params2D p
Eigen::Matrix< double, 4, 2 > R
qreal v
KisMagneticGraph::vertex_descriptor source(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g)
Q_GLOBAL_STATIC(KisStoragePluginRegistry, s_instance)
void HSYToRGB(const qreal h, const qreal s, const qreal y, qreal *red, qreal *green, qreal *blue, qreal R, qreal G, qreal B)
void RGBToHSI(qreal r, qreal g, qreal b, qreal *h, qreal *s, qreal *i)
void HSIToRGB(const qreal h, const qreal s, const qreal i, qreal *red, qreal *green, qreal *blue)
void RGBToHSY(const qreal r, const qreal g, const qreal b, qreal *h, qreal *s, qreal *y, qreal R, qreal G, qreal B)
const KoID Float32BitsColorDepthID("F32", ki18n("32-bit float/channel"))
const KoID Float16BitsColorDepthID("F16", ki18n("16-bit float/channel"))
const KoID Integer8BitsColorDepthID("U8", ki18n("8-bit integer/channel"))
const KoID Integer16BitsColorDepthID("U16", ki18n("16-bit integer/channel"))
const KoID RGBAColorModelID("RGBA", ki18n("RGB/Alpha"))
static KisConfigNotifier * instance()
const KoColorSpace * customColorSelectorColorSpace(bool defaultValue=false) const
qreal minVisibleFloatValue(const KoChannelInfo *chaninfo) const override
DisplayRenderer(KisDisplayColorConverter *displayColorConverter, KoCanvasResourceProvider *resourceManager)
QColor toQColor(const KoColor &c, bool proofToPaintColors=false) const override
KoColor approximateFromRenderedQColor(const QColor &c) const override
KoColor fromHsv(int h, int s, int v, int a) const override
const KoColorSpace * getPaintingColorSpace() const override
getColorSpace
QImage toQImage(const KoColorSpace *srcColorSpace, const quint8 *data, QSize size, bool proofPaintColors=false) const override
Convert a consecutive block of pixel data to an ARGB32 QImage.
KisHandlePalette handlePaletteForDisplayColorSpace() const override
handlePaletteForDisplayColorSpace
QImage convertImageToDisplayColorSpace(const QImage source) const override
convertImageToDisplayColorSpace
QPalette systemPaletteForDisplayColorSpace() const override
systemPaletteForDisplayColorSpace
QColor convertColorToDisplayColorSpace(KoColor c) const override
convertColorToDisplayColorSpace
void getHsv(const KoColor &srcColor, int *h, int *s, int *v, int *a) const override
qreal maxVisibleFloatValue(const KoChannelInfo *chaninfo) const override
void getHslF(const KoColor &srcColor, qreal *h, qreal *s, qreal *l, qreal *a=0)
KisHandlePalette handlePaletteForDisplayColorSpace() const
handlePaletteForDisplayColorSpace
std::pair< KoColorConversionTransformation::Intent, KoColorConversionTransformation::ConversionFlags > ConversionOptions
KisMultiSurfaceDisplayConfig multiSurfaceDisplayConfig() const
KoColor fromHsiF(qreal h, qreal s, qreal i)
KoColorDisplayRendererInterface * displayRendererInterface() const
QColor convertColorToDisplayColorSpace(const KoColor color, bool applyOcio=false) const
convertColorToDisplayColorSpace This applies displayfiltering to the given KoColor,...
const KoColorSpace * paintingColorSpace() const
QSharedPointer< KisDisplayFilter > displayFilter() const
void getHsiF(const KoColor &srcColor, qreal *h, qreal *s, qreal *i)
const QScopedPointer< Private > m_d
QImage toQImage(KisPaintDeviceSP srcDevice, bool proofPaintColors=false) const
KoColor applyDisplayFiltering(const KoColor &srcColor, const KoID &bitDepthId) const
QPalette systemPaletteForDisplayColorSpace() const
systemPaletteForDisplayColorSpace
void getHsyF(const KoColor &srcColor, qreal *h, qreal *s, qreal *y, qreal R=0.2126, qreal G=0.7152, qreal B=0.0722, qreal gamma=2.2)
KoColor fromHslF(qreal h, qreal s, qreal l, qreal a=1.0)
void getHsvF(const KoColor &srcColor, qreal *h, qreal *s, qreal *v, qreal *a=0)
static KisDisplayColorConverter * dumbConverterInstance()
void setImageColorSpace(const KoColorSpace *cs)
void getHsv(const KoColor &srcColor, int *h, int *s, int *v, int *a=0) const
bool canSkipDisplayConversion(const KoColorSpace *cs) const
void applyDisplayFilteringF32(KisFixedPaintDeviceSP device, const KoColorSpace *dstColorSpace) const
void setMultiSurfaceDisplayConfig(const KisMultiSurfaceDisplayConfig &config)
void setDisplayFilter(QSharedPointer< KisDisplayFilter > displayFilter)
QImage convertImageToDisplayColorSpace(KisPaintDeviceSP srcDevice, QRect source=QRect(), bool applyOcio=false) const
convertImageToDisplayColorSpace Same as convertColorToDisplayColorSpace, but then for a KisPaintDevic...
QColor toQColor(const KoColor &c, bool proofToPaintColors=false) const
KoColor approximateFromRenderedQColor(const QColor &c) const
KoColor fromHsv(int h, int s, int v, int a=255) const
KoColor fromHsyF(qreal h, qreal s, qreal y, qreal R=0.2126, qreal G=0.7152, qreal B=0.0722, qreal gamma=2.2)
const KoColorSpace * nodeColorSpace() const
ConversionOptions conversionOptions() const
KoColor fromHsvF(qreal h, qreal s, qreal v, qreal a=1.0)
KisDisplayConfig This class keeps track of the color management configuration for image to display....
void setProfile(const KoColorProfile *profile)
void convertTo(const KoColorSpace *dstColorSpace=0, KoColorConversionTransformation::Intent renderingIntent=KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::ConversionFlags conversionFlags=KoColorConversionTransformation::internalConversionFlags())
const KoColorSpace * colorSpace() const
virtual const KoColorSpace * compositionSourceColorSpace() const
QRect exactBounds() const
const KoColorSpace * colorSpace() const
QImage convertToQImage(const KoColorProfile *dstProfile, qint32 x, qint32 y, qint32 w, qint32 h, KoColorConversionTransformation::Intent renderingIntent=KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::ConversionFlags conversionFlags=KoColorConversionTransformation::internalConversionFlags()) const
void convertFromQImage(const QImage &image, const KoColorProfile *profile, qint32 offsetX=0, qint32 offsetY=0)
bool setProfile(const KoColorProfile *profile, KUndo2Command *parentCommand)
void convertTo(const KoColorSpace *dstColorSpace, KoColorConversionTransformation::Intent renderingIntent=KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::ConversionFlags conversionFlags=KoColorConversionTransformation::internalConversionFlags(), KUndo2Command *parentCommand=nullptr, KoUpdater *progressUpdater=nullptr)
static KisPart * instance()
Definition KisPart.cpp:130
ALWAYS_INLINE quint8 * rawData()
double getUIMin(void) const
qint32 displayPosition() const
double getUIMax(void) const
virtual quint32 pixelSize() const =0
virtual QImage convertToQImage(const quint8 *data, qint32 width, qint32 height, const KoColorProfile *dstProfile, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const
QList< KoChannelInfo * > channels
virtual KoID colorModelId() const =0
virtual quint32 channelCount() const =0
virtual KoID colorDepthId() const =0
virtual void normalisedChannelsValue(const quint8 *pixel, QVector< float > &channels) const =0
virtual bool convertPixelsTo(const quint8 *src, quint8 *dst, const KoColorSpace *dstColorSpace, quint32 numPixels, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const
virtual const KoColorProfile * profile() const =0
void convertTo(const KoColorSpace *cs, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags)
Definition KoColor.cpp:136
void fromQColor(const QColor &c)
Convenient function for converting from a QColor.
Definition KoColor.cpp:213
quint8 * data()
Definition KoColor.h:144
const KoColorSpace * colorSpace() const
return the current colorSpace
Definition KoColor.h:82
void toQColor(QColor *c) const
a convenience method for the above.
Definition KoColor.cpp:198
void setProfile(const KoColorProfile *profile)
assign new profile without converting pixel data
Definition KoColor.cpp:177
Definition KoID.h:30
QString id() const
Definition KoID.cpp:63
#define KIS_ASSERT_RECOVER(cond)
Definition kis_assert.h:55
#define KIS_SAFE_ASSERT_RECOVER(cond)
Definition kis_assert.h:126
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
#define KIS_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:75
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130
#define bounds(x, a, b)
#define warnKrita
Definition kis_debug.h:91
KisPaintDeviceSP findValidDevice(KisNodeSP node)
@ ForegroundColor
The active foreground color selected for this canvas.
virtual KisPaintDeviceSP original() const =0
virtual const KoColorSpace * colorSpace() const =0
virtual KisPaintDeviceSP paintDevice() const =0
Private(KisDisplayColorConverter *_q, KoCanvasResourceProvider *_resourceManager)
bool needsColorProofing(const KoColorSpace *srcColorSpace) const
void slotCanvasResourceChanged(int key, const QVariant &v)
QSharedPointer< KisDisplayFilter > displayFilter
const KoColorProfile * ocioInputProfile() const
const KoColorProfile * ocioOutputProfile() const
KisMultiSurfaceDisplayConfig multiSurfaceDisplayConfig
const KoColorProfile * openGLSurfaceProfile() const
QScopedPointer< KoColorDisplayRendererInterface > displayRenderer
const KoColorSpace * ocioOutputColorSpace() const
const KoColorSpace * ocioInputColorSpace() const
KoColor approximateFromQColor(const QColor &qcolor)
const KoColorSpace * intermediateColorSpace() const
const KoColorSpace * openGLSurfaceColorSpace(const KoID &bitDepthId) const
const KoColorProfile * qtWidgetsProfile() const
QColor highlightOutlineColor
virtual void linearizeFloatValueFast(QVector< qreal > &Value) const =0
virtual QByteArray uniqueId() const =0
virtual void delinearizeFloatValueFast(QVector< qreal > &Value) const =0
static KoColorSpaceRegistry * instance()
const KoColorProfile * p709SRGBProfile() const
const KoColorSpace * rgb8(const QString &profileName=QString())
const KoColorProfile * p2020G10Profile() const