1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
2 /* pdfdocument.h: Implementation of EvDocument for PDF
3 * Copyright (C) 2004, Red Hat, Inc.
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)
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.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 #include <glib/gi18n.h>
22 #include "pdf-document.h"
23 #include "ev-ps-exporter.h"
24 #include "ev-document-find.h"
25 #include "ev-document-misc.h"
26 #include "ev-document-links.h"
27 #include "ev-document-security.h"
28 #include "ev-document-thumbnails.h"
30 #include <goo/GooList.h>
31 #include <splash/SplashBitmap.h>
32 #include <GlobalParams.h>
35 #include <ErrorCodes.h>
36 #include <UnicodeMap.h>
38 #include <PSOutputDev.h>
41 #include "GDKSplashOutputDev.h"
50 PdfDocument *document;
54 /* full results are only possible for the rendered current page */
56 GArray *current_page_results;
57 int *other_page_flags; /* length n_pages + 1, first element ignored */
58 int start_page; /* skip this one as we iterate, since we did it first */
59 int search_page; /* the page we're searching now */
60 TextOutputDev *output_dev;
63 typedef struct _PdfDocumentClass PdfDocumentClass;
65 #define PDF_DOCUMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PDF_TYPE_DOCUMENT, PdfDocumentClass))
66 #define PDF_IS_DOCUMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PDF_TYPE_DOCUMENT))
67 #define PDF_DOCUMENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PDF_TYPE_DOCUMENT, PdfDocumentClass))
69 struct _PdfDocumentClass
71 GObjectClass parent_class;
76 GObject parent_instance;
84 GDKSplashOutputDev *out;
92 PdfDocumentSearch *search;
95 static void pdf_document_document_links_iface_init (EvDocumentLinksIface *iface);
96 static void pdf_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface);
97 static void pdf_document_document_iface_init (EvDocumentIface *iface);
98 static void pdf_document_ps_exporter_iface_init (EvPSExporterIface *iface);
99 static void pdf_document_find_iface_init (EvDocumentFindIface *iface);
100 static void pdf_document_security_iface_init (EvDocumentSecurityIface *iface);
101 static void pdf_document_search_free (PdfDocumentSearch *search);
102 static void pdf_document_search_page_changed (PdfDocumentSearch *search);
105 G_DEFINE_TYPE_WITH_CODE (PdfDocument, pdf_document, G_TYPE_OBJECT,
107 G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT,
108 pdf_document_document_iface_init);
109 G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_LINKS,
110 pdf_document_document_links_iface_init);
111 G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_THUMBNAILS,
112 pdf_document_document_thumbnails_iface_init);
113 G_IMPLEMENT_INTERFACE (EV_TYPE_PS_EXPORTER,
114 pdf_document_ps_exporter_iface_init);
115 G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_FIND,
116 pdf_document_find_iface_init);
117 G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_SECURITY,
118 pdf_document_security_iface_init);
122 document_init_links (PdfDocument *pdf_document)
127 if (pdf_document->links) {
128 delete pdf_document->links;
130 page = pdf_document->doc->getCatalog ()->getPage (pdf_document->page);
131 pdf_document->links = new Links (page->getAnnots (&obj),
132 pdf_document->doc->getCatalog ()->getBaseURI ());
137 document_display_page (PdfDocument *pdf_document)
139 if (pdf_document->out != NULL) {
140 pdf_document->doc->displayPage (pdf_document->out, pdf_document->page,
141 72 * pdf_document->scale,
142 72 * pdf_document->scale,
145 document_init_links (pdf_document);
147 /* Update the search results available to the app since
148 * we only provide full results on the current page
150 if (pdf_document->search)
151 pdf_document_search_page_changed (pdf_document->search);
156 pdf_document_load (EvDocument *document,
160 PdfDocument *pdf_document = PDF_DOCUMENT (document);
164 GooString *filename_g;
168 globalParams = new GlobalParams("/etc/xpdfrc");
169 globalParams->setupBaseFontsFc(NULL);
172 if (! pdf_document->umap) {
173 enc = new GooString("UTF-8");
174 pdf_document->umap = globalParams->getUnicodeMap(enc);
175 pdf_document->umap->incRefCnt ();
179 filename = g_filename_from_uri (uri, NULL, error);
183 filename_g = new GooString (filename);
186 // open the PDF file, assumes ownership of filename_g
187 GooString *password = NULL;
188 if (pdf_document->password)
189 password = new GooString (pdf_document->password);
190 newDoc = new PDFDoc(filename_g, password, password);
194 if (!newDoc->isOk()) {
195 err = newDoc->getErrorCode();
197 if (err == errEncrypted) {
198 g_set_error (error, EV_DOCUMENT_ERROR,
199 EV_DOCUMENT_ERROR_ENCRYPTED,
200 "Document is encrypted.");
202 g_set_error (error, G_FILE_ERROR,
204 "Failed to load document (error %d) '%s'\n",
212 if (pdf_document->doc)
213 delete pdf_document->doc;
214 pdf_document->doc = newDoc;
216 pdf_document->page = 1;
218 if (pdf_document->out)
219 pdf_document->out->startDoc(pdf_document->doc->getXRef());
221 g_object_notify (G_OBJECT (pdf_document), "title");
227 pdf_document_save (EvDocument *document,
231 PdfDocument *pdf_document = PDF_DOCUMENT (document);
233 gboolean retval = FALSE;
235 filename = g_filename_from_uri (uri, NULL, error);
236 if (filename != NULL) {
237 GooString *fname = new GooString (filename);
239 retval = pdf_document->doc->saveAs (fname);
246 pdf_document_get_n_pages (EvDocument *document)
248 PdfDocument *pdf_document = PDF_DOCUMENT (document);
250 if (pdf_document->doc)
251 return pdf_document->doc->getNumPages();
257 pdf_document_set_page (EvDocument *document,
260 PdfDocument *pdf_document = PDF_DOCUMENT (document);
262 page = CLAMP (page, 1, ev_document_get_n_pages (document));
264 if (page != pdf_document->page) {
265 pdf_document->page = page;
266 document_display_page (pdf_document);
267 ev_document_page_changed (EV_DOCUMENT (pdf_document));
272 pdf_document_get_page (EvDocument *document)
274 PdfDocument *pdf_document = PDF_DOCUMENT (document);
276 return pdf_document->page;
280 redraw_callback (void *data)
282 /* Need to hook up through a EvDocument callback? */
286 pdf_document_set_target (EvDocument *document,
289 PdfDocument *pdf_document = PDF_DOCUMENT (document);
291 if (pdf_document->target != target) {
292 if (pdf_document->target)
293 g_object_unref (pdf_document->target);
295 pdf_document->target = target;
297 if (pdf_document->target)
298 g_object_ref (pdf_document->target);
300 if (pdf_document->out) {
301 delete pdf_document->out;
302 pdf_document->out = NULL;
305 if (pdf_document->target) {
306 pdf_document->out = new GDKSplashOutputDev (gdk_drawable_get_screen (pdf_document->target),
307 redraw_callback, (void*) document);
309 if (pdf_document->doc)
310 pdf_document->out->startDoc(pdf_document->doc->getXRef());
312 document_display_page (pdf_document);
318 pdf_document_set_scale (EvDocument *document,
321 PdfDocument *pdf_document = PDF_DOCUMENT (document);
323 if (pdf_document->scale != scale) {
324 pdf_document->scale = scale;
325 document_display_page (pdf_document);
326 ev_document_scale_changed (EV_DOCUMENT (pdf_document));
331 pdf_document_set_page_offset (EvDocument *document,
335 PdfDocument *pdf_document = PDF_DOCUMENT (document);
337 pdf_document->page_x_offset = x;
338 pdf_document->page_y_offset = y;
342 canonical_multiple_of_90 (gint n)
351 return 90 * (gint)((n / 90.0) + .5);
355 pdf_document_get_page_size (EvDocument *document,
360 PdfDocument *pdf_document = PDF_DOCUMENT (document);
362 int page_width = 1, page_height = 1;
363 double scale = pdf_document->scale;
366 page = pdf_document->page;
368 doc_page = pdf_document->doc->getCatalog ()->getPage (page);
373 page_rotate = canonical_multiple_of_90 (doc_page->getRotate ());
374 if (page_rotate == 90 || page_rotate == 270) {
375 page_width = (int) ((doc_page->getHeight () * scale) + 0.5);
376 page_height = (int) ((doc_page->getWidth () * scale) + 0.5);
377 } else /* if (page_rotate == 0 || page_rotate == 180) */ {
378 page_width = (int) ((doc_page->getWidth () * scale) + 0.5);
379 page_height = (int) ((doc_page->getHeight () * scale) + 0.5);
383 if (width) *width = page_width;
384 if (height) *height = page_height;
388 pdf_document_render (EvDocument *document,
394 PdfDocument *pdf_document = PDF_DOCUMENT (document);
398 if (!pdf_document->target)
401 page.x = pdf_document->page_x_offset;
402 page.y = pdf_document->page_y_offset;
403 page.width = pdf_document->out->getBitmapWidth();
404 page.height = pdf_document->out->getBitmapHeight();
408 draw.width = clip_width;
409 draw.height = clip_height;
411 if (gdk_rectangle_intersect (&page, &draw, &draw))
412 pdf_document->out->redraw (draw.x - page.x, draw.y - page.y,
413 pdf_document->target,
415 draw.width, draw.height);
419 pdf_document_find_get_progress (EvDocumentFind *document_find)
421 PdfDocumentSearch *search;
422 int n_pages, pages_done;
424 search = PDF_DOCUMENT (document_find)->search;
426 if (search == NULL) {
430 n_pages = ev_document_get_n_pages (EV_DOCUMENT (document_find));
431 if (search->search_page > search->start_page) {
432 pages_done = search->search_page - search->start_page + 1;
433 } else if (search->search_page == search->start_page) {
434 pages_done = n_pages;
436 pages_done = n_pages - search->start_page + search->search_page;
439 return pages_done / (double) n_pages;
443 pdf_document_find_page_has_results (EvDocumentFind *document_find,
446 PdfDocumentSearch *search = PDF_DOCUMENT (document_find)->search;
448 g_return_val_if_fail (search != NULL, FALSE);
450 return search->other_page_flags[page];
454 pdf_document_find_get_n_results (EvDocumentFind *document_find)
456 PdfDocumentSearch *search = PDF_DOCUMENT (document_find)->search;
459 return search->current_page_results->len;
466 pdf_document_find_get_result (EvDocumentFind *document_find,
468 GdkRectangle *rectangle)
470 PdfDocument *pdf_document = PDF_DOCUMENT (document_find);
471 PdfDocumentSearch *search = pdf_document->search;
474 if (search != NULL &&
475 n_result < search->current_page_results->len) {
476 r = g_array_index (search->current_page_results,
477 GdkRectangle, n_result);
479 rectangle->x = r.x + pdf_document->page_x_offset;
480 rectangle->y = r.y + pdf_document->page_y_offset;
481 rectangle->width = r.width;
482 rectangle->height = r.height;
491 pdf_document_search_page_changed (PdfDocumentSearch *search)
493 PdfDocument *pdf_document = search->document;
496 int xMin, yMin, xMax, yMax;
498 current_page = pdf_document->page;
500 if (search->current_page == current_page)
503 /* We need to create current_page_results for the new current page */
504 g_array_set_size (search->current_page_results, 0);
506 if (pdf_document->out->findText (search->ucs4, search->ucs4_len,
507 gTrue, gTrue, // startAtTop, stopAtBottom
508 gFalse, gFalse, // startAtLast, stopAtLast
509 &xMin, &yMin, &xMax, &yMax)) {
512 result.width = xMax - xMin;
513 result.height = yMax - yMin;
515 g_array_append_val (search->current_page_results, result);
516 /* Now find further results */
518 while (pdf_document->out->findText (search->ucs4, search->ucs4_len,
521 &xMin, &yMin, &xMax, &yMax)) {
524 result.width = xMax - xMin;
525 result.height = yMax - yMin;
527 g_array_append_val (search->current_page_results, result);
533 pdf_document_search_idle_callback (void *data)
535 PdfDocumentSearch *search = (PdfDocumentSearch*) data;
536 PdfDocument *pdf_document = search->document;
537 int n_pages, changed_page;
538 double xMin, yMin, xMax, yMax;
540 /* Note that PDF page count is 1 through n_pages INCLUSIVE
541 * like a real book. We are looking to add one result for each
542 * page with a match, because the coordinates are meaningless
543 * with TextOutputDev, so we just want to flag matching pages
544 * and then when the user switches to the current page, we
545 * will emit "found" again with the real results.
547 n_pages = ev_document_get_n_pages (EV_DOCUMENT (search->document));
549 if (search->output_dev == 0) {
550 /* First time through here... */
551 search->output_dev = new TextOutputDev (NULL, gTrue, gFalse, gFalse);
552 if (!search->output_dev->isOk()) {
557 pdf_document->doc->displayPage (search->output_dev,
559 72, 72, 0, gTrue, gFalse);
561 if (search->output_dev->findText (search->ucs4,
563 gTrue, gTrue, // startAtTop, stopAtBottom
564 gFalse, gFalse, // startAtLast, stopAtLast
565 &xMin, &yMin, &xMax, &yMax)) {
566 /* This page has results */
567 search->other_page_flags[search->search_page] = 1;
569 search->other_page_flags[search->search_page] = 0;
572 changed_page = search->start_page;
574 search->search_page += 1;
575 if (search->search_page > n_pages) {
577 search->search_page = 1;
580 if (search->search_page != search->start_page) {
581 ev_document_find_changed (EV_DOCUMENT_FIND (pdf_document),
588 search->idle = 0; /* will return FALSE to remove */
593 pdf_document_find_begin (EvDocumentFind *document,
594 const char *search_string,
595 gboolean case_sensitive)
597 PdfDocument *pdf_document = PDF_DOCUMENT (document);
598 PdfDocumentSearch *search;
603 /* FIXME handle case_sensitive (right now XPDF
604 * code is always case insensitive for ASCII
605 * and case sensitive for all other languaages)
608 g_assert (sizeof (gunichar) == sizeof (Unicode));
609 ucs4 = g_utf8_to_ucs4_fast (search_string, -1,
612 if (pdf_document->search &&
613 pdf_document->search->ucs4_len == ucs4_len &&
614 memcmp (pdf_document->search->ucs4,
616 sizeof (gunichar) * ucs4_len) == 0) {
617 /* Search is unchanged */
622 if (pdf_document->search) {
623 pdf_document_search_free (pdf_document->search);
624 pdf_document->search = NULL;
627 search = g_new0 (PdfDocumentSearch, 1);
630 search->ucs4_len = ucs4_len;
632 search->current_page_results = g_array_new (FALSE,
634 sizeof (GdkRectangle));
635 n_pages = ev_document_get_n_pages (EV_DOCUMENT (document));
637 search->other_page_flags = g_new0 (int, n_pages + 1);
638 for (i = 0; i <= n_pages; i++) {
639 search->other_page_flags[i] = -1;
642 search->document = pdf_document;
644 /* We add at low priority so the progress bar repaints */
645 search->idle = g_idle_add_full (G_PRIORITY_LOW,
646 pdf_document_search_idle_callback,
650 search->output_dev = 0;
652 search->start_page = pdf_document->page;
653 search->search_page = search->start_page;
655 search->current_page = -1;
657 pdf_document->search = search;
659 /* Update for the current page right away */
660 pdf_document_search_page_changed (search);
664 pdf_document_find_cancel (EvDocumentFind *document)
666 PdfDocument *pdf_document = PDF_DOCUMENT (document);
668 if (pdf_document->search) {
669 pdf_document_search_free (pdf_document->search);
670 pdf_document->search = NULL;
675 pdf_document_search_free (PdfDocumentSearch *search)
677 if (search->idle != 0)
678 g_source_remove (search->idle);
680 if (search->output_dev)
681 delete search->output_dev;
683 g_array_free (search->current_page_results, TRUE);
684 g_free (search->other_page_flags);
686 g_free (search->ucs4);
691 pdf_document_has_document_security (EvDocumentSecurity *document_security)
693 /* FIXME: do we really need to have this? */
698 pdf_document_set_password (EvDocumentSecurity *document_security,
699 const char *password)
701 PdfDocument *document = PDF_DOCUMENT (document_security);
703 if (document->password)
704 g_free (document->password);
706 document->password = g_strdup (password);
710 pdf_document_ps_export_begin (EvPSExporter *exporter, const char *filename)
712 PdfDocument *document = PDF_DOCUMENT (exporter);
714 if (document->ps_out)
715 delete document->ps_out;
717 document->ps_out = new PSOutputDev ((char *)filename, document->doc->getXRef(),
718 document->doc->getCatalog(), 1,
719 ev_document_get_n_pages (EV_DOCUMENT (document)),
724 pdf_document_ps_export_do_page (EvPSExporter *exporter, int page)
726 PdfDocument *document = PDF_DOCUMENT (exporter);
728 document->doc->displayPage (document->ps_out, page,
729 72.0, 72.0, 0, gTrue, gFalse);
733 pdf_document_ps_export_end (EvPSExporter *exporter)
735 PdfDocument *document = PDF_DOCUMENT (exporter);
737 delete document->ps_out;
738 document->ps_out = NULL;
742 /* EvDocumentLinks Implementation */
751 unicode_to_char (OutlineItem *outline_item,
755 gchar buf[8]; /* 8 is enough for mapping an unicode char to a string */
758 for (i = 0; i < outline_item->getTitleLength(); ++i) {
759 n = uMap->mapUnicode(outline_item->getTitle()[i], buf, sizeof(buf));
763 return g_strdup (gstr.getCString ());
768 pdf_document_links_has_document_links (EvDocumentLinks *document_links)
770 PdfDocument *pdf_document = PDF_DOCUMENT (document_links);
773 g_return_val_if_fail (PDF_IS_DOCUMENT (document_links), FALSE);
775 outline = pdf_document->doc->getOutline();
776 if (outline->getItems() != NULL &&
777 outline->getItems()->getLength() > 0)
783 static EvDocumentLinksIter *
784 pdf_document_links_begin_read (EvDocumentLinks *document_links)
786 PdfDocument *pdf_document = PDF_DOCUMENT (document_links);
791 g_return_val_if_fail (PDF_IS_DOCUMENT (document_links), NULL);
793 outline = pdf_document->doc->getOutline();
794 items = outline->getItems();
798 iter = g_new0 (LinksIter, 1);
803 return (EvDocumentLinksIter *) iter;
807 build_link_from_action (PdfDocument *pdf_document,
808 LinkAction *link_action,
813 if (link_action == NULL) {
814 link = ev_link_new_title (title);
815 } else if (link_action->getKind () == actionGoToR) {
816 g_warning ("actionGoToR links not implemented");
817 } else if (link_action->getKind () == actionLaunch) {
818 g_warning ("actionLaunch links not implemented");
819 } else if (link_action->getKind () == actionNamed) {
820 g_warning ("actionNamed links not implemented");
821 } else if (link_action->getKind () == actionMovie) {
822 g_warning ("actionMovie links not implemented");
823 } else if (link_action->getKind () == actionGoTo) {
828 GooString *named_dest;
830 link_goto = dynamic_cast <LinkGoTo *> (link_action);
831 link_dest = link_goto->getDest ();
832 named_dest = link_goto->getNamedDest ();
834 /* Wow! This seems excessively slow on large
835 * documents. I need to investigate more... -jrb */
836 if (link_dest != NULL) {
837 link_dest = link_dest->copy ();
838 } else if (named_dest != NULL) {
839 named_dest = named_dest->copy ();
840 link_dest = pdf_document->doc->findDest (named_dest);
843 if (link_dest != NULL) {
844 if (link_dest->isPageRef ()) {
845 page_ref = link_dest->getPageRef ();
846 page_num = pdf_document->doc->findPage (page_ref.num, page_ref.gen);
848 page_num = link_dest->getPageNum ();
853 link = ev_link_new_page (title, page_num);
854 } else if (link_action->getKind () == actionURI) {
857 link_uri = dynamic_cast <LinkURI *> (link_action);
858 link = ev_link_new_external
859 (title, link_uri->getURI()->getCString());
860 } else if (link_action->getKind () == actionUnknown) {
861 LinkUnknown *link_unknown;
863 link_unknown = dynamic_cast <LinkUnknown *> (link_action);
865 g_warning ("Unknown link type %s",
866 link_unknown->getAction()->getCString());
870 link = ev_link_new_title (title);
876 /* FIXME This returns a new object every time, probably we should cache it
879 pdf_document_links_get_link (EvDocumentLinks *document_links,
880 EvDocumentLinksIter *links_iter)
882 PdfDocument *pdf_document = PDF_DOCUMENT (document_links);
883 LinksIter *iter = (LinksIter *)links_iter;
885 LinkAction *link_action;
889 g_return_val_if_fail (PDF_IS_DOCUMENT (document_links), FALSE);
890 g_return_val_if_fail (iter != NULL, FALSE);
892 anItem = (OutlineItem *)iter->items->get(iter->index);
893 link_action = anItem->getAction ();
894 link_title = anItem->getTitle ();
895 title = unicode_to_char (anItem, pdf_document->umap);
897 return build_link_from_action (pdf_document, link_action, title);
900 static EvDocumentLinksIter *
901 pdf_document_links_get_child (EvDocumentLinks *document_links,
902 EvDocumentLinksIter *links_iter)
904 LinksIter *iter = (LinksIter *)links_iter;
905 LinksIter *child_iter;
908 g_return_val_if_fail (PDF_IS_DOCUMENT (document_links), FALSE);
910 anItem = (OutlineItem *)iter->items->get(iter->index);
912 if (! (anItem->hasKids() && anItem->getKids()) )
915 child_iter = g_new0 (LinksIter, 1);
916 child_iter->index = 0;
917 child_iter->level = iter->level + 1;
918 child_iter->items = anItem->getKids ();
919 g_assert (child_iter->items);
921 return (EvDocumentLinksIter *) child_iter;
925 pdf_document_links_next (EvDocumentLinks *document_links,
926 EvDocumentLinksIter *links_iter)
928 LinksIter *iter = (LinksIter *) links_iter;
930 g_return_val_if_fail (PDF_IS_DOCUMENT (document_links), FALSE);
933 if (iter->index >= iter->items->getLength())
940 pdf_document_links_free_iter (EvDocumentLinks *document_links,
941 EvDocumentLinksIter *iter)
943 g_return_if_fail (PDF_IS_DOCUMENT (document_links));
944 g_return_if_fail (iter != NULL);
946 /* FIXME: Should I close all the nodes?? Free them? */
951 pdf_document_finalize (GObject *object)
953 PdfDocument *pdf_document = PDF_DOCUMENT (object);
955 if (pdf_document->links) {
956 delete pdf_document->links;
959 if (pdf_document->umap) {
960 pdf_document->umap->decRefCnt ();
961 pdf_document->umap = NULL;
964 if (pdf_document->search)
965 pdf_document_search_free (pdf_document->search);
967 if (pdf_document->target)
968 g_object_unref (pdf_document->target);
970 if (pdf_document->out)
971 delete pdf_document->out;
972 if (pdf_document->ps_out)
973 delete pdf_document->ps_out;
974 if (pdf_document->doc)
975 delete pdf_document->doc;
980 pdf_document_set_property (GObject *object,
995 has_unicode_marker (GooString *string)
997 return ((string->getChar (0) & 0xff) == 0xfe &&
998 (string->getChar (1) & 0xff) == 0xff);
1002 pdf_info_dict_get_string (Dict *info_dict, const gchar *key) {
1007 g_return_val_if_fail (info_dict != NULL, NULL);
1008 g_return_val_if_fail (key != NULL, NULL);
1010 if (!info_dict->lookup ((gchar *)key, &obj)->isString ()) {
1015 value = obj.getString ();
1017 if (has_unicode_marker (value)) {
1018 result = g_convert (value->getCString () + 2,
1019 value->getLength () - 2,
1020 "UTF-8", "UTF-16BE", NULL, NULL, NULL);
1022 result = g_strndup (value->getCString (), value->getLength ());
1031 pdf_document_get_title (PdfDocument *pdf_document)
1036 if (pdf_document->doc == NULL)
1038 pdf_document->doc->getDocInfo (&info);
1040 if (info.isDict ()) {
1041 title = pdf_info_dict_get_string (info.getDict(), "Title");
1048 pdf_document_get_text (EvDocument *document, GdkRectangle *rect)
1050 PdfDocument *pdf_document = PDF_DOCUMENT (document);
1051 GooString *sel_text = new GooString;
1055 x1 = rect->x - pdf_document->page_x_offset;
1056 y1 = rect->y - pdf_document->page_y_offset;
1057 x2 = x1 + rect->width;
1058 y2 = y1 + rect->height;
1060 sel_text = pdf_document->out->getText (x1, y1, x2, y2);
1061 text = sel_text->getCString ();
1063 return text ? g_strdup (text) : NULL;
1067 pdf_document_get_link (EvDocument *document, int x, int y)
1069 PdfDocument *pdf_document = PDF_DOCUMENT (document);
1071 double link_x, link_y;
1073 if (pdf_document->links == NULL) {
1078 link_x = x - pdf_document->page_x_offset;
1079 link_y = y - pdf_document->page_y_offset;
1082 link_y = pdf_document->out->getBitmapHeight() - link_y;
1085 link_x = link_x / pdf_document->scale;
1086 link_y = link_y / pdf_document->scale;
1088 action = pdf_document->links->find (link_x, link_y);
1091 return build_link_from_action (pdf_document, action, "");
1098 pdf_document_get_property (GObject *object,
1103 PdfDocument *pdf_document = PDF_DOCUMENT (object);
1109 title = pdf_document_get_title (pdf_document);
1110 g_value_set_string (value, title);
1117 pdf_document_class_init (PdfDocumentClass *klass)
1119 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1121 gobject_class->finalize = pdf_document_finalize;
1122 gobject_class->get_property = pdf_document_get_property;
1123 gobject_class->set_property = pdf_document_set_property;
1125 g_object_class_override_property (gobject_class, PROP_TITLE, "title");
1129 pdf_document_document_iface_init (EvDocumentIface *iface)
1131 iface->load = pdf_document_load;
1132 iface->save = pdf_document_save;
1133 iface->get_text = pdf_document_get_text;
1134 iface->get_link = pdf_document_get_link;
1135 iface->get_n_pages = pdf_document_get_n_pages;
1136 iface->set_page = pdf_document_set_page;
1137 iface->get_page = pdf_document_get_page;
1138 iface->set_scale = pdf_document_set_scale;
1139 iface->set_target = pdf_document_set_target;
1140 iface->set_page_offset = pdf_document_set_page_offset;
1141 iface->get_page_size = pdf_document_get_page_size;
1142 iface->render = pdf_document_render;
1146 pdf_document_ps_exporter_iface_init (EvPSExporterIface *iface)
1148 iface->begin = pdf_document_ps_export_begin;
1149 iface->do_page = pdf_document_ps_export_do_page;
1150 iface->end = pdf_document_ps_export_end;
1155 pdf_document_find_iface_init (EvDocumentFindIface *iface)
1157 iface->begin = pdf_document_find_begin;
1158 iface->get_n_results = pdf_document_find_get_n_results;
1159 iface->get_result = pdf_document_find_get_result;
1160 iface->page_has_results = pdf_document_find_page_has_results;
1161 iface->get_progress = pdf_document_find_get_progress;
1162 iface->cancel = pdf_document_find_cancel;
1166 pdf_document_security_iface_init (EvDocumentSecurityIface *iface)
1168 iface->has_document_security = pdf_document_has_document_security;
1169 iface->set_password = pdf_document_set_password;
1173 pdf_document_document_links_iface_init (EvDocumentLinksIface *iface)
1175 iface->has_document_links = pdf_document_links_has_document_links;
1176 iface->begin_read = pdf_document_links_begin_read;
1177 iface->get_link = pdf_document_links_get_link;
1178 iface->get_child = pdf_document_links_get_child;
1179 iface->next = pdf_document_links_next;
1180 iface->free_iter = pdf_document_links_free_iter;
1186 bitmap_to_pixbuf (SplashBitmap *bitmap,
1193 SplashColorPtr dataPtr;
1196 gboolean target_has_alpha;
1197 gint target_rowstride;
1198 guchar *target_data;
1200 width = bitmap->getWidth ();
1201 height = bitmap->getHeight ();
1203 if (width + x_offset > gdk_pixbuf_get_width (target))
1204 width = gdk_pixbuf_get_width (target) - x_offset;
1205 if (height + y_offset > gdk_pixbuf_get_height (target))
1206 height = gdk_pixbuf_get_height (target) - x_offset;
1208 target_has_alpha = gdk_pixbuf_get_has_alpha (target);
1209 target_rowstride = gdk_pixbuf_get_rowstride (target);
1210 target_data = gdk_pixbuf_get_pixels (target);
1212 dataPtr = bitmap->getDataPtr ();
1214 for (y = 0; y < height; y++) {
1219 p = dataPtr.rgb8 + y * width;
1220 q = target_data + ((y + y_offset) * target_rowstride +
1221 x_offset * (target_has_alpha?4:3));
1222 for (x = 0; x < width; x++) {
1225 *q++ = splashRGB8R (rgb);
1226 *q++ = splashRGB8G (rgb);
1227 *q++ = splashRGB8B (rgb);
1229 if (target_has_alpha)
1239 pdf_document_thumbnails_get_page_pixbuf (PdfDocument *pdf_document,
1240 gdouble scale_factor,
1246 SplashOutputDev *output;
1250 color.rgb8 = splashMakeRGB8 (255, 255, 255);
1252 output = new SplashOutputDev (splashModeRGB8, gFalse, color);
1253 output->startDoc (pdf_document->doc->getXRef());
1254 pdf_document->doc->displayPage (output,
1260 width = output->getBitmap()->getWidth();
1261 height = output->getBitmap()->getHeight();
1264 pixbuf = ev_document_misc_get_thumbnail_frame (width, height, NULL);
1265 bitmap_to_pixbuf (output->getBitmap(), pixbuf, 1, 1);
1267 pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
1269 gdk_pixbuf_fill (pixbuf, 0xffffffff);
1270 bitmap_to_pixbuf (output->getBitmap(), pixbuf, 0, 0);
1279 pdf_document_thumbnails_get_dimensions (EvDocumentThumbnails *document_thumbnails,
1285 PdfDocument *pdf_document = PDF_DOCUMENT (document_thumbnails);
1288 Thumb *thumb = NULL;
1290 the_page = pdf_document->doc->getCatalog ()->getPage (page);
1291 the_page->getThumb (&the_thumb);
1293 if (!(the_thumb.isNull () || the_thumb.isNone())) {
1294 /* Build the thumbnail object */
1295 thumb = new Thumb(pdf_document->doc->getXRef (),
1298 *width = thumb->getWidth ();
1299 *height = thumb->getHeight ();
1301 double page_width, page_height;
1303 page_width = the_page->getWidth ();
1304 page_height = the_page->getHeight ();
1306 if (page_width > page_height) {
1308 *height = (int) (size * page_height / page_width);
1310 *width = (int) (size * page_width / page_height);
1317 pdf_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document_thumbnails,
1322 PdfDocument *pdf_document = PDF_DOCUMENT (document_thumbnails);
1323 GdkPixbuf *thumbnail;
1326 Thumb *thumb = NULL;
1327 gboolean have_ethumbs = FALSE;
1329 the_page = pdf_document->doc->getCatalog ()->getPage (page);
1330 the_page->getThumb(&the_thumb);
1332 if (!(the_thumb.isNull () || the_thumb.isNone())) {
1333 /* Build the thumbnail object */
1334 thumb = new Thumb(pdf_document->doc->getXRef (),
1337 have_ethumbs = thumb->ok();
1342 GdkPixbuf *tmp_pixbuf;
1344 data = thumb->getPixbufData();
1345 tmp_pixbuf = gdk_pixbuf_new_from_data (data,
1350 thumb->getHeight (),
1351 thumb->getWidth () * 3,
1353 /* FIXME: do we want to check that the thumb's size isn't ridiculous?? */
1354 thumbnail = ev_document_misc_get_thumbnail_frame (-1, -1, tmp_pixbuf);
1355 g_object_unref (tmp_pixbuf);
1358 double scale_factor;
1360 pdf_document_thumbnails_get_dimensions (document_thumbnails, page, size,
1362 scale_factor = width / the_page->getWidth ();
1363 thumbnail = pdf_document_thumbnails_get_page_pixbuf (pdf_document,
1374 pdf_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface)
1376 iface->get_thumbnail = pdf_document_thumbnails_get_thumbnail;
1377 iface->get_dimensions = pdf_document_thumbnails_get_dimensions;
1382 pdf_document_init (PdfDocument *pdf_document)
1384 pdf_document->page = 1;
1385 pdf_document->page_x_offset = 0;
1386 pdf_document->page_y_offset = 0;
1387 pdf_document->scale = 1.;
1389 pdf_document->password = NULL;