[gnome-kra-ora-thumbnailer] Update thumbnailer skeleton code
- From: Bastien Nocera <hadess src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-kra-ora-thumbnailer] Update thumbnailer skeleton code
- Date: Thu, 20 Jun 2019 14:48:22 +0000 (UTC)
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]