1 /* separate+ 0.5 - image processing plug-in for the Gimp
2  *
3  * Copyright (C) 2002-2004 Alastair Robinson (blackfive@fakenhamweb.co.uk),
4  * Based on code by Andrew Kieschnick and Peter Kirchgessner
5  * 2007-2010 Modified by Yoshinori Yamakawa (yamma-ma@users.sourceforge.jp)
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */
21 
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 
26 #include <gtk/gtk.h>
27 #include <glib/gi18n.h>
28 
29 #include <libgimp/gimp.h>
30 
31 #include "platform.h"
32 
33 #include "separate.h"
34 #include "util.h"
35 
36 static char *separate_channelnames[] = {"C", "M", "Y", "K"};
37 
38 static gboolean
check_layer_name(char * layer_name,gint * mask)39 check_layer_name (char *layer_name,
40                   gint *mask)
41 {
42   if ((((*mask) & 16) == 0) && (strcmp (layer_name, _("Background")) == 0))
43     {
44       *mask |= 16;
45       return TRUE;
46     }
47   if ((((*mask) & 1) == 0) && (strcmp (layer_name, "C") == 0))
48     {
49       *mask |= 1;
50       return TRUE;
51     }
52   if ((((*mask) & 2) == 0) && (strcmp (layer_name, "M") == 0))
53     {
54       *mask |= 2;
55       return TRUE;
56     }
57   if ((((*mask) & 4) == 0) && (strcmp (layer_name, "Y") == 0))
58     {
59       *mask |= 4;
60       return TRUE;
61     }
62   if ((((*mask) & 8) == 0) && (strcmp (layer_name, "K") == 0))
63     {
64       *mask |= 8;
65       return TRUE;
66     }
67   return FALSE;
68 }
69 
70 
71 GimpDrawable *
separate_find_channel(gint32 image_id,enum separate_channel channel)72 separate_find_channel (gint32                image_id,
73                        enum separate_channel channel)
74 {
75   GimpDrawable *result=NULL;
76   gint *layers, layercount;
77   gint i;
78 
79   if ((channel < 0) || (channel > 3))
80     return NULL;
81 
82   layers = gimp_image_get_layers (image_id, &layercount);
83   for (i = 0; i < layercount; ++i)
84     {
85       char *layer_name = gimp_drawable_get_name (layers[i]);
86 
87       if (strcmp (layer_name, separate_channelnames[channel]) == 0)
88         {
89           result = gimp_drawable_get (layers[i]);
90           if (gimp_drawable_is_rgb (result->drawable_id))
91             result = gimp_drawable_get (gimp_layer_get_mask (layers[i]));
92 
93           return result;
94         }
95     }
96 
97   return result;
98 }
99 
100 GimpDrawable *
separate_find_alpha(gint32 image_id)101 separate_find_alpha (gint32 image_id)
102 {
103   gint *channels, n_channels;
104   gint i;
105 
106   channels = gimp_image_get_channels (image_id, &n_channels);
107 
108   if (n_channels && gimp_drawable_get_visible (channels[0]))
109     return gimp_drawable_get (channels[0]);
110   else
111     return NULL;
112 }
113 
114 
115 gboolean
separate_is_CMYK(gint32 image_id)116 separate_is_CMYK (gint32 image_id)
117 {
118   gint *layers, layercount;
119   gint i;
120   gint mask = 0;
121 
122   layers = gimp_image_get_layers (image_id, &layercount);
123 
124   if (layercount > 5)
125     return FALSE;
126 
127   for (i = 0; i < layercount; ++i)
128     {
129       char *layer_name = gimp_drawable_get_name (layers[i]);
130 
131       if (check_layer_name (layer_name, &mask) == FALSE)
132         return FALSE;
133     }
134 
135   if (mask == 0 || mask == 16)
136     return FALSE;
137 
138   return TRUE;
139 }
140 
141 
142 void
separate_init_settings(SeparateContext * sc,enum separate_function func,gboolean get_last_values)143 separate_init_settings (SeparateContext        *sc,
144                         enum separate_function  func,
145                         gboolean                get_last_values)
146 {
147 #ifdef ENABLE_COLOR_MANAGEMENT
148   GimpColorConfig *config;
149 #endif
150 
151   memset (sc, '\0', sizeof (SeparateContext));
152 
153   /* set default values */
154   switch (func)
155     {
156     case SEP_LIGHT:
157     case SEP_FULL:
158     case SEP_SEPARATE:
159     case SEP_PROOF:
160 #ifdef ENABLE_COLOR_MANAGEMENT
161       if ((config = gimp_get_color_configuration()))
162         {
163           g_object_get (config,
164                         "display-profile", &(sc->alt_displayfilename),
165                         "rgb-profile", &(sc->alt_rgbfilename),
166                         "cmyk-profile", &(sc->alt_cmykfilename),
167                         "printer-profile", &(sc->alt_prooffilename),
168                         "display-rendering-intent", &(sc->ps.mode),
169                         "simulation-rendering-intent", &(sc->ss.intent),
170                         NULL);
171           if (sc->ps.mode >= 2)
172             sc->ps.mode--;
173         }
174       g_object_unref (G_OBJECT (config));
175 #endif
176 
177       if (!(sc->alt_displayfilename))
178         sc->alt_displayfilename = DEFAULT_RGB_PROFILE;
179       if (!(sc->alt_rgbfilename))
180         sc->alt_rgbfilename = DEFAULT_RGB_PROFILE;
181       if (!(sc->alt_cmykfilename))
182         sc->alt_cmykfilename = DEFAULT_CMYK_PROFILE;
183       if (!(sc->alt_prooffilename))
184         sc->alt_prooffilename = DEFAULT_CMYK_PROFILE;
185 
186       sc->ss.profile = TRUE;
187       sc->ps.profile = TRUE;
188 
189       break;
190     case SEP_SAVE:
191     case SEP_EXPORT:
192 #ifdef ENABLE_COLOR_MANAGEMENT
193       if ((config = gimp_get_color_configuration()))
194         {
195           g_object_get (config,
196                         "cmyk-profile", &(sc->cmykfilename),
197                         "printer-profile", &(sc->prooffilename),
198                         NULL);
199         }
200       g_object_unref (G_OBJECT (config));
201 #endif
202       break;
203     case SEP_DUOTONE:
204     default:
205       break;
206     }
207 
208   /* get last values */
209   if (get_last_values)
210     {
211       gint size;
212 
213       switch (func)
214         {
215           /* TODO : g_free ()やNULL値の設定が必要でないことの検証 */
216         case SEP_LIGHT:
217         case SEP_FULL:
218         case SEP_SEPARATE:
219           if ((size = gimp_get_data_size ("separate_rgbprofile")))
220             {
221               g_free (sc->rgbfilename);
222               sc->rgbfilename = g_new (gchar, size);
223               gimp_get_data ("separate_rgbprofile", sc->rgbfilename);
224             }
225           g_free (sc->cmykfilename);
226           if ((size = gimp_get_data_size ("separate_cmykprofile")) > 1)
227             {
228               sc->cmykfilename = g_new (gchar, size);
229               gimp_get_data ("separate_cmykprofile", sc->cmykfilename);
230             }
231           else
232             sc->cmykfilename = NULL;
233           gimp_get_data ("separate_settings", &(sc->ss));
234           break;
235         case SEP_PROOF:
236           if ((size = gimp_get_data_size ("separate_displayprofile")))
237             {
238               g_free (sc->displayfilename );
239               sc->displayfilename = g_new (gchar, size);
240               gimp_get_data ("separate_displayprofile", sc->displayfilename);
241             }
242           if ((size = gimp_get_data_size ("separate_proofprofile")))
243             {
244               g_free (sc->prooffilename);
245               sc->prooffilename = g_new (gchar, size);
246               gimp_get_data ("separate_proofprofile", sc->prooffilename);
247             }
248           gimp_get_data( "separate_proofsettings", &( sc->ps ) );
249           break;
250         case SEP_EXPORT:
251           gimp_get_data ("separate_exportsettings", &(sc->sas));
252           break;
253         default:
254           break;
255         }
256     }
257 }
258 
259 void
separate_store_settings(SeparateContext * sc,enum separate_function func)260 separate_store_settings (SeparateContext        *sc,
261                          enum separate_function  func)
262 {
263   switch( func ) {
264   case SEP_SEPARATE:
265   case SEP_FULL:
266   case SEP_LIGHT:
267     if( sc->rgbfilename )
268       gimp_set_data( "separate_rgbprofile", sc->rgbfilename, strlen( sc->rgbfilename ) + 1 );
269     if( sc->cmykfilename )
270       gimp_set_data( "separate_cmykprofile", sc->cmykfilename, strlen( sc->cmykfilename ) + 1 );
271     else
272       gimp_set_data( "separate_cmykprofile", "", 1);
273     gimp_set_data( "separate_settings", &( sc->ss ), sizeof( SeparateSettings ) );
274     break;
275   case SEP_PROOF:
276     if( sc->displayfilename )
277       gimp_set_data( "separate_displayprofile", sc->displayfilename, strlen( sc->displayfilename ) + 1 );
278     if( sc->prooffilename )
279       gimp_set_data( "separate_proofprofile", sc->prooffilename, strlen( sc->prooffilename ) + 1 );
280     gimp_set_data( "separate_proofsettings", &( sc->ps ), sizeof( ProofSettings ) );
281     break;
282   case SEP_EXPORT:
283     gimp_set_data ("separate_exportsettings", &(sc->sas), sizeof (SaveSettings));
284     break;
285   default:
286     break;
287   }
288 }
289 
290 /* Create a normal RGB image for proof...*/
291 gint32
separate_create_RGB(gchar * filename,guint width,guint height,gboolean has_alpha,gint32 * layers)292 separate_create_RGB (gchar    *filename,
293                      guint     width,
294                      guint     height,
295                      gboolean  has_alpha,
296                      gint32   *layers)
297 {
298   gint32 image_id;
299 
300   image_id = gimp_image_new (width, height, GIMP_RGB);
301   gimp_image_undo_disable (image_id);
302   gimp_image_set_filename (image_id, filename);
303 
304   if (has_alpha)
305     layers[0] = gimp_layer_new (image_id, _("Layer 1"), width, height,
306                                 GIMP_RGBA_IMAGE, 100, GIMP_NORMAL_MODE);
307   else
308     layers[0] = gimp_layer_new (image_id, _("Background"), width, height,
309                                 GIMP_RGB_IMAGE, 100, GIMP_NORMAL_MODE);
310 
311   gimp_image_add_layer (image_id, layers[0], -1);
312 
313   return image_id;
314 }
315 
316 
317 /* Create an image with four greyscale layers, to be used as CMYK channels...*/
318 gint32
separate_create_planes_grey(gchar * filename,guint width,guint height,gint32 * layers)319 separate_create_planes_grey (gchar  *filename,
320                              guint   width,
321                              guint   height,
322                              gint32 *layers)
323 {
324   gint32 image_id;
325 
326   image_id = gimp_image_new (width, height, GIMP_GRAY);
327   gimp_image_undo_disable (image_id);
328   gimp_image_set_filename (image_id, filename);
329 
330   layers[0] = gimp_layer_new (image_id, "K", width, height,
331                               GIMP_GRAY_IMAGE, 100, GIMP_NORMAL_MODE);
332   gimp_image_add_layer (image_id, layers[0], -1);
333   layers[1] = gimp_layer_new (image_id, "Y", width, height,
334                               GIMP_GRAY_IMAGE, 100, GIMP_NORMAL_MODE);
335   gimp_image_add_layer (image_id, layers[1], -1);
336   layers[2] = gimp_layer_new (image_id, "M", width, height,
337                               GIMP_GRAY_IMAGE, 100, GIMP_NORMAL_MODE);
338   gimp_image_add_layer (image_id, layers[2], -1);
339   layers[3] = gimp_layer_new (image_id, "C", width, height,
340                               GIMP_GRAY_IMAGE, 100, GIMP_NORMAL_MODE);
341   gimp_image_add_layer (image_id, layers[3], -1);
342 
343   return image_id;
344 }
345 
346 
347 /* Create an image with four colour layers with masks, to be used as CMYK channels...*/
348 gint32
separate_create_planes_CMYK(gchar * filename,guint width,guint height,gint32 * layers,guchar * primaries)349 separate_create_planes_CMYK (gchar  *filename,
350                              guint   width,
351                              guint   height,
352                              gint32 *layers,
353                              guchar *primaries)
354 {
355   gint32 image_id;
356   gint32 background_id;
357   gint counter;
358   GimpRGB rgb;
359 
360   image_id = gimp_image_new (width, height, GIMP_RGB);
361   gimp_image_undo_disable (image_id);
362   gimp_image_set_filename (image_id, filename);
363 
364   background_id = gimp_layer_new (image_id, _("Background"), width, height,
365                                   GIMP_RGB_IMAGE, 100, GIMP_NORMAL_MODE);
366   gimp_image_add_layer (image_id, background_id, -1);
367   layers[0] = gimp_layer_new (image_id, "K", width, height,
368                               GIMP_RGBA_IMAGE, 100, GIMP_DARKEN_ONLY_MODE);
369   gimp_image_add_layer (image_id, layers[0], -1);
370   layers[1] = gimp_layer_new (image_id, "Y", width, height,
371                               GIMP_RGBA_IMAGE, 100, GIMP_DARKEN_ONLY_MODE);
372   gimp_image_add_layer (image_id, layers[1], -1);
373   layers[2] = gimp_layer_new (image_id, "M", width, height,
374                               GIMP_RGBA_IMAGE, 100, GIMP_DARKEN_ONLY_MODE);
375   gimp_image_add_layer (image_id, layers[2], -1);
376   layers[3] = gimp_layer_new (image_id, "C", width, height,
377                               GIMP_RGBA_IMAGE, 100, GIMP_DARKEN_ONLY_MODE);
378   gimp_image_add_layer (image_id, layers[3], -1);
379 
380   gimp_context_push ();
381 
382   for (counter = 0; counter < 4; counter++)
383     {
384       gimp_rgb_set_uchar (&rgb, primaries[0], primaries[1], primaries[2]);
385       gimp_context_set_foreground (&rgb);
386       primaries += 3;
387 
388       gimp_drawable_fill (layers[counter], GIMP_FOREGROUND_FILL);
389     }
390 
391   rgb.r = rgb.g = rgb.b = 1.0;
392   gimp_context_set_foreground (&rgb);
393   gimp_drawable_fill (background_id, GIMP_FOREGROUND_FILL);
394 
395   gimp_context_pop ();
396 
397   return image_id;
398 }
399 
400 
401 /* Create an image with two colour layers with masks, to be used as MK duotone channels...*/
402 gint32
separate_create_planes_Duotone(gchar * filename,guint width,guint height,gint32 * layers)403 separate_create_planes_Duotone (gchar  *filename,
404                                 guint   width,
405                                 guint   height,
406                                 gint32 *layers)
407 {
408   gint32 image_id;
409   gint32 background_id;
410   GimpRGB rgb = {0};
411 
412   image_id = gimp_image_new (width, height, GIMP_RGB);
413   gimp_image_undo_disable (image_id);
414   gimp_image_set_filename (image_id, filename);
415 
416   background_id = gimp_layer_new (image_id, _("Background"), width, height,
417                                   GIMP_RGB_IMAGE, 100, GIMP_NORMAL_MODE);
418   gimp_image_add_layer (image_id, background_id, -1);
419 
420   layers[0] = gimp_layer_new (image_id, "K", width, height,
421                               GIMP_RGBA_IMAGE, 100, GIMP_DARKEN_ONLY_MODE);
422   gimp_image_add_layer (image_id, layers[0], -1);
423 
424   layers[1] = gimp_layer_new (image_id, "M", width, height,
425                               GIMP_RGBA_IMAGE, 100, GIMP_DARKEN_ONLY_MODE);
426   gimp_image_add_layer (image_id, layers[1], -1);
427 
428   gimp_context_push ();
429 
430   gimp_context_set_foreground (&rgb);
431   gimp_drawable_fill (layers[0], GIMP_FOREGROUND_FILL);
432 
433   rgb.r = 1.0;
434   gimp_context_set_foreground (&rgb);
435   gimp_drawable_fill (layers[1], GIMP_FOREGROUND_FILL);
436 
437   rgb.r = rgb.g = rgb.b = 1.0;
438   gimp_context_set_foreground (&rgb);
439   gimp_drawable_fill (background_id, GIMP_FOREGROUND_FILL);
440 
441   gimp_context_pop ();
442 
443   return image_id;
444 }
445 
446 
447 char *
separate_build_filename(char * root,char * suffix)448 separate_build_filename (char *root,
449                          char *suffix)
450 {
451   /* Build a filename like <imagename>-<channel>.<extension> */
452   char *filename;
453   char *extension;
454   root = g_strdup (root);
455   extension = root + strlen (root) - 1;
456 
457   while (extension >= root)
458     {
459       if (*extension == '.')
460         break;
461 
462       extension--;
463     }
464 
465   if (extension >= root)
466     {
467       *(extension++) = '\0';
468       filename = g_strdup_printf ("%s-%s.%s", root, suffix, extension);
469     }
470   else
471     filename = g_strdup_printf ("%s-%s", root, suffix);
472 
473   g_free (root);
474 
475   return filename;
476 }
477 
478 
479 char *
separate_filename_add_suffix(char * root,char * suffix)480 separate_filename_add_suffix (char *root,
481                               char *suffix)
482 {
483   /* Build a filename like <imagename>-<channel>.<extension> */
484   char *filename;
485   char *extension;
486 
487   if (root == NULL)
488     return g_strdup_printf (_("Untitled-%s.tif"), suffix);
489 
490   root = g_strdup (root);
491   extension = root + strlen (root) - 1;
492 
493   while (extension >= root)
494     {
495       if (*extension == '.') break;
496       extension--;
497     }
498   if (extension >= root)
499     {
500       *(extension++) = '\0';
501     }
502 
503   filename = g_strdup_printf ("%s-%s.tif", root, suffix);
504   g_free (root);
505 
506   return filename;
507 }
508 
509 
510 char *
separate_filename_change_extension(char * root,char * newext)511 separate_filename_change_extension (char *root,
512                                     char *newext)
513 {
514   /* Change <imagename>.<extension> to <imagename>.<tif> */
515   char *filename;
516   char *extension;
517 
518   root =g_strdup (root);
519   extension = root + strlen (root) - 1;
520 
521   while (extension >= root)
522     {
523       if (*extension == '.')
524         break;
525 
526       extension--;
527     }
528 
529   if (extension >= root)
530     {
531       *extension++ = 0;
532       filename = g_strdup_printf ("%s.%s", root, newext);
533     }
534   else
535     filename = g_strdup (root);
536 
537   g_free (root);
538 
539   return filename;
540 }
541 
542 
543 gint
separate_path_get_extention_offset(gchar * filename)544 separate_path_get_extention_offset (gchar *filename)
545 {
546   gint length;
547   gint offset;
548 
549   g_return_val_if_fail (filename != NULL, 0);
550 
551   length = strlen (filename);
552   offset = length;
553 
554   while (offset > 0)
555     {
556       if (filename[offset] == '.')
557         {
558           if (!(offset == length - 1) && !G_IS_DIR_SEPARATOR (filename[offset - 1]))
559             return offset;
560           else
561             return 0;
562         }
563 
564       offset--;
565     }
566 
567   return 0;
568 }
569