diff options
Diffstat (limited to 'plugins/gepub-thumbnailer/gepub-thumbnailer.c')
-rw-r--r-- | plugins/gepub-thumbnailer/gepub-thumbnailer.c | 290 |
1 files changed, 290 insertions, 0 deletions
diff --git a/plugins/gepub-thumbnailer/gepub-thumbnailer.c b/plugins/gepub-thumbnailer/gepub-thumbnailer.c new file mode 100644 index 0000000..acd0fd3 --- /dev/null +++ b/plugins/gepub-thumbnailer/gepub-thumbnailer.c @@ -0,0 +1,290 @@ +/* vi:set et ai sw=2 sts=2 ts=2: */ +/*- + * Copyright (c) 2010 Jannis Pohlmann <jannis@xfce.org> + * Copyright (c) 2020, Olivier Duchateau <duchateau.olivier@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 Library General Public License for more details. + * + * You should have received a copy of the GNU Library General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <math.h> + +#include <glib.h> +#include <glib/gi18n.h> +#include <glib/gprintf.h> +#include <glib-object.h> +#include <gio/gio.h> +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <tumbler/tumbler.h> +#include <gepub.h> + +#include "gepub-thumbnailer.h" + + +static void gepub_thumbnailer_create (TumblerAbstractThumbnailer *thumbnailer, + GCancellable *cancellable, + TumblerFileInfo *info); + + + +struct _GepubThumbnailerClass +{ + TumblerAbstractThumbnailerClass __parent__; +}; + +struct _GepubThumbnailer +{ + TumblerAbstractThumbnailer __parent__; +}; + + + +G_DEFINE_DYNAMIC_TYPE (GepubThumbnailer, + gepub_thumbnailer, + TUMBLER_TYPE_ABSTRACT_THUMBNAILER); + + + +void +gepub_thumbnailer_register (TumblerProviderPlugin *plugin) +{ + gepub_thumbnailer_register_type (G_TYPE_MODULE (plugin)); +} + + + +static void +gepub_thumbnailer_class_init (GepubThumbnailerClass *klass) +{ + TumblerAbstractThumbnailerClass *abstractthumbnailer_class; + + abstractthumbnailer_class = TUMBLER_ABSTRACT_THUMBNAILER_CLASS (klass); + abstractthumbnailer_class->create = gepub_thumbnailer_create; +} + + + +static void +gepub_thumbnailer_class_finalize (GepubThumbnailerClass *klass) +{ +} + + + +static void +gepub_thumbnailer_init (GepubThumbnailer *thumbnailer) +{ +} + + + +static void +gepub_thumbnailer_size_prepared (GdkPixbufLoader *loader, + gint source_width, + gint source_height, + TumblerThumbnail *thumbnail) +{ + TumblerThumbnailFlavor *flavor; + gint dest_width; + gint dest_height; + gdouble hratio; + gdouble wratio; + + g_return_if_fail (GDK_IS_PIXBUF_LOADER (loader)); + g_return_if_fail (TUMBLER_IS_THUMBNAIL (thumbnail)); + + flavor = tumbler_thumbnail_get_flavor (thumbnail); + tumbler_thumbnail_flavor_get_size (flavor, &dest_width, &dest_height); + g_object_unref (flavor); + + if (source_width <= dest_width && source_height <= dest_height) + { + /* do not scale the image */ + dest_width = source_width; + dest_height = source_height; + } + else + { + /* determine which axis needs to be scaled down more */ + wratio = (gdouble) source_width / (gdouble) dest_width; + hratio = (gdouble) source_height / (gdouble) dest_height; + + /* adjust the other axis */ + if (hratio > wratio) + dest_width = rint (source_width / hratio); + else + dest_height = rint (source_height / wratio); + } + + gdk_pixbuf_loader_set_size (loader, MAX (dest_width, 1), + MAX (dest_height, 1)); +} + + + +static GdkPixbuf * +gepub_thumbnailer_create_from_mime (gchar *mime_type, + GBytes *content, + TumblerThumbnail *thumbnail, + GError **error) +{ + GdkPixbufLoader *loader; + GdkPixbuf *pixbuf = NULL; + GError *err = NULL; + + g_return_val_if_fail (TUMBLER_IS_THUMBNAIL (thumbnail), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + /* allow only some mime types */ + if (g_strcmp0 (mime_type, "image/png") == 0 || + g_strcmp0 (mime_type, "image/jpeg") == 0 || + g_strcmp0 (mime_type, "image/gif") == 0) + { + loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, &err); + g_signal_connect (loader, "size-prepared", + G_CALLBACK (gepub_thumbnailer_size_prepared), + thumbnail); + if (gdk_pixbuf_loader_write_bytes (loader, content, &err)) + { + if (gdk_pixbuf_loader_close (loader, &err)) + { + pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); + if (pixbuf != NULL) + g_object_ref (G_OBJECT (pixbuf)); + } + } + else + gdk_pixbuf_loader_close (loader, NULL); + + g_object_unref (loader); + + if (err != NULL) + g_propagate_error (error, err); + } + return pixbuf; +} + + + +static void +gepub_thumbnailer_create (TumblerAbstractThumbnailer *thumbnailer, + GCancellable *cancellable, + TumblerFileInfo *info) +{ + TumblerImageData data; + TumblerThumbnail *thumbnail; + const gchar *uri; + GFile *file; + GError *error = NULL; + gchar *path; + GdkPixbuf *pixbuf = NULL; + GepubDoc *doc; + gchar *cover; + gchar *cover_mime; + GBytes *content; + + g_return_if_fail (IS_GEPUB_THUMBNAILER (thumbnailer)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (TUMBLER_IS_FILE_INFO (info)); + + /* do nothing if cancelled */ + if (g_cancellable_is_cancelled (cancellable)) + return; + + uri = tumbler_file_info_get_uri (info); + file = g_file_new_for_uri (uri); + + if (g_file_is_native (file)) + { + /* try to load the EPUB file */ + path = g_file_get_path (file); + doc = gepub_doc_new (path, &error); + if (error != NULL) + { + g_signal_emit_by_name (thumbnailer, "error", uri, + error->code, error->message); + g_error_free (error); + + g_free (path); + g_object_unref (file); + return; + } + + /* find cover file and its mime type */ + cover = gepub_doc_get_cover (doc); + cover_mime = gepub_doc_get_resource_mime_by_id (doc, cover); + + if (cover_mime == NULL) + { + g_signal_emit_by_name (thumbnailer, "error", uri, + TUMBLER_ERROR_NO_CONTENT, + "Cover not found"); + + g_free (cover); + g_free (path); + g_object_unref (doc); + g_object_unref (file); + return; + } + + /* content of cover image */ + content = gepub_doc_get_resource_by_id (doc, cover); + g_free (cover); + + thumbnail = tumbler_file_info_get_thumbnail (info); + + pixbuf = gepub_thumbnailer_create_from_mime (cover_mime, content, + thumbnail, + &error); + g_free (cover_mime); + g_free (path); + g_object_unref (doc); + } + g_object_unref (file); + + if (pixbuf != NULL) + { + data.data = gdk_pixbuf_get_pixels (pixbuf); + data.has_alpha = gdk_pixbuf_get_has_alpha (pixbuf); + data.bits_per_sample = gdk_pixbuf_get_bits_per_sample (pixbuf); + data.width = gdk_pixbuf_get_width (pixbuf); + data.height = gdk_pixbuf_get_height (pixbuf); + data.rowstride = gdk_pixbuf_get_rowstride (pixbuf); + data.colorspace = (TumblerColorspace) gdk_pixbuf_get_colorspace (pixbuf); + + tumbler_thumbnail_save_image_data (thumbnail, &data, + tumbler_file_info_get_mtime (info), + NULL, &error); + + g_object_unref (pixbuf); + } + + if (error != NULL) + { + g_signal_emit_by_name (thumbnailer, "error", uri, error->code, + error->message); + g_error_free (error); + } + else + { + g_signal_emit_by_name (thumbnailer, "ready", uri); + } + + g_object_unref (thumbnail); +} |