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 "gpdf-g-switch.h"
23 #include "pdf-document.h"
24 #include "ev-ps-exporter.h"
25 #include "ev-document-find.h"
26 #include "ev-document-misc.h"
27 #include "gpdf-g-switch.h"
28 #include "ev-document-links.h"
29 #include "ev-document-security.h"
30 #include "ev-document-thumbnails.h"
32 #include "GlobalParams.h"
33 #include "GDKSplashOutputDev.h"
34 #include "SplashBitmap.h"
37 #include "ErrorCodes.h"
38 #include "UnicodeMap.h"
39 #include "GlobalParams.h"
42 #include "goo/GList.h"
43 #include "PSOutputDev.h"
52 PdfDocument *document;
56 /* full results are only possible for the rendered current page */
58 GArray *current_page_results;
59 int *other_page_flags; /* length n_pages + 1, first element ignored */
60 int start_page; /* skip this one as we iterate, since we did it first */
61 int search_page; /* the page we're searching now */
62 TextOutputDev *output_dev;
65 typedef struct _PdfDocumentClass PdfDocumentClass;
67 #define PDF_DOCUMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PDF_TYPE_DOCUMENT, PdfDocumentClass))
68 #define PDF_IS_DOCUMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PDF_TYPE_DOCUMENT))
69 #define PDF_DOCUMENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PDF_TYPE_DOCUMENT, PdfDocumentClass))
71 struct _PdfDocumentClass
73 GObjectClass parent_class;
78 GObject parent_instance;
86 GDKSplashOutputDev *out;
94 PdfDocumentSearch *search;
97 static void pdf_document_document_links_iface_init (EvDocumentLinksIface *iface);
98 static void pdf_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface);
99 static void pdf_document_document_iface_init (EvDocumentIface *iface);
100 static void pdf_document_ps_exporter_iface_init (EvPSExporterIface *iface);
101 static void pdf_document_find_iface_init (EvDocumentFindIface *iface);
102 static void pdf_document_security_iface_init (EvDocumentSecurityIface *iface);
103 static void pdf_document_search_free (PdfDocumentSearch *search);
104 static void pdf_document_search_page_changed (PdfDocumentSearch *search);
107 G_DEFINE_TYPE_WITH_CODE (PdfDocument, pdf_document, G_TYPE_OBJECT,
109 G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT,
110 pdf_document_document_iface_init);
111 G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_LINKS,
112 pdf_document_document_links_iface_init);
113 G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_THUMBNAILS,
114 pdf_document_document_thumbnails_iface_init);
115 G_IMPLEMENT_INTERFACE (EV_TYPE_PS_EXPORTER,
116 pdf_document_ps_exporter_iface_init);
117 G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_FIND,
118 pdf_document_find_iface_init);
119 G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_SECURITY,
120 pdf_document_security_iface_init);
124 document_init_links (PdfDocument *pdf_document)
129 if (pdf_document->links) {
130 delete pdf_document->links;
132 page = pdf_document->doc->getCatalog ()->getPage (pdf_document->page);
133 pdf_document->links = new Links (page->getAnnots (&obj),
134 pdf_document->doc->getCatalog ()->getBaseURI ());
139 document_display_page (PdfDocument *pdf_document)
141 if (pdf_document->out != NULL) {
142 pdf_document->doc->displayPage (pdf_document->out, pdf_document->page,
143 72 * pdf_document->scale,
144 72 * pdf_document->scale,
147 document_init_links (pdf_document);
149 /* Update the search results available to the app since
150 * we only provide full results on the current page
152 if (pdf_document->search)
153 pdf_document_search_page_changed (pdf_document->search);
158 pdf_document_load (EvDocument *document,
162 PdfDocument *pdf_document = PDF_DOCUMENT (document);
170 globalParams = new GlobalParams("/etc/xpdfrc");
171 globalParams->setupBaseFontsFc(NULL);
174 if (! pdf_document->umap) {
175 enc = new GString("UTF-8");
176 pdf_document->umap = globalParams->getUnicodeMap(enc);
177 pdf_document->umap->incRefCnt ();
181 filename = g_filename_from_uri (uri, NULL, error);
185 filename_g = new GString (filename);
188 // open the PDF file, assumes ownership of filename_g
189 GString *password = NULL;
190 if (pdf_document->password)
191 password = new GString (pdf_document->password);
192 newDoc = new PDFDoc(filename_g, password, password);
196 if (!newDoc->isOk()) {
197 err = newDoc->getErrorCode();
199 if (err == errEncrypted) {
200 g_set_error (error, EV_DOCUMENT_ERROR,
201 EV_DOCUMENT_ERROR_ENCRYPTED,
202 "Document is encrypted.");
204 g_set_error (error, G_FILE_ERROR,
206 "Failed to load document (error %d) '%s'\n",
214 if (pdf_document->doc)
215 delete pdf_document->doc;
216 pdf_document->doc = newDoc;
218 pdf_document->page = 1;
220 if (pdf_document->out)
221 pdf_document->out->startDoc(pdf_document->doc->getXRef());
223 g_object_notify (G_OBJECT (pdf_document), "title");
229 pdf_document_save (EvDocument *document,
233 PdfDocument *pdf_document = PDF_DOCUMENT (document);
235 gboolean retval = FALSE;
237 filename = g_filename_from_uri (uri, NULL, error);
238 if (filename != NULL) {
239 GString *fname = new GString (filename);
241 retval = pdf_document->doc->saveAs (fname);
248 pdf_document_get_n_pages (EvDocument *document)
250 PdfDocument *pdf_document = PDF_DOCUMENT (document);
252 if (pdf_document->doc)
253 return pdf_document->doc->getNumPages();
259 pdf_document_set_page (EvDocument *document,
262 PdfDocument *pdf_document = PDF_DOCUMENT (document);
264 page = CLAMP (page, 1, ev_document_get_n_pages (document));
266 if (page != pdf_document->page) {
267 pdf_document->page = page;
268 document_display_page (pdf_document);
269 ev_document_page_changed (EV_DOCUMENT (pdf_document));
274 pdf_document_get_page (EvDocument *document)
276 PdfDocument *pdf_document = PDF_DOCUMENT (document);
278 return pdf_document->page;
282 redraw_callback (void *data)
284 /* Need to hook up through a EvDocument callback? */
288 pdf_document_set_target (EvDocument *document,
291 PdfDocument *pdf_document = PDF_DOCUMENT (document);
293 if (pdf_document->target != target) {
294 if (pdf_document->target)
295 g_object_unref (pdf_document->target);
297 pdf_document->target = target;
299 if (pdf_document->target)
300 g_object_ref (pdf_document->target);
302 if (pdf_document->out) {
303 delete pdf_document->out;
304 pdf_document->out = NULL;
307 if (pdf_document->target) {
308 pdf_document->out = new GDKSplashOutputDev (gdk_drawable_get_screen (pdf_document->target),
309 redraw_callback, (void*) document);
311 if (pdf_document->doc)
312 pdf_document->out->startDoc(pdf_document->doc->getXRef());
314 document_display_page (pdf_document);
320 pdf_document_set_scale (EvDocument *document,
323 PdfDocument *pdf_document = PDF_DOCUMENT (document);
325 if (pdf_document->scale != scale) {
326 pdf_document->scale = scale;
327 document_display_page (pdf_document);
328 ev_document_scale_changed (EV_DOCUMENT (pdf_document));
333 pdf_document_set_page_offset (EvDocument *document,
337 PdfDocument *pdf_document = PDF_DOCUMENT (document);
339 pdf_document->page_x_offset = x;
340 pdf_document->page_y_offset = y;
344 canonical_multiple_of_90 (gint n)
353 return 90 * (gint)((n / 90.0) + .5);
357 pdf_document_get_page_size (EvDocument *document,
362 PdfDocument *pdf_document = PDF_DOCUMENT (document);
364 int page_width = 1, page_height = 1;
365 double scale = pdf_document->scale;
368 page = pdf_document->page;
370 doc_page = pdf_document->doc->getCatalog ()->getPage (page);
375 page_rotate = canonical_multiple_of_90 (doc_page->getRotate ());
376 if (page_rotate == 90 || page_rotate == 270) {
377 page_width = (int) ((doc_page->getHeight () * scale) + 0.5);
378 page_height = (int) ((doc_page->getWidth () * scale) + 0.5);
379 } else /* if (page_rotate == 0 || page_rotate == 180) */ {
380 page_width = (int) ((doc_page->getWidth () * scale) + 0.5);
381 page_height = (int) ((doc_page->getHeight () * scale) + 0.5);
385 if (width) *width = page_width;
386 if (height) *height = page_height;
390 pdf_document_render (EvDocument *document,
396 PdfDocument *pdf_document = PDF_DOCUMENT (document);
400 if (!pdf_document->target)
403 page.x = pdf_document->page_x_offset;
404 page.y = pdf_document->page_y_offset;
405 page.width = pdf_document->out->getBitmapWidth();
406 page.height = pdf_document->out->getBitmapHeight();
410 draw.width = clip_width;
411 draw.height = clip_height;
413 if (gdk_rectangle_intersect (&page, &draw, &draw))
414 pdf_document->out->redraw (draw.x - page.x, draw.y - page.y,
415 pdf_document->target,
417 draw.width, draw.height);
421 pdf_document_find_get_progress (EvDocumentFind *document_find)
423 PdfDocumentSearch *search;
424 int n_pages, pages_done;
426 search = PDF_DOCUMENT (document_find)->search;
428 if (search == NULL) {
432 n_pages = ev_document_get_n_pages (EV_DOCUMENT (document_find));
433 if (search->search_page > search->start_page) {
434 pages_done = search->search_page - search->start_page + 1;
435 } else if (search->search_page == search->start_page) {
436 pages_done = n_pages;
438 pages_done = n_pages - search->start_page + search->search_page;
441 return pages_done / (double) n_pages;
445 pdf_document_find_page_has_results (EvDocumentFind *document_find,
448 PdfDocumentSearch *search = PDF_DOCUMENT (document_find)->search;
450 g_return_val_if_fail (search != NULL, FALSE);
452 return search->other_page_flags[page];
456 pdf_document_find_get_n_results (EvDocumentFind *document_find)
458 PdfDocumentSearch *search = PDF_DOCUMENT (document_find)->search;
461 return search->current_page_results->len;
468 pdf_document_find_get_result (EvDocumentFind *document_find,
470 GdkRectangle *rectangle)
472 PdfDocument *pdf_document = PDF_DOCUMENT (document_find);
473 PdfDocumentSearch *search = pdf_document->search;
476 if (search != NULL &&
477 n_result < search->current_page_results->len) {
478 r = g_array_index (search->current_page_results,
479 GdkRectangle, n_result);
481 rectangle->x = r.x + pdf_document->page_x_offset;
482 rectangle->y = r.y + pdf_document->page_y_offset;
483 rectangle->width = r.width;
484 rectangle->height = r.height;
493 pdf_document_search_page_changed (PdfDocumentSearch *search)
495 PdfDocument *pdf_document = search->document;
498 int xMin, yMin, xMax, yMax;
500 current_page = pdf_document->page;
502 if (search->current_page == current_page)
505 /* We need to create current_page_results for the new current page */
506 g_array_set_size (search->current_page_results, 0);
508 if (pdf_document->out->findText (search->ucs4, search->ucs4_len,
509 gTrue, gTrue, // startAtTop, stopAtBottom
510 gFalse, gFalse, // startAtLast, stopAtLast
511 &xMin, &yMin, &xMax, &yMax)) {
514 result.width = xMax - xMin;
515 result.height = yMax - yMin;
517 g_array_append_val (search->current_page_results, result);
518 /* Now find further results */
520 while (pdf_document->out->findText (search->ucs4, search->ucs4_len,
523 &xMin, &yMin, &xMax, &yMax)) {
526 result.width = xMax - xMin;
527 result.height = yMax - yMin;
529 g_array_append_val (search->current_page_results, result);
535 pdf_document_search_idle_callback (void *data)
537 PdfDocumentSearch *search = (PdfDocumentSearch*) data;
538 PdfDocument *pdf_document = search->document;
539 int n_pages, changed_page;
540 double xMin, yMin, xMax, yMax;
542 /* Note that PDF page count is 1 through n_pages INCLUSIVE
543 * like a real book. We are looking to add one result for each
544 * page with a match, because the coordinates are meaningless
545 * with TextOutputDev, so we just want to flag matching pages
546 * and then when the user switches to the current page, we
547 * will emit "found" again with the real results.
549 n_pages = ev_document_get_n_pages (EV_DOCUMENT (search->document));
551 if (search->output_dev == 0) {
552 /* First time through here... */
553 search->output_dev = new TextOutputDev (NULL, gTrue, gFalse, gFalse);
554 if (!search->output_dev->isOk()) {
559 pdf_document->doc->displayPage (search->output_dev,
561 72, 72, 0, gTrue, gFalse);
563 if (search->output_dev->findText (search->ucs4,
565 gTrue, gTrue, // startAtTop, stopAtBottom
566 gFalse, gFalse, // startAtLast, stopAtLast
567 &xMin, &yMin, &xMax, &yMax)) {
568 /* This page has results */
569 search->other_page_flags[search->search_page] = 1;
571 search->other_page_flags[search->search_page] = 0;
574 changed_page = search->start_page;
576 search->search_page += 1;
577 if (search->search_page > n_pages) {
579 search->search_page = 1;
582 if (search->search_page != search->start_page) {
583 ev_document_find_changed (EV_DOCUMENT_FIND (pdf_document),
590 search->idle = 0; /* will return FALSE to remove */
595 pdf_document_find_begin (EvDocumentFind *document,
596 const char *search_string,
597 gboolean case_sensitive)
599 PdfDocument *pdf_document = PDF_DOCUMENT (document);
600 PdfDocumentSearch *search;
605 /* FIXME handle case_sensitive (right now XPDF
606 * code is always case insensitive for ASCII
607 * and case sensitive for all other languaages)
610 g_assert (sizeof (gunichar) == sizeof (Unicode));
611 ucs4 = g_utf8_to_ucs4_fast (search_string, -1,
614 if (pdf_document->search &&
615 pdf_document->search->ucs4_len == ucs4_len &&
616 memcmp (pdf_document->search->ucs4,
618 sizeof (gunichar) * ucs4_len) == 0) {
619 /* Search is unchanged */
624 if (pdf_document->search) {
625 pdf_document_search_free (pdf_document->search);
626 pdf_document->search = NULL;
629 search = g_new0 (PdfDocumentSearch, 1);
632 search->ucs4_len = ucs4_len;
634 search->current_page_results = g_array_new (FALSE,
636 sizeof (GdkRectangle));
637 n_pages = ev_document_get_n_pages (EV_DOCUMENT (document));
639 search->other_page_flags = g_new0 (int, n_pages + 1);
640 for (i = 0; i <= n_pages; i++) {
641 search->other_page_flags[i] = -1;
644 search->document = pdf_document;
646 /* We add at low priority so the progress bar repaints */
647 search->idle = g_idle_add_full (G_PRIORITY_LOW,
648 pdf_document_search_idle_callback,
652 search->output_dev = 0;
654 search->start_page = pdf_document->page;
655 search->search_page = search->start_page;
657 search->current_page = -1;
659 pdf_document->search = search;
661 /* Update for the current page right away */
662 pdf_document_search_page_changed (search);
666 pdf_document_find_cancel (EvDocumentFind *document)
668 PdfDocument *pdf_document = PDF_DOCUMENT (document);
670 if (pdf_document->search) {
671 pdf_document_search_free (pdf_document->search);
672 pdf_document->search = NULL;
677 pdf_document_search_free (PdfDocumentSearch *search)
679 if (search->idle != 0)
680 g_source_remove (search->idle);
682 if (search->output_dev)
683 delete search->output_dev;
685 g_array_free (search->current_page_results, TRUE);
686 g_free (search->other_page_flags);
688 g_free (search->ucs4);
693 pdf_document_has_document_security (EvDocumentSecurity *document_security)
695 /* FIXME: do we really need to have this? */
700 pdf_document_set_password (EvDocumentSecurity *document_security,
701 const char *password)
703 PdfDocument *document = PDF_DOCUMENT (document_security);
705 if (document->password)
706 g_free (document->password);
708 document->password = g_strdup (password);
712 pdf_document_ps_export_begin (EvPSExporter *exporter, const char *filename)
714 PdfDocument *document = PDF_DOCUMENT (exporter);
716 if (document->ps_out)
717 delete document->ps_out;
719 document->ps_out = new PSOutputDev ((char *)filename, document->doc->getXRef(),
720 document->doc->getCatalog(), 1,
721 ev_document_get_n_pages (EV_DOCUMENT (document)),
726 pdf_document_ps_export_do_page (EvPSExporter *exporter, int page)
728 PdfDocument *document = PDF_DOCUMENT (exporter);
730 document->doc->displayPage (document->ps_out, page,
731 72.0, 72.0, 0, gTrue, gFalse);
735 pdf_document_ps_export_end (EvPSExporter *exporter)
737 PdfDocument *document = PDF_DOCUMENT (exporter);
739 delete document->ps_out;
740 document->ps_out = NULL;
744 /* EvDocumentLinks Implementation */
747 /* goo GList, not glib */
754 unicode_to_char (OutlineItem *outline_item,
758 gchar buf[8]; /* 8 is enough for mapping an unicode char to a string */
761 for (i = 0; i < outline_item->getTitleLength(); ++i) {
762 n = uMap->mapUnicode(outline_item->getTitle()[i], buf, sizeof(buf));
766 return g_strdup (gstr.getCString ());
771 pdf_document_links_has_document_links (EvDocumentLinks *document_links)
773 PdfDocument *pdf_document = PDF_DOCUMENT (document_links);
776 g_return_val_if_fail (PDF_IS_DOCUMENT (document_links), FALSE);
778 outline = pdf_document->doc->getOutline();
779 if (outline->getItems() != NULL &&
780 outline->getItems()->getLength() > 0)
786 static EvDocumentLinksIter *
787 pdf_document_links_begin_read (EvDocumentLinks *document_links)
789 PdfDocument *pdf_document = PDF_DOCUMENT (document_links);
794 g_return_val_if_fail (PDF_IS_DOCUMENT (document_links), NULL);
796 outline = pdf_document->doc->getOutline();
797 items = outline->getItems();
801 iter = g_new0 (LinksIter, 1);
806 return (EvDocumentLinksIter *) iter;
810 build_link_from_action (PdfDocument *pdf_document,
811 LinkAction *link_action,
816 if (link_action == NULL) {
817 link = ev_link_new_title (title);
818 } else if (link_action->getKind () == actionGoToR) {
819 g_warning ("actionGoToR links not implemented");
820 } else if (link_action->getKind () == actionLaunch) {
821 g_warning ("actionLaunch links not implemented");
822 } else if (link_action->getKind () == actionNamed) {
823 g_warning ("actionNamed links not implemented");
824 } else if (link_action->getKind () == actionMovie) {
825 g_warning ("actionMovie links not implemented");
826 } else if (link_action->getKind () == actionGoTo) {
833 link_goto = dynamic_cast <LinkGoTo *> (link_action);
834 link_dest = link_goto->getDest ();
835 named_dest = link_goto->getNamedDest ();
837 /* Wow! This seems excessively slow on large
838 * documents. I need to investigate more... -jrb */
839 if (link_dest != NULL) {
840 link_dest = link_dest->copy ();
841 } else if (named_dest != NULL) {
842 named_dest = named_dest->copy ();
843 link_dest = pdf_document->doc->findDest (named_dest);
846 if (link_dest != NULL) {
847 if (link_dest->isPageRef ()) {
848 page_ref = link_dest->getPageRef ();
849 page_num = pdf_document->doc->findPage (page_ref.num, page_ref.gen);
851 page_num = link_dest->getPageNum ();
856 link = ev_link_new_page (title, page_num);
857 } else if (link_action->getKind () == actionURI) {
860 link_uri = dynamic_cast <LinkURI *> (link_action);
861 link = ev_link_new_external
862 (title, link_uri->getURI()->getCString());
863 } else if (link_action->getKind () == actionUnknown) {
864 LinkUnknown *link_unknown;
866 link_unknown = dynamic_cast <LinkUnknown *> (link_action);
868 g_warning ("Unknown link type %s",
869 link_unknown->getAction()->getCString());
873 link = ev_link_new_title (title);
879 /* FIXME This returns a new object every time, probably we should cache it
882 pdf_document_links_get_link (EvDocumentLinks *document_links,
883 EvDocumentLinksIter *links_iter)
885 PdfDocument *pdf_document = PDF_DOCUMENT (document_links);
886 LinksIter *iter = (LinksIter *)links_iter;
888 LinkAction *link_action;
892 g_return_val_if_fail (PDF_IS_DOCUMENT (document_links), FALSE);
893 g_return_val_if_fail (iter != NULL, FALSE);
895 anItem = (OutlineItem *)iter->items->get(iter->index);
896 link_action = anItem->getAction ();
897 link_title = anItem->getTitle ();
898 title = unicode_to_char (anItem, pdf_document->umap);
900 return build_link_from_action (pdf_document, link_action, title);
903 static EvDocumentLinksIter *
904 pdf_document_links_get_child (EvDocumentLinks *document_links,
905 EvDocumentLinksIter *links_iter)
907 LinksIter *iter = (LinksIter *)links_iter;
908 LinksIter *child_iter;
911 g_return_val_if_fail (PDF_IS_DOCUMENT (document_links), FALSE);
913 anItem = (OutlineItem *)iter->items->get(iter->index);
915 if (! (anItem->hasKids() && anItem->getKids()) )
918 child_iter = g_new0 (LinksIter, 1);
919 child_iter->index = 0;
920 child_iter->level = iter->level + 1;
921 child_iter->items = anItem->getKids ();
922 g_assert (child_iter->items);
924 return (EvDocumentLinksIter *) child_iter;
928 pdf_document_links_next (EvDocumentLinks *document_links,
929 EvDocumentLinksIter *links_iter)
931 LinksIter *iter = (LinksIter *) links_iter;
933 g_return_val_if_fail (PDF_IS_DOCUMENT (document_links), FALSE);
936 if (iter->index >= iter->items->getLength())
943 pdf_document_links_free_iter (EvDocumentLinks *document_links,
944 EvDocumentLinksIter *iter)
946 g_return_if_fail (PDF_IS_DOCUMENT (document_links));
947 g_return_if_fail (iter != NULL);
949 /* FIXME: Should I close all the nodes?? Free them? */
954 pdf_document_finalize (GObject *object)
956 PdfDocument *pdf_document = PDF_DOCUMENT (object);
958 if (pdf_document->links) {
959 delete pdf_document->links;
962 if (pdf_document->umap) {
963 pdf_document->umap->decRefCnt ();
964 pdf_document->umap = NULL;
967 if (pdf_document->search)
968 pdf_document_search_free (pdf_document->search);
970 if (pdf_document->target)
971 g_object_unref (pdf_document->target);
973 if (pdf_document->out)
974 delete pdf_document->out;
975 if (pdf_document->ps_out)
976 delete pdf_document->ps_out;
977 if (pdf_document->doc)
978 delete pdf_document->doc;
983 pdf_document_set_property (GObject *object,
998 has_unicode_marker (GString *string)
1000 return ((string->getChar (0) & 0xff) == 0xfe &&
1001 (string->getChar (1) & 0xff) == 0xff);
1005 pdf_info_dict_get_string (Dict *info_dict, const gchar *key) {
1010 g_return_val_if_fail (info_dict != NULL, NULL);
1011 g_return_val_if_fail (key != NULL, NULL);
1013 if (!info_dict->lookup ((gchar *)key, &obj)->isString ()) {
1018 value = obj.getString ();
1020 if (has_unicode_marker (value)) {
1021 result = g_convert (value->getCString () + 2,
1022 value->getLength () - 2,
1023 "UTF-8", "UTF-16BE", NULL, NULL, NULL);
1025 result = g_strndup (value->getCString (), value->getLength ());
1034 pdf_document_get_title (PdfDocument *pdf_document)
1039 if (pdf_document->doc == NULL)
1041 pdf_document->doc->getDocInfo (&info);
1043 if (info.isDict ()) {
1044 title = pdf_info_dict_get_string (info.getDict(), "Title");
1051 pdf_document_get_text (EvDocument *document, GdkRectangle *rect)
1053 PdfDocument *pdf_document = PDF_DOCUMENT (document);
1054 GString *sel_text = new GString;
1058 x1 = rect->x - pdf_document->page_x_offset;
1059 y1 = rect->y - pdf_document->page_y_offset;
1060 x2 = x1 + rect->width;
1061 y2 = y1 + rect->height;
1063 sel_text = pdf_document->out->getText (x1, y1, x2, y2);
1064 text = sel_text->getCString ();
1066 return text ? g_strdup (text) : NULL;
1070 pdf_document_get_link (EvDocument *document, int x, int y)
1072 PdfDocument *pdf_document = PDF_DOCUMENT (document);
1074 double link_x, link_y;
1076 if (pdf_document->links == NULL) {
1081 link_x = x - pdf_document->page_x_offset;
1082 link_y = y - pdf_document->page_y_offset;
1085 link_y = pdf_document->out->getBitmapHeight() - link_y;
1088 link_x = link_x / pdf_document->scale;
1089 link_y = link_y / pdf_document->scale;
1091 action = pdf_document->links->find (link_x, link_y);
1094 return build_link_from_action (pdf_document, action, "");
1101 pdf_document_get_property (GObject *object,
1106 PdfDocument *pdf_document = PDF_DOCUMENT (object);
1112 title = pdf_document_get_title (pdf_document);
1113 g_value_set_string (value, title);
1120 pdf_document_class_init (PdfDocumentClass *klass)
1122 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1124 gobject_class->finalize = pdf_document_finalize;
1125 gobject_class->get_property = pdf_document_get_property;
1126 gobject_class->set_property = pdf_document_set_property;
1128 g_object_class_override_property (gobject_class, PROP_TITLE, "title");
1132 pdf_document_document_iface_init (EvDocumentIface *iface)
1134 iface->load = pdf_document_load;
1135 iface->save = pdf_document_save;
1136 iface->get_text = pdf_document_get_text;
1137 iface->get_link = pdf_document_get_link;
1138 iface->get_n_pages = pdf_document_get_n_pages;
1139 iface->set_page = pdf_document_set_page;
1140 iface->get_page = pdf_document_get_page;
1141 iface->set_scale = pdf_document_set_scale;
1142 iface->set_target = pdf_document_set_target;
1143 iface->set_page_offset = pdf_document_set_page_offset;
1144 iface->get_page_size = pdf_document_get_page_size;
1145 iface->render = pdf_document_render;
1149 pdf_document_ps_exporter_iface_init (EvPSExporterIface *iface)
1151 iface->begin = pdf_document_ps_export_begin;
1152 iface->do_page = pdf_document_ps_export_do_page;
1153 iface->end = pdf_document_ps_export_end;
1158 pdf_document_find_iface_init (EvDocumentFindIface *iface)
1160 iface->begin = pdf_document_find_begin;
1161 iface->get_n_results = pdf_document_find_get_n_results;
1162 iface->get_result = pdf_document_find_get_result;
1163 iface->page_has_results = pdf_document_find_page_has_results;
1164 iface->get_progress = pdf_document_find_get_progress;
1165 iface->cancel = pdf_document_find_cancel;
1169 pdf_document_security_iface_init (EvDocumentSecurityIface *iface)
1171 iface->has_document_security = pdf_document_has_document_security;
1172 iface->set_password = pdf_document_set_password;
1176 pdf_document_document_links_iface_init (EvDocumentLinksIface *iface)
1178 iface->has_document_links = pdf_document_links_has_document_links;
1179 iface->begin_read = pdf_document_links_begin_read;
1180 iface->get_link = pdf_document_links_get_link;
1181 iface->get_child = pdf_document_links_get_child;
1182 iface->next = pdf_document_links_next;
1183 iface->free_iter = pdf_document_links_free_iter;
1189 bitmap_to_pixbuf (SplashBitmap *bitmap,
1196 SplashColorPtr dataPtr;
1199 gboolean target_has_alpha;
1200 gint target_rowstride;
1201 guchar *target_data;
1203 width = bitmap->getWidth ();
1204 height = bitmap->getHeight ();
1206 if (width + x_offset > gdk_pixbuf_get_width (target))
1207 width = gdk_pixbuf_get_width (target) - x_offset;
1208 if (height + y_offset > gdk_pixbuf_get_height (target))
1209 height = gdk_pixbuf_get_height (target) - x_offset;
1211 target_has_alpha = gdk_pixbuf_get_has_alpha (target);
1212 target_rowstride = gdk_pixbuf_get_rowstride (target);
1213 target_data = gdk_pixbuf_get_pixels (target);
1215 dataPtr = bitmap->getDataPtr ();
1217 for (y = 0; y < height; y++) {
1222 p = dataPtr.rgb8 + y * width;
1223 q = target_data + ((y + y_offset) * target_rowstride +
1224 x_offset * (target_has_alpha?4:3));
1225 for (x = 0; x < width; x++) {
1228 *q++ = splashRGB8R (rgb);
1229 *q++ = splashRGB8G (rgb);
1230 *q++ = splashRGB8B (rgb);
1232 if (target_has_alpha)
1242 pdf_document_thumbnails_get_page_pixbuf (PdfDocument *pdf_document,
1243 gdouble scale_factor,
1248 SplashOutputDev *output;
1252 color.rgb8 = splashMakeRGB8 (255, 255, 255);
1254 output = new SplashOutputDev (splashModeRGB8, gFalse, color);
1255 output->startDoc (pdf_document->doc->getXRef());
1256 pdf_document->doc->displayPage (output,
1262 pixbuf = ev_document_misc_get_thumbnail_frame (output->getBitmap()->getWidth(),
1263 output->getBitmap()->getHeight(),
1265 bitmap_to_pixbuf (output->getBitmap(), pixbuf, 1, 1);
1272 pdf_document_thumbnails_get_dimensions (EvDocumentThumbnails *document_thumbnails,
1274 gint suggested_width,
1278 PdfDocument *pdf_document = PDF_DOCUMENT (document_thumbnails);
1281 Thumb *thumb = NULL;
1284 the_page = pdf_document->doc->getCatalog ()->getPage (page);
1285 the_page->getThumb (&the_thumb);
1287 if (!(the_thumb.isNull () || the_thumb.isNone())) {
1288 /* Build the thumbnail object */
1289 thumb = new Thumb(pdf_document->doc->getXRef (),
1292 *width = thumb->getWidth ();
1293 *height = thumb->getHeight ();
1295 page_ratio = the_page->getHeight () / the_page->getWidth ();
1296 *width = suggested_width;
1297 *height = (gint) (suggested_width * page_ratio);
1302 pdf_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document_thumbnails,
1306 PdfDocument *pdf_document = PDF_DOCUMENT (document_thumbnails);
1307 GdkPixbuf *thumbnail;
1310 Thumb *thumb = NULL;
1311 gboolean have_ethumbs = FALSE;
1315 /* getPage seems to want page + 1 for some reason; */
1316 the_page = pdf_document->doc->getCatalog ()->getPage (page + 1);
1317 the_page->getThumb(&the_thumb);
1319 page_ratio = the_page->getHeight () / the_page->getWidth ();
1320 dest_height = (gint) (width * page_ratio);
1323 if (!(the_thumb.isNull () || the_thumb.isNone())) {
1324 /* Build the thumbnail object */
1325 thumb = new Thumb(pdf_document->doc->getXRef (),
1328 have_ethumbs = thumb->ok();
1333 GdkPixbuf *tmp_pixbuf;
1335 data = thumb->getPixbufData();
1336 tmp_pixbuf = gdk_pixbuf_new_from_data (data,
1341 thumb->getHeight (),
1342 thumb->getWidth () * 3,
1344 /* FIXME: do we want to check that the thumb's size isn't ridiculous?? */
1345 thumbnail = ev_document_misc_get_thumbnail_frame (-1, -1, tmp_pixbuf);
1346 g_object_unref (tmp_pixbuf);
1348 gdouble scale_factor;
1350 scale_factor = (gdouble)width / the_page->getWidth ();
1352 thumbnail = pdf_document_thumbnails_get_page_pixbuf (pdf_document,
1362 pdf_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface)
1364 iface->get_thumbnail = pdf_document_thumbnails_get_thumbnail;
1365 iface->get_dimensions = pdf_document_thumbnails_get_dimensions;
1370 pdf_document_init (PdfDocument *pdf_document)
1372 pdf_document->page = 1;
1373 pdf_document->page_x_offset = 0;
1374 pdf_document->page_y_offset = 0;
1375 pdf_document->scale = 1.;
1377 pdf_document->password = NULL;