Color management system - base classes + settings

This commit is contained in:
Jakub Melka 2019-12-24 17:29:40 +01:00
parent aae6c56a5f
commit 0470c4bc1d
13 changed files with 882 additions and 15 deletions

View File

@ -39,6 +39,7 @@ SOURCES += \
sources/pdfaction.cpp \
sources/pdfblendfunction.cpp \
sources/pdfccittfaxdecoder.cpp \
sources/pdfcms.cpp \
sources/pdfcompiler.cpp \
sources/pdffile.cpp \
sources/pdfitemmodels.cpp \
@ -77,6 +78,7 @@ HEADERS += \
sources/pdfaction.h \
sources/pdfblendfunction.h \
sources/pdfccittfaxdecoder.h \
sources/pdfcms.h \
sources/pdfcompiler.h \
sources/pdffile.h \
sources/pdfitemmodels.h \
@ -174,6 +176,16 @@ zlib.files = $$PDFFORQT_DEPENDENCIES_PATH/zlib/bin/zlib.dll
zlib.path = $$DESTDIR/install
INSTALLS += zlib
# Link lcms2
LIBS += -L$$PDFFORQT_DEPENDENCIES_PATH/lcms2/bin/ -llcms2
INCLUDEPATH += $$PDFFORQT_DEPENDENCIES_PATH/lcms2/include
DEPENDPATH += $$PDFFORQT_DEPENDENCIES_PATH/lcms2/include
# Add lcms2 to installations
lcms2.files = $$PDFFORQT_DEPENDENCIES_PATH/lcms2/bin/lcms2.dll
lcms2.path = $$DESTDIR/install
INSTALLS += lcms2
# ensure debug info even for RELEASE build
CONFIG += force_debug_info

View File

@ -0,0 +1,219 @@
// Copyright (C) 2019 Jakub Melka
//
// This file is part of PdfForQt.
//
// PdfForQt is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// PdfForQt 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDFForQt. If not, see <https://www.gnu.org/licenses/>.
#include "pdfcms.h"
#pragma warning(push)
#pragma warning(disable:5033)
#include <lcms2.h>
#pragma warning(pop)
namespace pdf
{
bool PDFCMSGeneric::isCompatible(const PDFCMSSettings& settings) const
{
return settings.system == PDFCMSSettings::System::Generic;
}
QColor PDFCMSGeneric::getColorFromDeviceGray(const PDFColor& color, RenderingIntent intent, PDFRenderErrorReporter* reporter) const
{
Q_UNUSED(color);
Q_UNUSED(intent);
Q_UNUSED(reporter);
return QColor();
}
QColor PDFCMSGeneric::getColorFromDeviceRGB(const PDFColor& color, RenderingIntent intent, PDFRenderErrorReporter* reporter) const
{
Q_UNUSED(color);
Q_UNUSED(intent);
Q_UNUSED(reporter);
return QColor();
}
QColor PDFCMSGeneric::getColorFromDeviceCMYK(const PDFColor& color, RenderingIntent intent, PDFRenderErrorReporter* reporter) const
{
Q_UNUSED(color);
Q_UNUSED(intent);
Q_UNUSED(reporter);
return QColor();
}
QColor PDFCMSGeneric::getColorFromXYZ(const PDFColor3& whitePoint, const PDFColor& color, RenderingIntent intent, PDFRenderErrorReporter* reporter) const
{
Q_UNUSED(color);
Q_UNUSED(intent);
Q_UNUSED(reporter);
Q_UNUSED(whitePoint);
return QColor();
}
PDFCMSManager::PDFCMSManager(QObject* parent) :
BaseClass(parent)
{
}
const PDFColorSpaceIdentifiers& PDFCMSManager::getOutputProfiles() const
{
QMutexLocker lock(&m_mutex);
return m_outputProfiles.get(this, &PDFCMSManager::getOutputProfilesImpl);
}
const PDFColorSpaceIdentifiers& PDFCMSManager::getGrayProfiles() const
{
QMutexLocker lock(&m_mutex);
return m_grayProfiles.get(this, &PDFCMSManager::getGrayProfilesImpl);
}
const PDFColorSpaceIdentifiers& PDFCMSManager::getRGBProfiles() const
{
QMutexLocker lock(&m_mutex);
return m_RGBProfiles.get(this, &PDFCMSManager::getRGBProfilesImpl);
}
const PDFColorSpaceIdentifiers& PDFCMSManager::getCMYKProfiles() const
{
QMutexLocker lock(&m_mutex);
return m_CMYKProfiles.get(this, &PDFCMSManager::getCMYKProfilesImpl);
}
PDFCMSSettings PDFCMSManager::getDefaultSettings() const
{
PDFCMSSettings settings;
auto getFirstProfileId = [](const PDFColorSpaceIdentifiers& identifiers)
{
if (!identifiers.empty())
{
return identifiers.front().id;
}
return QString();
};
settings.system = PDFCMSSettings::System::LittleCMS2;
settings.outputCS = getFirstProfileId(getOutputProfiles());
settings.deviceGray = getFirstProfileId(getGrayProfiles());
settings.deviceRGB = getFirstProfileId(getRGBProfiles());
settings.deviceCMYK = getFirstProfileId(getCMYKProfiles());
return settings;
}
QString PDFCMSManager::getSystemName(PDFCMSSettings::System system)
{
switch (system)
{
case PDFCMSSettings::System::Generic:
return tr("Generic");
case PDFCMSSettings::System::LittleCMS2:
{
const int major = LCMS_VERSION / 1000;
const int minor = (LCMS_VERSION % 1000) / 10;
return tr("Little CMS %1.%2").arg(major).arg(minor);
}
default:
{
Q_ASSERT(false);
break;
}
}
return QString();
}
PDFColorSpaceIdentifiers PDFCMSManager::getOutputProfilesImpl() const
{
// Currently, we only support sRGB output color profile.
return { PDFColorSpaceIdentifier::createSRGB() };
}
PDFColorSpaceIdentifiers PDFCMSManager::getGrayProfilesImpl() const
{
// Jakub Melka: We create gray profiles for temperature 5000K, 6500K and 9300K.
// We also use linear gamma and gamma value 2.2.
return {
PDFColorSpaceIdentifier::createGray(tr("Gray D65, γ = 2.2"), "@GENERIC_Gray_D65_g22", 6500.0, 2.2),
PDFColorSpaceIdentifier::createGray(tr("Gray D50, γ = 2.2"), "@GENERIC_Gray_D50_g22", 5000.0, 2.2),
PDFColorSpaceIdentifier::createGray(tr("Gray D93, γ = 2.2"), "@GENERIC_Gray_D93_g22", 9300.0, 2.2),
PDFColorSpaceIdentifier::createGray(tr("Gray D65, γ = 1.0 (linear)"), "@GENERIC_Gray_D65_g10", 6500.0, 1.0),
PDFColorSpaceIdentifier::createGray(tr("Gray D50, γ = 1.0 (linear)"), "@GENERIC_Gray_D50_g10", 5000.0, 1.0),
PDFColorSpaceIdentifier::createGray(tr("Gray D93, γ = 1.0 (linear)"), "@GENERIC_Gray_D93_g10", 9300.0, 1.0)
};
}
PDFColorSpaceIdentifiers PDFCMSManager::getRGBProfilesImpl() const
{
// Jakub Melka: We create RGB profiles for common standars and also for
// default standard sRGB. See https://en.wikipedia.org/wiki/Color_spaces_with_RGB_primaries.
return {
PDFColorSpaceIdentifier::createSRGB(),
PDFColorSpaceIdentifier::createRGB(tr("HDTV (ITU-R BT.709)"), "@GENERIC_RGB_HDTV", 6500, QPointF(0.64, 0.33), QPointF(0.30, 0.60), QPointF(0.15, 0.06), 20.0 / 9.0),
PDFColorSpaceIdentifier::createRGB(tr("Adobe RGB 1998"), "@GENERIC_RGB_Adobe1998", 6500, QPointF(0.64, 0.33), QPointF(0.30, 0.60), QPointF(0.15, 0.06), 563.0 / 256.0),
PDFColorSpaceIdentifier::createRGB(tr("PAL / SECAM"), "@GENERIC_RGB_PalSecam", 6500, QPointF(0.64, 0.33), QPointF(0.29, 0.60), QPointF(0.15, 0.06), 14.0 / 5.0),
PDFColorSpaceIdentifier::createRGB(tr("NTSC"), "@GENERIC_RGB_NTSC", 6500, QPointF(0.64, 0.34), QPointF(0.31, 0.595), QPointF(0.155, 0.07), 20.0 / 9.0),
PDFColorSpaceIdentifier::createRGB(tr("Adobe Wide Gamut RGB"), "@GENERIC_RGB_AdobeWideGamut", 5000, QPointF(0.735, 0.265), QPointF(0.115, 0.826), QPointF(0.157, 0.018), 563.0 / 256.0),
PDFColorSpaceIdentifier::createRGB(tr("ProPhoto RGB"), "@GENERIC_RGB_ProPhoto", 5000, QPointF(0.7347, 0.2653), QPointF(0.1596, 0.8404), QPointF(0.0366, 0.0001), 9.0 / 5.0)
};
}
PDFColorSpaceIdentifiers PDFCMSManager::getCMYKProfilesImpl() const
{
return {
};
}
PDFColorSpaceIdentifier PDFColorSpaceIdentifier::createGray(QString name, QString id, PDFReal temperature, PDFReal gamma)
{
PDFColorSpaceIdentifier result;
result.type = Type::Gray;
result.name = qMove(name);
result.id = qMove(id);
result.temperature = temperature;
result.gamma = gamma;
return result;
}
PDFColorSpaceIdentifier PDFColorSpaceIdentifier::createSRGB()
{
PDFColorSpaceIdentifier result;
result.type = Type::sRGB;
result.name = PDFCMSManager::tr("sRGB");
result.id = "@GENERIC_sRGB";
return result;
}
PDFColorSpaceIdentifier PDFColorSpaceIdentifier::createRGB(QString name, QString id, PDFReal temperature, QPointF primaryR, QPointF primaryG, QPointF primaryB, PDFReal gamma)
{
PDFColorSpaceIdentifier result;
result.type = Type::RGB;
result.name = qMove(name);
result.id = qMove(id);
result.temperature = temperature;
result.primaryR = primaryR;
result.primaryG = primaryG;
result.primaryB = primaryB;
result.gamma = gamma;
return result;
}
} // namespace pdf

