13#include <QDomDocument>
26#include <QGlobalStatic>
35struct DefaultKoColorInitializer
37 DefaultKoColorInitializer() {
45 qWarning() <<
"KoColor debug runtime checks are active.";
52 void initializeMetatype() {
53 qRegisterMetaType<KoColor>();
59#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
60 QMetaType::registerEqualsComparator<KoColor>();
64 ~DefaultKoColorInitializer() {
76 : m_colorSpace(s_defaultKoColor->
value->m_colorSpace)
77 , m_size(s_defaultKoColor->
value->m_size)
93 Q_ASSERT(color.isValid());
147 memset(
data, 0, size);
166 result.
convertTo(cs, renderingIntent, conversionFlags);
181 if (!dstColorSpace)
return;
230 for (
int i = 0; i < channels1.size(); i++) {
231 channels1[i] -= channels2[i];
254 for (
int i = 0; i < channels1.size(); i++) {
255 channels1[i] += channels2[i];
280 if (ch->
size() ==
sizeof(quint8)) {
283 }
else if (ch->
size() ==
sizeof(quint16)) {
285 dbgPigment <<
"Channel (short):" << ch->
name() <<
":" << QString().setNum(*((
const quint16 *)(
m_data+ch->
pos()))) <<
"";
286 }
else if (ch->
size() ==
sizeof(quint32)) {
288 dbgPigment <<
"Channel (int):" << ch->
name() <<
":" << QString().setNum(*((
const quint32 *)(
m_data+ch->
pos()))) <<
"";
310 QDomElement e = doc.createElement(
"metadata");
311 e.setAttribute(
"name", QString(key.toLatin1()));
313 e.setAttribute(
"type",
v.typeName());
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());
326 qWarning() <<
"no KoColor serialization for QVariant type:" <<
v.type();
328 colorElt.appendChild(e);
353 return fromXML(elt, channelDepthId, &ok);
361 QString modelName = elt.tagName();
362 if (modelName ==
"CMYK") {
364 }
else if (modelName ==
"RGB") {
366 }
else if (modelName ==
"sRGB") {
368 }
else if (modelName ==
"Lab") {
370 }
else if (modelName ==
"XYZ") {
372 }
else if (modelName ==
"Gray") {
374 }
else if (modelName ==
"YCbCr") {
381 if (modelName ==
"sRGB") {
387 profileName = elt.attribute(
"space",
"");
397 cs = colorSpaceRegistry->
colorSpace(modelId, list[0].
id(), profileName);
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");
418 if (type ==
"string") {
420 }
else if (type ==
"int") {
422 }
else if (type ==
"double") {
424 }
else if (type ==
"bool") {
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();
450 if (!doc.setContent(xml)) {
454 QDomElement root = doc.documentElement();
455 QDomElement child = root.firstChildElement();
459 if (child.hasAttribute(
"space") || child.tagName().toLower() ==
"srgb") {
461 }
else if (root.hasAttribute(
"space") || root.tagName().toLower() ==
"srgb"){
464 qWarning() <<
"Cannot parse color from xml" << xml;
473 colorDefinitions.append(
toQColor().name());
476 channelValues.fill(0.0);
493#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
494 csName.remove(QRegExp(
"[\\(\\),\\s]"));
496 QRegExp reg(
"[\\(\\),\\s]");
497 reg.removeIn(csName);
506 iccColor.append(csName);
510 QDomElement el = doc.createElement(
"color");
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"));
518 for (
int i = 0; i < channelValues.size(); i++) {
521 iccColor.append(QString::number(channelValues.at(location),
'g', 10));
525 colorDefinitions.append(QString(
"icc-color(%1)").arg(iccColor.join(
", ")));
526 if (!profileList->contains(csName) && !sRGB) {
531 return colorDefinitions.join(
" ");
539 if (
value.toLower() ==
"none") {
547 QRegExp splitDefinitions(
"(#?\\w+|[\\w\\-]*\\(.+\\))\\s");
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();
557 if (pos <
value.length()) {
558 QString remainder =
value.right(
value.length()-pos);
559 remainder.remove(
";");
560 colorDefinitions.append(remainder);
562 dbgPigment <<
"Color definitions found during svg11parsing" << colorDefinitions;
564 for (QString def : colorDefinitions) {
565 if (def.toLower() ==
"currentcolor") {
567 }
else if (QColor::isValidColor(def)) {
569 }
else if (def.toLower().startsWith(
"rgb")) {
570 QString parse = def.trimmed();
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();
576 if (r.contains(
'%')) {
577 r = r.left(r.length() - 1);
578 r = QString::number(
int((
double(255 * r.toDouble()) / 100.0)));
581 if (g.contains(
'%')) {
582 g = g.left(g.length() - 1);
583 g = QString::number(
int((
double(255 * g.toDouble()) / 100.0)));
586 if (b.contains(
'%')) {
587 b = b.left(b.length() - 1);
588 b = QString::number(
int((
double(255 * b.toDouble()) / 100.0)));
590 parsed.
fromQColor(QColor(r.toInt(), g.toInt(), b.toInt()));
592 }
else if (def.toLower().startsWith(
"icc-color")) {
594 QString iccprofilename = values.first().split(
"(").last();
595 values.removeFirst();
607 QString depth =
"F32";
611 for (
int i = 0; i < values.size(); i++) {
613 QString entry = values.at(i);
614 entry = entry.split(
")").first();
615 labV[i] = entry.toDouble();
618 QString lab = QString(
"<Lab space='%1' L='%2' a='%3' b='%4' />")
640 channelValues.fill(0.0);
642 for (
int channel = 0; channel < values.size(); channel++) {
644 QString entry = values.at(channel);
645 entry = entry.split(
")").first();
646 channelValues[location] = entry.toFloat();
660 ls << channel->
name();
694 dbg.nospace() <<
"KoColor (" << color.
colorSpace()->
id();
697 for (
auto it = channels.constBegin(); it != channels.constEnd(); ++it) {
701 dbg.nospace() <<
", " << ch->
name() <<
":";
705 const quint8 *ptr =
reinterpret_cast<const quint8*
>(color.
data() + ch->
pos());
706 dbg.nospace() << *ptr;
709 const quint16 *ptr =
reinterpret_cast<const quint16*
>(color.
data() + ch->
pos());
710 dbg.nospace() << *ptr;
713 const quint32 *ptr =
reinterpret_cast<const quint32*
>(color.
data() + ch->
pos());
714 dbg.nospace() << *ptr;
719 const half *ptr =
reinterpret_cast<const half*
>(color.
data() + ch->
pos());
720 dbg.nospace() << *ptr;
722 const quint16 *ptr =
reinterpret_cast<const quint16*
>(color.
data() + ch->
pos());
723 dbg.nospace() <<
"UNSUPPORTED_F16(" << *ptr <<
")";
727 const float *ptr =
reinterpret_cast<const float*
>(color.
data() + ch->
pos());
728 dbg.nospace() << *ptr;
731 const double *ptr =
reinterpret_cast<const double*
>(color.
data() + ch->
pos());
732 dbg.nospace() << *ptr;
735 const qint8 *ptr =
reinterpret_cast<const qint8*
>(color.
data() + ch->
pos());
736 dbg.nospace() << *ptr;
739 const qint16 *ptr =
reinterpret_cast<const qint16*
>(color.
data() + ch->
pos());
740 dbg.nospace() << *ptr;
743 const quint8 *ptr =
reinterpret_cast<const quint8*
>(color.
data() + ch->
pos());
744 dbg.nospace() <<
"undef(" << *ptr <<
")";
749 dbg.nospace() <<
")";
qreal length(const QPointF &vec)
float value(const T *src, size_t ch)
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
QDebug operator<<(QDebug dbg, const KoColor &color)
@ 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
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)
void add(const KoColor &value)
void subtract(const KoColor &value)
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...
static KoColor fromXML(const QDomElement &elt, const QString &channelDepthId)
KoColor added(const KoColor &value) const
static QString toQString(const KoColor &color)
toQString create a user-visible string of the channel names and the channel values
void toXML(QDomDocument &doc, QDomElement &colorElt) const
const KoColorProfile * profile() const
return the current profile
QMap< QString, QVariant > metadata() const
void addMetadata(QString key, QVariant value)
QMap< QString, QVariant > m_metadata
void clearMetadata()
clearMetadata clear th metadata map inside the KoColor.
KoColor subtracted(const KoColor &value) const
void setColor(const quint8 *data, const KoColorSpace *colorSpace=0)
void setOpacity(quint8 alpha)
QString toXML() const
toXML creates a string with XML that represents the current color. The XML is extended with a "channe...
KoColor convertedTo(const KoColorSpace *cs, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const
void fromQColor(const QColor &c)
Convenient function for converting from a QColor.
static KoColor createTransparent(const KoColorSpace *cs)
bool operator==(const KoColor &other) const
KoColor()
Create an empty KoColor. It will be valid, but also black and transparent.
void dump() const
use qDebug calls to print internal info
const KoColorSpace * m_colorSpace
QColor toQColor() const
a convenience method for the above.
const KoColorSpace * colorSpace() const
return the current colorSpace
quint8 m_data[MAX_PIXEL_SIZE]
void fromKoColor(const KoColor &src)
QString toSVG11(QHash< QString, const KoColorProfile * > *profileList) const
toSVG11
void setProfile(const KoColorProfile *profile)
assign new profile without converting pixel data
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
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.