1 /*
2  * UFRaw - Unidentified Flying Raw converter for digital camera images
3  *
4  * ufraw-gimp.c - The GIMP plug-in.
5  * Copyright 2004-2016 by Udi Fuchs
6  *
7  * based on the GIMP plug-in by Pawel T. Jochym jochym at ifj edu pl,
8  *
9  * based on the GIMP plug-in by Dave Coffin
10  * http://www.cybercom.net/~dcoffin/
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  */
17 
18 #include "ufraw.h"
19 #include "uf_gtk.h"
20 #if HAVE_GIMP_2_9
21 #include <gegl.h>
22 #endif
23 #include <libgimpbase/gimpbase.h>
24 #include <libgimp/gimp.h>
25 #include <libgimp/gimpui.h>
26 #include <glib/gi18n.h>
27 #include <string.h>
28 
29 void query();
30 void run(const gchar *name,
31          gint nparams,
32          const GimpParam *param,
33          gint *nreturn_vals,
34          GimpParam **return_vals);
35 
36 long ufraw_save_gimp_image(ufraw_data *uf, GtkWidget *widget);
37 
38 GimpPlugInInfo PLUG_IN_INFO = {
39     NULL,  /* init_procedure */
40     NULL,  /* quit_procedure */
41     query, /* query_procedure */
42     run,   /* run_procedure */
43 };
44 
MAIN()45 MAIN()
46 
47 void query()
48 {
49     static const GimpParamDef load_args[] = {
50         { GIMP_PDB_INT32,  "run_mode", "Interactive, non-interactive" },
51         { GIMP_PDB_STRING, "filename", "The name of the file to load" },
52         { GIMP_PDB_STRING, "raw_filename", "The name of the file to load" },
53     };
54     static const GimpParamDef load_return_vals[] = {
55         { GIMP_PDB_IMAGE, "image", "Output image" },
56     };
57     static const GimpParamDef thumb_args[] = {
58         { GIMP_PDB_STRING, "filename",     "The name of the file to load" },
59         { GIMP_PDB_INT32,  "thumb_size",   "Preferred thumbnail size" }
60     };
61     static const GimpParamDef thumb_return_vals[] = {
62         { GIMP_PDB_IMAGE,  "image",        "Thumbnail image" },
63         { GIMP_PDB_INT32,  "image_width",  "Width of full-sized image" },
64         { GIMP_PDB_INT32,  "image_height", "Height of full-sized image" }
65     };
66     gimp_install_procedure("file_ufraw_load",
67                            "Loads digital camera raw files",
68                            "Loads digital camera raw files.",
69                            "Udi Fuchs",
70                            "Copyright 2003 by Dave Coffin\n"
71                            "Copyright 2004 by Pawel Jochym\n"
72                            "Copyright 2004-2016 by Udi Fuchs",
73                            "ufraw-" VERSION,
74                            "raw image",
75                            NULL,
76                            GIMP_PLUGIN,
77                            G_N_ELEMENTS(load_args),
78                            G_N_ELEMENTS(load_return_vals),
79                            load_args,
80                            load_return_vals);
81 
82 #if HAVE_GIMP_2_9
83     gimp_register_magic_load_handler("file_ufraw_load",
84                                      (char *)raw_ext,
85                                      "",
86                                      "0,string,II*\\0,"
87                                      "0,string,MM\\0*,"
88                                      "0,string,<?xml");
89 #else
90     gimp_register_load_handler("file_ufraw_load", (char *)raw_ext, "");
91 #endif
92 
93     gimp_install_procedure("file_ufraw_load_thumb",
94                            "Loads thumbnails from digital camera raw files.",
95                            "Loads thumbnails from digital camera raw files.",
96                            "Udi Fuchs",
97                            "Copyright 2004-2016 by Udi Fuchs",
98                            "ufraw-" VERSION,
99                            NULL,
100                            NULL,
101                            GIMP_PLUGIN,
102                            G_N_ELEMENTS(thumb_args),
103                            G_N_ELEMENTS(thumb_return_vals),
104                            thumb_args, thumb_return_vals);
105 
106     gimp_register_thumbnail_loader("file_ufraw_load",
107                                    "file_ufraw_load_thumb");
108 }
109 
110 char *ufraw_binary;
111 gboolean sendToGimpMode;
112 
run(const gchar * name,gint nparams,const GimpParam * param,gint * nreturn_vals,GimpParam ** return_vals)113 void run(const gchar *name,
114          gint nparams,
115          const GimpParam *param,
116          gint *nreturn_vals,
117          GimpParam **return_vals)
118 {
119     // TODO: Check if the static variable here is really needed.
120     // In any case this should cause no issues with threads.
121     static GimpParam values[4];
122     GimpRunMode run_mode;
123     char *filename;
124     int size;
125     ufraw_data *uf;
126     conf_data rc;
127     int status;
128 
129 #if !GLIB_CHECK_VERSION(2,31,0)
130     g_thread_init(NULL);
131 #endif
132 #ifndef _WIN32
133     gdk_threads_init();
134     gdk_threads_enter();
135 #endif
136     ufraw_binary = g_path_get_basename(gimp_get_progname());
137     uf_init_locale(gimp_get_progname());
138 #if HAVE_GIMP_2_9
139     gegl_init(NULL, NULL);
140 #endif
141 
142     *nreturn_vals = 1;
143     *return_vals = values;
144 
145     if (!strcmp(name, "file_ufraw_load_thumb")) {
146         run_mode = 0;
147         filename = param[0].data.d_string;
148         size = param[1].data.d_int32;
149     } else if (!strcmp(name, "file_ufraw_load")) {
150         run_mode = (GimpRunMode)param[0].data.d_int32;
151         filename = param[1].data.d_string;
152         size = 0;
153     } else {
154         values[0].type = GIMP_PDB_STATUS;
155         values[0].data.d_status = GIMP_PDB_CALLING_ERROR;
156 #ifndef _WIN32
157         gdk_threads_leave();
158 #endif
159         return;
160     }
161     gboolean loadThumbnail = size > 0;
162     char *gtkrcfile = g_build_filename(uf_get_home_dir(),
163                                        ".ufraw-gtkrc", NULL);
164     gtk_rc_add_default_file(gtkrcfile);
165     g_free(gtkrcfile);
166     gimp_ui_init("ufraw-gimp", TRUE);
167 
168     uf = ufraw_open(filename);
169     /* if UFRaw fails on jpg/jpeg or tif/tiff then open with GIMP */
170     if (uf == NULL) {
171         if (!strcasecmp(filename + strlen(filename) - 4, ".jpg") ||
172                 !strcasecmp(filename + strlen(filename) - 5, ".jpeg")) {
173             if (loadThumbnail)
174                 *return_vals = gimp_run_procedure2("file_jpeg_load_thumb",
175                                                    nreturn_vals, nparams, param);
176             else
177                 *return_vals = gimp_run_procedure2("file_jpeg_load",
178                                                    nreturn_vals, nparams, param);
179 #ifndef _WIN32
180             gdk_threads_leave();
181 #endif
182             return;
183         } else if (!strcasecmp(filename + strlen(filename) - 4, ".tif") ||
184                    !strcasecmp(filename + strlen(filename) - 5, ".tiff")) {
185             if (!loadThumbnail)
186                 *return_vals = gimp_run_procedure2("file_tiff_load",
187                                                    nreturn_vals, nparams, param);
188             else {
189                 /* There is no "file_tiff_load_thumb".
190                  * The call to "file_ufraw_load" will handle the thumbnail */
191                 /* Following is another solution for tiff thumbnails
192                 GimpParam tiffParam[3];
193                 tiffParam[0].type = GIMP_PDB_INT32;
194                 tiffParam[0].data.d_int32 = GIMP_RUN_NONINTERACTIVE;
195                 tiffParam[1].type = GIMP_PDB_STRING;
196                 tiffParam[1].data.d_string = filename;
197                 tiffParam[2].type = GIMP_PDB_STRING;
198                 tiffParam[2].data.d_string = filename;
199                 *return_vals = gimp_run_procedure2 ("file_tiff_load",
200                     	nreturn_vals, 3, tiffParam);
201                 */
202             }
203 #ifndef _WIN32
204             gdk_threads_leave();
205 #endif
206             return;
207         } else {
208             /* Don't issue a message on thumbnail failure, since ufraw-gimp
209              * will be called again with "file_ufraw_load" */
210             if (loadThumbnail) {
211 #ifndef _WIN32
212                 gdk_threads_leave();
213 #endif
214                 return;
215             }
216             ufraw_icons_init();
217             GtkWidget *dummyWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
218             gtk_window_set_icon_name(GTK_WINDOW(dummyWindow), "ufraw");
219             ufraw_message(UFRAW_SET_PARENT, (char *)dummyWindow);
220 
221             ufraw_message(UFRAW_REPORT, NULL);
222             values[0].type = GIMP_PDB_STATUS;
223             /* With GIMP_PDB_CANCEL, Gimp won't issue a warning */
224             values[0].data.d_status = GIMP_PDB_CANCEL;
225 
226             gtk_widget_destroy(dummyWindow);
227 #ifndef _WIN32
228             gdk_threads_leave();
229 #endif
230             return;
231         }
232     }
233     /* Load $HOME/.ufrawrc */
234     conf_load(&rc, NULL);
235 
236     ufraw_config(uf, &rc, NULL, NULL);
237     sendToGimpMode = (uf->conf->createID == send_id);
238 #if !HAVE_GIMP_2_9
239     if (loadThumbnail) {
240         uf->conf->size = size;
241         uf->conf->embeddedImage = TRUE;
242     }
243 #else
244     if (run_mode == GIMP_RUN_NONINTERACTIVE) uf->conf->shrink = 8;
245 #endif
246     /* UFRaw already issues warnings.
247      * With GIMP_PDB_CANCEL, Gimp won't issue another one. */
248     values[0].type = GIMP_PDB_STATUS;
249     values[0].data.d_status = GIMP_PDB_CANCEL;
250     /* BUG - what should be done with GIMP_RUN_WITH_LAST_VALS */
251     if (run_mode == GIMP_RUN_INTERACTIVE &&
252             !loadThumbnail && !sendToGimpMode) {
253         /* Show the preview in interactive mode, unless if we are
254          * in thumbnail mode or 'send to gimp' mode. */
255         status = ufraw_preview(uf, &rc, ufraw_gimp_plugin, ufraw_save_gimp_image);
256     } else {
257         if (sendToGimpMode) {
258             char *text = g_strdup_printf(_("Loading raw file '%s'"),
259                                          uf->filename);
260             gimp_progress_init(text);
261             g_free(text);
262         }
263         if (sendToGimpMode) gimp_progress_update(0.1);
264         status = ufraw_load_raw(uf);
265         if (status != UFRAW_SUCCESS) {
266             values[0].type = GIMP_PDB_STATUS;
267             values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
268 #ifndef _WIN32
269             gdk_threads_leave();
270 #endif
271             return;
272         }
273         if (sendToGimpMode) gimp_progress_update(0.3);
274         ufraw_save_gimp_image(uf, NULL);
275         if (sendToGimpMode) gimp_progress_update(1.0);
276         ufraw_close_darkframe(uf->conf);
277         ufraw_close(uf);
278         /* To make sure we don't delete the raw file by mistake we check
279          * that the file is really an ID file. */
280         if (sendToGimpMode &&
281                 strcasecmp(filename + strlen(filename) - 6, ".ufraw") == 0)
282             g_unlink(filename);
283     }
284     if (status != UFRAW_SUCCESS || uf->gimpImage == -1) {
285         values[0].type = GIMP_PDB_STATUS;
286         if (status == UFRAW_CANCEL)
287             values[0].data.d_status = GIMP_PDB_CANCEL;
288         else
289             values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
290 #ifndef _WIN32
291         gdk_threads_leave();
292 #endif
293         return;
294     }
295     *nreturn_vals = 2;
296     values[0].type = GIMP_PDB_STATUS;
297     values[0].data.d_status = GIMP_PDB_SUCCESS;
298     values[1].type = GIMP_PDB_IMAGE;
299     values[1].data.d_image = uf->gimpImage;
300     if (loadThumbnail) {
301         *nreturn_vals = 4;
302         values[2].type = GIMP_PDB_INT32;
303         values[2].data.d_int32 = uf->initialWidth;
304         values[3].type = GIMP_PDB_INT32;
305         values[3].data.d_int32 = uf->initialHeight;
306     }
307 #ifndef _WIN32
308     gdk_threads_leave();
309 #endif
310     return;
311 }
312 
gimp_row_writer(ufraw_data * uf,void * volatile out,void * pixbuf,int row,int width,int height,int grayscale,int bitDepth)313 int gimp_row_writer(ufraw_data *uf, void *volatile out, void *pixbuf,
314                     int row, int width, int height, int grayscale, int bitDepth)
315 {
316     (void)uf;
317     (void)grayscale;
318     (void)bitDepth;
319 
320 #if HAVE_GIMP_2_9
321     gegl_buffer_set(out, GEGL_RECTANGLE(0, row, width, height),
322                     0, NULL, pixbuf,
323                     GEGL_AUTO_ROWSTRIDE);
324 #else
325     gimp_pixel_rgn_set_rect(out, pixbuf, 0, row, width, height);
326 #endif
327 
328     return UFRAW_SUCCESS;
329 }
330 
ufraw_save_gimp_image(ufraw_data * uf,GtkWidget * widget)331 long ufraw_save_gimp_image(ufraw_data *uf, GtkWidget *widget)
332 {
333 #if HAVE_GIMP_2_9
334     GeglBuffer *buffer;
335 #else
336     GimpDrawable *drawable;
337     GimpPixelRgn pixel_region;
338     int tile_height, row, nrows;
339 #endif
340     gint32 layer;
341     UFRectangle Crop;
342     int depth;
343     (void)widget;
344 
345     uf->gimpImage = -1;
346 
347     if (uf->conf->embeddedImage) {
348         if (ufraw_convert_embedded(uf) != UFRAW_SUCCESS)
349             return UFRAW_ERROR;
350         Crop.height = uf->thumb.height;
351         Crop.width = uf->thumb.width;
352         Crop.y = 0;
353         Crop.x = 0;
354         depth = 3;
355     } else {
356         if (ufraw_convert_image(uf) != UFRAW_SUCCESS)
357             return UFRAW_ERROR;
358         ufraw_get_scaled_crop(uf, &Crop);
359 #if HAVE_GIMP_2_9
360         if (uf->conf->profile[out_profile]
361                 [uf->conf->profileIndex[out_profile]].BitDepth == 16)
362             depth = 6;
363         else
364             depth = 3;
365 #else
366         depth = 3;
367 #endif
368     }
369 #if HAVE_GIMP_2_9
370     uf->gimpImage =
371         gimp_image_new_with_precision(Crop.width, Crop.height, GIMP_RGB,
372                                       depth == 3 ? GIMP_PRECISION_U8_GAMMA :
373                                       GIMP_PRECISION_U16_GAMMA);
374 #else
375     uf->gimpImage = gimp_image_new(Crop.width, Crop.height, GIMP_RGB);
376 #endif
377     if (uf->gimpImage == -1) {
378         ufraw_message(UFRAW_ERROR, _("Can't allocate new image."));
379         return UFRAW_ERROR;
380     }
381     gimp_image_set_filename(uf->gimpImage, uf->filename);
382 
383     /* Create the "background" layer to hold the image... */
384     layer = gimp_layer_new(uf->gimpImage, _("Background"), Crop.width,
385                            Crop.height, GIMP_RGB_IMAGE, 100.0,
386                            GIMP_NORMAL_MODE);
387 #if defined(GIMP_CHECK_VERSION) && GIMP_CHECK_VERSION(2,7,3)
388     gimp_image_insert_layer(uf->gimpImage, layer, 0, 0);
389 #else
390     gimp_image_add_layer(uf->gimpImage, layer, 0);
391 #endif
392 
393     /* Get the drawable and set the pixel region for our load... */
394 #if HAVE_GIMP_2_9
395     buffer = gimp_drawable_get_buffer(layer);
396 #else
397     drawable = gimp_drawable_get(layer);
398     gimp_pixel_rgn_init(&pixel_region, drawable, 0, 0, drawable->width,
399                         drawable->height, TRUE, FALSE);
400     tile_height = gimp_tile_height();
401 #endif
402 
403     if (uf->conf->embeddedImage) {
404 #if HAVE_GIMP_2_9
405         gegl_buffer_set(buffer,
406                         GEGL_RECTANGLE(0, 0, Crop.width, Crop.height),
407                         0, NULL, uf->thumb.buffer,
408                         GEGL_AUTO_ROWSTRIDE);
409 #else
410         for (row = 0; row < Crop.height; row += tile_height) {
411             nrows = MIN(Crop.height - row, tile_height);
412             gimp_pixel_rgn_set_rect(&pixel_region,
413                                     uf->thumb.buffer + 3 * row * Crop.width, 0, row, Crop.width, nrows);
414         }
415 #endif
416     } else {
417 #if HAVE_GIMP_2_9
418         ufraw_write_image_data(uf, buffer, &Crop, depth == 3 ? 8 : 16, 0,
419                                gimp_row_writer);
420 #else
421         ufraw_write_image_data(uf, &pixel_region, &Crop, depth == 3 ? 8 : 16, 0,
422                                gimp_row_writer);
423 #endif
424     }
425 #if HAVE_GIMP_2_9
426     gegl_buffer_flush(buffer);
427 #else
428     gimp_drawable_flush(drawable);
429     gimp_drawable_detach(drawable);
430 #endif
431 
432     if (uf->conf->embeddedImage) return UFRAW_SUCCESS;
433 
434     ufraw_exif_prepare_output(uf);
435     if (uf->outputExifBuf != NULL) {
436         if (uf->outputExifBufLen > 65533) {
437             ufraw_message(UFRAW_SET_WARNING,
438                           _("EXIF buffer length %d, too long, ignored."),
439                           uf->outputExifBufLen);
440         } else {
441 #if HAVE_GIMP_2_9
442             GimpMetadata *metadata;
443             metadata = gimp_metadata_new();
444             if (gimp_metadata_set_from_exif(metadata,
445                                             uf->outputExifBuf,
446                                             uf->outputExifBufLen,
447                                             NULL)) {
448                 gimp_image_set_metadata(uf->gimpImage, metadata);
449             }
450             g_object_unref(metadata);
451 #else // !HAVE_GIMP_2_9
452             GimpParasite *exif_parasite;
453 
454             exif_parasite = gimp_parasite_new("exif-data",
455                                               GIMP_PARASITE_PERSISTENT, uf->outputExifBufLen, uf->outputExifBuf);
456 #if defined(GIMP_CHECK_VERSION) && GIMP_CHECK_VERSION(2,8,0)
457             gimp_image_attach_parasite(uf->gimpImage, exif_parasite);
458 #else
459             gimp_image_parasite_attach(uf->gimpImage, exif_parasite);
460 #endif
461             gimp_parasite_free(exif_parasite);
462 
463 #if defined(GIMP_CHECK_VERSION) && GIMP_CHECK_VERSION(2,8,0)
464             {
465                 GimpParam    *return_vals;
466                 gint          nreturn_vals;
467                 return_vals = gimp_run_procedure("plug-in-metadata-decode-exif",
468                                                  &nreturn_vals,
469                                                  GIMP_PDB_IMAGE, uf->gimpImage,
470                                                  GIMP_PDB_INT32, 7,
471                                                  GIMP_PDB_INT8ARRAY, "unused",
472                                                  GIMP_PDB_END);
473                 if (return_vals[0].data.d_status != GIMP_PDB_SUCCESS) {
474                     g_warning("UFRaw Exif -> XMP Merge failed");
475                 }
476             }
477 #endif
478 #endif // HAVE_GIMP_2_9
479         }
480     }
481     /* Create "icc-profile" parasite from output profile
482      * if it is not the internal sRGB.*/
483     if (strcmp(uf->developer->profileFile[out_profile], "")) {
484         char *buf;
485         gsize len;
486         if (g_file_get_contents(uf->developer->profileFile[out_profile],
487                                 &buf, &len, NULL)) {
488             GimpParasite *icc_parasite;
489             icc_parasite = gimp_parasite_new("icc-profile",
490                                              GIMP_PARASITE_PERSISTENT, len, buf);
491 #if defined(GIMP_CHECK_VERSION) && GIMP_CHECK_VERSION(2,8,0)
492             gimp_image_attach_parasite(uf->gimpImage, icc_parasite);
493 #else
494             gimp_image_parasite_attach(uf->gimpImage, icc_parasite);
495 #endif
496             gimp_parasite_free(icc_parasite);
497             g_free(buf);
498         } else {
499             ufraw_message(UFRAW_WARNING,
500                           _("Failed to embed output profile '%s' in image."),
501                           uf->developer->profileFile[out_profile]);
502         }
503     }
504     return UFRAW_SUCCESS;
505 }
506