1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * file-gegl.c -- GEGL based file format plug-in
5  * Copyright (C) 2012 Simon Budig <simon@gimp.org>
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 3 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, see <https://www.gnu.org/licenses/>.
19  */
20 
21 #include "config.h"
22 
23 #include <stdlib.h>
24 #include <errno.h>
25 
26 #include <glib/gstdio.h>
27 
28 #include <libgimp/gimp.h>
29 #include <libgimp/gimpui.h>
30 
31 #include "libgimp/stdplugins-intl.h"
32 
33 
34 #define PLUG_IN_BINARY "file-gegl"
35 
36 
37 typedef struct _FileFormat FileFormat;
38 
39 struct _FileFormat
40 {
41   const gchar *file_type;
42   const gchar *mime_type;
43   const gchar *extensions;
44   const gchar *magic;
45 
46   const gchar *load_proc;
47   const gchar *load_blurb;
48   const gchar *load_help;
49   const gchar *load_op;
50 
51   const gchar *save_proc;
52   const gchar *save_blurb;
53   const gchar *save_help;
54   const gchar *save_op;
55 };
56 
57 
58 static void     query      (void);
59 static void     run        (const gchar      *name,
60                             gint              nparams,
61                             const GimpParam  *param,
62                             gint             *nreturn_vals,
63                             GimpParam       **return_vals);
64 static gint32   load_image (const gchar      *filename,
65                             const gchar      *gegl_op,
66                             GError          **error);
67 static gboolean save_image (const gchar      *filename,
68                             const gchar      *gegl_op,
69                             gint32            image_ID,
70                             gint32            drawable_ID,
71                             GError          **error);
72 
73 
74 static const FileFormat file_formats[] =
75 {
76   {
77     N_("Radiance RGBE"),
78     "image/vnd.radiance",
79     "hdr",
80     "0,string,#?",
81 
82     "file-load-rgbe",
83     "Load files in the RGBE file format",
84     "This procedure loads images in the RGBE format, using gegl:rgbe-load",
85     "gegl:rgbe-load",
86 
87     "file-save-rgbe",
88     "Saves files in the RGBE file format",
89     "This procedure exports images in the RGBE format, using gegl:rgbe-save",
90     "gegl:rgbe-save",
91   },
92   {
93     N_("OpenEXR image"),
94     "image/x-exr",
95     "exr",
96     "0,lelong,20000630",
97 
98     /* no EXR loading (implemented in native GIMP plug-in) */
99     NULL, NULL, NULL, NULL,
100 
101     "file-exr-save",
102     "Saves files in the OpenEXR file format",
103     "This procedure saves images in the OpenEXR format, using gegl:exr-save",
104     "gegl:exr-save"
105   }
106 };
107 
108 
109 const GimpPlugInInfo PLUG_IN_INFO =
110 {
111   NULL,  /* init_proc */
112   NULL,  /* quit_proc */
113   query, /* query proc */
114   run,   /* run_proc */
115 };
116 
MAIN()117 MAIN ()
118 
119 static void
120 query (void)
121 {
122   static const GimpParamDef load_args[] =
123   {
124     { GIMP_PDB_INT32,  "run-mode",     "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
125     { GIMP_PDB_STRING, "filename",     "The name of the file to load." },
126     { GIMP_PDB_STRING, "raw-filename", "The name entered" },
127   };
128 
129   static const GimpParamDef load_return_vals[] =
130   {
131     { GIMP_PDB_IMAGE,  "image",        "Output image" }
132   };
133 
134   static const GimpParamDef save_args[] =
135   {
136     { GIMP_PDB_INT32,    "run-mode",     "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
137     { GIMP_PDB_IMAGE,    "image",        "Input image" },
138     { GIMP_PDB_DRAWABLE, "drawable",     "Drawable to save" },
139     { GIMP_PDB_STRING,   "filename",     "The name of the file to save the image in" },
140     { GIMP_PDB_STRING,   "raw-filename", "The name of the file to save the image in" }
141   };
142 
143   gint i;
144 
145   for (i = 0; i < G_N_ELEMENTS (file_formats); i++)
146     {
147       const FileFormat *format = &file_formats[i];
148 
149       if (format->load_proc)
150         {
151           gimp_install_procedure (format->load_proc,
152                                   format->load_blurb,
153                                   format->load_help,
154                                   "Simon Budig",
155                                   "Simon Budig",
156                                   "2012",
157                                   format->file_type,
158                                   NULL,
159                                   GIMP_PLUGIN,
160                                   G_N_ELEMENTS (load_args),
161                                   G_N_ELEMENTS (load_return_vals),
162                                   load_args, load_return_vals);
163 
164           gimp_register_file_handler_mime (format->load_proc,
165                                            format->mime_type);
166           gimp_register_magic_load_handler (format->load_proc,
167                                             format->extensions,
168                                             "",
169                                             format->magic);
170         }
171 
172       if (format->save_proc)
173         {
174           gimp_install_procedure (format->save_proc,
175                                   format->save_blurb,
176                                   format->save_help,
177                                   "Simon Budig",
178                                   "Simon Budig",
179                                   "2012",
180                                   format->file_type,
181                                   "*",
182                                   GIMP_PLUGIN,
183                                   G_N_ELEMENTS (save_args), 0,
184                                   save_args, NULL);
185 
186           gimp_register_file_handler_mime (format->save_proc,
187                                            format->mime_type);
188           gimp_register_save_handler (format->save_proc,
189                                       format->extensions, "");
190         }
191     }
192 }
193 
194 static void
run(const gchar * name,gint nparams,const GimpParam * param,gint * nreturn_vals,GimpParam ** return_vals)195 run (const gchar      *name,
196      gint              nparams,
197      const GimpParam  *param,
198      gint             *nreturn_vals,
199      GimpParam       **return_vals)
200 {
201   static GimpParam   values[2];
202   GimpPDBStatusType  status = GIMP_PDB_SUCCESS;
203   GimpRunMode        run_mode;
204   gint               image_ID;
205   gint               drawable_ID;
206   GError            *error = NULL;
207   gint               i;
208 
209   INIT_I18N ();
210   gegl_init (NULL, NULL);
211 
212   run_mode = param[0].data.d_int32;
213 
214   *nreturn_vals = 1;
215   *return_vals  = values;
216 
217   values[0].type          = GIMP_PDB_STATUS;
218   values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
219 
220   for (i = 0; i < G_N_ELEMENTS (file_formats); i++)
221     {
222       const FileFormat *format = &file_formats[i];
223 
224       if (format->load_proc && !strcmp (name, format->load_proc))
225         {
226           image_ID = load_image (param[1].data.d_string, format->load_op, &error);
227 
228           if (image_ID != -1)
229             {
230               *nreturn_vals = 2;
231               values[1].type         = GIMP_PDB_IMAGE;
232               values[1].data.d_image = image_ID;
233             }
234           else
235             {
236               status = GIMP_PDB_EXECUTION_ERROR;
237             }
238 
239           break;
240         }
241       else if (format->save_proc && !strcmp (name, format->save_proc))
242         {
243           GimpExportReturn export = GIMP_EXPORT_CANCEL;
244 
245           image_ID    = param[1].data.d_int32;
246           drawable_ID = param[2].data.d_int32;
247 
248           /*  eventually export the image */
249           switch (run_mode)
250             {
251             case GIMP_RUN_INTERACTIVE:
252             case GIMP_RUN_WITH_LAST_VALS:
253               gimp_ui_init (PLUG_IN_BINARY, FALSE);
254 
255               export = gimp_export_image (&image_ID, &drawable_ID, "GEGL",
256                                           GIMP_EXPORT_CAN_HANDLE_RGB     |
257                                           GIMP_EXPORT_CAN_HANDLE_GRAY    |
258                                           GIMP_EXPORT_CAN_HANDLE_INDEXED |
259                                           GIMP_EXPORT_CAN_HANDLE_ALPHA);
260 
261               if (export == GIMP_EXPORT_CANCEL)
262                 {
263                   *nreturn_vals = 1;
264                   values[0].data.d_status = GIMP_PDB_CANCEL;
265                   return;
266                 }
267               break;
268 
269             default:
270               break;
271             }
272 
273           if (! save_image (param[3].data.d_string,
274                             format->save_op,
275                             image_ID, drawable_ID,
276                             &error))
277             {
278               status = GIMP_PDB_EXECUTION_ERROR;
279             }
280 
281           if (export == GIMP_EXPORT_EXPORT)
282             gimp_image_delete (image_ID);
283 
284           break;
285         }
286     }
287 
288   if (i == G_N_ELEMENTS (file_formats))
289     status = GIMP_PDB_CALLING_ERROR;
290 
291   if (status != GIMP_PDB_SUCCESS && error)
292     {
293       *nreturn_vals = 2;
294       values[1].type           = GIMP_PDB_STRING;
295       values[1].data.d_string  = error->message;
296     }
297 
298   values[0].data.d_status = status;
299 
300   gegl_exit ();
301 }
302 
303 static gint32
load_image(const gchar * filename,const gchar * gegl_op,GError ** error)304 load_image (const gchar  *filename,
305             const gchar  *gegl_op,
306             GError      **error)
307 {
308   gint32             image_ID = -1;
309   gint32             layer_ID;
310   GimpImageType      image_type;
311   GimpImageBaseType  base_type;
312   GimpPrecision      precision;
313   gint               width;
314   gint               height;
315   GeglNode          *graph;
316   GeglNode          *sink;
317   GeglNode          *source;
318   GeglBuffer        *src_buf  = NULL;
319   GeglBuffer        *dest_buf = NULL;
320   const Babl        *format;
321 
322   gimp_progress_init_printf (_("Opening '%s'"),
323                              gimp_filename_to_utf8 (filename));
324 
325   graph = gegl_node_new ();
326 
327   source = gegl_node_new_child (graph,
328                                 "operation", gegl_op,
329                                 "path",      filename,
330                                 NULL);
331   sink = gegl_node_new_child (graph,
332                               "operation", "gegl:buffer-sink",
333                               "buffer",    &src_buf,
334                               NULL);
335 
336   gegl_node_connect_to (source, "output",
337                         sink,   "input");
338 
339   gegl_node_process (sink);
340 
341   g_object_unref (graph);
342 
343   if (! src_buf)
344     {
345       g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
346                    _("Could not open '%s'"),
347                    gimp_filename_to_utf8 (filename));
348       return -1;
349     }
350 
351   gimp_progress_update (0.33);
352 
353   width  = gegl_buffer_get_width (src_buf);
354   height = gegl_buffer_get_height (src_buf);
355   format = gegl_buffer_get_format (src_buf);
356 
357   if (babl_format_is_palette (format))
358     {
359       base_type = GIMP_INDEXED;
360 
361       if (babl_format_has_alpha (format))
362         image_type = GIMP_INDEXEDA_IMAGE;
363       else
364         image_type = GIMP_INDEXED_IMAGE;
365 
366       precision = GIMP_PRECISION_U8_GAMMA;
367     }
368   else
369     {
370       const Babl *model  = babl_format_get_model (format);
371       const Babl *type   = babl_format_get_type (format, 0);
372       gboolean    linear = TRUE;
373 
374       if (model == babl_model ("Y")  ||
375           model == babl_model ("Y'") ||
376           model == babl_model ("YA") ||
377           model == babl_model ("Y'A"))
378         {
379           base_type = GIMP_GRAY;
380 
381           if (babl_format_has_alpha (format))
382             image_type = GIMP_GRAYA_IMAGE;
383           else
384             image_type = GIMP_GRAY_IMAGE;
385 
386           if (model == babl_model ("Y'") ||
387               model == babl_model ("Y'A"))
388             linear = FALSE;
389         }
390       else
391         {
392           base_type = GIMP_RGB;
393 
394           if (babl_format_has_alpha (format))
395             image_type = GIMP_RGBA_IMAGE;
396           else
397             image_type = GIMP_RGB_IMAGE;
398 
399           if (model == babl_model ("R'G'B'") ||
400               model == babl_model ("R'G'B'A"))
401             linear = FALSE;
402         }
403 
404       if (linear)
405         {
406           if (type == babl_type ("u8"))
407             precision = GIMP_PRECISION_U8_LINEAR;
408           else if (type == babl_type ("u16"))
409             precision = GIMP_PRECISION_U16_LINEAR;
410           else if (type == babl_type ("u32"))
411             precision = GIMP_PRECISION_U32_LINEAR;
412           else if (type == babl_type ("half"))
413             precision = GIMP_PRECISION_HALF_LINEAR;
414           else
415             precision = GIMP_PRECISION_FLOAT_LINEAR;
416         }
417       else
418         {
419           if (type == babl_type ("u8"))
420             precision = GIMP_PRECISION_U8_GAMMA;
421           else if (type == babl_type ("u16"))
422             precision = GIMP_PRECISION_U16_GAMMA;
423           else if (type == babl_type ("u32"))
424             precision = GIMP_PRECISION_U32_GAMMA;
425           else if (type == babl_type ("half"))
426             precision = GIMP_PRECISION_HALF_GAMMA;
427           else
428             precision = GIMP_PRECISION_FLOAT_GAMMA;
429         }
430     }
431 
432 
433   image_ID = gimp_image_new_with_precision (width, height,
434                                             base_type, precision);
435   gimp_image_set_filename (image_ID, filename);
436 
437   layer_ID = gimp_layer_new (image_ID,
438                              _("Background"),
439                              width, height,
440                              image_type,
441                              100,
442                              gimp_image_get_default_new_layer_mode (image_ID));
443   gimp_image_insert_layer (image_ID, layer_ID, -1, 0);
444   dest_buf = gimp_drawable_get_buffer (layer_ID);
445 
446   gimp_progress_update (0.66);
447 
448   gegl_buffer_copy (src_buf, NULL, GEGL_ABYSS_NONE, dest_buf, NULL);
449 
450   g_object_unref (src_buf);
451   g_object_unref (dest_buf);
452 
453   gimp_progress_update (1.0);
454 
455   return image_ID;
456 }
457 
458 static gboolean
save_image(const gchar * filename,const gchar * gegl_op,gint32 image_ID,gint32 drawable_ID,GError ** error)459 save_image (const gchar  *filename,
460             const gchar  *gegl_op,
461             gint32        image_ID,
462             gint32        drawable_ID,
463             GError      **error)
464 {
465   GeglNode   *graph;
466   GeglNode   *source;
467   GeglNode   *sink;
468   GeglBuffer *src_buf;
469 
470   src_buf = gimp_drawable_get_buffer (drawable_ID);
471 
472   graph = gegl_node_new ();
473 
474   source = gegl_node_new_child (graph,
475                                 "operation", "gegl:buffer-source",
476                                 "buffer",    src_buf,
477                                 NULL);
478   sink = gegl_node_new_child (graph,
479                               "operation", gegl_op,
480                               "path",      filename,
481                               NULL);
482 
483   gegl_node_connect_to (source, "output",
484                         sink,   "input");
485 
486   gegl_node_process (sink);
487 
488   g_object_unref (graph);
489   g_object_unref (src_buf);
490 
491   return TRUE;
492 }
493