~ubuntu-branches/ubuntu/oneiric/koffice/oneiric-updates

« back to all changes in this revision

Viewing changes to plugins/colorengines/lcms2/colorprofiles/LcmsColorProfileContainer.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alessandro Ghersi
  • Date: 2010-10-27 17:52:57 UTC
  • mfrom: (0.12.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20101027175257-s04zqqk5bs8ckm9o
Tags: 1:2.2.83-0ubuntu1
* Merge with Debian git remaining changes:
 - Add build-deps on librcps-dev, opengtl-dev, libqtgtl-dev, freetds-dev,
   create-resources, libspnav-dev
 - Remove needless build-dep on libwv2-dev
 - koffice-libs recommends create-resources
 - krita recommends pstoedit
 - Keep our patches
* New upstream release 2.3 beta 3
  - Remove debian/patches fixed by upstream
  - Update install files

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * This file is part of the KDE project
 
3
 *  Copyright (c) 2000 Matthias Elter <elter@kde.org>
 
4
 *                2001 John Califf
 
5
 *                2004 Boudewijn Rempt <boud@valdyas.org>
 
6
 *  Copyright (c) 2007 Thomas Zander <zander@kde.org>
 
7
 *  Copyright (c) 2007 Adrian Page <adrian@pagenet.plus.com>
 
8
 *
 
9
 * This library is free software; you can redistribute it and/or
 
10
 * modify it under the terms of the GNU Library General Public
 
11
 * License as published by the Free Software Foundation; either
 
12
 * version 2 of the License, or (at your option) any later version.
 
13
 *
 
14
 * This library is distributed in the hope that it will be useful,
 
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
17
 * Library General Public License for more details.
 
18
 *
 
19
 * You should have received a copy of the GNU Library General Public License
 
20
 * along with this library; see the file COPYING.LIB.  If not, write to
 
21
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 
22
 * Boston, MA 02110-1301, USA.
 
23
*/
 
24
 
 
25
#include "LcmsColorProfileContainer.h"
 
26
 
 
27
#include <cfloat>
 
28
#include <cmath>
 
29
 
 
30
#include "DebugPigment.h"
 
31
#include "KoChromaticities.h"
 
32
 
 
33
class LcmsColorProfileContainer::Private
 
34
{
 
35
public:
 
36
    Private() : valid(false), suitableForOutput(false) { }
 
37
 
 
38
    cmsHPROFILE profile;
 
39
    cmsColorSpaceSignature colorSpaceSignature;
 
40
    cmsProfileClassSignature deviceClass;
 
41
    QString productDescription;
 
42
    QString manufacturer;
 
43
    QString name;
 
44
    IccColorProfile::Data * data;
 
45
    bool valid;
 
46
    bool suitableForOutput;
 
47
};
 
48
 
 
49
LcmsColorProfileContainer::LcmsColorProfileContainer()
 
50
        : d(new Private())
 
51
{
 
52
    d->profile = 0;
 
53
}
 
54
 
 
55
LcmsColorProfileContainer::LcmsColorProfileContainer(IccColorProfile::Data * data)
 
56
        : d(new Private())
 
57
{
 
58
    d->data = data;
 
59
    d->profile = 0;
 
60
    init();
 
61
}
 
62
 
 
63
QByteArray LcmsColorProfileContainer::lcmsProfileToByteArray(const cmsHPROFILE profile)
 
64
{
 
65
    cmsUInt32Number  bytesNeeded = 0;
 
66
    // Make a raw data image ready for saving
 
67
    cmsSaveProfileToMem(profile, 0, &bytesNeeded); // calc size
 
68
    QByteArray rawData;
 
69
    rawData.resize(bytesNeeded);
 
70
    if (rawData.size() >= (int)bytesNeeded) {
 
71
        cmsSaveProfileToMem(profile, rawData.data(), &bytesNeeded); // fill buffer
 
72
    } else {
 
73
        errorPigment << "Couldn't resize the profile buffer, system is probably running out of memory.";
 
74
        rawData.resize(0);
 
75
    }
 
76
    return rawData;
 
77
}
 
78
 
 
79
IccColorProfile* LcmsColorProfileContainer::createFromLcmsProfile(const cmsHPROFILE profile)
 
80
{
 
81
    IccColorProfile* iccprofile = new IccColorProfile(lcmsProfileToByteArray(profile));
 
82
    cmsCloseProfile(profile);
 
83
    return iccprofile;
 
84
}
 
85
 
 
86
#define lcmsToPigmentViceVersaStructureCopy(dst, src  ) \
 
87
    dst .x = src .x; \
 
88
    dst .y = src .y; \
 
89
    dst .Y = src .Y;
 
90
 
 
91
QByteArray LcmsColorProfileContainer::createFromChromacities(const KoRGBChromaticities& _chromacities, qreal gamma, QString _profileName)
 
92
{
 
93
    cmsCIExyYTRIPLE primaries;
 
94
    cmsCIExyY whitePoint;
 
95
    lcmsToPigmentViceVersaStructureCopy(primaries.Red, _chromacities.primaries.Red);
 
96
    lcmsToPigmentViceVersaStructureCopy(primaries.Green, _chromacities.primaries.Green);
 
97
    lcmsToPigmentViceVersaStructureCopy(primaries.Blue, _chromacities.primaries.Blue);
 
98
    lcmsToPigmentViceVersaStructureCopy(whitePoint, _chromacities.whitePoint);
 
99
    cmsToneCurve* gammaTable = cmsBuildGamma(0, gamma);
 
100
 
 
101
    const int numTransferFunctions = 3;
 
102
    cmsToneCurve* transferFunctions[numTransferFunctions];
 
103
 
 
104
    for (int i = 0; i < numTransferFunctions; ++i) {
 
105
        transferFunctions[i] = gammaTable;
 
106
    }
 
107
 
 
108
    cmsHPROFILE profile = cmsCreateRGBProfile(&whitePoint, &primaries,
 
109
                          transferFunctions);
 
110
    QString name = _profileName;
 
111
 
 
112
    if (name.isEmpty()) {
 
113
        name = QString("lcms virtual RGB profile - R(%1, %2) G(%3, %4) B(%5, %6) W(%7, %8) gamma %9")
 
114
               .arg(primaries.Red.x)
 
115
               .arg(primaries.Red.y)
 
116
               .arg(primaries.Green.x)
 
117
               .arg(primaries.Green.y)
 
118
               .arg(primaries.Blue.x)
 
119
               .arg(primaries.Blue.y)
 
120
               .arg(whitePoint.x)
 
121
               .arg(whitePoint.y)
 
122
               .arg(gamma);
 
123
    }
 
124
 
 
125
    // icSigProfileDescriptionTag is the compulsory tag and is the profile name
 
126
    // displayed by other applications.
 
127
    cmsWriteTag(profile, cmsSigProfileDescriptionTag, name.toLatin1().data());
 
128
 
 
129
    cmsWriteTag(profile, cmsSigDeviceModelDescTag, name.toLatin1().data());
 
130
 
 
131
    // Clear the default manufacturer's tag that is set to "(lcms internal)"
 
132
    QByteArray ba("");
 
133
    cmsWriteTag(profile, cmsSigDeviceMfgDescTag, ba.data());
 
134
 
 
135
    cmsFreeToneCurve(gammaTable);
 
136
    QByteArray profileArray = lcmsProfileToByteArray(profile);
 
137
    cmsCloseProfile(profile);
 
138
    return profileArray;
 
139
}
 
140
 
 
141
LcmsColorProfileContainer::~LcmsColorProfileContainer()
 
142
{
 
143
    cmsCloseProfile(d->profile);
 
144
    delete d;
 
145
}
 
146
 
 
147
bool LcmsColorProfileContainer::init()
 
148
{
 
149
    if (d->profile) cmsCloseProfile(d->profile);
 
150
 
 
151
    d->profile = cmsOpenProfileFromMem((void*)d->data->rawData().constData(), d->data->rawData().size());
 
152
 
 
153
#ifndef NDEBUG
 
154
    if (d->data->rawData().size() == 4096) {
 
155
        warnPigment << "Profile has a size of 4096, which is suspicious and indicates a possible misuse of QIODevice::read(int), check your code.";
 
156
    }
 
157
#endif
 
158
 
 
159
    if (d->profile) {
 
160
        wchar_t buffer[500];
 
161
        d->colorSpaceSignature = cmsGetColorSpace(d->profile);
 
162
        d->deviceClass = cmsGetDeviceClass(d->profile);
 
163
        cmsGetProfileInfo(d->profile, cmsInfoDescription, cmsNoLanguage, cmsNoCountry, buffer, 500);
 
164
        d->productDescription = QString::fromWCharArray(buffer);
 
165
        d->valid = true;
 
166
        cmsGetProfileInfo(d->profile, cmsInfoModel, cmsNoLanguage, cmsNoCountry, buffer, 500);
 
167
        d->name = QString::fromWCharArray(buffer);
 
168
 
 
169
        cmsGetProfileInfo(d->profile, cmsInfoManufacturer, cmsNoLanguage, cmsNoCountry, buffer, 500);
 
170
        d->manufacturer = QString::fromWCharArray(buffer);
 
171
        
 
172
        // Check if the profile can convert (something->this)
 
173
        d->suitableForOutput = cmsIsMatrixShaper(d->profile)
 
174
                               || ( cmsIsCLUT(d->profile, INTENT_PERCEPTUAL, LCMS_USED_AS_INPUT) && 
 
175
                                    cmsIsCLUT(d->profile, INTENT_PERCEPTUAL, LCMS_USED_AS_OUTPUT) );
 
176
        return true;
 
177
    }
 
178
    return false;
 
179
}
 
180
 
 
181
cmsHPROFILE LcmsColorProfileContainer::lcmsProfile() const
 
182
{
 
183
#if 0
 
184
    if (d->profile = 0) {
 
185
        QFile file(d->filename);
 
186
        file.open(QIODevice::ReadOnly);
 
187
        d->rawData = file.readAll();
 
188
        d->profile = cmsOpenProfileFromMem((void*)d->rawData.constData(), (DWORD)d->rawData.size());
 
189
        file.close();
 
190
    }
 
191
#endif
 
192
    return d->profile;
 
193
}
 
194
 
 
195
cmsColorSpaceSignature LcmsColorProfileContainer::colorSpaceSignature() const
 
196
{
 
197
    return d->colorSpaceSignature;
 
198
}
 
199
 
 
200
cmsProfileClassSignature LcmsColorProfileContainer::deviceClass() const
 
201
{
 
202
    return d->deviceClass;
 
203
}
 
204
 
 
205
QString LcmsColorProfileContainer::manufacturer() const
 
206
{
 
207
    return d->manufacturer;
 
208
}
 
209
 
 
210
bool LcmsColorProfileContainer::valid() const
 
211
{
 
212
    return d->valid;
 
213
}
 
214
 
 
215
bool LcmsColorProfileContainer::isSuitableForOutput() const
 
216
{
 
217
    return d->suitableForOutput;
 
218
}
 
219
 
 
220
bool LcmsColorProfileContainer::isSuitableForPrinting() const
 
221
{
 
222
    return deviceClass() == cmsSigOutputClass;
 
223
}
 
224
 
 
225
bool LcmsColorProfileContainer::isSuitableForDisplay() const
 
226
{
 
227
    return deviceClass() == cmsSigDisplayClass;
 
228
}
 
229
 
 
230
QString LcmsColorProfileContainer::name() const
 
231
{
 
232
    return d->name;
 
233
}
 
234
QString LcmsColorProfileContainer::info() const
 
235
{
 
236
    return d->productDescription;
 
237
}
 
238
 
 
239
static KoCIExyY RGB2xyY(cmsHPROFILE RGBProfile, qreal red, qreal green, qreal blue)
 
240
{
 
241
    cmsHPROFILE XYZProfile = cmsCreateXYZProfile();
 
242
 
 
243
    const cmsUInt32Number inputFormat = TYPE_RGB_DBL;
 
244
    const cmsUInt32Number outputFormat = TYPE_XYZ_DBL;
 
245
    const cmsUInt32Number transformFlags = cmsFLAGS_LOWRESPRECALC;
 
246
 
 
247
    cmsHTRANSFORM transform = cmsCreateTransform(RGBProfile, inputFormat, XYZProfile, outputFormat,
 
248
                              INTENT_ABSOLUTE_COLORIMETRIC, transformFlags);
 
249
 
 
250
    struct XYZPixel {
 
251
        qreal X;
 
252
        qreal Y;
 
253
        qreal Z;
 
254
    };
 
255
    struct RGBPixel {
 
256
        qreal red;
 
257
        qreal green;
 
258
        qreal blue;
 
259
    };
 
260
 
 
261
    XYZPixel xyzPixel;
 
262
    RGBPixel rgbPixel;
 
263
 
 
264
    rgbPixel.red = red;
 
265
    rgbPixel.green = green;
 
266
    rgbPixel.blue = blue;
 
267
 
 
268
    const unsigned int numPixelsToTransform = 1;
 
269
 
 
270
    cmsDoTransform(transform, &rgbPixel, &xyzPixel, numPixelsToTransform);
 
271
 
 
272
    cmsCIEXYZ xyzPixelXYZ;
 
273
 
 
274
    xyzPixelXYZ.X = xyzPixel.X;
 
275
    xyzPixelXYZ.Y = xyzPixel.Y;
 
276
    xyzPixelXYZ.Z = xyzPixel.Z;
 
277
 
 
278
    cmsCIExyY xyzPixelxyY;
 
279
 
 
280
    cmsXYZ2xyY(&xyzPixelxyY, &xyzPixelXYZ);
 
281
 
 
282
    cmsDeleteTransform(transform);
 
283
    cmsCloseProfile(XYZProfile);
 
284
    KoCIExyY res;
 
285
    lcmsToPigmentViceVersaStructureCopy(res, xyzPixelxyY);
 
286
    return res;
 
287
}
 
288
 
 
289
KoRGBChromaticities* LcmsColorProfileContainer::chromaticitiesFromProfile() const
 
290
{
 
291
    if (cmsGetColorSpace(d->profile) != cmsSigRgbData) return 0;
 
292
 
 
293
    KoRGBChromaticities* chromaticities = new KoRGBChromaticities();
 
294
 
 
295
    chromaticities->primaries.Red = RGB2xyY(d->profile, 1.0f, 0.0f, 0.0f);
 
296
    chromaticities->primaries.Green = RGB2xyY(d->profile, 0.0f, 1.0f, 0.0f);
 
297
    chromaticities->primaries.Blue = RGB2xyY(d->profile, 0.0f, 0.0f, 1.0f);
 
298
    chromaticities->whitePoint = RGB2xyY(d->profile, 1.0f, 1.0f, 1.0f);
 
299
 
 
300
    return chromaticities;
 
301
}