View File

@ -0,0 +1,225 @@
// Copyright (C) 2019 Jakub Melka
//
// This file is part of PdfForQt.
//
// PdfForQt is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// PdfForQt 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDFForQt. If not, see <https://www.gnu.org/licenses/>.
#ifndef PDFCMS_H
#define PDFCMS_H
#include "pdfglobal.h"
#include "pdfcolorspaces.h"
#include "pdfexception.h"
#include "pdfutils.h"
#include <QMutex>
#include <compare>
namespace pdf
{
/// This simple structure stores settings for color management system, and what
/// color management system should be used. At default, two color management
/// system are available - generic (which uses default imprecise color management),
/// and CMS using engine LittleCMS2, which was written by Marti Maria, and is
/// linked as separate library.
struct PDFCMSSettings
{
/// Type of color management system
enum class System
{
Generic,
LittleCMS2
};
/// Controls accuracy of the color transformations. High accuracy
/// could mean high memory consumption, but better color accuracy,
/// low accuracy means low memory consumption and low color accuracy.
enum class Accuracy
{
Low,
Medium,
High
};
bool operator==(const PDFCMSSettings&) const = default;
System system = System::Generic;
Accuracy accuracy = Accuracy::Medium;
RenderingIntent intent = RenderingIntent::Auto;
bool isBlackPointCompensationActive = true;
bool isWhitePaperColorTransformed = false;
QString outputCS; ///< Output (rendering) color space
QString deviceGray; ///< Identifiers for color space (device gray)
QString deviceRGB; ///< Identifiers for color space (device RGB)
QString deviceCMYK; ///< Identifiers for color space (device CMYK)
};
/// Color management system base class. It contains functions to transform
/// colors from various color system to device color system. If color management
/// system can't handle color transform, it should return invalid color.
class PDFCMS
{
public:
explicit inline PDFCMS() = default;
virtual ~PDFCMS() = default;
/// This function should decide, if color management system is compatible with these
/// settings (so, it transforms colors according to this setting). If this
/// function returns false, then this color management system should be replaced
/// by newly created one, according these settings.
virtual bool isCompatible(const PDFCMSSettings& settings) const = 0;
/// Converts color in Device Gray color space to the target device
/// color space. If error occurs, then invalid color is returned.
/// Caller then should handle this - try to convert color as accurate
/// as possible.
/// \param color Single color channel value
/// \param intent Rendering intent
/// \param reporter Render error reporter (used, when color transform fails)
virtual QColor getColorFromDeviceGray(const PDFColor& color, RenderingIntent intent, PDFRenderErrorReporter* reporter) const = 0;
/// Converts color in Device RGB color space to the target device
/// color space. If error occurs, then invalid color is returned.
/// Caller then should handle this - try to convert color as accurate
/// as possible.
/// \param color Three color channel value (R,G,B channel)
/// \param intent Rendering intent
/// \param reporter Render error reporter (used, when color transform fails)
virtual QColor getColorFromDeviceRGB(const PDFColor& color, RenderingIntent intent, PDFRenderErrorReporter* reporter) const = 0;
/// Converts color in Device CMYK color space to the target device
/// color space. If error occurs, then invalid color is returned.
/// Caller then should handle this - try to convert color as accurate
/// as possible.
/// \param color Four color channel value (C,M,Y,K channel)
/// \param intent Rendering intent
/// \param reporter Render error reporter (used, when color transform fails)
virtual QColor getColorFromDeviceCMYK(const PDFColor& color, RenderingIntent intent, PDFRenderErrorReporter* reporter) const = 0;
/// Converts color in XYZ color space to the target device
/// color space. If error occurs, then invalid color is returned.
/// Caller then should handle this - try to convert color as accurate
/// as possible.
/// \param whitePoint White point of source XYZ color space
/// \param Three color channel value (X,Y,Z channel)
/// \param intent Rendering intent
/// \param reporter Render error reporter (used, when color transform fails)
virtual QColor getColorFromXYZ(const PDFColor3& whitePoint, const PDFColor& color, RenderingIntent intent, PDFRenderErrorReporter* reporter) const = 0;
};
class PDFCMSGeneric : public PDFCMS
{
public:
explicit inline PDFCMSGeneric() = default;
virtual bool isCompatible(const PDFCMSSettings& settings) const override;
virtual QColor getColorFromDeviceGray(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 getColorFromXYZ(const PDFColor3& whitePoint, const PDFColor& color, RenderingIntent intent, PDFRenderErrorReporter* reporter) const override;
};
struct PDFColorSpaceIdentifier
{
enum class Type
{
Gray,
sRGB,
RGB,
CMYK
};
Type type = Type::sRGB;
QString name;
QString id;
PDFReal temperature = 6500.0;
QPointF primaryR;
QPointF primaryG;
QPointF primaryB;
PDFReal gamma = 1.0;
/// Creates gray color space identifier
/// \param name Name of color profile
/// \param id Identifier of color profile
/// \param temperature White point temperature
/// \param gamma Gamma correction
static PDFColorSpaceIdentifier createGray(QString name, QString id, PDFReal temperature, PDFReal gamma);
/// Creates sRGB color space identifier
static PDFColorSpaceIdentifier createSRGB();
/// Creates RGB color space identifier
/// \param name Name of color profile
/// \param id Identifier of color profile
/// \param temperature White point temperature
/// \param primaryR Primary red
/// \param primaryG Primary green
/// \param primaryB Primary blue
/// \param gamma Gamma correction
static PDFColorSpaceIdentifier createRGB(QString name, QString id, PDFReal temperature, QPointF primaryR, QPointF primaryG, QPointF primaryB, PDFReal gamma);
};
using PDFColorSpaceIdentifiers = std::vector<PDFColorSpaceIdentifier>;
/// Manager, that manages current color management system and also list
/// of usable input and output color profiles. It has color profiles
/// for outout device, and color profiles for input (gray/RGB/CMYK).
/// It also handles settings, and it's changes. Constant functions
/// is save to call from multiple threads, this also holds for some
/// non-constant functions - manager is protected by mutexes.
class PDFFORQTLIBSHARED_EXPORT PDFCMSManager : public QObject
{
Q_OBJECT
private:
using BaseClass = QObject;
public:
explicit PDFCMSManager(QObject* parent);
const PDFColorSpaceIdentifiers& getOutputProfiles() const;
const PDFColorSpaceIdentifiers& getGrayProfiles() const;
const PDFColorSpaceIdentifiers& getRGBProfiles() const;
const PDFColorSpaceIdentifiers& getCMYKProfiles() const;
/// Returns default color management settings
PDFCMSSettings getDefaultSettings() const;
/// Get translated name for color management system
/// \param system System
static QString getSystemName(PDFCMSSettings::System system);
signals:
void colorManagementSystemChanged();
private:
PDFColorSpaceIdentifiers getOutputProfilesImpl() const;
PDFColorSpaceIdentifiers getGrayProfilesImpl() const;
PDFColorSpaceIdentifiers getRGBProfilesImpl() const;
PDFColorSpaceIdentifiers getCMYKProfilesImpl() const;
PDFCMSSettings m_settings;
mutable QMutex m_mutex;
mutable PDFCachedItem<PDFColorSpaceIdentifiers> m_outputProfiles;
mutable PDFCachedItem<PDFColorSpaceIdentifiers> m_grayProfiles;
mutable PDFCachedItem<PDFColorSpaceIdentifiers> m_RGBProfiles;
mutable PDFCachedItem<PDFColorSpaceIdentifiers> m_CMYKProfiles;
};
} // namespace pdf
#endif // PDFCMS_H

View File

@ -150,6 +150,7 @@ enum class RendererEngine
enum class RenderingIntent
{
Auto, ///< Rendering intent is automatically selected
Perceptual,
AbsoluteColorimetric,
RelativeColorimetric,

View File

@ -26,5 +26,6 @@
<file>resources/shortcuts.svg</file>
<file>resources/info.svg</file>
<file>resources/send-mail.svg</file>
<file>resources/cms.svg</file>
</qresource>
</RCC>

View File

@ -59,9 +59,10 @@
namespace pdfviewer
{
PDFViewerMainWindow::PDFViewerMainWindow(QWidget *parent) :
PDFViewerMainWindow::PDFViewerMainWindow(QWidget* parent) :
QMainWindow(parent),
ui(new Ui::PDFViewerMainWindow),
m_CMSManager(new pdf::PDFCMSManager(this)),
m_settings(new PDFViewerSettings(this)),
m_pdfWidget(nullptr),
m_sidebarDockWidget(nullptr),
@ -544,8 +545,7 @@ void PDFViewerMainWindow::readSettings()
restoreState(state);
}
m_settings->readSettings(settings);
m_settings->readSettings(settings, m_CMSManager->getDefaultSettings());
}
void PDFViewerMainWindow::readActionSettings()
@ -976,10 +976,11 @@ void PDFViewerMainWindow::on_actionRendering_Errors_triggered()
void PDFViewerMainWindow::on_actionOptions_triggered()
{
PDFViewerSettingsDialog dialog(m_settings->getSettings(), getActions(), this);
PDFViewerSettingsDialog dialog(m_settings->getSettings(), m_settings->getColorManagementSystemSettings(), getActions(), m_CMSManager, this);
if (dialog.exec() == QDialog::Accepted)
{
m_settings->setSettings(dialog.getSettings());
m_settings->setColorManagementSystemSettings(dialog.getCMSSettings());
}
}

View File

@ -139,6 +139,7 @@ private:
};
Ui::PDFViewerMainWindow* ui;
pdf::PDFCMSManager* m_CMSManager;
PDFViewerSettings* m_settings;
pdf::PDFWidget* m_pdfWidget;
QSharedPointer<pdf::PDFDocument> m_pdfDocument;

