1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * file-rawtherapee.c -- raw file format plug-in that uses RawTherapee
5 * Copyright (C) 2012 Simon Budig <simon@gimp.org>
6 * Copyright (C) 2016 Tobias Ellinghaus <me@houz.org>
7 * Copyright (C) 2017 Alberto Griggio <alberto.griggio@gmail.com>
8 *
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
23 #include "config.h"
24
25 #include <stdlib.h>
26 #include <errno.h>
27
28 #include <glib/gstdio.h>
29
30 #include <libgimp/gimp.h>
31
32 #include "libgimp/stdplugins-intl.h"
33
34 #include "file-formats.h"
35
36
37 #define LOAD_THUMB_PROC "file-rawtherapee-load-thumb"
38
39
40 static void init (void);
41 static void query (void);
42 static void run (const gchar *name,
43 gint nparams,
44 const GimpParam *param,
45 gint *nreturn_vals,
46 GimpParam **return_vals);
47 static gint32 load_image (const gchar *filename,
48 GimpRunMode run_mode,
49 GError **error);
50
51 static gint32 load_thumbnail_image (const gchar *filename,
52 gint thumb_size,
53 GError **error);
54
55 const GimpPlugInInfo PLUG_IN_INFO =
56 {
57 init, /* init_proc */
58 NULL, /* quit_proc */
59 query, /* query proc */
60 run, /* run_proc */
61 };
62
MAIN()63 MAIN ()
64
65
66 static void
67 init (void)
68 {
69 static const GimpParamDef load_args[] =
70 {
71 { GIMP_PDB_INT32, "run-mode", "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
72 { GIMP_PDB_STRING, "filename", "The name of the file to load." },
73 { GIMP_PDB_STRING, "raw-filename", "The name entered" },
74 };
75
76 static const GimpParamDef load_return_vals[] =
77 {
78 { GIMP_PDB_IMAGE, "image", "Output image" }
79 };
80
81 static const GimpParamDef thumb_args[] =
82 {
83 { GIMP_PDB_STRING, "filename", "The name of the file to load" },
84 { GIMP_PDB_INT32, "thumb-size", "Preferred thumbnail size" }
85 };
86
87 static const GimpParamDef thumb_return_vals[] =
88 {
89 { GIMP_PDB_IMAGE, "image", "Thumbnail image" }
90 };
91
92 /* check if rawtherapee is installed
93 * TODO: allow setting the location of the executable in preferences
94 */
95 gchar *argv[] = { "rawtherapee", "-v", NULL };
96 gchar *rawtherapee_stdout = NULL;
97 gboolean have_rawtherapee = FALSE;
98 gint i;
99
100 if (g_spawn_sync (NULL,
101 argv,
102 NULL,
103 G_SPAWN_STDERR_TO_DEV_NULL |
104 G_SPAWN_SEARCH_PATH,
105 NULL,
106 NULL,
107 &rawtherapee_stdout,
108 NULL,
109 NULL,
110 NULL))
111 {
112 int rtmajor = 0, rtminor = 0;
113
114 if (sscanf (rawtherapee_stdout,
115 "RawTherapee, version %d.%d",
116 &rtmajor, &rtminor) == 2 && rtmajor >= 5 && rtminor >= 2)
117 {
118 have_rawtherapee = TRUE;
119 }
120
121 g_free (rawtherapee_stdout);
122 }
123
124 if (! have_rawtherapee)
125 return;
126
127 gimp_install_procedure (LOAD_THUMB_PROC,
128 "Load thumbnail from a raw image via rawtherapee",
129 "This plug-in loads a thumbnail from a raw image by calling rawtherapee-cli.",
130 "Alberto Griggio",
131 "Alberto Griggio",
132 "2017",
133 NULL,
134 NULL,
135 GIMP_PLUGIN,
136 G_N_ELEMENTS (thumb_args),
137 G_N_ELEMENTS (thumb_return_vals),
138 thumb_args, thumb_return_vals);
139
140 for (i = 0; i < G_N_ELEMENTS (file_formats); i++)
141 {
142 const FileFormat *format = &file_formats[i];
143
144 gimp_install_procedure (format->load_proc,
145 format->load_blurb,
146 format->load_help,
147 "Alberto Griggio",
148 "Alberto Griggio",
149 "2017",
150 format->file_type,
151 NULL,
152 GIMP_PLUGIN,
153 G_N_ELEMENTS (load_args),
154 G_N_ELEMENTS (load_return_vals),
155 load_args, load_return_vals);
156
157 gimp_register_file_handler_mime (format->load_proc,
158 format->mime_type);
159 gimp_register_file_handler_raw (format->load_proc);
160 gimp_register_magic_load_handler (format->load_proc,
161 format->extensions,
162 "",
163 format->magic);
164
165 gimp_register_thumbnail_loader (format->load_proc, LOAD_THUMB_PROC);
166 }
167 }
168
169 static void
query(void)170 query (void)
171 {
172 /* query() is run only the first time for efficiency. Yet this plugin
173 * is dependent on the presence of rawtherapee which may be installed
174 * or uninstalled between GIMP startups. Therefore we should move the
175 * usual gimp_install_procedure() to init() so that the check is done
176 * at every startup instead.
177 */
178 }
179
180 static void
run(const gchar * name,gint nparams,const GimpParam * param,gint * nreturn_vals,GimpParam ** return_vals)181 run (const gchar *name,
182 gint nparams,
183 const GimpParam *param,
184 gint *nreturn_vals,
185 GimpParam **return_vals)
186 {
187 static GimpParam values[6];
188 GimpPDBStatusType status = GIMP_PDB_SUCCESS;
189 GimpRunMode run_mode;
190 gint image_ID;
191 GError *error = NULL;
192 gint i;
193
194 INIT_I18N ();
195
196 run_mode = param[0].data.d_int32;
197
198 *nreturn_vals = 1;
199 *return_vals = values;
200
201 values[0].type = GIMP_PDB_STATUS;
202 values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
203
204 /* check if the format passed is actually supported & load */
205 for (i = 0; i < G_N_ELEMENTS (file_formats); i++)
206 {
207 const FileFormat *format = &file_formats[i];
208
209 if (format->load_proc && ! strcmp (name, format->load_proc))
210 {
211 image_ID = load_image (param[1].data.d_string, run_mode, &error);
212
213 if (image_ID != -1)
214 {
215 *nreturn_vals = 2;
216 values[1].type = GIMP_PDB_IMAGE;
217 values[1].data.d_image = image_ID;
218 }
219 else
220 {
221 status = GIMP_PDB_EXECUTION_ERROR;
222 }
223
224 break;
225 }
226 else if (! strcmp (name, LOAD_THUMB_PROC))
227 {
228 image_ID = load_thumbnail_image (param[0].data.d_string,
229 param[1].data.d_int32,
230 &error);
231
232 if (image_ID != -1)
233 {
234 *nreturn_vals = 4;
235 values[1].type = GIMP_PDB_IMAGE;
236 values[1].data.d_image = image_ID;
237 values[4].type = GIMP_PDB_INT32;
238 values[4].data.d_int32 = GIMP_RGB_IMAGE;
239 values[5].type = GIMP_PDB_INT32;
240 values[5].data.d_int32 = 1; /* num_layers */
241 }
242 else
243 {
244 status = GIMP_PDB_EXECUTION_ERROR;
245 }
246
247 break;
248 }
249 }
250
251 if (i == G_N_ELEMENTS (file_formats))
252 status = GIMP_PDB_CALLING_ERROR;
253
254 if (status != GIMP_PDB_SUCCESS && error)
255 {
256 *nreturn_vals = 2;
257 values[1].type = GIMP_PDB_STRING;
258 values[1].data.d_string = error->message;
259 }
260
261 values[0].data.d_status = status;
262 }
263
264 static gint32
load_image(const gchar * filename,GimpRunMode run_mode,GError ** error)265 load_image (const gchar *filename,
266 GimpRunMode run_mode,
267 GError **error)
268 {
269 gint32 image_ID = -1;
270 gchar *filename_out = gimp_temp_name ("tif");
271
272 gchar *rawtherapee_stdout = NULL;
273
274 /* linear sRGB for now as GIMP uses that internally in many places anyway */
275 gchar *argv[] =
276 {
277 "rawtherapee",
278 "-gimp",
279 (gchar *) filename,
280 filename_out,
281 NULL
282 };
283
284 gimp_progress_init_printf (_("Opening '%s'"),
285 gimp_filename_to_utf8 (filename));
286
287 if (g_spawn_sync (NULL,
288 argv,
289 NULL,
290 /*G_SPAWN_STDOUT_TO_DEV_NULL |*/
291 G_SPAWN_STDERR_TO_DEV_NULL |
292 G_SPAWN_SEARCH_PATH,
293 NULL,
294 NULL,
295 &rawtherapee_stdout,
296 NULL,
297 NULL,
298 error))
299 {
300 image_ID = gimp_file_load (run_mode, filename_out, filename_out);
301 if (image_ID != -1)
302 gimp_image_set_filename (image_ID, filename);
303 }
304
305 /*if (rawtherapee_stdout) printf ("%s\n", rawtherapee_stdout);*/
306 g_free (rawtherapee_stdout);
307
308 g_unlink (filename_out);
309 g_free (filename_out);
310
311 gimp_progress_update (1.0);
312
313 return image_ID;
314 }
315
316 static gint32
load_thumbnail_image(const gchar * filename,gint thumb_size,GError ** error)317 load_thumbnail_image (const gchar *filename,
318 gint thumb_size,
319 GError **error)
320 {
321 gint32 image_ID = -1;
322 gchar *filename_out = gimp_temp_name ("jpg");
323 gchar *thumb_pp3 = gimp_temp_name ("pp3");
324 FILE *thumb_pp3_f = fopen (thumb_pp3, "w");
325 gchar *rawtherapee_stdout = NULL;
326 const char *pp3_content =
327 "[Version]\n"
328 "AppVersion=5.0\n"
329 "Version=326\n"
330 "\n"
331 "[Resize]\n"
332 "Enabled=true\n"
333 "AppliesTo=Cropped area\n"
334 "Method=Lanczos\n"
335 "Width=%d\n"
336 "Height=%d\n"
337 "\n"
338 "[Sharpening]\n"
339 "Enabled=false\n"
340 "\n"
341 "[SharpenEdge]\n"
342 "Enabled=false\n"
343 "\n"
344 "[SharpenMicro]\n"
345 "Enabled=false\n"
346 "\n"
347 "[Defringing]\n"
348 "Enabled=false\n"
349 "\n"
350 "[Directional Pyramid Equalizer]\n"
351 "Enabled=false\n"
352 "\n"
353 "[PostResizeSharpening]\n"
354 "Enabled=false\n"
355 "\n"
356 "[Directional Pyramid Denoising]\n"
357 "Enabled=false\n"
358 "\n"
359 "[Impulse Denoising]\n"
360 "Enabled=false\n"
361 "\n"
362 "[Wavelet]\n"
363 "Enabled=false\n"
364 "\n"
365 "[RAW Bayer]\n"
366 "Method=fast\n"
367 "\n"
368 "[RAW X-Trans]\n"
369 "Method=fast\n";
370
371
372 gchar *argv[] =
373 {
374 "rawtherapee-cli",
375 "-o", filename_out,
376 "-d",
377 "-s",
378 "-j",
379 "-p", thumb_pp3,
380 "-f",
381 "-c", (char *) filename,
382 NULL
383 };
384
385 if (thumb_pp3_f) {
386 if (fprintf (thumb_pp3_f, pp3_content, thumb_size, thumb_size) < 0) {
387 fclose (thumb_pp3_f);
388 thumb_pp3_f = NULL;
389 }
390 }
391
392 gimp_progress_init_printf (_("Opening thumbnail for '%s'"),
393 gimp_filename_to_utf8 (filename));
394
395 if (thumb_pp3_f &&
396 g_spawn_sync (NULL,
397 argv,
398 NULL,
399 G_SPAWN_STDERR_TO_DEV_NULL |
400 G_SPAWN_SEARCH_PATH,
401 NULL,
402 NULL,
403 &rawtherapee_stdout,
404 NULL,
405 NULL,
406 error))
407 {
408 gimp_progress_update (0.5);
409
410 image_ID = gimp_file_load (GIMP_RUN_NONINTERACTIVE,
411 filename_out,
412 filename_out);
413 if (image_ID != -1)
414 {
415 /* is this needed for thumbnails? */
416 gimp_image_set_filename (image_ID, filename);
417 }
418 }
419
420 gimp_progress_update (1.0);
421
422 if (thumb_pp3_f) {
423 fclose (thumb_pp3_f);
424 }
425 g_unlink (thumb_pp3);
426 g_free (filename_out);
427 g_free (thumb_pp3);
428 g_free (rawtherapee_stdout);
429
430 return image_ID;
431 }
432