mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
Loading external color profiles
This commit is contained in:
@ -17,6 +17,8 @@
|
||||
|
||||
#include "pdfcms.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:5033)
|
||||
#include <lcms2.h>
|
||||
@ -25,6 +27,46 @@
|
||||
namespace pdf
|
||||
{
|
||||
|
||||
QString getInfoFromProfile(cmsHPROFILE profile, cmsInfoType infoType)
|
||||
{
|
||||
QLocale locale;
|
||||
QString country = QLocale::countryToString(locale.country());
|
||||
QString language = QLocale::languageToString(locale.language());
|
||||
|
||||
char countryCode[3] = { };
|
||||
char languageCode[3] = { };
|
||||
if (country.size() == 2)
|
||||
{
|
||||
countryCode[0] = country[0].toLatin1();
|
||||
countryCode[1] = country[1].toLatin1();
|
||||
}
|
||||
if (language.size() == 2)
|
||||
{
|
||||
languageCode[0] = language[0].toLatin1();
|
||||
languageCode[1] = language[1].toLatin1();
|
||||
}
|
||||
|
||||
// Jakub Melka: try to get profile info from current language/country.
|
||||
// If it fails, then pick any language/any country.
|
||||
cmsUInt32Number bufferSize = cmsGetProfileInfo(profile, infoType, languageCode, countryCode, nullptr, 0);
|
||||
if (bufferSize)
|
||||
{
|
||||
std::vector<wchar_t> buffer(bufferSize, 0);
|
||||
cmsGetProfileInfo(profile, infoType, languageCode, countryCode, buffer.data(), static_cast<cmsUInt32Number>(buffer.size()));
|
||||
return QString::fromWCharArray(buffer.data());
|
||||
}
|
||||
|
||||
bufferSize = cmsGetProfileInfo(profile, infoType, cmsNoLanguage, cmsNoCountry, nullptr, 0);
|
||||
if (bufferSize)
|
||||
{
|
||||
std::vector<wchar_t> buffer(bufferSize, 0);
|
||||
cmsGetProfileInfo(profile, infoType, cmsNoLanguage, cmsNoCountry, buffer.data(), static_cast<cmsUInt32Number>(buffer.size()));
|
||||
return QString::fromWCharArray(buffer.data());
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
bool PDFCMSGeneric::isCompatible(const PDFCMSSettings& settings) const
|
||||
{
|
||||
return settings.system == PDFCMSSettings::System::Generic;
|
||||
@ -69,35 +111,62 @@ PDFCMSManager::PDFCMSManager(QObject* parent) :
|
||||
|
||||
}
|
||||
|
||||
const PDFColorSpaceIdentifiers& PDFCMSManager::getOutputProfiles() const
|
||||
void PDFCMSManager::setSettings(const PDFCMSSettings& settings)
|
||||
{
|
||||
if (m_settings != settings)
|
||||
{
|
||||
// We must ensure, that mutex is not locked, while we are
|
||||
// sending signal about CMS change.
|
||||
{
|
||||
QMutexLocker lock(&m_mutex);
|
||||
m_settings = settings;
|
||||
m_outputProfiles.dirty();
|
||||
m_grayProfiles.dirty();
|
||||
m_RGBProfiles.dirty();
|
||||
m_CMYKProfiles.dirty();
|
||||
m_externalProfiles.dirty();
|
||||
}
|
||||
|
||||
emit colorManagementSystemChanged();
|
||||
}
|
||||
}
|
||||
|
||||
const PDFColorProfileIdentifiers& PDFCMSManager::getOutputProfiles() const
|
||||
{
|
||||
QMutexLocker lock(&m_mutex);
|
||||
return m_outputProfiles.get(this, &PDFCMSManager::getOutputProfilesImpl);
|
||||
}
|
||||
|
||||
const PDFColorSpaceIdentifiers& PDFCMSManager::getGrayProfiles() const
|
||||
const PDFColorProfileIdentifiers& PDFCMSManager::getGrayProfiles() const
|
||||
{
|
||||
QMutexLocker lock(&m_mutex);
|
||||
return m_grayProfiles.get(this, &PDFCMSManager::getGrayProfilesImpl);
|
||||
}
|
||||
|
||||
const PDFColorSpaceIdentifiers& PDFCMSManager::getRGBProfiles() const
|
||||
const PDFColorProfileIdentifiers& PDFCMSManager::getRGBProfiles() const
|
||||
{
|
||||
QMutexLocker lock(&m_mutex);
|
||||
return m_RGBProfiles.get(this, &PDFCMSManager::getRGBProfilesImpl);
|
||||
}
|
||||
|
||||
const PDFColorSpaceIdentifiers& PDFCMSManager::getCMYKProfiles() const
|
||||
const PDFColorProfileIdentifiers& PDFCMSManager::getCMYKProfiles() const
|
||||
{
|
||||
QMutexLocker lock(&m_mutex);
|
||||
return m_CMYKProfiles.get(this, &PDFCMSManager::getCMYKProfilesImpl);
|
||||
}
|
||||
|
||||
const PDFColorProfileIdentifiers& PDFCMSManager::getExternalProfiles() const
|
||||
{
|
||||
// Jakub Melka: do not protect this by mutex, this function is private
|
||||
// and must be called only from mutex-protected code.
|
||||
return m_externalProfiles.get(this, &PDFCMSManager::getExternalProfilesImpl);
|
||||
}
|
||||
|
||||
PDFCMSSettings PDFCMSManager::getDefaultSettings() const
|
||||
{
|
||||
PDFCMSSettings settings;
|
||||
|
||||
auto getFirstProfileId = [](const PDFColorSpaceIdentifiers& identifiers)
|
||||
auto getFirstProfileId = [](const PDFColorProfileIdentifiers& identifiers)
|
||||
{
|
||||
if (!identifiers.empty())
|
||||
{
|
||||
@ -139,51 +208,145 @@ QString PDFCMSManager::getSystemName(PDFCMSSettings::System system)
|
||||
return QString();
|
||||
}
|
||||
|
||||
PDFColorSpaceIdentifiers PDFCMSManager::getOutputProfilesImpl() const
|
||||
PDFColorProfileIdentifiers PDFCMSManager::getOutputProfilesImpl() const
|
||||
{
|
||||
// Currently, we only support sRGB output color profile.
|
||||
return { PDFColorSpaceIdentifier::createSRGB() };
|
||||
return { PDFColorProfileIdentifier::createSRGB() };
|
||||
}
|
||||
|
||||
PDFColorSpaceIdentifiers PDFCMSManager::getGrayProfilesImpl() const
|
||||
PDFColorProfileIdentifiers 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)
|
||||
PDFColorProfileIdentifiers result =
|
||||
{
|
||||
PDFColorProfileIdentifier::createGray(tr("Gray D65, γ = 2.2"), "@GENERIC_Gray_D65_g22", 6500.0, 2.2),
|
||||
PDFColorProfileIdentifier::createGray(tr("Gray D50, γ = 2.2"), "@GENERIC_Gray_D50_g22", 5000.0, 2.2),
|
||||
PDFColorProfileIdentifier::createGray(tr("Gray D93, γ = 2.2"), "@GENERIC_Gray_D93_g22", 9300.0, 2.2),
|
||||
PDFColorProfileIdentifier::createGray(tr("Gray D65, γ = 1.0 (linear)"), "@GENERIC_Gray_D65_g10", 6500.0, 1.0),
|
||||
PDFColorProfileIdentifier::createGray(tr("Gray D50, γ = 1.0 (linear)"), "@GENERIC_Gray_D50_g10", 5000.0, 1.0),
|
||||
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());
|
||||
return result;
|
||||
}
|
||||
|
||||
PDFColorSpaceIdentifiers PDFCMSManager::getRGBProfilesImpl() const
|
||||
PDFColorProfileIdentifiers 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)
|
||||
PDFColorProfileIdentifiers result =
|
||||
{
|
||||
PDFColorProfileIdentifier::createSRGB(),
|
||||
PDFColorProfileIdentifier::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),
|
||||
PDFColorProfileIdentifier::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),
|
||||
PDFColorProfileIdentifier::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),
|
||||
PDFColorProfileIdentifier::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),
|
||||
PDFColorProfileIdentifier::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),
|
||||
PDFColorProfileIdentifier::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)
|
||||
};
|
||||
|
||||
PDFColorProfileIdentifiers externalRGBProfiles = getFilteredExternalProfiles(PDFColorProfileIdentifier::Type::FileRGB);
|
||||
result.insert(result.end(), externalRGBProfiles.begin(), externalRGBProfiles.end());
|
||||
return result;
|
||||
}
|
||||
|
||||
PDFColorSpaceIdentifiers PDFCMSManager::getCMYKProfilesImpl() const
|
||||
PDFColorProfileIdentifiers PDFCMSManager::getCMYKProfilesImpl() const
|
||||
{
|
||||
return {
|
||||
|
||||
};
|
||||
return getFilteredExternalProfiles(PDFColorProfileIdentifier::Type::FileCMYK);
|
||||
}
|
||||
|
||||
PDFColorSpaceIdentifier PDFColorSpaceIdentifier::createGray(QString name, QString id, PDFReal temperature, PDFReal gamma)
|
||||
PDFColorProfileIdentifiers PDFCMSManager::getExternalColorProfiles(QString profileDirectory) const
|
||||
{
|
||||
PDFColorSpaceIdentifier result;
|
||||
PDFColorProfileIdentifiers result;
|
||||
|
||||
QDir directory(profileDirectory);
|
||||
if (!profileDirectory.isEmpty() && directory.exists())
|
||||
{
|
||||
QStringList iccProfiles = directory.entryList({ "*.icc" }, QDir::Files | QDir::Readable | QDir::NoDotAndDotDot, QDir::NoSort);
|
||||
for (const QString& fileName : iccProfiles)
|
||||
{
|
||||
QString filePath = directory.absoluteFilePath(fileName);
|
||||
|
||||
// Try to read the profile from the file. If it fails, then do nothing.
|
||||
QFile file(filePath);
|
||||
if (file.open(QFile::ReadOnly))
|
||||
{
|
||||
QByteArray content = file.readAll();
|
||||
file.close();
|
||||
|
||||
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::FileGray;
|
||||
break;
|
||||
|
||||
case cmsSigRgbData:
|
||||
csiType = PDFColorProfileIdentifier::Type::FileRGB;
|
||||
break;
|
||||
|
||||
case cmsSigCmykData:
|
||||
csiType = PDFColorProfileIdentifier::Type::FileCMYK;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
QString description = getInfoFromProfile(profile, cmsInfoDescription);
|
||||
cmsCloseProfile(profile);
|
||||
|
||||
// If we have a valid profile, then add it
|
||||
if (csiType != PDFColorProfileIdentifier::Type::Invalid)
|
||||
{
|
||||
result.emplace_back(PDFColorProfileIdentifier::createFile(csiType, qMove(description), filePath));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
PDFColorProfileIdentifiers PDFCMSManager::getExternalProfilesImpl() const
|
||||
{
|
||||
PDFColorProfileIdentifiers result;
|
||||
|
||||
QStringList directories(m_settings.profileDirectory);
|
||||
QDir applicationDirectory(QApplication::applicationDirPath());
|
||||
if (applicationDirectory.cd("colorprofiles"))
|
||||
{
|
||||
directories << applicationDirectory.absolutePath();
|
||||
}
|
||||
|
||||
for (const QString& directory : directories)
|
||||
{
|
||||
PDFColorProfileIdentifiers externalProfiles = getExternalColorProfiles(directory);
|
||||
result.insert(result.end(), externalProfiles.begin(), externalProfiles.end());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
PDFColorProfileIdentifiers PDFCMSManager::getFilteredExternalProfiles(PDFColorProfileIdentifier::Type type) const
|
||||
{
|
||||
PDFColorProfileIdentifiers result;
|
||||
const PDFColorProfileIdentifiers& externalProfiles = getExternalProfiles();
|
||||
std::copy_if(externalProfiles.cbegin(), externalProfiles.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;
|
||||
result.type = Type::Gray;
|
||||
result.name = qMove(name);
|
||||
result.id = qMove(id);
|
||||
@ -192,18 +355,18 @@ PDFColorSpaceIdentifier PDFColorSpaceIdentifier::createGray(QString name, QStrin
|
||||
return result;
|
||||
}
|
||||
|
||||
PDFColorSpaceIdentifier PDFColorSpaceIdentifier::createSRGB()
|
||||
PDFColorProfileIdentifier PDFColorProfileIdentifier::createSRGB()
|
||||
{
|
||||
PDFColorSpaceIdentifier result;
|
||||
PDFColorProfileIdentifier 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)
|
||||
PDFColorProfileIdentifier PDFColorProfileIdentifier::createRGB(QString name, QString id, PDFReal temperature, QPointF primaryR, QPointF primaryG, QPointF primaryB, PDFReal gamma)
|
||||
{
|
||||
PDFColorSpaceIdentifier result;
|
||||
PDFColorProfileIdentifier result;
|
||||
result.type = Type::RGB;
|
||||
result.name = qMove(name);
|
||||
result.id = qMove(id);
|
||||
@ -215,5 +378,14 @@ PDFColorSpaceIdentifier PDFColorSpaceIdentifier::createRGB(QString name, QString
|
||||
return result;
|
||||
}
|
||||
|
||||
PDFColorProfileIdentifier PDFColorProfileIdentifier::createFile(Type type, QString name, QString id)
|
||||
{
|
||||
PDFColorProfileIdentifier result;
|
||||
result.type = type;
|
||||
result.name = qMove(name);
|
||||
result.id = qMove(id);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace pdf
|
||||
|
||||
|
Reference in New Issue
Block a user