mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-03-10 00:10:10 +01:00
Color management - custom icc profiles
This commit is contained in:
parent
189836d76c
commit
0c7b0e6c3d
@ -42,7 +42,7 @@ public:
|
|||||||
virtual QColor getColorFromDeviceRGB(const PDFColor& color, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
|
virtual QColor getColorFromDeviceRGB(const PDFColor& color, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
|
||||||
virtual QColor getColorFromDeviceCMYK(const PDFColor& color, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
|
virtual QColor getColorFromDeviceCMYK(const PDFColor& color, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
|
||||||
virtual QColor getColorFromXYZ(const PDFColor3& whitePoint, const PDFColor3& color, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
|
virtual QColor getColorFromXYZ(const PDFColor3& whitePoint, const PDFColor3& color, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
|
||||||
virtual QColor getColorFromICC(const PDFColor& color, const QByteArray& iccID, const QByteArray& iccData) const override;
|
virtual QColor getColorFromICC(const PDFColor& color, RenderingIntent renderingIntent, const QByteArray& iccID, const QByteArray& iccData, PDFRenderErrorReporter* reporter) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void init();
|
void init();
|
||||||
@ -99,6 +99,9 @@ private:
|
|||||||
|
|
||||||
mutable QReadWriteLock m_transformationCacheLock;
|
mutable QReadWriteLock m_transformationCacheLock;
|
||||||
mutable std::unordered_map<int, cmsHTRANSFORM> m_transformationCache;
|
mutable std::unordered_map<int, cmsHTRANSFORM> m_transformationCache;
|
||||||
|
|
||||||
|
mutable QReadWriteLock m_customIccProfileCacheLock;
|
||||||
|
mutable std::map<std::pair<QByteArray, RenderingIntent>, cmsHTRANSFORM> m_customIccProfileCache;
|
||||||
};
|
};
|
||||||
|
|
||||||
PDFLittleCMS::PDFLittleCMS(const PDFCMSManager* manager, const PDFCMSSettings& settings) :
|
PDFLittleCMS::PDFLittleCMS(const PDFCMSManager* manager, const PDFCMSSettings& settings) :
|
||||||
@ -121,6 +124,15 @@ PDFLittleCMS::~PDFLittleCMS()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const auto& transformItem : m_customIccProfileCache)
|
||||||
|
{
|
||||||
|
cmsHTRANSFORM transform = transformItem.second;
|
||||||
|
if (transform)
|
||||||
|
{
|
||||||
|
cmsDeleteTransform(transform);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (cmsHPROFILE profile : m_profiles)
|
for (cmsHPROFILE profile : m_profiles)
|
||||||
{
|
{
|
||||||
if (profile)
|
if (profile)
|
||||||
@ -249,9 +261,71 @@ QColor PDFLittleCMS::getColorFromXYZ(const PDFColor3& whitePoint, const PDFColor
|
|||||||
return QColor();
|
return QColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
QColor PDFLittleCMS::getColorFromICC(const PDFColor& color, const QByteArray& iccID, const QByteArray& iccData) const
|
QColor PDFLittleCMS::getColorFromICC(const PDFColor& color, RenderingIntent renderingIntent, const QByteArray& iccID, const QByteArray& iccData, PDFRenderErrorReporter* reporter) const
|
||||||
{
|
{
|
||||||
// TODO: Dodelat ICC profily
|
cmsHTRANSFORM transform = cmsHTRANSFORM();
|
||||||
|
|
||||||
|
{
|
||||||
|
RenderingIntent effectiveRenderingIntent = getEffectiveRenderingIntent(renderingIntent);
|
||||||
|
const auto key = std::make_pair(iccID, effectiveRenderingIntent);
|
||||||
|
QReadLocker lock(&m_customIccProfileCacheLock);
|
||||||
|
auto it = m_customIccProfileCache.find(key);
|
||||||
|
if (it == m_customIccProfileCache.cend())
|
||||||
|
{
|
||||||
|
lock.unlock();
|
||||||
|
QWriteLocker writeLock(&m_customIccProfileCacheLock);
|
||||||
|
|
||||||
|
// Now, we have locked cache for writing. We must find out,
|
||||||
|
// if some other thread doesn't created the transformation already.
|
||||||
|
it = m_customIccProfileCache.find(key);
|
||||||
|
if (it == m_customIccProfileCache.cend())
|
||||||
|
{
|
||||||
|
cmsHPROFILE profile = cmsOpenProfileFromMem(iccData.data(), iccData.size());
|
||||||
|
if (profile)
|
||||||
|
{
|
||||||
|
if (const cmsUInt32Number inputDataFormat = getProfileDataFormat(profile))
|
||||||
|
{
|
||||||
|
cmsUInt32Number lcmsIntent = getLittleCMSRenderingIntent(effectiveRenderingIntent);
|
||||||
|
transform = cmsCreateTransform(profile, inputDataFormat, m_profiles[Output], TYPE_RGB_FLT, lcmsIntent, getTransformationFlags());
|
||||||
|
}
|
||||||
|
cmsCloseProfile(profile);
|
||||||
|
}
|
||||||
|
|
||||||
|
it = m_customIccProfileCache.insert(std::make_pair(key, transform)).first;
|
||||||
|
}
|
||||||
|
|
||||||
|
transform = it->second;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
transform = it->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!transform)
|
||||||
|
{
|
||||||
|
reporter->reportRenderErrorOnce(RenderErrorType::Error, PDFTranslationContext::tr("Conversion from icc profile space to output device using CMS failed."));
|
||||||
|
return QColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<float, 4> inputBuffer = { };
|
||||||
|
const cmsUInt32Number channels = T_CHANNELS(cmsGetTransformInputFormat(transform));
|
||||||
|
if (channels == color.size() && channels <= inputBuffer.size())
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < color.size(); ++i)
|
||||||
|
{
|
||||||
|
inputBuffer[i] = color[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<float, 3> rgbOutputColor = { };
|
||||||
|
cmsDoTransform(transform, inputBuffer.data(), rgbOutputColor.data(), 1);
|
||||||
|
return getColorFromOutputColor(rgbOutputColor);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
reporter->reportRenderErrorOnce(RenderErrorType::Error, PDFTranslationContext::tr("Conversion from icc profile space to output device using CMS failed - invalid data format."));
|
||||||
|
}
|
||||||
|
|
||||||
return QColor();
|
return QColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -468,7 +542,6 @@ cmsUInt32Number PDFLittleCMS::getProfileDataFormat(cmsHPROFILE profile)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_ASSERT(false);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -562,11 +635,17 @@ QColor PDFCMSGeneric::getColorFromXYZ(const PDFColor3& whitePoint, const PDFColo
|
|||||||
return QColor();
|
return QColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
QColor PDFCMSGeneric::getColorFromICC(const PDFColor& color, const QByteArray& iccID, const QByteArray& iccData) const
|
QColor PDFCMSGeneric::getColorFromICC(const PDFColor& color,
|
||||||
|
RenderingIntent renderingIntent,
|
||||||
|
const QByteArray& iccID,
|
||||||
|
const QByteArray& iccData,
|
||||||
|
PDFRenderErrorReporter* reporter) const
|
||||||
{
|
{
|
||||||
Q_UNUSED(color);
|
Q_UNUSED(color);
|
||||||
|
Q_UNUSED(renderingIntent);
|
||||||
Q_UNUSED(iccID);
|
Q_UNUSED(iccID);
|
||||||
Q_UNUSED(iccData);
|
Q_UNUSED(iccData);
|
||||||
|
Q_UNUSED(reporter);
|
||||||
return QColor();
|
return QColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,7 +128,7 @@ public:
|
|||||||
/// \param color Input color
|
/// \param color Input color
|
||||||
/// \param iccID Unique ICC profile identifier
|
/// \param iccID Unique ICC profile identifier
|
||||||
/// \param iccData Color profile data
|
/// \param iccData Color profile data
|
||||||
virtual QColor getColorFromICC(const PDFColor& color, const QByteArray& iccID, const QByteArray& iccData) const = 0;
|
virtual QColor getColorFromICC(const PDFColor& color, RenderingIntent renderingIntent, const QByteArray& iccID, const QByteArray& iccData, PDFRenderErrorReporter* reporter) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
using PDFCMSPointer = QSharedPointer<PDFCMS>;
|
using PDFCMSPointer = QSharedPointer<PDFCMS>;
|
||||||
@ -144,7 +144,7 @@ public:
|
|||||||
virtual QColor getColorFromDeviceRGB(const PDFColor& color, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
|
virtual QColor getColorFromDeviceRGB(const PDFColor& color, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
|
||||||
virtual QColor getColorFromDeviceCMYK(const PDFColor& color, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
|
virtual QColor getColorFromDeviceCMYK(const PDFColor& color, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
|
||||||
virtual QColor getColorFromXYZ(const PDFColor3& whitePoint, const PDFColor3& color, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
|
virtual QColor getColorFromXYZ(const PDFColor3& whitePoint, const PDFColor3& color, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
|
||||||
virtual QColor getColorFromICC(const PDFColor& color, const QByteArray& iccID, const QByteArray& iccData) const override;
|
virtual QColor getColorFromICC(const PDFColor& color, RenderingIntent renderingIntent, const QByteArray& iccID, const QByteArray& iccData, PDFRenderErrorReporter* reporter) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PDFColorProfileIdentifier
|
struct PDFColorProfileIdentifier
|
||||||
|
@ -887,7 +887,7 @@ QColor PDFICCBasedColorSpace::getColor(const PDFColor& color, const PDFCMS* cms,
|
|||||||
clippedColor[i] = qBound(m_range[imin], clippedColor[i], m_range[imax]);
|
clippedColor[i] = qBound(m_range[imin], clippedColor[i], m_range[imax]);
|
||||||
}
|
}
|
||||||
|
|
||||||
QColor cmsColor = cms->getColorFromICC(clippedColor, m_iccProfileDataChecksum, m_iccProfileData);
|
QColor cmsColor = cms->getColorFromICC(clippedColor, intent, m_iccProfileDataChecksum, m_iccProfileData, reporter);
|
||||||
if (cmsColor.isValid())
|
if (cmsColor.isValid())
|
||||||
{
|
{
|
||||||
return cmsColor;
|
return cmsColor;
|
||||||
|
@ -24,6 +24,11 @@
|
|||||||
#include <openjpeg.h>
|
#include <openjpeg.h>
|
||||||
#include <openssl/opensslv.h>
|
#include <openssl/opensslv.h>
|
||||||
|
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable:5033)
|
||||||
|
#include <lcms2.h>
|
||||||
|
#pragma warning(pop)
|
||||||
|
|
||||||
namespace pdf
|
namespace pdf
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -260,6 +265,16 @@ std::vector<PDFDependentLibraryInfo> PDFDependentLibraryInfo::getLibraryInfo()
|
|||||||
opensslInfo.url = tr("https://www.openssl.org/");
|
opensslInfo.url = tr("https://www.openssl.org/");
|
||||||
result.emplace_back(qMove(opensslInfo));
|
result.emplace_back(qMove(opensslInfo));
|
||||||
|
|
||||||
|
// LittleCMS 2.x
|
||||||
|
const int lcmsMajor = LCMS_VERSION / 1000;
|
||||||
|
const int lcmsMinor = (LCMS_VERSION % 1000) / 10;
|
||||||
|
PDFDependentLibraryInfo lcms2Info;
|
||||||
|
lcms2Info.library = tr("LittleCMS");
|
||||||
|
lcms2Info.license = tr("2-clause MIT license");
|
||||||
|
lcms2Info.version = tr("%1.%2").arg(lcmsMajor).arg(lcmsMinor);;
|
||||||
|
lcms2Info.url = tr("http://www.littlecms.com/");
|
||||||
|
result.emplace_back(qMove(lcms2Info));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user