From d73fbe4dffacce30a3ec2b3ef6d8274da2088b22 Mon Sep 17 00:00:00 2001 From: Jakub Melka Date: Thu, 4 Mar 2021 19:39:14 +0100 Subject: [PATCH] Consider document's output intents in color transformation --- Pdf4QtLib/sources/pdfcms.cpp | 189 ++++++++++++++++-- Pdf4QtLib/sources/pdfcms.h | 29 +++ Pdf4QtLib/sources/pdftransparencyrenderer.cpp | 13 +- Pdf4QtLib/sources/pdftransparencyrenderer.h | 4 + Pdf4QtViewer/pdfprogramcontroller.cpp | 1 + Pdf4QtViewer/pdfviewersettings.cpp | 2 + Pdf4QtViewer/pdfviewersettingsdialog.cpp | 8 + Pdf4QtViewer/pdfviewersettingsdialog.ui | 164 ++++++++------- PdfTool/pdftoolabstractapplication.cpp | 6 + PdfTool/pdftoolfetchimages.cpp | 1 + PdfTool/pdftoolrender.cpp | 1 + 11 files changed, 320 insertions(+), 98 deletions(-) diff --git a/Pdf4QtLib/sources/pdfcms.cpp b/Pdf4QtLib/sources/pdfcms.cpp index f7b80b5..993b6ae 100644 --- a/Pdf4QtLib/sources/pdfcms.cpp +++ b/Pdf4QtLib/sources/pdfcms.cpp @@ -16,6 +16,7 @@ // along with Pdf4Qt. If not, see . #include "pdfcms.h" +#include "pdfdocument.h" #include "pdfexecutionpolicy.h" #include @@ -69,10 +70,13 @@ private: bool isSoftProofing() const; /// Creates a profile using provided id and a list of profile descriptors. - /// If profile can't be created, then null handle is returned. + /// If profile can't be created, then null handle is returned. If \p preferOutputProfile + /// is set to true, and given profile is not output profile, then first output profile + /// is being selected. /// \param id Id of color profile /// \param profileDescriptors Profile descriptor list - cmsHPROFILE createProfile(const QString& id, const PDFColorProfileIdentifiers& profileDescriptors) const; + /// \param preferOutputProfile + cmsHPROFILE createProfile(const QString& id, const PDFColorProfileIdentifiers& profileDescriptors, bool preferOutputProfile) const; /// Gets transform from cache. If transform doesn't exist, then it is created. /// \param profile Color profile @@ -659,11 +663,11 @@ QColor PDFLittleCMS::getColorFromICC(const PDFColor& color, RenderingIntent rend void PDFLittleCMS::init() { // Jakub Melka: initialize all color profiles - m_profiles[Output] = createProfile(m_settings.outputCS, m_manager->getOutputProfiles()); - m_profiles[Gray] = createProfile(m_settings.deviceGray, m_manager->getGrayProfiles()); - m_profiles[RGB] = createProfile(m_settings.deviceRGB, m_manager->getRGBProfiles()); - m_profiles[CMYK] = createProfile(m_settings.deviceCMYK, m_manager->getCMYKProfiles()); - m_profiles[SoftProofing] = createProfile(m_settings.softProofingProfile, m_manager->getCMYKProfiles()); + m_profiles[Output] = createProfile(m_settings.outputCS, m_manager->getOutputProfiles(), false); + m_profiles[Gray] = createProfile(m_settings.deviceGray, m_manager->getGrayProfiles(), m_settings.isConsiderOutputIntent); + m_profiles[RGB] = createProfile(m_settings.deviceRGB, m_manager->getRGBProfiles(), m_settings.isConsiderOutputIntent); + m_profiles[CMYK] = createProfile(m_settings.deviceCMYK, m_manager->getCMYKProfiles(), m_settings.isConsiderOutputIntent); + m_profiles[SoftProofing] = createProfile(m_settings.softProofingProfile, m_manager->getCMYKProfiles(), false); m_profiles[XYZ] = cmsCreateXYZProfile(); cmsUInt16Number outOfGamutR = m_settings.outOfGamutColor.redF() * 0xFFFF; @@ -695,9 +699,23 @@ bool PDFLittleCMS::isSoftProofing() const return (m_settings.isSoftProofing || m_settings.isGamutChecking) && m_profiles[SoftProofing]; } -cmsHPROFILE PDFLittleCMS::createProfile(const QString& id, const PDFColorProfileIdentifiers& profileDescriptors) const +cmsHPROFILE PDFLittleCMS::createProfile(const QString& id, const PDFColorProfileIdentifiers& profileDescriptors, bool preferOutputProfile) const { auto it = std::find_if(profileDescriptors.cbegin(), profileDescriptors.cend(), [&id](const PDFColorProfileIdentifier& identifier) { return identifier.id == id; }); + if (preferOutputProfile && it != profileDescriptors.end()) + { + const PDFColorProfileIdentifier& identifier = *it; + if (!identifier.isOutputIntentProfile) + { + // Find first output intent color profile + auto itOutputIntentColorProfile = std::find_if(profileDescriptors.cbegin(), profileDescriptors.cend(), [&id](const PDFColorProfileIdentifier& identifier) { return identifier.isOutputIntentProfile; }); + if (itOutputIntentColorProfile != profileDescriptors.end()) + { + it = itOutputIntentColorProfile; + } + } + } + if (it != profileDescriptors.cend()) { const PDFColorProfileIdentifier& identifier = *it; @@ -752,6 +770,11 @@ cmsHPROFILE PDFLittleCMS::createProfile(const QString& id, const PDFColorProfile break; } + case PDFColorProfileIdentifier::Type::MemoryGray: + case PDFColorProfileIdentifier::Type::MemoryRGB: + case PDFColorProfileIdentifier::Type::MemoryCMYK: + return cmsOpenProfileFromMem(identifier.profileMemoryData.data(), identifier.profileMemoryData.size()); + default: Q_ASSERT(false); break; @@ -1190,7 +1213,8 @@ bool PDFCMSGeneric::transformColorSpace(const PDFCMS::ColorSpaceTransformParams& PDFCMSManager::PDFCMSManager(QObject* parent) : BaseClass(parent), - m_mutex(QMutex::Recursive) + m_mutex(QMutex::Recursive), + m_document(nullptr) { } @@ -1210,12 +1234,7 @@ void PDFCMSManager::setSettings(const PDFCMSSettings& settings) { QMutexLocker lock(&m_mutex); m_settings = settings; - m_CMS.dirty(); - m_outputProfiles.dirty(); - m_grayProfiles.dirty(); - m_RGBProfiles.dirty(); - m_CMYKProfiles.dirty(); - m_externalProfiles.dirty(); + clearCache(); } emit colorManagementSystemChanged(); @@ -1275,6 +1294,98 @@ PDFCMSSettings PDFCMSManager::getDefaultSettings() const return settings; } +void PDFCMSManager::setDocument(const PDFDocument* document) +{ + std::optional lock; + lock.emplace(&m_mutex); + + if (m_document == document) + { + return; + } + + m_document = document; + + int i = 0; + PDFColorProfileIdentifiers outputIntentProfiles; + + if (m_document) + { + for (const PDFOutputIntent& outputIntent : m_document->getCatalog()->getOutputIntents()) + { + QByteArray content; + + try + { + // Try to read the profile from the output intent stream. If it fails, then do nothing. + PDFObject outputProfileObject = m_document->getObject(outputIntent.getOutputProfile()); + if (outputProfileObject.isStream()) + { + content = m_document->getDecodedStream(outputProfileObject.getStream()); + } + } + catch (PDFException) + { + continue; + } + + if (content.isEmpty()) + { + // Decoding of output profile failed. Continue + // with next output profile. + continue; + } + + cmsHPROFILE profile = cmsOpenProfileFromMem(content.data(), content.size()); + if (profile) + { + PDFColorProfileIdentifier::Type csiType = PDFColorProfileIdentifier::Type::Invalid; + const cmsColorSpaceSignature colorSpace = cmsGetColorSpace(profile); + switch (colorSpace) + { + case cmsSigGrayData: + csiType = PDFColorProfileIdentifier::Type::MemoryGray; + break; + + case cmsSigRgbData: + csiType = PDFColorProfileIdentifier::Type::MemoryRGB; + break; + + case cmsSigCmykData: + csiType = PDFColorProfileIdentifier::Type::MemoryCMYK; + break; + + default: + break; + } + + QString description = getInfoFromProfile(profile, cmsInfoDescription); + cmsCloseProfile(profile); + + // If we have a valid profile, then add it + if (csiType != PDFColorProfileIdentifier::Type::Invalid) + { + outputIntentProfiles.emplace_back(PDFColorProfileIdentifier::createOutputIntent(csiType, qMove(description), QString("@@OUTPUT_INTENT_PROFILE_%1").arg(++i), qMove(content))); + } + } + } + } + + bool outputIntentProfilesChanged = false; + if (m_outputIntentProfiles != outputIntentProfiles) + { + m_outputIntentProfiles = qMove(outputIntentProfiles); + clearCache(); + outputIntentProfilesChanged = true; + } + + if (outputIntentProfilesChanged) + { + lock = std::nullopt; + emit colorManagementSystemChanged(); + } +} + QString PDFCMSManager::getSystemName(PDFCMSSettings::System system) { switch (system) @@ -1317,6 +1428,17 @@ PDFCMSPointer PDFCMSManager::getCurrentCMSImpl() const return PDFCMSPointer(new PDFCMSGeneric()); } +void PDFCMSManager::clearCache() +{ + QMutexLocker lock(&m_mutex); + m_CMS.dirty(); + m_outputProfiles.dirty(); + m_grayProfiles.dirty(); + m_RGBProfiles.dirty(); + m_CMYKProfiles.dirty(); + m_externalProfiles.dirty(); +} + PDFColorProfileIdentifiers PDFCMSManager::getOutputProfilesImpl() const { // Currently, we only support sRGB output color profile. @@ -1337,14 +1459,16 @@ PDFColorProfileIdentifiers PDFCMSManager::getGrayProfilesImpl() const PDFColorProfileIdentifier::createGray(tr("Gray D93, γ = 1.0 (linear)"), "@GENERIC_Gray_D93_g10", 9300.0, 1.0) }; - PDFColorProfileIdentifiers externalRGBProfiles = getFilteredExternalProfiles(PDFColorProfileIdentifier::Type::FileGray); - result.insert(result.end(), externalRGBProfiles.begin(), externalRGBProfiles.end()); + PDFColorProfileIdentifiers externalGrayProfiles = getFilteredExternalProfiles(PDFColorProfileIdentifier::Type::FileGray); + result.insert(result.end(), std::make_move_iterator(externalGrayProfiles.begin()), std::make_move_iterator(externalGrayProfiles.end())); + PDFColorProfileIdentifiers outputIntentRGBProfiles = getFilteredOutputIntentProfiles(PDFColorProfileIdentifier::Type::MemoryGray); + result.insert(result.end(), std::make_move_iterator(outputIntentRGBProfiles.begin()), std::make_move_iterator(outputIntentRGBProfiles.end())); return result; } PDFColorProfileIdentifiers PDFCMSManager::getRGBProfilesImpl() const { - // Jakub Melka: We create RGB profiles for common standars and also for + // Jakub Melka: We create RGB profiles for common standards and also for // default standard sRGB. See https://en.wikipedia.org/wiki/Color_spaces_with_RGB_primaries. PDFColorProfileIdentifiers result = { @@ -1359,12 +1483,21 @@ PDFColorProfileIdentifiers PDFCMSManager::getRGBProfilesImpl() const PDFColorProfileIdentifiers externalRGBProfiles = getFilteredExternalProfiles(PDFColorProfileIdentifier::Type::FileRGB); result.insert(result.end(), externalRGBProfiles.begin(), externalRGBProfiles.end()); + PDFColorProfileIdentifiers outputIntentRGBProfiles = getFilteredOutputIntentProfiles(PDFColorProfileIdentifier::Type::MemoryRGB); + result.insert(result.end(), std::make_move_iterator(outputIntentRGBProfiles.begin()), std::make_move_iterator(outputIntentRGBProfiles.end())); return result; } PDFColorProfileIdentifiers PDFCMSManager::getCMYKProfilesImpl() const { - return getFilteredExternalProfiles(PDFColorProfileIdentifier::Type::FileCMYK); + PDFColorProfileIdentifiers result; + + PDFColorProfileIdentifiers externalCMYKProfiles = getFilteredExternalProfiles(PDFColorProfileIdentifier::Type::FileCMYK); + result.insert(result.end(), externalCMYKProfiles.begin(), externalCMYKProfiles.end()); + PDFColorProfileIdentifiers outputIntentCMYKProfiles = getFilteredOutputIntentProfiles(PDFColorProfileIdentifier::Type::MemoryCMYK); + result.insert(result.end(), std::make_move_iterator(outputIntentCMYKProfiles.begin()), std::make_move_iterator(outputIntentCMYKProfiles.end())); + + return result; } PDFColorProfileIdentifiers PDFCMSManager::getExternalColorProfiles(QString profileDirectory) const @@ -1454,6 +1587,13 @@ PDFColorProfileIdentifiers PDFCMSManager::getFilteredExternalProfiles(PDFColorPr return result; } +PDFColorProfileIdentifiers PDFCMSManager::getFilteredOutputIntentProfiles(PDFColorProfileIdentifier::Type type) const +{ + PDFColorProfileIdentifiers result; + std::copy_if(m_outputIntentProfiles.cbegin(), m_outputIntentProfiles.cend(), std::back_inserter(result), [type](const PDFColorProfileIdentifier& identifier) { return identifier.type == type; }); + return result; +} + PDFColorProfileIdentifier PDFColorProfileIdentifier::createGray(QString name, QString id, PDFReal temperature, PDFReal gamma) { PDFColorProfileIdentifier result; @@ -1497,6 +1637,17 @@ PDFColorProfileIdentifier PDFColorProfileIdentifier::createFile(Type type, QStri return result; } +PDFColorProfileIdentifier PDFColorProfileIdentifier::createOutputIntent(PDFColorProfileIdentifier::Type type, QString name, QString id, QByteArray profileData) +{ + PDFColorProfileIdentifier result; + result.type = type; + result.name = qMove(name); + result.id = qMove(id); + result.profileMemoryData = qMove(profileData); + result.isOutputIntentProfile = true; + return result; +} + PDFColor3 PDFCMS::getDefaultXYZWhitepoint() { const cmsCIEXYZ* whitePoint = cmsD50_XYZ(); diff --git a/Pdf4QtLib/sources/pdfcms.h b/Pdf4QtLib/sources/pdfcms.h index 4336971..c142c65 100644 --- a/Pdf4QtLib/sources/pdfcms.h +++ b/Pdf4QtLib/sources/pdfcms.h @@ -65,6 +65,7 @@ struct PDFCMSSettings bool isWhitePaperColorTransformed = false; bool isGamutChecking = false; bool isSoftProofing = false; + bool isConsiderOutputIntent = true; QColor outOfGamutColor = Qt::red; ///< Color, which marks out-of-gamut when soft-proofing is proceeded QString outputCS; ///< Output (rendering) color space QString deviceGray; ///< Identifiers for color space (device gray) @@ -269,9 +270,15 @@ struct PDFColorProfileIdentifier FileGray, FileRGB, FileCMYK, + MemoryGray, + MemoryRGB, + MemoryCMYK, Invalid }; + bool operator==(const PDFColorProfileIdentifier&) const = default; + bool operator!=(const PDFColorProfileIdentifier&) const = default; + Type type = Type::sRGB; QString name; QString id; @@ -280,6 +287,10 @@ struct PDFColorProfileIdentifier QPointF primaryG; QPointF primaryB; PDFReal gamma = 1.0; + bool isOutputIntentProfile = false; + + /// Data for MemoryGray, MemoryRGB and MemoryCMYK + QByteArray profileMemoryData; /// Creates gray color profile identifier /// \param name Name of color profile @@ -303,6 +314,9 @@ struct PDFColorProfileIdentifier /// Create file color profile identifier static PDFColorProfileIdentifier createFile(Type type, QString name, QString id); + + /// Create memory output intent color profile identifier + static PDFColorProfileIdentifier createOutputIntent(Type type, QString name, QString id, QByteArray profileData); }; using PDFColorProfileIdentifiers = std::vector; @@ -338,6 +352,11 @@ public: /// Returns default color management settings PDFCMSSettings getDefaultSettings() const; + /// Set current document. Document is examined for output + /// rendering intents and they can be used when rendering. + /// \param document Document + void setDocument(const PDFDocument* document); + /// Get translated name for color management system /// \param system System static QString getSystemName(PDFCMSSettings::System system); @@ -349,6 +368,9 @@ private: /// Creates new CMS based on current settings PDFCMSPointer getCurrentCMSImpl() const; + /// Clear cached items + void clearCache(); + /// This function returns external profiles. It is not protected by mutex, /// so it is not thread-safe. For this reason, it is not in public /// interface. @@ -365,11 +387,18 @@ private: /// \param type Type of profile PDFColorProfileIdentifiers getFilteredExternalProfiles(PDFColorProfileIdentifier::Type type) const; + /// Returns filtered list of output intent profiles (list are filtered by type, + /// so, for example, only CMYK profiles are returned) + /// \param type Type of profile + PDFColorProfileIdentifiers getFilteredOutputIntentProfiles(PDFColorProfileIdentifier::Type type) const; + /// Gets list of color profiles from external directory /// \param profileDirectory Directory with profiles PDFColorProfileIdentifiers getExternalColorProfiles(QString profileDirectory) const; PDFCMSSettings m_settings; + const PDFDocument* m_document; + PDFColorProfileIdentifiers m_outputIntentProfiles; mutable QMutex m_mutex; mutable PDFCachedItem m_CMS; diff --git a/Pdf4QtLib/sources/pdftransparencyrenderer.cpp b/Pdf4QtLib/sources/pdftransparencyrenderer.cpp index 482e6db..993a439 100644 --- a/Pdf4QtLib/sources/pdftransparencyrenderer.cpp +++ b/Pdf4QtLib/sources/pdftransparencyrenderer.cpp @@ -2819,7 +2819,7 @@ void PDFInkMapper::createSpotColors(bool activate) { // Try to add spot color const QByteArray& colorName = separationColorSpace->getColorName(); - if (!containsSpotColor(colorName)) + if (!containsSpotColor(colorName) && !containsProcessColor(colorName)) { ColorInfo info; info.name = colorName; @@ -2843,7 +2843,7 @@ void PDFInkMapper::createSpotColors(bool activate) for (size_t i = 0; i < colorants.size(); ++i) { const PDFDeviceNColorSpace::ColorantInfo& colorantInfo = colorants[i]; - if (!containsSpotColor(colorantInfo.name)) + if (!containsSpotColor(colorantInfo.name) && !containsProcessColor(colorantInfo.name)) { ColorInfo info; info.name = colorantInfo.name; @@ -2881,6 +2881,11 @@ bool PDFInkMapper::containsSpotColor(const QByteArray& colorName) const return getSpotColor(colorName) != nullptr; } +bool PDFInkMapper::containsProcessColor(const QByteArray& colorName) const +{ + return getProcessColor(colorName) != nullptr; +} + const PDFInkMapper::ColorInfo* PDFInkMapper::getSpotColor(const QByteArray& colorName) const { auto it = std::find_if(m_spotColors.cbegin(), m_spotColors.cend(), [&colorName](const auto& info) { return info.name == colorName; }); @@ -2895,7 +2900,7 @@ const PDFInkMapper::ColorInfo* PDFInkMapper::getSpotColor(const QByteArray& colo const PDFInkMapper::ColorInfo* PDFInkMapper::getProcessColor(const QByteArray& colorName) const { auto it = std::find_if(m_deviceColors.cbegin(), m_deviceColors.cend(), [&colorName](const auto& info) { return info.name == colorName; }); - if (it != m_spotColors.cend()) + if (it != m_deviceColors.cend()) { return &*it; } @@ -3039,7 +3044,7 @@ PDFInkMapping PDFInkMapper::createMapping(const PDFAbstractColorSpace* sourceCol { if (targetPixelFormat.hasProcessColors() && processColor->spotColorIndex < targetPixelFormat.getProcessColorChannelCount()) { - mapping.map(0, uint8_t(targetPixelFormat.getProcessColorChannelIndexStart() + processColor->spotColorIndex)); + mapping.map(uint8_t(i), uint8_t(targetPixelFormat.getProcessColorChannelIndexStart() + processColor->spotColorIndex)); } } else diff --git a/Pdf4QtLib/sources/pdftransparencyrenderer.h b/Pdf4QtLib/sources/pdftransparencyrenderer.h index 668c590..146d141 100644 --- a/Pdf4QtLib/sources/pdftransparencyrenderer.h +++ b/Pdf4QtLib/sources/pdftransparencyrenderer.h @@ -361,6 +361,10 @@ public: /// \param colorName Color name bool containsSpotColor(const QByteArray& colorName) const; + /// Returns true, if mapper contains given process color + /// \param colorName Color name + bool containsProcessColor(const QByteArray& colorName) const; + /// Returns number of active spot colors size_t getActiveSpotColorCount() const { return m_activeSpotColors; } diff --git a/Pdf4QtViewer/pdfprogramcontroller.cpp b/Pdf4QtViewer/pdfprogramcontroller.cpp index 002fce3..2cfca4d 100644 --- a/Pdf4QtViewer/pdfprogramcontroller.cpp +++ b/Pdf4QtViewer/pdfprogramcontroller.cpp @@ -1569,6 +1569,7 @@ void PDFProgramController::setDocument(pdf::PDFModifiedDocument document) m_pdfWidget->setDocument(document); m_mainWindowInterface->setDocument(document); + m_CMSManager->setDocument(document); updateTitle(); m_mainWindowInterface->updateUI(true); diff --git a/Pdf4QtViewer/pdfviewersettings.cpp b/Pdf4QtViewer/pdfviewersettings.cpp index 4601da7..9c5a915 100644 --- a/Pdf4QtViewer/pdfviewersettings.cpp +++ b/Pdf4QtViewer/pdfviewersettings.cpp @@ -66,6 +66,7 @@ void PDFViewerSettings::readSettings(QSettings& settings, const pdf::PDFCMSSetti m_colorManagementSystemSettings.intent = static_cast(settings.value("intent", int(defaultCMSSettings.intent)).toInt()); m_colorManagementSystemSettings.isBlackPointCompensationActive = settings.value("isBlackPointCompensationActive", defaultCMSSettings.isBlackPointCompensationActive).toBool(); m_colorManagementSystemSettings.isWhitePaperColorTransformed = settings.value("isWhitePaperColorTransformed", defaultCMSSettings.isWhitePaperColorTransformed).toBool(); + m_colorManagementSystemSettings.isConsiderOutputIntent = settings.value("isConsiderOutputIntent", defaultCMSSettings.isConsiderOutputIntent).toBool(); m_colorManagementSystemSettings.outputCS = settings.value("outputCS", defaultCMSSettings.outputCS).toString(); m_colorManagementSystemSettings.deviceGray = settings.value("deviceGray", defaultCMSSettings.deviceGray).toString(); m_colorManagementSystemSettings.deviceRGB = settings.value("deviceRGB", defaultCMSSettings.deviceRGB).toString(); @@ -130,6 +131,7 @@ void PDFViewerSettings::writeSettings(QSettings& settings) settings.setValue("intent", int(m_colorManagementSystemSettings.intent)); settings.setValue("isBlackPointCompensationActive", m_colorManagementSystemSettings.isBlackPointCompensationActive); settings.setValue("isWhitePaperColorTransformed", m_colorManagementSystemSettings.isWhitePaperColorTransformed); + settings.setValue("isConsiderOutputIntent", m_colorManagementSystemSettings.isConsiderOutputIntent); settings.setValue("outputCS", m_colorManagementSystemSettings.outputCS); settings.setValue("deviceGray", m_colorManagementSystemSettings.deviceGray); settings.setValue("deviceRGB", m_colorManagementSystemSettings.deviceRGB); diff --git a/Pdf4QtViewer/pdfviewersettingsdialog.cpp b/Pdf4QtViewer/pdfviewersettingsdialog.cpp index 04498b8..4944732 100644 --- a/Pdf4QtViewer/pdfviewersettingsdialog.cpp +++ b/Pdf4QtViewer/pdfviewersettingsdialog.cpp @@ -305,6 +305,8 @@ void PDFViewerSettingsDialog::loadData() ui->cmsAccuracyComboBox->setCurrentIndex(ui->cmsAccuracyComboBox->findData(int(m_cmsSettings.accuracy))); ui->cmsIsBlackPointCompensationCheckBox->setEnabled(true); ui->cmsIsBlackPointCompensationCheckBox->setChecked(m_cmsSettings.isBlackPointCompensationActive); + ui->cmsConsiderOutputIntentCheckBox->setEnabled(true); + ui->cmsConsiderOutputIntentCheckBox->setChecked(m_cmsSettings.isConsiderOutputIntent); ui->cmsWhitePaperColorTransformedCheckBox->setEnabled(true); ui->cmsWhitePaperColorTransformedCheckBox->setChecked(m_cmsSettings.isWhitePaperColorTransformed); ui->cmsOutputColorProfileComboBox->setEnabled(true); @@ -327,6 +329,8 @@ void PDFViewerSettingsDialog::loadData() ui->cmsAccuracyComboBox->setCurrentIndex(-1); ui->cmsIsBlackPointCompensationCheckBox->setEnabled(false); ui->cmsIsBlackPointCompensationCheckBox->setChecked(false); + ui->cmsConsiderOutputIntentCheckBox->setEnabled(false); + ui->cmsConsiderOutputIntentCheckBox->setChecked(false); ui->cmsWhitePaperColorTransformedCheckBox->setEnabled(false); ui->cmsWhitePaperColorTransformedCheckBox->setChecked(false); ui->cmsOutputColorProfileComboBox->setEnabled(false); @@ -472,6 +476,10 @@ void PDFViewerSettingsDialog::saveData() { m_cmsSettings.isWhitePaperColorTransformed = ui->cmsWhitePaperColorTransformedCheckBox->isChecked(); } + else if (sender == ui->cmsConsiderOutputIntentCheckBox) + { + m_cmsSettings.isConsiderOutputIntent = ui->cmsConsiderOutputIntentCheckBox->isChecked(); + } else if (sender == ui->cmsOutputColorProfileComboBox) { m_cmsSettings.outputCS = ui->cmsOutputColorProfileComboBox->currentData().toString(); diff --git a/Pdf4QtViewer/pdfviewersettingsdialog.ui b/Pdf4QtViewer/pdfviewersettingsdialog.ui index 4014758..d5fd900 100644 --- a/Pdf4QtViewer/pdfviewersettingsdialog.ui +++ b/Pdf4QtViewer/pdfviewersettingsdialog.ui @@ -610,70 +610,9 @@ - - - - Device gray color profile - - - - - - - Device CMYK color profile - - - - - - - Enable - - - - - - - Output color profile - - - - - - - Black point compensation - - - - - - - - - - - - - - - - White paper color transformed - - - - - - - - - - Rendering intent - - - @@ -684,13 +623,6 @@ - - - - Accuracy - - - @@ -698,16 +630,33 @@ - - - - - + + - Color management system + White paper color transformed + + + + + + + Device CMYK color profile + + + + + + + Accuracy + + + + + + @@ -715,6 +664,22 @@ + + + + + + + + + + Rendering intent + + + + + + @@ -729,12 +694,61 @@ + + + + Output color profile + + + + + + + Color management system + + + + + + + Black point compensation + + + + + + + Device gray color profile + + + + + + + Enable + + + + + + + Enable + + + + + + + Consider document output intents + + + - <html><head/><body><p><span style=" font-weight:600;">Color management system </span>manages input and output color profiles and color transformations. It enables to perceive real colors defined in PDF document. Select 'Generic' to disable this functionality for fast color transform. <span style=" font-weight:600;">Rendering intent</span> affects how colors are transformed. Rendering intents are usually defined in content streams in PDF document, but you can override them, if you select other intent, than 'Auto'. <span style=" font-weight:600;">Accuracy </span>affects how precise the color transformation would be, at the cost of more memory consumption. <span style=" font-weight:600;">Black point compensation</span> compensates black colors out of gamut. <span style=" font-weight:600;">White paper color transformed </span>affects color of the underlying white paper - it transforms pure white from device RGB profile to output profile, if enabled.</p><p><span style=" font-weight:600;">Output color profile</span> defines output (target) rendering profile. This profile should be color space, in which your screen is displaying colors. You can also define color spaces for <span style=" font-weight:600;">gray/RGB/CMYK</span> device color spaces, which are used to transform gray/RGB/CMYK colors to the output color profile.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Color management system </span>manages input and output color profiles and color transformations. It enables to perceive real colors defined in PDF document. Select 'Generic' to disable this functionality for fast color transform. <span style=" font-weight:600;">Rendering intent</span> affects how colors are transformed. Rendering intents are usually defined in content streams in PDF document, but you can override them, if you select other intent, than 'Auto'. <span style=" font-weight:600;">Accuracy </span>affects how precise the color transformation would be, at the cost of more memory consumption. <span style=" font-weight:600;">Black point compensation</span> compensates black colors out of gamut. <span style=" font-weight:600;">White paper color transformed </span>affects color of the underlying white paper - it transforms pure white from device RGB profile to output profile, if enabled.</p><p><span style=" font-weight:600;">Output color profile</span> defines output (target) rendering profile. This profile should be color space, in which your screen is displaying colors. You can also define color spaces for <span style=" font-weight:600;">gray/RGB/CMYK</span> device color spaces, which are used to transform gray/RGB/CMYK colors to the output color profile.</p><p>Document can contain output intents, which can be used for transforming between color spaces. If option <span style=" font-weight:600;">Consider document output intents</span> is checked, color management system checks, if document contains output intents, and if yes, then they are used for color transformation as device color spaces (gray/RGB/CMYK).</p></body></html> true diff --git a/PdfTool/pdftoolabstractapplication.cpp b/PdfTool/pdftoolabstractapplication.cpp index 3646042..e06a964 100644 --- a/PdfTool/pdftoolabstractapplication.cpp +++ b/PdfTool/pdftoolabstractapplication.cpp @@ -283,6 +283,7 @@ void PDFToolAbstractApplication::initializeCommandLineParser(QCommandLineParser* parser->addOption(QCommandLineOption("cms-intent", "Rendering intent. Valid values are auto|perceptual|abs|rel|saturation.", "intent", "auto")); parser->addOption(QCommandLineOption("cms-black-compensated", "Black point compensation.", "bool", "1")); parser->addOption(QCommandLineOption("cms-white-paper-trans", "Transform also color of paper using cms.", "bool", "0")); + parser->addOption(QCommandLineOption("cms-consider-output-intents", "Consider output rendering intents in the document.", "bool", "1")); parser->addOption(QCommandLineOption("cms-profile-output", "Output color profile.", "profile")); parser->addOption(QCommandLineOption("cms-profile-gray", "Gray color profile for gray device.", "profile")); parser->addOption(QCommandLineOption("cms-profile-rgb", "RGB color profile for RGB device.", "profile")); @@ -763,6 +764,11 @@ PDFToolOptions PDFToolAbstractApplication::getOptions(QCommandLineParser* parser options.cmsSettings.isWhitePaperColorTransformed = parser->value("cms-white-paper-trans").toInt(); } + if (parser->isSet("cms-consider-output-intents")) + { + options.cmsSettings.isConsiderOutputIntent = parser->value("cms-consider-output-intents").toInt(); + } + auto setProfile = [&parser, &options](QString settings, QString& profile) { if (parser->isSet(settings)) diff --git a/PdfTool/pdftoolfetchimages.cpp b/PdfTool/pdftoolfetchimages.cpp index e07ee77..3776656 100644 --- a/PdfTool/pdftoolfetchimages.cpp +++ b/PdfTool/pdftoolfetchimages.cpp @@ -151,6 +151,7 @@ int PDFToolFetchImages::execute(const PDFToolOptions& options) // We are ready to render the document pdf::PDFOptionalContentActivity optionalContentActivity(&document, pdf::OCUsage::Export, nullptr); pdf::PDFCMSManager cmsManager(nullptr); + cmsManager.setDocument(&document); cmsManager.setSettings(options.cmsSettings); pdf::PDFCMSPointer cms = cmsManager.getCurrentCMS(); pdf::PDFMeshQualitySettings meshQualitySettings; diff --git a/PdfTool/pdftoolrender.cpp b/PdfTool/pdftoolrender.cpp index 443cb9c..bc631b7 100644 --- a/PdfTool/pdftoolrender.cpp +++ b/PdfTool/pdftoolrender.cpp @@ -172,6 +172,7 @@ int PDFToolRenderBase::execute(const PDFToolOptions& options) // We are ready to render the document pdf::PDFOptionalContentActivity optionalContentActivity(&document, pdf::OCUsage::Export, nullptr); pdf::PDFCMSManager cmsManager(nullptr); + cmsManager.setDocument(&document); cmsManager.setSettings(options.cmsSettings); pdf::PDFMeshQualitySettings meshQualitySettings; pdf::PDFFontCache fontCache(pdf::DEFAULT_FONT_CACHE_LIMIT, pdf::DEFAULT_REALIZED_FONT_CACHE_LIMIT);