Krita Source Code Documentation
Loading...
Searching...
No Matches
KoColor.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2005 Boudewijn Rempt <boud@valdyas.org>
3 * SPDX-FileCopyrightText: 2007 Thomas Zander <zander@kde.org>
4 * SPDX-FileCopyrightText: 2007 Cyrille Berger <cberger@cberger.net>
5 *
6 * SPDX-License-Identifier: LGPL-2.1-or-later
7*/
8
9#include "KoColor.h"
10
11#include <QColor>
12
13#include <QDomDocument>
14#include <QRegExp>
15
16#include "DebugPigment.h"
17
19#include "KoColorProfile.h"
20#include "KoColorSpace.h"
22#include "KoChannelInfo.h"
23#include "kis_assert.h"
24#include "kis_dom_utils.h"
25
26#include <QGlobalStatic>
27
28#include <KoConfig.h>
29#ifdef HAVE_OPENEXR
30#include <half.h>
31#endif
32
33namespace {
34
35struct DefaultKoColorInitializer
36{
37 DefaultKoColorInitializer() {
38 const KoColorSpace *defaultColorSpace = KoColorSpaceRegistry::instance()->rgb16(0);
39 KIS_ASSERT(defaultColorSpace);
40
41 value = new KoColor(Qt::black, defaultColorSpace);
42#ifndef NODEBUG
43#ifndef QT_NO_DEBUG
44 // warn about rather expensive checks in assertPermanentColorspace().
45 qWarning() << "KoColor debug runtime checks are active.";
46#endif
47#endif
48
49 initializeMetatype();
50 }
51
52 void initializeMetatype() {
53 qRegisterMetaType<KoColor>();
54
59#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
60 QMetaType::registerEqualsComparator<KoColor>();
61#endif
62 }
63
64 ~DefaultKoColorInitializer() {
65 delete value;
66 }
67
68 KoColor *value = 0;
69};
70
71Q_GLOBAL_STATIC(DefaultKoColorInitializer, s_defaultKoColor)
72
73}
74
76 : m_colorSpace(s_defaultKoColor->value->m_colorSpace)
77 , m_size(s_defaultKoColor->value->m_size)
78{
79 memcpy(m_data, s_defaultKoColor->value->m_data, m_size);
80}
81
90
91KoColor::KoColor(const QColor & color, const KoColorSpace * colorSpace)
92{
93 Q_ASSERT(color.isValid());
94 Q_ASSERT(colorSpace);
96
98 Q_ASSERT(m_size <= MAX_PIXEL_SIZE);
99 memset(m_data, 0, m_size);
100
102}
103
104KoColor::KoColor(const quint8 * data, const KoColorSpace * colorSpace)
105{
106 Q_ASSERT(colorSpace);
107 Q_ASSERT(data);
110 Q_ASSERT(m_size <= MAX_PIXEL_SIZE);
111 memmove(m_data, data, m_size);
112}
113
114
125
126bool KoColor::operator==(const KoColor &other) const {
127 if (*colorSpace() != *other.colorSpace()) {
128 return false;
129 }
130 if (m_size != other.m_size) {
131 return false;
132 }
133 return memcmp(m_data, other.m_data, m_size) == 0;
134}
135
136void KoColor::convertTo(const KoColorSpace * cs, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags)
137{
138 //dbgPigment <<"Our colormodel:" << d->colorSpace->id().name()
139 // << ", new colormodel: " << cs->id().name() << "\n";
140
141 if (*m_colorSpace == *cs)
142 return;
143
144 quint8 data[MAX_PIXEL_SIZE];
145 const size_t size = cs->pixelSize();
146 Q_ASSERT(size <= MAX_PIXEL_SIZE);
147 memset(data, 0, size);
148
149 m_colorSpace->convertPixelsTo(m_data, data, cs, 1, renderingIntent, conversionFlags);
150
151 memcpy(m_data, data, size);
152 m_size = size;
154}
155
162
163KoColor KoColor::convertedTo(const KoColorSpace *cs, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const
164{
165 KoColor result(*this);
166 result.convertTo(cs, renderingIntent, conversionFlags);
167 return result;
168}
169
176
178{
179 const KoColorSpace *dstColorSpace =
180 KoColorSpaceRegistry::instance()->colorSpace(colorSpace()->colorModelId().id(), colorSpace()->colorDepthId().id(), profile);
181 if (!dstColorSpace) return;
182
184}
185
186void KoColor::setColor(const quint8 * data, const KoColorSpace * colorSpace)
187{
188 Q_ASSERT(colorSpace);
189
191 Q_ASSERT(m_size <= MAX_PIXEL_SIZE);
192
193 memcpy(m_data, data, m_size);
195}
196
197// To save the user the trouble of doing color->colorSpace()->toQColor(color->data(), &c, &a, profile
198void KoColor::toQColor(QColor *c) const
199{
200 Q_ASSERT(c);
201 if (m_colorSpace) {
203 }
204}
205
206QColor KoColor::toQColor() const
207{
208 QColor c;
209 toQColor(&c);
210 return c;
211}
212
213void KoColor::fromQColor(const QColor& c)
214{
215 if (m_colorSpace) {
217 }
218}
219
221{
223
226
228 m_colorSpace->normalisedChannelsValue(value.data(), channels2);
229
230 for (int i = 0; i < channels1.size(); i++) {
231 channels1[i] -= channels2[i];
232 }
233
235}
236
238{
239 KoColor result(*this);
240 result.subtract(value);
241 return result;
242}
243
245{
247
250
252 m_colorSpace->normalisedChannelsValue(value.data(), channels2);
253
254 for (int i = 0; i < channels1.size(); i++) {
255 channels1[i] += channels2[i];
256 }
257
259}
260
262{
263 KoColor result(*this);
264 result.add(value);
265 return result;
266}
267
268#ifndef NDEBUG
269void KoColor::dump() const
270{
271 dbgPigment <<"KoColor (" << this <<")," << m_colorSpace->id() <<"";
273
274 QList<KoChannelInfo *>::const_iterator begin = channels.constBegin();
275 QList<KoChannelInfo *>::const_iterator end = channels.constEnd();
276
277 for (QList<KoChannelInfo *>::const_iterator it = begin; it != end; ++it) {
278 KoChannelInfo * ch = (*it);
279 // XXX: setNum always takes a byte.
280 if (ch->size() == sizeof(quint8)) {
281 // Byte
282 dbgPigment <<"Channel (byte):" << ch->name() <<":" << QString().setNum(m_data[ch->pos()]) <<"";
283 } else if (ch->size() == sizeof(quint16)) {
284 // Short (may also by an nvidia half)
285 dbgPigment <<"Channel (short):" << ch->name() <<":" << QString().setNum(*((const quint16 *)(m_data+ch->pos()))) <<"";
286 } else if (ch->size() == sizeof(quint32)) {
287 // Integer (may also be float... Find out how to distinguish these!)
288 dbgPigment <<"Channel (int):" << ch->name() <<":" << QString().setNum(*((const quint32 *)(m_data+ch->pos()))) <<"";
289 }
290 }
291}
292#endif
293
298
300{
301 return m_colorSpace->profile();
302}
303
304void KoColor::toXML(QDomDocument& doc, QDomElement& colorElt) const
305{
306 m_colorSpace->colorToXML(m_data, doc, colorElt);
307
308 for (QString key : m_metadata.keys()) {
309
310 QDomElement e = doc.createElement("metadata");
311 e.setAttribute("name", QString(key.toLatin1()));
312 QVariant v = m_metadata.value(key);
313 e.setAttribute("type", v.typeName());
314
315 QString attrName = "value";
316 if(v.type() == QVariant::String ) {
317 e.setAttribute(attrName, v.toString());
318 e.setAttribute("type", "string");
319 } else if(v.type() == QVariant::Int ) {
320 e.setAttribute(attrName, v.toInt());
321 } else if(v.type() == QVariant::Double ) {
322 e.setAttribute(attrName, v.toDouble());
323 } else if(v.type() == QVariant::Bool ) {
324 e.setAttribute(attrName, v.toBool());
325 } else {
326 qWarning() << "no KoColor serialization for QVariant type:" << v.type();
327 }
328 colorElt.appendChild(e);
329 }
330
331}
332
333void KoColor::setOpacity(quint8 alpha)
334{
335 m_colorSpace->setOpacity(m_data, alpha, 1);
336}
337void KoColor::setOpacity(qreal alpha)
338{
339 m_colorSpace->setOpacity(m_data, alpha, 1);
340}
341quint8 KoColor::opacityU8() const
342{
344}
345qreal KoColor::opacityF() const
346{
348}
349
350KoColor KoColor::fromXML(const QDomElement& elt, const QString& channelDepthId)
351{
352 bool ok;
353 return fromXML(elt, channelDepthId, &ok);
354}
355
356KoColor KoColor::fromXML(const QDomElement &elt, const QString &channelDepthId, bool *ok)
357{
358 *ok = true;
359
360 QString modelId;
361 QString modelName = elt.tagName();
362 if (modelName == "CMYK") {
363 modelId = CMYKAColorModelID.id();
364 } else if (modelName == "RGB") {
365 modelId = RGBAColorModelID.id();
366 } else if (modelName == "sRGB") {
367 modelId = RGBAColorModelID.id();
368 } else if (modelName == "Lab") {
369 modelId = LABAColorModelID.id();
370 } else if (modelName == "XYZ") {
371 modelId = XYZAColorModelID.id();
372 } else if (modelName == "Gray") {
373 modelId = GrayAColorModelID.id();
374 } else if (modelName == "YCbCr") {
375 modelId = YCbCrAColorModelID.id();
376 }
377
379
380 QString profileName;
381 if (modelName == "sRGB") {
382 const KoColorProfile *profile = colorSpaceRegistry->p709SRGBProfile();
383 if (profile) {
384 profileName = profile->name();
385 }
386 } else {
387 profileName = elt.attribute("space", "");
388 if (!colorSpaceRegistry->profileByName(profileName)) {
389 profileName.clear();
390 }
391 }
392
393 const KoColorSpace* cs = colorSpaceRegistry->colorSpace(modelId, channelDepthId, profileName);
394 if (!cs) {
395 QList<KoID> list = colorSpaceRegistry->colorDepthList(modelId, KoColorSpaceRegistry::AllColorSpaces);
396 if (!list.empty()) {
397 cs = colorSpaceRegistry->colorSpace(modelId, list[0].id(), profileName);
398 }
399 }
400
401 if (!cs) {
402 *ok = false;
403 return KoColor();
404 }
405
406 KoColor c(cs);
407 // TODO: Provide a way for colorFromXML() to notify the caller if parsing failed.
408 // Currently it returns default values on failure.
409 cs->colorFromXML(c.data(), elt);
410
411 QDomElement e = elt.nextSiblingElement("metadata");
412 for (; !e.isNull(); e = e.nextSiblingElement("metadata")) {
413 const QString name = e.attribute("name");
414 const QString type = e.attribute("type");
415 const QString value = e.attribute("value");
416
417 QVariant v;
418 if (type == "string") {
420 } else if (type == "int") {
422 } else if (type == "double") {
424 } else if (type == "bool") {
426 } else {
427 continue;
428 }
429
430 c.addMetadata(name , v);
431 }
432
433 return c;
434}
435
436QString KoColor::toXML() const
437{
438 QDomDocument cdataDoc = QDomDocument("color");
439 QDomElement cdataRoot = cdataDoc.createElement("color");
440 cdataDoc.appendChild(cdataRoot);
441 cdataRoot.setAttribute("channeldepth", colorSpace()->colorDepthId().id());
442 toXML(cdataDoc, cdataRoot);
443 return cdataDoc.toString();
444}
445
446KoColor KoColor::fromXML(const QString &xml)
447{
448 KoColor c;
449 QDomDocument doc;
450 if (!doc.setContent(xml)) {
451 return c;
452 }
453
454 QDomElement root = doc.documentElement();
455 QDomElement child = root.firstChildElement();
456 QString channelDepthID = root.attribute("channeldepth", Integer16BitsColorDepthID.id());
457
458 bool ok;
459 if (child.hasAttribute("space") || child.tagName().toLower() == "srgb") {
460 c = KoColor::fromXML(child, channelDepthID, &ok);
461 } else if (root.hasAttribute("space") || root.tagName().toLower() == "srgb"){
462 c = KoColor::fromXML(root, channelDepthID, &ok);
463 } else {
464 qWarning() << "Cannot parse color from xml" << xml;
465 }
466
467 return c;
468}
469
470QString KoColor::toSVG11(QHash<QString, const KoColorProfile *> *profileList) const
471{
472 QStringList colorDefinitions;
473 colorDefinitions.append(toQColor().name());
474
475 QVector<float> channelValues(colorSpace()->channelCount());
476 channelValues.fill(0.0);
477 colorSpace()->normalisedChannelsValue(data(), channelValues);
478
479 bool sRGB = false;
480 if (colorSpace() && colorSpace()->profile()
481 && colorSpace()->profile()->getColorPrimaries() == ColorPrimaries::PRIMARIES_ITU_R_BT_709_5
482 && colorSpace()->profile()->getTransferCharacteristics() != TransferCharacteristics::TRC_LINEAR) {
483 sRGB = true;
484 }
485
486 // We don't write a icc-color definition for XYZ and 8bit sRGB.
487 if (!(sRGB && colorSpace()->colorDepthId() == Integer8BitsColorDepthID) &&
488 colorSpace()->colorModelId() != XYZAColorModelID) {
489 QStringList iccColor;
490 QString csName = colorSpace()->profile()->name();
491 // remove forbidden characters
492 // https://www.w3.org/TR/SVG11/types.html#DataTypeName
493#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
494 csName.remove(QRegExp("[\\(\\),\\s]"));
495#else
496 QRegExp reg("[\\(\\),\\s]");
497 reg.removeIn(csName);
498#endif
499 //reuse existing name if possible. We're looking for the color profile, because svg doesn't care about depth.
500 csName = profileList->key(colorSpace()->profile(), csName);
501
502 if (sRGB) {
503 csName = "sRGB";
504 }
505
506 iccColor.append(csName);
507
508 if (colorSpace()->colorModelId() == LABAColorModelID) {
509 QDomDocument doc;
510 QDomElement el = doc.createElement("color");
511 toXML(doc, el);
512 QDomElement lab = el.firstChildElement();
513 iccColor.append(lab.attribute("L", "0.0"));
514 iccColor.append(lab.attribute("a", "0.0"));
515 iccColor.append(lab.attribute("b", "0.0"));
516 }
517 else {
518 for (int i = 0; i < channelValues.size(); i++) {
519 int location = KoChannelInfo::displayPositionToChannelIndex(i, colorSpace()->channels());
520 if (i != int(colorSpace()->alphaPos())) {
521 iccColor.append(QString::number(channelValues.at(location), 'g', 10));
522 }
523 }
524 }
525 colorDefinitions.append(QString("icc-color(%1)").arg(iccColor.join(", ")));
526 if (!profileList->contains(csName) && !sRGB) {
527 profileList->insert(csName, colorSpace()->profile());
528 }
529 }
530
531 return colorDefinitions.join(" ");
532}
533
534KoColor KoColor::fromSVG11(const QString value, QHash<QString, const KoColorProfile *> profileList, KoColor current)
535{
536 KoColor parsed(KoColorSpaceRegistry::instance()->rgb16(KoColorSpaceRegistry::instance()->p709SRGBProfile()));
537 parsed.setOpacity(1.0);
538
539 if (value.toLower() == "none") {
540 return parsed;
541 }
542
543 // add the sRGB default name.
544 profileList.insert("sRGB", KoColorSpaceRegistry::instance()->p709SRGBProfile());
545 // first, try to split at \w\d\‍) space.
546 // we want to split up a string like... colorcolor none rgb(0.8, 0.1, 200%) #ff0000 icc-color(blah, 0.0, 1.0, 1.0, 0.0);
547 QRegExp splitDefinitions("(#?\\w+|[\\w\\-]*\\(.+\\))\\s");
548 int pos = 0;
549 int pos2 = 0;
550 QStringList colorDefinitions;
551 QString valueAdjust = value.split(";").first();
552 valueAdjust.append(" ");
553 while ((pos2 = splitDefinitions.indexIn(valueAdjust, pos)) != -1) {
554 colorDefinitions.append(splitDefinitions.cap(1).trimmed());
555 pos = pos2 + splitDefinitions.matchedLength();
556 }
557 if (pos < value.length()) {
558 QString remainder = value.right(value.length()-pos);
559 remainder.remove(";");
560 colorDefinitions.append(remainder);
561 }
562 dbgPigment << "Color definitions found during svg11parsing" << colorDefinitions;
563
564 for (QString def : colorDefinitions) {
565 if (def.toLower() == "currentcolor") {
566 parsed = current;
567 } else if (QColor::isValidColor(def)) {
568 parsed.fromQColor(QColor(def));
569 } else if (def.toLower().startsWith("rgb")) {
570 QString parse = def.trimmed();
571 QStringList colors = parse.split(',');
572 QString r = colors[0].right((colors[0].length() - 4)).trimmed();
573 QString g = colors[1].trimmed();
574 QString b = colors[2].left((colors[2].length() - 1)).trimmed();
575
576 if (r.contains('%')) {
577 r = r.left(r.length() - 1);
578 r = QString::number(int((double(255 * r.toDouble()) / 100.0)));
579 }
580
581 if (g.contains('%')) {
582 g = g.left(g.length() - 1);
583 g = QString::number(int((double(255 * g.toDouble()) / 100.0)));
584 }
585
586 if (b.contains('%')) {
587 b = b.left(b.length() - 1);
588 b = QString::number(int((double(255 * b.toDouble()) / 100.0)));
589 }
590 parsed.fromQColor(QColor(r.toInt(), g.toInt(), b.toInt()));
591
592 } else if (def.toLower().startsWith("icc-color")) {
593 QStringList values = def.split(",");
594 QString iccprofilename = values.first().split("(").last();
595 values.removeFirst();
596
597 // svg11 docs say that searching the name should be case-insensitive.
598 QStringList entry = QStringList(profileList.keys()).filter(iccprofilename, Qt::CaseInsensitive);
599 if (entry.empty()) {
600 continue;
601 }
602 const KoColorProfile *profile = profileList.value(entry.first());
603 if (!profile) {
604 continue;
605 }
606 QString colormodel = profile->colorModelID();
607 QString depth = "F32";
608 if (colormodel == LABAColorModelID.id()) {
609 // let our xml handling deal with lab
610 QVector<float> labV(3);
611 for (int i = 0; i < values.size(); i++) {
612 if (i<labV.size()) {
613 QString entry = values.at(i);
614 entry = entry.split(")").first();
615 labV[i] = entry.toDouble();
616 }
617 }
618 QString lab = QString("<Lab space='%1' L='%2' a='%3' b='%4' />")
619 .arg(profile->name())
620 .arg(labV[0])
621 .arg(labV[1])
622 .arg(labV[2]);
623 QDomDocument doc;
624 doc.setContent(lab);
625 parsed = KoColor::fromXML(doc.documentElement(), "U16");
626 continue;
627 } else if (colormodel == CMYKAColorModelID.id()) {
628 depth = "U16";
629 } else if (colormodel == XYZAColorModelID.id()) {
630 // Inkscape decided to have X and Z go from 0 to 2, and I can't for the live of me figure out why.
631 // So we're just not parsing XYZ.
632 continue;
633 }
634 const KoColorSpace * cs = KoColorSpaceRegistry::instance()->colorSpace(colormodel, depth, profile);
635 if (!cs) {
636 continue;
637 }
638 parsed = KoColor(cs);
639 QVector<float> channelValues(parsed.colorSpace()->channelCount());
640 channelValues.fill(0.0);
641 channelValues[parsed.colorSpace()->alphaPos()] = 1.0;
642 for (int channel = 0; channel < values.size(); channel++) {
643 int location = KoChannelInfo::displayPositionToChannelIndex(channel, parsed.colorSpace()->channels());
644 QString entry = values.at(channel);
645 entry = entry.split(")").first();
646 channelValues[location] = entry.toFloat();
647 }
648 parsed.colorSpace()->fromNormalisedChannelsValue(parsed.data(), channelValues);
649 }
650 }
651
652 return parsed;
653}
654
655QString KoColor::toQString(const KoColor &color)
656{
657 QStringList ls;
658 Q_FOREACH (KoChannelInfo *channel, KoChannelInfo::displayOrderSorted(color.colorSpace()->channels())) {
660 ls << channel->name();
661 ls << color.colorSpace()->channelValueText(color.data(), realIndex);
662 }
663 return ls.join(" ");
664}
665
666void KoColor::addMetadata(QString key, QVariant value)
667{
668 m_metadata.insert(key, value);
669}
670
671QMap<QString, QVariant> KoColor::metadata() const
672{
673 return m_metadata;
674}
675
677{
678 m_metadata.clear();
679}
680
682{
683 KoColor result;
684
686 result.m_size = cs->pixelSize();
687 cs->transparentColor(result.m_data, 1);
688
689 return result;
690}
691
692QDebug operator<<(QDebug dbg, const KoColor &color)
693{
694 dbg.nospace() << "KoColor (" << color.colorSpace()->id();
695
696 const QList<KoChannelInfo*> channels = color.colorSpace()->channels();
697 for (auto it = channels.constBegin(); it != channels.constEnd(); ++it) {
698
699 KoChannelInfo *ch = (*it);
700
701 dbg.nospace() << ", " << ch->name() << ":";
702
703 switch (ch->channelValueType()) {
705 const quint8 *ptr = reinterpret_cast<const quint8*>(color.data() + ch->pos());
706 dbg.nospace() << *ptr;
707 break;
708 } case KoChannelInfo::UINT16: {
709 const quint16 *ptr = reinterpret_cast<const quint16*>(color.data() + ch->pos());
710 dbg.nospace() << *ptr;
711 break;
712 } case KoChannelInfo::UINT32: {
713 const quint32 *ptr = reinterpret_cast<const quint32*>(color.data() + ch->pos());
714 dbg.nospace() << *ptr;
715 break;
716 } case KoChannelInfo::FLOAT16: {
717
718#ifdef HAVE_OPENEXR
719 const half *ptr = reinterpret_cast<const half*>(color.data() + ch->pos());
720 dbg.nospace() << *ptr;
721#else
722 const quint16 *ptr = reinterpret_cast<const quint16*>(color.data() + ch->pos());
723 dbg.nospace() << "UNSUPPORTED_F16(" << *ptr << ")";
724#endif
725 break;
726 } case KoChannelInfo::FLOAT32: {
727 const float *ptr = reinterpret_cast<const float*>(color.data() + ch->pos());
728 dbg.nospace() << *ptr;
729 break;
730 } case KoChannelInfo::FLOAT64: {
731 const double *ptr = reinterpret_cast<const double*>(color.data() + ch->pos());
732 dbg.nospace() << *ptr;
733 break;
734 } case KoChannelInfo::INT8: {
735 const qint8 *ptr = reinterpret_cast<const qint8*>(color.data() + ch->pos());
736 dbg.nospace() << *ptr;
737 break;
738 } case KoChannelInfo::INT16: {
739 const qint16 *ptr = reinterpret_cast<const qint16*>(color.data() + ch->pos());
740 dbg.nospace() << *ptr;
741 break;
742 } case KoChannelInfo::OTHER: {
743 const quint8 *ptr = reinterpret_cast<const quint8*>(color.data() + ch->pos());
744 dbg.nospace() << "undef(" << *ptr << ")";
745 break;
746 }
747 }
748 }
749 dbg.nospace() << ")";
750 return dbg.space();
751}
#define dbgPigment
qreal length(const QPointF &vec)
Definition Ellipse.cc:82
float value(const T *src, size_t ch)
qreal v
QList< QString > QStringList
Q_GLOBAL_STATIC(KisStoragePluginRegistry, s_instance)
const KoID YCbCrAColorModelID("YCbCrA", ki18n("YCbCr/Alpha"))
const KoID GrayAColorModelID("GRAYA", ki18n("Grayscale/Alpha"))
const KoID XYZAColorModelID("XYZA", ki18n("XYZ/Alpha"))
const KoID Integer8BitsColorDepthID("U8", ki18n("8-bit integer/channel"))
const KoID Integer16BitsColorDepthID("U16", ki18n("16-bit integer/channel"))
const KoID CMYKAColorModelID("CMYKA", ki18n("CMYK/Alpha"))
const KoID LABAColorModelID("LABA", ki18n("L*a*b*/Alpha"))
const KoID RGBAColorModelID("RGBA", ki18n("RGB/Alpha"))
@ PRIMARIES_ITU_R_BT_709_5
const int MAX_PIXEL_SIZE
QDebug operator<<(QDebug dbg, const KoColor &color)
Definition KoColor.cpp:692
qint32 size() const
qint32 pos() const
@ UINT8
use this for an unsigned integer 8bits channel
@ UINT16
use this for an integer 16bits channel
@ OTHER
Use this if the channel is neither an integer or a float.
@ INT16
use this for an integer 16bits channel
@ INT8
use this for an integer 8bits channel
@ FLOAT32
use this for a float 32bits channel
@ FLOAT16
use this for a float 16bits channel
@ UINT32
use this for an unsigned integer 21bits channel
@ FLOAT64
use this for a float 64bits channel
static int displayPositionToChannelIndex(int displayPosition, const QList< KoChannelInfo * > &channels)
enumChannelValueType channelValueType() const
QString name() const
static QList< KoChannelInfo * > displayOrderSorted(const QList< KoChannelInfo * > &channels)
qint32 displayPosition() const
virtual quint32 alphaPos() const =0
virtual quint32 pixelSize() const =0
virtual void toQColor(const quint8 *src, QColor *c) const =0
virtual QString channelValueText(const quint8 *pixel, quint32 channelIndex) const =0
virtual qreal opacityF(const quint8 *pixel) const =0
virtual void setOpacity(quint8 *pixels, quint8 alpha, qint32 nPixels) const =0
QList< KoChannelInfo * > channels
virtual void fromQColor(const QColor &color, quint8 *dst) const =0
virtual quint32 channelCount() const =0
virtual void normalisedChannelsValue(const quint8 *pixel, QVector< float > &channels) const =0
virtual quint8 opacityU8(const quint8 *pixel) const =0
virtual void fromNormalisedChannelsValue(quint8 *pixel, const QVector< float > &values) const =0
virtual bool convertPixelsTo(const quint8 *src, quint8 *dst, const KoColorSpace *dstColorSpace, quint32 numPixels, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const
virtual void colorToXML(const quint8 *pixel, QDomDocument &doc, QDomElement &colorElt) const =0
virtual void colorFromXML(quint8 *pixel, const QDomElement &elt) const =0
virtual void transparentColor(quint8 *dst, quint32 nPixels) const
virtual const KoColorProfile * profile() const =0
void convertTo(const KoColorSpace *cs, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags)
Definition KoColor.cpp:136
void add(const KoColor &value)
Definition KoColor.cpp:244
void subtract(const KoColor &value)
Definition KoColor.cpp:220
static KoColor fromSVG11(const QString value, QHash< QString, const KoColorProfile * > profileList, KoColor current=KoColor())
fromSVG11 Parses a color attribute value and returns a KoColor. SVG defines the colorprofiles elsewhe...
Definition KoColor.cpp:534
qreal opacityF() const
Definition KoColor.cpp:345
static KoColor fromXML(const QDomElement &elt, const QString &channelDepthId)
Definition KoColor.cpp:350
KoColor added(const KoColor &value) const
Definition KoColor.cpp:261
static QString toQString(const KoColor &color)
toQString create a user-visible string of the channel names and the channel values
Definition KoColor.cpp:655
void toXML(QDomDocument &doc, QDomElement &colorElt) const
Definition KoColor.cpp:304
const KoColorProfile * profile() const
return the current profile
Definition KoColor.cpp:299
QMap< QString, QVariant > metadata() const
Definition KoColor.cpp:671
void addMetadata(QString key, QVariant value)
Definition KoColor.cpp:666
QMap< QString, QVariant > m_metadata
Definition KoColor.h:323
void clearMetadata()
clearMetadata clear th metadata map inside the KoColor.
Definition KoColor.cpp:676
KoColor subtracted(const KoColor &value) const
Definition KoColor.cpp:237
void setColor(const quint8 *data, const KoColorSpace *colorSpace=0)
Definition KoColor.cpp:186
void setOpacity(quint8 alpha)
Definition KoColor.cpp:333
QString toXML() const
toXML creates a string with XML that represents the current color. The XML is extended with a "channe...
Definition KoColor.cpp:436
KoColor convertedTo(const KoColorSpace *cs, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const
Definition KoColor.cpp:163
void fromQColor(const QColor &c)
Convenient function for converting from a QColor.
Definition KoColor.cpp:213
static KoColor createTransparent(const KoColorSpace *cs)
Definition KoColor.cpp:681
quint8 m_size
Definition KoColor.h:322
quint8 * data()
Definition KoColor.h:144
bool operator==(const KoColor &other) const
Definition KoColor.cpp:126
KoColor()
Create an empty KoColor. It will be valid, but also black and transparent.
Definition KoColor.cpp:75
void dump() const
use qDebug calls to print internal info
Definition KoColor.cpp:269
quint8 opacityU8() const
Definition KoColor.cpp:341
const KoColorSpace * m_colorSpace
Definition KoColor.h:320
QColor toQColor() const
a convenience method for the above.
Definition KoColor.cpp:206
const KoColorSpace * colorSpace() const
return the current colorSpace
Definition KoColor.h:82
quint8 m_data[MAX_PIXEL_SIZE]
Definition KoColor.h:321
void fromKoColor(const KoColor &src)
Definition KoColor.cpp:294
QString toSVG11(QHash< QString, const KoColorProfile * > *profileList) const
toSVG11
Definition KoColor.cpp:470
void setProfile(const KoColorProfile *profile)
assign new profile without converting pixel data
Definition KoColor.cpp:177
QString id() const
Definition KoID.cpp:63
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
#define KIS_ASSERT(cond)
Definition kis_assert.h:33
double toDouble(const QString &str, bool *ok=nullptr)
int toInt(const QString &str, bool *ok=nullptr)
QString toString(const QString &value)
virtual QString colorModelID() const
const KoColorProfile * profileByName(const QString &name) const
QList< KoID > colorDepthList(const KoID &colorModelId, ColorSpaceListVisibility option) const
const KoColorSpace * permanentColorspace(const KoColorSpace *_colorSpace)
const KoColorSpace * colorSpace(const QString &colorModelId, const QString &colorDepthId, const KoColorProfile *profile)
static KoColorSpaceRegistry * instance()
const KoColorProfile * p709SRGBProfile() const
const KoColorSpace * rgb16(const QString &profileName=QString())
@ AllColorSpaces
All color space even those not visible to the user.