KoColor.cpp 8.63 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
 *
5
 * This library is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU Lesser General Public
7 8
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
9
 *
10 11 12
 * 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
13
 * Lesser General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU Lesser General Public License
16 17 18 19
 * 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.
*/
20
#include <QColor>
Thomas Zander's avatar
Thomas Zander committed
21

22 23
#include <QDomDocument>

24
#include "kdebug.h"
25
#include "KoColor.h"
26
#include "KoColorModelStandardIds.h"
27 28
#include "KoColorProfile.h"
#include "KoColorSpace.h"
29
#include "KoColorSpaceRegistry.h"
30

31 32


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

Thomas Zander's avatar
Thomas Zander committed
37
    ~Private() {
38 39
        if ( data )
            delete [] data;
Thomas Zander's avatar
Thomas Zander committed
40
    }
41

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

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

55
KoColor::KoColor(const KoColorSpace * colorSpace)
Thomas Zander's avatar
Thomas Zander committed
56
    : d(new Private())
57
{
Thomas Zander's avatar
Thomas Zander committed
58 59 60
    d->colorSpace = colorSpace;
    d->data = new quint8[d->colorSpace->pixelSize()];
    memset(d->data, 0, d->colorSpace->pixelSize());
61 62
}

63 64 65

KoColor::~KoColor()
{
Thomas Zander's avatar
Thomas Zander committed
66
    delete d;
67 68
}

69
KoColor::KoColor(const QColor & color, const KoColorSpace * colorSpace)
Thomas Zander's avatar
Thomas Zander committed
70
    : d(new Private())
71
{
Thomas Zander's avatar
Thomas Zander committed
72
    d->colorSpace = colorSpace;
73 74 75
    Q_ASSERT(color.isValid());
    Q_ASSERT(colorSpace);

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

    d->colorSpace->fromQColor(color, OPACITY_OPAQUE, d->data);
80 81 82
}


83
KoColor::KoColor(const QColor & color, quint8 alpha, const KoColorSpace * colorSpace)
Thomas Zander's avatar
Thomas Zander committed
84
    : d(new Private())
85
{
Thomas Zander's avatar
Thomas Zander committed
86
    d->colorSpace = colorSpace;
87 88
    Q_ASSERT(color.isValid());
    Q_ASSERT(colorSpace);
Thomas Zander's avatar
Thomas Zander committed
89 90
    d->data = new quint8[colorSpace->pixelSize()];
    memset(d->data, 0, d->colorSpace->pixelSize());
91

Thomas Zander's avatar
Thomas Zander committed
92
    d->colorSpace->fromQColor(color, alpha, d->data);
93 94
}

95
KoColor::KoColor(const quint8 * data, const KoColorSpace * colorSpace)
Thomas Zander's avatar
Thomas Zander committed
96
    : d(new Private())
97
{
Thomas Zander's avatar
Thomas Zander committed
98 99 100 101
    d->colorSpace = colorSpace;
    d->data = new quint8[colorSpace->pixelSize()];
    memset(d->data, 0, d->colorSpace->pixelSize());
    memmove(d->data, data, colorSpace->pixelSize());
102 103 104
}


105
KoColor::KoColor(const KoColor &src, const KoColorSpace * colorSpace)
Thomas Zander's avatar
Thomas Zander committed
106
    : d(new Private())
107
{
Thomas Zander's avatar
Thomas Zander committed
108 109 110
    d->colorSpace = colorSpace;
    d->data = new quint8[colorSpace->pixelSize()];
    memset(d->data, 0, d->colorSpace->pixelSize());
111

Thomas Zander's avatar
Thomas Zander committed
112
    src.colorSpace()->convertPixelsTo(src.d->data, d->data, colorSpace, 1);
113 114
}

115
KoColor::KoColor(const KoColor & rhs)
Thomas Zander's avatar
Thomas Zander committed
116
    : d(new Private())
