diff options
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | thumbnailer/Makefile.am | 36 | ||||
-rw-r--r-- | thumbnailer/gdk-pixbuf-print-mime-types.c | 29 | ||||
-rw-r--r-- | thumbnailer/gdk-pixbuf-thumbnailer.c | 303 | ||||
-rw-r--r-- | thumbnailer/gdk-pixbuf-thumbnailer.thumbnailer.in | 4 | ||||
-rw-r--r-- | thumbnailer/gnome-thumbnailer-skeleton.c | 324 | ||||
-rw-r--r-- | thumbnailer/gnome-thumbnailer-skeleton.h | 38 |
8 files changed, 736 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am index ed4a5c270..ab16470c6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = gdk-pixbuf po docs tests contrib build +SUBDIRS = gdk-pixbuf po docs thumbnailer tests contrib build EXTRA_DIST = \ config.h.win32 \ diff --git a/configure.ac b/configure.ac index d7ec2b801..1e0475e38 100644 --- a/configure.ac +++ b/configure.ac @@ -1121,6 +1121,7 @@ docs/reference/gdk-pixbuf/Makefile docs/reference/gdk-pixbuf/version.xml po/Makefile.in tests/Makefile +thumbnailer/Makefile contrib/Makefile contrib/gdk-pixbuf-xlib/Makefile contrib/gdk-pixbuf-xlib/gdk-pixbuf-xlib-2.0.pc diff --git a/thumbnailer/Makefile.am b/thumbnailer/Makefile.am new file mode 100644 index 000000000..d85af210b --- /dev/null +++ b/thumbnailer/Makefile.am @@ -0,0 +1,36 @@ +bin_PROGRAMS = gdk-pixbuf-thumbnailer +noinst_PROGRAMS = gdk-pixbuf-print-mime-types + +gdk_pixbuf_thumbnailer_SOURCES = gdk-pixbuf-thumbnailer.c gnome-thumbnailer-skeleton.c gnome-thumbnailer-skeleton.h +gdk_pixbuf_thumbnailer_CPPFLAGS = \ + -I$(top_srcdir) \ + -I$(top_srcdir)/gdk-pixbuf \ + $(GDK_PIXBUF_DEP_CFLAGS) \ + -DTHUMBNAILER_RETURNS_PIXBUF \ + -DTHUMBNAILER_USAGE="\"Thumbnail images\"" \ + $(WARN_CFLAGS) +gdk_pixbuf_thumbnailer_LDADD = \ + $(GDK_PIXBUF_DEP_LIBS) \ + $(top_builddir)/gdk-pixbuf/libgdk_pixbuf-$(GDK_PIXBUF_API_VERSION).la + +gdk_pixbuf_print_mime_types_SOURCES = gdk-pixbuf-print-mime-types.c +gdk_pixbuf_print_mime_types_CPPFLAGS = \ + -I$(top_srcdir) \ + -I$(top_srcdir)/gdk-pixbuf \ + $(GDK_PIXBUF_DEP_CFLAGS) \ + $(WARN_CFLAGS) +gdk_pixbuf_print_mime_types_LDADD = \ + $(GDK_PIXBUF_DEP_LIBS) \ + $(top_builddir)/gdk-pixbuf/libgdk_pixbuf-$(GDK_PIXBUF_API_VERSION).la + +thumbnailerdir = $(datadir)/thumbnailers/ +thumbnailer_DATA = gdk-pixbuf-thumbnailer.thumbnailer +gdk-pixbuf-thumbnailer.thumbnailer: gdk-pixbuf-thumbnailer.thumbnailer.in Makefile gdk-pixbuf-print-mime-types + $(AM_V_GEN) GDK_PIXBUF_MODULE_FILE=$(top_builddir)/gdk-pixbuf/loaders.cache \ + GDK_PIXBUF_PIXDATA=$(top_builddir)/gdk-pixbuf/gdk-pixbuf-pixdata \ + $(SED) -e "s|\@bindir\@|$(bindir)|" \ + -e "s|\@mimetypes\@|`$(builddir)/gdk-pixbuf-print-mime-types`|" $< > $@ + +EXTRA_DIST = gdk-pixbuf-thumbnailer.thumbnailer.in + +CLEANFILES = $(thumbnailer_DATA) diff --git a/thumbnailer/gdk-pixbuf-print-mime-types.c b/thumbnailer/gdk-pixbuf-print-mime-types.c new file mode 100644 index 000000000..0cf8393ce --- /dev/null +++ b/thumbnailer/gdk-pixbuf-print-mime-types.c @@ -0,0 +1,29 @@ +#include <gdk-pixbuf/gdk-pixbuf.h> + +int main (int argc, char **argv) +{ + GSList *formats, *l; + GString *s; + + formats = gdk_pixbuf_get_formats (); + s = g_string_new (NULL); + for (l = formats; l != NULL; l = l->next) { + GdkPixbufFormat *format = l->data; + char **mime_types; + guint i; + + mime_types = gdk_pixbuf_format_get_mime_types (format); + for (i = 0; mime_types[i] != NULL; i++) { + g_string_append (s, mime_types[i]); + g_string_append (s, ";"); + } + + g_strfreev (mime_types); + } + g_slist_free (formats); + + g_print ("%s", s->str); + g_string_free (s, TRUE); + + return 0; +} diff --git a/thumbnailer/gdk-pixbuf-thumbnailer.c b/thumbnailer/gdk-pixbuf-thumbnailer.c new file mode 100644 index 000000000..2c7207262 --- /dev/null +++ b/thumbnailer/gdk-pixbuf-thumbnailer.c @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2016 Bastien Nocera <hadess@hadess.net> + * + * Authors: Bastien Nocera <hadess@hadess.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include <string.h> +#include <glib.h> + +#include "gnome-thumbnailer-skeleton.h" + +typedef struct { + gint width; + gint height; + gint input_width; + gint input_height; + gboolean preserve_aspect_ratio; +} SizePrepareContext; + +#define LOAD_BUFFER_SIZE 4096 + +static void +size_prepared_cb (GdkPixbufLoader *loader, + int width, + int height, + gpointer data) +{ + SizePrepareContext *info = data; + + g_return_if_fail (width > 0 && height > 0); + + info->input_width = width; + info->input_height = height; + + if (width < info->width && height < info->height) return; + + if (info->preserve_aspect_ratio && + (info->width > 0 || info->height > 0)) { + if (info->width < 0) + { + width = width * (double)info->height/(double)height; + height = info->height; + } + else if (info->height < 0) + { + height = height * (double)info->width/(double)width; + width = info->width; + } + else if ((double)height * (double)info->width > + (double)width * (double)info->height) { + width = 0.5 + (double)width * (double)info->height / (double)height; + height = info->height; + } else { + height = 0.5 + (double)height * (double)info->width / (double)width; + width = info->width; + } + } else { + if (info->width > 0) + width = info->width; + if (info->height > 0) + height = info->height; + } + + gdk_pixbuf_loader_set_size (loader, width, height); +} + +static GdkPixbufLoader * +create_loader (GFile *file, + const guchar *data, + gsize size) +{ + GdkPixbufLoader *loader; + GError *error = NULL; + char *mime_type; + char *filename; + + loader = NULL; + + /* need to specify the type here because the gdk_pixbuf_loader_write + doesn't have access to the filename in order to correct detect + the image type. */ + filename = g_file_get_basename (file); + mime_type = g_content_type_guess (filename, data, size, NULL); + g_free (filename); + + if (mime_type != NULL) { + loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, &error); + } + + if (loader == NULL) { + g_debug ("Unable to create loader for mime type %s: %s", mime_type, error->message); + g_clear_error (&error); + loader = gdk_pixbuf_loader_new (); + } + g_free (mime_type); + + return loader; +} + +static GdkPixbuf * +_gdk_pixbuf_new_from_uri_at_scale (const char *uri, + gint width, + gint height, + gboolean preserve_aspect_ratio) +{ + gboolean result; + guchar buffer[LOAD_BUFFER_SIZE]; + gssize bytes_read; + GdkPixbufLoader *loader = NULL; + GdkPixbuf *pixbuf; + GdkPixbufAnimation *animation; + GdkPixbufAnimationIter *iter; + gboolean has_frame; + SizePrepareContext info; + GFile *file; + GFileInfo *file_info; + GInputStream *input_stream; + GError *error = NULL; + + g_return_val_if_fail (uri != NULL, NULL); + + input_stream = NULL; + + file = g_file_new_for_uri (uri); + + /* First see if we can get an input stream via preview::icon */ + file_info = g_file_query_info (file, + G_FILE_ATTRIBUTE_PREVIEW_ICON, + G_FILE_QUERY_INFO_NONE, + NULL, /* GCancellable */ + NULL); /* return location for GError */ + if (file_info != NULL) { + GObject *object; + + object = g_file_info_get_attribute_object (file_info, + G_FILE_ATTRIBUTE_PREVIEW_ICON); + if (object != NULL && G_IS_LOADABLE_ICON (object)) { + input_stream = g_loadable_icon_load (G_LOADABLE_ICON (object), + 0, /* size */ + NULL, /* return location for type */ + NULL, /* GCancellable */ + NULL); /* return location for GError */ + } + g_object_unref (file_info); + } + + if (input_stream == NULL) { + input_stream = G_INPUT_STREAM (g_file_read (file, NULL, &error)); + if (input_stream == NULL) { + g_warning ("Unable to create an input stream for %s: %s", uri, error->message); + g_clear_error (&error); + g_object_unref (file); + return NULL; + } + } + + has_frame = FALSE; + + result = FALSE; + while (!has_frame) { + + bytes_read = g_input_stream_read (input_stream, + buffer, + sizeof (buffer), + NULL, + &error); + if (bytes_read == -1) { + g_warning ("Error reading from %s: %s", uri, error->message); + g_clear_error (&error); + break; + } + result = TRUE; + if (bytes_read == 0) { + break; + } + + if (loader == NULL) { + loader = create_loader (file, buffer, bytes_read); + if (1 <= width || 1 <= height) { + info.width = width; + info.height = height; + info.input_width = info.input_height = 0; + info.preserve_aspect_ratio = preserve_aspect_ratio; + g_signal_connect (loader, "size-prepared", G_CALLBACK (size_prepared_cb), &info); + } + g_assert (loader != NULL); + } + + if (!gdk_pixbuf_loader_write (loader, + (unsigned char *)buffer, + bytes_read, + &error)) { + g_warning ("Error creating thumbnail for %s: %s", uri, error->message); + g_clear_error (&error); + result = FALSE; + break; + } + + animation = gdk_pixbuf_loader_get_animation (loader); + if (animation) { + iter = gdk_pixbuf_animation_get_iter (animation, NULL); + if (!gdk_pixbuf_animation_iter_on_currently_loading_frame (iter)) { + has_frame = TRUE; + } + g_object_unref (iter); + } + } + + if (loader == NULL) { + /* This can happen if the above loop was exited due to the + * g_input_stream_read() call failing. */ + result = FALSE; + } else if (gdk_pixbuf_loader_close (loader, &error) == FALSE && + !g_error_matches (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INCOMPLETE_ANIMATION)) { + g_warning ("Error creating thumbnail for %s: %s", uri, error->message); + result = FALSE; + } + g_clear_error (&error); + + if (!result) { + g_clear_object (&loader); + g_input_stream_close (input_stream, NULL, NULL); + g_object_unref (input_stream); + g_object_unref (file); + return NULL; + } + + g_input_stream_close (input_stream, NULL, NULL); + g_object_unref (input_stream); + g_object_unref (file); + + pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); + if (pixbuf != NULL) { + g_object_ref (G_OBJECT (pixbuf)); + g_object_set_data (G_OBJECT (pixbuf), "gnome-original-width", + GINT_TO_POINTER (info.input_width)); + g_object_set_data (G_OBJECT (pixbuf), "gnome-original-height", + GINT_TO_POINTER (info.input_height)); + } + g_object_unref (G_OBJECT (loader)); + + return pixbuf; +} + +GdkPixbuf * +file_to_pixbuf (const char *path, + guint destination_size, + GError **error) +{ + GdkPixbuf *pixbuf, *tmp_pixbuf; + GFile *file; + char *uri; + int original_width, original_height; + + file = g_file_new_for_path (path); + uri = g_file_get_uri (file); + pixbuf = _gdk_pixbuf_new_from_uri_at_scale (uri, destination_size, destination_size, TRUE); + if (pixbuf == NULL) { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Generic error"); + return pixbuf; + } + + tmp_pixbuf = gdk_pixbuf_apply_embedded_orientation (pixbuf); + gdk_pixbuf_copy_options (pixbuf, tmp_pixbuf); + gdk_pixbuf_remove_option (tmp_pixbuf, "orientation"); + g_object_unref (pixbuf); + pixbuf = tmp_pixbuf; + + original_width = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (pixbuf), + "gnome-original-width")); + original_height = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (pixbuf), + "gnome-original-height")); + + if (original_width > 0 && original_height > 0) { + char *tmp; + + tmp = g_strdup_printf ("%d", original_width); + gdk_pixbuf_set_option (pixbuf, "tEXt::Thumb::Image::Width", tmp); + g_free (tmp); + + tmp = g_strdup_printf ("%d", original_height); + gdk_pixbuf_set_option (pixbuf, "tEXt::Thumb::Image::Height", tmp); + g_free (tmp); + } + + return pixbuf; +} diff --git a/thumbnailer/gdk-pixbuf-thumbnailer.thumbnailer.in b/thumbnailer/gdk-pixbuf-thumbnailer.thumbnailer.in new file mode 100644 index 000000000..44f972602 --- /dev/null +++ b/thumbnailer/gdk-pixbuf-thumbnailer.thumbnailer.in @@ -0,0 +1,4 @@ +[Thumbnailer Entry] +TryExec=@bindir@/gdk-pixbuf-thumbnailer +Exec=@bindir@/gdk-pixbuf-thumbnailer -s %s %u %o +MimeType=@mimetypes@ diff --git a/thumbnailer/gnome-thumbnailer-skeleton.c b/thumbnailer/gnome-thumbnailer-skeleton.c new file mode 100644 index 000000000..6224bec28 --- /dev/null +++ b/thumbnailer/gnome-thumbnailer-skeleton.c @@ -0,0 +1,324 @@ +/* + * Copyright (C) 2013 Bastien Nocera <hadess@hadess.net> + * + * Authors: Bastien Nocera <hadess@hadess.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include <string.h> +#include <glib.h> +#include <gio/gio.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#include <math.h> +#include <stdlib.h> + +#include "gnome-thumbnailer-skeleton.h" + +#ifndef THUMBNAILER_USAGE +#error "THUMBNAILER_USAGE must be set" +#endif + +static int output_size = 256; +static gboolean g_fatal_warnings = FALSE; +static char **filenames = NULL; + +/** + * 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; + + 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; + } + + 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; +} + +static char * +get_target_uri (GFile *file) +{ + GFileInfo *info; + char *target; + + info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TARGET_URI, G_FILE_QUERY_INFO_NONE, NULL, NULL); + if (info == NULL) + return NULL; + target = g_strdup (g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_TARGET_URI)); + g_object_unref (info); + + return target; +} + +static char * +get_target_path (GFile *input) +{ + if (g_file_has_uri_scheme (input, "trash") != FALSE || + g_file_has_uri_scheme (input, "recent") != FALSE) { + GFile *file; + char *input_uri; + char *input_path; + + input_uri = get_target_uri (input); + file = g_file_new_for_uri (input_uri); + g_free (input_uri); + input_path = g_file_get_path (file); + g_object_unref (file); + return input_path; + } + return g_file_get_path (input); +} + +static const GOptionEntry entries[] = { + { "size", 's', 0, G_OPTION_ARG_INT, &output_size, "Size of the thumbnail in pixels", NULL }, + {"g-fatal-warnings", 0, 0, G_OPTION_ARG_NONE, &g_fatal_warnings, "Make all warnings fatal", NULL}, + { G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_FILENAME_ARRAY, &filenames, NULL, "[INPUT FILE] [OUTPUT FILE]" }, + { NULL } +}; + +int main (int argc, char **argv) +{ + char *input_filename; + GdkPixbuf *pixbuf; + GError *error = NULL; + GOptionContext *context; + GFile *input; + const char *output; + +#ifdef THUMBNAILER_RETURNS_PIXBUF + int width, height; +#elif THUMBNAILER_RETURNS_DATA + char *data = NULL; + gsize length; +#endif + + g_type_init (); + + /* Options parsing */ + context = g_option_context_new (THUMBNAILER_USAGE); + g_option_context_add_main_entries (context, entries, NULL); + + if (g_option_context_parse (context, &argc, &argv, &error) == FALSE) { + g_warning ("Couldn't parse command-line options: %s", error->message); + g_error_free (error); + return 1; + } + + /* Set fatal warnings if required */ + if (g_fatal_warnings) { + GLogLevelFlags fatal_mask; + + fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK); + fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL; + g_log_set_always_fatal (fatal_mask); + } + + if (filenames == NULL || g_strv_length (filenames) != 2) { + g_print ("Expects an input and an output file\n"); + return 1; + } + + input = g_file_new_for_commandline_arg (filenames[0]); + input_filename = get_target_path (input); + g_object_unref (input); + + if (input_filename == NULL) { + g_warning ("Could not get file path for %s", filenames[0]); + return 1; + } + + output = filenames[1]; + +#ifdef THUMBNAILER_RETURNS_PIXBUF + pixbuf = file_to_pixbuf (input_filename, output_size, &error); + + 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); + + scaled = gnome_desktop_thumbnail_scale_down_pixbuf (pixbuf, + floor (width * scale + 0.5), + floor (height * scale + 0.5)); + 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) { + GInputStream *mem_stream; + + mem_stream = g_memory_input_stream_new_from_data (data, length, g_free); + pixbuf = gdk_pixbuf_new_from_stream_at_scale (mem_stream, output_size, -1, TRUE, NULL, &error); + g_object_unref (mem_stream); + } else { + pixbuf = NULL; + } +#else +#error "One of THUMBNAILER_RETURNS_PIXBUF or THUMBNAILER_RETURNS_DATA must be set" +#endif + g_free (input_filename); + + if (!pixbuf) { + g_warning ("Could not thumbnail '%s': %s", filenames[0], error->message); + g_error_free (error); + g_strfreev (filenames); + return 1; + } + + if (gdk_pixbuf_save (pixbuf, output, "png", &error, NULL) == FALSE) { + g_warning ("Couldn't save the thumbnail '%s' for file '%s': %s", output, filenames[0], error->message); + g_error_free (error); + return 1; + } + + g_object_unref (pixbuf); + + return 0; +} diff --git a/thumbnailer/gnome-thumbnailer-skeleton.h b/thumbnailer/gnome-thumbnailer-skeleton.h new file mode 100644 index 000000000..b38964545 --- /dev/null +++ b/thumbnailer/gnome-thumbnailer-skeleton.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2013 Bastien Nocera <hadess@hadess.net> + * + * Authors: Bastien Nocera <hadess@hadess.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include <gdk-pixbuf/gdk-pixbuf.h> + +#ifdef THUMBNAILER_RETURNS_PIXBUF +#ifdef THUMBNAILER_RETURNS_DATA +#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 +char * file_to_data (const char *path, + gsize *ret_length, + GError **error); +#else +#error "One of THUMBNAILER_RETURNS_PIXBUF or THUMBNAILER_RETURNS_DATA must be set" +#endif |