1 /* Eye Of Gnome - Image
2 *
3 * Copyright (C) 2006 The Free Software Foundation
4 *
5 * Author: Lucas Rocha <lucasr@gnome.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 2 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 along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #define GDK_PIXBUF_ENABLE_BACKEND
27
28 #include "eog-image.h"
29 #include "eog-image-private.h"
30 #include "eog-debug.h"
31
32 #ifdef HAVE_JPEG
33 #include "eog-image-jpeg.h"
34 #endif
35
36 #include "eog-marshal.h"
37 #include "eog-pixbuf-util.h"
38 #include "eog-metadata-reader.h"
39 #include "eog-image-save-info.h"
40 #include "eog-transform.h"
41 #include "eog-util.h"
42 #include "eog-jobs.h"
43 #include "eog-thumbnail.h"
44
45 #include <unistd.h>
46 #include <string.h>
47
48 #include <glib.h>
49 #include <glib-object.h>
50 #include <glib/gi18n.h>
51 #include <gtk/gtk.h>
52 #include <gdk-pixbuf/gdk-pixbuf.h>
53
54 #ifdef HAVE_EXIF
55 #include "eog-exif-util.h"
56 #include <libexif/exif-data.h>
57 #include <libexif/exif-utils.h>
58 #include <libexif/exif-loader.h>
59 #endif
60
61 #ifdef HAVE_EXEMPI
62 #include <exempi/xmp.h>
63 #endif
64
65 #ifdef HAVE_LCMS
66 #include <lcms2.h>
67 #ifndef EXIF_TAG_GAMMA
68 #define EXIF_TAG_GAMMA 0xa500
69 #endif
70 #endif
71
72 #ifdef HAVE_RSVG
73 #include <librsvg/rsvg.h>
74 #endif
75
76 G_DEFINE_TYPE_WITH_PRIVATE (EogImage, eog_image, G_TYPE_OBJECT)
77
78 enum {
79 SIGNAL_CHANGED,
80 SIGNAL_SIZE_PREPARED,
81 SIGNAL_THUMBNAIL_CHANGED,
82 SIGNAL_SAVE_PROGRESS,
83 SIGNAL_NEXT_FRAME,
84 SIGNAL_FILE_CHANGED,
85 SIGNAL_LAST
86 };
87
88 static gint signals[SIGNAL_LAST];
89
90 static GList *supported_mime_types = NULL;
91
92 #define EOG_IMAGE_READ_BUFFER_SIZE 65535
93
94 static void
eog_image_free_mem_private(EogImage * image)95 eog_image_free_mem_private (EogImage *image)
96 {
97 EogImagePrivate *priv;
98
99 priv = image->priv;
100
101 if (priv->status == EOG_IMAGE_STATUS_LOADING) {
102 eog_image_cancel_load (image);
103 } else {
104 if (priv->anim_source != 0) {
105 g_source_remove (priv->anim_source);
106 priv->anim_source = 0;
107 }
108
109 if (priv->anim_iter != NULL) {
110 g_object_unref (priv->anim_iter);
111 priv->anim_iter = NULL;
112 }
113
114 if (priv->anim != NULL) {
115 g_object_unref (priv->anim);
116 priv->anim = NULL;
117 }
118
119 priv->is_playing = FALSE;
120
121 if (priv->image != NULL) {
122 g_object_unref (priv->image);
123 priv->image = NULL;
124 }
125
126 #ifdef HAVE_RSVG
127 if (priv->svg != NULL) {
128 g_object_unref (priv->svg);
129 priv->svg = NULL;
130 }
131 #endif
132
133 #ifdef HAVE_EXIF
134 if (priv->exif != NULL) {
135 exif_data_unref (priv->exif);
136 priv->exif = NULL;
137 }
138 #endif
139
140 if (priv->exif_chunk != NULL) {
141 g_free (priv->exif_chunk);
142 priv->exif_chunk = NULL;
143 }
144
145 priv->exif_chunk_len = 0;
146
147 #ifdef HAVE_EXEMPI
148 if (priv->xmp != NULL) {
149 xmp_free (priv->xmp);
150 priv->xmp = NULL;
151 }
152 #endif
153
154 #ifdef HAVE_LCMS
155 if (priv->profile != NULL) {
156 cmsCloseProfile (priv->profile);
157 priv->profile = NULL;
158 }
159 #endif
160
161 priv->status = EOG_IMAGE_STATUS_UNKNOWN;
162 priv->metadata_status = EOG_IMAGE_METADATA_NOT_READ;
163 }
164 }
165
166 static void
eog_image_dispose(GObject * object)167 eog_image_dispose (GObject *object)
168 {
169 EogImagePrivate *priv;
170
171 priv = EOG_IMAGE (object)->priv;
172
173 eog_image_free_mem_private (EOG_IMAGE (object));
174
175 if (priv->file) {
176 g_object_unref (priv->file);
177 priv->file = NULL;
178 }
179
180 if (priv->caption) {
181 g_free (priv->caption);
182 priv->caption = NULL;
183 }
184
185 if (priv->collate_key) {
186 g_free (priv->collate_key);
187 priv->collate_key = NULL;
188 }
189
190 if (priv->file_type) {
191 g_free (priv->file_type);
192 priv->file_type = NULL;
193 }
194
195 g_mutex_clear (&priv->status_mutex);
196
197 if (priv->trans) {
198 g_object_unref (priv->trans);
199 priv->trans = NULL;
200 }
201
202 if (priv->trans_autorotate) {
203 g_object_unref (priv->trans_autorotate);
204 priv->trans_autorotate = NULL;
205 }
206
207 if (priv->undo_stack) {
208 g_slist_foreach (priv->undo_stack, (GFunc) g_object_unref, NULL);
209 g_slist_free (priv->undo_stack);
210 priv->undo_stack = NULL;
211 }
212
213 G_OBJECT_CLASS (eog_image_parent_class)->dispose (object);
214 }
215
216 static void
eog_image_finalize(GObject * object)217 eog_image_finalize (GObject *object)
218 {
219 EogImagePrivate *priv;
220
221 priv = EOG_IMAGE (object)->priv;
222
223 g_mutex_clear (&priv->status_mutex);
224
225 G_OBJECT_CLASS (eog_image_parent_class)->finalize (object);
226 }
227
228 static void
eog_image_class_init(EogImageClass * klass)229 eog_image_class_init (EogImageClass *klass)
230 {
231 GObjectClass *object_class = (GObjectClass*) klass;
232
233 object_class->dispose = eog_image_dispose;
234 object_class->finalize = eog_image_finalize;
235
236 signals[SIGNAL_SIZE_PREPARED] =
237 g_signal_new ("size-prepared",
238 EOG_TYPE_IMAGE,
239 G_SIGNAL_RUN_LAST,
240 G_STRUCT_OFFSET (EogImageClass, size_prepared),
241 NULL, NULL,
242 eog_marshal_VOID__INT_INT,
243 G_TYPE_NONE, 2,
244 G_TYPE_INT,
245 G_TYPE_INT);
246
247 signals[SIGNAL_CHANGED] =
248 g_signal_new ("changed",
249 EOG_TYPE_IMAGE,
250 G_SIGNAL_RUN_LAST,
251 G_STRUCT_OFFSET (EogImageClass, changed),
252 NULL, NULL,
253 g_cclosure_marshal_VOID__VOID,
254 G_TYPE_NONE, 0);
255
256 signals[SIGNAL_THUMBNAIL_CHANGED] =
257 g_signal_new ("thumbnail-changed",
258 EOG_TYPE_IMAGE,
259 G_SIGNAL_RUN_LAST,
260 G_STRUCT_OFFSET (EogImageClass, thumbnail_changed),
261 NULL, NULL,
262 g_cclosure_marshal_VOID__VOID,
263 G_TYPE_NONE, 0);
264
265 signals[SIGNAL_SAVE_PROGRESS] =
266 g_signal_new ("save-progress",
267 EOG_TYPE_IMAGE,
268 G_SIGNAL_RUN_LAST,
269 G_STRUCT_OFFSET (EogImageClass, save_progress),
270 NULL, NULL,
271 g_cclosure_marshal_VOID__FLOAT,
272 G_TYPE_NONE, 1,
273 G_TYPE_FLOAT);
274 /**
275 * EogImage::next-frame:
276 * @img: the object which received the signal.
277 * @delay: number of milliseconds the current frame will be displayed.
278 *
279 * The ::next-frame signal will be emitted each time an animated image
280 * advances to the next frame.
281 */
282 signals[SIGNAL_NEXT_FRAME] =
283 g_signal_new ("next-frame",
284 EOG_TYPE_IMAGE,
285 G_SIGNAL_RUN_LAST,
286 G_STRUCT_OFFSET (EogImageClass, next_frame),
287 NULL, NULL,
288 g_cclosure_marshal_VOID__INT,
289 G_TYPE_NONE, 1,
290 G_TYPE_INT);
291
292 signals[SIGNAL_FILE_CHANGED] = g_signal_new ("file-changed",
293 EOG_TYPE_IMAGE,
294 G_SIGNAL_RUN_LAST,
295 G_STRUCT_OFFSET (EogImageClass, file_changed),
296 NULL, NULL,
297 g_cclosure_marshal_VOID__VOID,
298 G_TYPE_NONE, 0);
299 }
300
301 static void
eog_image_init(EogImage * img)302 eog_image_init (EogImage *img)
303 {
304 img->priv = eog_image_get_instance_private (img);
305
306 img->priv->file = NULL;
307 img->priv->image = NULL;
308 img->priv->anim = NULL;
309 img->priv->anim_iter = NULL;
310 img->priv->is_playing = FALSE;
311 img->priv->thumbnail = NULL;
312 img->priv->width = -1;
313 img->priv->height = -1;
314 img->priv->modified = FALSE;
315 img->priv->file_is_changed = FALSE;
316 g_mutex_init (&img->priv->status_mutex);
317 img->priv->status = EOG_IMAGE_STATUS_UNKNOWN;
318 img->priv->metadata_status = EOG_IMAGE_METADATA_NOT_READ;
319 img->priv->undo_stack = NULL;
320 img->priv->trans = NULL;
321 img->priv->trans_autorotate = NULL;
322 img->priv->data_ref_count = 0;
323 img->priv->anim_source = 0;
324 #ifdef HAVE_EXIF
325 img->priv->orientation = 0;
326 img->priv->autorotate = FALSE;
327 img->priv->exif = NULL;
328 #endif
329 #ifdef HAVE_EXEMPI
330 img->priv->xmp = NULL;
331 #endif
332 #ifdef HAVE_LCMS
333 img->priv->profile = NULL;
334 #endif
335 #ifdef HAVE_RSVG
336 img->priv->svg = NULL;
337 #endif
338 }
339
340 EogImage *
eog_image_new_file(GFile * file,const gchar * caption)341 eog_image_new_file (GFile *file, const gchar *caption)
342 {
343 EogImage *img;
344
345 img = EOG_IMAGE (g_object_new (EOG_TYPE_IMAGE, NULL));
346
347 img->priv->file = g_object_ref (file);
348 img->priv->caption = g_strdup (caption);
349
350 return img;
351 }
352
353 GQuark
eog_image_error_quark(void)354 eog_image_error_quark (void)
355 {
356 static GQuark q = 0;
357
358 if (q == 0) {
359 q = g_quark_from_static_string ("eog-image-error-quark");
360 }
361
362 return q;
363 }
364
365 static void
eog_image_update_exif_data(EogImage * image)366 eog_image_update_exif_data (EogImage *image)
367 {
368 #ifdef HAVE_EXIF
369 EogImagePrivate *priv;
370 ExifEntry *entry;
371 ExifByteOrder bo;
372
373 eog_debug (DEBUG_IMAGE_DATA);
374
375 g_return_if_fail (EOG_IS_IMAGE (image));
376
377 priv = image->priv;
378
379 if (priv->exif == NULL) return;
380
381 bo = exif_data_get_byte_order (priv->exif);
382
383 /* Update image width */
384 entry = exif_data_get_entry (priv->exif, EXIF_TAG_PIXEL_X_DIMENSION);
385 if (entry != NULL && (priv->width >= 0)) {
386 if (entry->format == EXIF_FORMAT_LONG)
387 exif_set_long (entry->data, bo, priv->width);
388 else if (entry->format == EXIF_FORMAT_SHORT)
389 exif_set_short (entry->data, bo, priv->width);
390 else
391 g_warning ("Exif entry has unsupported size");
392 }
393
394 /* Update image height */
395 entry = exif_data_get_entry (priv->exif, EXIF_TAG_PIXEL_Y_DIMENSION);
396 if (entry != NULL && (priv->height >= 0)) {
397 if (entry->format == EXIF_FORMAT_LONG)
398 exif_set_long (entry->data, bo, priv->height);
399 else if (entry->format == EXIF_FORMAT_SHORT)
400 exif_set_short (entry->data, bo, priv->height);
401 else
402 g_warning ("Exif entry has unsupported size");
403 }
404
405 /* Update image orientation */
406 entry = exif_data_get_entry (priv->exif, EXIF_TAG_ORIENTATION);
407 if (entry != NULL) {
408 if (entry->format == EXIF_FORMAT_LONG)
409 exif_set_long (entry->data, bo, 1);
410 else if (entry->format == EXIF_FORMAT_SHORT)
411 exif_set_short (entry->data, bo, 1);
412 else
413 g_warning ("Exif entry has unsupported size");
414
415 priv->orientation = 1;
416 }
417 #endif
418 }
419
420 static void
eog_image_real_transform(EogImage * img,EogTransform * trans,gboolean is_undo,EogJob * job)421 eog_image_real_transform (EogImage *img,
422 EogTransform *trans,
423 gboolean is_undo,
424 EogJob *job)
425 {
426 EogImagePrivate *priv;
427 GdkPixbuf *transformed;
428 gboolean modified = FALSE;
429
430 g_return_if_fail (EOG_IS_IMAGE (img));
431 g_return_if_fail (EOG_IS_TRANSFORM (trans));
432
433 priv = img->priv;
434
435 if (priv->image != NULL) {
436 transformed = eog_transform_apply (trans, priv->image, job);
437
438 g_object_unref (priv->image);
439 priv->image = transformed;
440
441 priv->width = gdk_pixbuf_get_width (transformed);
442 priv->height = gdk_pixbuf_get_height (transformed);
443
444 modified = TRUE;
445 }
446
447 if (priv->thumbnail != NULL) {
448 transformed = eog_transform_apply (trans, priv->thumbnail, NULL);
449
450 g_object_unref (priv->thumbnail);
451 priv->thumbnail = transformed;
452
453 modified = TRUE;
454 }
455
456 if (modified) {
457 priv->modified = TRUE;
458 eog_image_update_exif_data (img);
459 }
460
461 if (priv->trans == NULL) {
462 g_object_ref (trans);
463 priv->trans = trans;
464 } else {
465 EogTransform *composition;
466
467 composition = eog_transform_compose (priv->trans, trans);
468
469 g_object_unref (priv->trans);
470
471 priv->trans = composition;
472 }
473
474 if (!is_undo) {
475 g_object_ref (trans);
476 priv->undo_stack = g_slist_prepend (priv->undo_stack, trans);
477 }
478 }
479
480 static gboolean
do_emit_size_prepared_signal(EogImage * img)481 do_emit_size_prepared_signal (EogImage *img)
482 {
483 g_signal_emit (img, signals[SIGNAL_SIZE_PREPARED], 0,
484 img->priv->width, img->priv->height);
485 return FALSE;
486 }
487
488 static void
eog_image_emit_size_prepared(EogImage * img)489 eog_image_emit_size_prepared (EogImage *img)
490 {
491 g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
492 (GSourceFunc) do_emit_size_prepared_signal,
493 g_object_ref (img), g_object_unref);
494 }
495
496 static void
eog_image_size_prepared(GdkPixbufLoader * loader,gint width,gint height,gpointer data)497 eog_image_size_prepared (GdkPixbufLoader *loader,
498 gint width,
499 gint height,
500 gpointer data)
501 {
502 EogImage *img;
503
504 eog_debug (DEBUG_IMAGE_LOAD);
505
506 g_return_if_fail (EOG_IS_IMAGE (data));
507
508 img = EOG_IMAGE (data);
509
510 g_mutex_lock (&img->priv->status_mutex);
511
512 img->priv->width = width;
513 img->priv->height = height;
514
515 g_mutex_unlock (&img->priv->status_mutex);
516
517 #ifdef HAVE_EXIF
518 if (!img->priv->autorotate || img->priv->exif)
519 #endif
520 eog_image_emit_size_prepared (img);
521 }
522
523 static EogMetadataReader*
check_for_metadata_img_format(EogImage * img,guchar * buffer,guint bytes_read)524 check_for_metadata_img_format (EogImage *img, guchar *buffer, guint bytes_read)
525 {
526 EogMetadataReader *md_reader = NULL;
527
528 eog_debug_message (DEBUG_IMAGE_DATA, "Check image format for jpeg: %x%x - length: %i",
529 buffer[0], buffer[1], bytes_read);
530
531 if (bytes_read >= 2) {
532 /* SOI (start of image) marker for JPEGs is 0xFFD8 */
533 if ((buffer[0] == 0xFF) && (buffer[1] == 0xD8)) {
534 md_reader = eog_metadata_reader_new (EOG_METADATA_JPEG);
535 }
536 if (bytes_read >= 8 &&
537 memcmp (buffer, "\x89PNG\x0D\x0A\x1a\x0A", 8) == 0) {
538 md_reader = eog_metadata_reader_new (EOG_METADATA_PNG);
539 }
540 }
541
542 return md_reader;
543 }
544
545 static gboolean
eog_image_needs_transformation(EogImage * img)546 eog_image_needs_transformation (EogImage *img)
547 {
548 g_return_val_if_fail (EOG_IS_IMAGE (img), FALSE);
549
550 return (img->priv->trans != NULL || img->priv->trans_autorotate != NULL);
551 }
552
553 static gboolean
eog_image_apply_transformations(EogImage * img,GError ** error)554 eog_image_apply_transformations (EogImage *img, GError **error)
555 {
556 GdkPixbuf *transformed = NULL;
557 EogTransform *composition = NULL;
558 EogImagePrivate *priv;
559
560 g_return_val_if_fail (EOG_IS_IMAGE (img), FALSE);
561
562 priv = img->priv;
563
564 if (priv->trans == NULL && priv->trans_autorotate == NULL) {
565 return TRUE;
566 }
567
568 if (priv->image == NULL) {
569 g_set_error (error,
570 EOG_IMAGE_ERROR,
571 EOG_IMAGE_ERROR_NOT_LOADED,
572 _("Transformation on unloaded image."));
573
574 return FALSE;
575 }
576
577 if (priv->trans != NULL && priv->trans_autorotate != NULL) {
578 composition = eog_transform_compose (priv->trans,
579 priv->trans_autorotate);
580 } else if (priv->trans != NULL) {
581 composition = g_object_ref (priv->trans);
582 } else if (priv->trans_autorotate != NULL) {
583 composition = g_object_ref (priv->trans_autorotate);
584 }
585
586 if (composition != NULL) {
587 transformed = eog_transform_apply (composition, priv->image, NULL);
588 }
589
590 g_object_unref (priv->image);
591 priv->image = transformed;
592
593 if (transformed != NULL) {
594 priv->width = gdk_pixbuf_get_width (priv->image);
595 priv->height = gdk_pixbuf_get_height (priv->image);
596 } else {
597 g_set_error (error,
598 EOG_IMAGE_ERROR,
599 EOG_IMAGE_ERROR_GENERIC,
600 _("Transformation failed."));
601 }
602
603 g_object_unref (composition);
604
605 return (transformed != NULL);
606 }
607
608 static void
eog_image_get_file_info(EogImage * img,goffset * bytes,gchar ** mime_type,GError ** error)609 eog_image_get_file_info (EogImage *img,
610 goffset *bytes,
611 gchar **mime_type,
612 GError **error)
613 {
614 GFileInfo *file_info;
615
616 file_info = g_file_query_info (img->priv->file,
617 G_FILE_ATTRIBUTE_STANDARD_SIZE ","
618 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
619 0, NULL, error);
620
621 if (file_info == NULL) {
622 if (bytes)
623 *bytes = 0;
624
625 if (mime_type)
626 *mime_type = NULL;
627 } else {
628 if (bytes)
629 *bytes = g_file_info_get_size (file_info);
630
631 if (mime_type)
632 *mime_type = g_strdup (g_file_info_get_content_type (file_info));
633 g_object_unref (file_info);
634 }
635 }
636
637 #ifdef HAVE_LCMS
638 void
eog_image_apply_display_profile(EogImage * img,cmsHPROFILE screen)639 eog_image_apply_display_profile (EogImage *img, cmsHPROFILE screen)
640 {
641 EogImagePrivate *priv;
642 cmsHTRANSFORM transform;
643 gint row, width, rows, stride;
644 guchar *p;
645
646 g_return_if_fail (img != NULL);
647
648 priv = img->priv;
649
650 if (screen == NULL) return;
651
652 if (priv->profile == NULL) {
653 /* Check whether GdkPixbuf was able to extract a profile */
654 const char* data = gdk_pixbuf_get_option (priv->image,
655 "icc-profile");
656
657 if(data) {
658 gsize profile_size = 0;
659 guchar *profile_data = g_base64_decode(data,
660 &profile_size);
661
662 if (profile_data && profile_size > 0) {
663 eog_debug_message (DEBUG_LCMS,
664 "Using ICC profile "
665 "extracted by GdkPixbuf");
666 priv->profile =
667 cmsOpenProfileFromMem(profile_data,
668 profile_size);
669 g_free(profile_data);
670 }
671 }
672
673 if(priv->profile == NULL) {
674 /* Assume sRGB color space for images without ICC profile */
675 eog_debug_message (DEBUG_LCMS, "Image has no ICC profile. "
676 "Assuming sRGB.");
677 priv->profile = cmsCreate_sRGBProfile ();
678 }
679 }
680
681 /* TODO: support other colorspaces than RGB */
682 if (cmsGetColorSpace (priv->profile) != cmsSigRgbData ||
683 cmsGetColorSpace (screen) != cmsSigRgbData) {
684 eog_debug_message (DEBUG_LCMS, "One or both ICC profiles not in RGB colorspace; not correcting");
685 return;
686 }
687
688 cmsUInt32Number color_type = TYPE_RGB_8;
689
690 if (gdk_pixbuf_get_has_alpha (priv->image))
691 color_type = TYPE_RGBA_8;
692
693 transform = cmsCreateTransform (priv->profile,
694 color_type,
695 screen,
696 color_type,
697 INTENT_PERCEPTUAL,
698 0);
699
700 if (G_LIKELY (transform != NULL)) {
701 rows = gdk_pixbuf_get_height (priv->image);
702 width = gdk_pixbuf_get_width (priv->image);
703 stride = gdk_pixbuf_get_rowstride (priv->image);
704 p = gdk_pixbuf_get_pixels (priv->image);
705
706 for (row = 0; row < rows; ++row) {
707 cmsDoTransform (transform, p, p, width);
708 p += stride;
709 }
710 cmsDeleteTransform (transform);
711 }
712 }
713
714 static void
eog_image_set_icc_data(EogImage * img,EogMetadataReader * md_reader)715 eog_image_set_icc_data (EogImage *img, EogMetadataReader *md_reader)
716 {
717 EogImagePrivate *priv = img->priv;
718
719 priv->profile = eog_metadata_reader_get_icc_profile (md_reader);
720
721
722 }
723 #endif
724
725 static void
eog_image_set_orientation(EogImage * img)726 eog_image_set_orientation (EogImage *img)
727 {
728 EogImagePrivate *priv;
729 #ifdef HAVE_EXIF
730 ExifData* exif;
731 #endif
732
733 g_return_if_fail (EOG_IS_IMAGE (img));
734
735 priv = img->priv;
736
737 #ifdef HAVE_EXIF
738 exif = (ExifData*) eog_image_get_exif_info (img);
739
740 if (exif != NULL) {
741 ExifByteOrder o = exif_data_get_byte_order (exif);
742
743 ExifEntry *entry = exif_data_get_entry (exif,
744 EXIF_TAG_ORIENTATION);
745
746 if (entry && entry->data != NULL) {
747 priv->orientation = exif_get_short (entry->data, o);
748 }
749
750 exif_data_unref (exif);
751 } else
752 #endif
753 {
754 GdkPixbuf *pbuf;
755
756 pbuf = eog_image_get_pixbuf (img);
757
758 if (pbuf) {
759 const gchar *o_str;
760
761 o_str = gdk_pixbuf_get_option (pbuf, "orientation");
762 if (o_str) {
763 short t = (short) g_ascii_strtoll (o_str,
764 NULL, 10);
765 if (t >= 0 && t < 9)
766 priv->orientation = t;
767 }
768 g_object_unref (pbuf);
769 }
770 }
771
772 if (priv->orientation > 4 &&
773 priv->orientation < 9) {
774 gint tmp;
775
776 tmp = priv->width;
777 priv->width = priv->height;
778 priv->height = tmp;
779 }
780 }
781
782 static void
eog_image_real_autorotate(EogImage * img)783 eog_image_real_autorotate (EogImage *img)
784 {
785 static const EogTransformType lookup[8] = {EOG_TRANSFORM_NONE,
786 EOG_TRANSFORM_FLIP_HORIZONTAL,
787 EOG_TRANSFORM_ROT_180,
788 EOG_TRANSFORM_FLIP_VERTICAL,
789 EOG_TRANSFORM_TRANSPOSE,
790 EOG_TRANSFORM_ROT_90,
791 EOG_TRANSFORM_TRANSVERSE,
792 EOG_TRANSFORM_ROT_270};
793 EogImagePrivate *priv;
794 EogTransformType type;
795
796 g_return_if_fail (EOG_IS_IMAGE (img));
797
798 priv = img->priv;
799
800 type = (priv->orientation >= 1 && priv->orientation <= 8 ?
801 lookup[priv->orientation - 1] : EOG_TRANSFORM_NONE);
802
803 if (type != EOG_TRANSFORM_NONE) {
804 img->priv->trans_autorotate = eog_transform_new (type);
805 }
806
807 /* Disable auto orientation for next loads */
808 priv->autorotate = FALSE;
809 }
810
811 void
eog_image_autorotate(EogImage * img)812 eog_image_autorotate (EogImage *img)
813 {
814 g_return_if_fail (EOG_IS_IMAGE (img));
815
816 /* Schedule auto orientation */
817 img->priv->autorotate = TRUE;
818 }
819
820 #ifdef HAVE_EXEMPI
821 static void
eog_image_set_xmp_data(EogImage * img,EogMetadataReader * md_reader)822 eog_image_set_xmp_data (EogImage *img, EogMetadataReader *md_reader)
823 {
824 EogImagePrivate *priv;
825
826 g_return_if_fail (EOG_IS_IMAGE (img));
827
828 priv = img->priv;
829
830 if (priv->xmp) {
831 xmp_free (priv->xmp);
832 }
833 priv->xmp = eog_metadata_reader_get_xmp_data (md_reader);
834 }
835 #endif
836
837 static void
eog_image_set_exif_data(EogImage * img,EogMetadataReader * md_reader)838 eog_image_set_exif_data (EogImage *img, EogMetadataReader *md_reader)
839 {
840 EogImagePrivate *priv;
841
842 g_return_if_fail (EOG_IS_IMAGE (img));
843
844 priv = img->priv;
845
846 #ifdef HAVE_EXIF
847 g_mutex_lock (&priv->status_mutex);
848 if (priv->exif) {
849 exif_data_unref (priv->exif);
850 }
851 priv->exif = eog_metadata_reader_get_exif_data (md_reader);
852 g_mutex_unlock (&priv->status_mutex);
853
854 priv->exif_chunk = NULL;
855 priv->exif_chunk_len = 0;
856
857 /* EXIF data is already available, set the image orientation */
858 if (priv->autorotate) {
859 eog_image_set_orientation (img);
860
861 /* Emit size prepared signal if we have the size */
862 if (priv->width > 0 &&
863 priv->height > 0) {
864 eog_image_emit_size_prepared (img);
865 }
866 }
867 #else
868 if (priv->exif_chunk) {
869 g_free (priv->exif_chunk);
870 }
871 eog_metadata_reader_get_exif_chunk (md_reader,
872 &priv->exif_chunk,
873 &priv->exif_chunk_len);
874 #endif
875 }
876
877 /*
878 * Attempts to get the image dimensions from the thumbnail.
879 * Returns FALSE if this information is not found.
880 **/
881 static gboolean
eog_image_get_dimension_from_thumbnail(EogImage * image,gint * width,gint * height)882 eog_image_get_dimension_from_thumbnail (EogImage *image,
883 gint *width,
884 gint *height)
885 {
886 if (image->priv->thumbnail == NULL)
887 return FALSE;
888
889 *width = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (image->priv->thumbnail),
890 EOG_THUMBNAIL_ORIGINAL_WIDTH));
891 *height = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (image->priv->thumbnail),
892 EOG_THUMBNAIL_ORIGINAL_HEIGHT));
893
894 return (*width || *height);
895 }
896
897 static GdkPixbufLoader *
eog_image_new_pixbuf_loader(EogImage * img,gboolean * is_svg,gchar * mime_type,GError ** error)898 eog_image_new_pixbuf_loader (EogImage *img,
899 gboolean *is_svg,
900 gchar *mime_type,
901 GError **error)
902 {
903 EogImagePrivate *priv = img->priv;
904 GdkPixbufLoader *loader = NULL;
905 #ifdef HAVE_RSVG
906 if (priv->svg != NULL) {
907 g_object_unref (priv->svg);
908 priv->svg = NULL;
909 }
910
911 if (!g_strcmp0 (mime_type, "image/svg+xml")
912 || !g_strcmp0 (mime_type, "image/svg+xml-compressed")
913 ) {
914 /* Keep the object for rendering */
915 priv->svg = rsvg_handle_new ();
916 rsvg_handle_set_base_gfile (priv->svg, priv->file);
917
918 /* Use 96dpi when rendering SVG documents with units
919 * different then pixels. This value is specified in
920 * the CSS standard on which SVG depends. */
921 rsvg_handle_set_dpi_x_y (priv->svg, 96.0, 96.0);
922 *is_svg = TRUE;
923 }
924 #endif
925
926 if (!(*is_svg)) {
927 if (G_LIKELY (mime_type))
928 loader = gdk_pixbuf_loader_new_with_mime_type (mime_type,
929 error);
930
931 if (loader == NULL) {
932 g_clear_error (error);
933
934 loader = gdk_pixbuf_loader_new ();
935 }
936
937 g_signal_connect_object (G_OBJECT (loader),
938 "size-prepared",
939 G_CALLBACK (eog_image_size_prepared),
940 img,
941 0);
942 }
943 return loader;
944 }
945
946 static gboolean
eog_image_update_stream(EogImage * img,gchar * old_mime_type,gchar * new_mimetype,GFileInputStream * input_stream)947 eog_image_update_stream (EogImage *img,
948 gchar *old_mime_type,
949 gchar *new_mimetype,
950 GFileInputStream *input_stream)
951 {
952 gboolean success = FALSE;
953
954 if (new_mimetype != NULL && strcmp (old_mime_type, new_mimetype) != 0) {
955 success = g_seekable_seek (G_SEEKABLE (input_stream),
956 0, G_SEEK_SET, NULL, NULL);
957 }
958 return success;
959 }
960
961 static gboolean
eog_image_real_load(EogImage * img,EogImageData data2read,EogJob * job,GError ** error)962 eog_image_real_load (EogImage *img,
963 EogImageData data2read,
964 EogJob *job,
965 GError **error)
966 {
967 EogImagePrivate *priv;
968 GFileInputStream *input_stream;
969 EogMetadataReader *md_reader = NULL;
970 GdkPixbufFormat *format;
971 gchar *mime_type;
972 GdkPixbufLoader *loader = NULL;
973 guchar *buffer;
974 goffset bytes_read = 0, bytes_read_total = 0;
975 gboolean failed = FALSE;
976 gboolean first_run = TRUE;
977 gboolean set_metadata = TRUE;
978 gboolean use_rsvg = FALSE;
979 gboolean read_image_data = (data2read & EOG_IMAGE_DATA_IMAGE);
980 gboolean read_only_dimension = (data2read & EOG_IMAGE_DATA_DIMENSION) &&
981 ((data2read ^ EOG_IMAGE_DATA_DIMENSION) == 0);
982
983
984 priv = img->priv;
985
986 g_assert (!read_image_data || priv->image == NULL);
987
988 if (read_image_data && priv->file_type != NULL) {
989 g_free (priv->file_type);
990 priv->file_type = NULL;
991 }
992
993 eog_image_get_file_info (img, &priv->bytes, &mime_type, error);
994
995 if (error && *error) {
996 g_free (mime_type);
997 return FALSE;
998 }
999
1000 if (read_only_dimension) {
1001 gint width, height;
1002 gboolean done;
1003
1004 done = eog_image_get_dimension_from_thumbnail (img,
1005 &width,
1006 &height);
1007
1008 if (done) {
1009 priv->width = width;
1010 priv->height = height;
1011
1012 g_free (mime_type);
1013 return TRUE;
1014 }
1015 }
1016
1017 input_stream = g_file_read (priv->file, NULL, error);
1018
1019 if (input_stream == NULL) {
1020 g_free (mime_type);
1021
1022 if (error != NULL) {
1023 g_clear_error (error);
1024 g_set_error (error,
1025 EOG_IMAGE_ERROR,
1026 EOG_IMAGE_ERROR_VFS,
1027 "Failed to open input stream for file");
1028 }
1029 return FALSE;
1030 }
1031
1032 buffer = g_new0 (guchar, EOG_IMAGE_READ_BUFFER_SIZE);
1033
1034 if (read_image_data || read_only_dimension)
1035 loader = eog_image_new_pixbuf_loader (img, &use_rsvg, mime_type, error);
1036
1037 while (!priv->cancel_loading) {
1038 #ifdef HAVE_RSVG
1039 if (use_rsvg && first_run && (read_image_data || read_only_dimension)) {
1040 if (rsvg_handle_read_stream_sync (priv->svg,
1041 G_INPUT_STREAM (input_stream),
1042 NULL,
1043 error))
1044 {
1045 /* The entire file is read by now */
1046 bytes_read_total = priv->bytes;
1047 } else {
1048 g_error_free (*error);
1049 *error = NULL;
1050
1051 use_rsvg = FALSE;
1052 g_object_unref (priv->svg);
1053 priv->svg = NULL;
1054
1055 g_object_unref (input_stream);
1056 input_stream = g_file_read (priv->file, NULL, error);
1057 if (input_stream != NULL && *error == NULL) {
1058 if (loader != NULL)
1059 g_object_unref (loader);
1060
1061 /* We cannot call eog_image_new_pixbuf_loader
1062 * since we don't have a buffer to guess
1063 * the mime type. */
1064 loader = gdk_pixbuf_loader_new ();
1065 continue;
1066 } else
1067 failed = TRUE;
1068 }
1069 break;
1070 } else {
1071 #endif
1072 /* FIXME: make this async */
1073 bytes_read = g_input_stream_read (G_INPUT_STREAM (input_stream),
1074 buffer,
1075 EOG_IMAGE_READ_BUFFER_SIZE,
1076 NULL, error);
1077
1078 if (bytes_read == 0) {
1079 /* End of the file */
1080 break;
1081 } else if (bytes_read == -1) {
1082 failed = TRUE;
1083
1084 g_set_error (error,
1085 EOG_IMAGE_ERROR,
1086 EOG_IMAGE_ERROR_VFS,
1087 "Failed to read from input stream");
1088
1089 break;
1090 }
1091
1092 if ((read_image_data || read_only_dimension)) {
1093 if (!gdk_pixbuf_loader_write (loader, buffer, bytes_read, error)) {
1094 gboolean uncertain;
1095 gchar *new_mimetype = g_content_type_guess (NULL,
1096 buffer,
1097 EOG_IMAGE_READ_BUFFER_SIZE,
1098 &uncertain);
1099
1100 if (!uncertain &&
1101 eog_image_update_stream (img, mime_type, new_mimetype, input_stream)) {
1102 g_error_free (*error);
1103 *error = NULL;
1104 g_free (mime_type);
1105 mime_type = g_strdup (new_mimetype);
1106 loader = eog_image_new_pixbuf_loader (img, &use_rsvg, mime_type, error);
1107 g_free (new_mimetype);
1108 continue;
1109 }
1110 failed = TRUE;
1111 break;
1112 }
1113 }
1114
1115 bytes_read_total += bytes_read;
1116 #ifdef HAVE_RSVG
1117 }
1118 #endif
1119
1120 /* For now allow calling from outside of jobs */
1121 if (job != NULL)
1122 {
1123 /* check that load job wasn't cancelled */
1124 if (eog_job_is_cancelled (job)) {
1125 eog_image_cancel_load (img);
1126 continue;
1127 } else if (priv->bytes > 0.0) {
1128 float progress = (float) bytes_read_total / (float) priv->bytes;
1129 eog_job_set_progress (job, progress);
1130 }
1131 }
1132
1133 if (first_run) {
1134 md_reader = check_for_metadata_img_format (img, buffer, bytes_read);
1135
1136 if (md_reader == NULL) {
1137 if (data2read == EOG_IMAGE_DATA_EXIF) {
1138 g_set_error (error,
1139 EOG_IMAGE_ERROR,
1140 EOG_IMAGE_ERROR_GENERIC,
1141 _("EXIF not supported for this file format."));
1142 break;
1143 }
1144
1145 priv->metadata_status = EOG_IMAGE_METADATA_NOT_AVAILABLE;
1146 }
1147
1148 first_run = FALSE;
1149 }
1150
1151 if (md_reader != NULL) {
1152 eog_metadata_reader_consume (md_reader, buffer, bytes_read);
1153
1154 if (eog_metadata_reader_finished (md_reader)) {
1155 if (set_metadata) {
1156 eog_image_set_exif_data (img, md_reader);
1157
1158 #ifdef HAVE_LCMS
1159 eog_image_set_icc_data (img, md_reader);
1160 #endif
1161
1162 #ifdef HAVE_EXEMPI
1163 eog_image_set_xmp_data (img, md_reader);
1164 #endif
1165 set_metadata = FALSE;
1166 priv->metadata_status = EOG_IMAGE_METADATA_READY;
1167 }
1168
1169 if (data2read == EOG_IMAGE_DATA_EXIF)
1170 break;
1171 }
1172 }
1173
1174 if (read_only_dimension &&
1175 eog_image_has_data (img, EOG_IMAGE_DATA_DIMENSION)) {
1176 break;
1177 }
1178 }
1179
1180 if (read_image_data || read_only_dimension) {
1181 if (!use_rsvg) {
1182 if (failed) {
1183 gdk_pixbuf_loader_close (loader, NULL);
1184 } else if (!gdk_pixbuf_loader_close (loader, error)) {
1185 if (gdk_pixbuf_loader_get_pixbuf (loader) != NULL) {
1186 /* Clear error in order to support partial
1187 * images as well. */
1188 g_clear_error (error);
1189 }
1190 }
1191 }
1192 }
1193
1194 g_free (mime_type);
1195 g_free (buffer);
1196
1197 g_object_unref (G_OBJECT (input_stream));
1198
1199 failed = (failed ||
1200 priv->cancel_loading ||
1201 bytes_read_total == 0 ||
1202 (error && *error != NULL));
1203
1204 if (failed) {
1205 if (priv->cancel_loading) {
1206 priv->cancel_loading = FALSE;
1207 priv->status = EOG_IMAGE_STATUS_UNKNOWN;
1208 } else {
1209 priv->status = EOG_IMAGE_STATUS_FAILED;
1210 }
1211 } else if (read_image_data) {
1212 if (priv->image != NULL) {
1213 g_object_unref (priv->image);
1214 }
1215
1216 #ifdef HAVE_RSVG
1217 if (use_rsvg) {
1218 priv->image = rsvg_handle_get_pixbuf (priv->svg);
1219 } else
1220 #endif
1221 {
1222
1223 priv->anim = gdk_pixbuf_loader_get_animation (loader);
1224
1225 if (gdk_pixbuf_animation_is_static_image (priv->anim)) {
1226 priv->image = gdk_pixbuf_animation_get_static_image (priv->anim);
1227 priv->anim = NULL;
1228 } else {
1229 priv->anim_iter = gdk_pixbuf_animation_get_iter (priv->anim,NULL);
1230 priv->image = gdk_pixbuf_animation_iter_get_pixbuf (priv->anim_iter);
1231 }
1232
1233 }
1234
1235 if (G_LIKELY (priv->image != NULL)) {
1236 if (!use_rsvg)
1237 g_object_ref (priv->image);
1238
1239 priv->width = gdk_pixbuf_get_width (priv->image);
1240 priv->height = gdk_pixbuf_get_height (priv->image);
1241
1242 if (use_rsvg) {
1243 format = NULL;
1244 priv->file_type = g_strdup ("svg");
1245 } else {
1246 format = gdk_pixbuf_loader_get_format (loader);
1247 }
1248
1249 if (format != NULL) {
1250 priv->file_type = gdk_pixbuf_format_get_name (format);
1251 }
1252
1253 priv->file_is_changed = FALSE;
1254
1255 /* Set orientation again for safety, eg. if we don't
1256 * have Exif data or HAVE_EXIF is undefined. */
1257 if (priv->autorotate) {
1258 eog_image_set_orientation (img);
1259 eog_image_emit_size_prepared (img);
1260 }
1261 } else {
1262 /* Some loaders don't report errors correctly.
1263 * Error will be set below. */
1264 failed = TRUE;
1265 priv->status = EOG_IMAGE_STATUS_FAILED;
1266 }
1267 }
1268
1269 if (loader != NULL) {
1270 g_object_unref (loader);
1271 }
1272
1273 if (md_reader != NULL) {
1274 g_object_unref (md_reader);
1275 md_reader = NULL;
1276 }
1277
1278 /* Catch-all in case of poor-error reporting */
1279 if (failed && error && *error == NULL) {
1280 g_set_error (error,
1281 EOG_IMAGE_ERROR,
1282 EOG_IMAGE_ERROR_GENERIC,
1283 _("Image loading failed."));
1284 }
1285
1286 return !failed;
1287 }
1288
1289 gboolean
eog_image_has_data(EogImage * img,EogImageData req_data)1290 eog_image_has_data (EogImage *img, EogImageData req_data)
1291 {
1292 EogImagePrivate *priv;
1293 gboolean has_data = TRUE;
1294
1295 g_return_val_if_fail (EOG_IS_IMAGE (img), FALSE);
1296
1297 priv = img->priv;
1298
1299 if ((req_data & EOG_IMAGE_DATA_IMAGE) > 0) {
1300 req_data = (req_data & ~EOG_IMAGE_DATA_IMAGE);
1301 has_data = has_data && (priv->image != NULL);
1302 }
1303
1304 if ((req_data & EOG_IMAGE_DATA_DIMENSION) > 0 ) {
1305 req_data = (req_data & ~EOG_IMAGE_DATA_DIMENSION);
1306 has_data = has_data && (priv->width >= 0) && (priv->height >= 0);
1307 }
1308
1309 if ((req_data & EOG_IMAGE_DATA_EXIF) > 0) {
1310 req_data = (req_data & ~EOG_IMAGE_DATA_EXIF);
1311 #ifdef HAVE_EXIF
1312 has_data = has_data && (priv->exif != NULL);
1313 #else
1314 has_data = has_data && (priv->exif_chunk != NULL);
1315 #endif
1316 }
1317
1318 if ((req_data & EOG_IMAGE_DATA_XMP) > 0) {
1319 req_data = (req_data & ~EOG_IMAGE_DATA_XMP);
1320 #ifdef HAVE_EXEMPI
1321 has_data = has_data && (priv->xmp != NULL);
1322 #endif
1323 }
1324
1325 if (req_data != 0) {
1326 g_warning ("Asking for unknown data, remaining: %i\n", req_data);
1327 has_data = FALSE;
1328
1329 }
1330
1331 return has_data;
1332 }
1333
1334 gboolean
eog_image_load(EogImage * img,EogImageData data2read,EogJob * job,GError ** error)1335 eog_image_load (EogImage *img, EogImageData data2read, EogJob *job, GError **error)
1336 {
1337 EogImagePrivate *priv;
1338 gboolean success = FALSE;
1339
1340 eog_debug (DEBUG_IMAGE_LOAD);
1341
1342 g_return_val_if_fail (EOG_IS_IMAGE (img), FALSE);
1343
1344 priv = EOG_IMAGE (img)->priv;
1345
1346 if (data2read == 0) {
1347 return TRUE;
1348 }
1349
1350 if (eog_image_has_data (img, data2read)) {
1351 return TRUE;
1352 }
1353
1354 priv->status = EOG_IMAGE_STATUS_LOADING;
1355
1356 success = eog_image_real_load (img, data2read, job, error);
1357
1358
1359 /* Check that the metadata was loaded at least once before
1360 * trying to autorotate. Also only an image load job should try to
1361 * autorotate an image. */
1362 if (priv->autorotate &&
1363 #ifdef HAVE_EXIF
1364 priv->metadata_status != EOG_IMAGE_METADATA_NOT_READ &&
1365 #endif
1366 data2read & EOG_IMAGE_DATA_IMAGE) {
1367 eog_image_real_autorotate (img);
1368 }
1369
1370 if (success && eog_image_needs_transformation (img)) {
1371 success = eog_image_apply_transformations (img, error);
1372 }
1373
1374 if (success) {
1375 priv->status = EOG_IMAGE_STATUS_LOADED;
1376 } else {
1377 priv->status = EOG_IMAGE_STATUS_FAILED;
1378 }
1379
1380 return success;
1381 }
1382
1383 void
eog_image_set_thumbnail(EogImage * img,GdkPixbuf * thumbnail)1384 eog_image_set_thumbnail (EogImage *img, GdkPixbuf *thumbnail)
1385 {
1386 EogImagePrivate *priv;
1387
1388 g_return_if_fail (EOG_IS_IMAGE (img));
1389 g_return_if_fail (GDK_IS_PIXBUF (thumbnail) || thumbnail == NULL);
1390
1391 priv = img->priv;
1392
1393 if (priv->thumbnail != NULL) {
1394 g_object_unref (priv->thumbnail);
1395 priv->thumbnail = NULL;
1396 }
1397
1398 if (thumbnail != NULL && priv->trans != NULL) {
1399 priv->thumbnail = eog_transform_apply (priv->trans, thumbnail, NULL);
1400 } else {
1401 priv->thumbnail = thumbnail;
1402
1403 if (thumbnail != NULL) {
1404 g_object_ref (priv->thumbnail);
1405 }
1406 }
1407
1408 if (priv->thumbnail != NULL) {
1409 g_signal_emit (img, signals[SIGNAL_THUMBNAIL_CHANGED], 0);
1410 }
1411 }
1412
1413 /**
1414 * eog_image_get_pixbuf:
1415 * @img: a #EogImage
1416 *
1417 * Gets the #GdkPixbuf of the image
1418 *
1419 * Returns: (transfer full): a #GdkPixbuf
1420 **/
1421 GdkPixbuf *
eog_image_get_pixbuf(EogImage * img)1422 eog_image_get_pixbuf (EogImage *img)
1423 {
1424 GdkPixbuf *image = NULL;
1425
1426 g_return_val_if_fail (EOG_IS_IMAGE (img), NULL);
1427
1428 g_mutex_lock (&img->priv->status_mutex);
1429 image = img->priv->image;
1430 g_mutex_unlock (&img->priv->status_mutex);
1431
1432 if (image != NULL) {
1433 g_object_ref (image);
1434 }
1435
1436 return image;
1437 }
1438
1439 #ifdef HAVE_LCMS
1440 cmsHPROFILE
eog_image_get_profile(EogImage * img)1441 eog_image_get_profile (EogImage *img)
1442 {
1443 g_return_val_if_fail (EOG_IS_IMAGE (img), NULL);
1444
1445 return img->priv->profile;
1446 }
1447 #endif
1448
1449 /**
1450 * eog_image_get_thumbnail:
1451 * @img: a #EogImage
1452 *
1453 * Gets the thumbnail pixbuf for @img
1454 *
1455 * Returns: (transfer full): a #GdkPixbuf with a thumbnail
1456 **/
1457 GdkPixbuf *
eog_image_get_thumbnail(EogImage * img)1458 eog_image_get_thumbnail (EogImage *img)
1459 {
1460 g_return_val_if_fail (EOG_IS_IMAGE (img), NULL);
1461
1462 if (img->priv->thumbnail != NULL) {
1463 return g_object_ref (img->priv->thumbnail);
1464 }
1465
1466 return NULL;
1467 }
1468
1469 void
eog_image_get_size(EogImage * img,int * width,int * height)1470 eog_image_get_size (EogImage *img, int *width, int *height)
1471 {
1472 EogImagePrivate *priv;
1473
1474 g_return_if_fail (EOG_IS_IMAGE (img));
1475
1476 priv = img->priv;
1477
1478 *width = priv->width;
1479 *height = priv->height;
1480 }
1481
1482 void
eog_image_transform(EogImage * img,EogTransform * trans,EogJob * job)1483 eog_image_transform (EogImage *img, EogTransform *trans, EogJob *job)
1484 {
1485 eog_image_real_transform (img, trans, FALSE, job);
1486 }
1487
1488 void
eog_image_undo(EogImage * img)1489 eog_image_undo (EogImage *img)
1490 {
1491 EogImagePrivate *priv;
1492 EogTransform *trans;
1493 EogTransform *inverse;
1494
1495 g_return_if_fail (EOG_IS_IMAGE (img));
1496
1497 priv = img->priv;
1498
1499 if (priv->undo_stack != NULL) {
1500 trans = EOG_TRANSFORM (priv->undo_stack->data);
1501
1502 inverse = eog_transform_reverse (trans);
1503
1504 eog_image_real_transform (img, inverse, TRUE, NULL);
1505
1506 priv->undo_stack = g_slist_delete_link (priv->undo_stack, priv->undo_stack);
1507
1508 g_object_unref (trans);
1509 g_object_unref (inverse);
1510
1511 if (eog_transform_is_identity (priv->trans)) {
1512 g_object_unref (priv->trans);
1513 priv->trans = NULL;
1514 }
1515 }
1516
1517 priv->modified = (priv->undo_stack != NULL);
1518 }
1519
1520 static GFile *
tmp_file_get(void)1521 tmp_file_get (void)
1522 {
1523 GFile *tmp_file;
1524 char *tmp_file_path;
1525 gint fd;
1526
1527 tmp_file_path = g_build_filename (g_get_tmp_dir (), "eog-save-XXXXXX", NULL);
1528 fd = g_mkstemp (tmp_file_path);
1529 if (fd == -1) {
1530 g_free (tmp_file_path);
1531 return NULL;
1532 }
1533 else {
1534 tmp_file = g_file_new_for_path (tmp_file_path);
1535 g_free (tmp_file_path);
1536 return tmp_file;
1537 }
1538 }
1539
1540 static void
transfer_progress_cb(goffset cur_bytes,goffset total_bytes,gpointer user_data)1541 transfer_progress_cb (goffset cur_bytes,
1542 goffset total_bytes,
1543 gpointer user_data)
1544 {
1545 EogImage *image = EOG_IMAGE (user_data);
1546
1547 if (cur_bytes > 0) {
1548 g_signal_emit (G_OBJECT(image),
1549 signals[SIGNAL_SAVE_PROGRESS],
1550 0,
1551 (gfloat) cur_bytes / (gfloat) total_bytes);
1552 }
1553 }
1554
1555 static void
tmp_file_restore_unix_attributes(GFile * temp_file,GFile * target_file)1556 tmp_file_restore_unix_attributes (GFile *temp_file,
1557 GFile *target_file)
1558 {
1559 GFileInfo *file_info;
1560 guint uid;
1561 guint gid;
1562 guint mode;
1563 guint mode_mask = 00600;
1564
1565 GError *error = NULL;
1566
1567 g_return_if_fail (G_IS_FILE (temp_file));
1568 g_return_if_fail (G_IS_FILE (target_file));
1569
1570 /* check if file exists */
1571 if (!g_file_query_exists (target_file, NULL)) {
1572 eog_debug_message (DEBUG_IMAGE_SAVE,
1573 "Target file doesn't exist. Setting default attributes.");
1574 return;
1575 }
1576
1577 /* retrieve UID, GID, and MODE of the original file info */
1578 file_info = g_file_query_info (target_file,
1579 "unix::uid,unix::gid,unix::mode",
1580 G_FILE_QUERY_INFO_NONE,
1581 NULL,
1582 &error);
1583
1584 /* check that there aren't any error */
1585 if (error != NULL) {
1586 eog_debug_message (DEBUG_IMAGE_SAVE,
1587 "File information not available. Setting default attributes.");
1588
1589 /* free objects */
1590 g_object_unref (file_info);
1591 g_clear_error (&error);
1592
1593 return;
1594 }
1595
1596 /* save UID, GID and MODE values */
1597 uid = g_file_info_get_attribute_uint32 (file_info,
1598 G_FILE_ATTRIBUTE_UNIX_UID);
1599
1600 gid = g_file_info_get_attribute_uint32 (file_info,
1601 G_FILE_ATTRIBUTE_UNIX_GID);
1602
1603 mode = g_file_info_get_attribute_uint32 (file_info,
1604 G_FILE_ATTRIBUTE_UNIX_MODE);
1605
1606 /* apply default mode mask to file mode */
1607 mode |= mode_mask;
1608
1609 /* restore original UID, GID, and MODE into the temporal file */
1610 g_file_set_attribute_uint32 (temp_file,
1611 G_FILE_ATTRIBUTE_UNIX_UID,
1612 uid,
1613 G_FILE_QUERY_INFO_NONE,
1614 NULL,
1615 &error);
1616
1617 /* check that there aren't any error */
1618 if (error != NULL) {
1619 eog_debug_message (DEBUG_IMAGE_SAVE,
1620 "You do not have the permissions necessary to change the file UID.");
1621
1622 g_clear_error (&error);
1623 }
1624
1625 g_file_set_attribute_uint32 (temp_file,
1626 G_FILE_ATTRIBUTE_UNIX_GID,
1627 gid,
1628 G_FILE_QUERY_INFO_NONE,
1629 NULL,
1630 &error);
1631
1632 /* check that there aren't any error */
1633 if (error != NULL) {
1634 eog_debug_message (DEBUG_IMAGE_SAVE,
1635 "You do not have the permissions necessary to change the file GID. Setting user default GID.");
1636
1637 g_clear_error (&error);
1638 }
1639
1640 g_file_set_attribute_uint32 (temp_file,
1641 G_FILE_ATTRIBUTE_UNIX_MODE,
1642 mode,
1643 G_FILE_QUERY_INFO_NONE,
1644 NULL,
1645 &error);
1646
1647 /* check that there aren't any error */
1648 if (error != NULL) {
1649 eog_debug_message (DEBUG_IMAGE_SAVE,
1650 "You do not have the permissions necessary to change the file MODE.");
1651
1652 g_clear_error (&error);
1653 }
1654
1655 /* free objects */
1656 g_object_unref (file_info);
1657 }
1658
1659 static gboolean
tmp_file_move_to_uri(EogImage * image,GFile * tmpfile,GFile * file,gboolean overwrite,GError ** error)1660 tmp_file_move_to_uri (EogImage *image,
1661 GFile *tmpfile,
1662 GFile *file,
1663 gboolean overwrite,
1664 GError **error)
1665 {
1666 gboolean result;
1667 GError *ioerror = NULL;
1668
1669 /* try to restore target file unix attributes */
1670 tmp_file_restore_unix_attributes (tmpfile, file);
1671
1672 /* replace target file with temporal file */
1673 result = g_file_move (tmpfile,
1674 file,
1675 (overwrite ? G_FILE_COPY_OVERWRITE : 0) |
1676 G_FILE_COPY_ALL_METADATA,
1677 NULL,
1678 (GFileProgressCallback) transfer_progress_cb,
1679 image,
1680 &ioerror);
1681
1682 if (result == FALSE) {
1683 if (g_error_matches (ioerror, G_IO_ERROR,
1684 G_IO_ERROR_EXISTS)) {
1685 g_set_error (error, EOG_IMAGE_ERROR,
1686 EOG_IMAGE_ERROR_FILE_EXISTS,
1687 "File exists");
1688 } else {
1689 g_set_error (error, EOG_IMAGE_ERROR,
1690 EOG_IMAGE_ERROR_VFS,
1691 "VFS error moving the temp file");
1692 }
1693 g_clear_error (&ioerror);
1694 }
1695
1696 return result;
1697 }
1698
1699 static gboolean
tmp_file_delete(GFile * tmpfile)1700 tmp_file_delete (GFile *tmpfile)
1701 {
1702 gboolean result;
1703 GError *err = NULL;
1704
1705 if (tmpfile == NULL) return FALSE;
1706
1707 result = g_file_delete (tmpfile, NULL, &err);
1708 if (result == FALSE) {
1709 char *tmpfile_path;
1710 if (err != NULL) {
1711 if (err->code == G_IO_ERROR_NOT_FOUND) {
1712 g_error_free (err);
1713 return TRUE;
1714 }
1715 g_error_free (err);
1716 }
1717 tmpfile_path = g_file_get_path (tmpfile);
1718 g_warning ("Couldn't delete temporary file: %s", tmpfile_path);
1719 g_free (tmpfile_path);
1720 }
1721
1722 return result;
1723 }
1724
1725 static void
eog_image_reset_modifications(EogImage * image)1726 eog_image_reset_modifications (EogImage *image)
1727 {
1728 EogImagePrivate *priv;
1729
1730 g_return_if_fail (EOG_IS_IMAGE (image));
1731
1732 priv = image->priv;
1733
1734 g_slist_foreach (priv->undo_stack, (GFunc) g_object_unref, NULL);
1735 g_slist_free (priv->undo_stack);
1736 priv->undo_stack = NULL;
1737
1738 if (priv->trans != NULL) {
1739 g_object_unref (priv->trans);
1740 priv->trans = NULL;
1741 }
1742
1743 if (priv->trans_autorotate != NULL) {
1744 g_object_unref (priv->trans_autorotate);
1745 priv->trans_autorotate = NULL;
1746 }
1747
1748 priv->modified = FALSE;
1749 }
1750
1751 static void
eog_image_link_with_target(EogImage * image,EogImageSaveInfo * target)1752 eog_image_link_with_target (EogImage *image, EogImageSaveInfo *target)
1753 {
1754 EogImagePrivate *priv;
1755
1756 g_return_if_fail (EOG_IS_IMAGE (image));
1757 g_return_if_fail (EOG_IS_IMAGE_SAVE_INFO (target));
1758
1759 priv = image->priv;
1760
1761 /* update file location */
1762 if (priv->file != NULL) {
1763 g_object_unref (priv->file);
1764 }
1765 priv->file = g_object_ref (target->file);
1766
1767 /* Clear caption and caption key, these will be
1768 * updated on next eog_image_get_caption call.
1769 */
1770 if (priv->caption != NULL) {
1771 g_free (priv->caption);
1772 priv->caption = NULL;
1773 }
1774 if (priv->collate_key != NULL) {
1775 g_free (priv->collate_key);
1776 priv->collate_key = NULL;
1777 }
1778
1779 /* update file format */
1780 if (priv->file_type != NULL) {
1781 g_free (priv->file_type);
1782 }
1783 priv->file_type = g_strdup (target->format);
1784 }
1785
1786 static gboolean
check_if_file_is_writable(GFile * file)1787 check_if_file_is_writable (GFile *file)
1788 {
1789 GFile *file_to_check;
1790 GFileInfo *file_info;
1791 GError *error = NULL;
1792 gboolean is_writable, has_writable;
1793
1794 g_return_val_if_fail (G_IS_FILE (file), FALSE);
1795
1796 /* check if file exists */
1797 if (!g_file_query_exists (file, NULL)) {
1798 eog_debug_message (DEBUG_IMAGE_SAVE, "File doesn't exist. "
1799 "Checking parent directory.");
1800
1801 file_to_check = g_file_get_parent (file);
1802 } else {
1803 /* Add another ref so we don't need to split between file and
1804 * parent file again after querying and can simply unref it. */
1805 file_to_check = g_object_ref (file);
1806 }
1807
1808 /* recover file information */
1809 file_info = g_file_query_info (file_to_check,
1810 G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE,
1811 G_FILE_QUERY_INFO_NONE,
1812 NULL,
1813 &error);
1814
1815 /* we assume that the image can't be saved when
1816 we can't retrieve any file information */
1817 if (G_UNLIKELY (file_info == NULL)) {
1818 eog_debug_message (DEBUG_IMAGE_SAVE,
1819 "Couldn't query file info: %s",
1820 error->message);
1821 g_error_free (error);
1822 g_object_unref (file_to_check);
1823 return FALSE;
1824 }
1825
1826 /* check if file can be written */
1827 has_writable = g_file_info_has_attribute (file_info,
1828 G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE);
1829 if (has_writable) {
1830 is_writable = g_file_info_get_attribute_boolean (file_info,
1831 G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE);
1832 } else {
1833 /* try writing the file when the writable attribute is absent */
1834 is_writable = TRUE;
1835 }
1836
1837 /* free objects */
1838 g_object_unref (file_info);
1839 g_object_unref (file_to_check);
1840
1841 return is_writable;
1842 }
1843
1844 gboolean
eog_image_save_by_info(EogImage * img,EogImageSaveInfo * source,GError ** error)1845 eog_image_save_by_info (EogImage *img, EogImageSaveInfo *source, GError **error)
1846 {
1847 EogImagePrivate *priv;
1848 EogImageStatus prev_status;
1849 gboolean success = FALSE;
1850 GFile *tmp_file;
1851 char *tmp_file_path;
1852
1853 g_return_val_if_fail (EOG_IS_IMAGE (img), FALSE);
1854 g_return_val_if_fail (EOG_IS_IMAGE_SAVE_INFO (source), FALSE);
1855
1856 priv = img->priv;
1857
1858 prev_status = priv->status;
1859
1860 /* Image is now being saved */
1861 priv->status = EOG_IMAGE_STATUS_SAVING;
1862
1863 /* see if we need any saving at all */
1864 if (source->exists && !source->modified) {
1865 return TRUE;
1866 }
1867
1868 /* fail if there is no image to save */
1869 if (priv->image == NULL) {
1870 g_set_error (error, EOG_IMAGE_ERROR,
1871 EOG_IMAGE_ERROR_NOT_LOADED,
1872 _("No image loaded."));
1873 return FALSE;
1874 }
1875
1876 /* fail if there is not write rights to save */
1877 if (!check_if_file_is_writable (priv->file)) {
1878 g_set_error (error, EOG_IMAGE_ERROR,
1879 EOG_IMAGE_ERROR_NOT_SAVED,
1880 _("You do not have the permissions necessary to save the file."));
1881 return FALSE;
1882 }
1883
1884 /* generate temporary file */
1885 tmp_file = tmp_file_get ();
1886
1887 if (tmp_file == NULL) {
1888 g_set_error (error, EOG_IMAGE_ERROR,
1889 EOG_IMAGE_ERROR_TMP_FILE_FAILED,
1890 _("Temporary file creation failed."));
1891 return FALSE;
1892 }
1893
1894 tmp_file_path = g_file_get_path (tmp_file);
1895
1896 #ifdef HAVE_JPEG
1897 /* determine kind of saving */
1898 if ((g_ascii_strcasecmp (source->format, EOG_FILE_FORMAT_JPEG) == 0) &&
1899 source->exists && source->modified)
1900 {
1901 success = eog_image_jpeg_save_file (img, tmp_file_path, source, NULL, error);
1902 }
1903 #endif
1904
1905 if (!success && (*error == NULL)) {
1906 success = gdk_pixbuf_save (priv->image, tmp_file_path, source->format, error, NULL);
1907 }
1908
1909 if (success) {
1910 /* try to move result file to target uri */
1911 success = tmp_file_move_to_uri (img, tmp_file, priv->file, TRUE /*overwrite*/, error);
1912 }
1913
1914 if (success) {
1915 eog_image_reset_modifications (img);
1916 }
1917
1918 tmp_file_delete (tmp_file);
1919
1920 g_free (tmp_file_path);
1921 g_object_unref (tmp_file);
1922
1923 priv->status = prev_status;
1924
1925 return success;
1926 }
1927
1928 static gboolean
eog_image_copy_file(EogImage * image,EogImageSaveInfo * source,EogImageSaveInfo * target,GError ** error)1929 eog_image_copy_file (EogImage *image, EogImageSaveInfo *source, EogImageSaveInfo *target, GError **error)
1930 {
1931 gboolean result;
1932 GError *ioerror = NULL;
1933
1934 g_return_val_if_fail (EOG_IS_IMAGE_SAVE_INFO (source), FALSE);
1935 g_return_val_if_fail (EOG_IS_IMAGE_SAVE_INFO (target), FALSE);
1936
1937 /* copy the image */
1938 result = g_file_copy (source->file,
1939 target->file,
1940 (target->overwrite ? G_FILE_COPY_OVERWRITE : 0) |
1941 G_FILE_COPY_ALL_METADATA,
1942 NULL,
1943 EOG_IS_IMAGE (image) ? transfer_progress_cb :NULL,
1944 image,
1945 &ioerror);
1946
1947 if (result == FALSE) {
1948 if (ioerror->code == G_IO_ERROR_EXISTS) {
1949 g_set_error (error, EOG_IMAGE_ERROR,
1950 EOG_IMAGE_ERROR_FILE_EXISTS,
1951 "%s", ioerror->message);
1952 } else {
1953 g_set_error (error, EOG_IMAGE_ERROR,
1954 EOG_IMAGE_ERROR_VFS,
1955 "%s", ioerror->message);
1956 }
1957 g_error_free (ioerror);
1958 } else {
1959 /* reset NAUTILUS-ICON-POSITION metadata attribute */
1960 g_file_set_attribute (target->file,
1961 "metadata::nautilus-icon-position",
1962 G_FILE_ATTRIBUTE_TYPE_INVALID,
1963 NULL,
1964 G_FILE_QUERY_INFO_NONE,
1965 NULL,
1966 NULL);
1967 }
1968
1969 return result;
1970 }
1971
1972 gboolean
eog_image_save_as_by_info(EogImage * img,EogImageSaveInfo * source,EogImageSaveInfo * target,GError ** error)1973 eog_image_save_as_by_info (EogImage *img, EogImageSaveInfo *source, EogImageSaveInfo *target, GError **error)
1974 {
1975 EogImagePrivate *priv;
1976 gboolean success = FALSE;
1977 char *tmp_file_path;
1978 GFile *tmp_file;
1979 gboolean direct_copy = FALSE;
1980
1981 g_return_val_if_fail (EOG_IS_IMAGE (img), FALSE);
1982 g_return_val_if_fail (EOG_IS_IMAGE_SAVE_INFO (source), FALSE);
1983 g_return_val_if_fail (EOG_IS_IMAGE_SAVE_INFO (target), FALSE);
1984
1985 priv = img->priv;
1986
1987 /* fail if there is no image to save */
1988 if (priv->image == NULL) {
1989 g_set_error (error,
1990 EOG_IMAGE_ERROR,
1991 EOG_IMAGE_ERROR_NOT_LOADED,
1992 _("No image loaded."));
1993
1994 return FALSE;
1995 }
1996
1997 /* fail if there is not write rights to save on target */
1998 if (!check_if_file_is_writable (target->file)) {
1999 g_set_error (error, EOG_IMAGE_ERROR,
2000 EOG_IMAGE_ERROR_NOT_SAVED,
2001 _("You do not have the permissions necessary to save the file."));
2002 return FALSE;
2003 }
2004
2005 /* generate temporary file name */
2006 tmp_file = tmp_file_get ();
2007
2008 if (tmp_file == NULL) {
2009 g_set_error (error,
2010 EOG_IMAGE_ERROR,
2011 EOG_IMAGE_ERROR_TMP_FILE_FAILED,
2012 _("Temporary file creation failed."));
2013
2014 return FALSE;
2015 }
2016 tmp_file_path = g_file_get_path (tmp_file);
2017
2018 /* determine kind of saving */
2019 if (g_ascii_strcasecmp (source->format, target->format) == 0 && !source->modified) {
2020 success = eog_image_copy_file (img, source, target, error);
2021 direct_copy = success;
2022 }
2023
2024 #ifdef HAVE_JPEG
2025 else if ((g_ascii_strcasecmp (source->format, EOG_FILE_FORMAT_JPEG) == 0 && source->exists) ||
2026 (g_ascii_strcasecmp (target->format, EOG_FILE_FORMAT_JPEG) == 0))
2027 {
2028 success = eog_image_jpeg_save_file (img, tmp_file_path, source, target, error);
2029 }
2030 #endif
2031
2032 if (!success && (*error == NULL)) {
2033 success = gdk_pixbuf_save (priv->image, tmp_file_path, target->format, error, NULL);
2034 }
2035
2036 if (success && !direct_copy) { /* not required if we already copied the file directly */
2037 /* try to move result file to target uri */
2038 success = tmp_file_move_to_uri (img, tmp_file, target->file, target->overwrite, error);
2039 }
2040
2041 if (success) {
2042 /* update image information to new uri */
2043 eog_image_reset_modifications (img);
2044 eog_image_link_with_target (img, target);
2045 }
2046
2047 tmp_file_delete (tmp_file);
2048 g_object_unref (tmp_file);
2049 g_free (tmp_file_path);
2050
2051 priv->status = EOG_IMAGE_STATUS_UNKNOWN;
2052
2053 return success;
2054 }
2055
2056 /*
2057 * This function is inspired by
2058 * nautilus/libnautilus-private/nautilus-file.c:nautilus_file_get_display_name_nocopy
2059 * Revision: 1.309
2060 * Author: Darin Adler <darin@bentspoon.com>
2061 */
2062 const gchar*
eog_image_get_caption(EogImage * img)2063 eog_image_get_caption (EogImage *img)
2064 {
2065 EogImagePrivate *priv;
2066 GFileInfo *info;
2067
2068 g_return_val_if_fail (EOG_IS_IMAGE (img), NULL);
2069
2070 priv = img->priv;
2071
2072 if (priv->file == NULL) return NULL;
2073
2074 if (priv->caption != NULL)
2075 /* Use cached caption string */
2076 return priv->caption;
2077
2078 info = g_file_query_info (priv->file,
2079 G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
2080 G_FILE_QUERY_INFO_NONE,
2081 NULL,
2082 NULL);
2083
2084 if (G_LIKELY (info != NULL))
2085 {
2086 priv->caption = g_strdup (g_file_info_get_display_name (info));
2087 g_object_unref(info);
2088 }
2089
2090 if (G_UNLIKELY (priv->caption == NULL)) {
2091 char *short_str;
2092
2093 short_str = g_file_get_basename (priv->file);
2094 if (g_utf8_validate (short_str, -1, NULL)) {
2095 priv->caption = g_strdup (short_str);
2096 } else {
2097 priv->caption = g_filename_to_utf8 (short_str, -1, NULL, NULL, NULL);
2098 }
2099 g_free (short_str);
2100 }
2101
2102 return priv->caption;
2103 }
2104
2105 const gchar*
eog_image_get_collate_key(EogImage * img)2106 eog_image_get_collate_key (EogImage *img)
2107 {
2108 EogImagePrivate *priv;
2109
2110 g_return_val_if_fail (EOG_IS_IMAGE (img), NULL);
2111
2112 priv = img->priv;
2113
2114 if (priv->collate_key == NULL) {
2115 const char *caption;
2116
2117 caption = eog_image_get_caption (img);
2118
2119 priv->collate_key = g_utf8_collate_key_for_filename (caption, -1);
2120 }
2121
2122 return priv->collate_key;
2123 }
2124
2125 void
eog_image_cancel_load(EogImage * img)2126 eog_image_cancel_load (EogImage *img)
2127 {
2128 EogImagePrivate *priv;
2129
2130 g_return_if_fail (EOG_IS_IMAGE (img));
2131
2132 priv = img->priv;
2133
2134 g_mutex_lock (&priv->status_mutex);
2135
2136 if (priv->status == EOG_IMAGE_STATUS_LOADING) {
2137 priv->cancel_loading = TRUE;
2138 }
2139
2140 g_mutex_unlock (&priv->status_mutex);
2141 }
2142
2143 #ifdef HAVE_EXIF
2144 ExifData *
eog_image_get_exif_info(EogImage * img)2145 eog_image_get_exif_info (EogImage *img)
2146 {
2147 EogImagePrivate *priv;
2148 ExifData *data = NULL;
2149
2150 g_return_val_if_fail (EOG_IS_IMAGE (img), NULL);
2151
2152 priv = img->priv;
2153
2154 g_mutex_lock (&priv->status_mutex);
2155
2156 exif_data_ref (priv->exif);
2157 data = priv->exif;
2158
2159 g_mutex_unlock (&priv->status_mutex);
2160
2161 return data;
2162 }
2163 #endif
2164
2165 /**
2166 * eog_image_get_xmp_info:
2167 * @img: a #EogImage
2168 *
2169 * Gets the XMP info for @img or NULL if compiled without
2170 * libexempi support.
2171 *
2172 * Returns: (transfer full): the xmp data
2173 **/
2174 gpointer
eog_image_get_xmp_info(EogImage * img)2175 eog_image_get_xmp_info (EogImage *img)
2176 {
2177 gpointer data = NULL;
2178
2179 g_return_val_if_fail (EOG_IS_IMAGE (img), NULL);
2180
2181 #ifdef HAVE_EXEMPI
2182 EogImagePrivate *priv;
2183 priv = img->priv;
2184
2185 g_mutex_lock (&priv->status_mutex);
2186 data = (gpointer) xmp_copy (priv->xmp);
2187 g_mutex_unlock (&priv->status_mutex);
2188 #endif
2189
2190 return data;
2191 }
2192
2193
2194 /**
2195 * eog_image_get_file:
2196 * @img: a #EogImage
2197 *
2198 * Gets the #GFile associated with @img
2199 *
2200 * Returns: (transfer full): a #GFile
2201 **/
2202 GFile *
eog_image_get_file(EogImage * img)2203 eog_image_get_file (EogImage *img)
2204 {
2205 g_return_val_if_fail (EOG_IS_IMAGE (img), NULL);
2206
2207 return g_object_ref (img->priv->file);
2208 }
2209
2210 gboolean
eog_image_is_modified(EogImage * img)2211 eog_image_is_modified (EogImage *img)
2212 {
2213 g_return_val_if_fail (EOG_IS_IMAGE (img), FALSE);
2214
2215 return img->priv->modified;
2216 }
2217
2218 goffset
eog_image_get_bytes(EogImage * img)2219 eog_image_get_bytes (EogImage *img)
2220 {
2221 g_return_val_if_fail (EOG_IS_IMAGE (img), 0);
2222
2223 return img->priv->bytes;
2224 }
2225
2226 void
eog_image_modified(EogImage * img)2227 eog_image_modified (EogImage *img)
2228 {
2229 g_return_if_fail (EOG_IS_IMAGE (img));
2230
2231 g_signal_emit (G_OBJECT (img), signals[SIGNAL_CHANGED], 0);
2232 }
2233
2234 gchar*
eog_image_get_uri_for_display(EogImage * img)2235 eog_image_get_uri_for_display (EogImage *img)
2236 {
2237 EogImagePrivate *priv;
2238 gchar *uri_str = NULL;
2239 gchar *str = NULL;
2240
2241 g_return_val_if_fail (EOG_IS_IMAGE (img), NULL);
2242
2243 priv = img->priv;
2244
2245 if (priv->file != NULL) {
2246 uri_str = g_file_get_uri (priv->file);
2247
2248 if (uri_str != NULL) {
2249 str = g_uri_unescape_string (uri_str, NULL);
2250 g_free (uri_str);
2251 }
2252 }
2253
2254 return str;
2255 }
2256
2257 EogImageStatus
eog_image_get_status(EogImage * img)2258 eog_image_get_status (EogImage *img)
2259 {
2260 g_return_val_if_fail (EOG_IS_IMAGE (img), EOG_IMAGE_STATUS_UNKNOWN);
2261
2262 return img->priv->status;
2263 }
2264
2265 /**
2266 * eog_image_get_metadata_status:
2267 * @img: a #EogImage
2268 *
2269 * Returns the current status of the image metadata, that is,
2270 * whether the metadata has not been read yet, is ready, or not available at all.
2271 *
2272 * Returns: one of #EogImageMetadataStatus
2273 **/
2274 EogImageMetadataStatus
eog_image_get_metadata_status(EogImage * img)2275 eog_image_get_metadata_status (EogImage *img)
2276 {
2277 g_return_val_if_fail (EOG_IS_IMAGE (img), EOG_IMAGE_METADATA_NOT_AVAILABLE);
2278
2279 return img->priv->metadata_status;
2280 }
2281
2282 void
eog_image_data_ref(EogImage * img)2283 eog_image_data_ref (EogImage *img)
2284 {
2285 g_return_if_fail (EOG_IS_IMAGE (img));
2286
2287 g_object_ref (G_OBJECT (img));
2288 img->priv->data_ref_count++;
2289
2290 g_assert (img->priv->data_ref_count <= G_OBJECT (img)->ref_count);
2291 }
2292
2293 void
eog_image_data_unref(EogImage * img)2294 eog_image_data_unref (EogImage *img)
2295 {
2296 g_return_if_fail (EOG_IS_IMAGE (img));
2297
2298 if (img->priv->data_ref_count > 0) {
2299 img->priv->data_ref_count--;
2300 } else {
2301 g_warning ("More image data unrefs than refs.");
2302 }
2303
2304 if (img->priv->data_ref_count == 0) {
2305 eog_image_free_mem_private (img);
2306 }
2307
2308 g_object_unref (G_OBJECT (img));
2309
2310 g_assert (img->priv->data_ref_count <= G_OBJECT (img)->ref_count);
2311 }
2312
2313 static gint
compare_quarks(gconstpointer a,gconstpointer b)2314 compare_quarks (gconstpointer a, gconstpointer b)
2315 {
2316 GQuark quark;
2317
2318 quark = g_quark_from_string ((const gchar *) a);
2319
2320 return quark - GPOINTER_TO_INT (b);
2321 }
2322
2323 /**
2324 * eog_image_get_supported_mime_types:
2325 *
2326 * Gets the list of supported mimetypes
2327 *
2328 * Returns: (transfer none)(element-type utf8): a #GList of supported mimetypes
2329 **/
2330 GList *
eog_image_get_supported_mime_types(void)2331 eog_image_get_supported_mime_types (void)
2332 {
2333 GSList *format_list, *it;
2334 gchar **mime_types;
2335 int i;
2336
2337 if (!supported_mime_types) {
2338 format_list = gdk_pixbuf_get_formats ();
2339
2340 for (it = format_list; it != NULL; it = it->next) {
2341 mime_types =
2342 gdk_pixbuf_format_get_mime_types ((GdkPixbufFormat *) it->data);
2343
2344 for (i = 0; mime_types[i] != NULL; i++) {
2345 supported_mime_types =
2346 g_list_prepend (supported_mime_types,
2347 g_strdup (mime_types[i]));
2348 }
2349
2350 g_strfreev (mime_types);
2351 }
2352
2353 supported_mime_types = g_list_sort (supported_mime_types,
2354 (GCompareFunc) compare_quarks);
2355
2356 g_slist_free (format_list);
2357 }
2358
2359 return supported_mime_types;
2360 }
2361
2362 gboolean
eog_image_is_supported_mime_type(const char * mime_type)2363 eog_image_is_supported_mime_type (const char *mime_type)
2364 {
2365 GList *supported_mime_types, *result;
2366 GQuark quark;
2367
2368 if (mime_type == NULL) {
2369 return FALSE;
2370 }
2371
2372 supported_mime_types = eog_image_get_supported_mime_types ();
2373
2374 quark = g_quark_from_string (mime_type);
2375
2376 result = g_list_find_custom (supported_mime_types,
2377 GINT_TO_POINTER (quark),
2378 (GCompareFunc) compare_quarks);
2379
2380 return (result != NULL);
2381 }
2382
2383 static gboolean
eog_image_iter_advance(EogImage * img)2384 eog_image_iter_advance (EogImage *img)
2385 {
2386 EogImagePrivate *priv;
2387 gboolean new_frame;
2388
2389 g_return_val_if_fail (EOG_IS_IMAGE (img), FALSE);
2390 g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION_ITER (img->priv->anim_iter), FALSE);
2391
2392 priv = img->priv;
2393
2394 if ((new_frame = gdk_pixbuf_animation_iter_advance (img->priv->anim_iter, NULL)) == TRUE)
2395 {
2396 g_mutex_lock (&priv->status_mutex);
2397 g_object_unref (priv->image);
2398 priv->image = gdk_pixbuf_animation_iter_get_pixbuf (priv->anim_iter);
2399 g_object_ref (priv->image);
2400 /* keep the transformation over time */
2401 if (EOG_IS_TRANSFORM (priv->trans)) {
2402 GdkPixbuf* transformed = eog_transform_apply (priv->trans, priv->image, NULL);
2403 g_object_unref (priv->image);
2404 priv->image = transformed;
2405 priv->width = gdk_pixbuf_get_width (transformed);
2406 priv->height = gdk_pixbuf_get_height (transformed);
2407 }
2408 g_mutex_unlock (&priv->status_mutex);
2409 /* Emit next frame signal so we can update the display */
2410 g_signal_emit (img, signals[SIGNAL_NEXT_FRAME], 0,
2411 gdk_pixbuf_animation_iter_get_delay_time (priv->anim_iter));
2412 }
2413
2414 return new_frame;
2415 }
2416
2417 /**
2418 * eog_image_is_animation:
2419 * @img: a #EogImage
2420 *
2421 * Checks whether a given image is animated.
2422 *
2423 * Returns: #TRUE if it is an animated image, #FALSE otherwise.
2424 *
2425 **/
2426 gboolean
eog_image_is_animation(EogImage * img)2427 eog_image_is_animation (EogImage *img)
2428 {
2429 g_return_val_if_fail (EOG_IS_IMAGE (img), FALSE);
2430 return img->priv->anim != NULL;
2431 }
2432
2433 static gboolean
private_timeout(gpointer data)2434 private_timeout (gpointer data)
2435 {
2436 EogImage *img = EOG_IMAGE (data);
2437 EogImagePrivate *priv = img->priv;
2438
2439 if (eog_image_is_animation (img) &&
2440 !g_source_is_destroyed (g_main_current_source ()) &&
2441 priv->is_playing) {
2442 while (eog_image_iter_advance (img) != TRUE) {}; /* cpu-sucking ? */
2443 priv->anim_source = g_timeout_add (
2444 gdk_pixbuf_animation_iter_get_delay_time (priv->anim_iter),
2445 private_timeout, img);
2446 return FALSE;
2447 }
2448 priv->is_playing = FALSE;
2449 priv->anim_source = 0;
2450 return FALSE; /* stop playing */
2451 }
2452
2453 /**
2454 * eog_image_start_animation:
2455 * @img: a #EogImage
2456 *
2457 * Starts playing an animated image.
2458 *
2459 * Returns: %TRUE on success, %FALSE if @img is already playing or isn't an animated image.
2460 **/
2461 gboolean
eog_image_start_animation(EogImage * img)2462 eog_image_start_animation (EogImage *img)
2463 {
2464 EogImagePrivate *priv;
2465
2466 g_return_val_if_fail (EOG_IS_IMAGE (img), FALSE);
2467 priv = img->priv;
2468
2469 if (!eog_image_is_animation (img) || priv->is_playing)
2470 return FALSE;
2471
2472 g_mutex_lock (&priv->status_mutex);
2473 g_object_ref (priv->anim_iter);
2474 priv->is_playing = TRUE;
2475 g_mutex_unlock (&priv->status_mutex);
2476
2477 priv->anim_source =
2478 g_timeout_add (gdk_pixbuf_animation_iter_get_delay_time (priv->anim_iter),
2479 private_timeout, img);
2480
2481 return TRUE;
2482 }
2483
2484 #ifdef HAVE_RSVG
2485 gboolean
eog_image_is_svg(EogImage * img)2486 eog_image_is_svg (EogImage *img)
2487 {
2488 g_return_val_if_fail (EOG_IS_IMAGE (img), FALSE);
2489
2490 return (img->priv->svg != NULL);
2491 }
2492
2493 RsvgHandle *
eog_image_get_svg(EogImage * img)2494 eog_image_get_svg (EogImage *img)
2495 {
2496 g_return_val_if_fail (EOG_IS_IMAGE (img), NULL);
2497
2498 return img->priv->svg;
2499 }
2500 #endif
2501
2502 /**
2503 * eog_image_get_transform:
2504 * @img: a #EogImage
2505 *
2506 * Get @img transform.
2507 *
2508 * Returns: (transfer none): A #EogTransform.
2509 */
2510
2511 EogTransform *
eog_image_get_transform(EogImage * img)2512 eog_image_get_transform (EogImage *img)
2513 {
2514 g_return_val_if_fail (EOG_IS_IMAGE (img), NULL);
2515
2516 return img->priv->trans;
2517 }
2518
2519 /**
2520 * eog_image_get_autorotate_transform:
2521 * @img: a #EogImage
2522 *
2523 * Get @img autorotate transform.
2524 *
2525 * Returns: (transfer none): A #EogTransform.
2526 */
2527
2528 EogTransform*
eog_image_get_autorotate_transform(EogImage * img)2529 eog_image_get_autorotate_transform (EogImage *img)
2530 {
2531 g_return_val_if_fail (EOG_IS_IMAGE (img), NULL);
2532
2533 return img->priv->trans_autorotate;
2534 }
2535
2536 /**
2537 * eog_image_file_changed:
2538 * @img: a #EogImage
2539 *
2540 * Marks the image file contents as changed. Also, emits
2541 * EogImage::file-changed signal.
2542 **/
2543 void
eog_image_file_changed(EogImage * img)2544 eog_image_file_changed (EogImage *img)
2545 {
2546 g_return_if_fail (EOG_IS_IMAGE (img));
2547
2548 img->priv->file_is_changed = TRUE;
2549 g_signal_emit (img, signals[SIGNAL_FILE_CHANGED], 0);
2550 }
2551
2552 gboolean
eog_image_is_file_changed(EogImage * img)2553 eog_image_is_file_changed (EogImage *img)
2554 {
2555 g_return_val_if_fail (EOG_IS_IMAGE (img), TRUE);
2556
2557 return img->priv->file_is_changed;
2558 }
2559
2560 /**
2561 * eog_image_is_file_writable:
2562 * @img: a #EogImage
2563 *
2564 * Evaluate if the user has write permission on the image file.
2565 *
2566 * Returns: %TRUE on success, %FALSE if the user hasn't write permissions on it,
2567 * or @img is not an #EogImage.
2568 **/
2569 gboolean
eog_image_is_file_writable(EogImage * img)2570 eog_image_is_file_writable (EogImage *img)
2571 {
2572 gboolean is_writable;
2573
2574 g_return_val_if_fail (EOG_IS_IMAGE (img), FALSE);
2575
2576 is_writable = check_if_file_is_writable (img->priv->file);
2577
2578 return is_writable;
2579 }
2580
2581 gboolean
eog_image_is_jpeg(EogImage * img)2582 eog_image_is_jpeg (EogImage *img)
2583 {
2584 g_return_val_if_fail (EOG_IS_IMAGE (img), FALSE);
2585
2586 return ((img->priv->file_type != NULL) && (g_ascii_strcasecmp (img->priv->file_type, EOG_FILE_FORMAT_JPEG) == 0));
2587 }
2588
2589 /**
2590 * eog_image_is_multipaged:
2591 * @img: an #EogImage
2592 *
2593 * Check whether the image actually contains multiple images/pages.
2594 * This can happen for TIFF files. GIF animations are not multipaged.
2595 *
2596 * Note that this only works if the image data is loaded.
2597 *
2598 * Returns: %TRUE if @img is multipaged, %FALSE if not or the image data wasn't loaded.
2599 * Since: 3.18
2600 **/
2601 gboolean
eog_image_is_multipaged(EogImage * img)2602 eog_image_is_multipaged (EogImage *img)
2603 {
2604 gboolean result = FALSE;
2605
2606 g_return_val_if_fail (EOG_IS_IMAGE (img), FALSE);
2607
2608 if (img->priv->image != NULL)
2609 {
2610 const gchar* value = gdk_pixbuf_get_option (img->priv->image,
2611 "multipage");
2612
2613 result = (g_strcmp0 ("yes", value) == 0);
2614 }
2615
2616 return result;
2617 }
2618