mirror of
				https://github.com/JakubMelka/PDF4QT.git
				synced 2025-06-05 21:59:17 +02:00 
			
		
		
		
	Color management - custom icc profiles
This commit is contained in:
		@@ -42,7 +42,7 @@ public:
 | 
			
		||||
    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 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:
 | 
			
		||||
    void init();
 | 
			
		||||
@@ -99,6 +99,9 @@ private:
 | 
			
		||||
 | 
			
		||||
    mutable QReadWriteLock m_transformationCacheLock;
 | 
			
		||||
    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) :
 | 
			
		||||
@@ -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)
 | 
			
		||||
    {
 | 
			
		||||
        if (profile)
 | 
			
		||||
@@ -249,9 +261,71 @@ QColor PDFLittleCMS::getColorFromXYZ(const PDFColor3& whitePoint, const PDFColor
 | 
			
		||||
    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();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -468,7 +542,6 @@ cmsUInt32Number PDFLittleCMS::getProfileDataFormat(cmsHPROFILE profile)
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Q_ASSERT(false);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -562,11 +635,17 @@ QColor PDFCMSGeneric::getColorFromXYZ(const PDFColor3& whitePoint, const PDFColo
 | 
			
		||||
    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(renderingIntent);
 | 
			
		||||
    Q_UNUSED(iccID);
 | 
			
		||||
    Q_UNUSED(iccData);
 | 
			
		||||
    Q_UNUSED(reporter);
 | 
			
		||||
    return QColor();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -128,7 +128,7 @@ public:
 | 
			
		||||
    /// \param color Input color
 | 
			
		||||
    /// \param iccID Unique ICC profile identifier
 | 
			
		||||
    /// \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>;
 | 
			
		||||
@@ -144,7 +144,7 @@ public:
 | 
			
		||||
    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 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
 | 
			
		||||
 
 | 
			
		||||
@@ -887,7 +887,7 @@ QColor PDFICCBasedColorSpace::getColor(const PDFColor& color, const PDFCMS* cms,
 | 
			
		||||
        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())
 | 
			
		||||
    {
 | 
			
		||||
        return cmsColor;
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,11 @@
 | 
			
		||||
#include <openjpeg.h>
 | 
			
		||||
#include <openssl/opensslv.h>
 | 
			
		||||
 | 
			
		||||
#pragma warning(push)
 | 
			
		||||
#pragma warning(disable:5033)
 | 
			
		||||
#include <lcms2.h>
 | 
			
		||||
#pragma warning(pop)
 | 
			
		||||
 | 
			
		||||
namespace pdf
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
@@ -260,6 +265,16 @@ std::vector<PDFDependentLibraryInfo> PDFDependentLibraryInfo::getLibraryInfo()
 | 
			
		||||
    opensslInfo.url = tr("https://www.openssl.org/");
 | 
			
		||||
    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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user