KoColor.cpp 9 KB
Newer Older
1 2
/*
 *  Copyright (c) 2005 Boudewijn Rempt <boud@valdyas.org>
Thomas Zander's avatar
Thomas Zander committed
3
 *  Copyright (C) 2007 Thomas Zander <zander@kde.org>
4
 *  Copyright (C) 2007 Cyrille Berger <cberger@cberger.net>
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8 9
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
10
 *
11 12 13
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public License
17 18 19 20
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
*/
21
#include <QColor>
Thomas Zander's avatar
Thomas Zander committed
22

23 24
#include <QDomDocument>

Boudewijn Rempt's avatar
Boudewijn Rempt committed
25
#include "DebugPigment.h"
26
#include "KoColor.h"
27 28


29
#include "KoColorModelStandardIds.h"
30 31
#include "KoColorProfile.h"
#include "KoColorSpace.h"
32
#include "KoColorSpaceRegistry.h"
33

34

35 36
class KoColor::Private
{
Thomas Zander's avatar
Thomas Zander committed
37 38
public:
    Private() : data(0), colorSpace(0) {}
39

Thomas Zander's avatar
Thomas Zander committed
40
    ~Private() {
41
        delete [] data;
Thomas Zander's avatar
Thomas Zander committed
42
    }
43

Thomas Zander's avatar
Thomas Zander committed
44
    quint8 * data;
45
    const KoColorSpace * colorSpace;
Thomas Zander's avatar
Thomas Zander committed
46 47
};

48
KoColor::KoColor()
49
        : d(new Private())
50
{
51
    d->colorSpace = KoColorSpaceRegistry::instance()->lab16(0);
Thomas Zander's avatar
Thomas Zander committed
52 53 54
    d->data = new quint8[d->colorSpace->pixelSize()];
    memset(d->data, 0, d->colorSpace->pixelSize());
    d->colorSpace->setAlpha(d->data, OPACITY_OPAQUE, 1);
55
}
56

57
KoColor::KoColor(const KoColorSpace * colorSpace)
58
        : d(new Private())
59
{
Cyrille Berger's avatar
Cyrille Berger committed
60
    Q_ASSERT(colorSpace);
61
    d->colorSpace = KoColorSpaceRegistry::instance()->permanentColorspace(colorSpace);
Thomas Zander's avatar
Thomas Zander committed
62 63
    d->data = new quint8[d->colorSpace->pixelSize()];
    memset(d->data, 0, d->colorSpace->pixelSize());
64 65
}

66 67 68

KoColor::~KoColor()
{
Thomas Zander's avatar
Thomas Zander committed
69
    delete d;
70 71
}

72
KoColor::KoColor(const QColor & color, const KoColorSpace * colorSpace)
73
        : d(new Private())
74 75 76
{
    Q_ASSERT(color.isValid());
    Q_ASSERT(colorSpace);
77
    d->colorSpace = KoColorSpaceRegistry::instance()->permanentColorspace(colorSpace);
78

Thomas Zander's avatar
Thomas Zander committed
79 80 81
    d->data = new quint8[colorSpace->pixelSize()];
    memset(d->data, 0, d->colorSpace->pixelSize());

82
    d->colorSpace->fromQColor(color, d->data);
83 84
}

85
KoColor::KoColor(const quint8 * data, const KoColorSpace * colorSpace)
86
        : d(new Private())
87
{
Cyrille Berger's avatar
Cyrille Berger committed
88 89
    Q_ASSERT(colorSpace);
    Q_ASSERT(data);
90
    d->colorSpace = KoColorSpaceRegistry::instance()->permanentColorspace(colorSpace);
Thomas Zander's avatar
Thomas Zander committed
91 92 93
    d->data = new quint8[colorSpace->pixelSize()];
    memset(d->data, 0, d->colorSpace->pixelSize());
    memmove(d->data, data, colorSpace->pixelSize());
94 95 96
}


97
KoColor::KoColor(const KoColor &src, const KoColorSpace * colorSpace)
98
        : d(new Private())
99
{
Cyrille Berger's avatar
Cyrille Berger committed
100
    Q_ASSERT(colorSpace);
101
    d->colorSpace = KoColorSpaceRegistry::instance()->permanentColorspace(colorSpace);
Thomas Zander's avatar
Thomas Zander committed
102 103
    d->data = new quint8[colorSpace->pixelSize()];
    memset(d->data, 0, d->colorSpace->pixelSize());
104

Thomas Zander's avatar
Thomas Zander committed
105
    src.colorSpace()->convertPixelsTo(src.d->data, d->data, colorSpace, 1);
106 107
}

108
KoColor::KoColor(const KoColor & rhs)
109
        : d(new Private())
