[gnome-control-center] background: handle EXIF orientation in chooser



commit 55082264056df8d15a0a495d8146142ddfd1a496
Author: Silvère Latchurié <slatchurie gmail com>
Date:   Thu Jun 1 16:55:50 2017 +0200

    background: handle EXIF orientation in chooser
    
    The chooser ignores EXIF orientations embedded in the pictures when the
    thumbnails are generated.
    
    Because the EXIF informations are available after the file has been
    loaded, it has to be reloaded if the transformed dimensions don't
    match the thumbnails constraints.
    
    The transformations are directly applied for EXIF orientations 1, 2,
    3 and 4. For EXIF orientations 5, 6, 7 and 8, the pictures are reloaded
    with swapped dimensions before the transformations are applied.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=783200

 panels/background/bg-pictures-source.c |   69 +++++++++++++++++++++++++++++++-
 1 files changed, 67 insertions(+), 2 deletions(-)
---
diff --git a/panels/background/bg-pictures-source.c b/panels/background/bg-pictures-source.c
index a33cee7..a3b35f3 100644
--- a/panels/background/bg-pictures-source.c
+++ b/panels/background/bg-pictures-source.c
@@ -73,6 +73,8 @@ const char * const screenshot_types[] = {
 
 static char *bg_pictures_source_get_unique_filename (const char *uri);
 
+static void picture_opened_for_read (GObject *source_object, GAsyncResult *res, gpointer user_data);
+
 static void
 bg_pictures_source_dispose (GObject *object)
 {
@@ -136,6 +138,34 @@ remove_placeholder (BgPicturesSource *bg_source, CcBackgroundItem *item)
   gtk_list_store_remove (store, &iter);
 }
 
+static gboolean
+picture_needs_rotation (GdkPixbuf *pixbuf)
+{
+  const gchar *str;
+
+  str = gdk_pixbuf_get_option (pixbuf, "orientation");
+  if (str == NULL)
+    return FALSE;
+
+  if (*str == '5' || *str == '6' || *str == '7' || *str == '8')
+    return TRUE;
+
+  return FALSE;
+}
+
+static GdkPixbuf *
+swap_rotated_pixbuf (GdkPixbuf *pixbuf)
+{
+  GdkPixbuf *tmp_pixbuf;
+
+  tmp_pixbuf = gdk_pixbuf_apply_embedded_orientation (pixbuf);
+  if (tmp_pixbuf == NULL)
+    return pixbuf;
+
+  g_object_unref (pixbuf);
+  return tmp_pixbuf;
+}
+
 static void
 picture_scaled (GObject *source_object,
                 GAsyncResult *res,
@@ -153,6 +183,7 @@ picture_scaled (GObject *source_object,
   GtkListStore *store;
   cairo_surface_t *surface = NULL;
   int scale_factor;
+  gboolean rotation_applied;
 
   item = g_object_get_data (source_object, "item");
   pixbuf = gdk_pixbuf_new_from_stream_finish (res, &error);
@@ -187,6 +218,27 @@ picture_scaled (GObject *source_object,
       goto out;
     }
 
+  /* Process embedded orientation */
+  rotation_applied = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "rotation-applied"));
+
+  if (!rotation_applied && picture_needs_rotation (pixbuf))
+    {
+      /* the width and height of pixbuf we requested are wrong for EXIF
+       * orientations 5, 6, 7 and 8. the file has to be reloaded. */
+      GFile *file;
+
+      file = g_file_new_for_uri (uri);
+      g_object_set_data (G_OBJECT (item), "needs-rotation", GINT_TO_POINTER (TRUE));
+      g_object_set_data_full (G_OBJECT (file), "item", g_object_ref (item), g_object_unref);
+      g_file_read_async (G_FILE (file), G_PRIORITY_DEFAULT,
+                         bg_source->priv->cancellable,
+                         picture_opened_for_read, bg_source);
+      g_object_unref (file);
+      goto out;
+    }
+
+  pixbuf = swap_rotated_pixbuf (pixbuf);
+
   scale_factor = bg_source_get_scale_factor (BG_SOURCE (bg_source));
   surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, scale_factor, NULL);
   cc_background_item_load (item, NULL);
@@ -233,6 +285,7 @@ picture_opened_for_read (GObject *source_object,
   GError *error = NULL;
   gint thumbnail_height;
   gint thumbnail_width;
+  gboolean needs_rotation;
 
   item = g_object_get_data (source_object, "item");
   stream = g_file_read_finish (G_FILE (source_object), res, &error);
@@ -255,8 +308,20 @@ picture_opened_for_read (GObject *source_object,
    */
   bg_source = BG_PICTURES_SOURCE (user_data);
 
-  thumbnail_height = bg_source_get_thumbnail_height (BG_SOURCE (bg_source));
-  thumbnail_width = bg_source_get_thumbnail_width (BG_SOURCE (bg_source));
+  needs_rotation = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "needs-rotation"));
+  if (needs_rotation)
+    {
+      /* swap width and height for EXIF orientations that need it */
+      thumbnail_width = bg_source_get_thumbnail_height (BG_SOURCE (bg_source));
+      thumbnail_height = bg_source_get_thumbnail_width (BG_SOURCE (bg_source));
+      g_object_set_data (G_OBJECT (item), "rotation-applied", GINT_TO_POINTER (TRUE));
+    }
+  else
+    {
+      thumbnail_width = bg_source_get_thumbnail_width (BG_SOURCE (bg_source));
+      thumbnail_height = bg_source_get_thumbnail_height (BG_SOURCE (bg_source));
+    }
+
   g_object_set_data_full (G_OBJECT (stream), "item", g_object_ref (item), g_object_unref);
   gdk_pixbuf_new_from_stream_at_scale_async (G_INPUT_STREAM (stream),
                                              thumbnail_width, thumbnail_height,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]