3 #include "xml/repr.h"
4 #include "color-profile.h"
5 #include "color-profile-fns.h"
6 #include "attributes.h"
7 #include "document.h"
9 //#define DEBUG_LCMS
11 #ifdef DEBUG_LCMS
12 #include "prefs-utils.h"
13 #include <gtk/gtkmessagedialog.h>
14 #endif // DEBUG_LCMS
16 using Inkscape::ColorProfile;
17 using Inkscape::ColorProfileClass;
19 namespace Inkscape
20 {
21 static void colorprofile_class_init( ColorProfileClass *klass );
22 static void colorprofile_init( ColorProfile *cprof );
24 static void colorprofile_release( SPObject *object );
25 static void colorprofile_build( SPObject *object, SPDocument *document, Inkscape::XML::Node *repr );
26 static void colorprofile_set( SPObject *object, unsigned key, gchar const *value );
27 static Inkscape::XML::Node *colorprofile_write( SPObject *object, Inkscape::XML::Node *repr, guint flags );
28 }
30 #ifdef DEBUG_LCMS
31 extern guint update_in_progress;
32 #define DEBUG_MESSAGE(key, ...) \
33 {\
34 gint dump = prefs_get_int_attribute_limited("options.scislac", #key, 0, 0, 1);\
35 gint dumpD = prefs_get_int_attribute_limited("options.scislac", #key"D", 0, 0, 1);\
36 gint dumpD2 = prefs_get_int_attribute_limited("options.scislac", #key"D2", 0, 0, 1);\
37 dumpD &= ( (update_in_progress == 0) || dumpD2 );\
38 if ( dump )\
39 {\
40 g_message( __VA_ARGS__ );\
41 \
42 }\
43 if ( dumpD )\
44 {\
45 GtkWidget *dialog = gtk_message_dialog_new(NULL,\
46 GTK_DIALOG_DESTROY_WITH_PARENT, \
47 GTK_MESSAGE_INFO, \
48 GTK_BUTTONS_OK, \
49 __VA_ARGS__ \
50 );\
51 g_signal_connect_swapped(dialog, "response",\
52 G_CALLBACK(gtk_widget_destroy), \
53 dialog); \
54 gtk_widget_show_all( dialog );\
55 }\
56 }
57 #endif // DEBUG_LCMS
59 static SPObject *cprof_parent_class;
61 /**
62 * Register ColorProfile class and return its type.
63 */
64 GType Inkscape::colorprofile_get_type()
65 {
66 static GType type = 0;
67 if (!type) {
68 GTypeInfo info = {
69 sizeof(ColorProfileClass),
70 NULL, NULL,
71 (GClassInitFunc) colorprofile_class_init,
72 NULL, NULL,
73 sizeof(ColorProfile),
74 16,
75 (GInstanceInitFunc) colorprofile_init,
76 NULL, /* value_table */
77 };
78 type = g_type_register_static( SP_TYPE_OBJECT, "ColorProfile", &info, static_cast<GTypeFlags>(0) );
79 }
80 return type;
81 }
83 /**
84 * ColorProfile vtable initialization.
85 */
86 static void Inkscape::colorprofile_class_init( ColorProfileClass *klass )
87 {
88 SPObjectClass *sp_object_class = reinterpret_cast<SPObjectClass *>(klass);
90 cprof_parent_class = static_cast<SPObject*>(g_type_class_ref(SP_TYPE_OBJECT));
92 sp_object_class->release = colorprofile_release;
93 sp_object_class->build = colorprofile_build;
94 sp_object_class->set = colorprofile_set;
95 sp_object_class->write = colorprofile_write;
96 }
98 /**
99 * Callback for ColorProfile object initialization.
100 */
101 static void Inkscape::colorprofile_init( ColorProfile *cprof )
102 {
103 cprof->href = 0;
104 cprof->local = 0;
105 cprof->name = 0;
106 cprof->intentStr = 0;
107 cprof->rendering_intent = Inkscape::RENDERING_INTENT_UNKNOWN;
108 #if ENABLE_LCMS
109 cprof->profHandle = 0;
110 #endif // ENABLE_LCMS
111 }
113 /**
114 * Callback: free object
115 */
116 static void Inkscape::colorprofile_release( SPObject *object )
117 {
118 ColorProfile *cprof = COLORPROFILE(object);
119 if ( cprof->href ) {
120 g_free( cprof->href );
121 cprof->href = 0;
122 }
124 if ( cprof->local ) {
125 g_free( cprof->local );
126 cprof->local = 0;
127 }
129 if ( cprof->name ) {
130 g_free( cprof->name );
131 cprof->name = 0;
132 }
134 if ( cprof->intentStr ) {
135 g_free( cprof->intentStr );
136 cprof->intentStr = 0;
137 }
139 #if ENABLE_LCMS
140 if ( cprof->profHandle ) {
141 cmsCloseProfile( cprof->profHandle );
142 cprof->profHandle = 0;
143 }
144 #endif // ENABLE_LCMS
145 }
147 /**
148 * Callback: set attributes from associated repr.
149 */
150 static void Inkscape::colorprofile_build( SPObject *object, SPDocument *document, Inkscape::XML::Node *repr )
151 {
152 ColorProfile *cprof = COLORPROFILE(object);
153 g_assert(cprof->href == 0);
154 g_assert(cprof->local == 0);
155 g_assert(cprof->name == 0);
156 g_assert(cprof->intentStr == 0);
158 if (((SPObjectClass *) cprof_parent_class)->build) {
159 (* ((SPObjectClass *) cprof_parent_class)->build)(object, document, repr);
160 }
161 sp_object_read_attr( object, "xlink:href" );
162 sp_object_read_attr( object, "local" );
163 sp_object_read_attr( object, "name" );
164 sp_object_read_attr( object, "rendering-intent" );
165 }
167 /**
168 * Callback: set attribute.
169 */
170 static void Inkscape::colorprofile_set( SPObject *object, unsigned key, gchar const *value )
171 {
172 ColorProfile *cprof = COLORPROFILE(object);
174 switch (key) {
175 case SP_ATTR_XLINK_HREF:
176 if ( cprof->href ) {
177 g_free( cprof->href );
178 cprof->href = 0;
179 }
180 if ( value ) {
181 cprof->href = g_strdup( value );
182 if ( *cprof->href ) {
183 #if ENABLE_LCMS
184 cmsErrorAction( LCMS_ERROR_SHOW );
186 // TODO open filename and URIs properly
187 //FILE* fp = fopen_utf8name( filename, "r" );
188 //LCMSAPI cmsHPROFILE LCMSEXPORT cmsOpenProfileFromMem(LPVOID MemPtr, DWORD dwSize);
190 if ( !g_path_is_absolute(cprof->href) ) {
191 // Try to open relative
192 gchar* docbase = SP_DOCUMENT_BASE( SP_OBJECT_DOCUMENT(object) );
193 gchar* fullname = g_build_filename( docbase ? docbase : ".", cprof->href, NULL );
195 cprof->profHandle = cmsOpenProfileFromFile( fullname, "r" );
196 #ifdef DEBUG_LCMS
197 DEBUG_MESSAGE( lcmsOne, "cmsOpenProfileFromFile( '%s'...) = %p", fullname, (void*)cprof->profHandle );
198 #endif // DEBUG_LCMS
199 g_free (fullname);
200 } else {
201 cprof->profHandle = cmsOpenProfileFromFile( cprof->href, "r" );
202 #ifdef DEBUG_LCMS
203 DEBUG_MESSAGE( lcmsOne, "cmsOpenProfileFromFile( '%s'...) = %p", cprof->href, (void*)cprof->profHandle );
204 #endif // DEBUG_LCMS
205 }
207 #endif // ENABLE_LCMS
208 }
209 }
210 object->requestModified(SP_OBJECT_MODIFIED_FLAG);
211 break;
213 case SP_ATTR_LOCAL:
214 if ( cprof->local ) {
215 g_free( cprof->local );
216 cprof->local = 0;
217 }
218 cprof->local = g_strdup( value );
219 object->requestModified(SP_OBJECT_MODIFIED_FLAG);
220 break;
222 case SP_ATTR_NAME:
223 if ( cprof->name ) {
224 g_free( cprof->name );
225 cprof->name = 0;
226 }
227 cprof->name = g_strdup( value );
228 #ifdef DEBUG_LCMS
229 DEBUG_MESSAGE( lcmsTwo, "<color-profile> name set to '%s'", cprof->name );
230 #endif // DEBUG_LCMS
231 object->requestModified(SP_OBJECT_MODIFIED_FLAG);
232 break;
234 case SP_ATTR_RENDERING_INTENT:
235 if ( cprof->intentStr ) {
236 g_free( cprof->intentStr );
237 cprof->intentStr = 0;
238 }
239 cprof->intentStr = g_strdup( value );
241 if ( value ) {
242 if ( strcmp( value, "auto" ) == 0 ) {
243 cprof->rendering_intent = RENDERING_INTENT_AUTO;
244 } else if ( strcmp( value, "perceptual" ) == 0 ) {
245 cprof->rendering_intent = RENDERING_INTENT_PERCEPTUAL;
246 } else if ( strcmp( value, "relative-colorimetric" ) == 0 ) {
247 cprof->rendering_intent = RENDERING_INTENT_RELATIVE_COLORIMETRIC;
248 } else if ( strcmp( value, "saturation" ) == 0 ) {
249 cprof->rendering_intent = RENDERING_INTENT_SATURATION;
250 } else if ( strcmp( value, "absolute-colorimetric" ) == 0 ) {
251 cprof->rendering_intent = RENDERING_INTENT_ABSOLUTE_COLORIMETRIC;
252 } else {
253 cprof->rendering_intent = RENDERING_INTENT_UNKNOWN;
254 }
255 } else {
256 cprof->rendering_intent = RENDERING_INTENT_UNKNOWN;
257 }
259 object->requestModified(SP_OBJECT_MODIFIED_FLAG);
260 break;
262 default:
263 if (((SPObjectClass *) cprof_parent_class)->set) {
264 (* ((SPObjectClass *) cprof_parent_class)->set)(object, key, value);
265 }
266 break;
267 }
269 }
271 /**
272 * Callback: write attributes to associated repr.
273 */
274 static Inkscape::XML::Node* Inkscape::colorprofile_write( SPObject *object, Inkscape::XML::Node *repr, guint flags )
275 {
276 ColorProfile *cprof = COLORPROFILE(object);
278 if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
279 repr = sp_repr_new("svg:color-profile");
280 }
282 if ( (flags & SP_OBJECT_WRITE_ALL) || cprof->href ) {
283 repr->setAttribute( "xlink:href", cprof->href );
284 }
286 if ( (flags & SP_OBJECT_WRITE_ALL) || cprof->local ) {
287 repr->setAttribute( "local", cprof->local );
288 }
290 if ( (flags & SP_OBJECT_WRITE_ALL) || cprof->name ) {
291 repr->setAttribute( "name", cprof->name );
292 }
294 if ( (flags & SP_OBJECT_WRITE_ALL) || cprof->intentStr ) {
295 repr->setAttribute( "rendering-intent", cprof->intentStr );
296 }
298 if (((SPObjectClass *) cprof_parent_class)->write) {
299 (* ((SPObjectClass *) cprof_parent_class)->write)(object, repr, flags);
300 }
302 return repr;
303 }
306 #if ENABLE_LCMS
309 static SPObject* bruteFind( SPObject* curr, gchar* const name )
310 {
311 SPObject* result = 0;
313 if ( curr ) {
314 if ( IS_COLORPROFILE(curr) ) {
315 ColorProfile* prof = COLORPROFILE(curr);
316 if ( prof ) {
317 if ( prof->name && (strcmp(prof->name, name) == 0) ) {
318 result = curr;
319 }
320 }
321 } else {
322 if ( curr->hasChildren() ) {
323 SPObject* child = curr->firstChild();
324 while ( child && !result ) {
325 result = bruteFind( child, name );
326 if ( !result ) {
327 child = child->next;
328 }
329 };
330 }
331 }
332 }
334 return result;
335 }
337 cmsHPROFILE Inkscape::colorprofile_get_handle( SPDocument* document, guint* intent, gchar* const name )
338 {
339 cmsHPROFILE prof = 0;
341 SPObject* root = SP_DOCUMENT_ROOT(document);
342 SPObject* thing = bruteFind( root, name );
343 if ( thing ) {
344 prof = COLORPROFILE(thing)->profHandle;
345 }
347 if ( intent ) {
348 *intent = thing ? COLORPROFILE(thing)->rendering_intent : (guint)RENDERING_INTENT_UNKNOWN;
349 }
351 #ifdef DEBUG_LCMS
352 DEBUG_MESSAGE( lcmsThree, "<color-profile> queried for profile of '%s'. Returning %p with intent of %d", name, prof, (intent? *intent:0) );
353 #endif // DEBUG_LCMS
355 return prof;
356 }
357 #endif // ENABLE_LCMS
359 /*
360 Local Variables:
361 mode:c++
362 c-file-style:"stroustrup"
363 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
364 indent-tabs-mode:nil
365 fill-column:99
366 End:
367 */
368 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :