Warning, file /office/calligra/libs/pigment/KoColor.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002  *  Copyright (c) 2005 Boudewijn Rempt <boud@valdyas.org>
0003  *  Copyright (C) 2007 Thomas Zander <zander@kde.org>
0004  *  Copyright (C) 2007 Cyrille Berger <cberger@cberger.net>
0005  *
0006  * This library is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU Lesser General Public
0008  * License as published by the Free Software Foundation; either
0009  * version 2.1 of the License, or (at your option) any later version.
0010  *
0011  * This library is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014  * Lesser General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU Lesser General Public License
0017  * along with this library; see the file COPYING.LIB.  If not, write to
0018  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019  * Boston, MA 02110-1301, USA.
0020 */
0021 
0022 #include "KoColor.h"
0023 
0024 #include <QColor>
0025 
0026 #include <QDomDocument>
0027 
0028 #include "DebugPigment.h"
0029 
0030 #include "KoColorModelStandardIds.h"
0031 #include "KoColorProfile.h"
0032 #include "KoColorSpace.h"
0033 #include "KoColorSpaceRegistry.h"
0034 #include "KoChannelInfo.h"
0035 
0036 
0037 class Q_DECL_HIDDEN KoColor::Private
0038 {
0039 public:
0040     Private() : data(0), colorSpace(0) {}
0041 
0042     ~Private() {
0043         delete [] data;
0044     }
0045 
0046     quint8 * data;
0047     const KoColorSpace * colorSpace;
0048 };
0049 
0050 KoColor::KoColor()
0051         : d(new Private())
0052 {
0053     d->colorSpace = KoColorSpaceRegistry::instance()->rgb16(0);
0054     d->data = new quint8[d->colorSpace->pixelSize()];
0055     d->colorSpace->fromQColor(Qt::black, d->data);
0056     d->colorSpace->setOpacity(d->data, OPACITY_OPAQUE_U8, 1);
0057 }
0058 
0059 KoColor::KoColor(const KoColorSpace * colorSpace)
0060         : d(new Private())
0061 {
0062     Q_ASSERT(colorSpace);
0063     d->colorSpace = KoColorSpaceRegistry::instance()->permanentColorspace(colorSpace);
0064     d->data = new quint8[d->colorSpace->pixelSize()];
0065     memset(d->data, 0, d->colorSpace->pixelSize());
0066 }
0067 
0068 KoColor::~KoColor()
0069 {
0070     delete d;
0071 }
0072 
0073 KoColor::KoColor(const QColor & color, const KoColorSpace * colorSpace)
0074         : d(new Private())
0075 {
0076     Q_ASSERT(color.isValid());
0077     Q_ASSERT(colorSpace);
0078     d->colorSpace = KoColorSpaceRegistry::instance()->permanentColorspace(colorSpace);
0079 
0080     d->data = new quint8[colorSpace->pixelSize()];
0081     memset(d->data, 0, d->colorSpace->pixelSize());
0082 
0083     d->colorSpace->fromQColor(color, d->data);
0084 }
0085 
0086 KoColor::KoColor(const quint8 * data, const KoColorSpace * colorSpace)
0087         : d(new Private())
0088 {
0089     Q_ASSERT(colorSpace);
0090     Q_ASSERT(data);
0091     d->colorSpace = KoColorSpaceRegistry::instance()->permanentColorspace(colorSpace);
0092     d->data = new quint8[colorSpace->pixelSize()];
0093     memset(d->data, 0, d->colorSpace->pixelSize());
0094     memmove(d->data, data, colorSpace->pixelSize());
0095 }
0096 
0097 
0098 KoColor::KoColor(const KoColor &src, const KoColorSpace * colorSpace)
0099         : d(new Private())
0100 {
0101     Q_ASSERT(colorSpace);
0102     d->colorSpace = KoColorSpaceRegistry::instance()->permanentColorspace(colorSpace);
0103     d->data = new quint8[colorSpace->pixelSize()];
0104     memset(d->data, 0, d->colorSpace->pixelSize());
0105 
0106     src.colorSpace()->convertPixelsTo(src.d->data, d->data, colorSpace, 1, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags());
0107 }
0108 
0109 KoColor::KoColor(const KoColor & rhs)
0110         : d(new Private())
0111 {
0112     d->colorSpace = rhs.colorSpace();
0113     Q_ASSERT(*d->colorSpace == *KoColorSpaceRegistry::instance()->permanentColorspace(d->colorSpace));
0114     if (d->colorSpace && rhs.d->data) {
0115         d->data = new quint8[d->colorSpace->pixelSize()];
0116         memcpy(d->data, rhs.d->data, d->colorSpace->pixelSize());
0117     }
0118 }
0119 
0120 KoColor & KoColor::operator=(const KoColor & rhs)
0121 {
0122     if (this == &rhs) return *this;
0123 
0124     delete [] d->data;
0125     d->data = 0;
0126     d->colorSpace = rhs.colorSpace();
0127 
0128     if (rhs.d->colorSpace && rhs.d->data) {
0129         Q_ASSERT(d->colorSpace == KoColorSpaceRegistry::instance()->permanentColorspace(d->colorSpace)); // here we want to do a check on pointer, since d->colorSpace is supposed to already be a permanent one
0130         d->data = new quint8[d->colorSpace->pixelSize()];
0131         memcpy(d->data, rhs.d->data, d->colorSpace->pixelSize());
0132     }
0133     return * this;
0134 }
0135 
0136 bool KoColor::operator==(const KoColor &other) const
0137 {
0138     if (!(*colorSpace() == *other.colorSpace()))
0139         return false;
0140     return memcmp(d->data, other.d->data, d->colorSpace->pixelSize()) == 0;
0141 }
0142 
0143 void KoColor::convertTo(const KoColorSpace * cs, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags)
0144 {
0145     //dbgPigment <<"Our colormodel:" << d->colorSpace->id().name()
0146     //      << ", new colormodel: " << cs->id().name() << "\n";
0147 
0148     if (*d->colorSpace == *cs)
0149         return;
0150 
0151     quint8 * data = new quint8[cs->pixelSize()];
0152     memset(data, 0, cs->pixelSize());
0153 
0154     d->colorSpace->convertPixelsTo(d->data, data, cs, 1, renderingIntent, conversionFlags);
0155 
0156     delete [] d->data;
0157     d->data = data;
0158     d->colorSpace = KoColorSpaceRegistry::instance()->permanentColorspace(cs);
0159 }
0160 
0161 void KoColor::convertTo(const KoColorSpace * cs)
0162 {
0163     convertTo(cs,
0164               KoColorConversionTransformation::internalRenderingIntent(),
0165               KoColorConversionTransformation::internalConversionFlags());
0166 }
0167 
0168 void KoColor::setColor(const quint8 * data, const KoColorSpace * colorSpace)
0169 {
0170     Q_ASSERT(data);
0171     Q_ASSERT(colorSpace);
0172     if(d->colorSpace->pixelSize() != colorSpace->pixelSize())
0173     {
0174         delete [] d->data;
0175         d->data = new quint8[colorSpace->pixelSize()];
0176     }
0177     memcpy(d->data, data, colorSpace->pixelSize());
0178     d->colorSpace = KoColorSpaceRegistry::instance()->permanentColorspace(colorSpace);
0179 }
0180 
0181 // To save the user the trouble of doing color->colorSpace()->toQColor(color->data(), &c, &a, profile
0182 void KoColor::toQColor(QColor *c) const
0183 {
0184     Q_ASSERT(c);
0185     if (d->colorSpace && d->data) {
0186         d->colorSpace->toQColor(d->data, c);
0187     }
0188 }
0189 
0190 QColor KoColor::toQColor() const
0191 {
0192     QColor c;
0193     toQColor(&c);
0194     return c;
0195 }
0196 
0197 void KoColor::fromQColor(const QColor& c) const
0198 {
0199     if (d->colorSpace && d->data) {
0200         d->colorSpace->fromQColor(c, d->data);
0201     }
0202 }
0203 
0204 #ifndef NDEBUG
0205 void KoColor::dump() const
0206 {
0207     dbgPigment <<"KoColor (" << this <<")," << d->colorSpace->id() <<"";
0208     QList<KoChannelInfo *> channels = d->colorSpace->channels();
0209 
0210     QList<KoChannelInfo *>::const_iterator begin = channels.constBegin();
0211     QList<KoChannelInfo *>::const_iterator end = channels.constEnd();
0212 
0213     for (QList<KoChannelInfo *>::const_iterator it = begin; it != end; ++it) {
0214         KoChannelInfo * ch = (*it);
0215         // XXX: setNum always takes a byte.
0216         if (ch->size() == sizeof(quint8)) {
0217             // Byte
0218             dbgPigment <<"Channel (byte):" << ch->name() <<":" << QString().setNum(d->data[ch->pos()]) <<"";
0219         } else if (ch->size() == sizeof(quint16)) {
0220             // Short (may also by an nvidia half)
0221             dbgPigment <<"Channel (short):" << ch->name() <<":" << QString().setNum(*((const quint16 *)(d->data+ch->pos())))  <<"";
0222         } else if (ch->size() == sizeof(quint32)) {
0223             // Integer (may also be float... Find out how to distinguish these!)
0224             dbgPigment <<"Channel (int):" << ch->name() <<":" << QString().setNum(*((const quint32 *)(d->data+ch->pos())))  <<"";
0225         }
0226     }
0227 }
0228 #endif
0229 
0230 void KoColor::fromKoColor(const KoColor& src)
0231 {
0232     src.colorSpace()->convertPixelsTo(src.d->data, d->data, colorSpace(), 1, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags());
0233 }
0234 
0235 const KoColorProfile *  KoColor::profile() const
0236 {
0237     return d->colorSpace->profile();
0238 }
0239 
0240 quint8 * KoColor::data()
0241 {
0242     return d->data;
0243 }
0244 
0245 const quint8 * KoColor::data() const
0246 {
0247     return d->data;
0248 }
0249 
0250 const KoColorSpace * KoColor::colorSpace() const
0251 {
0252     return d->colorSpace;
0253 }
0254 
0255 void KoColor::toXML(QDomDocument& doc, QDomElement& colorElt) const
0256 {
0257     d->colorSpace->colorToXML(d->data, doc, colorElt);
0258 }
0259 
0260 void KoColor::setOpacity(quint8 alpha)
0261 {
0262     d->colorSpace->setOpacity(d->data, alpha, 1);
0263 }
0264 void KoColor::setOpacity(qreal alpha)
0265 {
0266     d->colorSpace->setOpacity(d->data, alpha, 1);
0267 }
0268 quint8 KoColor::opacityU8() const
0269 {
0270     return d->colorSpace->opacityU8(d->data);
0271 }
0272 qreal KoColor::opacityF() const
0273 {
0274     return d->colorSpace->opacityF(d->data);
0275 }
0276 
0277 KoColor KoColor::fromXML(const QDomElement& elt, const QString & bitDepthId, const QHash<QString, QString> & aliases)
0278 {
0279     QString modelId;
0280     if (elt.tagName() == "CMYK") {
0281         modelId = CMYKAColorModelID.id();
0282     } else if (elt.tagName() == "RGB") {
0283         modelId = RGBAColorModelID.id();
0284     } else if (elt.tagName() == "sRGB") {
0285         modelId = RGBAColorModelID.id();
0286     } else if (elt.tagName() == "Lab") {
0287         modelId = LABAColorModelID.id();
0288     } else if (elt.tagName() == "XYZ") {
0289         modelId = XYZAColorModelID.id();
0290     } else if (elt.tagName() == "Gray") {
0291         modelId = GrayAColorModelID.id();
0292     } else if (elt.tagName() == "YCbCr") {
0293         modelId = YCbCrAColorModelID.id();
0294     }
0295     QString profileName;
0296     if (elt.tagName() != "sRGB") {
0297         profileName = elt.attribute("space", "");
0298         const QHash<QString, QString>::ConstIterator it = aliases.find(profileName);
0299         if (it != aliases.end()) {
0300             profileName = it.value();
0301         }
0302         if (!KoColorSpaceRegistry::instance()->profileByName(profileName)) {
0303             profileName.clear();
0304         }
0305     }
0306     const KoColorSpace* cs = KoColorSpaceRegistry::instance()->colorSpace(modelId, bitDepthId, profileName);
0307     if (cs == 0) {
0308         QList<KoID> list =  KoColorSpaceRegistry::instance()->colorDepthList(modelId, KoColorSpaceRegistry::AllColorSpaces);
0309         if (!list.empty()) {
0310             cs = KoColorSpaceRegistry::instance()->colorSpace(modelId, list[0].id(), profileName);
0311         }
0312     }
0313     if (cs) {
0314         KoColor c(cs);
0315         cs->colorFromXML(c.data(), elt);
0316         return c;
0317     } else {
0318         return KoColor();
0319     }
0320 }
0321 
0322 QString KoColor::toQString(const KoColor &color)
0323 {
0324     QStringList ls;
0325     foreach(KoChannelInfo *channel, KoChannelInfo::displayOrderSorted(color.colorSpace()->channels())) {
0326         int realIndex = KoChannelInfo::displayPositionToChannelIndex(channel->displayPosition(), color.colorSpace()->channels());
0327         ls << channel->name();
0328         ls << color.colorSpace()->channelValueText(color.data(), realIndex);
0329     }
0330     return ls.join(" ");
0331 }