110
{
Thomas Zander's avatar
Thomas Zander committed
111
    d->colorSpace = rhs.colorSpace();
112
    Q_ASSERT(*d->colorSpace == *KoColorSpaceRegistry::instance()->permanentColorspace(d->colorSpace));
113
    if (d->colorSpace && rhs.d->data) {
Thomas Zander's avatar
Thomas Zander committed
114 115
        d->data = new quint8[d->colorSpace->pixelSize()];
        memcpy(d->data, rhs.d->data, d->colorSpace->pixelSize());
116
    }
117 118 119 120
}

KoColor & KoColor::operator=(const KoColor & rhs)
{
121 122
    if (this == &rhs) return *this;

Thomas Zander's avatar
Thomas Zander committed
123 124 125
    delete [] d->data;
    d->data = 0;
    d->colorSpace = rhs.colorSpace();
126

Thomas Zander's avatar
Thomas Zander committed
127
    if (rhs.d->colorSpace && rhs.d->data) {
128
        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
Thomas Zander's avatar
Thomas Zander committed
129 130
        d->data = new quint8[d->colorSpace->pixelSize()];
        memcpy(d->data, rhs.d->data, d->colorSpace->pixelSize());
131
    }
132 133 134
    return * this;
}

135
bool KoColor::operator==(const KoColor &other) const
136
{
137 138
    if (!(*colorSpace() == *other.colorSpace()))
        return false;
139 140 141
    return memcmp(d->data, other.d->data, d->colorSpace->pixelSize()) == 0;
}

142
void KoColor::convertTo(const KoColorSpace * cs)
143
{
Boudewijn Rempt's avatar
Boudewijn Rempt committed
144
    //dbgPigment <<"Our colormodel:" << d->colorSpace->id().name()
145 146
    //      << ", new colormodel: " << cs->id().name() << "\n";

147
    if (*d->colorSpace == *cs)
148 149
        return;

Thomas Zander's avatar
Thomas Zander committed
150 151
    quint8 * data = new quint8[cs->pixelSize()];
    memset(data, 0, cs->pixelSize());
152

Thomas Zander's avatar
Thomas Zander committed
153
    d->colorSpace->convertPixelsTo(d->data, data, cs, 1);
154

Thomas Zander's avatar
Thomas Zander committed
155 156
    delete [] d->data;
    d->data = data;
157
    d->colorSpace = KoColorSpaceRegistry::instance()->permanentColorspace(cs);
158 159 160
}


161
void KoColor::setColor(quint8 * data, const KoColorSpace * colorSpace)
162
{
Cyrille Berger's avatar
Cyrille Berger committed
163 164
    Q_ASSERT(data);
    Q_ASSERT(colorSpace);
Thomas Zander's avatar
Thomas Zander committed
165 166 167
    delete [] d->data;
    d->data = new quint8[colorSpace->pixelSize()];
    memcpy(d->data, data, colorSpace->pixelSize());
168
    d->colorSpace = KoColorSpaceRegistry::instance()->permanentColorspace(colorSpace);
169 170
}

171 172 173
// To save the user the trouble of doing color->colorSpace()->toQColor(color->data(), &c, &a, profile
void KoColor::toQColor(QColor *c) const
{
Cyrille Berger's avatar
Cyrille Berger committed
174
    Q_ASSERT(c);
Thomas Zander's avatar
Thomas Zander committed
175 176
    if (d->colorSpace && d->data) {
        d->colorSpace->toQColor(d->data, c);
177
    }
178 179 180 181 182 183 184 185
}

QColor KoColor::toQColor() const
{
    QColor c;
    toQColor(&c);
    return c;
}
186

187 188
void KoColor::fromQColor(const QColor& c) const
{
Thomas Zander's avatar
Thomas Zander committed
189 190
    if (d->colorSpace && d->data) {
        d->colorSpace->fromQColor(c, d->data);
191 192 193
    }
}

