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
djvu-document.c
Go to the documentation of this file.
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
2 /*
3  * Copyright (C) 2005, Nickolay V. Shmyrev <nshmyrev@yandex.ru>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2, or (at your option)
8  * any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19 
20 #include "config.h"
21 
22 #include <config.h>
23 #include "djvu-document.h"
24 #include "djvu-text-page.h"
25 #include "djvu-links.h"
26 #include "djvu-document-private.h"
27 #include "ev-file-exporter.h"
28 #include "ev-document-misc.h"
29 #include "ev-document-find.h"
30 #include "ev-document-links.h"
31 #include "ev-selection.h"
32 #include "ev-file-helpers.h"
33 #include "ev-document-text.h"
34 
35 #include <glib.h>
36 #include <gdk-pixbuf/gdk-pixbuf.h>
37 #include <glib/gi18n-lib.h>
38 #include <string.h>
39 
40 enum {
43 };
44 
46 {
48 };
49 
51 
57 
59  {
65  });
66 
67 
68 #define EV_DJVU_ERROR ev_djvu_error_quark ()
69 
70 static GQuark
72 {
73  static GQuark q = 0;
74  if (q == 0)
75  q = g_quark_from_string ("ev-djvu-quark");
76 
77  return q;
78 }
79 
80 static void
81 handle_message (const ddjvu_message_t *msg, GError **error)
82 {
83  switch (msg->m_any.tag) {
84  case DDJVU_ERROR: {
85  gchar *error_str;
86 
87  if (msg->m_error.filename) {
88  error_str = g_strdup_printf ("DjvuLibre error: %s:%d",
89  msg->m_error.filename,
90  msg->m_error.lineno);
91  } else {
92  error_str = g_strdup_printf ("DjvuLibre error: %s",
93  msg->m_error.message);
94  }
95 
96  if (error) {
97  g_set_error_literal (error, EV_DJVU_ERROR, 0, error_str);
98  } else {
99  g_warning ("%s", error_str);
100  }
101 
102  g_free (error_str);
103  return;
104  }
105  break;
106  default:
107  break;
108  }
109 }
110 
111 void
112 djvu_handle_events (DjvuDocument *djvu_document, int wait, GError **error)
113 {
114  ddjvu_context_t *ctx = djvu_document->d_context;
115  const ddjvu_message_t *msg;
116 
117  if (!ctx)
118  return;
119 
120  if (wait)
121  ddjvu_message_wait (ctx);
122 
123  while ((msg = ddjvu_message_peek (ctx))) {
124  handle_message (msg, error);
125  ddjvu_message_pop (ctx);
126  if (error && *error)
127  return;
128  }
129 }
130 
131 static void
132 djvu_wait_for_message (DjvuDocument *djvu_document, ddjvu_message_tag_t message, GError **error)
133 {
134  ddjvu_context_t *ctx = djvu_document->d_context;
135  const ddjvu_message_t *msg;
136 
137  ddjvu_message_wait (ctx);
138  while ((msg = ddjvu_message_peek (ctx)) && (msg->m_any.tag != message)) {
139  handle_message (msg, error);
140  ddjvu_message_pop (ctx);
141  if (error && *error)
142  return;
143  }
144  if (msg && msg->m_any.tag == message)
145  ddjvu_message_pop (ctx);
146 }
147 
148 static gboolean
150  const char *uri,
151  GError **error)
152 {
153  DjvuDocument *djvu_document = DJVU_DOCUMENT (document);
154  ddjvu_document_t *doc;
155  gchar *filename;
156  gboolean missing_files = FALSE;
157  gboolean check_for_missing_files = FALSE;
158  GError *djvu_error = NULL;
159  gint n_files;
160  gint i;
161  gchar *base;
162 
163  /* FIXME: We could actually load uris */
164  filename = g_filename_from_uri (uri, NULL, error);
165  if (!filename)
166  return FALSE;
167 
168 #ifdef __APPLE__
169  doc = ddjvu_document_create_by_filename_utf8 (djvu_document->d_context, filename, TRUE);
170 #else
171  doc = ddjvu_document_create_by_filename (djvu_document->d_context, filename, TRUE);
172 #endif
173 
174  if (!doc) {
175  g_free (filename);
176  g_set_error_literal (error,
179  _("DjVu document has incorrect format"));
180  return FALSE;
181  }
182 
183  if (djvu_document->d_document)
184  ddjvu_document_release (djvu_document->d_document);
185 
186  djvu_document->d_document = doc;
187 
188  djvu_wait_for_message (djvu_document, DDJVU_DOCINFO, &djvu_error);
189  if (djvu_error) {
190  g_set_error_literal (error,
193  djvu_error->message);
194  g_error_free (djvu_error);
195  g_free (filename);
196  ddjvu_document_release (djvu_document->d_document);
197  djvu_document->d_document = NULL;
198 
199  return FALSE;
200  }
201 
202  if (ddjvu_document_decoding_error (djvu_document->d_document))
203  djvu_handle_events (djvu_document, TRUE, &djvu_error);
204 
205  if (djvu_error) {
206  g_set_error_literal (error,
209  djvu_error->message);
210  g_error_free (djvu_error);
211  g_free (filename);
212  ddjvu_document_release (djvu_document->d_document);
213  djvu_document->d_document = NULL;
214 
215  return FALSE;
216  }
217 
218  g_free (djvu_document->uri);
219  djvu_document->uri = g_strdup (uri);
220 
221  djvu_document->n_pages = ddjvu_document_get_pagenum (djvu_document->d_document);
222 
223  if (djvu_document->n_pages > 0) {
224  djvu_document->fileinfo_pages = g_new0 (ddjvu_fileinfo_t, djvu_document->n_pages);
225  djvu_document->file_ids = g_hash_table_new (g_str_hash, g_str_equal);
226  }
227  if (ddjvu_document_get_type (djvu_document->d_document) == DDJVU_DOCTYPE_INDIRECT)
228  check_for_missing_files = TRUE;
229 
230  base = g_path_get_dirname (filename);
231 
232  n_files = ddjvu_document_get_filenum (djvu_document->d_document);
233  for (i = 0; i < n_files; i++) {
234  ddjvu_fileinfo_t fileinfo;
235  gchar *file;
236 
237  ddjvu_document_get_fileinfo (djvu_document->d_document,
238  i, &fileinfo);
239 
240  if (fileinfo.type != 'P')
241  continue;
242 
243  if (fileinfo.pageno >= 0 && fileinfo.pageno < djvu_document->n_pages) {
244  djvu_document->fileinfo_pages[fileinfo.pageno] = fileinfo;
245  }
246 
247  g_hash_table_insert (djvu_document->file_ids,
248  (gpointer) djvu_document->fileinfo_pages[fileinfo.pageno].id,
249  GINT_TO_POINTER(fileinfo.pageno));
250 
251  if (check_for_missing_files && !missing_files) {
252  file = g_build_filename (base, fileinfo.id, NULL);
253  if (!g_file_test (file, G_FILE_TEST_EXISTS)) {
254  missing_files = TRUE;
255  }
256  g_free (file);
257  }
258  }
259  g_free (base);
260  g_free (filename);
261 
262  if (missing_files) {
263  g_set_error_literal (error,
264  G_FILE_ERROR,
265  G_FILE_ERROR_EXIST,
266  _("The document is composed of several files. "
267  "One or more of these files cannot be accessed."));
268 
269  return FALSE;
270  }
271 
272  return TRUE;
273 }
274 
275 
276 static gboolean
278  const char *uri,
279  GError **error)
280 {
281  DjvuDocument *djvu_document = DJVU_DOCUMENT (document);
282 
283  return ev_xfer_uri_simple (djvu_document->uri, uri, error);
284 }
285 
286 int
288 {
289  DjvuDocument *djvu_document = DJVU_DOCUMENT (document);
290 
291  g_return_val_if_fail (djvu_document->d_document, 0);
292 
293  return ddjvu_document_get_pagenum (djvu_document->d_document);
294 }
295 
296 static void
298  gint page,
299  double *width,
300  double *height,
301  double *dpi)
302 {
303  ddjvu_pageinfo_t info;
304  ddjvu_status_t r;
305 
306  while ((r = ddjvu_document_get_pageinfo(djvu_document->d_document, page, &info)) < DDJVU_JOB_OK)
307  djvu_handle_events(djvu_document, TRUE, NULL);
308 
309  if (r >= DDJVU_JOB_FAILED)
310  djvu_handle_events(djvu_document, TRUE, NULL);
311 
312  if (width)
313  *width = info.width * 72.0 / info.dpi;
314  if (height)
315  *height = info.height * 72.0 / info.dpi;
316  if (dpi)
317  *dpi = info.dpi;
318 }
319 
320 static void
322  EvPage *page,
323  double *width,
324  double *height)
325 {
326  DjvuDocument *djvu_document = DJVU_DOCUMENT (document);
327 
328  g_return_if_fail (djvu_document->d_document);
329 
330  document_get_page_size (djvu_document, page->index,
331  width, height, NULL);
332 }
333 
334 static cairo_surface_t *
336  EvRenderContext *rc)
337 {
338  DjvuDocument *djvu_document = DJVU_DOCUMENT (document);
339  cairo_surface_t *surface;
340  gchar *pixels;
341  gint rowstride;
342  ddjvu_rect_t rrect;
343  ddjvu_rect_t prect;
344  ddjvu_page_t *d_page;
345  ddjvu_page_rotation_t rotation;
346  gint buffer_modified;
347  double page_width, page_height;
348  gint transformed_width, transformed_height;
349 
350  d_page = ddjvu_page_create_by_pageno (djvu_document->d_document, rc->page->index);
351 
352  while (!ddjvu_page_decoding_done (d_page))
353  djvu_handle_events(djvu_document, TRUE, NULL);
354 
355  document_get_page_size (djvu_document, rc->page->index, &page_width, &page_height, NULL);
356  rotation = ddjvu_page_get_initial_rotation (d_page);
357 
358  ev_render_context_compute_transformed_size (rc, page_width, page_height,
359  &transformed_width, &transformed_height);
360 
361  /*
362  * Evince rotates documents in clockwise direction
363  * and djvulibre rotates documents in counter-clockwise direction.
364  */
365  switch (rc->rotation) {
366  case 90:
367  rotation += DDJVU_ROTATE_270;
368 
369  break;
370  case 180:
371  rotation += DDJVU_ROTATE_180;
372 
373  break;
374  case 270:
375  rotation += DDJVU_ROTATE_90;
376 
377  break;
378  default:
379  rotation += DDJVU_ROTATE_0;
380  }
381  rotation = rotation % 4;
382 
383  surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
384  transformed_width, transformed_height);
385 
386  rowstride = cairo_image_surface_get_stride (surface);
387  pixels = (gchar *)cairo_image_surface_get_data (surface);
388 
389  prect.x = 0;
390  prect.y = 0;
391  prect.w = transformed_width;
392  prect.h = transformed_height;
393  rrect = prect;
394 
395  ddjvu_page_set_rotation (d_page, rotation);
396 
397  buffer_modified = ddjvu_page_render (d_page, DDJVU_RENDER_COLOR,
398  &prect,
399  &rrect,
400  djvu_document->d_format,
401  rowstride,
402  pixels);
403 
404  if (!buffer_modified) {
405  cairo_t *cr = cairo_create (surface);
406 
407  cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
408  cairo_paint (cr);
409  cairo_destroy (cr);
410  } else {
411  cairo_surface_mark_dirty (surface);
412  }
413 
414  return surface;
415 }
416 
417 static char *
419  EvPage *page)
420 {
421  DjvuDocument *djvu_document = DJVU_DOCUMENT (document);
422  const gchar *title = NULL;
423  gchar *label = NULL;
424 
425  g_assert (page->index >= 0 && page->index < djvu_document->n_pages);
426 
427  if (djvu_document->fileinfo_pages == NULL)
428  return NULL;
429 
430  title = djvu_document->fileinfo_pages[page->index].title;
431 
432  if (!g_str_has_suffix (title, ".djvu"))
433  label = g_strdup (title);
434 
435  return label;
436 }
437 
438 static GdkPixbuf *
440  EvRenderContext *rc)
441 {
442  DjvuDocument *djvu_document = DJVU_DOCUMENT (document);
443  GdkPixbuf *pixbuf, *rotated_pixbuf;
444  gdouble page_width, page_height;
445  gint thumb_width, thumb_height;
446  guchar *pixels;
447 
448  g_return_val_if_fail (djvu_document->d_document, NULL);
449 
450  djvu_document_get_page_size (EV_DOCUMENT(djvu_document), rc->page,
451  &page_width, &page_height);
452 
453  ev_render_context_compute_scaled_size (rc, page_width, page_height,
454  &thumb_width, &thumb_height);
455 
456  pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8,
457  thumb_width, thumb_height);
458  gdk_pixbuf_fill (pixbuf, 0xffffffff);
459  pixels = gdk_pixbuf_get_pixels (pixbuf);
460 
461  while (ddjvu_thumbnail_status (djvu_document->d_document, rc->page->index, 1) < DDJVU_JOB_OK)
462  djvu_handle_events(djvu_document, TRUE, NULL);
463 
464  ddjvu_thumbnail_render (djvu_document->d_document, rc->page->index,
465  &thumb_width, &thumb_height,
466  djvu_document->thumbs_format,
467  gdk_pixbuf_get_rowstride (pixbuf),
468  (gchar *)pixels);
469 
470  rotated_pixbuf = gdk_pixbuf_rotate_simple (pixbuf, 360 - rc->rotation);
471  g_object_unref (pixbuf);
472 
473  return rotated_pixbuf;
474 }
475 
476 static cairo_surface_t *
478  EvRenderContext *rc)
479 {
480  DjvuDocument *djvu_document = DJVU_DOCUMENT (document);
481  cairo_surface_t *surface, *rotated_surface;
482  gdouble page_width, page_height;
483  gint thumb_width, thumb_height;
484  gchar *pixels;
485  gint thumbnail_rendered;
486 
487  g_return_val_if_fail (djvu_document->d_document, NULL);
488 
489  djvu_document_get_page_size (EV_DOCUMENT(djvu_document), rc->page,
490  &page_width, &page_height);
491 
492  ev_render_context_compute_scaled_size (rc, page_width, page_height,
493  &thumb_width, &thumb_height);
494 
495  surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
496  thumb_width, thumb_height);
497  pixels = (gchar *)cairo_image_surface_get_data (surface);
498 
499  while (ddjvu_thumbnail_status (djvu_document->d_document, rc->page->index, 1) < DDJVU_JOB_OK)
500  djvu_handle_events(djvu_document, TRUE, NULL);
501 
502  thumbnail_rendered = ddjvu_thumbnail_render (djvu_document->d_document,
503  rc->page->index,
504  &thumb_width, &thumb_height,
505  djvu_document->d_format,
506  cairo_image_surface_get_stride (surface),
507  pixels);
508 
509  if (!thumbnail_rendered) {
510  cairo_surface_destroy (surface);
511  surface = djvu_document_render (document, rc);
512  } else {
513  cairo_surface_mark_dirty (surface);
514  rotated_surface = ev_document_misc_surface_rotate_and_scale (surface,
515  thumb_width,
516  thumb_height,
517  rc->rotation);
518  cairo_surface_destroy (surface);
519  surface = rotated_surface;
520  }
521 
522  return surface;
523 }
524 
525 static void
526 djvu_document_finalize (GObject *object)
527 {
528  DjvuDocument *djvu_document = DJVU_DOCUMENT (object);
529 
530  if (djvu_document->d_document)
531  ddjvu_document_release (djvu_document->d_document);
532 
533  if (djvu_document->opts)
534  g_string_free (djvu_document->opts, TRUE);
535 
536  if (djvu_document->ps_filename)
537  g_free (djvu_document->ps_filename);
538 
539  if (djvu_document->fileinfo_pages)
540  g_free (djvu_document->fileinfo_pages);
541 
542  if (djvu_document->file_ids)
543  g_hash_table_destroy (djvu_document->file_ids);
544 
545  ddjvu_context_release (djvu_document->d_context);
546  ddjvu_format_release (djvu_document->d_format);
547  ddjvu_format_release (djvu_document->thumbs_format);
548  g_free (djvu_document->uri);
549 
550  G_OBJECT_CLASS (djvu_document_parent_class)->finalize (object);
551 }
552 
553 static void
555 {
556  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
557  EvDocumentClass *ev_document_class = EV_DOCUMENT_CLASS (klass);
558 
559  gobject_class->finalize = djvu_document_finalize;
560 
561  ev_document_class->load = djvu_document_load;
562  ev_document_class->save = djvu_document_save;
563  ev_document_class->get_n_pages = djvu_document_get_n_pages;
564  ev_document_class->get_page_label = djvu_document_get_page_label;
565  ev_document_class->get_page_size = djvu_document_get_page_size;
566  ev_document_class->render = djvu_document_render;
567  ev_document_class->get_thumbnail = djvu_document_get_thumbnail;
569 }
570 
571 static gchar *
572 djvu_text_copy (DjvuDocument *djvu_document,
573  gint page_num,
574  EvRectangle *rectangle)
575 {
576  miniexp_t page_text;
577  gchar *text = NULL;
578 
579  while ((page_text =
580  ddjvu_document_get_pagetext (djvu_document->d_document,
581  page_num, "char")) == miniexp_dummy)
582  djvu_handle_events (djvu_document, TRUE, NULL);
583 
584  if (page_text != miniexp_nil) {
585  DjvuTextPage *page = djvu_text_page_new (page_text);
586 
587  text = djvu_text_page_copy (page, rectangle);
588  djvu_text_page_free (page);
589  ddjvu_miniexp_release (djvu_document->d_document, page_text);
590  }
591 
592  return text;
593 }
594 
595 static void
597  EvRectangle *source,
598  gdouble height,
599  gdouble dpi)
600 {
601  dest->x1 = source->x1 * dpi / 72;
602  dest->x2 = source->x2 * dpi / 72;
603  dest->y1 = (height - source->y2) * dpi / 72;
604  dest->y2 = (height - source->y1) * dpi / 72;
605 }
606 
607 static GList *
609  gint page,
610  EvRectangle *points,
611  gdouble height,
612  gdouble dpi)
613 {
614  miniexp_t page_text;
615  EvRectangle rectangle;
616  GList *rects = NULL;
617 
618  djvu_convert_to_doc_rect (&rectangle, points, height, dpi);
619 
620  while ((page_text = ddjvu_document_get_pagetext (djvu_document->d_document,
621  page, "char")) == miniexp_dummy)
622  djvu_handle_events (djvu_document, TRUE, NULL);
623 
624  if (page_text != miniexp_nil) {
625  DjvuTextPage *tpage = djvu_text_page_new (page_text);
626 
627  rects = djvu_text_page_get_selection_region (tpage, &rectangle);
628  djvu_text_page_free (tpage);
629  ddjvu_miniexp_release (djvu_document->d_document, page_text);
630  }
631 
632  return rects;
633 }
634 
635 static cairo_region_t *
637  gint page,
638  gdouble scale_x,
639  gdouble scale_y,
640  EvRectangle *points)
641 {
642  double height, dpi;
643  GList *rects = NULL, *l;
644  cairo_region_t *region;
645 
646  document_get_page_size (djvu_document, page, NULL, &height, &dpi);
647  rects = djvu_selection_get_selection_rects (djvu_document, page, points,
648  height, dpi);
649  region = cairo_region_create ();
650  for (l = rects; l && l->data; l = g_list_next (l)) {
651  cairo_rectangle_int_t rect;
652  EvRectangle *r = (EvRectangle *)l->data;
653  gdouble tmp;
654 
655  tmp = r->y1;
656  r->x1 *= 72 / dpi;
657  r->x2 *= 72 / dpi;
658  r->y1 = height - r->y2 * 72 / dpi;
659  r->y2 = height - tmp * 72 / dpi;
660 
661  rect.x = (gint) ((r->x1 * scale_x) + 0.5);
662  rect.y = (gint) ((r->y1 * scale_y) + 0.5);
663  rect.width = (gint) ((r->x2 * scale_x) + 0.5) - rect.x;
664  rect.height = (gint) ((r->y2 * scale_y) + 0.5) - rect.y;
665  cairo_region_union_rectangle (region, &rect);
666  ev_rectangle_free (r);
667  }
668  g_list_free (l);
669 
670  return region;
671 }
672 
673 static cairo_region_t *
675  EvRenderContext *rc,
676  EvSelectionStyle style,
677  EvRectangle *points)
678 {
679  DjvuDocument *djvu_document = DJVU_DOCUMENT (selection);
680  gdouble page_width, page_height;
681  gdouble scale_x, scale_y;
682 
683  document_get_page_size (djvu_document, rc->page->index, &page_width, &page_height, NULL);
684  ev_render_context_compute_scales (rc, page_width, page_height, &scale_x, &scale_y);
685 
686  return djvu_get_selection_region (djvu_document, rc->page->index,
687  scale_x, scale_y, points);
688 }
689 
690 static gchar *
692  EvPage *page,
693  EvSelectionStyle style,
694  EvRectangle *points)
695 {
696  DjvuDocument *djvu_document = DJVU_DOCUMENT (selection);
697  double height, dpi;
698  EvRectangle rectangle;
699  gchar *text;
700 
701  document_get_page_size (djvu_document, page->index, NULL, &height, &dpi);
702  djvu_convert_to_doc_rect (&rectangle, points, height, dpi);
703  text = djvu_text_copy (djvu_document, page->index, &rectangle);
704 
705  if (text == NULL)
706  text = g_strdup ("");
707 
708  return text;
709 }
710 
711 static void
713 {
716 }
717 
718 static cairo_region_t *
720  EvPage *page)
721 {
722  DjvuDocument *djvu_document = DJVU_DOCUMENT (document_text);
723  EvRectangle points;
724 
725  points.x1 = 0;
726  points.y1 = 0;
727 
728  document_get_page_size (djvu_document, page->index,
729  &points.x2, &points.y2, NULL);
730 
731  return djvu_get_selection_region (djvu_document, page->index,
732  1.0, 1.0, &points);
733 }
734 
735 static gchar *
737  EvPage *page)
738 {
739  DjvuDocument *djvu_document = DJVU_DOCUMENT (selection);
740  miniexp_t page_text;
741  gchar *text = NULL;
742 
743  while ((page_text = ddjvu_document_get_pagetext (djvu_document->d_document,
744  page->index,
745  "char")) == miniexp_dummy)
746  djvu_handle_events (djvu_document, TRUE, NULL);
747 
748  if (page_text != miniexp_nil) {
749  DjvuTextPage *tpage = djvu_text_page_new (page_text);
750 
752  text = tpage->text;
753  tpage->text = NULL;
754  djvu_text_page_free (tpage);
755  ddjvu_miniexp_release (djvu_document->d_document, page_text);
756  }
757  return text;
758 }
759 
760 static void
762 {
765 }
766 
767 /* EvFileExporterIface */
768 static void
771 {
772  DjvuDocument *djvu_document = DJVU_DOCUMENT (exporter);
773 
774  if (djvu_document->ps_filename)
775  g_free (djvu_document->ps_filename);
776  djvu_document->ps_filename = g_strdup (fc->filename);
777 
778  g_string_assign (djvu_document->opts, "-page=");
779 }
780 
781 static void
783  EvRenderContext *rc)
784 {
785  DjvuDocument *djvu_document = DJVU_DOCUMENT (exporter);
786 
787  g_string_append_printf (djvu_document->opts, "%d,", (rc->page->index) + 1);
788 }
789 
790 static void
792 {
793  int d_optc = 1;
794  const char *d_optv[d_optc];
795  ddjvu_job_t *job;
796 
797  DjvuDocument *djvu_document = DJVU_DOCUMENT (exporter);
798 
799  FILE *fn = fopen (djvu_document->ps_filename, "w");
800  if (fn == NULL) {
801  g_warning ("Cannot open file ā€œ%sā€.", djvu_document->ps_filename);
802  return;
803  }
804 
805  d_optv[0] = djvu_document->opts->str;
806 
807  job = ddjvu_document_print(djvu_document->d_document, fn, d_optc, d_optv);
808  while (!ddjvu_job_done(job)) {
809  djvu_handle_events (djvu_document, TRUE, NULL);
810  }
811 
812  fclose(fn);
813 }
814 
817 {
823 }
824 
825 static void
827 {
832 }
833 
834 static void
836 {
837  guint masks[4] = { 0xff0000, 0xff00, 0xff, 0xff000000 };
838 
839  djvu_document->d_context = ddjvu_context_create ("Evince");
840  djvu_document->d_format = ddjvu_format_create (DDJVU_FORMAT_RGBMASK32, 4, masks);
841  ddjvu_format_set_row_order (djvu_document->d_format, 1);
842 
843  djvu_document->thumbs_format = ddjvu_format_create (DDJVU_FORMAT_RGB24, 0, 0);
844  ddjvu_format_set_row_order (djvu_document->thumbs_format, 1);
845 
846  djvu_document->ps_filename = NULL;
847  djvu_document->opts = g_string_new ("");
848 
849  djvu_document->d_document = NULL;
850 }
851 
852 static GList *
854  EvPage *page,
855  const char *text,
856  gboolean case_sensitive)
857 {
858  DjvuDocument *djvu_document = DJVU_DOCUMENT (document);
859  miniexp_t page_text;
860  gdouble width, height, dpi;
861  GList *matches = NULL, *l;
862 
863  g_return_val_if_fail (text != NULL, NULL);
864 
865  while ((page_text = ddjvu_document_get_pagetext (djvu_document->d_document,
866  page->index,
867  "char")) == miniexp_dummy)
868  djvu_handle_events (djvu_document, TRUE, NULL);
869 
870  if (page_text != miniexp_nil) {
871  DjvuTextPage *tpage = djvu_text_page_new (page_text);
872 
873  djvu_text_page_index_text (tpage, case_sensitive);
874  if (tpage->links->len > 0) {
875  djvu_text_page_search (tpage, text);
876  matches = tpage->results;
877  }
878  djvu_text_page_free (tpage);
879  ddjvu_miniexp_release (djvu_document->d_document, page_text);
880  }
881  if (!matches)
882  return NULL;
883 
884  document_get_page_size (djvu_document, page->index, &width, &height, &dpi);
885  for (l = matches; l && l->data; l = g_list_next (l)) {
886  EvRectangle *r = (EvRectangle *)l->data;
887  gdouble tmp = r->y1;
888 
889  r->x1 *= 72.0 / dpi;
890  r->x2 *= 72.0 / dpi;
891 
892  r->y1 = height - r->y2 * 72.0 / dpi;
893  r->y2 = height - tmp * 72.0 / dpi;
894  }
895 
896 
897  return matches;
898 }
899 
900 static EvFindOptions
902 {
903  return EV_FIND_CASE_SENSITIVE;
904 }
905 
906 static void
908 {
911 }
912 
913 static EvMappingList *
915  EvPage *page)
916 {
917  gdouble dpi;
918 
919  document_get_page_size (DJVU_DOCUMENT (document_links), page->index, NULL, NULL, &dpi);
920  return djvu_links_get_links (document_links, page->index, 72.0 / dpi);
921 }
922 
923 static void
925 {
931 }