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
28#include "kundo2command.h"
29#include "kis_config.h"
30#include "kis_paint_device.h"
31#include "kis_iterator_ng.h"
33#include "KisDisplayConfig.h"
34
35#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
36#include <QGuiApplication>
37#endif
38
40
41
43{
45 : q(_q),
46 resourceManager(_resourceManager),
47 nodeColorSpace(0),
48 paintingColorSpace(0),
49 displayFilter(0),
50 displayRenderer(new DisplayRenderer(_q, _resourceManager))
51 {
52 }
53
55
57
60
61 const KoColorProfile* inputImageProfile = 0;
62
63 mutable const KoColorSpace *cachedOcioInputColorSpace = 0;
64 mutable const KoColorSpace *cachedOcioOutputColorSpace = 0;
65 mutable const KoColorSpace *cachedQtWidgetsColorSpace = 0;
66 mutable const KoColorSpace *cachedOpenGLSurfaceColorSpace = 0;
67
68 // this color space will never change during the run of Krita
69 mutable const KoColorSpace *cachedIntermediateColorSpace = 0;
70
72 cachedOcioInputColorSpace = 0;
73 cachedOcioOutputColorSpace = 0;
74 cachedQtWidgetsColorSpace = 0;
75 cachedOpenGLSurfaceColorSpace = 0;
76
78 }
79
81 return multiSurfaceDisplayConfig.uiProfile;
82 }
83
85 return multiSurfaceDisplayConfig.canvasProfile;
86 }
87
89 return displayFilter && displayFilter->useInternalColorManagement() ?
90 openGLSurfaceProfile() : inputImageProfile;
91 }
92
94 return openGLSurfaceProfile();
95 }
96
98 return cachedOcioInputColorSpace
99 ? cachedOcioInputColorSpace
100 : (cachedOcioInputColorSpace =
102 colorSpace(
105 ocioInputProfile()));
106 }
107
109 return cachedOcioOutputColorSpace
110 ? cachedOcioOutputColorSpace
111 : (cachedOcioOutputColorSpace =
113 colorSpace(
116 ocioOutputProfile()));
117
118 }
119
121 return cachedQtWidgetsColorSpace
122 ? cachedQtWidgetsColorSpace
123 : (cachedQtWidgetsColorSpace =
125 colorSpace(
128 qtWidgetsProfile()));
129
130 }
131
132 const KoColorSpace* openGLSurfaceColorSpace(const KoID &bitDepthId) const {
133 return cachedOpenGLSurfaceColorSpace
134 ? cachedOpenGLSurfaceColorSpace
135 : (cachedOpenGLSurfaceColorSpace =
137 colorSpace(
139 bitDepthId.id(),
140 openGLSurfaceProfile()));
141 }
142
144 // the color space where we apply exposure and
145 // gamma should always be linear
146 return cachedIntermediateColorSpace
147 ? cachedIntermediateColorSpace
148 : (cachedIntermediateColorSpace =
150 colorSpace(
154 }
155
157
159
163
166
167 inline KoColor approximateFromQColor(const QColor &qcolor);
168 inline QColor approximateToQColor(const KoColor &color);
169
170 void slotCanvasResourceChanged(int key, const QVariant &v);
171 void slotUpdateCurrentNodeColorSpace();
172 void selectPaintingColorSpace();
173
174 void updateIntermediateFgColor(const KoColor &color);
175 void setCurrentNode(KisNodeSP node);
176 bool useOcio() const;
177 bool needsColorProofing(const KoColorSpace *srcColorSpace) const;
178
180 public:
181 DisplayRenderer(KisDisplayColorConverter *displayColorConverter, KoCanvasResourceProvider *resourceManager)
182 : m_displayColorConverter(displayColorConverter),
183 m_resourceManager(resourceManager)
184 {
185 displayColorConverter->connect(displayColorConverter, SIGNAL(displayConfigurationChanged()),
186 this, SIGNAL(displayConfigurationChanged()), Qt::UniqueConnection);
187 }
188
189 QImage toQImage(const KoColorSpace *srcColorSpace, const quint8 *data, QSize size, bool proofPaintColors = false) const override {
190 QImage result = m_displayColorConverter->toQImage(srcColorSpace, data, size, proofPaintColors);
191 return result;
192 }
193
194 QColor toQColor(const KoColor &c, bool proofToPaintColors = false) const override {
195 return m_displayColorConverter->toQColor(c, proofToPaintColors);
196 }
197
198 KoColor approximateFromRenderedQColor(const QColor &c) const override {
199 return m_displayColorConverter->approximateFromRenderedQColor(c);
200 }
201
202 KoColor fromHsv(int h, int s, int v, int a) const override {
203 return m_displayColorConverter->fromHsv(h, s, v, a);
204 }
205
206 void getHsv(const KoColor &srcColor, int *h, int *s, int *v, int *a) const override {
207 m_displayColorConverter->getHsv(srcColor, h, s, v, a);
208 }
209
210 qreal minVisibleFloatValue(const KoChannelInfo *chaninfo) const override {
211 return chaninfo->getUIMin();
212 }
213
214 qreal maxVisibleFloatValue(const KoChannelInfo *chaninfo) const override {
215 qreal maxValue = chaninfo->getUIMax();
216
217 if (m_resourceManager) {
218 qreal exposure = m_resourceManager->resource(KoCanvasResource::HdrExposure).value<qreal>();
219 // not sure if *= is what we want
220 maxValue *= std::pow(2.0, -exposure);
221 }
222
223 return maxValue;
224 }
225
226 const KoColorSpace* getPaintingColorSpace() const override {
227 return m_displayColorConverter->paintingColorSpace();
228 }
229
230 QColor convertColorToDisplayColorSpace(KoColor c) const override {
231 return m_displayColorConverter->convertColorToDisplayColorSpace(c);
232 }
233
234 QImage convertImageToDisplayColorSpace(const QImage source) const override {
235 // Limited to 8bit sRGB for now...
237 srcDevice->convertFromQImage(source, KoColorSpaceRegistry::instance()->p709SRGBProfile(), 0, 0);
238 QImage destination = m_displayColorConverter->convertImageToDisplayColorSpace(srcDevice);
239 destination.setDevicePixelRatio(source.devicePixelRatio());
240 return destination;
241 }
242
244 return m_displayColorConverter->handlePaletteForDisplayColorSpace();
245 }
246
247 QPalette systemPaletteForDisplayColorSpace() const override {
248 return m_displayColorConverter->systemPaletteForDisplayColorSpace();
249 }
250
251 private:
254 };
255
256 QScopedPointer<KoColorDisplayRendererInterface> displayRenderer;
257};
258
260 : QObject(parent),
261 m_d(new Private(this, resourceManager))
262{
263 connect(m_d->resourceManager, SIGNAL(canvasResourceChanged(int,QVariant)),
264 SLOT(slotCanvasResourceChanged(int,QVariant)));
265 connect(KisConfigNotifier::instance(), SIGNAL(configChanged()),
266 SLOT(selectPaintingColorSpace()));
267
268 m_d->inputImageProfile = KoColorSpaceRegistry::instance()->p709SRGBProfile();
269 m_d->paintingColorSpace = KoColorSpaceRegistry::instance()->rgb8();
270 m_d->setCurrentNode(0);
273 connect(this, SIGNAL(displayConfigurationChanged()), this, SLOT(updatePalettes()));
274}
275
277 : m_d(new Private(this, 0))
278{
280
281 m_d->inputImageProfile = KoColorSpaceRegistry::instance()->p709SRGBProfile();
282 m_d->paintingColorSpace = KoColorSpaceRegistry::instance()->rgb8();
283
284 m_d->setCurrentNode(0);
285}
286
290
292{
293 m_d->inputImageProfile =
295 cs->profile() :
297
298 m_d->notifyDisplayConfigurationChanged();
299}
300
301
306
311
316
318{
319 if (!paintingColorSpace || srcColorSpace == paintingColorSpace || *srcColorSpace == *paintingColorSpace) {
320 return false;
321 }
322 // TODO: ideally, we'd identify color profiles that only differ in transfer curves but
323 // define the same primaries/gamut and return false for them aswell
324 if (srcColorSpace->colorModelId() == paintingColorSpace->colorModelId()) {
325 const KoColorProfile *paintProfile = paintingColorSpace->profile();
326 const KoColorProfile *srcProfile = srcColorSpace->profile();
327 bool matchingProfiles = (paintProfile == srcProfile) ||
328 (paintProfile && srcProfile && *paintProfile == *srcProfile);
329 // unless we go float->int, the color spaces are considered compatible
330 if (matchingProfiles &&
331 (srcColorSpace->colorDepthId() == Integer8BitsColorDepthID ||
332 srcColorSpace->colorDepthId() == Integer16BitsColorDepthID ||
335 return false;
336 }
337 }
338 return true;
339}
340
342{
344
345 KoColor color = srcColor;
346 color.convertTo(intermediateColorSpace());
347 displayFilter->approximateForwardTransformation(color.data(), 1);
348 intermediateFgColor = color;
349}
350
352{
354 KisNodeSP currentNode = v.value<KisNodeWSP>();
355 setCurrentNode(currentNode);
356 } else if (useOcio() && key == KoCanvasResource::ForegroundColor) {
357 updateIntermediateFgColor(v.value<KoColor>());
358 }
359}
360
362{
363 setCurrentNode(connectedNode);
364}
365
367{
369 KoColor c;
370 c.fromQColor(palette.gradientFillColor);
371 palette.gradientFillColor = convertColorToDisplayColorSpace(c);
372
373 c.fromQColor(palette.highlightColor);
374 palette.highlightColor = convertColorToDisplayColorSpace(c);
375
376 c.fromQColor(palette.highlightOutlineColor);
377 palette.highlightOutlineColor = convertColorToDisplayColorSpace(c);
378
379 c.fromQColor(palette.primaryColor);
381
382 c.fromQColor(palette.secondaryColor);
383 palette.secondaryColor = convertColorToDisplayColorSpace(c);
384
385 c.fromQColor(palette.selectionColor);
386 palette.selectionColor = convertColorToDisplayColorSpace(c);
387
388 c.fromQColor(palette.white);
390
391 c.fromQColor(palette.black);
393
394 QPalette pal = qApp->palette();
395 for (int r = 0; r < QPalette::NColorRoles; r++) {
396 for (int cg = 0; cg < QPalette::NColorGroups; cg++) {
397 c.fromQColor(pal.brush(QPalette::ColorGroup(cg), QPalette::ColorRole(r)).color());
398 pal.setBrush(QPalette::ColorGroup(cg), QPalette::ColorRole(r), convertColorToDisplayColorSpace(c));
399 }
400 }
401
402 m_d->handlePalette = palette;
403 m_d->systemPalette = pal;
404}
405
407 return node->paintDevice() ? node->paintDevice() : node->original();
408}
409
411{
412 if (connectedNode) {
413 KisPaintDeviceSP device = findValidDevice(connectedNode);
414
415 if (device) {
416 q->disconnect(device, 0);
417 }
418 }
419
420 nodeColorSpace = 0;
421
422 if (node) {
423 KisPaintDeviceSP device = findValidDevice(node);
424
425 nodeColorSpace = device ?
427 node->colorSpace();
428
430
431 if (device) {
432 q->connect(device, SIGNAL(profileChanged(const KoColorProfile*)),
433 SLOT(slotUpdateCurrentNodeColorSpace()), Qt::UniqueConnection);
434 q->connect(device, SIGNAL(colorSpaceChanged(const KoColorSpace*)),
435 SLOT(slotUpdateCurrentNodeColorSpace()), Qt::UniqueConnection);
436 }
437
438 }
439
440 if (!nodeColorSpace) {
442 }
443
444 connectedNode = node;
445 selectPaintingColorSpace();
446}
447
449{
450 KisConfig cfg(true);
452
455 }
456
457 notifyDisplayConfigurationChanged();
458}
459
461{
462 KIS_SAFE_ASSERT_RECOVER(m_d->paintingColorSpace) {
464 }
465
466 return m_d->paintingColorSpace;
467}
468
470{
471 return m_d->nodeColorSpace;
472}
473
475{
476 if (m_d->multiSurfaceDisplayConfig == config) return;
477
478
479
480 m_d->multiSurfaceDisplayConfig = config;
481 m_d->notifyDisplayConfigurationChanged();
482}
483
485{
486 if (m_d->displayFilter && displayFilter &&
487 displayFilter->lockCurrentColorVisualRepresentation()) {
488
489 KoColor color(m_d->intermediateFgColor);
490 displayFilter->approximateInverseTransformation(color.data(), 1);
491 color.convertTo(m_d->paintingColorSpace);
492 m_d->resourceManager->setForegroundColor(color);
493 }
494
495 m_d->displayFilter = displayFilter;
496
497 if (m_d->displayFilter) {
498 m_d->updateIntermediateFgColor(
499 m_d->resourceManager->foregroundColor());
500 }
501
502
503 { // sanity check
504 // KisConfig cfg;
505 // KIS_ASSERT_RECOVER_NOOP(cfg.useOcio() == (bool) m_d->displayFilter);
506 }
507
508 m_d->selectPaintingColorSpace();
509}
510
512{
513 return m_d->multiSurfaceDisplayConfig.uiDisplayConfig();
514}
515
520
522{
523 return m_d->multiSurfaceDisplayConfig;
524}
525
527{
528 return m_d->multiSurfaceDisplayConfig.options();
529}
530
531QColor KisDisplayColorConverter::toQColor(const KoColor &srcColor, bool proofToPaintColors) const
532{
533 KoColor c(srcColor);
534
535 if (proofToPaintColors && m_d->needsColorProofing(c.colorSpace())) {
536 c.convertTo(m_d->paintingColorSpace, m_d->multiSurfaceDisplayConfig.intent, m_d->multiSurfaceDisplayConfig.conversionFlags);
537 }
538
539 if (m_d->useOcio()) {
540 KIS_ASSERT_RECOVER(m_d->ocioInputColorSpace()->pixelSize() == 16) {
541 return QColor(Qt::green);
542 }
543
544 c.convertTo(m_d->ocioInputColorSpace());
545 m_d->displayFilter->filter(c.data(), 1);
546 c.setProfile(m_d->ocioOutputProfile());
547 }
548
549 // we expect the display profile is rgb8, which is BGRA here
550 KIS_ASSERT_RECOVER(m_d->qtWidgetsColorSpace()->pixelSize() == 4) {
551 return QColor(Qt::red);
552 }
553
554 c.convertTo(m_d->qtWidgetsColorSpace(), m_d->multiSurfaceDisplayConfig.intent, m_d->multiSurfaceDisplayConfig.conversionFlags);
555 const quint8 *p = c.data();
556 return QColor(p[2], p[1], p[0], p[3]);
557}
558
560 const KoID &bitDepthId) const
561{
562 KoColor c(srcColor);
563
564 if (m_d->useOcio()) {
565 KIS_ASSERT_RECOVER(m_d->ocioInputColorSpace()->pixelSize() == 16) {
566 return srcColor;
567 }
568
569 c.convertTo(m_d->ocioInputColorSpace());
570 m_d->displayFilter->filter(c.data(), 1);
571 c.setProfile(m_d->ocioOutputProfile());
572 }
573
574 c.convertTo(m_d->openGLSurfaceColorSpace(bitDepthId), m_d->multiSurfaceDisplayConfig.intent, m_d->multiSurfaceDisplayConfig.conversionFlags);
575 return c;
576}
577
579{
580 const KoColorProfile *displayProfile = m_d->openGLSurfaceProfile();
581
582 return !m_d->useOcio() &&
584 (!!cs->profile() == !!displayProfile) &&
585 (!cs->profile() ||
586 cs->profile()->uniqueId() == displayProfile->uniqueId());
587}
588
589
591{
592 return m_d->approximateFromQColor(c);
593}
594
595QImage KisDisplayColorConverter::toQImage(KisPaintDeviceSP srcDevice, bool proofPaintColors) const
596{
597 KisPaintDeviceSP device = srcDevice;
598
599 QRect bounds = srcDevice->exactBounds();
600 if (bounds.isEmpty()) return QImage();
601
602 if (proofPaintColors && m_d->needsColorProofing(srcDevice->colorSpace())) {
603 srcDevice->convertTo(paintingColorSpace(), m_d->multiSurfaceDisplayConfig.intent, m_d->multiSurfaceDisplayConfig.conversionFlags);
604 }
605
606 if (m_d->useOcio()) {
607 KIS_ASSERT_RECOVER(m_d->ocioInputColorSpace()->pixelSize() == 16) {
608 return QImage();
609 }
610
611 device = new KisPaintDevice(*srcDevice);
612 device->convertTo(m_d->ocioInputColorSpace());
613
614 KisSequentialIterator it(device, bounds);
615 int numConseqPixels = it.nConseqPixels();
616 while (it.nextPixels(numConseqPixels)) {
617 numConseqPixels = it.nConseqPixels();
618 m_d->displayFilter->filter(it.rawData(), numConseqPixels);
619 }
620
621 device->setProfile(m_d->ocioOutputProfile(), 0);
622 }
623
624 // we expect the display profile is rgb8, which is BGRA here
625 KIS_ASSERT_RECOVER(m_d->qtWidgetsColorSpace()->pixelSize() == 4) {
626 return QImage();
627 }
628
629 return device->convertToQImage(m_d->qtWidgetsProfile(),
630 bounds,
631 m_d->multiSurfaceDisplayConfig.intent,
632 m_d->multiSurfaceDisplayConfig.conversionFlags);
633}
634
635QImage KisDisplayColorConverter::toQImage(const KoColorSpace *srcColorSpace, const quint8 *data, QSize size, bool proofPaintColors) const
636{
637 const int numPixels = size.width() * size.height();
638
639 const KoColorSpace *colorSpace = srcColorSpace;
640 const quint8 *pixels = data;
641
642 QScopedArrayPointer<quint8> proofBuffer;
643
644 if (proofPaintColors && m_d->needsColorProofing(srcColorSpace)) {
645 const int imageSize = numPixels * paintingColorSpace()->pixelSize();
646 proofBuffer.reset(new quint8[imageSize]);
647 colorSpace->convertPixelsTo(pixels, proofBuffer.data(),
649 numPixels,
650 m_d->multiSurfaceDisplayConfig.intent,
651 m_d->multiSurfaceDisplayConfig.conversionFlags);
652 colorSpace = paintingColorSpace();
653 pixels = proofBuffer.data();
654 }
655
656 QScopedArrayPointer<quint8> ocioBuffer;
657 if (m_d->useOcio()) {
658 const int imageSize = numPixels * m_d->ocioInputColorSpace()->pixelSize();
659 ocioBuffer.reset(new quint8[imageSize]);
660 colorSpace->convertPixelsTo(pixels, ocioBuffer.data(),
661 m_d->ocioInputColorSpace(),
662 numPixels,
663 m_d->multiSurfaceDisplayConfig.intent,
664 m_d->multiSurfaceDisplayConfig.conversionFlags);
665 m_d->displayFilter->filter(ocioBuffer.data(), numPixels);
666
667 return m_d->ocioOutputColorSpace()->convertToQImage(ocioBuffer.data(), size.width(), size.height(),
668 m_d->qtWidgetsProfile(),
669 m_d->multiSurfaceDisplayConfig.intent,
670 m_d->multiSurfaceDisplayConfig.conversionFlags);
671 }
672
673 return colorSpace->convertToQImage(pixels, size.width(), size.height(),
674 m_d->qtWidgetsProfile(),
675 m_d->multiSurfaceDisplayConfig.intent,
676 m_d->multiSurfaceDisplayConfig.conversionFlags);
677}
678
680 const KoColorSpace *dstColorSpace) const
681{
689 KIS_SAFE_ASSERT_RECOVER_RETURN(device->bounds().isValid());
690
691 if (m_d->useOcio()) {
692 KIS_ASSERT_RECOVER_RETURN(m_d->ocioInputColorSpace()->pixelSize() == 16);
693
694 device->convertTo(m_d->ocioInputColorSpace());
695 m_d->displayFilter->filter(device->data(), device->bounds().width() * device->bounds().height());
696 device->setProfile(m_d->ocioOutputProfile());
697 }
698
699 KIS_SAFE_ASSERT_RECOVER_RETURN(dstColorSpace);
700 device->convertTo(dstColorSpace);
701}
702
704{
705 KoColor newColor;
706 if (applyOcio) {
708 } else {
709 newColor = KoColor(color);
710 newColor.convertTo(m_d->openGLSurfaceColorSpace(Float32BitsColorDepthID), m_d->multiSurfaceDisplayConfig.intent, m_d->multiSurfaceDisplayConfig.conversionFlags);
711 }
712
715
716 QVector<float> norm(newColor.colorSpace()->channelCount());
717 newColor.colorSpace()->normalisedChannelsValue(newColor.data(), norm);
718
719 // sort into RGBA order... maybe a little overengineered.
720 QVector<float> sorted = norm;
721 for (int ch = 0; ch < norm.size(); ch++) {
722 const KoChannelInfo *info = newColor.colorSpace()->channels().at(ch);
723 sorted[info->displayPosition()] = norm[ch];
724 }
725
726 // We need to manually create a QColor here, because if we use KoColor.toQColor, the whole KoColor is first
727 // converted to sRGB before becoming a QColor, while we explicitely do not want that for our QColor.
728 // This is further complicated by the fact that QColors cannot have any (Q)ColorSpace metadata associated with it, unlike KoColor.
729 return QColor::fromRgbF(sorted[0], sorted[1], sorted[2], sorted[3]);
730}
731
733{
734 KisPaintDeviceSP conversionDevice = new KisPaintDevice(*srcDevice.data());
735 const QRect s = source.isValid()? source: conversionDevice->exactBounds();
736
737 if (m_d->useOcio() && applyOcio) {
738 KIS_ASSERT_RECOVER(m_d->ocioInputColorSpace()->pixelSize() == 16) {
739 return QImage();
740 }
741
742 conversionDevice->convertTo(m_d->ocioInputColorSpace());
743 KisSequentialIterator it(conversionDevice, s);
744 int numConseqPixels = it.nConseqPixels();
745 while (it.nextPixels(numConseqPixels)) {
746 numConseqPixels = it.nConseqPixels();
747 m_d->displayFilter->filter(it.rawData(), numConseqPixels);
748 }
749 conversionDevice->setProfile(m_d->ocioOutputProfile(), 0);
750 }
751
752 conversionDevice->convertTo(m_d->openGLSurfaceColorSpace(Float32BitsColorDepthID), m_d->multiSurfaceDisplayConfig.intent, m_d->multiSurfaceDisplayConfig.conversionFlags);
753 return conversionDevice->convertToQImage(m_d->openGLSurfaceProfile(), s, m_d->multiSurfaceDisplayConfig.intent, m_d->multiSurfaceDisplayConfig.conversionFlags);
754}
755
760
762{
763 return m_d->systemPalette;
764}
765
767{
768 if (!useOcio()) {
769 return KoColor(qcolor, paintingColorSpace);
770 } else {
771 KoColor color(qcolor, intermediateColorSpace());
772 displayFilter->approximateInverseTransformation(color.data(), 1);
774 return color;
775 }
776
777 qFatal("Must not be reachable");
778 return KoColor();
779}
780
782{
783 KoColor color(srcColor);
784
785 if (useOcio()) {
786 color.convertTo(intermediateColorSpace());
787 displayFilter->approximateForwardTransformation(color.data(), 1);
788 }
789
790 return color.toQColor();
791}
792
793
794KoColor KisDisplayColorConverter::fromHsv(int h, int s, int v, int a) const
795{
796 // generate HSV from sRGB!
797 QColor qcolor(QColor::fromHsv(h, s, v, a));
798 return m_d->approximateFromQColor(qcolor);
799}
800
801void KisDisplayColorConverter::getHsv(const KoColor &srcColor, int *h, int *s, int *v, int *a) const
802{
803 // we are going through sRGB here!
804 QColor color = m_d->approximateToQColor(srcColor);
805 color.getHsv(h, s, v, a);
806}
807
808KoColor KisDisplayColorConverter::fromHsvF(qreal h, qreal s, qreal v, qreal a)
809{
810 // generate HSV from sRGB!
811 QColor qcolor(QColor::fromHsvF(h, s, v, a));
812 return m_d->approximateFromQColor(qcolor);
813}
814
815void KisDisplayColorConverter::getHsvF(const KoColor &srcColor, qreal *h, qreal *s, qreal *v, qreal *a)
816{
817 // we are going through sRGB here!
818 QColor color = m_d->approximateToQColor(srcColor);
819#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
820 color.getHsvF(h, s, v, a);
821#else
822 float fH, fS, fV, fA;
823 fH = *h;
824 fS = *s;
825 fV = *v;
826 if (a) {
827 fA = *a;
828 }
829 color.getHsvF(&fH, &fS, &fV, &fA);
830 *h = fH;
831 *s = fS;
832 *v = fV;
833 if (a) {
834 *a = fA;
835 }
836#endif
837}
838
839KoColor KisDisplayColorConverter::fromHslF(qreal h, qreal s, qreal l, qreal a)
840{
841 // generate HSL from sRGB!
842 QColor qcolor(QColor::fromHslF(h, s, l, a));
843 if (!qcolor.isValid()) {
844 warnKrita << "Could not construct valid color from h" << h << "s" << s << "l" << l << "a" << a;
845 qcolor = Qt::black;
846 }
847 return m_d->approximateFromQColor(qcolor);
848
849}
850
851void KisDisplayColorConverter::getHslF(const KoColor &srcColor, qreal *h, qreal *s, qreal *l, qreal *a)
852{
853 // we are going through sRGB here!
854 QColor color = m_d->approximateToQColor(srcColor);
855#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
856 color.getHslF(h, s, l, a);
857#else
858 float fH, fS, fL, fA;
859 fH = *h;
860 fS = *s;
861 fL = *l;
862 if (a) {
863 fA = *a;
864 }
865 color.getHslF(&fH, &fS, &fL, &fA);
866 *h = fH;
867 *s = fS;
868 *l = fL;
869 if (a) {
870 *a = fA;
871 }
872#endif
873}
874
876{
877 // generate HSI from sRGB!
878 qreal r=0.0;
879 qreal g=0.0;
880 qreal b=0.0;
881 qreal a=1.0;
882 HSIToRGB(h, s, i, &r, &g, &b);
883 QColor qcolor;
884 qcolor.setRgbF(qBound(0.0,r,1.0), qBound(0.0,g,1.0), qBound(0.0,b,1.0), a);
885 return m_d->approximateFromQColor(qcolor);
886}
887
888void KisDisplayColorConverter::getHsiF(const KoColor &srcColor, qreal *h, qreal *s, qreal *i)
889{
890 // we are going through sRGB here!
891 QColor color = m_d->approximateToQColor(srcColor);
892 qreal r=color.redF();
893 qreal g=color.greenF();
894 qreal b=color.blueF();
895 RGBToHSI(r, g, b, h, s, i);
896}
897
898KoColor KisDisplayColorConverter::fromHsyF(qreal h, qreal s, qreal y, qreal R, qreal G, qreal B, qreal gamma)
899{
900 // generate HSL from sRGB!
901 QVector <qreal> channelValues(3);
902 y = pow(y, gamma);
903 HSYToRGB(h, s, y, &channelValues[0], &channelValues[1], &channelValues[2], R, G, B);
905 QColor qcolor;
906 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);
907 return m_d->approximateFromQColor(qcolor);
908}
909
910void KisDisplayColorConverter::getHsyF(const KoColor &srcColor, qreal *h, qreal *s, qreal *y, qreal R, qreal G, qreal B, qreal gamma)
911{
912 // we are going through sRGB here!
913 QColor color = m_d->approximateToQColor(srcColor);
914 QVector <qreal> channelValues(3);
915 channelValues[0]=color.redF();
916 channelValues[1]=color.greenF();
917 channelValues[2]=color.blueF();
918 //TODO: if we're going to have KoColor here, remember to check whether the TRC of the profile exists...
920 RGBToHSY(channelValues[0], channelValues[1], channelValues[2], h, s, y, R, G, B);
921 *y = pow(*y, 1/gamma);
922}
923
924#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)
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:87
KisPaintDeviceSP findValidDevice(KisNodeSP node)
@ ForegroundColor
The active foreground color selected for this canvas.
rgba palette[MAX_PALETTE]
Definition palette.c:35
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
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