File 0001-comics-Optionally-use-libgsf-for-reading-comics.patch of Package mingw64-evince
From 92ef94e923cbc4de5d3ea38beeaaec394ce1eba7 Mon Sep 17 00:00:00 2001
From: Hib Eris <hib@hiberis.nl>
Date: Wed, 21 Jul 2010 14:08:57 +0200
Subject: [PATCH] [comics] (Optionally) use libgsf for reading comics
---
backend/comics/Makefile.am | 4 +-
backend/comics/comics-document.c | 405 +++++++++++++++++++++++++++++++++-----
configure.ac | 14 ++
3 files changed, 374 insertions(+), 49 deletions(-)
diff --git a/backend/comics/Makefile.am b/backend/comics/Makefile.am
index 3d56cd7..960342e 100644
--- a/backend/comics/Makefile.am
+++ b/backend/comics/Makefile.am
@@ -3,7 +3,7 @@ INCLUDES = \
-I$(top_srcdir)/libdocument \
-DGNOMELOCALEDIR=\"$(datadir)/locale\" \
-DEVINCE_COMPILATION \
- $(BACKEND_CFLAGS) \
+ $(COMICS_CFLAGS) \
$(LIB_CFLAGS) \
$(WARN_CFLAGS) \
$(DISABLE_DEPRECATED)
@@ -17,7 +17,7 @@ libcomicsdocument_la_SOURCES = \
libcomicsdocument_la_LDFLAGS = $(BACKEND_LIBTOOL_FLAGS)
libcomicsdocument_la_LIBADD = \
$(top_builddir)/libdocument/libevdocument.la \
- $(BACKEND_LIBS) \
+ $(COMICS_LIBS) \
$(LIB_LIBS)
backend_in_files = comicsdocument.evince-backend.in
diff --git a/backend/comics/comics-document.c b/backend/comics/comics-document.c
index 4d74385..fbd75b6 100644
--- a/backend/comics/comics-document.c
+++ b/backend/comics/comics-document.c
@@ -30,6 +30,14 @@
#include <glib/gstdio.h>
#include <gio/gio.h>
+#if WITH_LIBGSF
+#include <gsf/gsf.h>
+#include <gsf/gsf-input-gio.h>
+#include <gsf/gsf-infile.h>
+#include <gsf/gsf-infile-zip.h>
+#include <gsf/gsf-infile-tar.h>
+#endif
+
#ifdef G_OS_WIN32
# define WIFEXITED(x) ((x) != 3)
# define WEXITSTATUS(x) (x)
@@ -54,6 +62,15 @@
typedef enum
{
+ TYPE_INVALID,
+ TYPE_ZIP,
+ TYPE_TAR,
+ TYPE_P7ZIP,
+ TYPE_RAR
+} ComicBookType;
+
+typedef enum
+{
RARLABS,
GNAUNRAR,
UNZIP,
@@ -72,8 +89,10 @@ struct _ComicsDocument
{
EvDocument parent_instance;
+ ComicBookType type;
gchar *archive, *dir;
GPtrArray *page_names;
+ GPtrArray *pages;
gchar *selected_command, *alternative_command;
gchar *extract_command, *list_command, *decompress_tmp;
gboolean regex_arg;
@@ -135,6 +154,54 @@ static void render_pixbuf_size_prepared_cb (GdkPixbufLoader *loader,
static char** extract_argv (EvDocument *document,
gint page);
+static ComicBookType
+comics_document_get_comics_type (const char *uri,
+ GError **error)
+{
+ ComicBookType type;
+
+ gchar *mime_type;
+ GError *err;
+
+ mime_type = ev_file_get_mime_type (uri, FALSE, &err);
+ if (!mime_type) {
+ if (err) {
+ g_propagate_error (error, err);
+ } else {
+ g_set_error_literal (error,
+ EV_DOCUMENT_ERROR,
+ EV_DOCUMENT_ERROR_INVALID,
+ _("Unknown MIME Type"));
+ }
+ return TYPE_INVALID;
+ }
+
+ /* FIXME, use proper cbr/cbz mime types once they're
+ * included in shared-mime-info */
+ if (!strcmp (mime_type, "application/x-cbz") ||
+ !strcmp (mime_type, "application/zip")) {
+ type = TYPE_ZIP;
+ } else if (!strcmp (mime_type, "application/x-cbt") ||
+ !strcmp (mime_type, "application/x-tar")) {
+ type = TYPE_TAR;
+ } else if (!strcmp (mime_type, "application/x-cb7") ||
+ !strcmp (mime_type, "application/x-7z-compressed")) {
+ type = TYPE_P7ZIP;
+ } else if (!strcmp (mime_type, "application/x-cbr") ||
+ !strcmp (mime_type, "application/x-rar")) {
+ type = TYPE_RAR;
+ } else {
+ g_set_error (error,
+ EV_DOCUMENT_ERROR,
+ EV_DOCUMENT_ERROR_INVALID,
+ _("Not a comic book MIME type: %s"),
+ mime_type);
+ type = TYPE_INVALID;
+ }
+
+ g_free (mime_type);
+ return type;
+}
EV_BACKEND_REGISTER_WITH_CODE (ComicsDocument, comics_document,
{
@@ -307,20 +374,18 @@ comics_generate_command_lines (ComicsDocument *comics_document,
/* This function chooses an external command for decompressing a comic
* book based on its mime tipe. */
static gboolean
-comics_check_decompress_command (gchar *mime_type,
- ComicsDocument *comics_document,
- GError **error)
+comics_check_decompress_command (ComicsDocument *comics_document,
+ ComicBookType type,
+ GError **error)
{
gboolean success;
gchar *std_out, *std_err;
gint retval;
GError *err = NULL;
- /* FIXME, use proper cbr/cbz mime types once they're
- * included in shared-mime-info */
-
- if (!strcmp (mime_type, "application/x-cbr") ||
- !strcmp (mime_type, "application/x-rar")) {
+ switch (type) {
+
+ case TYPE_RAR:
/* The RARLAB provides a no-charge proprietary (freeware)
* decompress-only client for Linux called unrar. Another
* option is a GPLv2-licensed command-line tool developed by
@@ -368,9 +433,9 @@ comics_check_decompress_command (gchar *mime_type,
comics_document->command_usage = GNAUNRAR;
return TRUE;
}
+ break;
- } else if (!strcmp (mime_type, "application/x-cbz") ||
- !strcmp (mime_type, "application/zip")) {
+ case TYPE_ZIP:
/* InfoZIP's unzip program */
comics_document->selected_command =
g_find_program_in_path ("unzip");
@@ -381,9 +446,9 @@ comics_check_decompress_command (gchar *mime_type,
comics_document->command_usage = UNZIP;
return TRUE;
}
+ break;
- } else if (!strcmp (mime_type, "application/x-cb7") ||
- !strcmp (mime_type, "application/x-7z-compressed")) {
+ case TYPE_P7ZIP:
/* 7zr, 7za and 7z are the commands from the p7zip project able
* to decompress .7z files */
comics_document->selected_command =
@@ -404,8 +469,9 @@ comics_check_decompress_command (gchar *mime_type,
comics_document->command_usage = P7ZIP;
return TRUE;
}
- } else if (!strcmp (mime_type, "application/x-cbt") ||
- !strcmp (mime_type, "application/x-tar")) {
+ break;
+
+ case TYPE_TAR:
/* tar utility (Tape ARchive) */
comics_document->selected_command =
g_find_program_in_path ("tar");
@@ -413,14 +479,13 @@ comics_check_decompress_command (gchar *mime_type,
comics_document->command_usage = TAR;
return TRUE;
}
- } else {
- g_set_error (error,
- EV_DOCUMENT_ERROR,
- EV_DOCUMENT_ERROR_INVALID,
- _("Not a comic book MIME type: %s"),
- mime_type);
- return FALSE;
+ break;
+
+ default:
+ g_warning (_("Invalid comic book type"));
+ break;
}
+
g_set_error_literal (error,
EV_DOCUMENT_ERROR,
EV_DOCUMENT_ERROR_INVALID,
@@ -436,49 +501,119 @@ sort_page_names (gconstpointer a,
return strcmp (* (const char **) a, * (const char **) b);
}
+#if WITH_LIBGSF
+static void
+get_pages_gsf (GsfInput *source,
+ GSList *supported_extensions,
+ GPtrArray **pages)
+{
+ GsfInfile *infile = GSF_IS_INFILE (source) ? GSF_INFILE (source) : NULL;
+ GsfInput *child;
+ int i, n;
+
+ n = infile ? gsf_infile_num_children (infile): 0;
+ if (n > 0) {
+ GPtrArray *page_names = g_ptr_array_sized_new (n);
+ for (i = 0; i < n; i++) {
+ child = gsf_infile_child_by_index (infile, i);
+ g_ptr_array_add (page_names,
+ g_strdup (gsf_input_name (child)));
+ g_object_unref (child);
+ }
+ g_ptr_array_sort (page_names, sort_page_names);
+
+ for (i = 0; i < page_names->len; i++) {
+ child = gsf_infile_child_by_name (infile,
+ (char const*) page_names->pdata[i]);
+ get_pages_gsf (child, supported_extensions, pages);
+ g_object_unref (child);
+ }
+ g_ptr_array_foreach (page_names, (GFunc) g_free, NULL);
+ g_ptr_array_free (page_names, TRUE);
+ } else {
+ gchar *suffix = g_strrstr (gsf_input_name (source), ".");
+ if (suffix) {
+ suffix = g_ascii_strdown (suffix + 1, -1);
+ if (g_slist_find_custom (supported_extensions, suffix,
+ (GCompareFunc) strcmp) != NULL) {
+ g_object_ref (source);
+ g_ptr_array_add (*pages, source);
+ }
+ g_free (suffix);
+ }
+ }
+}
+
static gboolean
-comics_document_load (EvDocument *document,
+comics_document_load_gsf (EvDocument *document,
+ const char *uri,
+ GError **error)
+{
+ ComicsDocument *comics_document = COMICS_DOCUMENT (document);
+ GsfInput *source;
+ GsfInfile *infile;
+ GSList *supported_extensions;
+
+ source = gsf_input_gio_new_for_uri (uri, error);
+ if (!source)
+ return FALSE;
+
+ switch (comics_document->type) {
+ case TYPE_ZIP:
+ infile = gsf_infile_zip_new (source, error);
+ break;
+ case TYPE_TAR:
+ infile = gsf_infile_tar_new (source, error);
+ break;
+ default:
+ g_warning (_("Invalid comic book type"));
+ g_set_error_literal (error,
+ EV_DOCUMENT_ERROR,
+ EV_DOCUMENT_ERROR_INVALID,
+ _("Can't find an appropriate command to "
+ "decompress this type of comic book"));
+ g_object_unref (source);
+ return FALSE;
+ }
+ g_object_unref (source);
+ if (!infile)
+ return FALSE;
+
+ comics_document->pages = g_ptr_array_sized_new (64);
+
+ supported_extensions = get_supported_image_extensions ();
+ get_pages_gsf (GSF_INPUT (infile), supported_extensions, &(comics_document->pages));
+ g_slist_foreach (supported_extensions, (GFunc) g_free, NULL);
+ g_slist_free (supported_extensions);
+ g_object_unref (infile);
+
+ return TRUE;
+}
+#endif
+
+static gboolean
+comics_document_load_external (EvDocument *document,
const char *uri,
GError **error)
{
ComicsDocument *comics_document = COMICS_DOCUMENT (document);
GSList *supported_extensions;
gchar *std_out;
- gchar *mime_type;
gchar **cb_files, *cb_file;
gboolean success;
int i, retval;
- GError *err = NULL;
comics_document->archive = g_filename_from_uri (uri, NULL, error);
if (!comics_document->archive)
return FALSE;
- mime_type = ev_file_get_mime_type (uri, FALSE, &err);
- if (!mime_type) {
- if (err) {
- g_propagate_error (error, err);
- } else {
- g_set_error_literal (error,
- EV_DOCUMENT_ERROR,
- EV_DOCUMENT_ERROR_INVALID,
- _("Unknown MIME Type"));
- }
-
- return FALSE;
- }
-
- if (!comics_check_decompress_command (mime_type, comics_document,
- error)) {
- g_free (mime_type);
+ if (!comics_check_decompress_command (comics_document,
+ comics_document->type, error)) {
return FALSE;
} else if (!comics_generate_command_lines (comics_document, error)) {
- g_free (mime_type);
return FALSE;
}
- g_free (mime_type);
-
/* Get list of files in archive */
success = g_spawn_command_line_sync (comics_document->list_command,
&std_out, NULL, &retval, error);
@@ -552,6 +687,31 @@ comics_document_load (EvDocument *document,
return TRUE;
}
+static gboolean
+comics_document_load (EvDocument *document,
+ const char *uri,
+ GError **error)
+{
+ ComicsDocument *comics_document = COMICS_DOCUMENT (document);
+
+ comics_document->type = comics_document_get_comics_type (uri, error);
+ if (comics_document->type == TYPE_INVALID)
+ return FALSE;
+
+#if WITH_LIBGSF
+ switch (comics_document->type) {
+
+ case TYPE_ZIP:
+ case TYPE_TAR:
+ return comics_document_load_gsf (document, uri, error);
+ break;
+ default:
+ ;
+ }
+#endif
+
+ return comics_document_load_external (document, uri, error);
+}
static gboolean
comics_document_save (EvDocument *document,
@@ -568,14 +728,69 @@ comics_document_get_n_pages (EvDocument *document)
{
ComicsDocument *comics_document = COMICS_DOCUMENT (document);
+#if WITH_LIBGSF
+ if (comics_document->pages != NULL)
+ return comics_document->pages->len;
+#endif
if (comics_document->page_names == NULL)
return 0;
return comics_document->page_names->len;
}
+#if WITH_LIBGSF
static void
-comics_document_get_page_size (EvDocument *document,
+comics_document_get_page_size_gsf (EvDocument *document,
+ EvPage *page,
+ double *width,
+ double *height)
+{
+ ComicsDocument *comics_document = COMICS_DOCUMENT (document);
+ GdkPixbufLoader *loader;
+ guint8 const *data;
+ gsf_off_t len;
+ GdkPixbuf *pixbuf;
+ gboolean got_size = FALSE;
+
+ loader = gdk_pixbuf_loader_new ();
+ g_signal_connect (loader, "area-prepared",
+ G_CALLBACK (get_page_size_area_prepared_cb),
+ &got_size);
+
+ GsfInput *input = GSF_INPUT (
+ g_ptr_array_index(comics_document->pages, page->index));
+
+ gsf_input_seek(input, 0, G_SEEK_SET);
+
+ while ((len = gsf_input_remaining (input)) > 0) {
+
+ if (len > 1024)
+ len = 1024;
+
+ if ((data = gsf_input_read (input, len, NULL))) {
+ gdk_pixbuf_loader_write (loader, data, len, NULL);
+ }
+
+ if ((!data) || got_size) {
+ break;
+ }
+ }
+ gdk_pixbuf_loader_close (loader, NULL);
+
+ if (gdk_pixbuf_loader_get_pixbuf (loader)) {
+ pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
+ if (width)
+ *width = gdk_pixbuf_get_width (pixbuf);
+ if (height)
+ *height = gdk_pixbuf_get_height (pixbuf);
+ }
+
+ g_object_unref (loader);
+}
+#endif
+
+static void
+comics_document_get_page_size_external (EvDocument *document,
EvPage *page,
double *width,
double *height)
@@ -643,6 +858,27 @@ comics_document_get_page_size (EvDocument *document,
}
static void
+comics_document_get_page_size (EvDocument *document,
+ EvPage *page,
+ double *width,
+ double *height)
+{
+ ComicsDocument *comics_document = COMICS_DOCUMENT (document);
+ switch (comics_document->type) {
+#if WITH_LIBGSF
+ case TYPE_ZIP:
+ case TYPE_TAR:
+ comics_document_get_page_size_gsf (document,
+ page, width, height);
+ break;
+#endif
+ default:
+ comics_document_get_page_size_external (document,
+ page, width, height);
+ }
+}
+
+static void
get_page_size_area_prepared_cb (GdkPixbufLoader *loader,
gpointer data)
{
@@ -650,9 +886,54 @@ get_page_size_area_prepared_cb (GdkPixbufLoader *loader,
*got_size = TRUE;
}
+#if WITH_LIBGSF
static GdkPixbuf *
-comics_document_render_pixbuf (EvDocument *document,
- EvRenderContext *rc)
+comics_document_render_pixbuf_gsf (EvDocument *document,
+ EvRenderContext *rc)
+{
+ ComicsDocument *comics_document = COMICS_DOCUMENT (document);
+ GdkPixbufLoader *loader;
+ GdkPixbuf *rotated_pixbuf;
+ guint8 const *data;
+ gsf_off_t len;
+
+ loader = gdk_pixbuf_loader_new ();
+ g_signal_connect (loader, "size-prepared",
+ G_CALLBACK (render_pixbuf_size_prepared_cb),
+ &rc->scale);
+
+ GsfInput *input = GSF_INPUT (
+ g_ptr_array_index(comics_document->pages, rc->page->index));
+
+ gsf_input_seek(input, 0, G_SEEK_SET);
+ while ((len = gsf_input_remaining (input)) > 0) {
+
+ if (len > 1024)
+ len = 1024;
+
+ if ((data = gsf_input_read (input, len, NULL))) {
+ gdk_pixbuf_loader_write (loader, data, len, NULL);
+ }
+
+ if (!data) {
+ g_warning (_("Failed to read data"));
+ break;
+ }
+ }
+ gdk_pixbuf_loader_close (loader, NULL);
+
+ rotated_pixbuf = gdk_pixbuf_rotate_simple (
+ gdk_pixbuf_loader_get_pixbuf (loader),
+ 360 - rc->rotation);
+ g_object_unref (loader);
+
+ return rotated_pixbuf;
+}
+#endif
+
+static GdkPixbuf *
+comics_document_render_pixbuf_external (EvDocument *document,
+ EvRenderContext *rc)
{
GdkPixbufLoader *loader;
GdkPixbuf *rotated_pixbuf;
@@ -719,6 +1000,23 @@ comics_document_render_pixbuf (EvDocument *document,
return rotated_pixbuf;
}
+static GdkPixbuf *
+comics_document_render_pixbuf (EvDocument *document,
+ EvRenderContext *rc)
+{
+ ComicsDocument *comics_document = COMICS_DOCUMENT (document);
+ switch (comics_document->type) {
+#if WITH_LIBGSF
+ case TYPE_ZIP:
+ case TYPE_TAR:
+ return comics_document_render_pixbuf_gsf (document, rc);
+ break;
+#endif
+ default:
+ return comics_document_render_pixbuf_external (document, rc);
+ }
+}
+
static cairo_surface_t *
comics_document_render (EvDocument *document,
EvRenderContext *rc)
@@ -790,6 +1088,13 @@ comics_document_finalize (GObject *object)
g_free (comics_document->dir);
}
+#if WITH_LIBGSF
+ if (comics_document->pages) {
+ g_ptr_array_foreach (comics_document->pages, (GFunc) g_object_unref, NULL);
+ g_ptr_array_free (comics_document->pages, TRUE);
+ }
+#endif
+
if (comics_document->page_names) {
g_ptr_array_foreach (comics_document->page_names, (GFunc) g_free, NULL);
g_ptr_array_free (comics_document->page_names, TRUE);
@@ -823,8 +1128,14 @@ static void
comics_document_init (ComicsDocument *comics_document)
{
comics_document->archive = NULL;
+ comics_document->dir = NULL;
comics_document->page_names = NULL;
+ comics_document->pages = NULL;
+ comics_document->selected_command = NULL;
+ comics_document->alternative_command = NULL;
comics_document->extract_command = NULL;
+ comics_document->list_command = NULL;
+ comics_document->decompress_tmp = NULL;
}
/* Returns a list of file extensions supported by gdk-pixbuf */
diff --git a/configure.ac b/configure.ac
index d061c2e..13556b0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -672,6 +672,20 @@ AC_ARG_ENABLE(comics,
if test "x$enable_comics" = "xyes"; then
AC_DEFINE([ENABLE_COMICS], [1], [Enable support for comics.])
+ COMICS_PKGS="gtk+-$GTK_API_VERSION >= $GTK_REQUIRED"
+ AC_ARG_WITH(libgsf,
+ [AS_HELP_STRING([--with-libgsf],
+ [Use libgsf for comics support])],
+ [],
+ [case "$with_platform" in
+ win32) with_libgsf=yes ;;
+ *) with_libgsf=no ;;
+ esac])
+ if test "x$with_libgsf" = "xyes"; then
+ AC_DEFINE([WITH_LIBGSF], [1], [Use libgsf for comics support.])
+ COMICS_PKGS="$COMICS_PKGS libgsf-1"
+ fi
+ PKG_CHECK_MODULES(COMICS, [$COMICS_PKGS])
fi
AM_CONDITIONAL(ENABLE_COMICS, test x$enable_comics = xyes)
--
1.6.4.2