View File

@ -26,11 +26,14 @@ const int PIXMAP_CACHE_LIMIT = QPixmapCache::cacheLimit();
void PDFViewerSettings::setSettings(const PDFViewerSettings::Settings& settings)
{
m_settings = settings;
emit settingsChanged();
if (m_settings != settings)
{
m_settings = settings;
emit settingsChanged();
}
}
void PDFViewerSettings::readSettings(QSettings& settings)
void PDFViewerSettings::readSettings(QSettings& settings, const pdf::PDFCMSSettings& defaultCMSSettings)
{
Settings defaultSettings;
@ -52,6 +55,18 @@ void PDFViewerSettings::readSettings(QSettings& settings)
m_settings.m_allowLaunchURI = settings.value("allowLaunchURI", defaultSettings.m_allowLaunchURI).toBool();
settings.endGroup();
settings.beginGroup("ColorManagementSystemSettings");
m_colorManagementSystemSettings.system = static_cast<pdf::PDFCMSSettings::System>(settings.value("system", int(defaultCMSSettings.system)).toInt());
m_colorManagementSystemSettings.accuracy = static_cast<pdf::PDFCMSSettings::Accuracy>(settings.value("accuracy", int(defaultCMSSettings.accuracy)).toInt());
m_colorManagementSystemSettings.intent = static_cast<pdf::RenderingIntent>(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.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();
m_colorManagementSystemSettings.deviceCMYK = settings.value("deviceCMYK", defaultCMSSettings.deviceCMYK).toString();
settings.endGroup();
emit settingsChanged();
}
@ -74,6 +89,18 @@ void PDFViewerSettings::writeSettings(QSettings& settings)
settings.setValue("allowLaunchApplications", m_settings.m_allowLaunchApplications);
settings.setValue("allowLaunchURI", m_settings.m_allowLaunchURI);
settings.endGroup();
settings.beginGroup("ColorManagementSystemSettings");
settings.setValue("system", int(m_colorManagementSystemSettings.system));
settings.setValue("accuracy", int(m_colorManagementSystemSettings.accuracy));
settings.setValue("intent", int(m_colorManagementSystemSettings.intent));
settings.setValue("isBlackPointCompensationActive", m_colorManagementSystemSettings.isBlackPointCompensationActive);
settings.setValue("isWhitePaperColorTransformed", m_colorManagementSystemSettings.isWhitePaperColorTransformed);
settings.setValue("outputCS", m_colorManagementSystemSettings.outputCS);
settings.setValue("deviceGray", m_colorManagementSystemSettings.deviceGray);
settings.setValue("deviceRGB", m_colorManagementSystemSettings.deviceRGB);
settings.setValue("deviceCMYK", m_colorManagementSystemSettings.deviceCMYK);
settings.endGroup();
}
QString PDFViewerSettings::getDirectory() const

