KoColor.cpp 8.97 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>

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

32 33


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

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

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

47
KoColor::KoColor()
Thomas Zander's avatar
Thomas Zander committed
48
    : d(new Private())
49
{
Thomas Zander's avatar
Thomas Zander committed
50 51 52 53
    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);
54
}
55

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

64 65 66

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

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

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

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


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

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

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


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

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

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

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

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

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

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

148
void KoColor::convertTo(const KoColorSpace * cs)
149
{
Boudewijn Rempt's avatar
Boudewijn Rempt committed
150
    //kDebug(DBG_PIGMENT) <<"Our colormodel:" << d->colorSpace->id().name()
151 152
    //      << ", new colormodel: " << cs->id().name() << "\n";

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

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

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

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


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

175 176 177
// 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
178 179
    if (d->colorSpace && d->data) {
        d->colorSpace->toQColor(d->data, c);
180
    }
181 182 183 184
}

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

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

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

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

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

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

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

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

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

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

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

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

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

267 268 269 270 271 272 273 274 275
void KoColor::setOpacity(quint8 alpha )
{
    d->colorSpace->setAlpha( d->data, alpha, 1);
}
quint8 KoColor::opacity() const
{
    d->colorSpace->alpha( d->data );
}

276 277
KoColor KoColor::fromXML(const QDomElement& elt, QString bitDepthId, QHash<QString, QString> aliases)
{
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
    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);
        }
303 304 305 306
        if( not KoColorSpaceRegistry::instance()->profileByName( profileName))
        {
            profileName = "";
        }
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
    }
    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();
    }
326
}