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