X-Git-Url: https://www.fi.muni.cz/~kas/git//home/kas/public_html/git/?a=blobdiff_plain;f=pdf%2Fxpdf%2Fpdf-document.cc;h=feb009d017a7ee263dd46b23bc48f12088deabea;hb=8b3ebe4d7024547993d3b4660f3f22036e327be3;hp=284b3710cefe5392775f2a48927a359ec498de5c;hpb=81ab197b294eaaba8b6b99bf2c259c5adb1e2251;p=evince.git diff --git a/pdf/xpdf/pdf-document.cc b/pdf/xpdf/pdf-document.cc index 284b3710..feb009d0 100644 --- a/pdf/xpdf/pdf-document.cc +++ b/pdf/xpdf/pdf-document.cc @@ -24,13 +24,19 @@ #include "ev-ps-exporter.h" #include "ev-document-find.h" #include "gpdf-g-switch.h" +#include "ev-document-bookmarks.h" +#include "ev-document-misc.h" +#include "ev-document-thumbnails.h" #include "GlobalParams.h" #include "GDKSplashOutputDev.h" +#include "SplashBitmap.h" #include "PDFDoc.h" #include "Outline.h" #include "UnicodeMap.h" #include "GlobalParams.h" +#include "GfxState.h" +#include "Thumb.h" #include "goo/GList.h" #include "PSOutputDev.h" @@ -85,8 +91,9 @@ struct _PdfDocument PdfDocumentSearch *search; }; -static void pdf_document_document_bookmarks_iface_init (EvDocumentBookmarksIface *iface); -static void pdf_document_document_iface_init (EvDocumentIface *iface); +static void pdf_document_document_bookmarks_iface_init (EvDocumentBookmarksIface *iface); +static void pdf_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface); +static void pdf_document_document_iface_init (EvDocumentIface *iface); static void pdf_document_ps_exporter_iface_init (EvPSExporterIface *iface); static void pdf_document_find_iface_init (EvDocumentFindIface *iface); static void pdf_document_search_free (PdfDocumentSearch *search); @@ -98,6 +105,8 @@ G_DEFINE_TYPE_WITH_CODE (PdfDocument, pdf_document, G_TYPE_OBJECT, pdf_document_document_iface_init); G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_BOOKMARKS, pdf_document_document_bookmarks_iface_init); + G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_THUMBNAILS, + pdf_document_document_thumbnails_iface_init); G_IMPLEMENT_INTERFACE (EV_TYPE_PS_EXPORTER, pdf_document_ps_exporter_iface_init); G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_FIND, @@ -121,7 +130,7 @@ document_validate_page (PdfDocument *pdf_document) if (pdf_document->search) pdf_document_search_page_changed (pdf_document->search); } - + return pdf_document->page_valid; } @@ -135,7 +144,7 @@ pdf_document_load (EvDocument *document, int err; char *filename; GString *filename_g; - GString *enc; + GString *enc; if (!globalParams) { globalParams = new GlobalParams("/etc/xpdfrc"); @@ -145,7 +154,7 @@ pdf_document_load (EvDocument *document, if (! pdf_document->umap) { enc = new GString("UTF-8"); pdf_document->umap = globalParams->getUnicodeMap(enc); - pdf_document->umap->incRefCnt (); + pdf_document->umap->incRefCnt (); delete enc; } @@ -189,6 +198,25 @@ pdf_document_load (EvDocument *document, return TRUE; } +static gboolean +pdf_document_save (EvDocument *document, + const char *uri, + GError **error) +{ + PdfDocument *pdf_document = PDF_DOCUMENT (document); + char *filename; + gboolean retval = FALSE; + + filename = g_filename_from_uri (uri, NULL, error); + if (filename != NULL) { + GString *fname = new GString (filename); + + retval = pdf_document->doc->saveAs (fname); + } + + return retval; +} + static int pdf_document_get_n_pages (EvDocument *document) { @@ -368,9 +396,9 @@ pdf_document_search_emit_found (PdfDocumentSearch *search) if (i != pdf_document->page && search->other_page_flags[i]) { EvFindResult result; - + result.page_num = i; - + /* Use bogus coordinates, again we can't get coordinates * until this is the current page because TextOutputDev * isn't good enough @@ -379,18 +407,18 @@ pdf_document_search_emit_found (PdfDocumentSearch *search) result.highlight_area.y = -1; result.highlight_area.width = 1; result.highlight_area.height = 1; - + g_array_append_val (tmp_results, result); } ++i; } - + ev_document_find_found (EV_DOCUMENT_FIND (pdf_document), (EvFindResult*) tmp_results->data, tmp_results->len, pages_done / (double) n_pages); - + g_array_free (tmp_results, TRUE); } @@ -409,13 +437,13 @@ pdf_document_search_page_changed (PdfDocumentSearch *search) search->current_page = -1; return; } - + if (search->current_page == current_page) return; - + /* We need to create current_page_results for the new current page */ g_array_set_size (search->current_page_results, 0); - + if (pdf_document->out->findText (search->ucs4, search->ucs4_len, gTrue, gTrue, // startAtTop, stopAtBottom gFalse, gFalse, // startAtLast, stopAtLast @@ -441,7 +469,7 @@ pdf_document_search_page_changed (PdfDocumentSearch *search) result.highlight_area.y = yMin; result.highlight_area.width = xMax - xMin; result.highlight_area.height = yMax - yMin; - + g_array_append_val (search->current_page_results, result); } } @@ -451,7 +479,7 @@ pdf_document_search_page_changed (PdfDocumentSearch *search) */ search->other_page_flags[current_page] = search->current_page_results->len > 0; - + pdf_document_search_emit_found (search); } @@ -483,7 +511,7 @@ pdf_document_search_idle_callback (void *data) goto end_search; } } - + pdf_document->doc->displayPage (search->output_dev, search->search_page, 72, 72, 0, gTrue, gFalse); @@ -496,7 +524,7 @@ pdf_document_search_idle_callback (void *data) /* This page has results */ search->other_page_flags[search->search_page] = TRUE; } - + search->search_page += 1; if (search->search_page > n_pages) { /* wrap around */ @@ -505,7 +533,7 @@ pdf_document_search_idle_callback (void *data) /* We do this even if nothing was found, to update the percent complete */ pdf_document_search_emit_found (search); - + return TRUE; end_search: @@ -529,7 +557,7 @@ pdf_document_find_begin (EvDocumentFind *document, * code is always case insensitive for ASCII * and case sensitive for all other languaages) */ - + g_assert (sizeof (gunichar) == sizeof (Unicode)); ucs4 = g_utf8_to_ucs4_fast (search_string, -1, &ucs4_len); @@ -548,22 +576,22 @@ pdf_document_find_begin (EvDocumentFind *document, pdf_document_search_free (pdf_document->search); pdf_document->search = NULL; } - + search = g_new0 (PdfDocumentSearch, 1); search->ucs4 = ucs4; search->ucs4_len = ucs4_len; - + search->current_page_results = g_array_new (FALSE, FALSE, sizeof (EvFindResult)); - n_pages = ev_document_get_n_pages (EV_DOCUMENT (document)); + n_pages = ev_document_get_n_pages (EV_DOCUMENT (document)); /* This is an array of bool; with the first value ignored * so we can index by the based-at-1 page numbers */ search->other_page_flags = g_new0 (guchar, n_pages + 1); - + search->document = pdf_document; /* We add at low priority so the progress bar repaints */ @@ -582,7 +610,7 @@ pdf_document_find_begin (EvDocumentFind *document, search->current_page = -1; pdf_document->search = search; - + /* Update for the current page right away */ pdf_document_search_page_changed (search); } @@ -606,10 +634,10 @@ pdf_document_search_free (PdfDocumentSearch *search) if (search->output_dev) delete search->output_dev; - + g_array_free (search->current_page_results, TRUE); g_free (search->other_page_flags); - + g_free (search->ucs4); g_free (search); } @@ -625,7 +653,7 @@ pdf_document_ps_export_begin (EvPSExporter *exporter, const char *filename) document->ps_out = new PSOutputDev ((char *)filename, document->doc->getXRef(), document->doc->getCatalog(), 1, ev_document_get_n_pages (EV_DOCUMENT (document)), - psModePS); + psModePS); } static void @@ -657,13 +685,13 @@ typedef struct } BookmarksIter; static gchar * -unicode_to_char (OutlineItem *outline_item, +unicode_to_char (OutlineItem *outline_item, UnicodeMap *uMap) { GString gstr; gchar buf[8]; /* 8 is enough for mapping an unicode char to a string */ int i, n; - + for (i = 0; i < outline_item->getTitleLength(); ++i) { n = uMap->mapUnicode(outline_item->getTitle()[i], buf, sizeof(buf)); gstr.append(buf, n); @@ -712,34 +740,30 @@ pdf_document_bookmarks_begin_read (EvDocumentBookmarks *document_bookmarks) return (EvDocumentBookmarksIter *) iter; } -static gboolean -pdf_document_bookmarks_get_values (EvDocumentBookmarks *document_bookmarks, - EvDocumentBookmarksIter *bookmarks_iter, - char **title, - EvDocumentBookmarksType *type, - gint *page) +static EvBookmark * +pdf_document_bookmarks_get_bookmark (EvDocumentBookmarks *document_bookmarks, + EvDocumentBookmarksIter *bookmarks_iter) { PdfDocument *pdf_document = PDF_DOCUMENT (document_bookmarks); + EvBookmark *bookmark; BookmarksIter *iter = (BookmarksIter *)bookmarks_iter; OutlineItem *anItem; LinkAction *link_action; LinkDest *link_dest = NULL; LinkURI *link_uri = NULL; LinkGoTo *link_goto = NULL; - GString *named_dest; + GString *named_dest; Unicode *link_title; Ref page_ref; - gint page_num = -1; + gint page_num = 0; + char *title; g_return_val_if_fail (PDF_IS_DOCUMENT (document_bookmarks), FALSE); g_return_val_if_fail (iter != NULL, FALSE); - g_return_val_if_fail (title != NULL, FALSE); - g_return_val_if_fail (type != NULL, FALSE); - g_return_val_if_fail (page != NULL, FALSE); anItem = (OutlineItem *)iter->items->get(iter->index); link_action = anItem->getAction (); - link_title = anItem->getTitle (); + link_title = anItem->getTitle (); if (link_action) { switch (link_action->getKind ()) { @@ -765,30 +789,31 @@ pdf_document_bookmarks_get_values (EvDocumentBookmarks *document_bookmarks, } else { page_num = link_dest->getPageNum (); } - + delete link_dest; } - + break; case actionURI: link_uri = dynamic_cast (link_action); break; - + case actionNamed: /*Skip, for now */ default: g_warning ("Unknown link action type: %d", link_action->getKind ()); } - *title = g_strdup (unicode_to_char (anItem, pdf_document->umap)); + title = g_strdup (unicode_to_char (anItem, pdf_document->umap)); } else if (link_title) { - *title = g_strdup (unicode_to_char (anItem, pdf_document->umap)); + title = g_strdup (unicode_to_char (anItem, pdf_document->umap)); } - *type = EV_DOCUMENT_BOOKMARKS_TYPE_LINK; - *page = page_num; + bookmark = ev_bookmark_new (title, EV_BOOKMARK_TYPE_LINK, page_num); - return TRUE; + g_free (title); + + return bookmark; } static EvDocumentBookmarksIter * @@ -853,7 +878,7 @@ pdf_document_finalize (GObject *object) if (pdf_document->search) pdf_document_search_free (pdf_document->search); - + if (pdf_document->target) g_object_unref (pdf_document->target); @@ -920,7 +945,7 @@ pdf_info_dict_get_string (Dict *info_dict, const gchar *key) { static char * pdf_document_get_title (PdfDocument *pdf_document) { - char *title; + char *title = NULL; Object info; pdf_document->doc->getDocInfo (&info); @@ -932,6 +957,25 @@ pdf_document_get_title (PdfDocument *pdf_document) return title; } +static char * +pdf_document_get_text (EvDocument *document, GdkRectangle *rect) +{ + PdfDocument *pdf_document = PDF_DOCUMENT (document); + GString *sel_text = new GString; + const char *text; + int x1, y1, x2, y2; + + x1 = rect->x; + y1 = rect->y; + x2 = x1 + rect->width; + y2 = y1 + rect->height; + + sel_text = pdf_document->out->getText (x1, y1, x2, y2); + text = sel_text->getCString (); + + return text ? g_strdup (text) : NULL; +} + static void pdf_document_get_property (GObject *object, guint prop_id, @@ -967,6 +1011,8 @@ static void pdf_document_document_iface_init (EvDocumentIface *iface) { iface->load = pdf_document_load; + iface->save = pdf_document_save; + iface->get_text = pdf_document_get_text; iface->get_n_pages = pdf_document_get_n_pages; iface->set_page = pdf_document_set_page; iface->get_page = pdf_document_get_page; @@ -998,12 +1044,197 @@ pdf_document_document_bookmarks_iface_init (EvDocumentBookmarksIface *iface) { iface->has_document_bookmarks = pdf_document_bookmarks_has_document_bookmarks; iface->begin_read = pdf_document_bookmarks_begin_read; - iface->get_values = pdf_document_bookmarks_get_values; + iface->get_bookmark = pdf_document_bookmarks_get_bookmark; iface->get_child = pdf_document_bookmarks_get_child; iface->next = pdf_document_bookmarks_next; iface->free_iter = pdf_document_bookmarks_free_iter; } +/* Thumbnails */ + +static GdkPixbuf * +bitmap_to_pixbuf (SplashBitmap *bitmap, + GdkPixbuf *target, + gint x_offset, + gint y_offset) +{ + gint width; + gint height; + SplashColorPtr dataPtr; + int x, y; + + gboolean target_has_alpha; + gint target_rowstride; + guchar *target_data; + + width = bitmap->getWidth (); + height = bitmap->getHeight (); + + if (width + x_offset > gdk_pixbuf_get_width (target)) + width = gdk_pixbuf_get_width (target) - x_offset; + if (height + y_offset > gdk_pixbuf_get_height (target)) + height = gdk_pixbuf_get_height (target) - x_offset; + + target_has_alpha = gdk_pixbuf_get_has_alpha (target); + target_rowstride = gdk_pixbuf_get_rowstride (target); + target_data = gdk_pixbuf_get_pixels (target); + + dataPtr = bitmap->getDataPtr (); + + for (y = 0; y < height; y++) { + SplashRGB8 *p; + SplashRGB8 rgb; + guchar *q; + + p = dataPtr.rgb8 + y * width; + q = target_data + ((y + y_offset) * target_rowstride + + x_offset * (target_has_alpha?4:3)); + for (x = 0; x < width; x++) { + rgb = *p++; + + *q++ = splashRGB8R (rgb); + *q++ = splashRGB8G (rgb); + *q++ = splashRGB8B (rgb); + + if (target_has_alpha) + q++; + } + } + + return target; +} + + +static GdkPixbuf * +pdf_document_thumbnails_get_page_pixbuf (PdfDocument *pdf_document, + gdouble scale_factor, + gint page_num, + gint width, + gint height) +{ + SplashOutputDev *output; + GdkPixbuf *pixbuf; + SplashColor color; + + color.rgb8 = splashMakeRGB8 (255, 255, 255); + + output = new SplashOutputDev (splashModeRGB8, gFalse, color); + output->startDoc (pdf_document->doc->getXRef()); + pdf_document->doc->displayPage (output, + page_num + 1, + 72*scale_factor, + 72*scale_factor, + 0, gTrue, gFalse); + + pixbuf = ev_document_misc_get_thumbnail_frame (output->getBitmap()->getWidth(), + output->getBitmap()->getHeight(), + NULL); + bitmap_to_pixbuf (output->getBitmap(), pixbuf, 1, 1); + delete output; + + return pixbuf; +} + +static void +pdf_document_thumbnails_get_dimensions (EvDocumentThumbnails *document_thumbnails, + gint page, + gint suggested_width, + gint *width, + gint *height) +{ + PdfDocument *pdf_document = PDF_DOCUMENT (document_thumbnails); + Page *the_page; + Object the_thumb; + Thumb *thumb = NULL; + gdouble page_ratio; + + /* getPage seems to want page + 1 for some reason; */ + the_page = pdf_document->doc->getCatalog ()->getPage (page + 1); + the_page->getThumb (&the_thumb); + + + + if (!(the_thumb.isNull () || the_thumb.isNone())) { + /* Build the thumbnail object */ + thumb = new Thumb(pdf_document->doc->getXRef (), + &the_thumb); + + *width = thumb->getWidth (); + *height = thumb->getHeight (); + } else { + page_ratio = the_page->getHeight () / the_page->getWidth (); + *width = suggested_width; + *height = (gint) (suggested_width * page_ratio); + } +} + +static GdkPixbuf * +pdf_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document_thumbnails, + gint page, + gint width) +{ + PdfDocument *pdf_document = PDF_DOCUMENT (document_thumbnails); + GdkPixbuf *thumbnail; + Page *the_page; + Object the_thumb; + Thumb *thumb = NULL; + gboolean have_ethumbs = FALSE; + gdouble page_ratio; + gint dest_height; + + /* getPage seems to want page + 1 for some reason; */ + the_page = pdf_document->doc->getCatalog ()->getPage (page + 1); + the_page->getThumb(&the_thumb); + + page_ratio = the_page->getHeight () / the_page->getWidth (); + dest_height = (gint) (width * page_ratio); + + + if (!(the_thumb.isNull () || the_thumb.isNone())) { + /* Build the thumbnail object */ + thumb = new Thumb(pdf_document->doc->getXRef (), + &the_thumb); + + have_ethumbs = thumb->ok(); + } + + if (have_ethumbs) { + guchar *data; + GdkPixbuf *tmp_pixbuf; + + data = thumb->getPixbufData(); + tmp_pixbuf = gdk_pixbuf_new_from_data (data, + GDK_COLORSPACE_RGB, + FALSE, + 8, + thumb->getWidth (), + thumb->getHeight (), + thumb->getWidth () * 3, + NULL, NULL); + /* FIXME: do we want to check that the thumb's size isn't ridiculous?? */ + thumbnail = ev_document_misc_get_thumbnail_frame (-1, -1, tmp_pixbuf); + g_object_unref (tmp_pixbuf); + } else { + gdouble scale_factor; + + scale_factor = (gdouble)width / the_page->getWidth (); + + thumbnail = pdf_document_thumbnails_get_page_pixbuf (pdf_document, + scale_factor, + page, + width, + dest_height); + } + + return thumbnail; +} +static void +pdf_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface) +{ + iface->get_thumbnail = pdf_document_thumbnails_get_thumbnail; + iface->get_dimensions = pdf_document_thumbnails_get_dimensions; +} + static void pdf_document_init (PdfDocument *pdf_document)