diff --git a/libs/pigment/KoColorProfile.h b/libs/pigment/KoColorProfile.h index f339ba60ed..aca3df8493 100644 --- a/libs/pigment/KoColorProfile.h +++ b/libs/pigment/KoColorProfile.h @@ -1,211 +1,215 @@ /* * Copyright (c) 2007 Cyrille Berger * * This library 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 2.1 of the License, or (at your option) any later version. * * This library 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 this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef _KO_COLOR_PROFILE_H_ #define _KO_COLOR_PROFILE_H_ #include #include #include #include "kritapigment_export.h" /** * Contains information needed for color transformation. */ class KRITAPIGMENT_EXPORT KoColorProfile { public: /** * @param fileName file name to load or save that profile */ explicit KoColorProfile(const QString &fileName = QString()); KoColorProfile(const KoColorProfile& profile); virtual ~KoColorProfile(); /** * @return the type of this profile (icc, ctlcs etc) */ virtual QString type() const { return QString(); } /** * Create a copy of this profile. * Data that shall not change during the life time of the profile shouldn't be * duplicated but shared, like for instance ICC data. * * Data that shall be changed like a palette or hdr information such as exposure * must be duplicated while cloning. */ virtual KoColorProfile* clone() const = 0; /** * Load the profile in memory. * @return true if the profile has been successfully loaded */ virtual bool load(); /** * Override this function to save the profile. * @param fileName destination * @return true if the profile has been successfully saved */ virtual bool save(const QString &fileName); /** * @return true if the profile is valid, false if it isn't been loaded in memory yet, or * if the loaded memory is a bad profile */ virtual bool valid() const = 0; /** * @return the name of this profile */ QString name() const; /** * @return the info of this profile */ QString info() const; /** @return manufacturer of the profile */ QString manufacturer() const; /** * @return the copyright of the profile */ QString copyright() const; /** * @return the filename of the profile (it might be empty) */ QString fileName() const; /** * @param filename new filename */ void setFileName(const QString &filename); /** * Return version */ virtual float version() const = 0; /** * @return true if you can use this profile can be used to convert color from a different * profile to this one */ virtual bool isSuitableForOutput() const = 0; /** * @return true if this profile is suitable to use for printing */ virtual bool isSuitableForPrinting() const = 0; /** * @return true if this profile is suitable to use for display */ virtual bool isSuitableForDisplay() const = 0; /** * @return which rendering intents are supported */ virtual bool supportsPerceptual() const = 0; virtual bool supportsSaturation() const = 0; virtual bool supportsAbsolute() const = 0; virtual bool supportsRelative() const = 0; /** * @return if the profile has colorants. */ virtual bool hasColorants() const = 0; /** * @return a qvector (9) with the RGB colorants in XYZ */ virtual QVector getColorantsXYZ() const = 0; /** * @return a qvector (9) with the RGB colorants in xyY */ virtual QVector getColorantsxyY() const = 0; /** * @return a qvector (3) with the whitepoint in XYZ */ virtual QVector getWhitePointXYZ() const = 0; /** * @return a qvector (3) with the whitepoint in xyY */ virtual QVector getWhitePointxyY() const = 0; /** * @return estimated gamma for RGB and Grayscale profiles */ virtual QVector getEstimatedTRC() const = 0; /** * @return if the profile has a TRC(required for linearisation). */ virtual bool hasTRC() const = 0; + /** + * @return if the profile's TRCs are linear. + */ + virtual bool isLinear() const = 0; /** * Linearizes first 3 values of QVector, leaving other values unchanged. * Returns the same QVector if it is not possible to linearize. */ virtual void linearizeFloatValue(QVector & Value) const = 0; /** * Delinearizes first 3 values of QVector, leaving other values unchanged. * Returns the same QVector if it is not possible to delinearize. * Effectively undoes LinearizeFloatValue. */ virtual void delinearizeFloatValue(QVector & Value) const = 0; /** * More imprecise versions of the above(limited to 16bit, and can't * delinearize above 1.0.) Use this for filters and images. */ virtual void linearizeFloatValueFast(QVector & Value) const = 0; virtual void delinearizeFloatValueFast(QVector & Value) const = 0; virtual QByteArray uniqueId() const = 0; virtual bool operator==(const KoColorProfile&) const = 0; /** * @return an array with the raw data of the profile */ virtual QByteArray rawData() const { return QByteArray(); } protected: /** * Allows to define the name of this profile. */ void setName(const QString &name); /** * Allows to set the information string of that profile. */ void setInfo(const QString &info); /** * Allows to set the manufacturer string of that profile. */ void setManufacturer(const QString &manufacturer); /** * Allows to set the copyright string of that profile. */ void setCopyright(const QString ©right); private: struct Private; Private* const d; }; #endif diff --git a/libs/pigment/colorprofiles/KoDummyColorProfile.cpp b/libs/pigment/colorprofiles/KoDummyColorProfile.cpp index ec6b08a25a..c528dfef37 100644 --- a/libs/pigment/colorprofiles/KoDummyColorProfile.cpp +++ b/libs/pigment/colorprofiles/KoDummyColorProfile.cpp @@ -1,141 +1,145 @@ /* * Copyright (c) 2010 Cyrille Berger * * This library 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 2.1 of the License, or (at your option) any later version. * * This library 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 this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KoDummyColorProfile.h" KoDummyColorProfile::KoDummyColorProfile() { setName("default"); } KoDummyColorProfile::~KoDummyColorProfile() { } KoColorProfile* KoDummyColorProfile::clone() const { return new KoDummyColorProfile(); } bool KoDummyColorProfile::valid() const { return true; } float KoDummyColorProfile::version() const { return 0.0; } bool KoDummyColorProfile::isSuitableForOutput() const { return true; } bool KoDummyColorProfile::isSuitableForPrinting() const { return true; } bool KoDummyColorProfile::isSuitableForDisplay() const { return true; } bool KoDummyColorProfile::supportsPerceptual() const { return true; } bool KoDummyColorProfile::supportsSaturation() const { return true; } bool KoDummyColorProfile::supportsAbsolute() const { return true; } bool KoDummyColorProfile::supportsRelative() const { return true; } bool KoDummyColorProfile::hasColorants() const { return true; } bool KoDummyColorProfile::hasTRC() const { return true; } +bool KoDummyColorProfile::isLinear() const +{ + return true; +} QVector KoDummyColorProfile::getColorantsXYZ() const { QVector d50Dummy(3); d50Dummy<<0.34773<<0.35952<<1.0; return d50Dummy; } QVector KoDummyColorProfile::getColorantsxyY() const { QVector d50Dummy(3); d50Dummy<<0.34773<<0.35952<<1.0; return d50Dummy; } QVector KoDummyColorProfile::getWhitePointXYZ() const { QVector d50Dummy(3); d50Dummy<<0.9642<<1.0000<<0.8249; return d50Dummy; } QVector KoDummyColorProfile::getWhitePointxyY() const { QVector d50Dummy(3); d50Dummy<<0.34773<<0.35952<<1.0; return d50Dummy; } QVector KoDummyColorProfile::getEstimatedTRC() const { QVector Dummy(3); Dummy.fill(2.2); return Dummy; } void KoDummyColorProfile::linearizeFloatValue(QVector & ) const { } void KoDummyColorProfile::delinearizeFloatValue(QVector & ) const { } void KoDummyColorProfile::linearizeFloatValueFast(QVector & ) const { } void KoDummyColorProfile::delinearizeFloatValueFast(QVector & ) const { } bool KoDummyColorProfile::operator==(const KoColorProfile& rhs) const { return dynamic_cast(&rhs); } QByteArray KoDummyColorProfile::uniqueId() const { return QByteArray(); } diff --git a/libs/pigment/colorprofiles/KoDummyColorProfile.h b/libs/pigment/colorprofiles/KoDummyColorProfile.h index 798ae3c2c3..a3b15d5452 100644 --- a/libs/pigment/colorprofiles/KoDummyColorProfile.h +++ b/libs/pigment/colorprofiles/KoDummyColorProfile.h @@ -1,55 +1,56 @@ /* * Copyright (c) 2010 Cyrille Berger * * This library 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 2.1 of the License, or (at your option) any later version. * * This library 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 this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef _KO_DUMMY_COLOR_PROFILE_H_ #define _KO_DUMMY_COLOR_PROFILE_H_ #include "KoColorProfile.h" class KoDummyColorProfile : public KoColorProfile { public: KoDummyColorProfile(); ~KoDummyColorProfile() override; KoColorProfile* clone() const override; bool valid() const override; float version() const override; bool isSuitableForOutput() const override; bool isSuitableForPrinting() const override; bool isSuitableForDisplay() const override; bool supportsPerceptual() const override; bool supportsSaturation() const override; bool supportsAbsolute() const override; bool supportsRelative() const override; bool hasColorants() const override; bool hasTRC() const override; + bool isLinear() const override; QVector getColorantsXYZ() const override; QVector getColorantsxyY() const override; QVector getWhitePointXYZ() const override; QVector getWhitePointxyY() const override; QVector getEstimatedTRC() const override; void linearizeFloatValue(QVector & Value) const override; void delinearizeFloatValue(QVector & Value) const override; void linearizeFloatValueFast(QVector & Value) const override; void delinearizeFloatValueFast(QVector & Value) const override; bool operator==(const KoColorProfile&) const override; QByteArray uniqueId() const override; }; #endif diff --git a/plugins/color/lcms2engine/colorprofiles/IccColorProfile.cpp b/plugins/color/lcms2engine/colorprofiles/IccColorProfile.cpp index 7a4802dc53..f463f52438 100644 --- a/plugins/color/lcms2engine/colorprofiles/IccColorProfile.cpp +++ b/plugins/color/lcms2engine/colorprofiles/IccColorProfile.cpp @@ -1,383 +1,389 @@ /* * Copyright (c) 2007 Cyrille Berger * * This library 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 2.1 of the License, or (at your option) any later version. * * This library 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 this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "IccColorProfile.h" #include #include #include #include #include "QDebug" #include "LcmsColorProfileContainer.h" #include "lcms2.h" struct IccColorProfile::Data::Private { QByteArray rawData; }; IccColorProfile::Data::Data() : d(new Private) { } IccColorProfile::Data::Data(const QByteArray &rawData) : d(new Private) { d->rawData = rawData; } IccColorProfile::Data::~Data() { } QByteArray IccColorProfile::Data::rawData() { return d->rawData; } void IccColorProfile::Data::setRawData(const QByteArray &rawData) { d->rawData = rawData; } IccColorProfile::Container::Container() { } IccColorProfile::Container::~Container() { } struct IccColorProfile::Private { struct Shared { QScopedPointer data; QScopedPointer lcmsProfile; QVector uiMinMaxes; }; QSharedPointer shared; }; IccColorProfile::IccColorProfile(const QString &fileName) : KoColorProfile(fileName), d(new Private) { // QSharedPointer lacks a reset in Qt 4.x d->shared = QSharedPointer(new Private::Shared()); d->shared->data.reset(new Data()); } IccColorProfile::IccColorProfile(const QByteArray &rawData) : KoColorProfile(QString()), d(new Private) { d->shared = QSharedPointer(new Private::Shared()); d->shared->data.reset(new Data()); setRawData(rawData); init(); } IccColorProfile::IccColorProfile(const IccColorProfile &rhs) : KoColorProfile(rhs) , d(new Private(*rhs.d)) { Q_ASSERT(d->shared); } IccColorProfile::~IccColorProfile() { Q_ASSERT(d->shared); } KoColorProfile *IccColorProfile::clone() const { return new IccColorProfile(*this); } QByteArray IccColorProfile::rawData() const { return d->shared->data->rawData(); } void IccColorProfile::setRawData(const QByteArray &rawData) { d->shared->data->setRawData(rawData); } bool IccColorProfile::valid() const { if (d->shared->lcmsProfile) { return d->shared->lcmsProfile->valid(); } return false; } float IccColorProfile::version() const { if (d->shared->lcmsProfile) { return d->shared->lcmsProfile->version(); } return 0.0; } bool IccColorProfile::isSuitableForOutput() const { if (d->shared->lcmsProfile) { return d->shared->lcmsProfile->isSuitableForOutput(); } return false; } bool IccColorProfile::isSuitableForPrinting() const { if (d->shared->lcmsProfile) { return d->shared->lcmsProfile->isSuitableForPrinting(); } return false; } bool IccColorProfile::isSuitableForDisplay() const { if (d->shared->lcmsProfile) { return d->shared->lcmsProfile->isSuitableForDisplay(); } return false; } bool IccColorProfile::supportsPerceptual() const { if (d->shared->lcmsProfile) { return d->shared->lcmsProfile->supportsPerceptual(); } return false; } bool IccColorProfile::supportsSaturation() const { if (d->shared->lcmsProfile) { return d->shared->lcmsProfile->supportsSaturation(); } return false; } bool IccColorProfile::supportsAbsolute() const { if (d->shared->lcmsProfile) { return d->shared->lcmsProfile->supportsAbsolute(); } return false; } bool IccColorProfile::supportsRelative() const { if (d->shared->lcmsProfile) { return d->shared->lcmsProfile->supportsRelative(); } return false; } bool IccColorProfile::hasColorants() const { if (d->shared->lcmsProfile) { return d->shared->lcmsProfile->hasColorants(); } return false; } bool IccColorProfile::hasTRC() const { if (d->shared->lcmsProfile) return d->shared->lcmsProfile->hasTRC(); return false; } +bool IccColorProfile::isLinear() const +{ + if (d->shared->lcmsProfile) + return d->shared->lcmsProfile->isLinear(); + return false; +} QVector IccColorProfile::getColorantsXYZ() const { if (d->shared->lcmsProfile) { return d->shared->lcmsProfile->getColorantsXYZ(); } return QVector(9); } QVector IccColorProfile::getColorantsxyY() const { if (d->shared->lcmsProfile) { return d->shared->lcmsProfile->getColorantsxyY(); } return QVector(9); } QVector IccColorProfile::getWhitePointXYZ() const { QVector d50Dummy(3); d50Dummy << 0.9642 << 1.0000 << 0.8249; if (d->shared->lcmsProfile) { return d->shared->lcmsProfile->getWhitePointXYZ(); } return d50Dummy; } QVector IccColorProfile::getWhitePointxyY() const { QVector d50Dummy(3); d50Dummy << 0.34773 << 0.35952 << 1.0; if (d->shared->lcmsProfile) { return d->shared->lcmsProfile->getWhitePointxyY(); } return d50Dummy; } QVector IccColorProfile::getEstimatedTRC() const { QVector dummy(3); dummy.fill(2.2);//estimated sRGB trc. if (d->shared->lcmsProfile) { return d->shared->lcmsProfile->getEstimatedTRC(); } return dummy; } void IccColorProfile::linearizeFloatValue(QVector & Value) const { if (d->shared->lcmsProfile) d->shared->lcmsProfile->LinearizeFloatValue(Value); } void IccColorProfile::delinearizeFloatValue(QVector & Value) const { if (d->shared->lcmsProfile) d->shared->lcmsProfile->DelinearizeFloatValue(Value); } void IccColorProfile::linearizeFloatValueFast(QVector & Value) const { if (d->shared->lcmsProfile) d->shared->lcmsProfile->LinearizeFloatValueFast(Value); } void IccColorProfile::delinearizeFloatValueFast(QVector &Value) const { if (d->shared->lcmsProfile) d->shared->lcmsProfile->DelinearizeFloatValueFast(Value); } QByteArray IccColorProfile::uniqueId() const { QByteArray dummy; if (d->shared->lcmsProfile) { dummy = d->shared->lcmsProfile->getProfileUniqueId(); } return dummy; } bool IccColorProfile::load() { QFile file(fileName()); file.open(QIODevice::ReadOnly); QByteArray rawData = file.readAll(); setRawData(rawData); file.close(); if (init()) { return true; } qWarning() << "Failed to load profile from " << fileName(); return false; } bool IccColorProfile::save() { return false; } bool IccColorProfile::init() { if (!d->shared->lcmsProfile) { d->shared->lcmsProfile.reset(new LcmsColorProfileContainer(d->shared->data.data())); } if (d->shared->lcmsProfile->init()) { setName(d->shared->lcmsProfile->name()); setInfo(d->shared->lcmsProfile->info()); setManufacturer(d->shared->lcmsProfile->manufacturer()); setCopyright(d->shared->lcmsProfile->copyright()); if (d->shared->lcmsProfile->valid()) { calculateFloatUIMinMax(); } return true; } else { return false; } } LcmsColorProfileContainer *IccColorProfile::asLcms() const { Q_ASSERT(d->shared->lcmsProfile); return d->shared->lcmsProfile.data(); } bool IccColorProfile::operator==(const KoColorProfile &rhs) const { const IccColorProfile *rhsIcc = dynamic_cast(&rhs); if (rhsIcc) { return d->shared == rhsIcc->d->shared; } return false; } const QVector &IccColorProfile::getFloatUIMinMax(void) const { Q_ASSERT(!d->shared->uiMinMaxes.isEmpty()); return d->shared->uiMinMaxes; } void IccColorProfile::calculateFloatUIMinMax(void) { QVector &ret = d->shared->uiMinMaxes; cmsHPROFILE cprofile = d->shared->lcmsProfile->lcmsProfile(); Q_ASSERT(cprofile); cmsColorSpaceSignature color_space_sig = cmsGetColorSpace(cprofile); unsigned int num_channels = cmsChannelsOf(color_space_sig); unsigned int color_space_mask = _cmsLCMScolorSpace(color_space_sig); Q_ASSERT(num_channels >= 1 && num_channels <= 4); // num_channels==1 is for grayscale, we need to handle it Q_ASSERT(color_space_mask); // to try to find the max range of float/doubles for this profile, // pass in min/max int and make the profile convert that // this is far from perfect, we need a better way, if possible to get the "bounds" of a profile uint16_t in_min_pixel[4] = {0, 0, 0, 0}; uint16_t in_max_pixel[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}; qreal out_min_pixel[4] = {0, 0, 0, 0}; qreal out_max_pixel[4] = {0, 0, 0, 0}; cmsHTRANSFORM trans = cmsCreateTransform( cprofile, (COLORSPACE_SH(color_space_mask) | CHANNELS_SH(num_channels) | BYTES_SH(2)), cprofile, (COLORSPACE_SH(color_space_mask) | FLOAT_SH(1) | CHANNELS_SH(num_channels) | BYTES_SH(0)), //NOTE THAT 'BYTES' FIELD IS SET TO ZERO ON DLB because 8 bytes overflows the bitfield INTENT_PERCEPTUAL, 0); // does the intent matter in this case? if (trans) { cmsDoTransform(trans, in_min_pixel, out_min_pixel, 1); cmsDoTransform(trans, in_max_pixel, out_max_pixel, 1); cmsDeleteTransform(trans); }//else, we'll just default to [0..1] below ret.resize(num_channels); for (unsigned int i = 0; i < num_channels; ++i) { if (out_min_pixel[i] < out_max_pixel[i]) { ret[i].minVal = out_min_pixel[i]; ret[i].maxVal = out_max_pixel[i]; } else { // apparently we can't even guarantee that converted_to_double(0x0000) < converted_to_double(0xFFFF) // assume [0..1] in such cases // we need to find a really solid way of determining the bounds of a profile, if possible ret[i].minVal = 0; ret[i].maxVal = 1; } } } diff --git a/plugins/color/lcms2engine/colorprofiles/IccColorProfile.h b/plugins/color/lcms2engine/colorprofiles/IccColorProfile.h index 948876ba66..3eb3ace963 100644 --- a/plugins/color/lcms2engine/colorprofiles/IccColorProfile.h +++ b/plugins/color/lcms2engine/colorprofiles/IccColorProfile.h @@ -1,143 +1,144 @@ /* * Copyright (c) 2007 Cyrille Berger * * This library 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 2.1 of the License, or (at your option) any later version. * * This library 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 this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef _KO_ICC_COLOR_PROFILE_H_ #define _KO_ICC_COLOR_PROFILE_H_ #include "KoColorProfile.h" #include "KoChannelInfo.h" class LcmsColorProfileContainer; /** * This class contains an ICC color profile. */ class IccColorProfile : public KoColorProfile { public: using KoColorProfile::save; /** * Contains the data associated with a profile. This is * shared through internal representation. */ class Data { public: Data(); explicit Data(const QByteArray &rawData); ~Data(); QByteArray rawData(); void setRawData(const QByteArray &); private: struct Private; QScopedPointer const d; }; /** * This class should be used to wrap the ICC profile * representation coming from various CMS engine. */ class Container { public: Container(); virtual ~Container(); public: virtual QString name() const = 0; virtual QString info() const = 0; virtual QString manufacturer() const = 0; virtual QString copyright() const = 0; virtual bool valid() const = 0; virtual bool isSuitableForOutput() const = 0; virtual bool isSuitableForPrinting() const = 0; virtual bool isSuitableForDisplay() const = 0; virtual bool hasColorants() const = 0; virtual QVector getColorantsXYZ() const = 0; virtual QVector getColorantsxyY() const = 0; virtual QVector getWhitePointXYZ() const = 0; virtual QVector getWhitePointxyY() const = 0; virtual QVector getEstimatedTRC() const = 0; virtual QByteArray getProfileUniqueId() const = 0; }; public: explicit IccColorProfile(const QString &fileName = QString()); explicit IccColorProfile(const QByteArray &rawData); IccColorProfile(const IccColorProfile &rhs); ~IccColorProfile() override; KoColorProfile *clone() const override; bool load() override; virtual bool save(); /** * @return an array with the raw data of the profile */ QByteArray rawData() const override; bool valid() const override; float version() const override; bool isSuitableForOutput() const override; bool isSuitableForPrinting() const override; bool isSuitableForDisplay() const override; bool supportsPerceptual() const override; bool supportsSaturation() const override; bool supportsAbsolute() const override; bool supportsRelative() const override; bool hasColorants() const override; bool hasTRC() const override; + bool isLinear() const override; QVector getColorantsXYZ() const override; QVector getColorantsxyY() const override; QVector getWhitePointXYZ() const override; QVector getWhitePointxyY() const override; QVector getEstimatedTRC() const override; void linearizeFloatValue(QVector & Value) const override; void delinearizeFloatValue(QVector & Value) const override; void linearizeFloatValueFast(QVector & Value) const override; void delinearizeFloatValueFast(QVector & Value) const override; QByteArray uniqueId() const override; bool operator==(const KoColorProfile &) const override; QString type() const override { return "icc"; } /** * Returns the set of min/maxes for each channel in this profile. * These (sometimes approximate) min and maxes are suitable * for UI building. * Furthermore, then only apply to the floating point uses of this profile, * and not the integer variants. */ const QVector &getFloatUIMinMax(void) const; protected: void setRawData(const QByteArray &rawData); public: LcmsColorProfileContainer *asLcms() const; protected: bool init(); void calculateFloatUIMinMax(void); private: struct Private; QScopedPointer d; }; #endif diff --git a/plugins/color/lcms2engine/colorprofiles/LcmsColorProfileContainer.cpp b/plugins/color/lcms2engine/colorprofiles/LcmsColorProfileContainer.cpp index 025212cf2c..8172fa50f7 100644 --- a/plugins/color/lcms2engine/colorprofiles/LcmsColorProfileContainer.cpp +++ b/plugins/color/lcms2engine/colorprofiles/LcmsColorProfileContainer.cpp @@ -1,560 +1,569 @@ /* * This file is part of the KDE project * Copyright (c) 2000 Matthias Elter * 2001 John Califf * 2004 Boudewijn Rempt * Copyright (c) 2007 Thomas Zander * Copyright (c) 2007 Adrian Page * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "LcmsColorProfileContainer.h" #include #include #include #include #include #include "kis_debug.h" class LcmsColorProfileContainer::Private { public: cmsHPROFILE profile; cmsColorSpaceSignature colorSpaceSignature; cmsProfileClassSignature deviceClass; QString productDescription; QString manufacturer; QString copyright; QString name; float version; IccColorProfile::Data *data {0}; bool valid {false}; bool suitableForOutput {false}; bool hasColorants; bool hasTRC; + bool isLinear {false}; bool adaptedFromD50; cmsCIEXYZ mediaWhitePoint; cmsCIExyY whitePoint; cmsCIEXYZTRIPLE colorants; cmsToneCurve *redTRC {0}; cmsToneCurve *greenTRC {0}; cmsToneCurve *blueTRC {0}; cmsToneCurve *grayTRC {0}; cmsToneCurve *redTRCReverse {0}; cmsToneCurve *greenTRCReverse {0}; cmsToneCurve *blueTRCReverse {0}; cmsToneCurve *grayTRCReverse {0}; cmsUInt32Number defaultIntent; bool isPerceptualCLUT; bool isRelativeCLUT; bool isAbsoluteCLUT; bool isSaturationCLUT; bool isMatrixShaper; QByteArray uniqueId; }; LcmsColorProfileContainer::LcmsColorProfileContainer() : d(new Private()) { d->profile = 0; } LcmsColorProfileContainer::LcmsColorProfileContainer(IccColorProfile::Data *data) : d(new Private()) { d->data = data; d->profile = 0; init(); } QByteArray LcmsColorProfileContainer::lcmsProfileToByteArray(const cmsHPROFILE profile) { cmsUInt32Number bytesNeeded = 0; // Make a raw data image ready for saving cmsSaveProfileToMem(profile, 0, &bytesNeeded); // calc size QByteArray rawData; rawData.resize(bytesNeeded); if (rawData.size() >= (int)bytesNeeded) { cmsSaveProfileToMem(profile, rawData.data(), &bytesNeeded); // fill buffer } else { qWarning() << "Couldn't resize the profile buffer, system is probably running out of memory."; rawData.resize(0); } return rawData; } IccColorProfile *LcmsColorProfileContainer::createFromLcmsProfile(const cmsHPROFILE profile) { IccColorProfile *iccprofile = new IccColorProfile(lcmsProfileToByteArray(profile)); cmsCloseProfile(profile); return iccprofile; } LcmsColorProfileContainer::~LcmsColorProfileContainer() { cmsCloseProfile(d->profile); delete d; } #define _BUFFER_SIZE_ 1000 bool LcmsColorProfileContainer::init() { if (d->profile) { cmsCloseProfile(d->profile); } d->profile = cmsOpenProfileFromMem((void *)d->data->rawData().constData(), d->data->rawData().size()); #ifndef NDEBUG if (d->data->rawData().size() == 4096) { qWarning() << "Profile has a size of 4096, which is suspicious and indicates a possible misuse of QIODevice::read(int), check your code."; } #endif if (d->profile) { wchar_t buffer[_BUFFER_SIZE_]; d->colorSpaceSignature = cmsGetColorSpace(d->profile); d->deviceClass = cmsGetDeviceClass(d->profile); cmsGetProfileInfo(d->profile, cmsInfoDescription, cmsNoLanguage, cmsNoCountry, buffer, _BUFFER_SIZE_); d->name = QString::fromWCharArray(buffer); //apparently this should give us a localised string??? Not sure about this. cmsGetProfileInfo(d->profile, cmsInfoModel, cmsNoLanguage, cmsNoCountry, buffer, _BUFFER_SIZE_); d->productDescription = QString::fromWCharArray(buffer); cmsGetProfileInfo(d->profile, cmsInfoManufacturer, cmsNoLanguage, cmsNoCountry, buffer, _BUFFER_SIZE_); d->manufacturer = QString::fromWCharArray(buffer); cmsGetProfileInfo(d->profile, cmsInfoCopyright, cmsNoLanguage, cmsNoCountry, buffer, _BUFFER_SIZE_); d->copyright = QString::fromWCharArray(buffer); cmsProfileClassSignature profile_class; profile_class = cmsGetDeviceClass(d->profile); d->valid = (profile_class != cmsSigNamedColorClass); //This is where obtain the whitepoint, and convert it to the actual white point of the profile in the case a Chromatic adaption tag is //present. This is necessary for profiles following the v4 spec. cmsCIEXYZ baseMediaWhitePoint;//dummy to hold copy of mediawhitepoint if this is modified by chromatic adaption. if (cmsIsTag(d->profile, cmsSigMediaWhitePointTag)) { d->mediaWhitePoint = *((cmsCIEXYZ *)cmsReadTag(d->profile, cmsSigMediaWhitePointTag)); baseMediaWhitePoint = d->mediaWhitePoint; cmsXYZ2xyY(&d->whitePoint, &d->mediaWhitePoint); if (cmsIsTag(d->profile, cmsSigChromaticAdaptationTag)) { //the chromatic adaption tag represent a matrix from the actual white point of the profile to D50. cmsCIEXYZ *CAM1 = (cmsCIEXYZ *)cmsReadTag(d->profile, cmsSigChromaticAdaptationTag); //We first put all our data into structures we can manipulate. double d3dummy [3] = {d->mediaWhitePoint.X, d->mediaWhitePoint.Y, d->mediaWhitePoint.Z}; QGenericMatrix<1, 3, double> whitePointMatrix(d3dummy); QTransform invertDummy(CAM1[0].X, CAM1[0].Y, CAM1[0].Z, CAM1[1].X, CAM1[1].Y, CAM1[1].Z, CAM1[2].X, CAM1[2].Y, CAM1[2].Z); //we then abuse QTransform's invert function because it probably does matrix invertion 20 times better than I can program. //if the matrix is uninvertable, invertedDummy will be an identity matrix, which for us means that it won't give any noticeble //effect when we start multiplying. QTransform invertedDummy = invertDummy.inverted(); //we then put the QTransform into a generic 3x3 matrix. double d9dummy [9] = {invertedDummy.m11(), invertedDummy.m12(), invertedDummy.m13(), invertedDummy.m21(), invertedDummy.m22(), invertedDummy.m23(), invertedDummy.m31(), invertedDummy.m32(), invertedDummy.m33() }; QGenericMatrix<3, 3, double> chromaticAdaptionMatrix(d9dummy); //multiplying our inverted adaption matrix with the whitepoint gives us the right whitepoint. QGenericMatrix<1, 3, double> result = chromaticAdaptionMatrix * whitePointMatrix; //and then we pour the matrix into the whitepoint variable. Generic matrix does row/column for indices even though it //uses column/row for initialising. d->mediaWhitePoint.X = result(0, 0); d->mediaWhitePoint.Y = result(1, 0); d->mediaWhitePoint.Z = result(2, 0); cmsXYZ2xyY(&d->whitePoint, &d->mediaWhitePoint); } } //This is for RGB profiles, but it only works for matrix profiles. Need to design it to work with non-matrix profiles. if (cmsIsTag(d->profile, cmsSigRedColorantTag)) { cmsCIEXYZTRIPLE tempColorants; tempColorants.Red = *((cmsCIEXYZ *)cmsReadTag(d->profile, cmsSigRedColorantTag)); tempColorants.Green = *((cmsCIEXYZ *)cmsReadTag(d->profile, cmsSigGreenColorantTag)); tempColorants.Blue = *((cmsCIEXYZ *)cmsReadTag(d->profile, cmsSigBlueColorantTag)); //convert to d65, this is useless. cmsAdaptToIlluminant(&d->colorants.Red, &baseMediaWhitePoint, &d->mediaWhitePoint, &tempColorants.Red); cmsAdaptToIlluminant(&d->colorants.Green, &baseMediaWhitePoint, &d->mediaWhitePoint, &tempColorants.Green); cmsAdaptToIlluminant(&d->colorants.Blue, &baseMediaWhitePoint, &d->mediaWhitePoint, &tempColorants.Blue); //d->colorants = tempColorants; d->hasColorants = true; } else { //qDebug()<name<<": has no colorants"; d->hasColorants = false; } //retrieve TRC. if (cmsIsTag(d->profile, cmsSigRedTRCTag) && cmsIsTag(d->profile, cmsSigBlueTRCTag) && cmsIsTag(d->profile, cmsSigGreenTRCTag)) { d->redTRC = ((cmsToneCurve *)cmsReadTag (d->profile, cmsSigRedTRCTag)); d->greenTRC = ((cmsToneCurve *)cmsReadTag (d->profile, cmsSigGreenTRCTag)); d->blueTRC = ((cmsToneCurve *)cmsReadTag (d->profile, cmsSigBlueTRCTag)); if (d->redTRC) d->redTRCReverse = cmsReverseToneCurve(d->redTRC); if (d->greenTRC) d->greenTRCReverse = cmsReverseToneCurve(d->greenTRC); if (d->blueTRC) d->blueTRCReverse = cmsReverseToneCurve(d->blueTRC); d->hasTRC = (d->redTRC && d->greenTRC && d->blueTRC && d->redTRCReverse && d->greenTRCReverse && d->blueTRCReverse); + if (d->hasTRC) d->isLinear = cmsIsToneCurveLinear(d->redTRC) + && cmsIsToneCurveLinear(d->greenTRC) + && cmsIsToneCurveLinear(d->blueTRC); } else if (cmsIsTag(d->profile, cmsSigGrayTRCTag)) { d->grayTRC = ((cmsToneCurve *)cmsReadTag (d->profile, cmsSigGrayTRCTag)); if (d->grayTRC) d->grayTRCReverse = cmsReverseToneCurve(d->grayTRC); d->hasTRC = (d->grayTRC && d->grayTRCReverse); + if (d->hasTRC) d->isLinear = cmsIsToneCurveLinear(d->grayTRC); } else { d->hasTRC = false; } // Check if the profile can convert (something->this) d->suitableForOutput = cmsIsMatrixShaper(d->profile) || (cmsIsCLUT(d->profile, INTENT_PERCEPTUAL, LCMS_USED_AS_INPUT) && cmsIsCLUT(d->profile, INTENT_PERCEPTUAL, LCMS_USED_AS_OUTPUT)); d->version = cmsGetProfileVersion(d->profile); d->defaultIntent = cmsGetHeaderRenderingIntent(d->profile); d->isMatrixShaper = cmsIsMatrixShaper(d->profile); d->isPerceptualCLUT = cmsIsCLUT(d->profile, INTENT_PERCEPTUAL, LCMS_USED_AS_INPUT); d->isSaturationCLUT = cmsIsCLUT(d->profile, INTENT_SATURATION, LCMS_USED_AS_INPUT); d->isAbsoluteCLUT = cmsIsCLUT(d->profile, INTENT_SATURATION, LCMS_USED_AS_INPUT); d->isRelativeCLUT = cmsIsCLUT(d->profile, INTENT_RELATIVE_COLORIMETRIC, LCMS_USED_AS_INPUT); return true; } return false; } cmsHPROFILE LcmsColorProfileContainer::lcmsProfile() const { return d->profile; } cmsColorSpaceSignature LcmsColorProfileContainer::colorSpaceSignature() const { return d->colorSpaceSignature; } cmsProfileClassSignature LcmsColorProfileContainer::deviceClass() const { return d->deviceClass; } QString LcmsColorProfileContainer::manufacturer() const { return d->manufacturer; } QString LcmsColorProfileContainer::copyright() const { return d->copyright; } bool LcmsColorProfileContainer::valid() const { return d->valid; } float LcmsColorProfileContainer::version() const { return d->version; } bool LcmsColorProfileContainer::isSuitableForOutput() const { return d->suitableForOutput; } bool LcmsColorProfileContainer::isSuitableForPrinting() const { return deviceClass() == cmsSigOutputClass; } bool LcmsColorProfileContainer::isSuitableForDisplay() const { return deviceClass() == cmsSigDisplayClass; } bool LcmsColorProfileContainer::supportsPerceptual() const { return d->isPerceptualCLUT; } bool LcmsColorProfileContainer::supportsSaturation() const { return d->isSaturationCLUT; } bool LcmsColorProfileContainer::supportsAbsolute() const { return d->isAbsoluteCLUT;//LCMS2 doesn't convert matrix shapers via absolute intent, because of V4 workflow. } bool LcmsColorProfileContainer::supportsRelative() const { if (d->isRelativeCLUT || d->isMatrixShaper){ return true; } return false; } bool LcmsColorProfileContainer::hasColorants() const { return d->hasColorants; } bool LcmsColorProfileContainer::hasTRC() const { return d->hasTRC; } +bool LcmsColorProfileContainer::isLinear() const +{ + return d->isLinear; +} QVector LcmsColorProfileContainer::getColorantsXYZ() const { QVector colorants(9); colorants[0] = d->colorants.Red.X; colorants[1] = d->colorants.Red.Y; colorants[2] = d->colorants.Red.Z; colorants[3] = d->colorants.Green.X; colorants[4] = d->colorants.Green.Y; colorants[5] = d->colorants.Green.Z; colorants[6] = d->colorants.Blue.X; colorants[7] = d->colorants.Blue.Y; colorants[8] = d->colorants.Blue.Z; return colorants; } QVector LcmsColorProfileContainer::getColorantsxyY() const { cmsCIEXYZ temp1; cmsCIExyY temp2; QVector colorants(9); temp1.X = d->colorants.Red.X; temp1.Y = d->colorants.Red.Y; temp1.Z = d->colorants.Red.Z; cmsXYZ2xyY(&temp2, &temp1); colorants[0] = temp2.x; colorants[1] = temp2.y; colorants[2] = temp2.Y; temp1.X = d->colorants.Green.X; temp1.Y = d->colorants.Green.Y; temp1.Z = d->colorants.Green.Z; cmsXYZ2xyY(&temp2, &temp1); colorants[3] = temp2.x; colorants[4] = temp2.y; colorants[5] = temp2.Y; temp1.X = d->colorants.Blue.X; temp1.Y = d->colorants.Blue.Y; temp1.Z = d->colorants.Blue.Z; cmsXYZ2xyY(&temp2, &temp1); colorants[6] = temp2.x; colorants[7] = temp2.y; colorants[8] = temp2.Y; return colorants; } QVector LcmsColorProfileContainer::getWhitePointXYZ() const { QVector tempWhitePoint(3); tempWhitePoint[0] = d->mediaWhitePoint.X; tempWhitePoint[1] = d->mediaWhitePoint.Y; tempWhitePoint[2] = d->mediaWhitePoint.Z; return tempWhitePoint; } QVector LcmsColorProfileContainer::getWhitePointxyY() const { QVector tempWhitePoint(3); tempWhitePoint[0] = d->whitePoint.x; tempWhitePoint[1] = d->whitePoint.y; tempWhitePoint[2] = d->whitePoint.Y; return tempWhitePoint; } QVector LcmsColorProfileContainer::getEstimatedTRC() const { QVector TRCtriplet(3); if (d->hasColorants) { if (cmsIsToneCurveLinear(d->redTRC)) { TRCtriplet[0] = 1.0; } else { TRCtriplet[0] = cmsEstimateGamma(d->redTRC, 0.01); } if (cmsIsToneCurveLinear(d->greenTRC)) { TRCtriplet[1] = 1.0; } else { TRCtriplet[1] = cmsEstimateGamma(d->greenTRC, 0.01); } if (cmsIsToneCurveLinear(d->blueTRC)) { TRCtriplet[2] = 1.0; } else { TRCtriplet[2] = cmsEstimateGamma(d->blueTRC, 0.01); } } else { if (cmsIsTag(d->profile, cmsSigGrayTRCTag)) { if (cmsIsToneCurveLinear(d->grayTRC)) { TRCtriplet.fill(1.0); } else { TRCtriplet.fill(cmsEstimateGamma(d->grayTRC, 0.01)); } } else { TRCtriplet.fill(1.0); } } return TRCtriplet; } void LcmsColorProfileContainer::LinearizeFloatValue(QVector & Value) const { if (d->hasColorants) { if (!cmsIsToneCurveLinear(d->redTRC)) { Value[0] = cmsEvalToneCurveFloat(d->redTRC, Value[0]); } if (!cmsIsToneCurveLinear(d->greenTRC)) { Value[1] = cmsEvalToneCurveFloat(d->greenTRC, Value[1]); } if (!cmsIsToneCurveLinear(d->blueTRC)) { Value[2] = cmsEvalToneCurveFloat(d->blueTRC, Value[2]); } } else { if (cmsIsTag(d->profile, cmsSigGrayTRCTag)) { Value[0] = cmsEvalToneCurveFloat(d->grayTRC, Value[0]); } } } void LcmsColorProfileContainer::DelinearizeFloatValue(QVector & Value) const { if (d->hasColorants) { if (!cmsIsToneCurveLinear(d->redTRC)) { Value[0] = cmsEvalToneCurveFloat(d->redTRCReverse, Value[0]); } if (!cmsIsToneCurveLinear(d->greenTRC)) { Value[1] = cmsEvalToneCurveFloat(d->greenTRCReverse, Value[1]); } if (!cmsIsToneCurveLinear(d->blueTRC)) { Value[2] = cmsEvalToneCurveFloat(d->blueTRCReverse, Value[2]); } } else { if (cmsIsTag(d->profile, cmsSigGrayTRCTag)) { Value[0] = cmsEvalToneCurveFloat(d->grayTRCReverse, Value[0]); } } } void LcmsColorProfileContainer::LinearizeFloatValueFast(QVector & Value) const { const qreal scale = 65535.0; const qreal invScale = 1.0 / scale; if (d->hasColorants) { //we can only reliably delinearise in the 0-1.0 range, outside of that leave the value alone. QVector TRCtriplet(3); TRCtriplet[0] = Value[0] * scale; TRCtriplet[1] = Value[1] * scale; TRCtriplet[2] = Value[2] * scale; if (!cmsIsToneCurveLinear(d->redTRC) && Value[0]<1.0) { TRCtriplet[0] = cmsEvalToneCurve16(d->redTRC, TRCtriplet[0]); Value[0] = TRCtriplet[0] * invScale; } if (!cmsIsToneCurveLinear(d->greenTRC) && Value[1]<1.0) { TRCtriplet[1] = cmsEvalToneCurve16(d->greenTRC, TRCtriplet[1]); Value[1] = TRCtriplet[1] * invScale; } if (!cmsIsToneCurveLinear(d->blueTRC) && Value[2]<1.0) { TRCtriplet[2] = cmsEvalToneCurve16(d->blueTRC, TRCtriplet[2]); Value[2] = TRCtriplet[2] * invScale; } } else { if (cmsIsTag(d->profile, cmsSigGrayTRCTag) && Value[0]<1.0) { quint16 newValue = cmsEvalToneCurve16(d->grayTRC, Value[0] * scale); Value[0] = newValue * invScale; } } } void LcmsColorProfileContainer::DelinearizeFloatValueFast(QVector & Value) const { const qreal scale = 65535.0; const qreal invScale = 1.0 / scale; if (d->hasColorants) { //we can only reliably delinearise in the 0-1.0 range, outside of that leave the value alone. QVector TRCtriplet(3); TRCtriplet[0] = Value[0] * scale; TRCtriplet[1] = Value[1] * scale; TRCtriplet[2] = Value[2] * scale; if (!cmsIsToneCurveLinear(d->redTRC) && Value[0]<1.0) { TRCtriplet[0] = cmsEvalToneCurve16(d->redTRCReverse, TRCtriplet[0]); Value[0] = TRCtriplet[0] * invScale; } if (!cmsIsToneCurveLinear(d->greenTRC) && Value[1]<1.0) { TRCtriplet[1] = cmsEvalToneCurve16(d->greenTRCReverse, TRCtriplet[1]); Value[1] = TRCtriplet[1] * invScale; } if (!cmsIsToneCurveLinear(d->blueTRC) && Value[2]<1.0) { TRCtriplet[2] = cmsEvalToneCurve16(d->blueTRCReverse, TRCtriplet[2]); Value[2] = TRCtriplet[2] * invScale; } } else { if (cmsIsTag(d->profile, cmsSigGrayTRCTag) && Value[0]<1.0) { quint16 newValue = cmsEvalToneCurve16(d->grayTRCReverse, Value[0] * scale); Value[0] = newValue * invScale; } } } QString LcmsColorProfileContainer::name() const { return d->name; } QString LcmsColorProfileContainer::info() const { return d->productDescription; } QByteArray LcmsColorProfileContainer::getProfileUniqueId() const { if (d->uniqueId.isEmpty() && d->profile) { QByteArray id(sizeof(cmsProfileID), 0); cmsGetHeaderProfileID(d->profile, (quint8*)id.data()); bool isNull = std::all_of(id.constBegin(), id.constEnd(), [](char c) {return c == 0;}); if (isNull) { if (cmsMD5computeID(d->profile)) { cmsGetHeaderProfileID(d->profile, (quint8*)id.data()); isNull = false; } } if (!isNull) { d->uniqueId = id; } } return d->uniqueId; } diff --git a/plugins/color/lcms2engine/colorprofiles/LcmsColorProfileContainer.h b/plugins/color/lcms2engine/colorprofiles/LcmsColorProfileContainer.h index f1dca0c9c9..ee1d4bcc7f 100644 --- a/plugins/color/lcms2engine/colorprofiles/LcmsColorProfileContainer.h +++ b/plugins/color/lcms2engine/colorprofiles/LcmsColorProfileContainer.h @@ -1,119 +1,120 @@ /* * This file is part of the KDE project * Copyright (c) 2000 Matthias Elter * 2004 Boudewijn Rempt * Copyright (c) 2007 Thomas Zander * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef _KO_LCMS_COLORPROFILE_H #define _KO_LCMS_COLORPROFILE_H #include "IccColorProfile.h" #include #include #include /** * This class contains an LCMS color profile. Don't use it outside LcmsColorSpace. */ class LcmsColorProfileContainer : public IccColorProfile::Container { friend class IccColorProfile; protected: LcmsColorProfileContainer(IccColorProfile::Data *); private: /** * Create a byte array from a lcms profile. */ static QByteArray lcmsProfileToByteArray(const cmsHPROFILE profile); public: /** * @param profile lcms memory structure with the profile, it is freed after the call * to this function * @return an ICC profile created from an LCMS profile */ static IccColorProfile *createFromLcmsProfile(const cmsHPROFILE profile); public: ~LcmsColorProfileContainer() override; /** * @return the ICC color space signature */ cmsColorSpaceSignature colorSpaceSignature() const; /** * @return the class of the color space signature */ cmsProfileClassSignature deviceClass() const; /** * @return the name of the manufacturer */ QString manufacturer() const override; /** * @return the embedded copyright */ QString copyright() const override; /** * @return the structure to use with LCMS functions */ cmsHPROFILE lcmsProfile() const; bool valid() const override; virtual float version() const; bool isSuitableForOutput() const override; bool isSuitableForPrinting() const override; bool isSuitableForDisplay() const override; virtual bool supportsPerceptual() const; virtual bool supportsSaturation() const; virtual bool supportsAbsolute() const; virtual bool supportsRelative() const; bool hasColorants() const override; virtual bool hasTRC() const; + bool isLinear() const; QVector getColorantsXYZ() const override; QVector getColorantsxyY() const override; QVector getWhitePointXYZ() const override; QVector getWhitePointxyY() const override; QVector getEstimatedTRC() const override; virtual void LinearizeFloatValue(QVector & Value) const; virtual void DelinearizeFloatValue(QVector & Value) const; virtual void LinearizeFloatValueFast(QVector & Value) const; virtual void DelinearizeFloatValueFast(QVector & Value) const; QString name() const override; QString info() const override; QByteArray getProfileUniqueId() const override; protected: LcmsColorProfileContainer(); private: bool init(); class Private; Private *const d; }; #endif // KOCOLORPROFILE_H