summaryrefslogtreecommitdiff
path: root/Build/source/libs/poppler/poppler-0.12.4/glib/poppler-page.cc
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/libs/poppler/poppler-0.12.4/glib/poppler-page.cc')
-rw-r--r--Build/source/libs/poppler/poppler-0.12.4/glib/poppler-page.cc2006
1 files changed, 2006 insertions, 0 deletions
diff --git a/Build/source/libs/poppler/poppler-0.12.4/glib/poppler-page.cc b/Build/source/libs/poppler/poppler-0.12.4/glib/poppler-page.cc
new file mode 100644
index 00000000000..3c0ead1f431
--- /dev/null
+++ b/Build/source/libs/poppler/poppler-0.12.4/glib/poppler-page.cc
@@ -0,0 +1,2006 @@
+/* poppler-page.cc: glib wrapper for poppler
+ * Copyright (C) 2005, Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include <math.h>
+
+#include <goo/GooList.h>
+#include <splash/SplashBitmap.h>
+#include <GlobalParams.h>
+#include <PDFDoc.h>
+#include <Outline.h>
+#include <ErrorCodes.h>
+#include <UnicodeMap.h>
+#include <GfxState.h>
+#include <PageTransition.h>
+
+#include "poppler.h"
+#include "poppler-private.h"
+
+enum
+{
+ PROP_0,
+ PROP_LABEL
+};
+
+typedef struct _PopplerPageClass PopplerPageClass;
+struct _PopplerPageClass
+{
+ GObjectClass parent_class;
+};
+
+G_DEFINE_TYPE (PopplerPage, poppler_page, G_TYPE_OBJECT)
+
+PopplerPage *
+_poppler_page_new (PopplerDocument *document, Page *page, int index)
+{
+ PopplerPage *poppler_page;
+
+ g_return_val_if_fail (POPPLER_IS_DOCUMENT (document), NULL);
+
+ poppler_page = (PopplerPage *) g_object_new (POPPLER_TYPE_PAGE, NULL, NULL);
+ poppler_page->document = (PopplerDocument *) g_object_ref (document);
+ poppler_page->page = page;
+ poppler_page->index = index;
+
+ return poppler_page;
+}
+
+static void
+poppler_page_finalize (GObject *object)
+{
+ PopplerPage *page = POPPLER_PAGE (object);
+
+ g_object_unref (page->document);
+ page->document = NULL;
+
+ if (page->annots != NULL)
+ delete page->annots;
+#if defined (HAVE_CAIRO)
+ if (page->text != NULL)
+ page->text->decRefCnt();
+#else
+ if (page->gfx != NULL)
+ delete page->gfx;
+ if (page->text_dev != NULL)
+ delete page->text_dev;
+#endif
+ /* page->page is owned by the document */
+}
+
+/**
+ * poppler_page_get_size:
+ * @page: A #PopplerPage
+ * @width: return location for the width of @page
+ * @height: return location for the height of @page
+ *
+ * Gets the size of @page at the current scale and rotation.
+ **/
+void
+poppler_page_get_size (PopplerPage *page,
+ double *width,
+ double *height)
+{
+ double page_width, page_height;
+ int rotate;
+
+ g_return_if_fail (POPPLER_IS_PAGE (page));
+
+ rotate = page->page->getRotate ();
+ if (rotate == 90 || rotate == 270) {
+ page_height = page->page->getCropWidth ();
+ page_width = page->page->getCropHeight ();
+ } else {
+ page_width = page->page->getCropWidth ();
+ page_height = page->page->getCropHeight ();
+ }
+
+ if (width != NULL)
+ *width = page_width;
+ if (height != NULL)
+ *height = page_height;
+}
+
+/**
+ * poppler_page_get_index:
+ * @page: a #PopplerPage
+ *
+ * Returns the index of @page
+ *
+ * Return value: index value of @page
+ **/
+int
+poppler_page_get_index (PopplerPage *page)
+{
+ g_return_val_if_fail (POPPLER_IS_PAGE (page), 0);
+
+ return page->index;
+}
+
+/**
+ * poppler_page_get_duration:
+ * @page: a #PopplerPage
+ *
+ * Returns the duration of @page
+ *
+ * Return value: duration in seconds of @page or -1.
+ **/
+double
+poppler_page_get_duration (PopplerPage *page)
+{
+ g_return_val_if_fail (POPPLER_IS_PAGE (page), -1);
+
+ return page->page->getDuration ();
+}
+
+/**
+ * poppler_page_get_transition:
+ * @page: a #PopplerPage
+ *
+ * Returns the transition effect of @page
+ *
+ * Return value: a #PopplerPageTransition or NULL.
+ **/
+PopplerPageTransition *
+poppler_page_get_transition (PopplerPage *page)
+{
+ PageTransition *trans;
+ PopplerPageTransition *transition;
+ Object obj;
+
+ g_return_val_if_fail (POPPLER_IS_PAGE (page), NULL);
+
+ trans = new PageTransition (page->page->getTrans (&obj));
+ obj.free ();
+
+ if (!trans->isOk ()) {
+ delete trans;
+ return NULL;
+ }
+
+ transition = poppler_page_transition_new ();
+
+ switch (trans->getType ())
+ {
+ case transitionReplace:
+ transition->type = POPPLER_PAGE_TRANSITION_REPLACE;
+ break;
+ case transitionSplit:
+ transition->type = POPPLER_PAGE_TRANSITION_SPLIT;
+ break;
+ case transitionBlinds:
+ transition->type = POPPLER_PAGE_TRANSITION_BLINDS;
+ break;
+ case transitionBox:
+ transition->type = POPPLER_PAGE_TRANSITION_BOX;
+ break;
+ case transitionWipe:
+ transition->type = POPPLER_PAGE_TRANSITION_WIPE;
+ break;
+ case transitionDissolve:
+ transition->type = POPPLER_PAGE_TRANSITION_DISSOLVE;
+ break;
+ case transitionGlitter:
+ transition->type = POPPLER_PAGE_TRANSITION_GLITTER;
+ break;
+ case transitionFly:
+ transition->type = POPPLER_PAGE_TRANSITION_FLY;
+ break;
+ case transitionPush:
+ transition->type = POPPLER_PAGE_TRANSITION_PUSH;
+ break;
+ case transitionCover:
+ transition->type = POPPLER_PAGE_TRANSITION_COVER;
+ break;
+ case transitionUncover:
+ transition->type = POPPLER_PAGE_TRANSITION_UNCOVER;
+ break;
+ case transitionFade:
+ transition->type = POPPLER_PAGE_TRANSITION_FADE;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ transition->alignment = (trans->getAlignment() == transitionHorizontal) ?
+ POPPLER_PAGE_TRANSITION_HORIZONTAL :
+ POPPLER_PAGE_TRANSITION_VERTICAL;
+
+ transition->direction = (trans->getDirection() == transitionInward) ?
+ POPPLER_PAGE_TRANSITION_INWARD :
+ POPPLER_PAGE_TRANSITION_OUTWARD;
+
+ transition->duration = trans->getDuration();
+ transition->angle = trans->getAngle();
+ transition->scale = trans->getScale();
+ transition->rectangular = trans->isRectangular();
+
+ delete trans;
+
+ return transition;
+}
+
+#if !defined (HAVE_CAIRO)
+static TextOutputDev *
+poppler_page_get_text_output_dev (PopplerPage *page)
+{
+ if (page->text_dev == NULL) {
+ page->text_dev = new TextOutputDev (NULL, gTrue, gFalse, gFalse);
+
+ if (page->gfx)
+ delete page->gfx;
+ page->gfx = page->page->createGfx(page->text_dev,
+ 72.0, 72.0, 0,
+ gFalse, /* useMediaBox */
+ gTrue, /* Crop */
+ -1, -1, -1, -1,
+ gFalse, /* printing */
+ page->document->doc->getCatalog (),
+ NULL, NULL, NULL, NULL);
+
+ page->page->display(page->gfx);
+
+ page->text_dev->endPage();
+ }
+
+ return page->text_dev;
+}
+#endif /* !defined (HAVE_CAIRO) */
+
+#if defined (HAVE_CAIRO)
+
+static TextPage *
+poppler_page_get_text_page (PopplerPage *page)
+{
+ if (page->text == NULL) {
+ cairo_t *cr;
+ cairo_surface_t *surface;
+
+ surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 1, 1);
+ cr = cairo_create (surface);
+ poppler_page_render (page, cr);
+ cairo_destroy (cr);
+ cairo_surface_destroy (surface);
+
+ }
+
+ return page->text;
+}
+
+#ifdef POPPLER_WITH_GDK
+typedef struct {
+ unsigned char *cairo_data;
+ cairo_surface_t *surface;
+ cairo_t *cairo;
+} OutputDevData;
+
+static void
+poppler_page_prepare_output_dev (PopplerPage *page,
+ double scale,
+ int rotation,
+ gboolean transparent,
+ OutputDevData *output_dev_data)
+{
+ CairoOutputDev *output_dev;
+ cairo_surface_t *surface;
+ double width, height;
+ int cairo_width, cairo_height, cairo_rowstride, rotate;
+ unsigned char *cairo_data;
+
+ rotate = rotation + page->page->getRotate ();
+ if (rotate == 90 || rotate == 270) {
+ height = page->page->getCropWidth ();
+ width = page->page->getCropHeight ();
+ } else {
+ width = page->page->getCropWidth ();
+ height = page->page->getCropHeight ();
+ }
+
+ cairo_width = (int) ceil(width * scale);
+ cairo_height = (int) ceil(height * scale);
+
+ output_dev = page->document->output_dev;
+ cairo_rowstride = cairo_width * 4;
+ cairo_data = (guchar *) gmallocn (cairo_height, cairo_rowstride);
+ if (transparent)
+ memset (cairo_data, 0x00, cairo_height * cairo_rowstride);
+ else
+ memset (cairo_data, 0xff, cairo_height * cairo_rowstride);
+
+ surface = cairo_image_surface_create_for_data(cairo_data,
+ CAIRO_FORMAT_ARGB32,
+ cairo_width, cairo_height,
+ cairo_rowstride);
+
+ output_dev_data->cairo_data = cairo_data;
+ output_dev_data->surface = surface;
+ output_dev_data->cairo = cairo_create (surface);
+ output_dev->setCairo (output_dev_data->cairo);
+}
+
+static void
+copy_cairo_surface_to_pixbuf (cairo_surface_t *surface,
+ unsigned char *data,
+ GdkPixbuf *pixbuf)
+{
+ int cairo_width, cairo_height, cairo_rowstride;
+ unsigned char *pixbuf_data, *dst, *cairo_data;
+ int pixbuf_rowstride, pixbuf_n_channels;
+ unsigned int *src;
+ int x, y;
+
+ cairo_width = cairo_image_surface_get_width (surface);
+ cairo_height = cairo_image_surface_get_height (surface);
+ cairo_rowstride = cairo_width * 4;
+ cairo_data = data;
+
+ pixbuf_data = gdk_pixbuf_get_pixels (pixbuf);
+ pixbuf_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+ pixbuf_n_channels = gdk_pixbuf_get_n_channels (pixbuf);
+
+ if (cairo_width > gdk_pixbuf_get_width (pixbuf))
+ cairo_width = gdk_pixbuf_get_width (pixbuf);
+ if (cairo_height > gdk_pixbuf_get_height (pixbuf))
+ cairo_height = gdk_pixbuf_get_height (pixbuf);
+ for (y = 0; y < cairo_height; y++)
+ {
+ src = (unsigned int *) (cairo_data + y * cairo_rowstride);
+ dst = pixbuf_data + y * pixbuf_rowstride;
+ for (x = 0; x < cairo_width; x++)
+ {
+ dst[0] = (*src >> 16) & 0xff;
+ dst[1] = (*src >> 8) & 0xff;
+ dst[2] = (*src >> 0) & 0xff;
+ if (pixbuf_n_channels == 4)
+ dst[3] = (*src >> 24) & 0xff;
+ dst += pixbuf_n_channels;
+ src++;
+ }
+ }
+}
+
+static void
+poppler_page_copy_to_pixbuf (PopplerPage *page,
+ GdkPixbuf *pixbuf,
+ OutputDevData *output_dev_data)
+{
+ copy_cairo_surface_to_pixbuf (output_dev_data->surface,
+ output_dev_data->cairo_data,
+ pixbuf);
+
+ page->document->output_dev->setCairo (NULL);
+ cairo_surface_destroy (output_dev_data->surface);
+ cairo_destroy (output_dev_data->cairo);
+ gfree (output_dev_data->cairo_data);
+}
+
+static void
+poppler_page_set_selection_alpha (PopplerPage *page,
+ double scale,
+ GdkPixbuf *pixbuf,
+ PopplerSelectionStyle style,
+ PopplerRectangle *selection)
+{
+ /* Cairo doesn't need this, since cairo generates an alpha channel. */
+}
+#endif /* POPPLER_WITH_GDK */
+
+#elif defined (HAVE_SPLASH) && defined (POPPLER_WITH_GDK)
+
+typedef struct {
+} OutputDevData;
+
+static void
+poppler_page_prepare_output_dev (PopplerPage *page,
+ double scale,
+ int rotation,
+ gboolean transparent,
+ OutputDevData *output_dev_data)
+{
+ /* pft */
+}
+
+static void
+poppler_page_copy_to_pixbuf(PopplerPage *page,
+ GdkPixbuf *pixbuf,
+ OutputDevData *data)
+{
+ SplashOutputDev *output_dev;
+ SplashBitmap *bitmap;
+ SplashColorPtr color_ptr;
+ int splash_width, splash_height, splash_rowstride;
+ int pixbuf_rowstride, pixbuf_n_channels;
+ guchar *pixbuf_data, *dst;
+ int x, y;
+
+ output_dev = page->document->output_dev;
+
+ bitmap = output_dev->getBitmap ();
+ color_ptr = bitmap->getDataPtr ();
+
+ splash_width = bitmap->getWidth ();
+ splash_height = bitmap->getHeight ();
+ splash_rowstride = bitmap->getRowSize ();
+
+ pixbuf_data = gdk_pixbuf_get_pixels (pixbuf);
+ pixbuf_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+ pixbuf_n_channels = gdk_pixbuf_get_n_channels (pixbuf);
+
+ if (splash_width > gdk_pixbuf_get_width (pixbuf))
+ splash_width = gdk_pixbuf_get_width (pixbuf);
+ if (splash_height > gdk_pixbuf_get_height (pixbuf))
+ splash_height = gdk_pixbuf_get_height (pixbuf);
+
+ SplashColorPtr pixel = new Guchar[4];
+ for (y = 0; y < splash_height; y++)
+ {
+ dst = pixbuf_data + y * pixbuf_rowstride;
+ for (x = 0; x < splash_width; x++)
+ {
+ output_dev->getBitmap()->getPixel(x, y, pixel);
+ dst[0] = pixel[0];
+ dst[1] = pixel[1];
+ dst[2] = pixel[2];
+ if (pixbuf_n_channels == 4)
+ dst[3] = 0xff;
+ dst += pixbuf_n_channels;
+ }
+ }
+ delete [] pixel;
+}
+
+static void
+poppler_page_set_selection_alpha (PopplerPage *page,
+ double scale,
+ GdkPixbuf *pixbuf,
+ PopplerSelectionStyle style,
+ PopplerRectangle *selection)
+{
+ GList *region, *l;
+ gint x, y, width, height;
+ int pixbuf_rowstride, pixbuf_n_channels;
+ guchar *pixbuf_data, *dst;
+
+ pixbuf_data = gdk_pixbuf_get_pixels (pixbuf);
+ pixbuf_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+ pixbuf_n_channels = gdk_pixbuf_get_n_channels (pixbuf);
+ width = gdk_pixbuf_get_width (pixbuf);
+ height = gdk_pixbuf_get_height (pixbuf);
+
+ if (pixbuf_n_channels != 4)
+ return;
+
+ for (y = 0; y < height; y++) {
+ dst = pixbuf_data + y * pixbuf_rowstride;
+ for (x = 0; x < width; x++) {
+ dst[3] = 0x00;
+ dst += pixbuf_n_channels;
+ }
+ }
+
+ region = poppler_page_get_selection_region (page, scale, style, selection);
+
+ for (l = region; l; l = g_list_next (l)) {
+ PopplerRectangle *rectangle = (PopplerRectangle *)l->data;
+ GdkRectangle rect;
+
+ rect.x = (gint)rectangle->x1;
+ rect.y = (gint)rectangle->y1;
+ rect.width = (gint) (rectangle->x2 - rectangle->x1);
+ rect.height = (gint) (rectangle->y2 - rectangle->y1);
+
+ for (y = 0; y < rect.height; y++) {
+ dst = pixbuf_data + (rect.y + y) * pixbuf_rowstride +
+ rect.x * pixbuf_n_channels;
+ for (x = 0; x < rect.width; x++) {
+ dst[3] = 0xff;
+ dst += pixbuf_n_channels;
+ }
+ }
+ }
+
+ poppler_page_selection_region_free (region);
+}
+
+#endif /* HAVE_SPLASH */
+
+static GBool
+poppler_print_annot_cb (Annot *annot, void *user_data)
+{
+ if (annot->getFlags () & Annot::flagPrint)
+ return gTrue;
+ return (annot->getType() == Annot::typeWidget);
+}
+
+#if defined (HAVE_CAIRO)
+
+static void
+_poppler_page_render (PopplerPage *page,
+ cairo_t *cairo,
+ GBool printing)
+{
+ CairoOutputDev *output_dev;
+
+ g_return_if_fail (POPPLER_IS_PAGE (page));
+
+ output_dev = page->document->output_dev;
+ output_dev->setCairo (cairo);
+ output_dev->setPrinting (printing);
+
+ if (!printing)
+ output_dev->setTextPage (page->text);
+
+ /* NOTE: instead of passing -1 we should/could use cairo_clip_extents()
+ * to get a bounding box */
+ cairo_save (cairo);
+ page->page->displaySlice(output_dev,
+ 72.0, 72.0, 0,
+ gFalse, /* useMediaBox */
+ gTrue, /* Crop */
+ -1, -1,
+ -1, -1,
+ printing,
+ page->document->doc->getCatalog (),
+ NULL, NULL,
+ printing ? poppler_print_annot_cb : NULL, NULL);
+ cairo_restore (cairo);
+
+ output_dev->setCairo (NULL);
+ output_dev->setTextPage (NULL);
+}
+
+/**
+ * poppler_page_render:
+ * @page: the page to render from
+ * @cairo: cairo context to render to
+ *
+ * Render the page to the given cairo context. This function
+ * is for rendering a page that will be displayed. If you want
+ * to render a page that will be printed use
+ * poppler_page_render_for_printing() instead
+ **/
+void
+poppler_page_render (PopplerPage *page,
+ cairo_t *cairo)
+{
+ g_return_if_fail (POPPLER_IS_PAGE (page));
+
+ if (!page->text)
+ page->text = new TextPage(gFalse);
+
+ _poppler_page_render (page, cairo, gFalse);
+}
+
+/**
+ * poppler_page_render_for_printing:
+ * @page: the page to render from
+ * @cairo: cairo context to render to
+ *
+ * Render the page to the given cairo context for printing.
+ **/
+void
+poppler_page_render_for_printing (PopplerPage *page,
+ cairo_t *cairo)
+{
+ g_return_if_fail (POPPLER_IS_PAGE (page));
+
+ _poppler_page_render (page, cairo, gTrue);
+}
+
+static cairo_surface_t *
+create_surface_from_thumbnail_data (guchar *data,
+ gint width,
+ gint height,
+ gint rowstride)
+{
+ guchar *cairo_pixels;
+ gint cairo_stride;
+ cairo_surface_t *surface;
+ int j;
+
+ surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
+ if (cairo_surface_status (surface))
+ return NULL;
+
+ cairo_pixels = cairo_image_surface_get_data (surface);
+ cairo_stride = cairo_image_surface_get_stride (surface);
+
+ for (j = height; j; j--) {
+ guchar *p = data;
+ guchar *q = cairo_pixels;
+ guchar *end = p + 3 * width;
+
+ while (p < end) {
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ q[0] = p[2];
+ q[1] = p[1];
+ q[2] = p[0];
+#else
+ q[1] = p[0];
+ q[2] = p[1];
+ q[3] = p[2];
+#endif
+ p += 3;
+ q += 4;
+ }
+
+ data += rowstride;
+ cairo_pixels += cairo_stride;
+ }
+
+ return surface;
+}
+
+
+/**
+ * poppler_page_get_thumbnail:
+ * @page: the #PopperPage to get the thumbnail for
+ *
+ * Get the embedded thumbnail for the specified page. If the document
+ * doesn't have an embedded thumbnail for the page, this function
+ * returns %NULL.
+ *
+ * Return value: the tumbnail as a cairo_surface_t or %NULL if the document
+ * doesn't have a thumbnail for this page.
+ **/
+cairo_surface_t *
+poppler_page_get_thumbnail (PopplerPage *page)
+{
+ unsigned char *data;
+ int width, height, rowstride;
+ cairo_surface_t *surface;
+
+ g_return_val_if_fail (POPPLER_IS_PAGE (page), FALSE);
+
+ if (!page->page->loadThumb (&data, &width, &height, &rowstride))
+ return NULL;
+
+ surface = create_surface_from_thumbnail_data (data, width, height, rowstride);
+ gfree (data);
+
+ return surface;
+}
+
+/**
+ * poppler_page_render_selection:
+ * @page: the #PopplerPage for which to render selection
+ * @cairo: cairo context to render to
+ * @selection: start and end point of selection as a rectangle
+ * @old_selection: previous selection
+ * @style: a #PopplerSelectionStyle
+ * @glyph_color: color to use for drawing glyphs
+ * @background_color: color to use for the selection background
+ *
+ * Render the selection specified by @selection for @page to
+ * the given cairo context. The selection will be rendered, using
+ * @glyph_color for the glyphs and @background_color for the selection
+ * background.
+ *
+ * If non-NULL, @old_selection specifies the selection that is already
+ * rendered to @cairo, in which case this function will (some day)
+ * only render the changed part of the selection.
+ **/
+void
+poppler_page_render_selection (PopplerPage *page,
+ cairo_t *cairo,
+ PopplerRectangle *selection,
+ PopplerRectangle *old_selection,
+ PopplerSelectionStyle style,
+ PopplerColor *glyph_color,
+ PopplerColor *background_color)
+{
+ CairoOutputDev *output_dev;
+ TextPage *text;
+ SelectionStyle selection_style = selectionStyleGlyph;
+ PDFRectangle pdf_selection(selection->x1, selection->y1,
+ selection->x2, selection->y2);
+
+ GfxColor gfx_background_color = {
+ {
+ background_color->red,
+ background_color->green,
+ background_color->blue
+ }
+ };
+ GfxColor gfx_glyph_color = {
+ {
+ glyph_color->red,
+ glyph_color->green,
+ glyph_color->blue
+ }
+ };
+
+ switch (style)
+ {
+ case POPPLER_SELECTION_GLYPH:
+ selection_style = selectionStyleGlyph;
+ break;
+ case POPPLER_SELECTION_WORD:
+ selection_style = selectionStyleWord;
+ break;
+ case POPPLER_SELECTION_LINE:
+ selection_style = selectionStyleLine;
+ break;
+ }
+
+ output_dev = page->document->output_dev;
+ output_dev->setCairo (cairo);
+
+ text = poppler_page_get_text_page (page);
+ text->drawSelection (output_dev, 1.0, 0,
+ &pdf_selection, selection_style,
+ &gfx_glyph_color, &gfx_background_color);
+
+ output_dev->setCairo (NULL);
+}
+
+#endif /* HAVE_CAIRO */
+
+#ifdef POPPLER_WITH_GDK
+static void
+_poppler_page_render_to_pixbuf (PopplerPage *page,
+ int src_x, int src_y,
+ int src_width, int src_height,
+ double scale,
+ int rotation,
+ GBool printing,
+ GdkPixbuf *pixbuf)
+{
+ OutputDevData data;
+
+ poppler_page_prepare_output_dev (page, scale, rotation, FALSE, &data);
+
+ page->page->displaySlice(page->document->output_dev,
+ 72.0 * scale, 72.0 * scale,
+ rotation,
+ gFalse, /* useMediaBox */
+ gTrue, /* Crop */
+ src_x, src_y,
+ src_width, src_height,
+ printing,
+ page->document->doc->getCatalog (),
+ NULL, NULL,
+ printing ? poppler_print_annot_cb : NULL, NULL);
+
+ poppler_page_copy_to_pixbuf (page, pixbuf, &data);
+}
+
+/**
+ * poppler_page_render_to_pixbuf:
+ * @page: the page to render from
+ * @src_x: x coordinate of upper left corner
+ * @src_y: y coordinate of upper left corner
+ * @src_width: width of rectangle to render
+ * @src_height: height of rectangle to render
+ * @scale: scale specified as pixels per point
+ * @rotation: rotate the document by the specified degree
+ * @pixbuf: pixbuf to render into
+ *
+ * First scale the document to match the specified pixels per point,
+ * then render the rectangle given by the upper left corner at
+ * (src_x, src_y) and src_width and src_height.
+ * This function is for rendering a page that will be displayed.
+ * If you want to render a page that will be printed use
+ * poppler_page_render_to_pixbuf_for_printing() instead
+ **/
+void
+poppler_page_render_to_pixbuf (PopplerPage *page,
+ int src_x, int src_y,
+ int src_width, int src_height,
+ double scale,
+ int rotation,
+ GdkPixbuf *pixbuf)
+{
+ g_return_if_fail (POPPLER_IS_PAGE (page));
+ g_return_if_fail (scale > 0.0);
+ g_return_if_fail (pixbuf != NULL);
+
+ _poppler_page_render_to_pixbuf (page, src_x, src_y,
+ src_width, src_height,
+ scale, rotation,
+ gFalse,
+ pixbuf);
+}
+
+/**
+ * poppler_page_render_to_pixbuf_for_printing:
+ * @page: the page to render from
+ * @src_x: x coordinate of upper left corner
+ * @src_y: y coordinate of upper left corner
+ * @src_width: width of rectangle to render
+ * @src_height: height of rectangle to render
+ * @scale: scale specified as pixels per point
+ * @rotation: rotate the document by the specified degree
+ * @pixbuf: pixbuf to render into
+ *
+ * First scale the document to match the specified pixels per point,
+ * then render the rectangle given by the upper left corner at
+ * (src_x, src_y) and src_width and src_height.
+ * This function is for rendering a page that will be printed.
+ **/
+void
+poppler_page_render_to_pixbuf_for_printing (PopplerPage *page,
+ int src_x, int src_y,
+ int src_width, int src_height,
+ double scale,
+ int rotation,
+ GdkPixbuf *pixbuf)
+{
+ g_return_if_fail (POPPLER_IS_PAGE (page));
+ g_return_if_fail (scale > 0.0);
+ g_return_if_fail (pixbuf != NULL);
+
+ _poppler_page_render_to_pixbuf (page, src_x, src_y,
+ src_width, src_height,
+ scale, rotation,
+ gTrue,
+ pixbuf);
+}
+
+/**
+ * poppler_page_get_thumbnail_pixbuf:
+ * @page: the #PopperPage to get the thumbnail for
+ *
+ * Get the embedded thumbnail for the specified page. If the document
+ * doesn't have an embedded thumbnail for the page, this function
+ * returns %NULL.
+ *
+ * Return value: the tumbnail as a #GdkPixbuf or %NULL if the document
+ * doesn't have a thumbnail for this page.
+ **/
+GdkPixbuf *
+poppler_page_get_thumbnail_pixbuf (PopplerPage *page)
+{
+ unsigned char *data;
+ int width, height, rowstride;
+
+ g_return_val_if_fail (POPPLER_IS_PAGE (page), FALSE);
+
+ if (!page->page->loadThumb (&data, &width, &height, &rowstride))
+ return NULL;
+
+ return gdk_pixbuf_new_from_data (data, GDK_COLORSPACE_RGB,
+ FALSE, 8, width, height, rowstride,
+ (GdkPixbufDestroyNotify)gfree, NULL);
+}
+
+/**
+ * poppler_page_render_selection_to_pixbuf:
+ * @page: the #PopplerPage for which to render selection
+ * @scale: scale specified as pixels per point
+ * @rotation: rotate the document by the specified degree
+ * @pixbuf: pixbuf to render to
+ * @selection: start and end point of selection as a rectangle
+ * @old_selection: previous selection
+ * @style: a #PopplerSelectionStyle
+ * @glyph_color: color to use for drawing glyphs
+ * @background_color: color to use for the selection background
+ *
+ * Render the selection specified by @selection for @page into
+ * @pixbuf. The selection will be rendered at @scale, using
+ * @glyph_color for the glyphs and @background_color for the selection
+ * background.
+ *
+ * If non-NULL, @old_selection specifies the selection that is already
+ * rendered in @pixbuf, in which case this function will (some day)
+ * only render the changed part of the selection.
+ **/
+void
+poppler_page_render_selection_to_pixbuf (PopplerPage *page,
+ gdouble scale,
+ int rotation,
+ GdkPixbuf *pixbuf,
+ PopplerRectangle *selection,
+ PopplerRectangle *old_selection,
+ PopplerSelectionStyle style,
+ GdkColor *glyph_color,
+ GdkColor *background_color)
+{
+ OutputDev *output_dev;
+ OutputDevData data;
+ SelectionStyle selection_style = selectionStyleGlyph;
+ PDFRectangle pdf_selection(selection->x1, selection->y1,
+ selection->x2, selection->y2);
+
+ GfxColor gfx_background_color = {
+ {
+ background_color->red,
+ background_color->green,
+ background_color->blue
+ }
+ };
+ GfxColor gfx_glyph_color = {
+ {
+ glyph_color->red,
+ glyph_color->green,
+ glyph_color->blue
+ }
+ };
+
+ switch (style)
+ {
+ case POPPLER_SELECTION_GLYPH:
+ selection_style = selectionStyleGlyph;
+ break;
+ case POPPLER_SELECTION_WORD:
+ selection_style = selectionStyleWord;
+ break;
+ case POPPLER_SELECTION_LINE:
+ selection_style = selectionStyleLine;
+ break;
+ }
+
+ output_dev = page->document->output_dev;
+
+ poppler_page_prepare_output_dev (page, scale, rotation, TRUE, &data);
+
+#if defined (HAVE_CAIRO)
+ TextPage *text;
+
+ text = poppler_page_get_text_page (page);
+ text->drawSelection (output_dev, scale, rotation,
+ &pdf_selection, selection_style,
+ &gfx_glyph_color, &gfx_background_color);
+#else
+ TextOutputDev *text_dev;
+
+ text_dev = poppler_page_get_text_output_dev (page);
+ text_dev->drawSelection (output_dev, scale, rotation,
+ &pdf_selection, selection_style,
+ &gfx_glyph_color, &gfx_background_color);
+ /* We'll need a function to destroy page->text_dev and page->gfx
+ * when the application wants to get rid of them.
+ *
+ * Two improvements: 1) make GfxFont refcounted and let TextPage and
+ * friends hold a reference to the GfxFonts they need so we can free
+ * up Gfx early. 2) use a TextPage directly when rendering the page
+ * so we don't have to use TextOutputDev and render a second
+ * time. */
+#endif
+
+ poppler_page_copy_to_pixbuf (page, pixbuf, &data);
+
+ poppler_page_set_selection_alpha (page, scale, pixbuf, style, selection);
+}
+
+#endif /* POPPLER_WITH_GDK */
+
+/**
+ * poppler_page_get_thumbnail_size:
+ * @page: A #PopplerPage
+ * @width: return location for width
+ * @height: return location for height
+ *
+ * Returns %TRUE if @page has a thumbnail associated with it. It also
+ * fills in @width and @height with the width and height of the
+ * thumbnail. The values of width and height are not changed if no
+ * appropriate thumbnail exists.
+ *
+ * Return value: %TRUE, if @page has a thumbnail associated with it.
+ **/
+gboolean
+poppler_page_get_thumbnail_size (PopplerPage *page,
+ int *width,
+ int *height)
+{
+ Object thumb;
+ Dict *dict;
+ gboolean retval = FALSE;
+
+ g_return_val_if_fail (POPPLER_IS_PAGE (page), FALSE);
+ g_return_val_if_fail (width != NULL, FALSE);
+ g_return_val_if_fail (height != NULL, FALSE);
+
+ page->page->getThumb (&thumb);
+ if (!thumb.isStream ())
+ {
+ thumb.free ();
+ return FALSE;
+ }
+
+ dict = thumb.streamGetDict();
+
+ /* Theoretically, this could succeed and you would still fail when
+ * loading the thumb */
+ if (dict->lookupInt ("Width", "W", width) &&
+ dict->lookupInt ("Height", "H", height))
+ retval = TRUE;
+
+ thumb.free ();
+
+ return retval;
+}
+
+/**
+ * poppler_page_get_selection_region:
+ * @page: a #PopplerPage
+ * @scale: scale specified as pixels per point
+ * @style: a #PopplerSelectionStyle
+ * @selection: start and end point of selection as a rectangle
+ *
+ * Returns a region containing the area that would be rendered by
+ * poppler_page_render_selection() or
+ * poppler_page_render_selection_to_pixbuf() as a #GList of
+ * #PopplerRectangle. The returned list must be freed with
+ * poppler_page_selection_region_free().
+ *
+ * Return value: a #GList of #PopplerRectangle
+ **/
+GList *
+poppler_page_get_selection_region (PopplerPage *page,
+ gdouble scale,
+ PopplerSelectionStyle style,
+ PopplerRectangle *selection)
+{
+ PDFRectangle poppler_selection;
+ SelectionStyle selection_style = selectionStyleGlyph;
+ GooList *list;
+ GList *region = NULL;
+ int i;
+
+ poppler_selection.x1 = selection->x1;
+ poppler_selection.y1 = selection->y1;
+ poppler_selection.x2 = selection->x2;
+ poppler_selection.y2 = selection->y2;
+
+ switch (style)
+ {
+ case POPPLER_SELECTION_GLYPH:
+ selection_style = selectionStyleGlyph;
+ break;
+ case POPPLER_SELECTION_WORD:
+ selection_style = selectionStyleWord;
+ break;
+ case POPPLER_SELECTION_LINE:
+ selection_style = selectionStyleLine;
+ break;
+ }
+
+#if defined (HAVE_CAIRO)
+ TextPage *text;
+
+ text = poppler_page_get_text_page (page);
+ list = text->getSelectionRegion(&poppler_selection,
+ selection_style, scale);
+#else
+ TextOutputDev *text_dev;
+
+ text_dev = poppler_page_get_text_output_dev (page);
+ list = text_dev->getSelectionRegion(&poppler_selection,
+ selection_style, scale);
+#endif
+
+ for (i = 0; i < list->getLength(); i++) {
+ PDFRectangle *selection_rect = (PDFRectangle *) list->get(i);
+ PopplerRectangle *rect;
+
+ rect = poppler_rectangle_new ();
+
+ rect->x1 = selection_rect->x1;
+ rect->y1 = selection_rect->y1;
+ rect->x2 = selection_rect->x2;
+ rect->y2 = selection_rect->y2;
+
+ region = g_list_prepend (region, rect);
+
+ delete selection_rect;
+ }
+
+ delete list;
+
+ return g_list_reverse (region);
+}
+
+void
+poppler_page_selection_region_free (GList *region)
+{
+ if (!region)
+ return;
+
+ g_list_foreach (region, (GFunc)poppler_rectangle_free, NULL);
+ g_list_free (region);
+}
+
+/**
+ * poppler_page_get_text:
+ * @page: a #PopplerPage
+ * @style: a #PopplerSelectionStyle
+ * @selection: the #PopplerRectangle including the text
+ *
+ * Retrieves the contents of the specified @selection as text.
+ *
+ * Return value: a pointer to the contents of the @selection
+ * as a string
+ **/
+char *
+poppler_page_get_text (PopplerPage *page,
+ PopplerSelectionStyle style,
+ PopplerRectangle *selection)
+{
+ GooString *sel_text;
+ double height;
+ char *result;
+ SelectionStyle selection_style = selectionStyleGlyph;
+ PDFRectangle pdf_selection;
+
+ g_return_val_if_fail (POPPLER_IS_PAGE (page), FALSE);
+ g_return_val_if_fail (selection != NULL, NULL);
+
+ poppler_page_get_size (page, NULL, &height);
+ pdf_selection.x1 = selection->x1;
+ pdf_selection.y1 = height - selection->y2;
+ pdf_selection.x2 = selection->x2;
+ pdf_selection.y2 = height - selection->y1;
+
+ switch (style)
+ {
+ case POPPLER_SELECTION_GLYPH:
+ selection_style = selectionStyleGlyph;
+ break;
+ case POPPLER_SELECTION_WORD:
+ selection_style = selectionStyleWord;
+ break;
+ case POPPLER_SELECTION_LINE:
+ selection_style = selectionStyleLine;
+ break;
+ }
+
+#if defined (HAVE_CAIRO)
+ TextPage *text;
+
+ text = poppler_page_get_text_page (page);
+ sel_text = text->getSelectionText (&pdf_selection, selection_style);
+#else
+ TextOutputDev *text_dev;
+
+ text_dev = poppler_page_get_text_output_dev (page);
+ sel_text = text_dev->getSelectionText (&pdf_selection, selection_style);
+#endif
+
+ result = g_strdup (sel_text->getCString ());
+ delete sel_text;
+
+ return result;
+}
+
+/**
+ * poppler_page_find_text:
+ * @page: a #PopplerPage
+ * @text: the text to search for (UTF-8 encoded)
+ *
+ * A #GList of rectangles for each occurance of the text on the page.
+ * The coordinates are in PDF points.
+ *
+ * Return value: a #GList of PopplerRectangle,
+ **/
+GList *
+poppler_page_find_text (PopplerPage *page,
+ const char *text)
+{
+ PopplerRectangle *match;
+ GList *matches;
+ double xMin, yMin, xMax, yMax;
+ gunichar *ucs4;
+ glong ucs4_len;
+ double height;
+#if defined (HAVE_CAIRO)
+ TextPage *text_dev;
+#else
+ TextOutputDev *text_dev;
+#endif
+
+ g_return_val_if_fail (POPPLER_IS_PAGE (page), FALSE);
+ g_return_val_if_fail (text != NULL, FALSE);
+
+#if defined (HAVE_CAIRO)
+ text_dev = poppler_page_get_text_page (page);
+#else
+ text_dev = new TextOutputDev (NULL, gTrue, gFalse, gFalse);
+ page->page->display (text_dev, 72, 72, 0,
+ gFalse, gTrue, gFalse,
+ page->document->doc->getCatalog());
+#endif
+
+ ucs4 = g_utf8_to_ucs4_fast (text, -1, &ucs4_len);
+ poppler_page_get_size (page, NULL, &height);
+
+ matches = NULL;
+ xMin = 0;
+ yMin = 0;
+
+ while (text_dev->findText (ucs4, ucs4_len,
+ gFalse, gTrue, // startAtTop, stopAtBottom
+ gTrue, gFalse, // startAtLast, stopAtLast
+ gFalse, gFalse, // caseSensitive, backwards
+ &xMin, &yMin, &xMax, &yMax))
+ {
+ match = g_new (PopplerRectangle, 1);
+ match->x1 = xMin;
+ match->y1 = height - yMax;
+ match->x2 = xMax;
+ match->y2 = height - yMin;
+ matches = g_list_prepend (matches, match);
+ }
+
+#if !defined (HAVE_CAIRO)
+ delete text_dev;
+#endif
+
+ g_free (ucs4);
+
+ return g_list_reverse (matches);
+}
+
+#if defined (HAVE_CAIRO)
+
+static CairoImageOutputDev *
+poppler_page_get_image_output_dev (PopplerPage *page,
+ GBool (*imgDrawDeviceCbk)(int img_id, void *data),
+ void *imgDrawCbkData)
+{
+ CairoImageOutputDev *image_dev;
+ Gfx *gfx;
+
+ image_dev = new CairoImageOutputDev ();
+
+ if (imgDrawDeviceCbk) {
+ image_dev->setImageDrawDecideCbk (imgDrawDeviceCbk,
+ imgDrawCbkData);
+ }
+
+ gfx = page->page->createGfx(image_dev,
+ 72.0, 72.0, 0,
+ gFalse, /* useMediaBox */
+ gTrue, /* Crop */
+ -1, -1, -1, -1,
+ gFalse, /* printing */
+ page->document->doc->getCatalog (),
+ NULL, NULL, NULL, NULL);
+ page->page->display(gfx);
+ delete gfx;
+
+ return image_dev;
+}
+
+/**
+ * poppler_page_get_image_mapping:
+ * @page: A #PopplerPage
+ *
+ * Returns a list of #PopplerImageMapping items that map from a
+ * location on @page to an image of the page. This list must be freed
+ * with poppler_page_free_image_mapping() when done.
+ *
+ * Return value: A #GList of #PopplerImageMapping
+ **/
+GList *
+poppler_page_get_image_mapping (PopplerPage *page)
+{
+ GList *map_list = NULL;
+ CairoImageOutputDev *out;
+ gint i;
+
+ g_return_val_if_fail (POPPLER_IS_PAGE (page), NULL);
+
+ out = poppler_page_get_image_output_dev (page, NULL, NULL);
+
+ for (i = 0; i < out->getNumImages (); i++) {
+ PopplerImageMapping *mapping;
+ CairoImage *image;
+
+ image = out->getImage (i);
+
+ /* Create the mapping */
+ mapping = g_new (PopplerImageMapping, 1);
+
+ image->getRect (&(mapping->area.x1), &(mapping->area.y1),
+ &(mapping->area.x2), &(mapping->area.y2));
+ mapping->image_id = i;
+
+ mapping->area.x1 -= page->page->getCropBox()->x1;
+ mapping->area.x2 -= page->page->getCropBox()->x1;
+ mapping->area.y1 -= page->page->getCropBox()->y1;
+ mapping->area.y2 -= page->page->getCropBox()->y1;
+
+ map_list = g_list_prepend (map_list, mapping);
+ }
+
+ delete out;
+
+ return map_list;
+}
+
+static GBool
+image_draw_decide_cb (int image_id, void *data)
+{
+ return (image_id == GPOINTER_TO_INT (data));
+}
+
+/**
+ * poppler_page_get_image:
+ * @page: A #PopplerPage
+ * @image_id: The image identificator
+ *
+ * Returns a cairo surface for the image of the @page
+ *
+ * Return value: A cairo surface for the image
+ **/
+cairo_surface_t *
+poppler_page_get_image (PopplerPage *page,
+ gint image_id)
+{
+ CairoImageOutputDev *out;
+ cairo_surface_t *image;
+
+ g_return_val_if_fail (POPPLER_IS_PAGE (page), NULL);
+
+ out = poppler_page_get_image_output_dev (page,
+ image_draw_decide_cb,
+ GINT_TO_POINTER (image_id));
+
+ if (image_id >= out->getNumImages ()) {
+ delete out;
+
+ return NULL;
+ }
+
+ image = out->getImage (image_id)->getImage ();
+ if (!image) {
+ delete out;
+
+ return NULL;
+ }
+
+ cairo_surface_reference (image);
+ delete out;
+
+ return image;
+}
+
+/**
+ * poppler_page_free_image_mapping:
+ * @list: A list of #PopplerImageMapping<!-- -->s
+ *
+ * Frees a list of #PopplerImageMapping<!-- -->s allocated by
+ * poppler_page_get_image_mapping().
+ **/
+void
+poppler_page_free_image_mapping (GList *list)
+{
+ if (list == NULL)
+ return;
+
+ g_list_foreach (list, (GFunc)g_free, NULL);
+ g_list_free (list);
+}
+
+#else /* HAVE_CAIRO */
+
+GList *
+poppler_page_get_image_mapping (PopplerPage *page)
+{
+ return NULL;
+}
+
+void
+poppler_page_free_image_mapping (GList *list)
+{
+}
+
+#endif /* HAVE_CAIRO */
+
+/**
+ * poppler_page_render_to_ps:
+ * @page: a #PopplerPage
+ * @ps_file: the PopplerPSFile to render to
+ *
+ * Render the page on a postscript file
+ *
+ **/
+void
+poppler_page_render_to_ps (PopplerPage *page,
+ PopplerPSFile *ps_file)
+{
+ g_return_if_fail (POPPLER_IS_PAGE (page));
+ g_return_if_fail (ps_file != NULL);
+
+ if (!ps_file->out)
+ ps_file->out = new PSOutputDev (ps_file->filename,
+ ps_file->document->doc->getXRef(),
+ ps_file->document->doc->getCatalog(),
+ NULL,
+ ps_file->first_page, ps_file->last_page,
+ psModePS, (int)ps_file->paper_width,
+ (int)ps_file->paper_height, ps_file->duplex,
+ 0, 0, 0, 0, gFalse, gFalse);
+
+
+ ps_file->document->doc->displayPage (ps_file->out, page->index + 1, 72.0, 72.0,
+ 0, gFalse, gTrue, gFalse);
+}
+
+static void
+poppler_page_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ PopplerPage *page = POPPLER_PAGE (object);
+ GooString label;
+
+ switch (prop_id)
+ {
+ case PROP_LABEL:
+ page->document->doc->getCatalog ()->indexToLabel (page->index, &label);
+ g_value_take_string (value, _poppler_goo_string_to_utf8(&label));
+ break;
+ }
+}
+
+static void
+poppler_page_class_init (PopplerPageClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GParamSpec *pspec;
+
+ gobject_class->finalize = poppler_page_finalize;
+ gobject_class->get_property = poppler_page_get_property;
+
+ pspec = g_param_spec_string ("label",
+ "Page Label",
+ "The label of the page",
+ NULL,
+ G_PARAM_READABLE);
+ g_object_class_install_property (G_OBJECT_CLASS (klass),
+ PROP_LABEL,
+ pspec);
+}
+
+static void
+poppler_page_init (PopplerPage *page)
+{
+}
+
+/**
+ * poppler_page_get_link_mapping:
+ * @page: A #PopplerPage
+ *
+ * Returns a list of #PopplerLinkMapping items that map from a
+ * location on @page to a #PopplerAction. This list must be freed
+ * with poppler_page_free_link_mapping() when done.
+ *
+ * Return value: A #GList of #PopplerLinkMapping
+ **/
+GList *
+poppler_page_get_link_mapping (PopplerPage *page)
+{
+ GList *map_list = NULL;
+ gint i;
+ Links *links;
+ Object obj;
+ double width, height;
+
+ g_return_val_if_fail (POPPLER_IS_PAGE (page), NULL);
+
+ links = new Links (page->page->getAnnots (&obj),
+ page->document->doc->getCatalog ()->getBaseURI ());
+ obj.free ();
+
+ if (links == NULL)
+ return NULL;
+
+ poppler_page_get_size (page, &width, &height);
+
+ for (i = 0; i < links->getNumLinks (); i++)
+ {
+ PopplerLinkMapping *mapping;
+ PopplerRectangle rect;
+ LinkAction *link_action;
+ Link *link;
+
+ link = links->getLink (i);
+ link_action = link->getAction ();
+
+ /* Create the mapping */
+ mapping = g_new (PopplerLinkMapping, 1);
+ mapping->action = _poppler_action_new (page->document, link_action, NULL);
+
+ link->getRect (&rect.x1, &rect.y1, &rect.x2, &rect.y2);
+
+ switch (page->page->getRotate ())
+ {
+ case 90:
+ mapping->area.x1 = rect.y1;
+ mapping->area.y1 = height - rect.x2;
+ mapping->area.x2 = mapping->area.x1 + (rect.y2 - rect.y1);
+ mapping->area.y2 = mapping->area.y1 + (rect.x2 - rect.x1);
+
+ break;
+ case 180:
+ mapping->area.x1 = width - rect.x2;
+ mapping->area.y1 = height - rect.y2;
+ mapping->area.x2 = mapping->area.x1 + (rect.x2 - rect.x1);
+ mapping->area.y2 = mapping->area.y1 + (rect.y2 - rect.y1);
+
+ break;
+ case 270:
+ mapping->area.x1 = width - rect.y2;
+ mapping->area.y1 = rect.x1;
+ mapping->area.x2 = mapping->area.x1 + (rect.y2 - rect.y1);
+ mapping->area.y2 = mapping->area.y1 + (rect.x2 - rect.x1);
+
+ break;
+ default:
+ mapping->area.x1 = rect.x1;
+ mapping->area.y1 = rect.y1;
+ mapping->area.x2 = rect.x2;
+ mapping->area.y2 = rect.y2;
+ }
+
+ mapping->area.x1 -= page->page->getCropBox()->x1;
+ mapping->area.x2 -= page->page->getCropBox()->x1;
+ mapping->area.y1 -= page->page->getCropBox()->y1;
+ mapping->area.y2 -= page->page->getCropBox()->y1;
+
+ map_list = g_list_prepend (map_list, mapping);
+ }
+
+ delete links;
+
+ return map_list;
+}
+
+static void
+poppler_mapping_free (PopplerLinkMapping *mapping)
+{
+ poppler_action_free (mapping->action);
+ g_free (mapping);
+}
+
+/**
+ * poppler_page_free_link_mapping:
+ * @list: A list of #PopplerLinkMapping<!-- -->s
+ *
+ * Frees a list of #PopplerLinkMapping<!-- -->s allocated by
+ * poppler_page_get_link_mapping(). It also frees the #PopplerAction<!-- -->s
+ * that each mapping contains, so if you want to keep them around, you need to
+ * copy them with poppler_action_copy().
+ **/
+void
+poppler_page_free_link_mapping (GList *list)
+{
+ if (list == NULL)
+ return;
+
+ g_list_foreach (list, (GFunc) (poppler_mapping_free), NULL);
+ g_list_free (list);
+}
+
+/**
+ * poppler_page_get_form_field_mapping:
+ * @page: A #PopplerPage
+ *
+ * Returns a list of #PopplerFormFieldMapping items that map from a
+ * location on @page to a form field. This list must be freed
+ * with poppler_page_free_form_field_mapping() when done.
+ *
+ * Return value: A #GList of #PopplerFormFieldMapping
+ **/
+GList *
+poppler_page_get_form_field_mapping (PopplerPage *page)
+{
+ GList *map_list = NULL;
+ FormPageWidgets *forms;
+ gint i;
+
+ g_return_val_if_fail (POPPLER_IS_PAGE (page), NULL);
+
+ forms = page->page->getPageWidgets ();
+ if (forms == NULL)
+ return NULL;
+
+ for (i = 0; i < forms->getNumWidgets (); i++) {
+ PopplerFormFieldMapping *mapping;
+ FormWidget *field;
+
+ mapping = poppler_form_field_mapping_new ();
+
+ field = forms->getWidget (i);
+
+ mapping->field = _poppler_form_field_new (page->document, field);
+ field->getRect (&(mapping->area.x1), &(mapping->area.y1),
+ &(mapping->area.x2), &(mapping->area.y2));
+
+ mapping->area.x1 -= page->page->getCropBox()->x1;
+ mapping->area.x2 -= page->page->getCropBox()->x1;
+ mapping->area.y1 -= page->page->getCropBox()->y1;
+ mapping->area.y2 -= page->page->getCropBox()->y1;
+
+ map_list = g_list_prepend (map_list, mapping);
+ }
+
+ return map_list;
+}
+
+/**
+ * poppler_page_free_form_field_mapping:
+ * @list: A list of #PopplerFormFieldMapping<!-- -->s
+ *
+ * Frees a list of #PopplerFormFieldMapping<!-- -->s allocated by
+ * poppler_page_get_form_field_mapping().
+ **/
+void
+poppler_page_free_form_field_mapping (GList *list)
+{
+ if (list == NULL)
+ return;
+
+ g_list_foreach (list, (GFunc) poppler_form_field_mapping_free, NULL);
+ g_list_free (list);
+}
+
+/**
+ * poppler_page_get_annot_mapping:
+ * @page: A #PopplerPage
+ *
+ * Returns a list of #PopplerAnnotMapping items that map from a location on
+ * @page to a #PopplerAnnot. This list must be freed with
+ * poppler_page_free_annot_mapping() when done.
+ *
+ * Return value: A #GList of #PopplerAnnotMapping
+ **/
+GList *
+poppler_page_get_annot_mapping (PopplerPage *page)
+{
+ GList *map_list = NULL;
+ double width, height;
+ gint i;
+
+ g_return_val_if_fail (POPPLER_IS_PAGE (page), NULL);
+
+ if (!page->annots)
+ page->annots = page->page->getAnnots (page->document->doc->getCatalog ());
+
+ if (!page->annots)
+ return NULL;
+
+ poppler_page_get_size (page, &width, &height);
+
+ for (i = 0; i < page->annots->getNumAnnots (); i++) {
+ PopplerAnnotMapping *mapping;
+ PopplerRectangle rect;
+ Annot *annot;
+ PDFRectangle *annot_rect;
+ gint rotation = 0;
+
+ annot = page->annots->getAnnot (i);
+
+ /* Create the mapping */
+ mapping = poppler_annot_mapping_new ();
+
+ switch (annot->getType ())
+ {
+ case Annot::typeText:
+ mapping->annot = _poppler_annot_text_new (annot);
+ break;
+ case Annot::typeFreeText:
+ mapping->annot = _poppler_annot_free_text_new (annot);
+ break;
+ default:
+ mapping->annot = _poppler_annot_new (annot);
+ break;
+ }
+
+ annot_rect = annot->getRect ();
+ rect.x1 = annot_rect->x1;
+ rect.y1 = annot_rect->y1;
+ rect.x2 = annot_rect->x2;
+ rect.y2 = annot_rect->y2;
+
+ if (! (annot->getFlags () & Annot::flagNoRotate))
+ rotation = page->page->getRotate ();
+
+ switch (rotation)
+ {
+ case 90:
+ mapping->area.x1 = rect.y1;
+ mapping->area.y1 = height - rect.x2;
+ mapping->area.x2 = mapping->area.x1 + (rect.y2 - rect.y1);
+ mapping->area.y2 = mapping->area.y1 + (rect.x2 - rect.x1);
+ break;
+ case 180:
+ mapping->area.x1 = width - rect.x2;
+ mapping->area.y1 = height - rect.y2;
+ mapping->area.x2 = mapping->area.x1 + (rect.x2 - rect.x1);
+ mapping->area.y2 = mapping->area.y1 + (rect.y2 - rect.y1);
+ break;
+ case 270:
+ mapping->area.x1 = width - rect.y2;
+ mapping->area.y1 = rect.x1;
+ mapping->area.x2 = mapping->area.x1 + (rect.y2 - rect.y1);
+ mapping->area.y2 = mapping->area.y1 + (rect.x2 - rect.x1);
+ break;
+ default:
+ mapping->area.x1 = rect.x1;
+ mapping->area.y1 = rect.y1;
+ mapping->area.x2 = rect.x2;
+ mapping->area.y2 = rect.y2;
+ }
+
+ mapping->area.x1 -= page->page->getCropBox()->x1;
+ mapping->area.x2 -= page->page->getCropBox()->x1;
+ mapping->area.y1 -= page->page->getCropBox()->y1;
+ mapping->area.y2 -= page->page->getCropBox()->y1;
+
+ map_list = g_list_prepend (map_list, mapping);
+ }
+
+ return g_list_reverse (map_list);
+}
+
+/**
+ * poppler_page_free_annot_mapping:
+ * @list: A list of #PopplerAnnotMapping<!-- -->s
+ *
+ * Frees a list of #PopplerAnnotMapping<!-- -->s allocated by
+ * poppler_page_get_annot_mapping(). It also frees the #PopplerAnnot<!-- -->s
+ * that each mapping contains, so if you want to keep them around, you need to
+ * copy them with poppler_annot_copy().
+ **/
+void
+poppler_page_free_annot_mapping (GList *list)
+{
+ if (!list)
+ return;
+
+ g_list_foreach (list, (GFunc)poppler_annot_mapping_free, NULL);
+ g_list_free (list);
+}
+
+/* PopplerRectangle type */
+
+POPPLER_DEFINE_BOXED_TYPE (PopplerRectangle, poppler_rectangle,
+ poppler_rectangle_copy,
+ poppler_rectangle_free)
+
+PopplerRectangle *
+poppler_rectangle_new (void)
+{
+ return g_new0 (PopplerRectangle, 1);
+}
+
+PopplerRectangle *
+poppler_rectangle_copy (PopplerRectangle *rectangle)
+{
+ PopplerRectangle *new_rectangle;
+
+ g_return_val_if_fail (rectangle != NULL, NULL);
+
+ new_rectangle = g_new (PopplerRectangle, 1);
+ *new_rectangle = *rectangle;
+
+ return new_rectangle;
+}
+
+void
+poppler_rectangle_free (PopplerRectangle *rectangle)
+{
+ g_free (rectangle);
+}
+
+/* PopplerColor type */
+POPPLER_DEFINE_BOXED_TYPE (PopplerColor, poppler_color, poppler_color_copy, poppler_color_free)
+
+PopplerColor *
+poppler_color_new (void)
+{
+ return (PopplerColor *) g_new0 (PopplerColor, 1);
+}
+
+PopplerColor *
+poppler_color_copy (PopplerColor *color)
+{
+ PopplerColor *new_color;
+
+ new_color = g_new (PopplerColor, 1);
+ *new_color = *color;
+
+ return new_color;
+}
+
+void
+poppler_color_free (PopplerColor *color)
+{
+ g_free (color);
+}
+
+/* PopplerLinkMapping type */
+POPPLER_DEFINE_BOXED_TYPE (PopplerLinkMapping, poppler_link_mapping,
+ poppler_link_mapping_copy,
+ poppler_link_mapping_free)
+
+PopplerLinkMapping *
+poppler_link_mapping_new (void)
+{
+ return (PopplerLinkMapping *) g_new0 (PopplerLinkMapping, 1);
+}
+
+PopplerLinkMapping *
+poppler_link_mapping_copy (PopplerLinkMapping *mapping)
+{
+ PopplerLinkMapping *new_mapping;
+
+ new_mapping = poppler_link_mapping_new ();
+
+ *new_mapping = *mapping;
+ if (new_mapping->action)
+ new_mapping->action = poppler_action_copy (new_mapping->action);
+
+ return new_mapping;
+}
+
+void
+poppler_link_mapping_free (PopplerLinkMapping *mapping)
+{
+ if (mapping->action)
+ poppler_action_free (mapping->action);
+
+ g_free (mapping);
+}
+
+/* Poppler Image mapping type */
+POPPLER_DEFINE_BOXED_TYPE (PopplerImageMapping, poppler_image_mapping,
+ poppler_image_mapping_copy,
+ poppler_image_mapping_free)
+
+PopplerImageMapping *
+poppler_image_mapping_new (void)
+{
+ return (PopplerImageMapping *) g_new0 (PopplerImageMapping, 1);
+}
+
+PopplerImageMapping *
+poppler_image_mapping_copy (PopplerImageMapping *mapping)
+{
+ PopplerImageMapping *new_mapping;
+
+ new_mapping = poppler_image_mapping_new ();
+
+ *new_mapping = *mapping;
+
+ return new_mapping;
+}
+
+void
+poppler_image_mapping_free (PopplerImageMapping *mapping)
+{
+ g_free (mapping);
+}
+
+/* Page Transition */
+POPPLER_DEFINE_BOXED_TYPE (PopplerPageTransition, poppler_page_transition,
+ poppler_page_transition_copy,
+ poppler_page_transition_free)
+
+PopplerPageTransition *
+poppler_page_transition_new (void)
+{
+ return (PopplerPageTransition *) g_new0 (PopplerPageTransition, 1);
+}
+
+PopplerPageTransition *
+poppler_page_transition_copy (PopplerPageTransition *transition)
+{
+ PopplerPageTransition *new_transition;
+
+ new_transition = poppler_page_transition_new ();
+ *new_transition = *transition;
+
+ return new_transition;
+}
+
+void
+poppler_page_transition_free (PopplerPageTransition *transition)
+{
+ g_free (transition);
+}
+
+/* Form Field Mapping Type */
+POPPLER_DEFINE_BOXED_TYPE (PopplerFormFieldMapping, poppler_form_field_mapping,
+ poppler_form_field_mapping_copy,
+ poppler_form_field_mapping_free)
+
+PopplerFormFieldMapping *
+poppler_form_field_mapping_new (void)
+{
+ return (PopplerFormFieldMapping *) g_new0 (PopplerFormFieldMapping, 1);
+}
+
+PopplerFormFieldMapping *
+poppler_form_field_mapping_copy (PopplerFormFieldMapping *mapping)
+{
+ PopplerFormFieldMapping *new_mapping;
+
+ new_mapping = poppler_form_field_mapping_new ();
+ *new_mapping = *mapping;
+
+ if (mapping->field)
+ new_mapping->field = (PopplerFormField *)g_object_ref (mapping->field);
+
+ return new_mapping;
+}
+
+void
+poppler_form_field_mapping_free (PopplerFormFieldMapping *mapping)
+{
+ if (!mapping)
+ return;
+
+ if (mapping->field)
+ g_object_unref (mapping->field);
+
+ g_free (mapping);
+}
+
+/* PopplerAnnot Mapping Type */
+POPPLER_DEFINE_BOXED_TYPE (PopplerAnnotMapping, poppler_annot_mapping,
+ poppler_annot_mapping_copy,
+ poppler_annot_mapping_free)
+
+PopplerAnnotMapping *
+poppler_annot_mapping_new (void)
+{
+ return (PopplerAnnotMapping *) g_new0 (PopplerAnnotMapping, 1);
+}
+
+PopplerAnnotMapping *
+poppler_annot_mapping_copy (PopplerAnnotMapping *mapping)
+{
+ PopplerAnnotMapping *new_mapping;
+
+ new_mapping = poppler_annot_mapping_new ();
+
+ *new_mapping = *mapping;
+ if (mapping->annot)
+ new_mapping->annot = (PopplerAnnot *) g_object_ref (mapping->annot);
+
+ return new_mapping;
+}
+
+void
+poppler_annot_mapping_free (PopplerAnnotMapping *mapping)
+{
+ if (!mapping)
+ return;
+
+ if (mapping->annot)
+ g_object_unref (mapping->annot);
+
+ g_free (mapping);
+}
+
+void
+poppler_page_get_crop_box (PopplerPage *page, PopplerRectangle *rect)
+{
+ PDFRectangle* cropBox = page->page->getCropBox ();
+
+ rect->x1 = cropBox->x1;
+ rect->x2 = cropBox->x2;
+ rect->y1 = cropBox->y1;
+ rect->y2 = cropBox->y2;
+}
+