|
|
|
/* ============================================================
|
|
|
|
*
|
|
|
|
* This file is a part of digiKam project
|
|
|
|
* http://www.digikam.org
|
|
|
|
*
|
|
|
|
* Date : 2005-11-18
|
|
|
|
* Description : a class to apply ICC color correction to image.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2005-2006 by F.J. Cruz <fj.cruz@supercable.es>
|
|
|
|
* Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it
|
|
|
|
* and/or modify it under the terms of the GNU General
|
|
|
|
* Public License as published by the Free Software Foundation;
|
|
|
|
* either version 2, or (at your option)
|
|
|
|
* any later version.
|
|
|
|
*
|
|
|
|
* This program 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 General Public License for more details.
|
|
|
|
*
|
|
|
|
* ============================================================ */
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
// TQt includes.
|
|
|
|
|
|
|
|
#include <tqstring.h>
|
|
|
|
#include <tqcstring.h>
|
|
|
|
#include <tqfile.h>
|
|
|
|
|
|
|
|
// KDE includes.
|
|
|
|
|
|
|
|
#include <kconfig.h>
|
|
|
|
#include <kapplication.h>
|
|
|
|
|
|
|
|
// Lcms includes.
|
|
|
|
|
|
|
|
#include LCMS_HEADER
|
|
|
|
#if LCMS_VERSION < 114
|
|
|
|
#define cmsTakeCopyright(profile) "Unknown"
|
|
|
|
#endif // LCMS_VERSION < 114
|
|
|
|
|
|
|
|
// Local includes.
|
|
|
|
|
|
|
|
#include "ddebug.h"
|
|
|
|
#include "icctransform.h"
|
|
|
|
|
|
|
|
namespace Digikam
|
|
|
|
{
|
|
|
|
|
|
|
|
class IccTransformPriv
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
|
|
|
IccTransformPriv()
|
|
|
|
{
|
|
|
|
has_embedded_profile = false;
|
|
|
|
do_proof_profile = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool do_proof_profile;
|
|
|
|
bool has_embedded_profile;
|
|
|
|
|
|
|
|
TQByteArray embedded_profile;
|
|
|
|
TQByteArray input_profile;
|
|
|
|
TQByteArray output_profile;
|
|
|
|
TQByteArray proof_profile;
|
|
|
|
};
|
|
|
|
|
|
|
|
IccTransform::IccTransform()
|
|
|
|
{
|
|
|
|
d = new IccTransformPriv;
|
|
|
|
cmsErrorAction(LCMS_ERROR_SHOW);
|
|
|
|
}
|
|
|
|
|
|
|
|
IccTransform::~IccTransform()
|
|
|
|
{
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IccTransform::hasInputProfile()
|
|
|
|
{
|
|
|
|
return !(d->input_profile.isEmpty());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IccTransform::hasOutputProfile()
|
|
|
|
{
|
|
|
|
return !(d->output_profile.isEmpty());
|
|
|
|
}
|
|
|
|
|
|
|
|
TQByteArray IccTransform::embeddedProfile() const
|
|
|
|
{
|
|
|
|
return d->embedded_profile;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQByteArray IccTransform::inputProfile() const
|
|
|
|
{
|
|
|
|
return d->input_profile;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQByteArray IccTransform::outputProfile() const
|
|
|
|
{
|
|
|
|
return d->output_profile;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQByteArray IccTransform::proofProfile() const
|
|
|
|
{
|
|
|
|
return d->proof_profile;
|
|
|
|
}
|
|
|
|
|
|
|
|
void IccTransform::getTransformType(bool do_proof_profile)
|
|
|
|
{
|
|
|
|
if (do_proof_profile)
|
|
|
|
{
|
|
|
|
d->do_proof_profile = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
d->do_proof_profile = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void IccTransform::getEmbeddedProfile(const DImg& image)
|
|
|
|
{
|
|
|
|
if (!image.getICCProfil().isNull())
|
|
|
|
{
|
|
|
|
d->embedded_profile = image.getICCProfil();
|
|
|
|
d->has_embedded_profile = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString IccTransform::getProfileDescription(const TQString& profile)
|
|
|
|
{
|
|
|
|
cmsHPROFILE _profile = cmsOpenProfileFromFile(TQFile::encodeName(profile), "r");
|
|
|
|
TQString _description = cmsTakeProductDesc(_profile);
|
|
|
|
cmsCloseProfile(_profile);
|
|
|
|
return _description;
|
|
|
|
}
|
|
|
|
|
|
|
|
int IccTransform::getRenderingIntent()
|
|
|
|
{
|
|
|
|
TDEConfig* config = kapp->config();
|
|
|
|
config->setGroup("Color Management");
|
|
|
|
return config->readNumEntry("RenderingIntent", 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IccTransform::getUseBPC()
|
|
|
|
{
|
|
|
|
TDEConfig* config = kapp->config();
|
|
|
|
config->setGroup("Color Management");
|
|
|
|
return config->readBoolEntry("BPCAlgorithm", false);
|
|
|
|
}
|
|
|
|
|
|
|
|
TQByteArray IccTransform::loadICCProfilFile(const TQString& filePath)
|
|
|
|
{
|
|
|
|
TQFile file(filePath);
|
|
|
|
if ( !file.open(IO_ReadOnly) )
|
|
|
|
return TQByteArray();
|
|
|
|
|
|
|
|
TQByteArray data(file.size());
|
|
|
|
TQDataStream stream( &file );
|
|
|
|
stream.readRawBytes(data.data(), data.size());
|
|
|
|
file.close();
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
void IccTransform::setProfiles(const TQString& input_profile, const TQString& output_profile)
|
|
|
|
{
|
|
|
|
d->input_profile = loadICCProfilFile(input_profile);
|
|
|
|
d->output_profile = loadICCProfilFile(output_profile);
|
|
|
|
}
|
|
|
|
|
|
|
|
void IccTransform::setProfiles(const TQString& input_profile, const TQString& output_profile,
|
|
|
|
const TQString& proof_profile)
|
|
|
|
{
|
|
|
|
d->input_profile = loadICCProfilFile(input_profile);
|
|
|
|
d->output_profile = loadICCProfilFile(output_profile);
|
|
|
|
d->proof_profile = loadICCProfilFile(proof_profile);
|
|
|
|
}
|
|
|
|
|
|
|
|
void IccTransform::setProfiles(const TQString& output_profile)
|
|
|
|
{
|
|
|
|
d->output_profile = loadICCProfilFile(output_profile);
|
|
|
|
}
|
|
|
|
|
|
|
|
void IccTransform::setProfiles(const TQString& output_profile, const TQString& proof_profile, bool forProof)
|
|
|
|
{
|
|
|
|
if (forProof)
|
|
|
|
{
|
|
|
|
d->output_profile = loadICCProfilFile(output_profile);
|
|
|
|
d->proof_profile = loadICCProfilFile(proof_profile);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString IccTransform::getEmbeddedProfileDescriptor()
|
|
|
|
{
|
|
|
|
if (d->embedded_profile.isEmpty())
|
|
|
|
return TQString();
|
|
|
|
|
|
|
|
cmsHPROFILE tmpProfile = cmsOpenProfileFromMem(d->embedded_profile.data(),
|
|
|
|
(DWORD)d->embedded_profile.size());
|
|
|
|
TQString embeddedProfileDescriptor = TQString(cmsTakeProductDesc(tmpProfile));
|
|
|
|
cmsCloseProfile(tmpProfile);
|
|
|
|
return embeddedProfileDescriptor;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString IccTransform::getInputProfileDescriptor()
|
|
|
|
{
|
|
|
|
if (d->input_profile.isEmpty()) return TQString();
|
|
|
|
cmsHPROFILE tmpProfile = cmsOpenProfileFromMem(d->input_profile.data(), (DWORD)d->input_profile.size());
|
|
|
|
TQString embeddedProfileDescriptor = TQString(cmsTakeProductDesc(tmpProfile));
|
|
|
|
cmsCloseProfile(tmpProfile);
|
|
|
|
return embeddedProfileDescriptor;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString IccTransform::getOutpoutProfileDescriptor()
|
|
|
|
{
|
|
|
|
if (d->output_profile.isEmpty()) return TQString();
|
|
|
|
cmsHPROFILE tmpProfile = cmsOpenProfileFromMem(d->output_profile.data(), (DWORD)d->output_profile.size());
|
|
|
|
TQString embeddedProfileDescriptor = TQString(cmsTakeProductDesc(tmpProfile));
|
|
|
|
cmsCloseProfile(tmpProfile);
|
|
|
|
return embeddedProfileDescriptor;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString IccTransform::getProofProfileDescriptor()
|
|
|
|
{
|
|
|
|
if (d->proof_profile.isEmpty()) return TQString();
|
|
|
|
cmsHPROFILE tmpProfile = cmsOpenProfileFromMem(d->proof_profile.data(), (DWORD)d->proof_profile.size());
|
|
|
|
TQString embeddedProfileDescriptor = TQString(cmsTakeProductDesc(tmpProfile));
|
|
|
|
cmsCloseProfile(tmpProfile);
|
|
|
|
return embeddedProfileDescriptor;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IccTransform::apply(DImg& image)
|
|
|
|
{
|
|
|
|
cmsHPROFILE inprofile=0, outprofile=0, proofprofile=0;
|
|
|
|
cmsHTRANSFORM transform;
|
|
|
|
int inputFormat = 0;
|
|
|
|
int intent = INTENT_PERCEPTUAL;
|
|
|
|
|
|
|
|
switch (getRenderingIntent())
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
intent = INTENT_PERCEPTUAL;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
intent = INTENT_RELATIVE_COLORIMETRIC;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
intent = INTENT_SATURATION;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
intent = INTENT_ABSOLUTE_COLORIMETRIC;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
//DDebug() << "Intent is: " << intent << endl;
|
|
|
|
|
|
|
|
if (d->has_embedded_profile)
|
|
|
|
{
|
|
|
|
inprofile = cmsOpenProfileFromMem(d->embedded_profile.data(),
|
|
|
|
(DWORD)d->embedded_profile.size());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
inprofile = cmsOpenProfileFromMem(d->input_profile.data(),
|
|
|
|
(DWORD)d->input_profile.size());
|
|
|
|
}
|
|
|
|
if (inprofile == NULL)
|
|
|
|
{
|
|
|
|
DDebug() << "Error: Input profile is NULL" << endl;
|
|
|
|
cmsCloseProfile(inprofile);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if (d->has_embedded_profile)
|
|
|
|
// {
|
|
|
|
// outprofile = cmsOpenProfileFromMem(d->embedded_profile.data(),
|
|
|
|
// (DWORD)d->embedded_profile.size());
|
|
|
|
// }
|
|
|
|
// else
|
|
|
|
// {
|
|
|
|
outprofile = cmsOpenProfileFromMem(d->output_profile.data(),
|
|
|
|
(DWORD)d->output_profile.size());
|
|
|
|
// }
|
|
|
|
|
|
|
|
if (outprofile == NULL)
|
|
|
|
{
|
|
|
|
DDebug() << "Error: Output profile is NULL" << endl;
|
|
|
|
cmsCloseProfile(outprofile);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!d->do_proof_profile)
|
|
|
|
{
|
|
|
|
if (image.sixteenBit())
|
|
|
|
{
|
|
|
|
if (image.hasAlpha())
|
|
|
|
{
|
|
|
|
switch (cmsGetColorSpace(inprofile))
|
|
|
|
{
|
|
|
|
case icSigGrayData:
|
|
|
|
inputFormat = TYPE_GRAYA_16;
|
|
|
|
break;
|
|
|
|
case icSigCmykData:
|
|
|
|
inputFormat = TYPE_CMYK_16;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
inputFormat = TYPE_BGRA_16;
|
|
|
|
}
|
|
|
|
|
|
|
|
transform = cmsCreateTransform( inprofile,
|
|
|
|
inputFormat,
|
|
|
|
outprofile,
|
|
|
|
TYPE_BGRA_16,
|
|
|
|
intent,
|
|
|
|
cmsFLAGS_WHITEBLACKCOMPENSATION);
|
|
|
|
|
|
|
|
if (!transform)
|
|
|
|
{
|
|
|
|
DDebug() << k_funcinfo << "LCMS internal error: cannot create a color transform instance" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
switch (cmsGetColorSpace(inprofile))
|
|
|
|
{
|
|
|
|
case icSigGrayData:
|
|
|
|
inputFormat = TYPE_GRAY_16;
|
|
|
|
break;
|
|
|
|
case icSigCmykData:
|
|
|
|
inputFormat = TYPE_CMYK_16;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
inputFormat = TYPE_BGR_16;
|
|
|
|
}
|
|
|
|
|
|
|
|
transform = cmsCreateTransform( inprofile,
|
|
|
|
inputFormat,
|
|
|
|
outprofile,
|
|
|
|
TYPE_BGR_16,
|
|
|
|
intent,
|
|
|
|
cmsFLAGS_WHITEBLACKCOMPENSATION);
|
|
|
|
|
|
|
|
if (!transform)
|
|
|
|
{
|
|
|
|
DDebug() << k_funcinfo << "LCMS internal error: cannot create a color transform instance" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (image.hasAlpha())
|
|
|
|
{
|
|
|
|
switch (cmsGetColorSpace(inprofile))
|
|
|
|
{
|
|
|
|
case icSigGrayData:
|
|
|
|
inputFormat = TYPE_GRAYA_8;
|
|
|
|
break;
|
|
|
|
case icSigCmykData:
|
|
|
|
inputFormat = TYPE_CMYK_8;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
inputFormat = TYPE_BGRA_8;
|
|
|
|
}
|
|
|
|
|
|
|
|
transform = cmsCreateTransform( inprofile,
|
|
|
|
inputFormat,
|
|
|
|
outprofile,
|
|
|
|
TYPE_BGRA_8,
|
|
|
|
intent,
|
|
|
|
cmsFLAGS_WHITEBLACKCOMPENSATION);
|
|
|
|
|
|
|
|
if (!transform)
|
|
|
|
{
|
|
|
|
DDebug() << k_funcinfo << "LCMS internal error: cannot create a color transform instance" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
switch (cmsGetColorSpace(inprofile))
|
|
|
|
{
|
|
|
|
case icSigGrayData:
|
|
|
|
inputFormat = TYPE_GRAYA_8;
|
|
|
|
break;
|
|
|
|
case icSigCmykData:
|
|
|
|
inputFormat = TYPE_CMYK_8;
|
|
|
|
//DDebug() << "input profile: cmyk no alpha" << endl;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
inputFormat = TYPE_BGR_8;
|
|
|
|
//DDebug() << "input profile: default no alpha" << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
transform = cmsCreateTransform(inprofile, inputFormat, outprofile,
|
|
|
|
TYPE_BGR_8, intent,
|
|
|
|
cmsFLAGS_WHITEBLACKCOMPENSATION);
|
|
|
|
|
|
|
|
if (!transform)
|
|
|
|
{
|
|
|
|
DDebug() << k_funcinfo << "LCMS internal error: cannot create a color transform instance" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
proofprofile = cmsOpenProfileFromMem(d->proof_profile.data(),
|
|
|
|
(DWORD)d->proof_profile.size());
|
|
|
|
|
|
|
|
if (proofprofile == NULL)
|
|
|
|
{
|
|
|
|
DDebug() << "Error: Input profile is NULL" << endl;
|
|
|
|
cmsCloseProfile(inprofile);
|
|
|
|
cmsCloseProfile(outprofile);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (image.sixteenBit())
|
|
|
|
{
|
|
|
|
if (image.hasAlpha())
|
|
|
|
{
|
|
|
|
transform = cmsCreateProofingTransform( inprofile,
|
|
|
|
TYPE_BGRA_16,
|
|
|
|
outprofile,
|
|
|
|
TYPE_BGRA_16,
|
|
|
|
proofprofile,
|
|
|
|
INTENT_ABSOLUTE_COLORIMETRIC,
|
|
|
|
INTENT_ABSOLUTE_COLORIMETRIC,
|
|
|
|
cmsFLAGS_WHITEBLACKCOMPENSATION);
|
|
|
|
|
|
|
|
if (!transform)
|
|
|
|
{
|
|
|
|
DDebug() << k_funcinfo << "LCMS internal error: cannot create a color transform instance" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
transform = cmsCreateProofingTransform( inprofile,
|
|
|
|
TYPE_BGR_16,
|
|
|
|
outprofile,
|
|
|
|
TYPE_BGR_16,
|
|
|
|
proofprofile,
|
|
|
|
INTENT_ABSOLUTE_COLORIMETRIC,
|
|
|
|
INTENT_ABSOLUTE_COLORIMETRIC,
|
|
|
|
cmsFLAGS_WHITEBLACKCOMPENSATION);
|
|
|
|
|
|
|
|
if (!transform)
|
|
|
|
{
|
|
|
|
DDebug() << k_funcinfo << "LCMS internal error: cannot create a color transform instance" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (image.hasAlpha())
|
|
|
|
{
|
|
|
|
transform = cmsCreateProofingTransform( inprofile,
|
|
|
|
TYPE_BGR_8,
|
|
|
|
outprofile,
|
|
|
|
TYPE_BGR_8,
|
|
|
|
proofprofile,
|
|
|
|
INTENT_ABSOLUTE_COLORIMETRIC,
|
|
|
|
INTENT_ABSOLUTE_COLORIMETRIC,
|
|
|
|
cmsFLAGS_WHITEBLACKCOMPENSATION);
|
|
|
|
|
|
|
|
if (!transform)
|
|
|
|
{
|
|
|
|
DDebug() << k_funcinfo << "LCMS internal error: cannot create a color transform instance" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
transform = cmsCreateProofingTransform( inprofile,
|
|
|
|
TYPE_BGR_8,
|
|
|
|
outprofile,
|
|
|
|
TYPE_BGR_8,
|
|
|
|
proofprofile,
|
|
|
|
INTENT_ABSOLUTE_COLORIMETRIC,
|
|
|
|
INTENT_ABSOLUTE_COLORIMETRIC,
|
|
|
|
cmsFLAGS_WHITEBLACKCOMPENSATION);
|
|
|
|
|
|
|
|
if (!transform)
|
|
|
|
{
|
|
|
|
DDebug() << k_funcinfo << "LCMS internal error: cannot create a color transform instance" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// We need to work using temp pixel buffer to apply ICC transformations.
|
|
|
|
uchar transdata[image.bytesDepth()];
|
|
|
|
|
|
|
|
// Always working with uchar* prevent endianess problem.
|
|
|
|
uchar *data = image.bits();
|
|
|
|
|
|
|
|
// We scan all image pixels one by one.
|
|
|
|
for (uint i=0; i < image.width()*image.height()*image.bytesDepth(); i+=image.bytesDepth())
|
|
|
|
{
|
|
|
|
// Apply ICC transformations.
|
|
|
|
cmsDoTransform( transform, &data[i], &transdata[0], 1);
|
|
|
|
|
|
|
|
// Copy buffer to source to update original image with ICC corrections.
|
|
|
|
// Alpha channel is restored in all cases.
|
|
|
|
memcpy (&data[i], &transdata[0], (image.bytesDepth() == 8) ? 6 : 3);
|
|
|
|
}
|
|
|
|
|
|
|
|
cmsDeleteTransform(transform);
|
|
|
|
cmsCloseProfile(inprofile);
|
|
|
|
cmsCloseProfile(outprofile);
|
|
|
|
|
|
|
|
if (d->do_proof_profile)
|
|
|
|
cmsCloseProfile(proofprofile);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IccTransform::apply( DImg& image, TQByteArray& profile, int intent, bool useBPC,
|
|
|
|
bool checkGamut, bool useBuiltin )
|
|
|
|
{
|
|
|
|
cmsHPROFILE inprofile=0, outprofile=0, proofprofile=0;
|
|
|
|
cmsHTRANSFORM transform;
|
|
|
|
int transformFlags = 0, inputFormat = 0;
|
|
|
|
|
|
|
|
switch (intent)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
intent = INTENT_PERCEPTUAL;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
intent = INTENT_RELATIVE_COLORIMETRIC;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
intent = INTENT_SATURATION;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
intent = INTENT_ABSOLUTE_COLORIMETRIC;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
//DDebug() << "Intent is: " << intent << endl;
|
|
|
|
|
|
|
|
if (!profile.isNull())
|
|
|
|
{
|
|
|
|
inprofile = cmsOpenProfileFromMem(profile.data(),
|
|
|
|
(DWORD)profile.size());
|
|
|
|
}
|
|
|
|
else if (useBuiltin)
|
|
|
|
{
|
|
|
|
inprofile = cmsCreate_sRGBProfile();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
inprofile = cmsOpenProfileFromMem(d->input_profile.data(),
|
|
|
|
(DWORD)d->input_profile.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (inprofile == NULL)
|
|
|
|
{
|
|
|
|
DDebug() << "Error: Input profile is NULL" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
outprofile = cmsOpenProfileFromMem(d->output_profile.data(),
|
|
|
|
(DWORD)d->output_profile.size());
|
|
|
|
|
|
|
|
if (outprofile == NULL)
|
|
|
|
{
|
|
|
|
DDebug() << "Error: Output profile is NULL" << endl;
|
|
|
|
cmsCloseProfile(inprofile);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (useBPC)
|
|
|
|
{
|
|
|
|
transformFlags |= cmsFLAGS_WHITEBLACKCOMPENSATION;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!d->do_proof_profile)
|
|
|
|
{
|
|
|
|
if (image.sixteenBit())
|
|
|
|
{
|
|
|
|
if (image.hasAlpha())
|
|
|
|
{
|
|
|
|
switch (cmsGetColorSpace(inprofile))
|
|
|
|
{
|
|
|
|
case icSigGrayData:
|
|
|
|
inputFormat = TYPE_GRAYA_16;
|
|
|
|
break;
|
|
|
|
case icSigCmykData:
|
|
|
|
inputFormat = TYPE_CMYK_16;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
inputFormat = TYPE_BGRA_16;
|
|
|
|
}
|
|
|
|
|
|
|
|
transform = cmsCreateTransform( inprofile,
|
|
|
|
inputFormat,
|
|
|
|
outprofile,
|
|
|
|
TYPE_BGRA_16,
|
|
|
|
intent,
|
|
|
|
transformFlags);
|
|
|
|
|
|
|
|
if (!transform)
|
|
|
|
{
|
|
|
|
DDebug() << k_funcinfo << "LCMS internal error: cannot create a color transform instance" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
switch (cmsGetColorSpace(inprofile))
|
|
|
|
{
|
|
|
|
case icSigGrayData:
|
|
|
|
inputFormat = TYPE_GRAY_16;
|
|
|
|
break;
|
|
|
|
case icSigCmykData:
|
|
|
|
inputFormat = TYPE_CMYK_16;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
inputFormat = TYPE_BGR_16;
|
|
|
|
}
|
|
|
|
|
|
|
|
transform = cmsCreateTransform( inprofile,
|
|
|
|
inputFormat,
|
|
|
|
outprofile,
|
|
|
|
TYPE_BGR_16,
|
|
|
|
intent,
|
|
|
|
transformFlags);
|
|
|
|
|
|
|
|
if (!transform)
|
|
|
|
{
|
|
|
|
DDebug() << k_funcinfo << "LCMS internal error: cannot create a color transform instance" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (image.hasAlpha())
|
|
|
|
{
|
|
|
|
switch (cmsGetColorSpace(inprofile))
|
|
|
|
{
|
|
|
|
case icSigGrayData:
|
|
|
|
inputFormat = TYPE_GRAYA_8;
|
|
|
|
break;
|
|
|
|
case icSigCmykData:
|
|
|
|
inputFormat = TYPE_CMYK_8;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
inputFormat = TYPE_BGRA_8;
|
|
|
|
}
|
|
|
|
|
|
|
|
transform = cmsCreateTransform( inprofile,
|
|
|
|
inputFormat,
|
|
|
|
outprofile,
|
|
|
|
TYPE_BGRA_8,
|
|
|
|
intent,
|
|
|
|
transformFlags);
|
|
|
|
|
|
|
|
if (!transform)
|
|
|
|
{
|
|
|
|
DDebug() << k_funcinfo << "LCMS internal error: cannot create a color transform instance" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
switch (cmsGetColorSpace(inprofile))
|
|
|
|
{
|
|
|
|
case icSigGrayData:
|
|
|
|
inputFormat = TYPE_GRAY_8;
|
|
|
|
break;
|
|
|
|
case icSigCmykData:
|
|
|
|
inputFormat = TYPE_CMYK_8;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
inputFormat = TYPE_BGR_8;
|
|
|
|
}
|
|
|
|
|
|
|
|
transform = cmsCreateTransform( inprofile,
|
|
|
|
inputFormat,
|
|
|
|
outprofile,
|
|
|
|
TYPE_BGR_8,
|
|
|
|
intent,
|
|
|
|
transformFlags);
|
|
|
|
|
|
|
|
if (!transform)
|
|
|
|
{
|
|
|
|
DDebug() << k_funcinfo << "LCMS internal error: cannot create a color transform instance" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
proofprofile = cmsOpenProfileFromMem(d->proof_profile.data(),
|
|
|
|
(DWORD)d->proof_profile.size());
|
|
|
|
|
|
|
|
if (proofprofile == NULL)
|
|
|
|
{
|
|
|
|
DDebug() << "Error: Input profile is NULL" << endl;
|
|
|
|
cmsCloseProfile(inprofile);
|
|
|
|
cmsCloseProfile(outprofile);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
transformFlags |= cmsFLAGS_SOFTPROOFING;
|
|
|
|
if (checkGamut)
|
|
|
|
{
|
|
|
|
cmsSetAlarmCodes(126, 255, 255);
|
|
|
|
transformFlags |= cmsFLAGS_GAMUTCHECK;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (image.sixteenBit())
|
|
|
|
{
|
|
|
|
if (image.hasAlpha())
|
|
|
|
{
|
|
|
|
transform = cmsCreateProofingTransform( inprofile,
|
|
|
|
TYPE_BGRA_16,
|
|
|
|
outprofile,
|
|
|
|
TYPE_BGRA_16,
|
|
|
|
proofprofile,
|
|
|
|
intent,
|
|
|
|
intent,
|
|
|
|
transformFlags);
|
|
|
|
|
|
|
|
if (!transform)
|
|
|
|
{
|
|
|
|
DDebug() << k_funcinfo << "LCMS internal error: cannot create a color transform instance" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
transform = cmsCreateProofingTransform( inprofile,
|
|
|
|
TYPE_BGR_16,
|
|
|
|
outprofile,
|
|
|
|
TYPE_BGR_16,
|
|
|
|
proofprofile,
|
|
|
|
intent,
|
|
|
|
intent,
|
|
|
|
transformFlags);
|
|
|
|
|
|
|
|
if (!transform)
|
|
|
|
{
|
|
|
|
DDebug() << k_funcinfo << "LCMS internal error: cannot create a color transform instance" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (image.hasAlpha())
|
|
|
|
{
|
|
|
|
transform = cmsCreateProofingTransform( inprofile,
|
|
|
|
TYPE_BGR_8,
|
|
|
|
outprofile,
|
|
|
|
TYPE_BGR_8,
|
|
|
|
proofprofile,
|
|
|
|
intent,
|
|
|
|
intent,
|
|
|
|
transformFlags);
|
|
|
|
|
|
|
|
if (!transform)
|
|
|
|
{
|
|
|
|
DDebug() << k_funcinfo << "LCMS internal error: cannot create a color transform instance" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
transform = cmsCreateProofingTransform( inprofile,
|
|
|
|
TYPE_BGR_8,
|
|
|
|
outprofile,
|
|
|
|
TYPE_BGR_8,
|
|
|
|
proofprofile,
|
|
|
|
intent,
|
|
|
|
intent,
|
|
|
|
transformFlags);
|
|
|
|
|
|
|
|
if (!transform)
|
|
|
|
{
|
|
|
|
DDebug() << k_funcinfo << "LCMS internal error: cannot create a color transform instance" << endl;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//DDebug() << "Transform flags are: " << transformFlags << endl;
|
|
|
|
|
|
|
|
// We need to work using temp pixel buffer to apply ICC transformations.
|
|
|
|
uchar transdata[image.bytesDepth()];
|
|
|
|
|
|
|
|
// Always working with uchar* prevent endianess problem.
|
|
|
|
uchar *data = image.bits();
|
|
|
|
|
|
|
|
// We scan all image pixels one by one.
|
|
|
|
for (uint i=0; i < image.width()*image.height()*image.bytesDepth(); i+=image.bytesDepth())
|
|
|
|
{
|
|
|
|
// Apply ICC transformations.
|
|
|
|
cmsDoTransform( transform, &data[i], &transdata[0], 1);
|
|
|
|
|
|
|
|
// Copy buffer to source to update original image with ICC corrections.
|
|
|
|
// Alpha channel is restored in all cases.
|
|
|
|
memcpy (&data[i], &transdata[0], (image.bytesDepth() == 8) ? 6 : 3);
|
|
|
|
}
|
|
|
|
|
|
|
|
cmsDeleteTransform(transform);
|
|
|
|
cmsCloseProfile(inprofile);
|
|
|
|
cmsCloseProfile(outprofile);
|
|
|
|
|
|
|
|
if (d->do_proof_profile)
|
|
|
|
cmsCloseProfile(proofprofile);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // NameSpace Digikam
|