117
{
Thomas Zander's avatar
Thomas Zander committed
118 119
    d->colorSpace = rhs.colorSpace();
    if(d->colorSpace && rhs.d->data)
120
    {
Thomas Zander's avatar
Thomas Zander committed
121 122
        d->data = new quint8[d->colorSpace->pixelSize()];
        memcpy(d->data, rhs.d->data, d->colorSpace->pixelSize());
123
    }
124 125 126 127
}

KoColor & KoColor::operator=(const KoColor & rhs)
{
128 129
    if (this == &rhs) return *this;

Thomas Zander's avatar
Thomas Zander committed
130 131 132
    delete [] d->data;
    d->data = 0;
    d->colorSpace = rhs.colorSpace();
133

Thomas Zander's avatar
Thomas Zander committed
134 135 136
    if (rhs.d->colorSpace && rhs.d->data) {
        d->data = new quint8[d->colorSpace->pixelSize()];
        memcpy(d->data, rhs.d->data, d->colorSpace->pixelSize());
137
    }
138 139 140
    return * this;
}

141
bool KoColor::operator==(const KoColor &other) const
142 143 144 145 146
{
    if(colorSpace() != other.colorSpace()) return false;
    return memcmp(d->data, other.d->data, d->colorSpace->pixelSize()) == 0;
}

147
void KoColor::convertTo(const KoColorSpace * cs)
148
{
149
    //kDebug(DBG_AREA_CMS) <<"Our colormodel:" << d->colorSpace->id().name()
150 151
    //      << ", new colormodel: " << cs->id().name() << "\n";

Thomas Zander's avatar
Thomas Zander committed
152
    if (d->colorSpace == cs)
153 154
        return;

Thomas Zander's avatar
Thomas Zander committed
155 156
    quint8 * data = new quint8[cs->pixelSize()];
    memset(data, 0, cs->pixelSize());
157

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

Thomas Zander's avatar
Thomas Zander committed
160 161 162
    delete [] d->data;
    d->data = data;
    d->colorSpace = cs;
163 164 165
}


166
void KoColor::setColor(quint8 * data, const KoColorSpace * colorSpace)
167
{
Thomas Zander's avatar
Thomas Zander committed
168 169 170 171
    delete [] d->data;
    d->data = new quint8[colorSpace->pixelSize()];
    memcpy(d->data, data, colorSpace->pixelSize());
    d->colorSpace = colorSpace;
172 173
}

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

void KoColor::toQColor(QColor *c, quint8 *opacity) const
{
Thomas Zander's avatar
Thomas Zander committed
184 185
    if (d->colorSpace && d->data) {
        d->colorSpace->toQColor(d->data, c, opacity);
186
    }
187 188 189 190 191 192 193 194
}

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

196 197
void KoColor::fromQColor(const QColor& c) const
{
Thomas Zander's avatar
Thomas Zander committed
198 199
    if (d->colorSpace && d->data) {
        d->colorSpace->fromQColor(c, d->data);
200 201 202 203 204
    }
}

void KoColor::fromQColor(const QColor& c, quint8 opacity) const
{
Thomas Zander's avatar
Thomas Zander committed
205 206
    if (d->colorSpace && d->data) {
        d->colorSpace->fromQColor(c, opacity, d->data);
207 208 209
    }
}

