Evince
Evince is a document viewer capable of displaying multiple and single page document formats like PDF and Postscript.
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
comics-document.c File Reference
#include <config.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <glib.h>
#include <glib/gi18n-lib.h>
#include <glib/gstdio.h>
#include <gio/gio.h>
#include "comics-document.h"
#include "ev-document-misc.h"
#include "ev-file-helpers.h"
#include "ev-archive.h"
+ Include dependency graph for comics-document.c:

Go to the source code of this file.

Data Structures

struct  _ComicsDocumentClass
 
struct  _ComicsDocument
 
struct  PixbufInfo
 

Macros

#define BLOCK_SIZE   10240
 

Typedefs

typedef struct _ComicsDocumentClass ComicsDocumentClass
 

Functions

static GSList * get_supported_image_extensions (void)
 
static char ** comics_document_list (ComicsDocument *comics_document)
 
static gboolean comics_check_decompress_support (gchar *mime_type, ComicsDocument *comics_document, GError **error)
 
static int sort_page_names (gconstpointer a, gconstpointer b)
 
static gboolean comics_document_load (EvDocument *document, const char *uri, GError **error)
 
static gboolean comics_document_save (EvDocument *document, const char *uri, GError **error)
 
static int comics_document_get_n_pages (EvDocument *document)
 
static void get_page_size_prepared_cb (GdkPixbufLoader *loader, int width, int height, PixbufInfo *info)
 
static void comics_document_get_page_size (EvDocument *document, EvPage *page, double *width, double *height)
 
static void render_pixbuf_size_prepared_cb (GdkPixbufLoader *loader, gint width, gint height, EvRenderContext *rc)
 
static GdkPixbuf * comics_document_render_pixbuf (EvDocument *document, EvRenderContext *rc)
 
static cairo_surface_t * comics_document_render (EvDocument *document, EvRenderContext *rc)
 
static void comics_document_finalize (GObject *object)
 
static void comics_document_class_init (ComicsDocumentClass *klass)
 
static void comics_document_init (ComicsDocument *comics_document)
 

Macro Definition Documentation

#define BLOCK_SIZE   10240

Definition at line 39 of file comics-document.c.

Typedef Documentation

Definition at line 41 of file comics-document.c.

Function Documentation

static gboolean comics_check_decompress_support ( gchar *  mime_type,
ComicsDocument comics_document,
GError **  error 
)
static

Definition at line 105 of file comics-document.c.

108 {
109  if (g_content_type_is_a (mime_type, "application/x-cbr") ||
110  g_content_type_is_a (mime_type, "application/x-rar")) {
112  return TRUE;
113  } else if (g_content_type_is_a (mime_type, "application/x-cbz") ||
114  g_content_type_is_a (mime_type, "application/zip")) {
116  return TRUE;
117  } else if (g_content_type_is_a (mime_type, "application/x-cb7") ||
118  g_content_type_is_a (mime_type, "application/x-7z-compressed")) {
120  return TRUE;
121  } else if (g_content_type_is_a (mime_type, "application/x-cbt") ||
122  g_content_type_is_a (mime_type, "application/x-tar")) {
124  return TRUE;
125  } else {
126  g_set_error (error,
129  _("Not a comic book MIME type: %s"),
130  mime_type);
131  return FALSE;
132  }
133  g_set_error_literal (error,
136  _("libarchive lacks support for this comic book’s "
137  "compression, please contact your distributor"));
138  return FALSE;
139 }

+ Here is the caller graph for this function:

static void comics_document_class_init ( ComicsDocumentClass klass)
static

Definition at line 475 of file comics-document.c.

476 {
477  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
478  EvDocumentClass *ev_document_class = EV_DOCUMENT_CLASS (klass);
479 
480  gobject_class->finalize = comics_document_finalize;
481 
482  ev_document_class->load = comics_document_load;
483  ev_document_class->save = comics_document_save;
484  ev_document_class->get_n_pages = comics_document_get_n_pages;
485  ev_document_class->get_page_size = comics_document_get_page_size;
486  ev_document_class->render = comics_document_render;
487 }
static void comics_document_finalize ( GObject *  object)
static

Definition at line 458 of file comics-document.c.

