[gnome-kra-ora-thumbnailer] Update thumbnailer skeleton code



commit 224197a9e8bb54ed1c6af1498c879de8a7a08b02
Author: Bastien Nocera <hadess hadess net>
Date:   Thu Jun 20 16:48:02 2019 +0200

    Update thumbnailer skeleton code

 gnome-thumbnailer-skeleton.c | 185 ++++++++++++++++++++++++++++++++++++++++++-
 gnome-thumbnailer-skeleton.h |   1 +
 2 files changed, 183 insertions(+), 3 deletions(-)
---
diff --git a/gnome-thumbnailer-skeleton.c b/gnome-thumbnailer-skeleton.c
index e4c11a6..75c0f9c 100644
--- a/gnome-thumbnailer-skeleton.c
+++ b/gnome-thumbnailer-skeleton.c
@@ -24,6 +24,9 @@
 #include <gio/gio.h>
 #include <gdk-pixbuf/gdk-pixbuf.h>
 
+#include <math.h>
+#include <stdlib.h>
+
 #include "gnome-thumbnailer-skeleton.h"
 
 #ifndef THUMBNAILER_USAGE
@@ -34,6 +37,150 @@ static int output_size = 256;
 static gboolean g_fatal_warnings = FALSE;
 static char **filenames = NULL;
 