Thomas Zander's avatar
Thomas Zander committed
210
#ifndef NDEBUG
211 212
void KoColor::dump() const
{
213
    //kDebug(DBG_AREA_CMS) <<"KoColor (" << this <<")," << d->colorSpace->id().name() <<"";
Adrian Page's avatar
q3--  
Adrian Page committed
214
    QList<KoChannelInfo *> channels = d->colorSpace->channels();
215

Adrian Page's avatar
q3--  
Adrian Page committed
216 217
    QList<KoChannelInfo *>::const_iterator begin = channels.begin();
    QList<KoChannelInfo *>::const_iterator end = channels.end();
218

Adrian Page's avatar
q3--  
Adrian Page committed
219
    for (QList<KoChannelInfo *>::const_iterator it = begin; it != end; ++it)
220 221 222 223 224
    {
        KoChannelInfo * ch = (*it);
        // XXX: setNum always takes a byte.
        if (ch->size() == sizeof(quint8)) {
            // Byte
225
            //kDebug(DBG_AREA_CMS) <<"Channel (byte):" << ch->name() <<":" << QString().setNum(d->data[ch->pos()]) <<"";
226 227 228
        }
        else if (ch->size() == sizeof(quint16)) {
            // Short (may also by an nvidia half)
229
            //kDebug(DBG_AREA_CMS) <<"Channel (short):" << ch->name() <<":" << QString().setNum(*((const quint16 *)(d->data+ch->pos())))  <<"";
230 231 232
        }
        else if (ch->size() == sizeof(quint32)) {
            // Integer (may also be float... Find out how to distinguish these!)
233
            //kDebug(DBG_AREA_CMS) <<"Channel (int):" << ch->name() <<":" << QString().setNum(*((const quint32 *)(d->data+ch->pos())))  <<"";
234 235 236
        }
    }
}
Thomas Zander's avatar
Thomas Zander committed
237
#endif
238 239 240

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

244
const KoColorProfile *  KoColor::profile() const
Cyrille Berger's avatar
Cyrille Berger committed
245
{
Thomas Zander's avatar
Thomas Zander committed
246 247 248
    return d->colorSpace->profile();
}

Thomas Zander's avatar
Thomas Zander committed
249 250 251 252 253
quint8 * KoColor::data() {
    return d->data;
}

const quint8 * KoColor::data() const {
Thomas Zander's avatar
Thomas Zander committed
254
    return d->data;
Cyrille Berger's avatar
Cyrille Berger committed
255
}
Thomas Zander's avatar
Thomas Zander committed
256

257
const KoColorSpace * KoColor::colorSpace() const {
Thomas Zander's avatar
Thomas Zander committed
258 259 260
    return d->colorSpace;
}

261 262 263 264 265 266 267
void KoColor::toXML(QDomDocument& doc, QDomElement& colorElt) const
{
    d->colorSpace->colorToXML( d->data, doc, colorElt);
}

KoColor KoColor::fromXML(const QDomElement& elt, QString bitDepthId, QHash<QString, QString> aliases)
{
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
    QString modelId;
    if(elt.tagName() == "CMYK")
    {
        modelId = CMYKAColorModelID.id();
    } else if( elt.tagName() == "RGB") {
        modelId = RGBAColorModelID.id();
    } else if( elt.tagName() == "sRGB") {
        modelId = RGBAColorModelID.id();
    } else if( elt.tagName() == "Lab") {
        modelId = LABAColorModelID.id();
    } else if( elt.tagName() == "XYZ") {
        modelId = XYZAColorModelID.id();
    } else if( elt.tagName() == "Gray") {
        modelId = GrayAColorModelID.id();
    } else if( elt.tagName() == "YCbCr") {
        modelId = YCbCrAColorModelID.id();
    }
    QString profileName;
    if( elt.tagName() != "sRGB")
    {
        profileName = elt.attribute("space","");
        if( aliases.contains(profileName))
        {
            profileName = aliases.value(profileName);
        }
    }
    QString csId = KoColorSpaceRegistry::instance()->colorSpaceId(modelId, bitDepthId);
    if(csId == "")
    {
        QList<KoID> list =  KoColorSpaceRegistry::instance()->colorDepthList(modelId, KoColorSpaceRegistry::AllColorSpaces );
        if(not list.empty())
        {
            csId = KoColorSpaceRegistry::instance()->colorSpaceId(modelId, list[0].id());
        }
    }
    const KoColorSpace* cs = KoColorSpaceRegistry::instance()->colorSpace(csId, profileName);
    if(cs)
    {
        KoColor c(cs);
        cs->colorFromXML( c.data(), elt);
        return c;
    } else {
        return KoColor();
    }
312
}