459 {
460  ComicsDocument *comics_document = COMICS_DOCUMENT (object);
461 
462  if (comics_document->page_names) {
463  g_ptr_array_foreach (comics_document->page_names, (GFunc) g_free, NULL);
464  g_ptr_array_free (comics_document->page_names, TRUE);
465  }
466 
467  g_clear_object (&comics_document->archive);
468  g_free (comics_document->archive_path);
469  g_free (comics_document->archive_uri);
470 
471  G_OBJECT_CLASS (comics_document_parent_class)->finalize (object);
472 }

+ Here is the caller graph for this function:

static int comics_document_get_n_pages ( EvDocument document)
static

Definition at line 252 of file comics-document.c.

253 {
254  ComicsDocument *comics_document = COMICS_DOCUMENT (document);
255 
256  if (comics_document->page_names == NULL)
257  return 0;
258 
259  return comics_document->page_names->len;
260 }

+ Here is the caller graph for this function:

static void comics_document_get_page_size ( EvDocument document,
EvPage page,
double *  width,
double *  height 
)
static

Definition at line 280 of file comics-document.c.

284 {
285  GdkPixbufLoader *loader;
286  ComicsDocument *comics_document = COMICS_DOCUMENT (document);
287  const char *page_path;
288  PixbufInfo info;
289  GError *error = NULL;
290 
291  if (!ev_archive_open_filename (comics_document->archive, comics_document->archive_path, &error)) {
292  g_warning ("Fatal error opening archive: %s", error->message);
293  g_error_free (error);
294  goto out;
295  }
296 
297  loader = gdk_pixbuf_loader_new ();
298  info.got_info = FALSE;
299  g_signal_connect (loader, "size-prepared",
300  G_CALLBACK (get_page_size_prepared_cb),
301  &info);
302 
303  page_path = g_ptr_array_index (comics_document->page_names, page->index);
304 
305  while (1) {
306  const char *name;
307  GError *error = NULL;
308 
309  if (!ev_archive_read_next_header (comics_document->archive, &error)) {
310  if (error != NULL) {
311  g_warning ("Fatal error handling archive: %s", error->message);
312  g_error_free (error);
313  }
314  break;
315  }
316 
317  name = ev_archive_get_entry_pathname (comics_document->archive);
318  if (g_strcmp0 (name, page_path) == 0) {
319  char buf[BLOCK_SIZE];
320  gssize read;
321  gint64 left;
322 
323  left = ev_archive_get_entry_size (comics_document->archive);
324  read = ev_archive_read_data (comics_document->archive, buf,
325  MIN(BLOCK_SIZE, left), &error);
326  while (read > 0 && !info.got_info) {
327  if (!gdk_pixbuf_loader_write (loader, (guchar *) buf, read, &error)) {
328  read = -1;
329  break;
330  }
331  left -= read;
332  read = ev_archive_read_data (comics_document->archive, buf,
333  MIN(BLOCK_SIZE, left), &error);
334  }
335  if (read < 0) {
336  g_warning ("Fatal error reading '%s' in archive: %s", name, error->message);
337  g_error_free (error);
338  }
339  break;
340  }
341  }
342 
343  gdk_pixbuf_loader_close (loader, NULL);
344  g_object_unref (loader);
345 
346  if (info.got_info) {
347  if (width)
348  *width = info.width;
349  if (height)
350  *height = info.height;
351  }
352 
353 out:
354  ev_archive_reset (comics_document->archive);
355 }

+ Here is the caller graph for this function:

static void comics_document_init ( ComicsDocument comics_document)
static

Definition at line 490 of file comics-document.c.

491 {
492  comics_document->archive = ev_archive_new ();
493 }
static char** comics_document_list ( ComicsDocument comics_document)
static

Definition at line 62 of file comics-document.c.

63 {
64  char **ret = NULL;
65  GPtrArray *array;
66 
67  if (!ev_archive_open_filename (comics_document->archive, comics_document->archive_path, NULL))
68  goto out;
69 
70  array = g_ptr_array_new ();
71 
72  while (1) {
73  const char *name;
74  GError *error = NULL;
75 
76  if (!ev_archive_read_next_header (comics_document->archive, &error)) {
77  if (error != NULL) {
78  g_warning ("Fatal error handling archive: %s", error->message);
79  g_error_free (error);
80  }
81  break;
82  }
83 
84  name = ev_archive_get_entry_pathname (comics_document->archive);
85 
86  g_debug ("Adding '%s' to the list of files in the comics", name);
87  g_ptr_array_add (array, g_strdup (name));
88  }
89 
90  if (array->len == 0) {
91  g_ptr_array_free (array, TRUE);
92  } else {
93  g_ptr_array_add (array, NULL);
94  ret = (char **) g_ptr_array_free (array, FALSE);
95  }
96 
97 out:
98  ev_archive_reset (comics_document->archive);
99  return ret;
100 }

