2
* This file is part of the KDE project
3
* Copyright (c) 2000 Matthias Elter <elter@kde.org>
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>
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.
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.
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.
25
#include "LcmsColorProfileContainer.h"
30
#include "DebugPigment.h"
31
#include "KoChromaticities.h"
33
class LcmsColorProfileContainer::Private
36
Private() : valid(false), suitableForOutput(false) { }
39
cmsColorSpaceSignature colorSpaceSignature;
40
cmsProfileClassSignature deviceClass;
41
QString productDescription;
44
IccColorProfile::Data * data;
46
bool suitableForOutput;
49
LcmsColorProfileContainer::LcmsColorProfileContainer()
55
LcmsColorProfileContainer::LcmsColorProfileContainer(IccColorProfile::Data * data)
63
QByteArray LcmsColorProfileContainer::lcmsProfileToByteArray(const cmsHPROFILE profile)
65
cmsUInt32Number bytesNeeded = 0;
66
// Make a raw data image ready for saving
67
cmsSaveProfileToMem(profile, 0, &bytesNeeded); // calc size
69
rawData.resize(bytesNeeded);
70
if (rawData.size() >= (int)bytesNeeded) {
71
cmsSaveProfileToMem(profile, rawData.data(), &bytesNeeded); // fill buffer
73
errorPigment << "Couldn't resize the profile buffer, system is probably running out of memory.";
79
IccColorProfile* LcmsColorProfileContainer::createFromLcmsProfile(const cmsHPROFILE profile)
81
IccColorProfile* iccprofile = new IccColorProfile(lcmsProfileToByteArray(profile));
82
cmsCloseProfile(profile);
86
#define lcmsToPigmentViceVersaStructureCopy(dst, src ) \
91
QByteArray LcmsColorProfileContainer::createFromChromacities(const KoRGBChromaticities& _chromacities, qreal gamma, QString _profileName)
93
cmsCIExyYTRIPLE primaries;
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);
101
const int numTransferFunctions = 3;
102
cmsToneCurve* transferFunctions[numTransferFunctions];
104
for (int i = 0; i < numTransferFunctions; ++i) {
105
transferFunctions[i] = gammaTable;
108
cmsHPROFILE profile = cmsCreateRGBProfile(&whitePoint, &primaries,
110
QString name = _profileName;
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)
125
// icSigProfileDescriptionTag is the compulsory tag and is the profile name
126
// displayed by other applications.
127
cmsWriteTag(profile, cmsSigProfileDescriptionTag, name.toLatin1().data());
129
cmsWriteTag(profile, cmsSigDeviceModelDescTag, name.toLatin1().data());
131
// Clear the default manufacturer's tag that is set to "(lcms internal)"
133
cmsWriteTag(profile, cmsSigDeviceMfgDescTag, ba.data());
135
cmsFreeToneCurve(gammaTable);
136
QByteArray profileArray = lcmsProfileToByteArray(profile);
137
cmsCloseProfile(profile);
141
LcmsColorProfileContainer::~LcmsColorProfileContainer()
143
cmsCloseProfile(d->profile);
147
bool LcmsColorProfileContainer::init()
149
if (d->profile) cmsCloseProfile(d->profile);
151
d->profile = cmsOpenProfileFromMem((void*)d->data->rawData().constData(), d->data->rawData().size());
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.";
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);
166
cmsGetProfileInfo(d->profile, cmsInfoModel, cmsNoLanguage, cmsNoCountry, buffer, 500);
167
d->name = QString::fromWCharArray(buffer);
169
cmsGetProfileInfo(d->profile, cmsInfoManufacturer, cmsNoLanguage, cmsNoCountry, buffer, 500);
170
d->manufacturer = QString::fromWCharArray(buffer);
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) );
181
cmsHPROFILE LcmsColorProfileContainer::lcmsProfile() const
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());
195
cmsColorSpaceSignature LcmsColorProfileContainer::colorSpaceSignature() const
197
return d->colorSpaceSignature;
200
cmsProfileClassSignature LcmsColorProfileContainer::deviceClass() const
202
return d->deviceClass;
205
QString LcmsColorProfileContainer::manufacturer() const
207
return d->manufacturer;
210
bool LcmsColorProfileContainer::valid() const
215
bool LcmsColorProfileContainer::isSuitableForOutput() const
217
return d->suitableForOutput;
220
bool LcmsColorProfileContainer::isSuitableForPrinting() const
222
return deviceClass() == cmsSigOutputClass;
225
bool LcmsColorProfileContainer::isSuitableForDisplay() const
227
return deviceClass() == cmsSigDisplayClass;
230
QString LcmsColorProfileContainer::name() const
234
QString LcmsColorProfileContainer::info() const
236
return d->productDescription;
239
static KoCIExyY RGB2xyY(cmsHPROFILE RGBProfile, qreal red, qreal green, qreal blue)
241
cmsHPROFILE XYZProfile = cmsCreateXYZProfile();
243
const cmsUInt32Number inputFormat = TYPE_RGB_DBL;
244
const cmsUInt32Number outputFormat = TYPE_XYZ_DBL;
245
const cmsUInt32Number transformFlags = cmsFLAGS_LOWRESPRECALC;
247
cmsHTRANSFORM transform = cmsCreateTransform(RGBProfile, inputFormat, XYZProfile, outputFormat,
248
INTENT_ABSOLUTE_COLORIMETRIC, transformFlags);
265
rgbPixel.green = green;
266
rgbPixel.blue = blue;
268
const unsigned int numPixelsToTransform = 1;
270
cmsDoTransform(transform, &rgbPixel, &xyzPixel, numPixelsToTransform);
272
cmsCIEXYZ xyzPixelXYZ;
274
xyzPixelXYZ.X = xyzPixel.X;
275
xyzPixelXYZ.Y = xyzPixel.Y;
276
xyzPixelXYZ.Z = xyzPixel.Z;
278
cmsCIExyY xyzPixelxyY;
280
cmsXYZ2xyY(&xyzPixelxyY, &xyzPixelXYZ);
282
cmsDeleteTransform(transform);
283
cmsCloseProfile(XYZProfile);
285
lcmsToPigmentViceVersaStructureCopy(res, xyzPixelxyY);
289
KoRGBChromaticities* LcmsColorProfileContainer::chromaticitiesFromProfile() const
291
if (cmsGetColorSpace(d->profile) != cmsSigRgbData) return 0;
293
KoRGBChromaticities* chromaticities = new KoRGBChromaticities();
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);
300
return chromaticities;