Thomas Zander's avatar
Thomas Zander committed
194
#ifndef NDEBUG
195 196
void KoColor::dump() const
{
Boudewijn Rempt's avatar
Boudewijn Rempt committed
197
    //dbgPigment <<"KoColor (" << this <<")," << d->colorSpace->id().name() <<"";
Adrian Page's avatar
q3--  
Adrian Page committed
198
    QList<KoChannelInfo *> channels = d->colorSpace->channels();
199

Laurent Montel's avatar
Laurent Montel committed
200 201
    QList<KoChannelInfo *>::const_iterator begin = channels.constBegin();
    QList<KoChannelInfo *>::const_iterator end = channels.constEnd();
202

203
    for (QList<KoChannelInfo *>::const_iterator it = begin; it != end; ++it) {
204 205 206 207
        KoChannelInfo * ch = (*it);
        // XXX: setNum always takes a byte.
        if (ch->size() == sizeof(quint8)) {
            // Byte
Boudewijn Rempt's avatar
Boudewijn Rempt committed
208
            //dbgPigment <<"Channel (byte):" << ch->name() <<":" << QString().setNum(d->data[ch->pos()]) <<"";
209
        } else if (ch->size() == sizeof(quint16)) {
210
            // Short (may also by an nvidia half)
Boudewijn Rempt's avatar
Boudewijn Rempt committed
211
            //dbgPigment <<"Channel (short):" << ch->name() <<":" << QString().setNum(*((const quint16 *)(d->data+ch->pos())))  <<"";
212
        } else if (ch->size() == sizeof(quint32)) {
213
            // Integer (may also be float... Find out how to distinguish these!)
Boudewijn Rempt's avatar
Boudewijn Rempt committed
214
            //dbgPigment <<"Channel (int):" << ch->name() <<":" << QString().setNum(*((const quint32 *)(d->data+ch->pos())))  <<"";
215 216 217
        }
    }
}
Thomas Zander's avatar
Thomas Zander committed
218
#endif
219 220 221

void KoColor::fromKoColor(const KoColor& src)
{
Thomas Zander's avatar
Thomas Zander committed
222
    src.colorSpace()->convertPixelsTo(src.d->data, d->data, colorSpace(), 1);
223
}
Cyrille Berger's avatar
Cyrille Berger committed
224

225
const KoColorProfile *  KoColor::profile() const
Cyrille Berger's avatar
Cyrille Berger committed
226
{
Thomas Zander's avatar
Thomas Zander committed
227 228 229
    return d->colorSpace->profile();
}

230 231
quint8 * KoColor::data()
{
Thomas Zander's avatar
Thomas Zander committed
232 233 234
    return d->data;
}

235 236
const quint8 * KoColor::data() const
{
Thomas Zander's avatar
Thomas Zander committed
237
    return d->data;
Cyrille Berger's avatar
Cyrille Berger committed
238
}
Thomas Zander's avatar
Thomas Zander committed
239

240 241
const KoColorSpace * KoColor::colorSpace() const
{
Thomas Zander's avatar
Thomas Zander committed
242 243 244
    return d->colorSpace;
}

245 246
void KoColor::toXML(QDomDocument& doc, QDomElement& colorElt) const
{
247
    d->colorSpace->colorToXML(d->data, doc, colorElt);
248 249
}

250
void KoColor::setOpacity(quint8 alpha)
251
{
252
    d->colorSpace->setAlpha(d->data, alpha, 1);
253 254 255
}
quint8 KoColor::opacity() const
{
256
    return d->colorSpace->alpha(d->data);
257 258
}

Boudewijn Rempt's avatar
Boudewijn Rempt committed
259
KoColor KoColor::fromXML(const QDomElement& elt, const QString & bitDepthId, const QHash<QString, QString> & aliases)
260
{
261
    QString modelId;
262
    if (elt.tagName() == "CMYK") {
263
        modelId = CMYKAColorModelID.id();
264
    } else if (elt.tagName() == "RGB") {
265
        modelId = RGBAColorModelID.id();
266
    } else if (elt.tagName() == "sRGB") {
267
        modelId = RGBAColorModelID.id();
268
    } else if (elt.tagName() == "Lab") {
269
        modelId = LABAColorModelID.id();
270
    } else if (elt.tagName() == "XYZ") {
271
        modelId = XYZAColorModelID.id();
272
    } else if (elt.tagName() == "Gray") {
273
        modelId = GrayAColorModelID.id();
274
    } else if (elt.tagName() == "YCbCr") {
275 276 277
        modelId = YCbCrAColorModelID.id();
    }
    QString profileName;
278 279 280
    if (elt.tagName() != "sRGB") {
        profileName = elt.attribute("space", "");
        if (aliases.contains(profileName)) {
281 282
            profileName = aliases.value(profileName);
        }
283
        if (!KoColorSpaceRegistry::instance()->profileByName(profileName)) {
284 285
            profileName = "";
        }
286 287
    }
    QString csId = KoColorSpaceRegistry::instance()->colorSpaceId(modelId, bitDepthId);
288 289 290
    if (csId.isEmpty()) {
        QList<KoID> list =  KoColorSpaceRegistry::instance()->colorDepthList(modelId, KoColorSpaceRegistry::AllColorSpaces);
        if (!list.empty()) {
291 292 293 294
            csId = KoColorSpaceRegistry::instance()->colorSpaceId(modelId, list[0].id());
        }
    }
    const KoColorSpace* cs = KoColorSpaceRegistry::instance()->colorSpace(csId, profileName);
295
    if (cs) {
296
        KoColor c(cs);
297
        cs->colorFromXML(c.data(), elt);
298 299 300 301
        return c;
    } else {
        return KoColor();
    }
302
}