+ Here is the caller graph for this function:

static gboolean comics_document_load ( EvDocument document,
const char *  uri,
GError **  error 
)
static

Definition at line 160 of file comics-document.c.

163 {
164  ComicsDocument *comics_document = COMICS_DOCUMENT (document);
165  GSList *supported_extensions;
166  gchar *mime_type;
167  gchar **cb_files, *cb_file;
168  int i;
169  GError *err = NULL;
170  GFile *file;
171 
172  file = g_file_new_for_uri (uri);
173  comics_document->archive_path = g_file_get_path (file);
174  g_object_unref (file);
175 
176  if (!comics_document->archive_path) {
177  g_set_error_literal (error,
180  _("Can not get local path for archive"));
181  return FALSE;
182  }
183 
184  comics_document->archive_uri = g_strdup (uri);
185 
186  mime_type = ev_file_get_mime_type (uri, FALSE, &err);
187  if (mime_type == NULL)
188  return FALSE;
189 
190  if (!comics_check_decompress_support (mime_type, comics_document, error)) {
191  g_free (mime_type);
192  return FALSE;
193  }
194  g_free (mime_type);
195 
196  /* Get list of files in archive */
197  cb_files = comics_document_list (comics_document);
198  if (!cb_files) {
199  g_set_error_literal (error,
202  _("File corrupted or no files in archive"));
203  return FALSE;
204  }
205 
206  comics_document->page_names = g_ptr_array_sized_new (64);
207 
208  supported_extensions = get_supported_image_extensions ();
209  for (i = 0; cb_files[i] != NULL; i++) {
210  cb_file = cb_files[i];
211  gchar *suffix = g_strrstr (cb_file, ".");
212  if (!suffix)
213  continue;
214  suffix = g_ascii_strdown (suffix + 1, -1);
215  if (g_slist_find_custom (supported_extensions, suffix,
216  (GCompareFunc) strcmp) != NULL) {
217  g_ptr_array_add (comics_document->page_names,
218  g_strstrip (g_strdup (cb_file)));
219  }
220  g_free (suffix);
221  }
222  g_strfreev (cb_files);
223  g_slist_foreach (supported_extensions, (GFunc) g_free, NULL);
224  g_slist_free (supported_extensions);
225 
226  if (comics_document->page_names->len == 0) {
227  g_set_error (error,
230  _("No images found in archive %s"),
231  uri);
232  return FALSE;
233  }
234 
235  /* Now sort the pages */
236  g_ptr_array_sort (comics_document->page_names, sort_page_names);
237 
238  return TRUE;
239 }

+ Here is the caller graph for this function:

static cairo_surface_t* comics_document_render ( EvDocument document,
EvRenderContext rc 
)
static

Definition at line 444 of file comics-document.c.

446 {
447  GdkPixbuf *pixbuf;
448  cairo_surface_t *surface;
449 
450  pixbuf = comics_document_render_pixbuf (document, rc);
451  surface = ev_document_misc_surface_from_pixbuf (pixbuf);
452  g_object_unref (pixbuf);
453 
454  return surface;
455 }

+ Here is the caller graph for this function:

static GdkPixbuf* comics_document_render_pixbuf ( EvDocument document,
EvRenderContext rc 
)
static

Definition at line 370 of file comics-document.c.