View File

@ -19,6 +19,7 @@
#define PDFVIEWERSETTINGS_H
#include "pdfrenderer.h"
#include "pdfcms.h"
#include <QObject>
@ -40,6 +41,9 @@ public:
{
Settings();
bool operator==(const Settings&) const = default;
bool operator!=(const Settings&) const = default;
pdf::PDFRenderer::Features m_features;
QString m_directory;
pdf::RendererEngine m_rendererEngine;
@ -62,7 +66,7 @@ public:
const Settings& getSettings() const { return m_settings; }
void setSettings(const Settings& settings);
void readSettings(QSettings& settings);
void readSettings(QSettings& settings, const pdf::PDFCMSSettings& defaultCMSSettings);
void writeSettings(QSettings& settings);
QString getDirectory() const;
@ -94,14 +98,17 @@ public:
int getFontCacheLimit() const { return m_settings.m_fontCacheLimit; }
int getInstancedFontCacheLimit() const { return m_settings.m_instancedFontCacheLimit; }
const pdf::PDFCMSSettings& getColorManagementSystemSettings() const { return m_colorManagementSystemSettings; }
void setColorManagementSystemSettings(const pdf::PDFCMSSettings& settings) { m_colorManagementSystemSettings = settings; }
signals:
void settingsChanged();
private:
Settings m_settings;
pdf::PDFCMSSettings m_colorManagementSystemSettings;
};
} // namespace pdfviewer
#endif // PDFVIEWERSETTINGS_H

View File

@ -29,10 +29,14 @@
namespace pdfviewer
{
PDFViewerSettingsDialog::PDFViewerSettingsDialog(const PDFViewerSettings::Settings& settings, QList<QAction*> actions, QWidget *parent) :
PDFViewerSettingsDialog::PDFViewerSettingsDialog(const PDFViewerSettings::Settings& settings,
const pdf::PDFCMSSettings& cmsSettings,
QList<QAction*> actions,
pdf::PDFCMSManager* cmsManager, QWidget *parent) :
QDialog(parent),
ui(new Ui::PDFViewerSettingsDialog),
m_settings(settings),
m_cmsSettings(cmsSettings),
m_actions(),
m_isLoadingData(false)
{
@ -43,6 +47,7 @@ PDFViewerSettingsDialog::PDFViewerSettingsDialog(const PDFViewerSettings::Settin
new QListWidgetItem(QIcon(":/resources/shading.svg"), tr("Shading"), ui->optionsPagesWidget, ShadingSettings);
new QListWidgetItem(QIcon(":/resources/cache.svg"), tr("Cache"), ui->optionsPagesWidget, CacheSettings);
new QListWidgetItem(QIcon(":/resources/shortcuts.svg"), tr("Shortcuts"), ui->optionsPagesWidget, ShortcutSettings);
new QListWidgetItem(QIcon(":/resources/cms.svg"), tr("Colors"), ui->optionsPagesWidget, ColorManagementSystemSettings);
new QListWidgetItem(QIcon(":/resources/security.svg"), tr("Security"), ui->optionsPagesWidget, SecuritySettings);
ui->renderingEngineComboBox->addItem(tr("Software"), static_cast<int>(pdf::RendererEngine::Software));
@ -53,7 +58,33 @@ PDFViewerSettingsDialog::PDFViewerSettingsDialog(const PDFViewerSettings::Settin
ui->multisampleAntialiasingSamplesCountComboBox->addItem(QString::number(i), i);
}
for (QWidget* widget : { ui->engineInfoLabel, ui->renderingInfoLabel, ui->securityInfoLabel })
// Load CMS data
ui->cmsTypeComboBox->addItem(pdf::PDFCMSManager::getSystemName(pdf::PDFCMSSettings::System::Generic), int(pdf::PDFCMSSettings::System::Generic));
ui->cmsTypeComboBox->addItem(pdf::PDFCMSManager::getSystemName(pdf::PDFCMSSettings::System::LittleCMS2), int(pdf::PDFCMSSettings::System::LittleCMS2));
ui->cmsRenderingIntentComboBox->addItem(tr("Auto"), int(pdf::RenderingIntent::Auto));
ui->cmsRenderingIntentComboBox->addItem(tr("Perceptual"), int(pdf::RenderingIntent::Perceptual));
ui->cmsRenderingIntentComboBox->addItem(tr("Relative colorimetric"), int(pdf::RenderingIntent::RelativeColorimetric));
ui->cmsRenderingIntentComboBox->addItem(tr("Absolute colorimetric"), int(pdf::RenderingIntent::AbsoluteColorimetric));
ui->cmsRenderingIntentComboBox->addItem(tr("Saturation"), int(pdf::RenderingIntent::Saturation));
ui->cmsAccuracyComboBox->addItem(tr("Low"), int(pdf::PDFCMSSettings::Accuracy::Low));
ui->cmsAccuracyComboBox->addItem(tr("Medium"), int(pdf::PDFCMSSettings::Accuracy::Medium));
ui->cmsAccuracyComboBox->addItem(tr("High"), int(pdf::PDFCMSSettings::Accuracy::High));
auto fillColorProfileList = [](QComboBox* comboBox, const pdf::PDFColorSpaceIdentifiers& identifiers)
{
for (const pdf::PDFColorSpaceIdentifier& identifier : identifiers)
{
comboBox->addItem(identifier.name, identifier.id);
}
};
fillColorProfileList(ui->cmsOutputColorProfileComboBox, cmsManager->getOutputProfiles());
fillColorProfileList(ui->cmsDeviceGrayColorProfileComboBox, cmsManager->getGrayProfiles());
fillColorProfileList(ui->cmsDeviceRGBColorProfileComboBox, cmsManager->getRGBProfiles());
fillColorProfileList(ui->cmsDeviceCMYKColorProfileComboBox, cmsManager->getCMYKProfiles());
for (QWidget* widget : { ui->engineInfoLabel, ui->renderingInfoLabel, ui->securityInfoLabel, ui->cmsInfoLabel })
{
widget->setMinimumWidth(widget->sizeHint().width());
}
@ -120,6 +151,10 @@ void PDFViewerSettingsDialog::on_optionsPagesWidget_currentItemChanged(QListWidg
ui->stackedWidget->setCurrentWidget(ui->shortcutsPage);
break;
case ColorManagementSystemSettings:
ui->stackedWidget->setCurrentWidget(ui->cmsPage);
break;
case SecuritySettings:
ui->stackedWidget->setCurrentWidget(ui->securityPage);
break;
@ -183,6 +218,47 @@ void PDFViewerSettingsDialog::loadData()
// Security
ui->allowLaunchCheckBox->setChecked(m_settings.m_allowLaunchApplications);
ui->allowRunURICheckBox->setChecked(m_settings.m_allowLaunchURI);
// CMS
ui->cmsTypeComboBox->setCurrentIndex(ui->cmsTypeComboBox->findData(int(m_cmsSettings.system)));
if (m_cmsSettings.system != pdf::PDFCMSSettings::System::Generic)
{
ui->cmsRenderingIntentComboBox->setEnabled(true);
ui->cmsRenderingIntentComboBox->setCurrentIndex(ui->cmsRenderingIntentComboBox->findData(int(m_cmsSettings.intent)));
ui->cmsAccuracyComboBox->setEnabled(true);
ui->cmsAccuracyComboBox->setCurrentIndex(ui->cmsAccuracyComboBox->findData(int(m_cmsSettings.accuracy)));
ui->cmsIsBlackPointCompensationCheckBox->setEnabled(true);
ui->cmsIsBlackPointCompensationCheckBox->setChecked(m_cmsSettings.isBlackPointCompensationActive);
ui->cmsWhitePaperColorTransformedCheckBox->setEnabled(true);
ui->cmsWhitePaperColorTransformedCheckBox->setChecked(m_cmsSettings.isWhitePaperColorTransformed);
ui->cmsOutputColorProfileComboBox->setEnabled(true);
ui->cmsOutputColorProfileComboBox->setCurrentIndex(ui->cmsOutputColorProfileComboBox->findData(m_cmsSettings.outputCS));
ui->cmsDeviceGrayColorProfileComboBox->setEnabled(true);
ui->cmsDeviceGrayColorProfileComboBox->setCurrentIndex(ui->cmsDeviceGrayColorProfileComboBox->findData(m_cmsSettings.deviceGray));
ui->cmsDeviceRGBColorProfileComboBox->setEnabled(true);
ui->cmsDeviceRGBColorProfileComboBox->setCurrentIndex(ui->cmsDeviceRGBColorProfileComboBox->findData(m_cmsSettings.deviceRGB));
ui->cmsDeviceCMYKColorProfileComboBox->setEnabled(true);
ui->cmsDeviceCMYKColorProfileComboBox->setCurrentIndex(ui->cmsDeviceCMYKColorProfileComboBox->findData(m_cmsSettings.deviceCMYK));
}
else
{
ui->cmsRenderingIntentComboBox->setEnabled(false);
ui->cmsRenderingIntentComboBox->setCurrentIndex(-1);
ui->cmsAccuracyComboBox->setEnabled(false);
ui->cmsAccuracyComboBox->setCurrentIndex(-1);
ui->cmsIsBlackPointCompensationCheckBox->setEnabled(false);
ui->cmsIsBlackPointCompensationCheckBox->setChecked(false);
ui->cmsWhitePaperColorTransformedCheckBox->setEnabled(false);
ui->cmsWhitePaperColorTransformedCheckBox->setChecked(false);
ui->cmsOutputColorProfileComboBox->setEnabled(false);
ui->cmsOutputColorProfileComboBox->setCurrentIndex(-1);
ui->cmsDeviceGrayColorProfileComboBox->setEnabled(false);
ui->cmsDeviceGrayColorProfileComboBox->setCurrentIndex(-1);
ui->cmsDeviceRGBColorProfileComboBox->setEnabled(false);
ui->cmsDeviceRGBColorProfileComboBox->setCurrentIndex(-1);
ui->cmsDeviceCMYKColorProfileComboBox->setEnabled(false);
ui->cmsDeviceCMYKColorProfileComboBox->setCurrentIndex(-1);
}
}
void PDFViewerSettingsDialog::saveData()
@ -270,6 +346,42 @@ void PDFViewerSettingsDialog::saveData()
{
m_settings.m_instancedFontCacheLimit = ui->cachedInstancedFontLimitEdit->value();
}
else if (sender == ui->cmsTypeComboBox)
{
m_cmsSettings.system = static_cast<pdf::PDFCMSSettings::System>(ui->cmsTypeComboBox->currentData().toInt());
}
else if (sender == ui->cmsRenderingIntentComboBox)
{
m_cmsSettings.intent = static_cast<pdf::RenderingIntent>(ui->cmsRenderingIntentComboBox->currentData().toInt());
}
else if (sender == ui->cmsAccuracyComboBox)
{
m_cmsSettings.accuracy = static_cast<pdf::PDFCMSSettings::Accuracy>(ui->cmsAccuracyComboBox->currentData().toInt());
}
else if (sender == ui->cmsIsBlackPointCompensationCheckBox)
{
m_cmsSettings.isBlackPointCompensationActive = ui->cmsIsBlackPointCompensationCheckBox->isChecked();
}
else if (sender == ui->cmsWhitePaperColorTransformedCheckBox)
{
m_cmsSettings.isWhitePaperColorTransformed = ui->cmsWhitePaperColorTransformedCheckBox->isChecked();
}
else if (sender == ui->cmsOutputColorProfileComboBox)
{
m_cmsSettings.outputCS = ui->cmsOutputColorProfileComboBox->currentData().toString();
}
else if (sender == ui->cmsDeviceGrayColorProfileComboBox)
{
m_cmsSettings.deviceGray = ui->cmsDeviceGrayColorProfileComboBox->currentData().toString();
}
else if (sender == ui->cmsDeviceRGBColorProfileComboBox)
{
m_cmsSettings.deviceRGB = ui->cmsDeviceRGBColorProfileComboBox->currentData().toString();
}
else if (sender == ui->cmsDeviceCMYKColorProfileComboBox)
{
m_cmsSettings.deviceCMYK = ui->cmsDeviceCMYKColorProfileComboBox->currentData().toString();
}
loadData();
}

View File

@ -37,7 +37,17 @@ class PDFViewerSettingsDialog : public QDialog
Q_OBJECT
public:
explicit PDFViewerSettingsDialog(const PDFViewerSettings::Settings& settings, QList<QAction*> actions, QWidget* parent);
/// Constructor
/// \param settings Viewer settings
/// \param cmsSettings Color management system settings
/// \param actions Actions
/// \param cmsManager CMS manager
/// \param parent Parent widget
explicit PDFViewerSettingsDialog(const PDFViewerSettings::Settings& settings,
const pdf::PDFCMSSettings& cmsSettings,
QList<QAction*> actions,
pdf::PDFCMSManager* cmsManager,
QWidget* parent);
virtual ~PDFViewerSettingsDialog() override;
virtual void accept() override;
@ -49,10 +59,12 @@ public:
ShadingSettings,
CacheSettings,
ShortcutSettings,
ColorManagementSystemSettings,
SecuritySettings
};
const PDFViewerSettings::Settings& getSettings() const { return m_settings; }
const pdf::PDFCMSSettings& getCMSSettings() const { return m_cmsSettings; }
private slots:
void on_optionsPagesWidget_currentItemChanged(QListWidgetItem* current, QListWidgetItem* previous);
@ -66,6 +78,7 @@ private:
Ui::PDFViewerSettingsDialog* ui;
PDFViewerSettings::Settings m_settings;
pdf::PDFCMSSettings m_cmsSettings;
QList<QAction*> m_actions;
bool m_isLoadingData;
};

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>720</width>
<height>538</height>
<width>742</width>
<height>573</height>
</rect>
</property>
<property name="windowTitle">
@ -26,7 +26,7 @@
<item>
<widget class="QStackedWidget" name="stackedWidget">
<property name="currentIndex">
<number>4</number>
<number>5</number>
</property>
<widget class="QWidget" name="enginePage">
<layout class="QVBoxLayout" name="enginePageLayout">
@ -564,6 +564,144 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="cmsPage">
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QGroupBox" name="cmsGroupBox">
<property name="title">
<string>Color management system settings</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<layout class="QGridLayout" name="cmsWidgetsLayout">
<item row="0" column="1">
<widget class="QComboBox" name="cmsTypeComboBox"/>
</item>
<item row="4" column="1">
<widget class="QCheckBox" name="cmsWhitePaperColorTransformedCheckBox">
<property name="text">
<string>Enabled</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="cmsWhitePaperColorTransformedLabel">
<property name="text">
<string>White paper color transformed</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="cmsDeviceRGBProfileLabel">
<property name="text">
<string>Device RGB color profile</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="cmsOutputProfileLabel">
<property name="text">
<string>Output color profile</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="cmsIsBlackPointCompensationCheckBox">
<property name="text">
<string>Enabled</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="cmsDeviceGrayColorProfileLabel">
<property name="text">
<string>Device gray color profile</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="cmsRenderingIntentComboBox"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="cmsRenderingIntentLabel">
<property name="text">
<string>Rendering intent</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="cmsAccuracyComboBox"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="cmsAccuracyLabel">
<property name="text">
<string>Accuracy</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="cmsLabel">
<property name="text">
<string>Color management system</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="cmsBlackPointCompensationLabel">
<property name="text">
<string>Black point compensation</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="cmsDeviceCMYKColorProfileLabel">
<property name="text">
<string>Device CMYK color profile</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QComboBox" name="cmsOutputColorProfileComboBox"/>
</item>
<item row="6" column="1">
<widget class="QComboBox" name="cmsDeviceGrayColorProfileComboBox"/>
</item>
<item row="7" column="1">
<widget class="QComboBox" name="cmsDeviceRGBColorProfileComboBox"/>
</item>
<item row="8" column="1">
<widget class="QComboBox" name="cmsDeviceCMYKColorProfileComboBox"/>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="cmsInfoLabel">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Color management system &lt;/span&gt;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. &lt;span style=&quot; font-weight:600;&quot;&gt;Rendering intent&lt;/span&gt; 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'. &lt;span style=&quot; font-weight:600;&quot;&gt;Accuracy &lt;/span&gt;affects how precise the color transformation would be, at the cost of more memory consumption. &lt;span style=&quot; font-weight:600;&quot;&gt;Black point compensation&lt;/span&gt; compensates black colors out of gamut. &lt;span style=&quot; font-weight:600;&quot;&gt;White paper color transformed &lt;/span&gt;affects color of the underlying white paper - it transforms pure white from device RGB profile to output profile, if enabled.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Output color profile&lt;/span&gt; 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 &lt;span style=&quot; font-weight:600;&quot;&gt;gray/RGB/CMYK&lt;/span&gt; device color spaces, which are used to transform gray/RGB/CMYK colors to the output color profile.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="cmsVerticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>41</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="securityPage">
<layout class="QVBoxLayout" name="securityPageLayout">
<property name="leftMargin">

View File

@ -0,0 +1,110 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="30mm"
height="30mm"
viewBox="0 0 30 30"
version="1.1"
id="svg8"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
sodipodi:docname="cms.svg">
<defs
id="defs2">
<inkscape:path-effect
effect="spiro"
id="path-effect831"
is_visible="true" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.6"
inkscape:cx="164.25422"
inkscape:cy="113.44001"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="3840"
inkscape:window-height="2035"
inkscape:window-x="-13"
inkscape:window-y="-13"
inkscape:window-maximized="1" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<cc:license
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
<dc:creator>
<cc:Agent>
<dc:title>Jakub Melka</dc:title>
</cc:Agent>
</dc:creator>
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Notice" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Attribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
</cc:License>
</rdf:RDF>
</metadata>
<g
inkscape:label="Vrstva 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-267)">
<path
style="fill:none;stroke:#000000;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 11.646391,283.58184 v 0 0"
id="path837"
inkscape:connector-curvature="0" />
<ellipse
style="fill:#969696;fill-opacity:0.75294119;stroke:none;stroke-width:1.3012532;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
id="path876"
cx="9.6383934"
cy="277.41611"
rx="7.7485123"
ry="7.9611235" />
<ellipse
style="fill:#000000;fill-opacity:0.75294119;stroke:none;stroke-width:1.3012532;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
id="path876-0"
cx="19.607515"
cy="278.33743"
rx="7.7485123"
ry="7.9611239" />
<ellipse
style="fill:#e6e6e6;fill-opacity:0.75294119;stroke:none;stroke-width:1.3012532;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
id="path876-06"
cx="13.512649"
cy="286.41666"
rx="7.7485123"
ry="7.9611239" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.7 KiB