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
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 connect(KisPart::instance()->currentMainwindow(), SIGNAL(themeChanged()), this, SLOT(updatePalettes()));
277}
278
280 : m_d(new Private(this, 0))
281{
283
284 m_d->inputImageProfile = KoColorSpaceRegistry::instance()->p709SRGBProfile();
285 m_d->paintingColorSpace = KoColorSpaceRegistry::instance()->rgb8();
286
287 m_d->setCurrentNode(0);
288}
289
293
295{
296 m_d->inputImageProfile =
298 cs->profile() :
300
301 m_d->notifyDisplayConfigurationChanged();
302}
303
304
309
314
319
321{
322 if (!paintingColorSpace || srcColorSpace == paintingColorSpace || *srcColorSpace == *paintingColorSpace) {
323 return false;
324 }
325 // TODO: ideally, we'd identify color profiles that only differ in transfer curves but
326 // define the same primaries/gamut and return false for them aswell
327 if (srcColorSpace->colorModelId() == paintingColorSpace->colorModelId()) {
328 const KoColorProfile *paintProfile = paintingColorSpace->profile();
329 const KoColorProfile *srcProfile = srcColorSpace->profile();
330 bool matchingProfiles = (paintProfile == srcProfile) ||
331 (paintProfile && srcProfile && *paintProfile == *srcProfile);
332 // unless we go float->int, the color spaces are considered compatible
333 if (matchingProfiles &&
334 (srcColorSpace->colorDepthId() == Integer8BitsColorDepthID ||
335 srcColorSpace->colorDepthId() == Integer16BitsColorDepthID ||
338 return false;
339 }
340 }
341 return true;
342}
343
345{
347
348 KoColor color = srcColor;
349 color.convertTo(intermediateColorSpace());
350 displayFilter->approximateForwardTransformation(color.data(), 1);
351 intermediateFgColor = color;
352}
353
355{
357 KisNodeSP currentNode = v.value<KisNodeWSP>();
358 setCurrentNode(currentNode);
359 } else if (useOcio() && key == KoCanvasResource::ForegroundColor) {
360 updateIntermediateFgColor(v.value<KoColor>());
361 }
362}
363
365{
366 setCurrentNode(connectedNode);
367}
368
370{
372 KoColor c;
373 c.fromQColor(palette.gradientFillColor);
374 palette.gradientFillColor = convertColorToDisplayColorSpace(c);
375
376 c.fromQColor(palette.highlightColor);
377 palette.highlightColor = convertColorToDisplayColorSpace(c);
378
379 c.fromQColor(palette.highlightOutlineColor);
380 palette.highlightOutlineColor = convertColorToDisplayColorSpace(c);
381
382 c.fromQColor(palette.primaryColor);
384
385 c.fromQColor(palette.secondaryColor);
386 palette.secondaryColor = convertColorToDisplayColorSpace(c);
387
388 c.fromQColor(palette.selectionColor);
389 palette.selectionColor = convertColorToDisplayColorSpace(c);
390
391 c.fromQColor(palette.white);
393
394 c.fromQColor(palette.black);
396
397 QPalette pal = qApp->palette();
398 for (int r = 0; r < QPalette::NColorRoles; r++) {
399 for (int cg = 0; cg < QPalette::NColorGroups; cg++) {
400 c.fromQColor(pal.brush(QPalette::ColorGroup(cg), QPalette::ColorRole(r)).color());
401 pal.setBrush(QPalette::ColorGroup(cg), QPalette::ColorRole(r), convertColorToDisplayColorSpace(c));
402 }
403 }
404
405 m_d->handlePalette = palette;
406 m_d->systemPalette = pal;
407}
408
410 return node->paintDevice() ? node->paintDevice() : node->original();
411}
412
414{
415 if (connectedNode) {
416 KisPaintDeviceSP device = findValidDevice(connectedNode);
417
418 if (device) {
419 q->disconnect(device, 0);
420 }
421 }
422
423 nodeColorSpace = 0;
424
425 if (node) {
426 KisPaintDeviceSP device = findValidDevice(node);
427
428 nodeColorSpace = device ?
430 node->colorSpace();
431
433
434 if (device) {
435 q->connect(device, SIGNAL(profileChanged(const KoColorProfile*)),
436 SLOT(slotUpdateCurrentNodeColorSpace()), Qt::UniqueConnection);
437 q->connect(device, SIGNAL(colorSpaceChanged(const KoColorSpace*)),
438 SLOT(slotUpdateCurrentNodeColorSpace()), Qt::UniqueConnection);
439 }
440
441 }
442
443 if (!nodeColorSpace) {
445 }
446
447 connectedNode = node;
448 selectPaintingColorSpace();
449}
450
452{
453 KisConfig cfg(true);
455
458 }
459
460 notifyDisplayConfigurationChanged();
461}
462
464{
465 KIS_SAFE_ASSERT_RECOVER(m_d->paintingColorSpace) {
467 }
468
469 return m_d->paintingColorSpace;
470}
471
473{
474 return m_d->nodeColorSpace;
475}
476
478{
479 if (m_d->multiSurfaceDisplayConfig == config) return;
480
481
482
483 m_d->multiSurfaceDisplayConfig = config;
484 m_d->notifyDisplayConfigurationChanged();
485}
486
488{
489 if (m_d->displayFilter && displayFilter &&
490 displayFilter->lockCurrentColorVisualRepresentation()) {
491
492 KoColor color(m_d->intermediateFgColor);
493 displayFilter->approximateInverseTransformation(color.data(), 1);
494 color.convertTo(m_d->paintingColorSpace);
495 m_d->resourceManager->setForegroundColor(color);
496 }
497
498 m_d->displayFilter = displayFilter;
499
500 if (m_d->displayFilter) {
501 m_d->updateIntermediateFgColor(
502 m_d->resourceManager->foregroundColor());
503 }
504
505
506 { // sanity check
507 // KisConfig cfg;
508 // KIS_ASSERT_RECOVER_NOOP(cfg.useOcio() == (bool) m_d->displayFilter);
509 }
510
511 m_d->selectPaintingColorSpace();
512}
513
515{
516 return m_d->multiSurfaceDisplayConfig.uiDisplayConfig();
517}
518
523
525{
526 return m_d->multiSurfaceDisplayConfig;
527}
528
530{
531 return m_d->multiSurfaceDisplayConfig.options();
532}
533
534QColor KisDisplayColorConverter::toQColor(const KoColor &srcColor, bool proofToPaintColors) const
535{
536 KoColor c(srcColor);
537
538 if (proofToPaintColors && m_d->needsColorProofing(c.colorSpace())) {
539 c.convertTo(m_d->paintingColorSpace, m_d->multiSurfaceDisplayConfig.intent, m_d->multiSurfaceDisplayConfig.conversionFlags);
540 }
541
542 if (m_d->useOcio()) {
543 KIS_ASSERT_RECOVER(m_d->ocioInputColorSpace()->pixelSize() == 16) {
544 return QColor(Qt::green);
545 }
546
547 c.convertTo(m_d->ocioInputColorSpace());
548 m_d->displayFilter->filter(c.data(), 1);
549 c.setProfile(m_d->ocioOutputProfile());
550 }
551
552 // we expect the display profile is rgb8, which is BGRA here
553 KIS_ASSERT_RECOVER(m_d->qtWidgetsColorSpace()->pixelSize() == 4) {
554 return QColor(Qt::red);
555 }
556
557 c.convertTo(m_d->qtWidgetsColorSpace(), m_d->multiSurfaceDisplayConfig.intent, m_d->multiSurfaceDisplayConfig.conversionFlags);
558 const quint8 *p = c.data();
559 return QColor(p[2], p[1], p[0], p[3]);
560}
561
563 const KoID &bitDepthId) const
564{
565 KoColor c(srcColor);
566
567 if (m_d->useOcio()) {
568 KIS_ASSERT_RECOVER(m_d->ocioInputColorSpace()->pixelSize() == 16) {
569 return srcColor;
570 }
571
572 c.convertTo(m_d->ocioInputColorSpace());
573 m_d->displayFilter->filter(c.data(), 1);
574 c.setProfile(m_d->ocioOutputProfile());
575 }
576
577 c.convertTo(m_d->openGLSurfaceColorSpace(bitDepthId), m_d->multiSurfaceDisplayConfig.intent, m_d->multiSurfaceDisplayConfig.conversionFlags);
578 return c;
579}
580
582{
583 const KoColorProfile *displayProfile = m_d->openGLSurfaceProfile();
584
585 return !m_d->useOcio() &&
587 (!!cs->profile() == !!displayProfile) &&
588 (!cs->profile() ||
589 cs->profile()->uniqueId() == displayProfile->uniqueId());
590}
591
592
594{
595 return m_d->approximateFromQColor(c);
596}
597
598QImage KisDisplayColorConverter::toQImage(KisPaintDeviceSP srcDevice, bool proofPaintColors) const
599{
600 KisPaintDeviceSP device = srcDevice;
601
602 QRect bounds = srcDevice->exactBounds();
603 if (bounds.isEmpty()) return QImage();
604
605 if (proofPaintColors && m_d->needsColorProofing(srcDevice->colorSpace())) {
606 srcDevice->convertTo(paintingColorSpace(), m_d->multiSurfaceDisplayConfig.intent, m_d->multiSurfaceDisplayConfig.conversionFlags);
607 }
608
609 if (m_d->useOcio()) {
610 KIS_ASSERT_RECOVER(m_d->ocioInputColorSpace()->pixelSize() == 16) {
611 return QImage();
612 }
613
614 device = new KisPaintDevice(*srcDevice);
615 device->convertTo(m_d->ocioInputColorSpace());
616
617 KisSequentialIterator it(device, bounds);
618 int numConseqPixels = it.nConseqPixels();
619 while (it.nextPixels(numConseqPixels)) {
620 numConseqPixels = it.nConseqPixels();
621 m_d->displayFilter->filter(it.rawData(), numConseqPixels);
622 }
623
624 device->setProfile(m_d->ocioOutputProfile(), 0);
625 }
626
627 // we expect the display profile is rgb8, which is BGRA here
628 KIS_ASSERT_RECOVER(m_d->qtWidgetsColorSpace()->pixelSize() == 4) {
629 return QImage();
630 }
631
632 return device->convertToQImage(m_d->qtWidgetsProfile(),
633 bounds,
634 m_d->multiSurfaceDisplayConfig.intent,
635 m_d->multiSurfaceDisplayConfig.conversionFlags);
636}
637
638QImage KisDisplayColorConverter::toQImage(const KoColorSpace *srcColorSpace, const quint8 *data, QSize size, bool proofPaintColors) const
639{
640 const int numPixels = size.width() * size.height();
641
642 const KoColorSpace *colorSpace = srcColorSpace;
643 const quint8 *pixels = data;
644
645 QScopedArrayPointer<quint8> proofBuffer;
646
647 if (proofPaintColors && m_d->needsColorProofing(srcColorSpace)) {
648 const int imageSize = numPixels * paintingColorSpace()->pixelSize();
649 proofBuffer.reset(new quint8[imageSize]);
650 colorSpace->convertPixelsTo(pixels, proofBuffer.data(),
652 numPixels,
653 m_d->multiSurfaceDisplayConfig.intent,
654 m_d->multiSurfaceDisplayConfig.conversionFlags);
655 colorSpace = paintingColorSpace();
656 pixels = proofBuffer.data();
657 }
658
659 QScopedArrayPointer<quint8> ocioBuffer;
660 if (m_d->useOcio()) {
661 const int imageSize = numPixels * m_d->ocioInputColorSpace()->pixelSize();
662 ocioBuffer.reset(new quint8[imageSize]);
663 colorSpace->convertPixelsTo(pixels, ocioBuffer.data(),
664 m_d->ocioInputColorSpace(),
665 numPixels,
666 m_d->multiSurfaceDisplayConfig.intent,
667 m_d->multiSurfaceDisplayConfig.conversionFlags);
668 m_d->displayFilter->filter(ocioBuffer.data(), numPixels);
669
670 return m_d->ocioOutputColorSpace()->convertToQImage(ocioBuffer.data(), size.width(), size.height(),
671 m_d->qtWidgetsProfile(),
672 m_d->multiSurfaceDisplayConfig.intent,
673 m_d->multiSurfaceDisplayConfig.conversionFlags);
674 }
675
676 return colorSpace->convertToQImage(pixels, size.width(), size.height(),
677 m_d->qtWidgetsProfile(),
678 m_d->multiSurfaceDisplayConfig.intent,
679 m_d->multiSurfaceDisplayConfig.conversionFlags);
680}
681
683 const KoColorSpace *dstColorSpace) const
684{
692 KIS_SAFE_ASSERT_RECOVER_RETURN(device->bounds().isValid());
693
694 if (m_d->useOcio()) {
695 KIS_ASSERT_RECOVER_RETURN(m_d->ocioInputColorSpace()->pixelSize() == 16);
696
697 device->convertTo(m_d->ocioInputColorSpace());
698 m_d->displayFilter->filter(device->data(), device->bounds().width() * device->bounds().height());
699 device->setProfile(m_d->ocioOutputProfile());
700 }
701
702 KIS_SAFE_ASSERT_RECOVER_RETURN(dstColorSpace);
703 device->convertTo(dstColorSpace);
704}
705
707{
708 KoColor newColor;
709 if (applyOcio) {
711 } else {
712 newColor = KoColor(color);
713 newColor.convertTo(m_d->openGLSurfaceColorSpace(Float32BitsColorDepthID), m_d->multiSurfaceDisplayConfig.intent, m_d->multiSurfaceDisplayConfig.conversionFlags);
714 }
715
718
719 QVector<float> norm(newColor.colorSpace()->channelCount());
720 newColor.colorSpace()->normalisedChannelsValue(newColor.data(), norm);
721
722 // sort into RGBA order... maybe a little overengineered.
723 QVector<float> sorted = norm;
724 for (int ch = 0; ch < norm.size(); ch++) {
725 const KoChannelInfo *info = newColor.colorSpace()->channels().at(ch);
726 sorted[info->displayPosition()] = norm[ch];
727 }
728
729 // We need to manually create a QColor here, because if we use KoColor.toQColor, the whole KoColor is first
730 // converted to sRGB before becoming a QColor, while we explicitely do not want that for our QColor.
731 // This is further complicated by the fact that QColors cannot have any (Q)ColorSpace metadata associated with it, unlike KoColor.
732 return QColor::fromRgbF(sorted[0], sorted[1], sorted[2], sorted[3]);
733}
734
736{
737 KisPaintDeviceSP conversionDevice = new KisPaintDevice(*srcDevice.data());
738 const QRect s = source.isValid()? source: conversionDevice->exactBounds();
739
740 if (m_d->useOcio() && applyOcio) {
741 KIS_ASSERT_RECOVER(m_d->ocioInputColorSpace()->pixelSize() == 16) {
742 return QImage();
743 }
744
745 conversionDevice->convertTo(m_d->ocioInputColorSpace());
746 KisSequentialIterator it(conversionDevice, s);
747 int numConseqPixels = it.nConseqPixels();
748 while (it.nextPixels(numConseqPixels)) {
749 numConseqPixels = it.nConseqPixels();
750 m_d->displayFilter->filter(it.rawData(), numConseqPixels);
751 }
752 conversionDevice->setProfile(m_d->ocioOutputProfile(), 0);
753 }
754
755 conversionDevice->convertTo(m_d->openGLSurfaceColorSpace(Float32BitsColorDepthID), m_d->multiSurfaceDisplayConfig.intent, m_d->multiSurfaceDisplayConfig.conversionFlags);
756 return conversionDevice->convertToQImage(m_d->openGLSurfaceProfile(), s, m_d->multiSurfaceDisplayConfig.intent, m_d->multiSurfaceDisplayConfig.conversionFlags);
757}
758
763
765{
766 return m_d->systemPalette;
767}
768
770{
771 if (!useOcio()) {
772 return KoColor(qcolor, paintingColorSpace);
773 } else {
774 KoColor color(qcolor, intermediateColorSpace());
775 displayFilter->approximateInverseTransformation(color.data(), 1);
777 return color;
778 }
779
780 qFatal("Must not be reachable");
781 return KoColor();
782}
783
785{
786 KoColor color(srcColor);
787
788 if (useOcio()) {
789 color.convertTo(intermediateColorSpace());
790 displayFilter->approximateForwardTransformation(color.data(), 1);
791 }
792
793 return color.toQColor();
794}
795
796
797KoColor KisDisplayColorConverter::fromHsv(int h, int s, int v, int a) const
798{
799 // generate HSV from sRGB!
800 QColor qcolor(QColor::fromHsv(h, s, v, a));
801 return m_d->approximateFromQColor(qcolor);
802}
803
804void KisDisplayColorConverter::getHsv(const KoColor &srcColor, int *h, int *s, int *v, int *a) const
805{
806 // we are going through sRGB here!
807 QColor color = m_d->approximateToQColor(srcColor);
808 color.getHsv(h, s, v, a);
809}
810
811KoColor KisDisplayColorConverter::fromHsvF(qreal h, qreal s, qreal v, qreal a)
812{
813 // generate HSV from sRGB!
814 QColor qcolor(QColor::fromHsvF(h, s, v, a));
815 return m_d->approximateFromQColor(qcolor);
816}
817
818void KisDisplayColorConverter::getHsvF(const KoColor &srcColor, qreal *h, qreal *s, qreal *v, qreal *a)
819{
820 // we are going through sRGB here!
821 QColor color = m_d->approximateToQColor(srcColor);
822#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
823 color.getHsvF(h, s, v, a);
824#else
825 float fH, fS, fV, fA;
826 fH = *h;
827 fS = *s;
828 fV = *v;
829 if (a) {
830 fA = *a;
831 }
832 color.getHsvF(&fH, &fS, &fV, &fA);
833 *h = fH;
834 *s = fS;
835 *v = fV;
836 if (a) {
837 *a = fA;
838 }
839#endif
840}
841
842KoColor KisDisplayColorConverter::fromHslF(qreal h, qreal s, qreal l, qreal a)
843{
844 // generate HSL from sRGB!
845 QColor qcolor(QColor::fromHslF(h, s, l, a));
846 if (!qcolor.isValid()) {
847 warnKrita << "Could not construct valid color from h" << h << "s" << s << "l" << l << "a" << a;
848 qcolor = Qt::black;
849 }
850 return m_d->approximateFromQColor(qcolor);
851
852}
853
854void KisDisplayColorConverter::getHslF(const KoColor &srcColor, qreal *h, qreal *s, qreal *l, qreal *a)
855{
856 // we are going through sRGB here!
857 QColor color = m_d->approximateToQColor(srcColor);
858#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
859 color.getHslF(h, s, l, a);
860#else
861 float fH, fS, fL, fA;
862 fH = *h;
863 fS = *s;
864 fL = *l;
865 if (a) {
866 fA = *a;
867 }
868 color.getHslF(&fH, &fS, &fL, &fA);
869 *h = fH;
870 *s = fS;
871 *l = fL;
872 if (a) {
873 *a = fA;
874 }
875#endif
876}
877
879{
880 // generate HSI from sRGB!
881 qreal r=0.0;
882 qreal g=0.0;
883 qreal b=0.0;
884 qreal a=1.0;
885 HSIToRGB(h, s, i, &r, &g, &b);
886 QColor qcolor;
887 qcolor.setRgbF(qBound(0.0,r,1.0), qBound(0.0,g,1.0), qBound(0.0,b,1.0), a);
888 return m_d->approximateFromQColor(qcolor);
889}
890
891void KisDisplayColorConverter::getHsiF(const KoColor &srcColor, qreal *h, qreal *s, qreal *i)
892{
893 // we are going through sRGB here!
894 QColor color = m_d->approximateToQColor(srcColor);
895 qreal r=color.redF();
896 qreal g=color.greenF();
897 qreal b=color.blueF();
898 RGBToHSI(r, g, b, h, s, i);
899}
900
901KoColor KisDisplayColorConverter::fromHsyF(qreal h, qreal s, qreal y, qreal R, qreal G, qreal B, qreal gamma)
902{
903 // generate HSL from sRGB!
904 QVector <qreal> channelValues(3);
905 y = pow(y, gamma);
906 HSYToRGB(h, s, y, &channelValues[0], &channelValues[1], &channelValues[2], R, G, B);
908 QColor qcolor;
909 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);
910 return m_d->approximateFromQColor(qcolor);
911}
912
913void KisDisplayColorConverter::getHsyF(const KoColor &srcColor, qreal *h, qreal *s, qreal *y, qreal R, qreal G, qreal B, qreal gamma)
914{
915 // we are going through sRGB here!
916 QColor color = m_d->approximateToQColor(srcColor);
917 QVector <qreal> channelValues(3);
918 channelValues[0]=color.redF();
919 channelValues[1]=color.greenF();
920 channelValues[2]=color.blueF();
921 //TODO: if we're going to have KoColor here, remember to check whether the TRC of the profile exists...
923 RGBToHSY(channelValues[0], channelValues[1], channelValues[2], h, s, y, R, G, B);
924 *y = pow(*y, 1/gamma);
925}
926
927#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:131
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