372 {
373  GdkPixbufLoader *loader;
374  GdkPixbuf *tmp_pixbuf;
375  GdkPixbuf *rotated_pixbuf = NULL;
376  ComicsDocument *comics_document = COMICS_DOCUMENT (document);
377  const char *page_path;
378  GError *error = NULL;
379 
380  if (!ev_archive_open_filename (comics_document->archive, comics_document->archive_path, &error)) {
381  g_warning ("Fatal error opening archive: %s", error->message);
382  g_error_free (error);
383  goto out;
384  }
385 
386  loader = gdk_pixbuf_loader_new ();
387  g_signal_connect (loader, "size-prepared",
388  G_CALLBACK (render_pixbuf_size_prepared_cb),
389  rc);
390 
391  page_path = g_ptr_array_index (comics_document->page_names, rc->page->index);
392 
393  while (1) {
394  const char *name;
395 
396  if (!ev_archive_read_next_header (comics_document->archive, &error)) {
397  if (error != NULL) {
398  g_warning ("Fatal error handling archive: %s", error->message);
399  g_error_free (error);
400  }
401  break;
402  }
403 
404  name = ev_archive_get_entry_pathname (comics_document->archive);
405  if (g_strcmp0 (name, page_path) == 0) {
406  size_t size = ev_archive_get_entry_size (comics_document->archive);
407  char *buf;
408  ssize_t read;
409 
410  buf = g_malloc (size);
411  read = ev_archive_read_data (comics_document->archive, buf, size, &error);
412  if (read <= 0) {
413  if (read < 0) {
414  g_warning ("Fatal error reading '%s' in archive: %s", name, error->message);
415  g_error_free (error);
416  } else {
417  g_warning ("Read an empty file from the archive");
418  }
419  } else {
420  gdk_pixbuf_loader_write (loader, (guchar *) buf, size, NULL);
421  }
422  g_free (buf);
423  gdk_pixbuf_loader_close (loader, NULL);
424  break;
425  }
426  }
427 
428  tmp_pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
429  if (tmp_pixbuf) {
430  if ((rc->rotation % 360) == 0)
431  rotated_pixbuf = g_object_ref (tmp_pixbuf);
432  else
433  rotated_pixbuf = gdk_pixbuf_rotate_simple (tmp_pixbuf,
434  360 - rc->rotation);
435  }
436  g_object_unref (loader);
437 
438 out:
439  ev_archive_reset (comics_document->archive);
440  return rotated_pixbuf;
441 }

+ Here is the caller graph for this function:

static gboolean comics_document_save ( EvDocument document,
const char *  uri,
GError **  error 
)
static

Definition at line 242 of file comics-document.c.

245 {
246  ComicsDocument *comics_document = COMICS_DOCUMENT (document);
247 
248  return ev_xfer_uri_simple (comics_document->archive_uri, uri, error);
249 }

+ Here is the caller graph for this function:

static void get_page_size_prepared_cb ( GdkPixbufLoader *  loader,
int  width,
int  height,
PixbufInfo info 
)
static

Definition at line 269 of file comics-document.c.

273 {
274  info->got_info = TRUE;
275  info->height = height;
276  info->width = width;
277 }

+ Here is the caller graph for this function:

static GSList * get_supported_image_extensions ( void  )
static

Definition at line 497 of file comics-document.c.

498 {
499  GSList *extensions = NULL;
500  GSList *formats = gdk_pixbuf_get_formats ();
501  GSList *l;
502 
503  for (l = formats; l != NULL; l = l->next) {
504  int i;
505  gchar **ext = gdk_pixbuf_format_get_extensions (l->data);
506 
507  for (i = 0; ext[i] != NULL; i++) {
508  extensions = g_slist_append (extensions,
509  g_strdup (ext[i]));
510  }
511 
512  g_strfreev (ext);
513  }
514 
515  g_slist_free (formats);
516  return extensions;
517 }

+ Here is the caller graph for this function:

static void render_pixbuf_size_prepared_cb ( GdkPixbufLoader *  loader,
gint  width,
gint  height,
EvRenderContext rc 
)
static

Definition at line 358 of file comics-document.c.

362 {
363  int scaled_width, scaled_height;
364 
365  ev_render_context_compute_scaled_size (rc, width, height, &scaled_width, &scaled_height);
366  gdk_pixbuf_loader_set_size (loader, scaled_width, scaled_height);
367 }

+ Here is the caller graph for this function:

static int sort_page_names ( gconstpointer  a,
gconstpointer  b 
)
static

Definition at line 142 of file comics-document.c.

144 {
145  gchar *temp1, *temp2;
146  gint ret;
147 
148  temp1 = g_utf8_collate_key_for_filename (* (const char **) a, -1);
149  temp2 = g_utf8_collate_key_for_filename (* (const char **) b, -1);
150 
151  ret = strcmp (temp1, temp2);
152 
153  g_free (temp1);
154  g_free (temp2);
155 
156  return ret;
157 }

+ Here is the caller graph for this function: