diff --git a/src/color-profile.cpp b/src/color-profile.cpp
index a73344d1775802e74148653ac2bfb23730017671..5868a958294f23234d2c1b9ecfedd066fd93a5f8 100644 (file)
--- a/src/color-profile.cpp
+++ b/src/color-profile.cpp
+//#define DEBUG_LCMS
+
+#include <glib/gstdio.h>
+#include <sys/fcntl.h>
+#include <gdkmm/color.h>
+
+#ifdef DEBUG_LCMS
+#include <gtk/gtkmessagedialog.h>
+#endif // DEBUG_LCMS
+
+#include <cstring>
+#include <string>
+// #ifdef WIN32
+// #include <windows.h>
+// #include <Icm.h>
+// #endif
#include "xml/repr.h"
#include "color-profile.h"
#include "color-profile-fns.h"
#include "attributes.h"
#include "inkscape.h"
#include "document.h"
+#include "preferences.h"
#include "dom/uri.h"
+#include "dom/util/digest.h"
-//#define DEBUG_LCMS
-
-#ifdef DEBUG_LCMS
-#include "prefs-utils.h"
-#include <gtk/gtkmessagedialog.h>
-#endif // DEBUG_LCMS
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 // ENABLE_LCMS
}
#ifdef DEBUG_LCMS
extern guint update_in_progress;
#define DEBUG_MESSAGE(key, ...) \
{\
- gint dump = prefs_get_int_attribute_limited("options.scislac", #key, 0, 0, 1);\
- gint dumpD = prefs_get_int_attribute_limited("options.scislac", #key"D", 0, 0, 1);\
- gint dumpD2 = prefs_get_int_attribute_limited("options.scislac", #key"D2", 0, 0, 1);\
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();\
+ bool dump = prefs->getBool(Glib::ustring("/options/scislac/") + #key);\
+ bool dumpD = prefs->getBool(Glib::ustring("/options/scislac/") + #key"D");\
+ bool dumpD2 = prefs->getBool(Glib::ustring("/options/scislac/") + #key"D2");\
dumpD &= ( (update_in_progress == 0) || dumpD2 );\
if ( dump )\
{\
}
#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 ( document ) {
+ sp_document_remove_resource (SP_OBJECT_DOCUMENT (object), "iccprofile", SP_OBJECT (object));
+ }
+
ColorProfile *cprof = COLORPROFILE(object);
if ( cprof->href ) {
g_free( cprof->href );
}
#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);
@@ -158,19 +213,24 @@ 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" );
sp_object_read_attr( object, "name" );
sp_object_read_attr( object, "rendering-intent" );
+
+ // Register
+ if ( document ) {
+ sp_document_add_resource( document, "iccprofile", object );
+ }
}
/**
* 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);
@@ -199,10 +259,10 @@ static void Inkscape::colorprofile_set( SPObject *object, unsigned key, gchar co
//# 1. Get complete URI of document
gchar const *docbase = SP_DOCUMENT_URI( doc );
if (!docbase)
- {
- g_warning("null docbase");
+ {
+ // Normal for files that have not yet been saved.
docbase = "";
- }
+ }
//g_message("docbase:%s\n", docbase);
org::w3c::dom::URI docUri(docbase);
//# 2. Get href of icc file. we don't care if it's rel or abs
@@ -210,12 +270,17 @@ static void Inkscape::colorprofile_set( SPObject *object, unsigned key, gchar co
//# 3. Resolve the href according the docBase. This follows
// 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();
+ gchar* fullname = g_strdup((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
-
+ g_free(fullname);
#endif // ENABLE_LCMS
}
}
@@ -272,8 +337,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;
}
@@ -283,12 +348,11 @@ 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::Document *xml_doc, Inkscape::XML::Node *repr, guint flags )
{
ColorProfile *cprof = COLORPROFILE(object);
if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
- Inkscape::XML::Document *xml_doc = sp_document_repr_doc(SP_OBJECT_DOCUMENT(object));
repr = xml_doc->createElement("svg:color-profile");
}
@@ -308,8 +372,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, xml_doc, repr, flags);
}
return repr;
@@ -318,41 +382,85 @@ static Inkscape::XML::Node* Inkscape::colorprofile_write( SPObject *object, Inks
#if ENABLE_LCMS
+struct MapMap {
+ icColorSpaceSignature space;
+ DWORD inForm;
+};
-static SPObject* bruteFind( SPObject* curr, gchar* const name )
+DWORD ColorProfile::_getInputFormat( icColorSpaceSignature space )
{
- SPObject* result = 0;
+ 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;
+}
- if ( curr ) {
- if ( IS_COLORPROFILE(curr) ) {
- ColorProfile* prof = COLORPROFILE(curr);
+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 )
+{
+ SPObject* result = 0;
+ const GSList * current = sp_document_get_resource_list(document, "iccprofile");
+ while ( current && !result ) {
+ if ( IS_COLORPROFILE(current->data) ) {
+ ColorProfile* prof = COLORPROFILE(current->data);
if ( prof ) {
if ( prof->name && (strcmp(prof->name, name) == 0) ) {
- result = curr;
+ result = SP_OBJECT(current->data);
+ break;
}
}
- } else {
- if ( curr->hasChildren() ) {
- SPObject* child = curr->firstChild();
- while ( child && !result ) {
- result = bruteFind( child, name );
- if ( !result ) {
- child = child->next;
- }
- };
- }
}
+ current = g_slist_next(current);
}
return result;
}
-cmsHPROFILE Inkscape::colorprofile_get_handle( SPDocument* document, guint* intent, gchar* const name )
+cmsHPROFILE Inkscape::colorprofile_get_handle( SPDocument* document, guint* intent, gchar const* name )
{
cmsHPROFILE prof = 0;
- SPObject* root = SP_DOCUMENT_ROOT(document);
- SPObject* thing = bruteFind( root, name );
+ SPObject* thing = bruteFind( document, name );
if ( thing ) {
prof = COLORPROFILE(thing)->profHandle;
}
@@ -367,6 +475,603 @@ 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>
+
+class ProfileInfo
+{
+public:
+ ProfileInfo( cmsHPROFILE, Glib::ustring const & path );
+
+ Glib::ustring const& getName() {return _name;}
+ Glib::ustring const& getPath() {return _path;}
+ icColorSpaceSignature getSpace() {return _profileSpace;}
+ icProfileClassSignature getClass() {return _profileClass;}
+
+private:
+ Glib::ustring _path;
+ Glib::ustring _name;
+ icColorSpaceSignature _profileSpace;
+ icProfileClassSignature _profileClass;
+};
+
+
+ProfileInfo::ProfileInfo( cmsHPROFILE prof, Glib::ustring const & path )
+{
+ _path = path;
+ _name = cmsTakeProductDesc(prof);
+ _profileSpace = cmsGetColorSpace( prof );
+ _profileClass = cmsGetDeviceClass( prof );
+}
+
+
+
+static std::vector<ProfileInfo> knownProfiles;
+
+std::vector<Glib::ustring> Inkscape::colorprofile_get_display_names()
+{
+ std::vector<Glib::ustring> result;
+
+ for ( std::vector<ProfileInfo>::iterator it = knownProfiles.begin(); it != knownProfiles.end(); ++it ) {
+ if ( it->getClass() == icSigDisplayClass && it->getSpace() == icSigRgbData ) {
+ result.push_back( it->getName() );
+ }
+ }
+
+ return result;
+}
+
+std::vector<Glib::ustring> Inkscape::colorprofile_get_softproof_names()
+{
+ std::vector<Glib::ustring> result;
+
+ for ( std::vector<ProfileInfo>::iterator it = knownProfiles.begin(); it != knownProfiles.end(); ++it ) {
+ if ( it->getClass() == icSigOutputClass ) {
+ result.push_back( it->getName() );
+ }
+ }
+
+ return result;
+}
+
+Glib::ustring Inkscape::get_path_for_profile(Glib::ustring const& name)
+{
+ Glib::ustring result;
+
+ for ( std::vector<ProfileInfo>::iterator it = knownProfiles.begin(); it != knownProfiles.end(); ++it ) {
+ if ( name == it->getName() ) {
+ result = it->getPath();
+ break;
+ }
+ }
+
+ return result;
+}
+#endif // ENABLE_LCMS
+
+std::list<Glib::ustring> ColorProfile::getProfileDirs() {
+ std::list<Glib::ustring> sources;
+
+ gchar* base = profile_path("XXX");
+ {
+ gchar* base2 = g_path_get_dirname(base);
+ g_free(base);
+ base = base2;
+ base2 = g_path_get_dirname(base);
+ g_free(base);
+ base = base2;
+ }
+
+ // first try user's local dir
+ sources.push_back( g_build_filename(g_get_user_data_dir(), "color", "icc", NULL) );
+
+
+ const gchar* const * dataDirs = g_get_system_data_dirs();
+ for ( int i = 0; dataDirs[i]; i++ ) {
+ gchar* path = g_build_filename(dataDirs[i], "color", "icc", NULL);
+ sources.push_back(path);
+ g_free(path);
+ }
+
+ // On OS X:
+ if ( g_file_test("/Library/ColorSync/Profiles", G_FILE_TEST_EXISTS) && g_file_test("/Library/ColorSync/Profiles", G_FILE_TEST_IS_DIR) ) {
+ sources.push_back("/Library/ColorSync/Profiles");
+
+ gchar* path = g_build_filename(g_get_home_dir(), "Library", "ColorSync", "Profiles", NULL);
+ if ( g_file_test(path, G_FILE_TEST_EXISTS) && g_file_test(path, G_FILE_TEST_IS_DIR) ) {
+ sources.push_back(path);
+ }
+ g_free(path);
+ }
+
+
+// #ifdef WIN32
+// wchar_t pathBuf[MAX_PATH + 1];
+// pathBuf[0] = 0;
+// DWORD pathSize = sizeof(pathBuf);
+// g_assert(sizeof(wchar_t) == sizeof(gunichar2));
+// if ( GetColorDirectoryW( NULL, &pathBuf, &pathSize ) ) {
+// gchar * utf8Path = g_utf16_to_utf8( (gunichar2*)(&pathBuf[0]), -1, NULL, NULL, NULL );
+// if ( !g_utf8_validate(utf8Path, -1, NULL) ) {
+// g_warning( "GetColorDirectoryW() resulted in invalid UTF-8" );
+// } else {
+// sources.pushback(utf8Path);
+// }
+// g_free( utf8Path );
+// }
+// #endif // WIN32
+
+ return sources;
+}
+
+#if ENABLE_LCMS
+static void findThings() {
+ std::list<Glib::ustring> sources = ColorProfile::getProfileDirs();
+
+ for ( std::list<Glib::ustring>::const_iterator it = sources.begin(); it != sources.end(); ++it ) {
+ if ( g_file_test( it->c_str(), G_FILE_TEST_EXISTS ) && g_file_test( it->c_str(), G_FILE_TEST_IS_DIR ) ) {
+ GError *err = 0;
+ GDir *dir = g_dir_open(it->c_str(), 0, &err);
+
+ if (dir) {
+ for (gchar const *file = g_dir_read_name(dir); file != NULL; file = g_dir_read_name(dir)) {
+ gchar *filepath = g_build_filename(it->c_str(), file, NULL);
+
+
+ if ( g_file_test( filepath, G_FILE_TEST_IS_DIR ) ) {
+ sources.push_back(g_strdup(filepath));
+ } else {
+ bool isIccFile = false;
+ struct stat st;
+ if ( g_stat(filepath, &st) == 0 && (st.st_size > 128) ) {
+ //0-3 == size
+ //36-39 == 'acsp' 0x61637370
+ int fd = g_open( filepath, O_RDONLY, S_IRWXU);
+ if ( fd != -1 ) {
+ guchar scratch[40] = {0};
+ size_t len = sizeof(scratch);
+
+ //size_t left = 40;
+ ssize_t got = read(fd, scratch, len);
+ if ( got != -1 ) {
+ size_t calcSize = (scratch[0] << 24) | (scratch[1] << 16) | (scratch[2] << 8) | scratch[3];
+ if ( calcSize > 128 && calcSize <= static_cast<size_t>(st.st_size) ) {
+ isIccFile = (scratch[36] == 'a') && (scratch[37] == 'c') && (scratch[38] == 's') && (scratch[39] == 'p');
+ }
+ }
+
+ close(fd);
+ }
+ }
+
+ if ( isIccFile ) {
+ cmsHPROFILE prof = cmsOpenProfileFromFile( filepath, "r" );
+ if ( prof ) {
+ ProfileInfo info( prof, Glib::filename_to_utf8( filepath ) );
+ cmsCloseProfile( prof );
+
+ bool sameName = false;
+ for ( std::vector<ProfileInfo>::iterator it = knownProfiles.begin(); it != knownProfiles.end(); ++it ) {
+ if ( it->getName() == info.getName() ) {
+ sameName = true;
+ break;
+ }
+ }
+
+ if ( !sameName ) {
+ knownProfiles.push_back(info);
+ }
+ }
+ }
+ }
+
+ g_free(filepath);
+ }
+ }
+ }
+ }
+}
+
+int errorHandlerCB(int ErrorCode, const char *ErrorText)
+{
+ g_message("lcms: Error %d; %s", ErrorCode, ErrorText);
+
+ return 1;
+}
+
+static bool gamutWarn = false;
+static Gdk::Color lastGamutColor("#808080");
+static bool lastBPC = false;
+#if defined(cmsFLAGS_PRESERVEBLACK)
+static bool lastPreserveBlack = false;
+#endif // defined(cmsFLAGS_PRESERVEBLACK)
+static int lastIntent = INTENT_PERCEPTUAL;
+static int lastProofIntent = INTENT_PERCEPTUAL;
+static cmsHTRANSFORM transf = 0;
+
+cmsHPROFILE Inkscape::colorprofile_get_system_profile_handle()
+{
+ static cmsHPROFILE theOne = 0;
+ static Glib::ustring lastURI;
+
+ static bool init = false;
+ if ( !init ) {
+ cmsSetErrorHandler(errorHandlerCB);
+
+ findThings();
+ init = true;
+ }
+
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ Glib::ustring uri = prefs->getString("/options/displayprofile/uri");
+
+ if ( !uri.empty() ) {
+ if ( uri != lastURI ) {
+ lastURI.clear();
+ if ( theOne ) {
+ cmsCloseProfile( theOne );
+ }
+ if ( transf ) {
+ cmsDeleteTransform( transf );
+ transf = 0;
+ }
+ theOne = cmsOpenProfileFromFile( uri.data(), "r" );
+ if ( theOne ) {
+ // a display profile must have the proper stuff
+ icColorSpaceSignature space = cmsGetColorSpace(theOne);
+ icProfileClassSignature profClass = cmsGetDeviceClass(theOne);
+
+ if ( profClass != icSigDisplayClass ) {
+ g_warning("Not a display profile");
+ cmsCloseProfile( theOne );
+ theOne = 0;
+ } else if ( space != icSigRgbData ) {
+ g_warning("Not an RGB profile");
+ cmsCloseProfile( theOne );
+ theOne = 0;
+ } else {
+ lastURI = uri;
+ }
+ }
+ }
+ } else if ( theOne ) {
+ cmsCloseProfile( theOne );
+ theOne = 0;
+ lastURI.clear();
+ if ( transf ) {
+ cmsDeleteTransform( transf );
+ transf = 0;
+ }
+ }
+
+ return theOne;
+}
+
+
+cmsHPROFILE Inkscape::colorprofile_get_proof_profile_handle()
+{
+ static cmsHPROFILE theOne = 0;
+ static Glib::ustring lastURI;
+
+ static bool init = false;
+ if ( !init ) {
+ cmsSetErrorHandler(errorHandlerCB);
+
+ findThings();
+ init = true;
+ }
+
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ bool which = prefs->getBool( "/options/softproof/enable");
+ Glib::ustring uri = prefs->getString("/options/softproof/uri");
+
+ if ( which && !uri.empty() ) {
+ if ( lastURI != uri ) {
+ lastURI.clear();
+ if ( theOne ) {
+ cmsCloseProfile( theOne );
+ }
+ if ( transf ) {
+ cmsDeleteTransform( transf );
+ transf = 0;
+ }
+ theOne = cmsOpenProfileFromFile( uri.data(), "r" );
+ if ( theOne ) {
+ // a display profile must have the proper stuff
+ icColorSpaceSignature space = cmsGetColorSpace(theOne);
+ icProfileClassSignature profClass = cmsGetDeviceClass(theOne);
+
+ (void)space;
+ (void)profClass;
+/*
+ if ( profClass != icSigDisplayClass ) {
+ g_warning("Not a display profile");
+ cmsCloseProfile( theOne );
+ theOne = 0;
+ } else if ( space != icSigRgbData ) {
+ g_warning("Not an RGB profile");
+ cmsCloseProfile( theOne );
+ theOne = 0;
+ } else {
+*/
+ lastURI = uri;
+/*
+ }
+*/
+ }
+ }
+ } else if ( theOne ) {
+ cmsCloseProfile( theOne );
+ theOne = 0;
+ lastURI.clear();
+ if ( transf ) {
+ cmsDeleteTransform( transf );
+ transf = 0;
+ }
+ }
+
+ return theOne;
+}
+
+static void free_transforms();
+
+cmsHTRANSFORM Inkscape::colorprofile_get_display_transform()
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ bool fromDisplay = prefs->getBool( "/options/displayprofile/from_display");
+ if ( fromDisplay ) {
+ if ( transf ) {
+ cmsDeleteTransform(transf);
+ transf = 0;
+ }
+ return 0;
+ }
+
+ bool warn = prefs->getBool( "/options/softproof/gamutwarn");
+ int intent = prefs->getIntLimited( "/options/displayprofile/intent", 0, 0, 3 );
+ int proofIntent = prefs->getIntLimited( "/options/softproof/intent", 0, 0, 3 );
+ bool bpc = prefs->getBool( "/options/softproof/bpc");
+#if defined(cmsFLAGS_PRESERVEBLACK)
+ bool preserveBlack = prefs->getBool( "/options/softproof/preserveblack");
+#endif //defined(cmsFLAGS_PRESERVEBLACK)
+ Glib::ustring colorStr = prefs->getString("/options/softproof/gamutcolor");
+ Gdk::Color gamutColor( colorStr.empty() ? "#808080" : colorStr );
+
+ 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 hprof = Inkscape::colorprofile_get_system_profile_handle();
+ cmsHPROFILE proofProf = hprof ? Inkscape::colorprofile_get_proof_profile_handle() : 0;
+
+ if ( !transf ) {
+ if ( 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)
+ transf = cmsCreateProofingTransform( ColorProfile::getSRGBProfile(), TYPE_RGBA_8, hprof, TYPE_RGBA_8, proofProf, intent, proofIntent, dwFlags );
+ } else if ( hprof ) {
+ transf = cmsCreateTransform( ColorProfile::getSRGBProfile(), TYPE_RGBA_8, hprof, TYPE_RGBA_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 ) {
+ id = Digest::hashHex(Digest::HASH_MD5,
+ reinterpret_cast<unsigned char*>(buf), bufLen);
+
+ // 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;
+ }
+
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ 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->getBool( "/options/softproof/gamutwarn");
+ int intent = prefs->getIntLimited( "/options/displayprofile/intent", 0, 0, 3 );
+ int proofIntent = prefs->getIntLimited( "/options/softproof/intent", 0, 0, 3 );
+ bool bpc = prefs->getBool( "/options/softproof/bpc");
+#if defined(cmsFLAGS_PRESERVEBLACK)
+ bool preserveBlack = prefs->getBool( "/options/softproof/preserveblack");
+#endif //defined(cmsFLAGS_PRESERVEBLACK)
+ Glib::ustring colorStr = prefs->getString("/options/softproof/gamutcolor");
+ Gdk::Color gamutColor( colorStr.empty() ? "#808080" : colorStr );
+
+ 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_RGBA_8, item.hprof, TYPE_RGBA_8, proofProf, intent, proofIntent, dwFlags );
+ } else if ( item.hprof ) {
+ item.transf = cmsCreateTransform( ColorProfile::getSRGBProfile(), TYPE_RGBA_8, item.hprof, TYPE_RGBA_8, intent, 0 );
+ }
+ }
+
+ result = item.transf;
+ found = true;
+ }
+ }
+ }
+
+ return result;
+}
+
+
+
#endif // ENABLE_LCMS
/*