1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /*
4 * GThumb
5 *
6 * Copyright (C) 2009 Free Software Foundation, Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22
23 #include <config.h>
24 #include <glib.h>
25 #include <gthumb.h>
26 #include <cairo.h>
27 #include <gtk/gtk.h>
28 #include <libraw.h>
29 #include "main.h"
30 #include "gth-metadata-provider-raw.h"
31
32
33 typedef enum {
34 RAW_OUTPUT_COLOR_RAW = 0,
35 RAW_OUTPUT_COLOR_SRGB = 1,
36 RAW_OUTPUT_COLOR_ADOBE = 2,
37 RAW_OUTPUT_COLOR_WIDE = 3,
38 RAW_OUTPUT_COLOR_PROPHOTO = 4,
39 RAW_OUTPUT_COLOR_XYZ = 5
40 } RawOutputColor;
41
42
43 static void
_libraw_set_gerror(GError ** error,int error_code)44 _libraw_set_gerror (GError **error,
45 int error_code)
46 {
47 g_set_error_literal (error,
48 G_IO_ERROR,
49 G_IO_ERROR_FAILED,
50 libraw_strerror (error_code));
51 }
52
53
54 static GthImage *
_libraw_read_jpeg_data(void * buffer,gsize buffer_size,int requested_size,GCancellable * cancellable,GError ** error)55 _libraw_read_jpeg_data (void *buffer,
56 gsize buffer_size,
57 int requested_size,
58 GCancellable *cancellable,
59 GError **error)
60 {
61 GthImageLoaderFunc loader_func;
62 GInputStream *istream;
63 GthImage *image;
64
65 loader_func = gth_main_get_image_loader_func ("image/jpeg", GTH_IMAGE_FORMAT_CAIRO_SURFACE);
66 if (loader_func == NULL)
67 return NULL;
68
69 istream = g_memory_input_stream_new_from_data (buffer, buffer_size, NULL);
70 if (istream == NULL)
71 return NULL;
72
73 image = loader_func (istream,
74 NULL,
75 requested_size,
76 NULL,
77 NULL,
78 NULL,
79 NULL,
80 cancellable,
81 error);
82
83 g_object_unref (istream);
84
85 return image;
86 }
87
88
89 static cairo_surface_t *
_cairo_surface_create_from_ppm(int width,int height,int colors,int bits,guchar * buffer,gsize buffer_size)90 _cairo_surface_create_from_ppm (int width,
91 int height,
92 int colors,
93 int bits,
94 guchar *buffer,
95 gsize buffer_size)
96 {
97 cairo_surface_t *surface;
98 int stride;
99 guchar *buffer_p;
100 int r, c;
101 guchar *row;
102 guchar *column;
103 guint32 pixel;
104
105 if (bits != 8)
106 return NULL;
107
108 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
109 stride = cairo_image_surface_get_stride (surface);
110
111 buffer_p = buffer;
112 row = _cairo_image_surface_flush_and_get_data (surface);
113 for (r = 0; r < height; r++) {
114 column = row;
115 for (c = 0; c < width; c++) {
116 switch (colors) {
117 case 4:
118 pixel = CAIRO_RGBA_TO_UINT32 (buffer_p[0], buffer_p[1], buffer_p[2], buffer_p[3]);
119 break;
120 case 3:
121 pixel = CAIRO_RGBA_TO_UINT32 (buffer_p[0], buffer_p[1], buffer_p[2], 0xff);
122 break;
123 case 1:
124 pixel = CAIRO_RGBA_TO_UINT32 (buffer_p[0], buffer_p[0], buffer_p[0], 0xff);
125 break;
126 default:
127 g_assert_not_reached ();
128 }
129
130 memcpy (column, &pixel, sizeof (guint32));
131
132 column += 4;
133 buffer_p += colors;
134 }
135 row += stride;
136 }
137
138 cairo_surface_mark_dirty (surface);
139
140 return surface;
141 }
142
143
144 static GthImage *
_libraw_read_bitmap_data(int width,int height,int colors,int bits,guchar * buffer,gsize buffer_size)145 _libraw_read_bitmap_data (int width,
146 int height,
147 int colors,
148 int bits,
149 guchar *buffer,
150 gsize buffer_size)
151 {
152 GthImage *image = NULL;
153 cairo_surface_t *surface = NULL;
154
155 surface = _cairo_surface_create_from_ppm (width, height, colors, bits, buffer, buffer_size);
156 if (surface != NULL) {
157 image = gth_image_new_for_surface (surface);
158 cairo_surface_destroy (surface);
159 }
160
161 return image;
162 }
163
164
165 static GthTransform
_libraw_get_tranform(libraw_data_t * raw_data)166 _libraw_get_tranform (libraw_data_t *raw_data)
167 {
168 GthTransform transform;
169
170 switch (raw_data->sizes.flip) {
171 case 3:
172 transform = GTH_TRANSFORM_ROTATE_180;
173 break;
174 case 5:
175 transform = GTH_TRANSFORM_ROTATE_270;
176 break;
177 case 6:
178 transform = GTH_TRANSFORM_ROTATE_90;
179 break;
180 default:
181 transform = GTH_TRANSFORM_NONE;
182 break;
183 }
184
185 return transform;
186 }
187
188
189 static int
_libraw_progress_cb(void * callback_data,enum LibRaw_progress stage,int iteration,int expected)190 _libraw_progress_cb (void *callback_data,
191 enum LibRaw_progress stage,
192 int iteration,
193 int expected)
194 {
195 return g_cancellable_is_cancelled ((GCancellable *) callback_data) ? 1 : 0;
196 }
197
198
199 static GthImage *
_cairo_image_surface_create_from_raw(GInputStream * istream,GthFileData * file_data,int requested_size,int * original_width,int * original_height,gboolean * loaded_original,gpointer user_data,GCancellable * cancellable,GError ** error)200 _cairo_image_surface_create_from_raw (GInputStream *istream,
201 GthFileData *file_data,
202 int requested_size,
203 int *original_width,
204 int *original_height,
205 gboolean *loaded_original,
206 gpointer user_data,
207 GCancellable *cancellable,
208 GError **error)
209 {
210 libraw_data_t *raw_data;
211 int result;
212 void *buffer = NULL;
213 size_t size;
214 GthImage *image = NULL;
215
216 raw_data = libraw_init (LIBRAW_OPIONS_NO_MEMERR_CALLBACK | LIBRAW_OPIONS_NO_DATAERR_CALLBACK);
217 if (raw_data == NULL) {
218 _libraw_set_gerror (error, errno);
219 goto fatal_error;
220 }
221
222 libraw_set_progress_handler (raw_data, _libraw_progress_cb, cancellable);
223
224 if (! _g_input_stream_read_all (istream, &buffer, &size, cancellable, error))
225 goto fatal_error;
226
227 raw_data->params.output_tiff = FALSE;
228 raw_data->params.use_camera_wb = TRUE;
229 raw_data->params.use_rawspeed = TRUE;
230 raw_data->params.highlight = FALSE;
231 raw_data->params.use_camera_matrix = TRUE;
232 raw_data->params.output_color = RAW_OUTPUT_COLOR_SRGB;
233 raw_data->params.output_bps = 8;
234 raw_data->params.half_size = (requested_size > 0);
235
236 result = libraw_open_buffer (raw_data, buffer, size);
237 if (LIBRAW_FATAL_ERROR (result)) {
238 _libraw_set_gerror (error, result);
239 goto fatal_error;
240 }
241
242
243 if (requested_size > 0) {
244
245 if (loaded_original != NULL)
246 *loaded_original = FALSE;
247
248 /* read the thumbnail */
249
250 result = libraw_unpack_thumb (raw_data);
251 if (result != LIBRAW_SUCCESS) {
252 _libraw_set_gerror (error, result);
253 goto fatal_error;
254 }
255
256 switch (raw_data->thumbnail.tformat) {
257 case LIBRAW_THUMBNAIL_JPEG:
258 image = _libraw_read_jpeg_data (raw_data->thumbnail.thumb,
259 raw_data->thumbnail.tlength,
260 requested_size,
261 cancellable,
262 error);
263 break;
264 case LIBRAW_THUMBNAIL_BITMAP:
265 if ((raw_data->thumbnail.tcolors > 0) && (raw_data->thumbnail.tcolors <= 4)) {
266 image = _libraw_read_bitmap_data (raw_data->thumbnail.twidth,
267 raw_data->thumbnail.theight,
268 raw_data->thumbnail.tcolors,
269 8,
270 (guchar *) raw_data->thumbnail.thumb,
271 raw_data->thumbnail.tlength);
272 }
273 else
274 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Unsupported data format");
275 break;
276 default:
277 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Unsupported data format");
278 break;
279 }
280
281 if ((image != NULL) && (_libraw_get_tranform (raw_data) != GTH_TRANSFORM_NONE)) {
282 cairo_surface_t *surface;
283 cairo_surface_t *rotated;
284
285 surface = gth_image_get_cairo_surface (image);
286 rotated = _cairo_image_surface_transform (surface, _libraw_get_tranform (raw_data));
287 gth_image_set_cairo_surface (image, rotated);
288
289 cairo_surface_destroy (rotated);
290 cairo_surface_destroy (surface);
291 }
292
293 /* get the original size */
294
295 if ((original_width != NULL) && (original_height != NULL)) {
296 libraw_close (raw_data);
297
298 raw_data = libraw_init (LIBRAW_OPIONS_NO_MEMERR_CALLBACK | LIBRAW_OPIONS_NO_DATAERR_CALLBACK);
299 if (raw_data == NULL)
300 goto fatal_error;
301
302 result = libraw_open_buffer (raw_data, buffer, size);
303 if (LIBRAW_FATAL_ERROR (result))
304 goto fatal_error;
305
306 result = libraw_unpack (raw_data);
307 if (result != LIBRAW_SUCCESS) {
308 _libraw_set_gerror (error, result);
309 goto fatal_error;
310 }
311
312 result = libraw_adjust_sizes_info_only (raw_data);
313 if (result != LIBRAW_SUCCESS) {
314 _libraw_set_gerror (error, result);
315 goto fatal_error;
316 }
317
318 *original_width = raw_data->sizes.iwidth;
319 *original_height = raw_data->sizes.iheight;
320 }
321 } else {
322 /* read the image */
323
324 libraw_processed_image_t *processed_image;
325
326 result = libraw_unpack (raw_data);
327 if (result != LIBRAW_SUCCESS) {
328 _libraw_set_gerror (error, result);
329 goto fatal_error;
330 }
331
332 result = libraw_dcraw_process (raw_data);
333 if (result != LIBRAW_SUCCESS) {
334 _libraw_set_gerror (error, result);
335 goto fatal_error;
336 }
337
338 processed_image = libraw_dcraw_make_mem_image (raw_data, &result);
339 if (result != LIBRAW_SUCCESS) {
340 _libraw_set_gerror (error, result);
341 goto fatal_error;
342 }
343
344 switch (processed_image->type) {
345 case LIBRAW_IMAGE_JPEG:
346 image = _libraw_read_jpeg_data (processed_image->data,
347 processed_image->data_size,
348 -1,
349 cancellable,
350 error);
351 break;
352 case LIBRAW_IMAGE_BITMAP:
353 image = _libraw_read_bitmap_data (processed_image->width,
354 processed_image->height,
355 processed_image->colors,
356 processed_image->bits,
357 processed_image->data,
358 processed_image->data_size);
359 break;
360 default:
361 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Unsupported data format");
362 break;
363 }
364
365 libraw_dcraw_clear_mem (processed_image);
366
367 /* get the original size */
368
369 if ((original_width != NULL) && (original_height != NULL)) {
370 result = libraw_adjust_sizes_info_only (raw_data);
371 if (result != LIBRAW_SUCCESS) {
372 _libraw_set_gerror (error, result);
373 goto fatal_error;
374 }
375
376 *original_width = raw_data->sizes.iwidth;
377 *original_height = raw_data->sizes.iheight;
378 }
379 }
380
381 fatal_error:
382
383 if (raw_data != NULL)
384 libraw_close (raw_data);
385 g_free (buffer);
386
387 return image;
388 }
389
390
391 G_MODULE_EXPORT void
gthumb_extension_activate(void)392 gthumb_extension_activate (void)
393 {
394 GList *mime_types;
395 mime_types = g_content_types_get_registered ();
396
397 GList *l = mime_types;
398 while (l != NULL) {
399 GList *next = l->next;
400 if (!_g_mime_type_is_raw (l->data)) {
401 g_free (l->data);
402 mime_types = g_list_delete_link (mime_types, l);
403 }
404 l = next;
405 }
406
407 int count_of_raw_types, i;
408 count_of_raw_types = g_list_length (mime_types);
409
410 gchar *raw_mime_types[count_of_raw_types+1];
411
412 i = 0;
413 l = mime_types;
414 while (l != NULL) {
415 GList *next = l->next;
416 raw_mime_types[i] = (gchar *) l->data;
417 i++;
418 l = next;
419 }
420 raw_mime_types[i] = NULL;
421
422 gth_main_register_metadata_provider (GTH_TYPE_METADATA_PROVIDER_RAW);
423 gth_main_register_image_loader_func_v (_cairo_image_surface_create_from_raw,
424 GTH_IMAGE_FORMAT_CAIRO_SURFACE,
425 (const gchar **) raw_mime_types);
426
427 g_list_free_full (mime_types, g_free);
428 }
429
430
431 G_MODULE_EXPORT void
gthumb_extension_deactivate(void)432 gthumb_extension_deactivate (void)
433 {
434 }
435
436
437 G_MODULE_EXPORT gboolean
gthumb_extension_is_configurable(void)438 gthumb_extension_is_configurable (void)
439 {
440 return FALSE;
441 }
442
443
444 G_MODULE_EXPORT void
gthumb_extension_configure(GtkWindow * parent)445 gthumb_extension_configure (GtkWindow *parent)
446 {
447 }
448