diff --git a/src/color-profile.cpp b/src/color-profile.cpp
index b094b650d08314ee0dccb0acd6ce42987cafc7fd..ecc0bcd4e37520a7eb2f6f9005f3947f540b322f 100644 (file)
--- a/src/color-profile.cpp
+++ b/src/color-profile.cpp
-#include "xml/repr.h"
-#include "color-profile.h"
-#include "color-profile-fns.h"
-#include "attributes.h"
-#include "inkscape.h"
-#include "document.h"
-#include "prefs-utils.h"
-
-#include "dom/uri.h"
-
//#define DEBUG_LCMS
#include <glib/gstdio.h>
#include <gtk/gtkmessagedialog.h>
#endif // DEBUG_LCMS
+#include <cstring>
+#include <string>
+#include "xml/repr.h"
+#include "color-profile.h"
+#include "color-profile-fns.h"
+#include "attributes.h"
+#include "inkscape.h"
+#include "document.h"
+#include "prefs-utils.h"
+
+#include "dom/uri.h"
+#include "dom/util/digest.h"
+
using Inkscape::ColorProfile;
using Inkscape::ColorProfileClass;
namespace Inkscape
{
-static void colorprofile_class_init( ColorProfileClass *klass );
-static void colorprofile_init( ColorProfile *cprof );
-
-static void colorprofile_release( SPObject *object );
-static void colorprofile_build( SPObject *object, SPDocument *document, Inkscape::XML::Node *repr );
-static void colorprofile_set( SPObject *object, unsigned key, gchar const *value );
-static Inkscape::XML::Node *colorprofile_write( SPObject *object, Inkscape::XML::Node *repr, guint flags );
-
#if ENABLE_LCMS
static cmsHPROFILE colorprofile_get_system_profile_handle();
static cmsHPROFILE colorprofile_get_proof_profile_handle();
}
#endif // DEBUG_LCMS
-static SPObject *cprof_parent_class;
+static SPObjectClass *cprof_parent_class;
+
+#if ENABLE_LCMS
+
+cmsHPROFILE ColorProfile::_sRGBProf = 0;
+
+cmsHPROFILE ColorProfile::getSRGBProfile() {
+ if ( !_sRGBProf ) {
+ _sRGBProf = cmsCreate_sRGBProfile();
+ }
+ return _sRGBProf;
+}
+
+#endif // ENABLE_LCMS
/**
* Register ColorProfile class and return its type.
*/
GType Inkscape::colorprofile_get_type()
+{
+ return ColorProfile::getType();
+}
+
+GType ColorProfile::getType()
{
static GType type = 0;
if (!type) {
GTypeInfo info = {
sizeof(ColorProfileClass),
NULL, NULL,
- (GClassInitFunc) colorprofile_class_init,
+ (GClassInitFunc) ColorProfile::classInit,
NULL, NULL,
sizeof(ColorProfile),
16,
- (GInstanceInitFunc) colorprofile_init,
+ (GInstanceInitFunc) ColorProfile::init,
NULL, /* value_table */
};
type = g_type_register_static( SP_TYPE_OBJECT, "ColorProfile", &info, static_cast<GTypeFlags>(0) );
/**
* ColorProfile vtable initialization.
*/
-static void Inkscape::colorprofile_class_init( ColorProfileClass *klass )
+void ColorProfile::classInit( ColorProfileClass *klass )
{
SPObjectClass *sp_object_class = reinterpret_cast<SPObjectClass *>(klass);
- cprof_parent_class = static_cast<SPObject*>(g_type_class_ref(SP_TYPE_OBJECT));
+ cprof_parent_class = static_cast<SPObjectClass*>(g_type_class_ref(SP_TYPE_OBJECT));
- sp_object_class->release = colorprofile_release;
- sp_object_class->build = colorprofile_build;
- sp_object_class->set = colorprofile_set;
- sp_object_class->write = colorprofile_write;
+ sp_object_class->release = ColorProfile::release;
+ sp_object_class->build = ColorProfile::build;
+ sp_object_class->set = ColorProfile::set;
+ sp_object_class->write = ColorProfile::write;
}
/**
* Callback for ColorProfile object initialization.
*/
-static void Inkscape::colorprofile_init( ColorProfile *cprof )
+void ColorProfile::init( ColorProfile *cprof )
{
cprof->href = 0;
cprof->local = 0;
cprof->rendering_intent = Inkscape::RENDERING_INTENT_UNKNOWN;
#if ENABLE_LCMS
cprof->profHandle = 0;
+ cprof->_profileClass = icSigInputClass;
+ cprof->_profileSpace = icSigRgbData;
+ cprof->_transf = 0;
+ cprof->_revTransf = 0;
#endif // ENABLE_LCMS
}
/**
* Callback: free object
*/
-static void Inkscape::colorprofile_release( SPObject *object )
+void ColorProfile::release( SPObject *object )
{
// Unregister ourselves
SPDocument* document = SP_OBJECT_DOCUMENT(object);
}
#if ENABLE_LCMS
- if ( cprof->profHandle ) {
- cmsCloseProfile( cprof->profHandle );
- cprof->profHandle = 0;
- }
+ cprof->_clearProfile();
#endif // ENABLE_LCMS
}
+#if ENABLE_LCMS
+void ColorProfile::_clearProfile()
+{
+ _profileSpace = icSigRgbData;
+
+ if ( _transf ) {
+ cmsDeleteTransform( _transf );
+ _transf = 0;
+ }
+ if ( _revTransf ) {
+ cmsDeleteTransform( _revTransf );
+ _revTransf = 0;
+ }
+ if ( profHandle ) {
+ cmsCloseProfile( profHandle );
+ profHandle = 0;
+ }
+}
+#endif // ENABLE_LCMS
+
/**
* Callback: set attributes from associated repr.
*/
-static void Inkscape::colorprofile_build( SPObject *object, SPDocument *document, Inkscape::XML::Node *repr )
+void ColorProfile::build( SPObject *object, SPDocument *document, Inkscape::XML::Node *repr )
{
ColorProfile *cprof = COLORPROFILE(object);
g_assert(cprof->href == 0);
@@ -173,8 +207,8 @@ static void Inkscape::colorprofile_build( SPObject *object, SPDocument *document
g_assert(cprof->name == 0);
g_assert(cprof->intentStr == 0);
- if (((SPObjectClass *) cprof_parent_class)->build) {
- (* ((SPObjectClass *) cprof_parent_class)->build)(object, document, repr);
+ if (cprof_parent_class->build) {
+ (* cprof_parent_class->build)(object, document, repr);
}
sp_object_read_attr( object, "xlink:href" );
sp_object_read_attr( object, "local" );
@@ -190,7 +224,7 @@ static void Inkscape::colorprofile_build( SPObject *object, SPDocument *document
/**
* Callback: set attribute.
*/
-static void Inkscape::colorprofile_set( SPObject *object, unsigned key, gchar const *value )
+void ColorProfile::set( SPObject *object, unsigned key, gchar const *value )
{
ColorProfile *cprof = COLORPROFILE(object);
@@ -231,7 +265,12 @@ static void Inkscape::colorprofile_set( SPObject *object, unsigned key, gchar co
// the w3c specs. All absolute and relative issues are considered
org::w3c::dom::URI cprofUri = docUri.resolve(hrefUri);
gchar* fullname = (gchar *)cprofUri.getNativePath().c_str();
+ cprof->_clearProfile();
cprof->profHandle = cmsOpenProfileFromFile( fullname, "r" );
+ if ( cprof->profHandle ) {
+ cprof->_profileSpace = cmsGetColorSpace( cprof->profHandle );
+ cprof->_profileClass = cmsGetDeviceClass( cprof->profHandle );
+ }
#ifdef DEBUG_LCMS
DEBUG_MESSAGE( lcmsOne, "cmsOpenProfileFromFile( '%s'...) = %p", fullname, (void*)cprof->profHandle );
#endif // DEBUG_LCMS
@@ -292,8 +331,8 @@ static void Inkscape::colorprofile_set( SPObject *object, unsigned key, gchar co
break;
default:
- if (((SPObjectClass *) cprof_parent_class)->set) {
- (* ((SPObjectClass *) cprof_parent_class)->set)(object, key, value);
+ if (cprof_parent_class->set) {
+ (* cprof_parent_class->set)(object, key, value);
}
break;
}
@@ -303,7 +342,7 @@ static void Inkscape::colorprofile_set( SPObject *object, unsigned key, gchar co
/**
* Callback: write attributes to associated repr.
*/
-static Inkscape::XML::Node* Inkscape::colorprofile_write( SPObject *object, Inkscape::XML::Node *repr, guint flags )
+Inkscape::XML::Node* ColorProfile::write( SPObject *object, Inkscape::XML::Node *repr, guint flags )
{
ColorProfile *cprof = COLORPROFILE(object);
@@ -328,8 +367,8 @@ static Inkscape::XML::Node* Inkscape::colorprofile_write( SPObject *object, Inks
repr->setAttribute( "rendering-intent", cprof->intentStr );
}
- if (((SPObjectClass *) cprof_parent_class)->write) {
- (* ((SPObjectClass *) cprof_parent_class)->write)(object, repr, flags);
+ if (cprof_parent_class->write) {
+ (* cprof_parent_class->write)(object, repr, flags);
}
return repr;
@@ -338,6 +377,59 @@ static Inkscape::XML::Node* Inkscape::colorprofile_write( SPObject *object, Inks
#if ENABLE_LCMS
+struct MapMap {
+ icColorSpaceSignature space;
+ DWORD inForm;
+};
+
+DWORD ColorProfile::_getInputFormat( icColorSpaceSignature space )
+{
+ MapMap possible[] = {
+ {icSigXYZData, TYPE_XYZ_16},
+ {icSigLabData, TYPE_Lab_16},
+ //icSigLuvData
+ {icSigYCbCrData, TYPE_YCbCr_16},
+ {icSigYxyData, TYPE_Yxy_16},
+ {icSigRgbData, TYPE_RGB_16},
+ {icSigGrayData, TYPE_GRAY_16},
+ {icSigHsvData, TYPE_HSV_16},
+ {icSigHlsData, TYPE_HLS_16},
+ {icSigCmykData, TYPE_CMYK_16},
+ {icSigCmyData, TYPE_CMY_16},
+ };
+
+ int index = 0;
+ for ( guint i = 0; i < G_N_ELEMENTS(possible); i++ ) {
+ if ( possible[i].space == space ) {
+ index = i;
+ break;
+ }
+ }
+
+ return possible[index].inForm;
+}
+
+static int getLcmsIntent( guint svgIntent )
+{
+ int intent = INTENT_PERCEPTUAL;
+ switch ( svgIntent ) {
+ case Inkscape::RENDERING_INTENT_RELATIVE_COLORIMETRIC:
+ intent = INTENT_RELATIVE_COLORIMETRIC;
+ break;
+ case Inkscape::RENDERING_INTENT_SATURATION:
+ intent = INTENT_SATURATION;
+ break;
+ case Inkscape::RENDERING_INTENT_ABSOLUTE_COLORIMETRIC:
+ intent = INTENT_ABSOLUTE_COLORIMETRIC;
+ break;
+ case Inkscape::RENDERING_INTENT_PERCEPTUAL:
+ case Inkscape::RENDERING_INTENT_UNKNOWN:
+ case Inkscape::RENDERING_INTENT_AUTO:
+ default:
+ intent = INTENT_PERCEPTUAL;
+ }
+ return intent;
+}
static SPObject* bruteFind( SPDocument* document, gchar const* name )
{
@@ -379,6 +471,24 @@ cmsHPROFILE Inkscape::colorprofile_get_handle( SPDocument* document, guint* inte
return prof;
}
+cmsHTRANSFORM ColorProfile::getTransfToSRGB8()
+{
+ if ( !_transf ) {
+ int intent = getLcmsIntent(rendering_intent);
+ _transf = cmsCreateTransform( profHandle, _getInputFormat(_profileSpace), getSRGBProfile(), TYPE_RGBA_8, intent, 0 );
+ }
+ return _transf;
+}
+
+cmsHTRANSFORM ColorProfile::getTransfFromSRGB8()
+{
+ if ( !_revTransf ) {
+ int intent = getLcmsIntent(rendering_intent);
+ _revTransf = cmsCreateTransform( getSRGBProfile(), TYPE_RGBA_8, profHandle, _getInputFormat(_profileSpace), intent, 0 );
+ }
+ return _revTransf;
+}
+
#include <io/sys.h>
static int lastIntent = INTENT_PERCEPTUAL;
static int lastProofIntent = INTENT_PERCEPTUAL;
static cmsHTRANSFORM transf = 0;
-static cmsHPROFILE srcprof = 0;
cmsHPROFILE Inkscape::colorprofile_get_system_profile_handle()
{
init = true;
}
- long long int which = prefs_get_int_attribute_limited( "options.displayprofile", "enable", 0, 0, 1 );
gchar const * uri = prefs_get_string_attribute("options.displayprofile", "uri");
- if ( which && uri && *uri ) {
+ if ( uri && *uri ) {
if ( lastURI != std::string(uri) ) {
lastURI.clear();
if ( theOne ) {
return theOne;
}
+static void free_transforms();
+
cmsHTRANSFORM Inkscape::colorprofile_get_display_transform()
{
+ long long int fromDisplay = prefs_get_int_attribute_limited( "options.displayprofile", "from_display", 0, 0, 1 );
+ if ( fromDisplay ) {
+ if ( transf ) {
+ cmsDeleteTransform(transf);
+ transf = 0;
+ }
+ return 0;
+ }
+
bool warn = prefs_get_int_attribute_limited( "options.softproof", "gamutwarn", 0, 0, 1 );
int intent = prefs_get_int_attribute_limited( "options.displayprofile", "intent", 0, 0, 3 );
int proofIntent = prefs_get_int_attribute_limited( "options.softproof", "intent", 0, 0, 3 );
|| (gamutColor != lastGamutColor)
) {
gamutWarn = warn;
- if ( transf ) {
- cmsDeleteTransform(transf);
- transf = 0;
- }
+ free_transforms();
lastIntent = intent;
lastProofIntent = proofIntent;
lastBPC = bpc;
lastGamutColor = gamutColor;
}
- // Fecth these now, as they might clear the transform as a side effect.
+ // Fetch these now, as they might clear the transform as a side effect.
cmsHPROFILE hprof = Inkscape::colorprofile_get_system_profile_handle();
cmsHPROFILE proofProf = hprof ? Inkscape::colorprofile_get_proof_profile_handle() : 0;
if ( !transf ) {
- if ( !srcprof ) {
- srcprof = cmsCreate_sRGBProfile();
- }
if ( hprof && proofProf ) {
DWORD dwFlags = cmsFLAGS_SOFTPROOFING;
if ( gamutWarn ) {
dwFlags |= cmsFLAGS_PRESERVEBLACK;
}
#endif // defined(cmsFLAGS_PRESERVEBLACK)
- transf = cmsCreateProofingTransform( srcprof, TYPE_RGB_8, hprof, TYPE_RGB_8, proofProf, intent, proofIntent, dwFlags );
+ transf = cmsCreateProofingTransform( ColorProfile::getSRGBProfile(), TYPE_RGB_8, hprof, TYPE_RGB_8, proofProf, intent, proofIntent, dwFlags );
} else if ( hprof ) {
- transf = cmsCreateTransform( srcprof, TYPE_RGB_8, hprof, TYPE_RGB_8, intent, 0 );
+ transf = cmsCreateTransform( ColorProfile::getSRGBProfile(), TYPE_RGB_8, hprof, TYPE_RGB_8, intent, 0 );
}
}
return transf;
}
+
+class MemProfile {
+public:
+ MemProfile();
+ ~MemProfile();
+
+ std::string id;
+ cmsHPROFILE hprof;
+ cmsHTRANSFORM transf;
+};
+
+MemProfile::MemProfile() :
+ id(),
+ hprof(0),
+ transf(0)
+{
+}
+
+MemProfile::~MemProfile()
+{
+}
+
+static std::vector< std::vector<MemProfile> > perMonitorProfiles;
+
+void free_transforms()
+{
+ if ( transf ) {
+ cmsDeleteTransform(transf);
+ transf = 0;
+ }
+
+ for ( std::vector< std::vector<MemProfile> >::iterator it = perMonitorProfiles.begin(); it != perMonitorProfiles.end(); ++it ) {
+ for ( std::vector<MemProfile>::iterator it2 = it->begin(); it2 != it->end(); ++it2 ) {
+ if ( it2->transf ) {
+ cmsDeleteTransform(it2->transf);
+ it2->transf = 0;
+ }
+ }
+ }
+}
+
+Glib::ustring Inkscape::colorprofile_get_display_id( int screen, int monitor )
+{
+ Glib::ustring id;
+
+ if ( screen >= 0 && screen < static_cast<int>(perMonitorProfiles.size()) ) {
+ std::vector<MemProfile>& row = perMonitorProfiles[screen];
+ if ( monitor >= 0 && monitor < static_cast<int>(row.size()) ) {
+ MemProfile& item = row[monitor];
+ id = item.id;
+ }
+ }
+
+ return id;
+}
+
+Glib::ustring Inkscape::colorprofile_set_display_per( gpointer buf, guint bufLen, int screen, int monitor )
+{
+ Glib::ustring id;
+
+ while ( static_cast<int>(perMonitorProfiles.size()) <= screen ) {
+ std::vector<MemProfile> tmp;
+ perMonitorProfiles.push_back(tmp);
+ }
+ std::vector<MemProfile>& row = perMonitorProfiles[screen];
+ while ( static_cast<int>(row.size()) <= monitor ) {
+ MemProfile tmp;
+ row.push_back(tmp);
+ }
+ MemProfile& item = row[monitor];
+
+ if ( item.hprof ) {
+ cmsCloseProfile( item.hprof );
+ item.hprof = 0;
+ }
+ id.clear();
+
+ if ( buf && bufLen ) {
+ Md5Digest digest;
+ if ( buf && bufLen ) {
+ digest.append(reinterpret_cast<unsigned char*>(buf), bufLen);
+ }
+ id = digest.finishHex();
+
+ // Note: if this is not a valid profile, item.hprof will be set to null.
+ item.hprof = cmsOpenProfileFromMem(buf, bufLen);
+ }
+ item.id = id;
+
+ return id;
+}
+
+cmsHTRANSFORM Inkscape::colorprofile_get_display_per( Glib::ustring const& id )
+{
+ cmsHTRANSFORM result = 0;
+ if ( id.empty() ) {
+ return 0;
+ }
+
+ bool found = false;
+ for ( std::vector< std::vector<MemProfile> >::iterator it = perMonitorProfiles.begin(); it != perMonitorProfiles.end() && !found; ++it ) {
+ for ( std::vector<MemProfile>::iterator it2 = it->begin(); it2 != it->end() && !found; ++it2 ) {
+ if ( id == it2->id ) {
+ MemProfile& item = *it2;
+
+ bool warn = prefs_get_int_attribute_limited( "options.softproof", "gamutwarn", 0, 0, 1 );
+ int intent = prefs_get_int_attribute_limited( "options.displayprofile", "intent", 0, 0, 3 );
+ int proofIntent = prefs_get_int_attribute_limited( "options.softproof", "intent", 0, 0, 3 );
+ bool bpc = prefs_get_int_attribute_limited( "options.softproof", "bpc", 0, 0, 1 );
+#if defined(cmsFLAGS_PRESERVEBLACK)
+ bool preserveBlack = prefs_get_int_attribute_limited( "options.softproof", "preserveblack", 0, 0, 1 );
+#endif //defined(cmsFLAGS_PRESERVEBLACK)
+ gchar const* colorStr = prefs_get_string_attribute("options.softproof", "gamutcolor");
+ Gdk::Color gamutColor( (colorStr && colorStr[0]) ? colorStr : "#808080");
+
+ if ( (warn != gamutWarn)
+ || (lastIntent != intent)
+ || (lastProofIntent != proofIntent)
+ || (bpc != lastBPC)
+#if defined(cmsFLAGS_PRESERVEBLACK)
+ || (preserveBlack != lastPreserveBlack)
+#endif // defined(cmsFLAGS_PRESERVEBLACK)
+ || (gamutColor != lastGamutColor)
+ ) {
+ gamutWarn = warn;
+ free_transforms();
+ lastIntent = intent;
+ lastProofIntent = proofIntent;
+ lastBPC = bpc;
+#if defined(cmsFLAGS_PRESERVEBLACK)
+ lastPreserveBlack = preserveBlack;
+#endif // defined(cmsFLAGS_PRESERVEBLACK)
+ lastGamutColor = gamutColor;
+ }
+
+ // Fetch these now, as they might clear the transform as a side effect.
+ cmsHPROFILE proofProf = item.hprof ? Inkscape::colorprofile_get_proof_profile_handle() : 0;
+
+ if ( !item.transf ) {
+ if ( item.hprof && proofProf ) {
+ DWORD dwFlags = cmsFLAGS_SOFTPROOFING;
+ if ( gamutWarn ) {
+ dwFlags |= cmsFLAGS_GAMUTCHECK;
+ cmsSetAlarmCodes(gamutColor.get_red() >> 8, gamutColor.get_green() >> 8, gamutColor.get_blue() >> 8);
+ }
+ if ( bpc ) {
+ dwFlags |= cmsFLAGS_BLACKPOINTCOMPENSATION;
+ }
+#if defined(cmsFLAGS_PRESERVEBLACK)
+ if ( preserveBlack ) {
+ dwFlags |= cmsFLAGS_PRESERVEBLACK;
+ }
+#endif // defined(cmsFLAGS_PRESERVEBLACK)
+ item.transf = cmsCreateProofingTransform( ColorProfile::getSRGBProfile(), TYPE_RGB_8, item.hprof, TYPE_RGB_8, proofProf, intent, proofIntent, dwFlags );
+ } else if ( item.hprof ) {
+ item.transf = cmsCreateTransform( ColorProfile::getSRGBProfile(), TYPE_RGB_8, item.hprof, TYPE_RGB_8, intent, 0 );
+ }
+ }
+
+ result = item.transf;
+ found = true;
+ }
+ }
+ }
+
+ return result;
+}
+
+
+
#endif // ENABLE_LCMS
/*