+#if !GDK_PIXBUF_CHECK_VERSION(2,36,5)
+/**
+ * gnome_desktop_thumbnail_scale_down_pixbuf:
+ * @pixbuf: a #GdkPixbuf
+ * @dest_width: the desired new width
+ * @dest_height: the desired new height
+ *
+ * Scales the pixbuf to the desired size. This function
+ * is a lot faster than gdk-pixbuf when scaling down by
+ * large amounts.
+ *
+ * Return value: (transfer full): a scaled pixbuf
+ * 
+ * Since: 2.2
+ **/
+GdkPixbuf *
+gnome_desktop_thumbnail_scale_down_pixbuf (GdkPixbuf *pixbuf,
+                                          int dest_width,
+                                          int dest_height)
+{
+       int source_width, source_height;
+       int s_x1, s_y1, s_x2, s_y2;
+       int s_xfrac, s_yfrac;
+       int dx, dx_frac, dy, dy_frac;
+       div_t ddx, ddy;
+       int x, y;
+       int r, g, b, a;
+       int n_pixels;
+       gboolean has_alpha;
+       guchar *dest, *src, *xsrc, *src_pixels;
+       GdkPixbuf *dest_pixbuf;
+       int pixel_stride;
+       int source_rowstride, dest_rowstride;
+
+       if (dest_width == 0 || dest_height == 0) {
+               return NULL;
+       }
+       
+       source_width = gdk_pixbuf_get_width (pixbuf);
+       source_height = gdk_pixbuf_get_height (pixbuf);
+
+       g_assert (source_width >= dest_width);
+       g_assert (source_height >= dest_height);
+
+       ddx = div (source_width, dest_width);
+       dx = ddx.quot;
+       dx_frac = ddx.rem;
+       
+       ddy = div (source_height, dest_height);
+       dy = ddy.quot;
+       dy_frac = ddy.rem;
+
+       g_assert (dx >= 1);
+       g_assert (dy >= 1);
+
+       has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
+       source_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+       src_pixels = gdk_pixbuf_get_pixels (pixbuf);
+
+       dest_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, has_alpha, 8,
+                                     dest_width, dest_height);
+       dest = gdk_pixbuf_get_pixels (dest_pixbuf);
+       dest_rowstride = gdk_pixbuf_get_rowstride (dest_pixbuf);
+
+       pixel_stride = (has_alpha)?4:3;
+       
+       s_y1 = 0;
+       s_yfrac = -dest_height/2;
+       while (s_y1 < source_height) {
+               s_y2 = s_y1 + dy;
+               s_yfrac += dy_frac;
+               if (s_yfrac > 0) {
+                       s_y2++;
+                       s_yfrac -= dest_height;
+               }
+
+               s_x1 = 0;
+               s_xfrac = -dest_width/2;
+               while (s_x1 < source_width) {
+                       s_x2 = s_x1 + dx;
+                       s_xfrac += dx_frac;
+                       if (s_xfrac > 0) {
+                               s_x2++;
+                               s_xfrac -= dest_width;
+                       }
+
+                       /* Average block of [x1,x2[ x [y1,y2[ and store in dest */
+                       r = g = b = a = 0;
+                       n_pixels = 0;
+
+                       src = src_pixels + s_y1 * source_rowstride + s_x1 * pixel_stride;
+                       for (y = s_y1; y < s_y2; y++) {
+                               xsrc = src;
+                               if (has_alpha) {
+                                       for (x = 0; x < s_x2-s_x1; x++) {
+                                               n_pixels++;
+                                               
+                                               r += xsrc[3] * xsrc[0];
+                                               g += xsrc[3] * xsrc[1];
+                                               b += xsrc[3] * xsrc[2];
+                                               a += xsrc[3];
+                                               xsrc += 4;
+                                       }
+                               } else {
+                                       for (x = 0; x < s_x2-s_x1; x++) {
+                                               n_pixels++;
+                                               r += *xsrc++;
+                                               g += *xsrc++;
+                                               b += *xsrc++;
+                                       }
+                               }
+                               src += source_rowstride;
+                       }
+
+                       g_assert (n_pixels > 0);
+
+                       if (has_alpha) {
+                               if (a != 0) {
+                                       *dest++ = r / a;
+                                       *dest++ = g / a;
+                                       *dest++ = b / a;
+                                       *dest++ = a / n_pixels;
+                               } else {
+                                       *dest++ = 0;
+                                       *dest++ = 0;
+                                       *dest++ = 0;
+                                       *dest++ = 0;
+                               }
+                       } else {
+                               *dest++ = r / n_pixels;
+                               *dest++ = g / n_pixels;
+                               *dest++ = b / n_pixels;
+                       }
+                       
+                       s_x1 = s_x2;
+               }
+               s_y1 = s_y2;
+               dest += dest_rowstride - dest_width * pixel_stride;
+       }
+       
+       return dest_pixbuf;
+}
+#endif
+
 static char *
 get_target_uri (GFile *file)
 {
@@ -91,7 +238,9 @@ int main (int argc, char **argv)
        gsize length;
 #endif
 
+#if !GLIB_CHECK_VERSION(2, 36, 0)
        g_type_init ();
+#endif
 
        /* Options parsing */
        context = g_option_context_new (THUMBNAILER_USAGE);
@@ -129,7 +278,36 @@ int main (int argc, char **argv)
        output = filenames[1];
 
 #ifdef THUMBNAILER_RETURNS_PIXBUF
-       pixbuf = file_to_pixbuf (input_filename, &error);
+       pixbuf = file_to_pixbuf (input_filename, output_size, &error);
+       if (pixbuf != NULL) {
+               int width, height;
+
+               width = gdk_pixbuf_get_width (pixbuf);
+               height = gdk_pixbuf_get_height (pixbuf);
+
+               /* Handle naive thumbnailers that don't resize */
+               if (output_size != 0 &&
+                   (height > output_size || width > output_size)) {
+                       GdkPixbuf *scaled;
+                       double scale;
+
+                       scale = (double)output_size / MAX (width, height);
+
+#if !GDK_PIXBUF_CHECK_VERSION(2,36,5)
+                       scaled = gnome_desktop_thumbnail_scale_down_pixbuf (pixbuf,
+                                                                           floor (width * scale + 0.5),
+                                                                           floor (height * scale + 0.5));
+#else
+                       scaled = gdk_pixbuf_scale_simple (pixbuf,
+                                                         floor (width * scale + 0.5),
+                                                         floor (height * scale + 0.5),
+                                                         GDK_INTERP_BILINEAR);
+#endif
+                       gdk_pixbuf_copy_options (pixbuf, scaled);
+                       g_object_unref (pixbuf);
+                       pixbuf = scaled;
+               }
+       }
 #elif THUMBNAILER_RETURNS_DATA
        data = file_to_data (input_filename, &length, &error);
        if (data) {
@@ -147,8 +325,9 @@ int main (int argc, char **argv)
        g_free (input_filename);
 
        if (!pixbuf) {
-               g_warning ("Could not thumbnail '%s': %s", filenames[0], error->message);
-               g_error_free (error);
+               g_warning ("Could not thumbnail '%s': %s", filenames[0],
+                          error ? error->message : "Thumbnailer failed without returning an error");
+               g_clear_error (&error);
                g_strfreev (filenames);
                return 1;
        }
diff --git a/gnome-thumbnailer-skeleton.h b/gnome-thumbnailer-skeleton.h
index 0c2e687..b389645 100644
--- a/gnome-thumbnailer-skeleton.h
+++ b/gnome-thumbnailer-skeleton.h
@@ -26,6 +26,7 @@
 #error "Only one of THUMBNAILER_RETURNS_PIXBUF or THUMBNAILER_RETURNS_DATA must be set"
 #else
 GdkPixbuf * file_to_pixbuf (const char  *path,
+                           guint        destination_size,
                            GError     **error);
 #endif
 #elif THUMBNAILER_RETURNS_DATA


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