1 /* poppler-page.cc: glib wrapper for poppler
2 * Copyright (C) 2005, Red Hat, Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 #include "config.h"
20 #include <math.h>
21
22 #ifndef __GI_SCANNER__
23 #include <goo/GooList.h>
24 #include <GlobalParams.h>
25 #include <PDFDoc.h>
26 #include <Outline.h>
27 #include <ErrorCodes.h>
28 #include <UnicodeMap.h>
29 #include <GfxState.h>
30 #include <PageTransition.h>
31 #endif
32
33 #include "poppler.h"
34 #include "poppler-private.h"
35
36 /**
37 * SECTION:poppler-page
38 * @short_description: Information about a page in a document
39 * @title: PopplerPage
40 */
41
42 enum
43 {
44 PROP_0,
45 PROP_LABEL
46 };
47
48 typedef struct _PopplerPageClass PopplerPageClass;
49 struct _PopplerPageClass
50 {
51 GObjectClass parent_class;
52 };
53
G_DEFINE_TYPE(PopplerPage,poppler_page,G_TYPE_OBJECT)54 G_DEFINE_TYPE (PopplerPage, poppler_page, G_TYPE_OBJECT)
55
56 PopplerPage *
57 _poppler_page_new (PopplerDocument *document, Page *page, int index)
58 {
59 PopplerPage *poppler_page;
60
61 g_return_val_if_fail (POPPLER_IS_DOCUMENT (document), NULL);
62
63 poppler_page = (PopplerPage *) g_object_new (POPPLER_TYPE_PAGE, NULL, NULL);
64 poppler_page->document = (PopplerDocument *) g_object_ref (document);
65 poppler_page->page = page;
66 poppler_page->index = index;
67
68 return poppler_page;
69 }
70
71 static void
poppler_page_finalize(GObject * object)72 poppler_page_finalize (GObject *object)
73 {
74 PopplerPage *page = POPPLER_PAGE (object);
75
76 g_object_unref (page->document);
77 page->document = NULL;
78
79 if (page->annots != NULL)
80 delete page->annots;
81 if (page->text != NULL)
82 page->text->decRefCnt();
83 /* page->page is owned by the document */
84 }
85
86 /**
87 * poppler_page_get_size:
88 * @page: A #PopplerPage
89 * @width: (out) (allow-none): return location for the width of @page
90 * @height: (out) (allow-none): return location for the height of @page
91 *
92 * Gets the size of @page at the current scale and rotation.
93 **/
94 void
poppler_page_get_size(PopplerPage * page,double * width,double * height)95 poppler_page_get_size (PopplerPage *page,
96 double *width,
97 double *height)
98 {
99 double page_width, page_height;
100 int rotate;
101
102 g_return_if_fail (POPPLER_IS_PAGE (page));
103
104 rotate = page->page->getRotate ();
105 if (rotate == 90 || rotate == 270) {
106 page_height = page->page->getCropWidth ();
107 page_width = page->page->getCropHeight ();
108 } else {
109 page_width = page->page->getCropWidth ();
110 page_height = page->page->getCropHeight ();
111 }
112
113 if (width != NULL)
114 *width = page_width;
115 if (height != NULL)
116 *height = page_height;
117 }
118
119 /**
120 * poppler_page_get_index:
121 * @page: a #PopplerPage
122 *
123 * Returns the index of @page
124 *
125 * Return value: index value of @page
126 **/
127 int
poppler_page_get_index(PopplerPage * page)128 poppler_page_get_index (PopplerPage *page)
129 {
130 g_return_val_if_fail (POPPLER_IS_PAGE (page), 0);
131
132 return page->index;
133 }
134
135 /**
136 * poppler_page_get_label:
137 * @page: a #PopplerPage
138 *
139 * Returns the label of @page. Note that page labels
140 * and page indices might not coincide.
141 *
142 * Return value: a new allocated string containing the label of @page,
143 * or %NULL if @page doesn't have a label
144 *
145 * Since: 0.16
146 **/
147 gchar *
poppler_page_get_label(PopplerPage * page)148 poppler_page_get_label (PopplerPage *page)
149 {
150 GooString label;
151
152 g_return_val_if_fail (POPPLER_IS_PAGE (page), NULL);
153
154 page->document->doc->getCatalog ()->indexToLabel (page->index, &label);
155 return _poppler_goo_string_to_utf8 (&label);
156 }
157
158 /**
159 * poppler_page_get_duration:
160 * @page: a #PopplerPage
161 *
162 * Returns the duration of @page
163 *
164 * Return value: duration in seconds of @page or -1.
165 **/
166 double
poppler_page_get_duration(PopplerPage * page)167 poppler_page_get_duration (PopplerPage *page)
168 {
169 g_return_val_if_fail (POPPLER_IS_PAGE (page), -1);
170
171 return page->page->getDuration ();
172 }
173
174 /**
175 * poppler_page_get_transition:
176 * @page: a #PopplerPage
177 *
178 * Returns the transition effect of @page
179 *
180 * Return value: a #PopplerPageTransition or NULL.
181 **/
182 PopplerPageTransition *
poppler_page_get_transition(PopplerPage * page)183 poppler_page_get_transition (PopplerPage *page)
184 {
185 PageTransition *trans;
186 PopplerPageTransition *transition;
187 Object obj;
188
189 g_return_val_if_fail (POPPLER_IS_PAGE (page), NULL);
190
191 trans = new PageTransition (page->page->getTrans (&obj));
192 obj.free ();
193
194 if (!trans->isOk ()) {
195 delete trans;
196 return NULL;
197 }
198
199 transition = poppler_page_transition_new ();
200
201 switch (trans->getType ())
202 {
203 case transitionReplace:
204 transition->type = POPPLER_PAGE_TRANSITION_REPLACE;
205 break;
206 case transitionSplit:
207 transition->type = POPPLER_PAGE_TRANSITION_SPLIT;
208 break;
209 case transitionBlinds:
210 transition->type = POPPLER_PAGE_TRANSITION_BLINDS;
211 break;
212 case transitionBox:
213 transition->type = POPPLER_PAGE_TRANSITION_BOX;
214 break;
215 case transitionWipe:
216 transition->type = POPPLER_PAGE_TRANSITION_WIPE;
217 break;
218 case transitionDissolve:
219 transition->type = POPPLER_PAGE_TRANSITION_DISSOLVE;
220 break;
221 case transitionGlitter:
222 transition->type = POPPLER_PAGE_TRANSITION_GLITTER;
223 break;
224 case transitionFly:
225 transition->type = POPPLER_PAGE_TRANSITION_FLY;
226 break;
227 case transitionPush:
228 transition->type = POPPLER_PAGE_TRANSITION_PUSH;
229 break;
230 case transitionCover:
231 transition->type = POPPLER_PAGE_TRANSITION_COVER;
232 break;
233 case transitionUncover:
234 transition->type = POPPLER_PAGE_TRANSITION_UNCOVER;
235 break;
236 case transitionFade:
237 transition->type = POPPLER_PAGE_TRANSITION_FADE;
238 break;
239 default:
240 g_assert_not_reached ();
241 }
242
243 transition->alignment = (trans->getAlignment() == transitionHorizontal) ?
244 POPPLER_PAGE_TRANSITION_HORIZONTAL :
245 POPPLER_PAGE_TRANSITION_VERTICAL;
246
247 transition->direction = (trans->getDirection() == transitionInward) ?
248 POPPLER_PAGE_TRANSITION_INWARD :
249 POPPLER_PAGE_TRANSITION_OUTWARD;
250
251 transition->duration = trans->getDuration();
252 transition->angle = trans->getAngle();
253 transition->scale = trans->getScale();
254 transition->rectangular = trans->isRectangular();
255
256 delete trans;
257
258 return transition;
259 }
260
261 static TextPage *
poppler_page_get_text_page(PopplerPage * page)262 poppler_page_get_text_page (PopplerPage *page)
263 {
264 if (page->text == NULL) {
265 TextOutputDev *text_dev;
266 Gfx *gfx;
267
268 text_dev = new TextOutputDev (NULL, gTrue, gFalse, gFalse);
269 gfx = page->page->createGfx(text_dev,
270 72.0, 72.0, 0,
271 gFalse, /* useMediaBox */
272 gTrue, /* Crop */
273 -1, -1, -1, -1,
274 gFalse, /* printing */
275 page->document->doc->getCatalog (),
276 NULL, NULL, NULL, NULL);
277 page->page->display(gfx);
278 text_dev->endPage();
279
280 page->text = text_dev->takeText();
281 delete gfx;
282 delete text_dev;
283 }
284
285 return page->text;
286 }
287
288 #ifdef POPPLER_WITH_GDK
289 static void
copy_cairo_surface_to_pixbuf(cairo_surface_t * surface,GdkPixbuf * pixbuf)290 copy_cairo_surface_to_pixbuf (cairo_surface_t *surface,
291 GdkPixbuf *pixbuf)
292 {
293 int cairo_width, cairo_height, cairo_rowstride;
294 unsigned char *pixbuf_data, *dst, *cairo_data;
295 int pixbuf_rowstride, pixbuf_n_channels;
296 unsigned int *src;
297 int x, y;
298
299 cairo_width = cairo_image_surface_get_width (surface);
300 cairo_height = cairo_image_surface_get_height (surface);
301 cairo_rowstride = cairo_image_surface_get_stride (surface);
302 cairo_data = cairo_image_surface_get_data (surface);
303
304 pixbuf_data = gdk_pixbuf_get_pixels (pixbuf);
305 pixbuf_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
306 pixbuf_n_channels = gdk_pixbuf_get_n_channels (pixbuf);
307
308 if (cairo_width > gdk_pixbuf_get_width (pixbuf))
309 cairo_width = gdk_pixbuf_get_width (pixbuf);
310 if (cairo_height > gdk_pixbuf_get_height (pixbuf))
311 cairo_height = gdk_pixbuf_get_height (pixbuf);
312 for (y = 0; y < cairo_height; y++)
313 {
314 src = (unsigned int *) (cairo_data + y * cairo_rowstride);
315 dst = pixbuf_data + y * pixbuf_rowstride;
316 for (x = 0; x < cairo_width; x++)
317 {
318 dst[0] = (*src >> 16) & 0xff;
319 dst[1] = (*src >> 8) & 0xff;
320 dst[2] = (*src >> 0) & 0xff;
321 if (pixbuf_n_channels == 4)
322 dst[3] = (*src >> 24) & 0xff;
323 dst += pixbuf_n_channels;
324 src++;
325 }
326 }
327 }
328 #endif /* POPPLER_WITH_GDK */
329
330 static gboolean
annot_is_markup(Annot * annot)331 annot_is_markup (Annot *annot)
332 {
333 switch (annot->getType())
334 {
335 case Annot::typeLink:
336 case Annot::typePopup:
337 case Annot::typeMovie:
338 case Annot::typeScreen:
339 case Annot::typePrinterMark:
340 case Annot::typeTrapNet:
341 case Annot::typeWatermark:
342 case Annot::type3D:
343 case Annot::typeWidget:
344 return FALSE;
345 default:
346 return TRUE;
347 }
348 }
349
350 static GBool
poppler_print_annot_cb(Annot * annot,void * user_data)351 poppler_print_annot_cb (Annot *annot, void *user_data)
352 {
353 PopplerPrintFlags user_print_flags = (PopplerPrintFlags)GPOINTER_TO_INT (user_data);
354
355 if (annot->getFlags () & Annot::flagHidden)
356 return gFalse;
357
358 if (user_print_flags & POPPLER_PRINT_STAMP_ANNOTS_ONLY) {
359 return (annot->getType() == Annot::typeStamp) ?
360 (annot->getFlags () & Annot::flagPrint) :
361 (annot->getType() == Annot::typeWidget);
362 }
363
364 if (user_print_flags & POPPLER_PRINT_MARKUP_ANNOTS) {
365 return annot_is_markup (annot) ?
366 (annot->getFlags () & Annot::flagPrint) :
367 (annot->getType() == Annot::typeWidget);
368 }
369
370 /* Print document only, form fields are always printed */
371 return (annot->getType() == Annot::typeWidget);
372 }
373
374 static void
_poppler_page_render(PopplerPage * page,cairo_t * cairo,GBool printing,PopplerPrintFlags print_flags)375 _poppler_page_render (PopplerPage *page,
376 cairo_t *cairo,
377 GBool printing,
378 PopplerPrintFlags print_flags)
379 {
380 CairoOutputDev *output_dev;
381
382 g_return_if_fail (POPPLER_IS_PAGE (page));
383
384 output_dev = page->document->output_dev;
385 output_dev->setCairo (cairo);
386 output_dev->setPrinting (printing);
387
388 if (!printing)
389 output_dev->setTextPage (page->text);
390
391 /* NOTE: instead of passing -1 we should/could use cairo_clip_extents()
392 * to get a bounding box */
393 cairo_save (cairo);
394 page->page->displaySlice(output_dev,
395 72.0, 72.0, 0,
396 gFalse, /* useMediaBox */
397 gTrue, /* Crop */
398 -1, -1,
399 -1, -1,
400 printing,
401 page->document->doc->getCatalog (),
402 NULL, NULL,
403 printing ? poppler_print_annot_cb : NULL,
404 printing ? GINT_TO_POINTER ((gint)print_flags) : NULL);
405 cairo_restore (cairo);
406
407 output_dev->setCairo (NULL);
408 output_dev->setTextPage (NULL);
409 }
410
411 /**
412 * poppler_page_render:
413 * @page: the page to render from
414 * @cairo: cairo context to render to
415 *
416 * Render the page to the given cairo context. This function
417 * is for rendering a page that will be displayed. If you want
418 * to render a page that will be printed use
419 * poppler_page_render_for_printing() instead
420 **/
421 void
poppler_page_render(PopplerPage * page,cairo_t * cairo)422 poppler_page_render (PopplerPage *page,
423 cairo_t *cairo)
424 {
425 g_return_if_fail (POPPLER_IS_PAGE (page));
426
427 if (!page->text)
428 page->text = new TextPage(gFalse);
429
430 _poppler_page_render (page, cairo, gFalse, (PopplerPrintFlags)0);
431 }
432
433 /**
434 * poppler_page_render_for_printing_with_options:
435 * @page: the page to render from
436 * @cairo: cairo context to render to
437 * @options: print options
438 *
439 * Render the page to the given cairo context for printing
440 * with the specified options
441 *
442 * Since: 0.16
443 **/
444 void
poppler_page_render_for_printing_with_options(PopplerPage * page,cairo_t * cairo,PopplerPrintFlags options)445 poppler_page_render_for_printing_with_options (PopplerPage *page,
446 cairo_t *cairo,
447 PopplerPrintFlags options)
448 {
449 g_return_if_fail (POPPLER_IS_PAGE (page));
450
451 _poppler_page_render (page, cairo, gTrue, options);
452 }
453
454 /**
455 * poppler_page_render_for_printing:
456 * @page: the page to render from
457 * @cairo: cairo context to render to
458 *
459 * Render the page to the given cairo context for printing.
460 **/
461 void
poppler_page_render_for_printing(PopplerPage * page,cairo_t * cairo)462 poppler_page_render_for_printing (PopplerPage *page,
463 cairo_t *cairo)
464 {
465 g_return_if_fail (POPPLER_IS_PAGE (page));
466
467 _poppler_page_render (page, cairo, gTrue, POPPLER_PRINT_ALL);
468 }
469
470 static cairo_surface_t *
create_surface_from_thumbnail_data(guchar * data,gint width,gint height,gint rowstride)471 create_surface_from_thumbnail_data (guchar *data,
472 gint width,
473 gint height,
474 gint rowstride)
475 {
476 guchar *cairo_pixels;
477 gint cairo_stride;
478 cairo_surface_t *surface;
479 int j;
480
481 surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
482 if (cairo_surface_status (surface))
483 return NULL;
484
485 cairo_pixels = cairo_image_surface_get_data (surface);
486 cairo_stride = cairo_image_surface_get_stride (surface);
487
488 for (j = height; j; j--) {
489 guchar *p = data;
490 guchar *q = cairo_pixels;
491 guchar *end = p + 3 * width;
492
493 while (p < end) {
494 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
495 q[0] = p[2];
496 q[1] = p[1];
497 q[2] = p[0];
498 #else
499 q[1] = p[0];
500 q[2] = p[1];
501 q[3] = p[2];
502 #endif
503 p += 3;
504 q += 4;
505 }
506
507 data += rowstride;
508 cairo_pixels += cairo_stride;
509 }
510
511 return surface;
512 }
513
514
515 /**
516 * poppler_page_get_thumbnail:
517 * @page: the #PopperPage to get the thumbnail for
518 *
519 * Get the embedded thumbnail for the specified page. If the document
520 * doesn't have an embedded thumbnail for the page, this function
521 * returns %NULL.
522 *
523 * Return value: the tumbnail as a cairo_surface_t or %NULL if the document
524 * doesn't have a thumbnail for this page.
525 **/
526 cairo_surface_t *
poppler_page_get_thumbnail(PopplerPage * page)527 poppler_page_get_thumbnail (PopplerPage *page)
528 {
529 unsigned char *data;
530 int width, height, rowstride;
531 cairo_surface_t *surface;
532
533 g_return_val_if_fail (POPPLER_IS_PAGE (page), NULL);
534
535 if (!page->page->loadThumb (&data, &width, &height, &rowstride))
536 return NULL;
537
538 surface = create_surface_from_thumbnail_data (data, width, height, rowstride);
539 gfree (data);
540
541 return surface;
542 }
543
544 /**
545 * poppler_page_render_selection:
546 * @page: the #PopplerPage for which to render selection
547 * @cairo: cairo context to render to
548 * @selection: start and end point of selection as a rectangle
549 * @old_selection: previous selection
550 * @style: a #PopplerSelectionStyle
551 * @glyph_color: color to use for drawing glyphs
552 * @background_color: color to use for the selection background
553 *
554 * Render the selection specified by @selection for @page to
555 * the given cairo context. The selection will be rendered, using
556 * @glyph_color for the glyphs and @background_color for the selection
557 * background.
558 *
559 * If non-NULL, @old_selection specifies the selection that is already
560 * rendered to @cairo, in which case this function will (some day)
561 * only render the changed part of the selection.
562 **/
563 void
poppler_page_render_selection(PopplerPage * page,cairo_t * cairo,PopplerRectangle * selection,PopplerRectangle * old_selection,PopplerSelectionStyle style,PopplerColor * glyph_color,PopplerColor * background_color)564 poppler_page_render_selection (PopplerPage *page,
565 cairo_t *cairo,
566 PopplerRectangle *selection,
567 PopplerRectangle *old_selection,
568 PopplerSelectionStyle style,
569 PopplerColor *glyph_color,
570 PopplerColor *background_color)
571 {
572 CairoOutputDev *output_dev;
573 TextPage *text;
574 SelectionStyle selection_style = selectionStyleGlyph;
575 PDFRectangle pdf_selection(selection->x1, selection->y1,
576 selection->x2, selection->y2);
577
578 GfxColor gfx_background_color = {
579 {
580 background_color->red,
581 background_color->green,
582 background_color->blue
583 }
584 };
585 GfxColor gfx_glyph_color = {
586 {
587 glyph_color->red,
588 glyph_color->green,
589 glyph_color->blue
590 }
591 };
592
593 switch (style)
594 {
595 case POPPLER_SELECTION_GLYPH:
596 selection_style = selectionStyleGlyph;
597 break;
598 case POPPLER_SELECTION_WORD:
599 selection_style = selectionStyleWord;
600 break;
601 case POPPLER_SELECTION_LINE:
602 selection_style = selectionStyleLine;
603 break;
604 }
605
606 output_dev = page->document->output_dev;
607 output_dev->setCairo (cairo);
608
609 text = poppler_page_get_text_page (page);
610 text->drawSelection (output_dev, 1.0, 0,
611 &pdf_selection, selection_style,
612 &gfx_glyph_color, &gfx_background_color);
613
614 output_dev->setCairo (NULL);
615 }
616
617 #ifdef POPPLER_WITH_GDK
618 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)619 _poppler_page_render_to_pixbuf (PopplerPage *page,
620 int src_x, int src_y,
621 int src_width, int src_height,
622 double scale,
623 int rotation,
624 GBool printing,
625 GdkPixbuf *pixbuf)
626 {
627 cairo_t *cr;
628 cairo_surface_t *surface;
629
630 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
631 src_width, src_height);
632 cr = cairo_create (surface);
633 cairo_save (cr);
634 switch (rotation) {
635 case 90:
636 cairo_translate (cr, src_x + src_width, -src_y);
637 break;
638 case 180:
639 cairo_translate (cr, src_x + src_width, src_y + src_height);
640 break;
641 case 270:
642 cairo_translate (cr, -src_x, src_y + src_height);
643 break;
644 default:
645 cairo_translate (cr, -src_x, -src_y);
646 }
647
648 if (scale != 1.0)
649 cairo_scale (cr, scale, scale);
650
651 if (rotation != 0)
652 cairo_rotate (cr, rotation * G_PI / 180.0);
653
654 if (printing)
655 poppler_page_render_for_printing (page, cr);
656 else
657 poppler_page_render (page, cr);
658 cairo_restore (cr);
659
660 cairo_set_operator (cr, CAIRO_OPERATOR_DEST_OVER);
661 cairo_set_source_rgb (cr, 1., 1., 1.);
662 cairo_paint (cr);
663
664 cairo_destroy (cr);
665
666 copy_cairo_surface_to_pixbuf (surface, pixbuf);
667 cairo_surface_destroy (surface);
668 }
669
670 /**
671 * poppler_page_render_to_pixbuf:
672 * @page: the page to render from
673 * @src_x: x coordinate of upper left corner
674 * @src_y: y coordinate of upper left corner
675 * @src_width: width of rectangle to render
676 * @src_height: height of rectangle to render
677 * @scale: scale specified as pixels per point
678 * @rotation: rotate the document by the specified degree
679 * @pixbuf: pixbuf to render into
680 *
681 * First scale the document to match the specified pixels per point,
682 * then render the rectangle given by the upper left corner at
683 * (src_x, src_y) and src_width and src_height.
684 * This function is for rendering a page that will be displayed.
685 * If you want to render a page that will be printed use
686 * poppler_page_render_to_pixbuf_for_printing() instead
687 *
688 * Deprecated: 0.16
689 **/
690 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)691 poppler_page_render_to_pixbuf (PopplerPage *page,
692 int src_x, int src_y,
693 int src_width, int src_height,
694 double scale,
695 int rotation,
696 GdkPixbuf *pixbuf)
697 {
698 g_return_if_fail (POPPLER_IS_PAGE (page));
699 g_return_if_fail (scale > 0.0);
700 g_return_if_fail (pixbuf != NULL);
701
702 _poppler_page_render_to_pixbuf (page, src_x, src_y,
703 src_width, src_height,
704 scale, rotation,
705 gFalse,
706 pixbuf);
707 }
708
709 /**
710 * poppler_page_render_to_pixbuf_for_printing:
711 * @page: the page to render from
712 * @src_x: x coordinate of upper left corner
713 * @src_y: y coordinate of upper left corner
714 * @src_width: width of rectangle to render
715 * @src_height: height of rectangle to render
716 * @scale: scale specified as pixels per point
717 * @rotation: rotate the document by the specified degree
718 * @pixbuf: pixbuf to render into
719 *
720 * First scale the document to match the specified pixels per point,
721 * then render the rectangle given by the upper left corner at
722 * (src_x, src_y) and src_width and src_height.
723 * This function is for rendering a page that will be printed.
724 *
725 * Deprecated: 0.16
726 **/
727 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)728 poppler_page_render_to_pixbuf_for_printing (PopplerPage *page,
729 int src_x, int src_y,
730 int src_width, int src_height,
731 double scale,
732 int rotation,
733 GdkPixbuf *pixbuf)
734 {
735 g_return_if_fail (POPPLER_IS_PAGE (page));
736 g_return_if_fail (scale > 0.0);
737 g_return_if_fail (pixbuf != NULL);
738
739 _poppler_page_render_to_pixbuf (page, src_x, src_y,
740 src_width, src_height,
741 scale, rotation,
742 gTrue,
743 pixbuf);
744 }
745
746 /**
747 * poppler_page_get_thumbnail_pixbuf:
748 * @page: the #PopperPage to get the thumbnail for
749 *
750 * Get the embedded thumbnail for the specified page. If the document
751 * doesn't have an embedded thumbnail for the page, this function
752 * returns %NULL.
753 *
754 * Return value: the tumbnail as a #GdkPixbuf or %NULL if the document
755 * doesn't have a thumbnail for this page.
756 *
757 * Deprecated: 0.16
758 **/
759 GdkPixbuf *
poppler_page_get_thumbnail_pixbuf(PopplerPage * page)760 poppler_page_get_thumbnail_pixbuf (PopplerPage *page)
761 {
762 unsigned char *data;
763 int width, height, rowstride;
764
765 g_return_val_if_fail (POPPLER_IS_PAGE (page), NULL);
766
767 if (!page->page->loadThumb (&data, &width, &height, &rowstride))
768 return NULL;
769
770 return gdk_pixbuf_new_from_data (data, GDK_COLORSPACE_RGB,
771 FALSE, 8, width, height, rowstride,
772 (GdkPixbufDestroyNotify)gfree, NULL);
773 }
774
775 /**
776 * poppler_page_render_selection_to_pixbuf:
777 * @page: the #PopplerPage for which to render selection
778 * @scale: scale specified as pixels per point
779 * @rotation: rotate the document by the specified degree
780 * @pixbuf: pixbuf to render to
781 * @selection: start and end point of selection as a rectangle
782 * @old_selection: previous selection
783 * @style: a #PopplerSelectionStyle
784 * @glyph_color: color to use for drawing glyphs
785 * @background_color: color to use for the selection background
786 *
787 * Render the selection specified by @selection for @page into
788 * @pixbuf. The selection will be rendered at @scale, using
789 * @glyph_color for the glyphs and @background_color for the selection
790 * background.
791 *
792 * If non-NULL, @old_selection specifies the selection that is already
793 * rendered in @pixbuf, in which case this function will (some day)
794 * only render the changed part of the selection.
795 *
796 * Deprecated: 0.16
797 **/
798 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)799 poppler_page_render_selection_to_pixbuf (PopplerPage *page,
800 gdouble scale,
801 int rotation,
802 GdkPixbuf *pixbuf,
803 PopplerRectangle *selection,
804 PopplerRectangle *old_selection,
805 PopplerSelectionStyle style,
806 GdkColor *glyph_color,
807 GdkColor *background_color)
808 {
809 cairo_t *cr;
810 cairo_surface_t *surface;
811 double width, height;
812 int cairo_width, cairo_height, rotate;
813 PopplerColor poppler_background_color;
814 PopplerColor poppler_glyph_color;
815
816 poppler_background_color.red = background_color->red;
817 poppler_background_color.green = background_color->green;
818 poppler_background_color.blue = background_color->blue;
819 poppler_glyph_color.red = glyph_color->red;
820 poppler_glyph_color.green = glyph_color->green;
821 poppler_glyph_color.blue = glyph_color->blue;
822
823 rotate = rotation + page->page->getRotate ();
824 if (rotate == 90 || rotate == 270) {
825 height = page->page->getCropWidth ();
826 width = page->page->getCropHeight ();
827 } else {
828 width = page->page->getCropWidth ();
829 height = page->page->getCropHeight ();
830 }
831
832 cairo_width = (int) ceil(width * scale);
833 cairo_height = (int) ceil(height * scale);
834
835 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
836 cairo_width, cairo_height);
837 cr = cairo_create (surface);
838 cairo_set_source_rgba (cr, 0, 0, 0, 0);
839 cairo_paint (cr);
840
841 switch (rotate) {
842 case 90:
843 cairo_translate (cr, cairo_width, 0);
844 break;
845 case 180:
846 cairo_translate (cr, cairo_width, cairo_height);
847 break;
848 case 270:
849 cairo_translate (cr, 0, cairo_height);
850 break;
851 default:
852 cairo_translate (cr, 0, 0);
853 }
854 if (scale != 1.0)
855 cairo_scale (cr, scale, scale);
856
857 if (rotate != 0)
858 cairo_rotate (cr, rotation * G_PI / 180.0);
859
860 poppler_page_render_selection (page, cr, selection, old_selection, style,
861 &poppler_glyph_color, &poppler_background_color);
862
863 cairo_destroy (cr);
864
865 copy_cairo_surface_to_pixbuf (surface, pixbuf);
866 cairo_surface_destroy (surface);
867 }
868
869 #endif /* POPPLER_WITH_GDK */
870
871 /**
872 * poppler_page_get_thumbnail_size:
873 * @page: A #PopplerPage
874 * @width: (out) return location for width
875 * @height: (out) return location for height
876 *
877 * Returns %TRUE if @page has a thumbnail associated with it. It also
878 * fills in @width and @height with the width and height of the
879 * thumbnail. The values of width and height are not changed if no
880 * appropriate thumbnail exists.
881 *
882 * Return value: %TRUE, if @page has a thumbnail associated with it.
883 **/
884 gboolean
poppler_page_get_thumbnail_size(PopplerPage * page,int * width,int * height)885 poppler_page_get_thumbnail_size (PopplerPage *page,
886 int *width,
887 int *height)
888 {
889 Object thumb;
890 Dict *dict;
891 gboolean retval = FALSE;
892
893 g_return_val_if_fail (POPPLER_IS_PAGE (page), FALSE);
894 g_return_val_if_fail (width != NULL, FALSE);
895 g_return_val_if_fail (height != NULL, FALSE);
896
897 page->page->getThumb (&thumb);
898 if (!thumb.isStream ())
899 {
900 thumb.free ();
901 return FALSE;
902 }
903
904 dict = thumb.streamGetDict();
905
906 /* Theoretically, this could succeed and you would still fail when
907 * loading the thumb */
908 if (dict->lookupInt ("Width", "W", width) &&
909 dict->lookupInt ("Height", "H", height))
910 retval = TRUE;
911
912 thumb.free ();
913
914 return retval;
915 }
916
917 /**
918 * poppler_page_get_selection_region:
919 * @page: a #PopplerPage
920 * @scale: scale specified as pixels per point
921 * @style: a #PopplerSelectionStyle
922 * @selection: start and end point of selection as a rectangle
923 *
924 * Returns a region containing the area that would be rendered by
925 * poppler_page_render_selection() or
926 * poppler_page_render_selection_to_pixbuf() as a #GList of
927 * #PopplerRectangle. The returned list must be freed with
928 * poppler_page_selection_region_free().
929 *
930 * Return value: (element-type PopplerRectangle) (transfer full): a #GList of #PopplerRectangle
931 *
932 * Deprecated: 0.16: Use poppler_page_get_selected_region() instead.
933 **/
934 GList *
poppler_page_get_selection_region(PopplerPage * page,gdouble scale,PopplerSelectionStyle style,PopplerRectangle * selection)935 poppler_page_get_selection_region (PopplerPage *page,
936 gdouble scale,
937 PopplerSelectionStyle style,
938 PopplerRectangle *selection)
939 {
940 PDFRectangle poppler_selection;
941 TextPage *text;
942 SelectionStyle selection_style = selectionStyleGlyph;
943 GooList *list;
944 GList *region = NULL;
945 int i;
946
947 poppler_selection.x1 = selection->x1;
948 poppler_selection.y1 = selection->y1;
949 poppler_selection.x2 = selection->x2;
950 poppler_selection.y2 = selection->y2;
951
952 switch (style)
953 {
954 case POPPLER_SELECTION_GLYPH:
955 selection_style = selectionStyleGlyph;
956 break;
957 case POPPLER_SELECTION_WORD:
958 selection_style = selectionStyleWord;
959 break;
960 case POPPLER_SELECTION_LINE:
961 selection_style = selectionStyleLine;
962 break;
963 }
964
965 text = poppler_page_get_text_page (page);
966 list = text->getSelectionRegion(&poppler_selection,
967 selection_style, scale);
968
969 for (i = 0; i < list->getLength(); i++) {
970 PDFRectangle *selection_rect = (PDFRectangle *) list->get(i);
971 PopplerRectangle *rect;
972
973 rect = poppler_rectangle_new ();
974
975 rect->x1 = selection_rect->x1;
976 rect->y1 = selection_rect->y1;
977 rect->x2 = selection_rect->x2;
978 rect->y2 = selection_rect->y2;
979
980 region = g_list_prepend (region, rect);
981
982 delete selection_rect;
983 }
984
985 delete list;
986
987 return g_list_reverse (region);
988 }
989
990 /**
991 * poppler_page_selection_region_free:
992 * @region: a #GList of #PopplerRectangle
993 *
994 * Frees @region
995 *
996 * Deprecated: 0.16
997 */
998 void
poppler_page_selection_region_free(GList * region)999 poppler_page_selection_region_free (GList *region)
1000 {
1001 if (G_UNLIKELY (!region))
1002 return;
1003
1004 g_list_foreach (region, (GFunc)poppler_rectangle_free, NULL);
1005 g_list_free (region);
1006 }
1007
1008 /**
1009 * poppler_page_get_selected_region:
1010 * @page: a #PopplerPage
1011 * @scale: scale specified as pixels per point
1012 * @style: a #PopplerSelectionStyle
1013 * @selection: start and end point of selection as a rectangle
1014 *
1015 * Returns a region containing the area that would be rendered by
1016 * poppler_page_render_selection() or
1017 * poppler_page_render_selection_to_pixbuf().
1018 * The returned region must be freed with cairo_region_destroy()
1019 *
1020 * Return value: (transfer full): a cairo_region_t
1021 *
1022 * Since: 0.16
1023 **/
1024 cairo_region_t *
poppler_page_get_selected_region(PopplerPage * page,gdouble scale,PopplerSelectionStyle style,PopplerRectangle * selection)1025 poppler_page_get_selected_region (PopplerPage *page,
1026 gdouble scale,
1027 PopplerSelectionStyle style,
1028 PopplerRectangle *selection)
1029 {
1030 PDFRectangle poppler_selection;
1031 TextPage *text;
1032 SelectionStyle selection_style = selectionStyleGlyph;
1033 GooList *list;
1034 cairo_region_t *region;
1035 int i;
1036
1037 poppler_selection.x1 = selection->x1;
1038 poppler_selection.y1 = selection->y1;
1039 poppler_selection.x2 = selection->x2;
1040 poppler_selection.y2 = selection->y2;
1041
1042 switch (style)
1043 {
1044 case POPPLER_SELECTION_GLYPH:
1045 selection_style = selectionStyleGlyph;
1046 break;
1047 case POPPLER_SELECTION_WORD:
1048 selection_style = selectionStyleWord;
1049 break;
1050 case POPPLER_SELECTION_LINE:
1051 selection_style = selectionStyleLine;
1052 break;
1053 }
1054
1055 text = poppler_page_get_text_page (page);
1056 list = text->getSelectionRegion(&poppler_selection,
1057 selection_style, 1.0);
1058
1059 region = cairo_region_create ();
1060
1061 for (i = 0; i < list->getLength(); i++) {
1062 PDFRectangle *selection_rect = (PDFRectangle *) list->get(i);
1063 cairo_rectangle_int_t rect;
1064
1065 rect.x = (gint) ((selection_rect->x1 * scale) + 0.5);
1066 rect.y = (gint) ((selection_rect->y1 * scale) + 0.5);
1067 rect.width = (gint) (((selection_rect->x2 - selection_rect->x1) * scale) + 0.5);
1068 rect.height = (gint) (((selection_rect->y2 - selection_rect->y1) * scale) + 0.5);
1069 cairo_region_union_rectangle (region, &rect);
1070
1071 delete selection_rect;
1072 }
1073
1074 delete list;
1075
1076 return region;
1077 }
1078
1079 /**
1080 * poppler_page_get_selected_text:
1081 * @page: a #PopplerPage
1082 * @style: a #PopplerSelectionStyle
1083 * @selection: the #PopplerRectangle including the text
1084 *
1085 * Retrieves the contents of the specified @selection as text.
1086 *
1087 * Return value: a pointer to the contents of the @selection
1088 * as a string
1089 * Since: 0.16
1090 **/
1091 char *
poppler_page_get_selected_text(PopplerPage * page,PopplerSelectionStyle style,PopplerRectangle * selection)1092 poppler_page_get_selected_text (PopplerPage *page,
1093 PopplerSelectionStyle style,
1094 PopplerRectangle *selection)
1095 {
1096 GooString *sel_text;
1097 char *result;
1098 TextPage *text;
1099 SelectionStyle selection_style = selectionStyleGlyph;
1100 PDFRectangle pdf_selection;
1101
1102 g_return_val_if_fail (POPPLER_IS_PAGE (page), NULL);
1103 g_return_val_if_fail (selection != NULL, NULL);
1104
1105 pdf_selection.x1 = selection->x1;
1106 pdf_selection.y1 = selection->y1;
1107 pdf_selection.x2 = selection->x2;
1108 pdf_selection.y2 = selection->y2;
1109
1110 switch (style)
1111 {
1112 case POPPLER_SELECTION_GLYPH:
1113 selection_style = selectionStyleGlyph;
1114 break;
1115 case POPPLER_SELECTION_WORD:
1116 selection_style = selectionStyleWord;
1117 break;
1118 case POPPLER_SELECTION_LINE:
1119 selection_style = selectionStyleLine;
1120 break;
1121 }
1122
1123 text = poppler_page_get_text_page (page);
1124 sel_text = text->getSelectionText (&pdf_selection, selection_style);
1125 result = g_strdup (sel_text->getCString ());
1126 delete sel_text;
1127
1128 return result;
1129 }
1130
1131 /**
1132 * poppler_page_get_text:
1133 * @page: a #PopplerPage
1134 *
1135 * Retrieves the text of @page.
1136 *
1137 * Return value: a pointer to the text of the @page
1138 * as a string
1139 * Since: 0.16
1140 **/
1141 char *
poppler_page_get_text(PopplerPage * page)1142 poppler_page_get_text (PopplerPage *page)
1143 {
1144 PopplerRectangle rectangle = {0, 0, 0, 0};
1145
1146 g_return_val_if_fail (POPPLER_IS_PAGE (page), NULL);
1147
1148 poppler_page_get_size (page, &rectangle.x2, &rectangle.y2);
1149
1150 return poppler_page_get_selected_text (page, POPPLER_SELECTION_GLYPH, &rectangle);
1151 }
1152
1153 /**
1154 * poppler_page_find_text:
1155 * @page: a #PopplerPage
1156 * @text: the text to search for (UTF-8 encoded)
1157 *
1158 * A #GList of rectangles for each occurance of the text on the page.
1159 * The coordinates are in PDF points.
1160 *
1161 * Return value: (element-type PopplerRectangle) (transfer full): a #GList of #PopplerRectangle,
1162 **/
1163 GList *
poppler_page_find_text(PopplerPage * page,const char * text)1164 poppler_page_find_text (PopplerPage *page,
1165 const char *text)
1166 {
1167 PopplerRectangle *match;
1168 GList *matches;
1169 double xMin, yMin, xMax, yMax;
1170 gunichar *ucs4;
1171 glong ucs4_len;
1172 double height;
1173 TextPage *text_dev;
1174
1175 g_return_val_if_fail (POPPLER_IS_PAGE (page), NULL);
1176 g_return_val_if_fail (text != NULL, NULL);
1177
1178 text_dev = poppler_page_get_text_page (page);
1179
1180 ucs4 = g_utf8_to_ucs4_fast (text, -1, &ucs4_len);
1181 poppler_page_get_size (page, NULL, &height);
1182
1183 matches = NULL;
1184 xMin = 0;
1185 yMin = 0;
1186
1187 while (text_dev->findText (ucs4, ucs4_len,
1188 gFalse, gTrue, // startAtTop, stopAtBottom
1189 gFalse, gFalse, // startAtLast, stopAtLast
1190 gFalse, gFalse, // caseSensitive, backwards
1191 &xMin, &yMin, &xMax, &yMax))
1192 {
1193 match = poppler_rectangle_new ();
1194 match->x1 = xMin;
1195 match->y1 = height - yMax;
1196 match->x2 = xMax;
1197 match->y2 = height - yMin;
1198 matches = g_list_prepend (matches, match);
1199 }
1200
1201 g_free (ucs4);
1202
1203 return g_list_reverse (matches);
1204 }
1205
1206 static CairoImageOutputDev *
poppler_page_get_image_output_dev(PopplerPage * page,GBool (* imgDrawDeviceCbk)(int img_id,void * data),void * imgDrawCbkData)1207 poppler_page_get_image_output_dev (PopplerPage *page,
1208 GBool (*imgDrawDeviceCbk)(int img_id, void *data),
1209 void *imgDrawCbkData)
1210 {
1211 CairoImageOutputDev *image_dev;
1212 Gfx *gfx;
1213
1214 image_dev = new CairoImageOutputDev ();
1215
1216 if (imgDrawDeviceCbk) {
1217 image_dev->setImageDrawDecideCbk (imgDrawDeviceCbk,
1218 imgDrawCbkData);
1219 }
1220
1221 gfx = page->page->createGfx(image_dev,
1222 72.0, 72.0, 0,
1223 gFalse, /* useMediaBox */
1224 gTrue, /* Crop */
1225 -1, -1, -1, -1,
1226 gFalse, /* printing */
1227 page->document->doc->getCatalog (),
1228 NULL, NULL, NULL, NULL);
1229 page->page->display(gfx);
1230 delete gfx;
1231
1232 return image_dev;
1233 }
1234
1235 /**
1236 * poppler_page_get_image_mapping:
1237 * @page: A #PopplerPage
1238 *
1239 * Returns a list of #PopplerImageMapping items that map from a
1240 * location on @page to an image of the page. This list must be freed
1241 * with poppler_page_free_image_mapping() when done.
1242 *
1243 * Return value: (element-type PopplerImageMapping) (transfer full): A #GList of #PopplerImageMapping
1244 **/
1245 GList *
poppler_page_get_image_mapping(PopplerPage * page)1246 poppler_page_get_image_mapping (PopplerPage *page)
1247 {
1248 GList *map_list = NULL;
1249 CairoImageOutputDev *out;
1250 gint i;
1251
1252 g_return_val_if_fail (POPPLER_IS_PAGE (page), NULL);
1253
1254 out = poppler_page_get_image_output_dev (page, NULL, NULL);
1255
1256 for (i = 0; i < out->getNumImages (); i++) {
1257 PopplerImageMapping *mapping;
1258 CairoImage *image;
1259
1260 image = out->getImage (i);
1261
1262 /* Create the mapping */
1263 mapping = poppler_image_mapping_new ();
1264
1265 image->getRect (&(mapping->area.x1), &(mapping->area.y1),
1266 &(mapping->area.x2), &(mapping->area.y2));
1267 mapping->image_id = i;
1268
1269 mapping->area.x1 -= page->page->getCropBox()->x1;
1270 mapping->area.x2 -= page->page->getCropBox()->x1;
1271 mapping->area.y1 -= page->page->getCropBox()->y1;
1272 mapping->area.y2 -= page->page->getCropBox()->y1;
1273
1274 map_list = g_list_prepend (map_list, mapping);
1275 }
1276
1277 delete out;
1278
1279 return map_list;
1280 }
1281
1282 static GBool
image_draw_decide_cb(int image_id,void * data)1283 image_draw_decide_cb (int image_id, void *data)
1284 {
1285 return (image_id == GPOINTER_TO_INT (data));
1286 }
1287
1288 /**
1289 * poppler_page_get_image:
1290 * @page: A #PopplerPage
1291 * @image_id: The image identificator
1292 *
1293 * Returns a cairo surface for the image of the @page
1294 *
1295 * Return value: A cairo surface for the image
1296 **/
1297 cairo_surface_t *
poppler_page_get_image(PopplerPage * page,gint image_id)1298 poppler_page_get_image (PopplerPage *page,
1299 gint image_id)
1300 {
1301 CairoImageOutputDev *out;
1302 cairo_surface_t *image;
1303
1304 g_return_val_if_fail (POPPLER_IS_PAGE (page), NULL);
1305
1306 out = poppler_page_get_image_output_dev (page,
1307 image_draw_decide_cb,
1308 GINT_TO_POINTER (image_id));
1309
1310 if (image_id >= out->getNumImages ()) {
1311 delete out;
1312
1313 return NULL;
1314 }
1315
1316 image = out->getImage (image_id)->getImage ();
1317 if (!image) {
1318 delete out;
1319
1320 return NULL;
1321 }
1322
1323 cairo_surface_reference (image);
1324 delete out;
1325
1326 return image;
1327 }
1328
1329 /**
1330 * poppler_page_free_image_mapping:
1331 * @list: A list of #PopplerImageMapping<!-- -->s
1332 *
1333 * Frees a list of #PopplerImageMapping<!-- -->s allocated by
1334 * poppler_page_get_image_mapping().
1335 **/
1336 void
poppler_page_free_image_mapping(GList * list)1337 poppler_page_free_image_mapping (GList *list)
1338 {
1339 if (G_UNLIKELY (list == NULL))
1340 return;
1341
1342 g_list_foreach (list, (GFunc)poppler_image_mapping_free, NULL);
1343 g_list_free (list);
1344 }
1345
1346 /**
1347 * poppler_page_render_to_ps:
1348 * @page: a #PopplerPage
1349 * @ps_file: the PopplerPSFile to render to
1350 *
1351 * Render the page on a postscript file
1352 *
1353 **/
1354 void
poppler_page_render_to_ps(PopplerPage * page,PopplerPSFile * ps_file)1355 poppler_page_render_to_ps (PopplerPage *page,
1356 PopplerPSFile *ps_file)
1357 {
1358 g_return_if_fail (POPPLER_IS_PAGE (page));
1359 g_return_if_fail (ps_file != NULL);
1360
1361 if (!ps_file->out)
1362 ps_file->out = new PSOutputDev (ps_file->filename,
1363 ps_file->document->doc,
1364 ps_file->document->doc->getXRef(),
1365 ps_file->document->doc->getCatalog(),
1366 NULL,
1367 ps_file->first_page, ps_file->last_page,
1368 psModePS, (int)ps_file->paper_width,
1369 (int)ps_file->paper_height, ps_file->duplex,
1370 0, 0, 0, 0, gFalse, gFalse);
1371
1372
1373 ps_file->document->doc->displayPage (ps_file->out, page->index + 1, 72.0, 72.0,
1374 0, gFalse, gTrue, gFalse);
1375 }
1376
1377 static void
poppler_page_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)1378 poppler_page_get_property (GObject *object,
1379 guint prop_id,
1380 GValue *value,
1381 GParamSpec *pspec)
1382 {
1383 PopplerPage *page = POPPLER_PAGE (object);
1384
1385 switch (prop_id)
1386 {
1387 case PROP_LABEL:
1388 g_value_take_string (value, poppler_page_get_label (page));
1389 break;
1390 default:
1391 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1392 }
1393 }
1394
1395 static void
poppler_page_class_init(PopplerPageClass * klass)1396 poppler_page_class_init (PopplerPageClass *klass)
1397 {
1398 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1399
1400 gobject_class->finalize = poppler_page_finalize;
1401 gobject_class->get_property = poppler_page_get_property;
1402
1403 /**
1404 * PopplerPage:label:
1405 *
1406 * The label of the page or %NULL. See also poppler_page_get_label()
1407 */
1408 g_object_class_install_property (G_OBJECT_CLASS (klass),
1409 PROP_LABEL,
1410 g_param_spec_string ("label",
1411 "Page Label",
1412 "The label of the page",
1413 NULL,
1414 G_PARAM_READABLE));
1415 }
1416
1417 static void
poppler_page_init(PopplerPage * page)1418 poppler_page_init (PopplerPage *page)
1419 {
1420 }
1421
1422 /**
1423 * poppler_page_get_link_mapping:
1424 * @page: A #PopplerPage
1425 *
1426 * Returns a list of #PopplerLinkMapping items that map from a
1427 * location on @page to a #PopplerAction. This list must be freed
1428 * with poppler_page_free_link_mapping() when done.
1429 *
1430 * Return value: (element-type PopplerLinkMapping) (transfer full): A #GList of #PopplerLinkMapping
1431 **/
1432 GList *
poppler_page_get_link_mapping(PopplerPage * page)1433 poppler_page_get_link_mapping (PopplerPage *page)
1434 {
1435 GList *map_list = NULL;
1436 gint i;
1437 Links *links;
1438 Object obj;
1439 double width, height;
1440
1441 g_return_val_if_fail (POPPLER_IS_PAGE (page), NULL);
1442
1443 links = new Links (page->page->getAnnots (&obj),
1444 page->document->doc->getCatalog ()->getBaseURI ());
1445 obj.free ();
1446
1447 if (links == NULL)
1448 return NULL;
1449
1450 poppler_page_get_size (page, &width, &height);
1451
1452 for (i = 0; i < links->getNumLinks (); i++)
1453 {
1454 PopplerLinkMapping *mapping;
1455 PopplerRectangle rect;
1456 LinkAction *link_action;
1457 Link *link;
1458
1459 link = links->getLink (i);
1460 link_action = link->getAction ();
1461
1462 /* Create the mapping */
1463 mapping = poppler_link_mapping_new ();
1464 mapping->action = _poppler_action_new (page->document, link_action, NULL);
1465
1466 link->getRect (&rect.x1, &rect.y1, &rect.x2, &rect.y2);
1467
1468 rect.x1 -= page->page->getCropBox()->x1;
1469 rect.x2 -= page->page->getCropBox()->x1;
1470 rect.y1 -= page->page->getCropBox()->y1;
1471 rect.y2 -= page->page->getCropBox()->y1;
1472
1473 switch (page->page->getRotate ())
1474 {
1475 case 90:
1476 mapping->area.x1 = rect.y1;
1477 mapping->area.y1 = height - rect.x2;
1478 mapping->area.x2 = mapping->area.x1 + (rect.y2 - rect.y1);
1479 mapping->area.y2 = mapping->area.y1 + (rect.x2 - rect.x1);
1480
1481 break;
1482 case 180:
1483 mapping->area.x1 = width - rect.x2;
1484 mapping->area.y1 = height - rect.y2;
1485 mapping->area.x2 = mapping->area.x1 + (rect.x2 - rect.x1);
1486 mapping->area.y2 = mapping->area.y1 + (rect.y2 - rect.y1);
1487
1488 break;
1489 case 270:
1490 mapping->area.x1 = width - rect.y2;
1491 mapping->area.y1 = rect.x1;
1492 mapping->area.x2 = mapping->area.x1 + (rect.y2 - rect.y1);
1493 mapping->area.y2 = mapping->area.y1 + (rect.x2 - rect.x1);
1494
1495 break;
1496 default:
1497 mapping->area.x1 = rect.x1;
1498 mapping->area.y1 = rect.y1;
1499 mapping->area.x2 = rect.x2;
1500 mapping->area.y2 = rect.y2;
1501 }
1502
1503 map_list = g_list_prepend (map_list, mapping);
1504 }
1505
1506 delete links;
1507
1508 return map_list;
1509 }
1510
1511 /**
1512 * poppler_page_free_link_mapping:
1513 * @list: A list of #PopplerLinkMapping<!-- -->s
1514 *
1515 * Frees a list of #PopplerLinkMapping<!-- -->s allocated by
1516 * poppler_page_get_link_mapping(). It also frees the #PopplerAction<!-- -->s
1517 * that each mapping contains, so if you want to keep them around, you need to
1518 * copy them with poppler_action_copy().
1519 **/
1520 void
poppler_page_free_link_mapping(GList * list)1521 poppler_page_free_link_mapping (GList *list)
1522 {
1523 if (G_UNLIKELY (list == NULL))
1524 return;
1525
1526 g_list_foreach (list, (GFunc)poppler_link_mapping_free, NULL);
1527 g_list_free (list);
1528 }
1529
1530 /**
1531 * poppler_page_get_form_field_mapping:
1532 * @page: A #PopplerPage
1533 *
1534 * Returns a list of #PopplerFormFieldMapping items that map from a
1535 * location on @page to a form field. This list must be freed
1536 * with poppler_page_free_form_field_mapping() when done.
1537 *
1538 * Return value: (element-type PopplerFormFieldMapping) (transfer full): A #GList of #PopplerFormFieldMapping
1539 **/
1540 GList *
poppler_page_get_form_field_mapping(PopplerPage * page)1541 poppler_page_get_form_field_mapping (PopplerPage *page)
1542 {
1543 GList *map_list = NULL;
1544 FormPageWidgets *forms;
1545 gint i;
1546
1547 g_return_val_if_fail (POPPLER_IS_PAGE (page), NULL);
1548
1549 forms = page->page->getPageWidgets ();
1550 if (forms == NULL)
1551 return NULL;
1552
1553 for (i = 0; i < forms->getNumWidgets (); i++) {
1554 PopplerFormFieldMapping *mapping;
1555 FormWidget *field;
1556
1557 mapping = poppler_form_field_mapping_new ();
1558
1559 field = forms->getWidget (i);
1560
1561 mapping->field = _poppler_form_field_new (page->document, field);
1562 field->getRect (&(mapping->area.x1), &(mapping->area.y1),
1563 &(mapping->area.x2), &(mapping->area.y2));
1564
1565 mapping->area.x1 -= page->page->getCropBox()->x1;
1566 mapping->area.x2 -= page->page->getCropBox()->x1;
1567 mapping->area.y1 -= page->page->getCropBox()->y1;
1568 mapping->area.y2 -= page->page->getCropBox()->y1;
1569
1570 map_list = g_list_prepend (map_list, mapping);
1571 }
1572
1573 return map_list;
1574 }
1575
1576 /**
1577 * poppler_page_free_form_field_mapping:
1578 * @list: A list of #PopplerFormFieldMapping<!-- -->s
1579 *
1580 * Frees a list of #PopplerFormFieldMapping<!-- -->s allocated by
1581 * poppler_page_get_form_field_mapping().
1582 **/
1583 void
poppler_page_free_form_field_mapping(GList * list)1584 poppler_page_free_form_field_mapping (GList *list)
1585 {
1586 if (G_UNLIKELY (list == NULL))
1587 return;
1588
1589 g_list_foreach (list, (GFunc) poppler_form_field_mapping_free, NULL);
1590 g_list_free (list);
1591 }
1592
1593 /**
1594 * poppler_page_get_annot_mapping:
1595 * @page: A #PopplerPage
1596 *
1597 * Returns a list of #PopplerAnnotMapping items that map from a location on
1598 * @page to a #PopplerAnnot. This list must be freed with
1599 * poppler_page_free_annot_mapping() when done.
1600 *
1601 * Return value: (element-type PopplerAnnotMapping) (transfer full): A #GList of #PopplerAnnotMapping
1602 **/
1603 GList *
poppler_page_get_annot_mapping(PopplerPage * page)1604 poppler_page_get_annot_mapping (PopplerPage *page)
1605 {
1606 GList *map_list = NULL;
1607 double width, height;
1608 gint i;
1609
1610 g_return_val_if_fail (POPPLER_IS_PAGE (page), NULL);
1611
1612 if (!page->annots)
1613 page->annots = page->page->getAnnots (page->document->doc->getCatalog ());
1614
1615 if (!page->annots)
1616 return NULL;
1617
1618 poppler_page_get_size (page, &width, &height);
1619
1620 for (i = 0; i < page->annots->getNumAnnots (); i++) {
1621 PopplerAnnotMapping *mapping;
1622 PopplerRectangle rect;
1623 Annot *annot;
1624 PDFRectangle *annot_rect;
1625 gint rotation = 0;
1626
1627 annot = page->annots->getAnnot (i);
1628
1629 /* Create the mapping */
1630 mapping = poppler_annot_mapping_new ();
1631
1632 switch (annot->getType ())
1633 {
1634 case Annot::typeText:
1635 mapping->annot = _poppler_annot_text_new (annot);
1636 break;
1637 case Annot::typeFreeText:
1638 mapping->annot = _poppler_annot_free_text_new (annot);
1639 break;
1640 case Annot::typeFileAttachment:
1641 mapping->annot = _poppler_annot_file_attachment_new (annot);
1642 break;
1643 case Annot::typeMovie:
1644 mapping->annot = _poppler_annot_movie_new (annot);
1645 break;
1646 case Annot::typeScreen:
1647 mapping->annot = _poppler_annot_screen_new (annot);
1648 break;
1649 default:
1650 mapping->annot = _poppler_annot_new (annot);
1651 break;
1652 }
1653
1654 annot_rect = annot->getRect ();
1655 rect.x1 = annot_rect->x1 - page->page->getCropBox()->x1;
1656 rect.y1 = annot_rect->y1 - page->page->getCropBox()->y1;
1657 rect.x2 = annot_rect->x2 - page->page->getCropBox()->x1;
1658 rect.y2 = annot_rect->y2 - page->page->getCropBox()->y1;
1659
1660 if (! (annot->getFlags () & Annot::flagNoRotate))
1661 rotation = page->page->getRotate ();
1662
1663 switch (rotation)
1664 {
1665 case 90:
1666 mapping->area.x1 = rect.y1;
1667 mapping->area.y1 = height - rect.x2;
1668 mapping->area.x2 = mapping->area.x1 + (rect.y2 - rect.y1);
1669 mapping->area.y2 = mapping->area.y1 + (rect.x2 - rect.x1);
1670 break;
1671 case 180:
1672 mapping->area.x1 = width - rect.x2;
1673 mapping->area.y1 = height - rect.y2;
1674 mapping->area.x2 = mapping->area.x1 + (rect.x2 - rect.x1);
1675 mapping->area.y2 = mapping->area.y1 + (rect.y2 - rect.y1);
1676 break;
1677 case 270:
1678 mapping->area.x1 = width - rect.y2;
1679 mapping->area.y1 = rect.x1;
1680 mapping->area.x2 = mapping->area.x1 + (rect.y2 - rect.y1);
1681 mapping->area.y2 = mapping->area.y1 + (rect.x2 - rect.x1);
1682 break;
1683 default:
1684 mapping->area.x1 = rect.x1;
1685 mapping->area.y1 = rect.y1;
1686 mapping->area.x2 = rect.x2;
1687 mapping->area.y2 = rect.y2;
1688 }
1689
1690 map_list = g_list_prepend (map_list, mapping);
1691 }
1692
1693 return g_list_reverse (map_list);
1694 }
1695
1696 /**
1697 * poppler_page_free_annot_mapping:
1698 * @list: A list of #PopplerAnnotMapping<!-- -->s
1699 *
1700 * Frees a list of #PopplerAnnotMapping<!-- -->s allocated by
1701 * poppler_page_get_annot_mapping(). It also frees the #PopplerAnnot<!-- -->s
1702 * that each mapping contains, so if you want to keep them around, you need to
1703 * copy them with poppler_annot_copy().
1704 **/
1705 void
poppler_page_free_annot_mapping(GList * list)1706 poppler_page_free_annot_mapping (GList *list)
1707 {
1708 if (G_UNLIKELY (!list))
1709 return;
1710
1711 g_list_foreach (list, (GFunc)poppler_annot_mapping_free, NULL);
1712 g_list_free (list);
1713 }
1714
1715 /**
1716 * poppler_page_add_annot:
1717 * @page: a #PopplerPage
1718 * @annot: a #PopplerAnnot to add
1719 *
1720 * Adds annotation @annot to @page.
1721 *
1722 * Since: 0.16
1723 */
1724 void
poppler_page_add_annot(PopplerPage * page,PopplerAnnot * annot)1725 poppler_page_add_annot (PopplerPage *page,
1726 PopplerAnnot *annot)
1727 {
1728 g_return_if_fail (POPPLER_IS_PAGE (page));
1729 g_return_if_fail (POPPLER_IS_ANNOT (annot));
1730
1731 page->page->addAnnot (annot->annot);
1732 }
1733
1734 /* PopplerRectangle type */
1735
POPPLER_DEFINE_BOXED_TYPE(PopplerRectangle,poppler_rectangle,poppler_rectangle_copy,poppler_rectangle_free)1736 POPPLER_DEFINE_BOXED_TYPE (PopplerRectangle, poppler_rectangle,
1737 poppler_rectangle_copy,
1738 poppler_rectangle_free)
1739
1740 /**
1741 * poppler_rectangle_new:
1742 *
1743 * Creates a new #PopplerRectangle
1744 *
1745 * Returns: a new #PopplerRectangle, use poppler_rectangle_free() to free it
1746 */
1747 PopplerRectangle *
1748 poppler_rectangle_new (void)
1749 {
1750 return g_slice_new0 (PopplerRectangle);
1751 }
1752
1753 /**
1754 * poppler_rectangle_copy:
1755 * @rectangle: a #PopplerRectangle to copy
1756 *
1757 * Creates a copy of @rectangle
1758 *
1759 * Returns: a new allocated copy of @rectangle
1760 */
1761 PopplerRectangle *
poppler_rectangle_copy(PopplerRectangle * rectangle)1762 poppler_rectangle_copy (PopplerRectangle *rectangle)
1763 {
1764 g_return_val_if_fail (rectangle != NULL, NULL);
1765
1766 return g_slice_dup (PopplerRectangle, rectangle);
1767 }
1768
1769 /**
1770 * poppler_rectangle_free:
1771 * @rectangle: a #PopplerRectangle
1772 *
1773 * Frees the given #PopplerRectangle
1774 */
1775 void
poppler_rectangle_free(PopplerRectangle * rectangle)1776 poppler_rectangle_free (PopplerRectangle *rectangle)
1777 {
1778 g_slice_free (PopplerRectangle, rectangle);
1779 }
1780
1781 /* PopplerColor type */
POPPLER_DEFINE_BOXED_TYPE(PopplerColor,poppler_color,poppler_color_copy,poppler_color_free)1782 POPPLER_DEFINE_BOXED_TYPE (PopplerColor, poppler_color, poppler_color_copy, poppler_color_free)
1783
1784 /**
1785 * poppler_color_new:
1786 *
1787 * Creates a new #PopplerColor
1788 *
1789 * Returns: a new #PopplerColor, use poppler_color_free() to free it
1790 */
1791 PopplerColor *
1792 poppler_color_new (void)
1793 {
1794 return (PopplerColor *) g_new0 (PopplerColor, 1);
1795 }
1796
1797 /**
1798 * poppler_color_copy:
1799 * @color: a #PopplerColor to copy
1800 *
1801 * Creates a copy of @color
1802 *
1803 * Returns: a new allocated copy of @color
1804 */
1805 PopplerColor *
poppler_color_copy(PopplerColor * color)1806 poppler_color_copy (PopplerColor *color)
1807 {
1808 PopplerColor *new_color;
1809
1810 new_color = g_new (PopplerColor, 1);
1811 *new_color = *color;
1812
1813 return new_color;
1814 }
1815
1816 /**
1817 * poppler_color_free:
1818 * @color: a #PopplerColor
1819 *
1820 * Frees the given #PopplerColor
1821 */
1822 void
poppler_color_free(PopplerColor * color)1823 poppler_color_free (PopplerColor *color)
1824 {
1825 g_free (color);
1826 }
1827
1828 /* PopplerLinkMapping type */
POPPLER_DEFINE_BOXED_TYPE(PopplerLinkMapping,poppler_link_mapping,poppler_link_mapping_copy,poppler_link_mapping_free)1829 POPPLER_DEFINE_BOXED_TYPE (PopplerLinkMapping, poppler_link_mapping,
1830 poppler_link_mapping_copy,
1831 poppler_link_mapping_free)
1832
1833 /**
1834 * poppler_link_mapping_new:
1835 *
1836 * Creates a new #PopplerLinkMapping
1837 *
1838 * Returns: a new #PopplerLinkMapping, use poppler_link_mapping_free() to free it
1839 */
1840 PopplerLinkMapping *
1841 poppler_link_mapping_new (void)
1842 {
1843 return g_slice_new0 (PopplerLinkMapping);
1844 }
1845
1846 /**
1847 * poppler_link_mapping_copy:
1848 * @mapping: a #PopplerLinkMapping to copy
1849 *
1850 * Creates a copy of @mapping
1851 *
1852 * Returns: a new allocated copy of @mapping
1853 */
1854 PopplerLinkMapping *
poppler_link_mapping_copy(PopplerLinkMapping * mapping)1855 poppler_link_mapping_copy (PopplerLinkMapping *mapping)
1856 {
1857 PopplerLinkMapping *new_mapping;
1858
1859 new_mapping = g_slice_dup (PopplerLinkMapping, mapping);
1860
1861 if (new_mapping->action)
1862 new_mapping->action = poppler_action_copy (new_mapping->action);
1863
1864 return new_mapping;
1865 }
1866
1867 /**
1868 * poppler_link_mapping_free:
1869 * @mapping: a #PopplerLinkMapping
1870 *
1871 * Frees the given #PopplerLinkMapping
1872 */
1873 void
poppler_link_mapping_free(PopplerLinkMapping * mapping)1874 poppler_link_mapping_free (PopplerLinkMapping *mapping)
1875 {
1876 if (G_UNLIKELY (!mapping))
1877 return;
1878
1879 if (mapping->action)
1880 poppler_action_free (mapping->action);
1881
1882 g_slice_free (PopplerLinkMapping, mapping);
1883 }
1884
1885 /* Poppler Image mapping type */
POPPLER_DEFINE_BOXED_TYPE(PopplerImageMapping,poppler_image_mapping,poppler_image_mapping_copy,poppler_image_mapping_free)1886 POPPLER_DEFINE_BOXED_TYPE (PopplerImageMapping, poppler_image_mapping,
1887 poppler_image_mapping_copy,
1888 poppler_image_mapping_free)
1889
1890 /**
1891 * poppler_image_mapping_new:
1892 *
1893 * Creates a new #PopplerImageMapping
1894 *
1895 * Returns: a new #PopplerImageMapping, use poppler_image_mapping_free() to free it
1896 */
1897 PopplerImageMapping *
1898 poppler_image_mapping_new (void)
1899 {
1900 return g_slice_new0 (PopplerImageMapping);
1901 }
1902
1903 /**
1904 * poppler_image_mapping_copy:
1905 * @mapping: a #PopplerImageMapping to copy
1906 *
1907 * Creates a copy of @mapping
1908 *
1909 * Returns: a new allocated copy of @mapping
1910 */
1911 PopplerImageMapping *
poppler_image_mapping_copy(PopplerImageMapping * mapping)1912 poppler_image_mapping_copy (PopplerImageMapping *mapping)
1913 {
1914 return g_slice_dup (PopplerImageMapping, mapping);
1915 }
1916
1917 /**
1918 * poppler_image_mapping_free:
1919 * @mapping: a #PopplerImageMapping
1920 *
1921 * Frees the given #PopplerImageMapping
1922 */
1923 void
poppler_image_mapping_free(PopplerImageMapping * mapping)1924 poppler_image_mapping_free (PopplerImageMapping *mapping)
1925 {
1926 g_slice_free (PopplerImageMapping, mapping);
1927 }
1928
1929 /* Page Transition */
POPPLER_DEFINE_BOXED_TYPE(PopplerPageTransition,poppler_page_transition,poppler_page_transition_copy,poppler_page_transition_free)1930 POPPLER_DEFINE_BOXED_TYPE (PopplerPageTransition, poppler_page_transition,
1931 poppler_page_transition_copy,
1932 poppler_page_transition_free)
1933
1934 /**
1935 * poppler_page_transition_new:
1936 *
1937 * Creates a new #PopplerPageTransition
1938 *
1939 * Returns: a new #PopplerPageTransition, use poppler_page_transition_free() to free it
1940 */
1941 PopplerPageTransition *
1942 poppler_page_transition_new (void)
1943 {
1944 return (PopplerPageTransition *) g_new0 (PopplerPageTransition, 1);
1945 }
1946
1947 /**
1948 * poppler_page_transition_copy:
1949 * @transition: a #PopplerPageTransition to copy
1950 *
1951 * Creates a copy of @transition
1952 *
1953 * Returns: a new allocated copy of @transition
1954 */
1955 PopplerPageTransition *
poppler_page_transition_copy(PopplerPageTransition * transition)1956 poppler_page_transition_copy (PopplerPageTransition *transition)
1957 {
1958 PopplerPageTransition *new_transition;
1959
1960 new_transition = poppler_page_transition_new ();
1961 *new_transition = *transition;
1962
1963 return new_transition;
1964 }
1965
1966 /**
1967 * poppler_page_transition_free:
1968 * @transition: a #PopplerPageTransition
1969 *
1970 * Frees the given #PopplerPageTransition
1971 */
1972 void
poppler_page_transition_free(PopplerPageTransition * transition)1973 poppler_page_transition_free (PopplerPageTransition *transition)
1974 {
1975 g_free (transition);
1976 }
1977
1978 /* Form Field Mapping Type */
POPPLER_DEFINE_BOXED_TYPE(PopplerFormFieldMapping,poppler_form_field_mapping,poppler_form_field_mapping_copy,poppler_form_field_mapping_free)1979 POPPLER_DEFINE_BOXED_TYPE (PopplerFormFieldMapping, poppler_form_field_mapping,
1980 poppler_form_field_mapping_copy,
1981 poppler_form_field_mapping_free)
1982
1983 /**
1984 * poppler_form_field_mapping_new:
1985 *
1986 * Creates a new #PopplerFormFieldMapping
1987 *
1988 * Returns: a new #PopplerFormFieldMapping, use poppler_form_field_mapping_free() to free it
1989 */
1990 PopplerFormFieldMapping *
1991 poppler_form_field_mapping_new (void)
1992 {
1993 return g_slice_new0 (PopplerFormFieldMapping);
1994 }
1995
1996 /**
1997 * poppler_form_field_mapping_copy:
1998 * @mapping: a #PopplerFormFieldMapping to copy
1999 *
2000 * Creates a copy of @mapping
2001 *
2002 * Returns: a new allocated copy of @mapping
2003 */
2004 PopplerFormFieldMapping *
poppler_form_field_mapping_copy(PopplerFormFieldMapping * mapping)2005 poppler_form_field_mapping_copy (PopplerFormFieldMapping *mapping)
2006 {
2007 PopplerFormFieldMapping *new_mapping;
2008
2009 new_mapping = g_slice_dup (PopplerFormFieldMapping, mapping);
2010
2011 if (mapping->field)
2012 new_mapping->field = (PopplerFormField *)g_object_ref (mapping->field);
2013
2014 return new_mapping;
2015 }
2016
2017 /**
2018 * poppler_form_field_mapping_free:
2019 * @mapping: a #PopplerFormFieldMapping
2020 *
2021 * Frees the given #PopplerFormFieldMapping
2022 */
2023 void
poppler_form_field_mapping_free(PopplerFormFieldMapping * mapping)2024 poppler_form_field_mapping_free (PopplerFormFieldMapping *mapping)
2025 {
2026 if (G_UNLIKELY (!mapping))
2027 return;
2028
2029 if (mapping->field)
2030 g_object_unref (mapping->field);
2031
2032 g_slice_free (PopplerFormFieldMapping, mapping);
2033 }
2034
2035 /* PopplerAnnot Mapping Type */
POPPLER_DEFINE_BOXED_TYPE(PopplerAnnotMapping,poppler_annot_mapping,poppler_annot_mapping_copy,poppler_annot_mapping_free)2036 POPPLER_DEFINE_BOXED_TYPE (PopplerAnnotMapping, poppler_annot_mapping,
2037 poppler_annot_mapping_copy,
2038 poppler_annot_mapping_free)
2039
2040 /**
2041 * poppler_annot_mapping_new:
2042 *
2043 * Creates a new #PopplerAnnotMapping
2044 *
2045 * Returns: a new #PopplerAnnotMapping, use poppler_annot_mapping_free() to free it
2046 */
2047 PopplerAnnotMapping *
2048 poppler_annot_mapping_new (void)
2049 {
2050 return g_slice_new0 (PopplerAnnotMapping);
2051 }
2052
2053 /**
2054 * poppler_annot_mapping_copy:
2055 * @mapping: a #PopplerAnnotMapping to copy
2056 *
2057 * Creates a copy of @mapping
2058 *
2059 * Returns: a new allocated copy of @mapping
2060 */
2061 PopplerAnnotMapping *
poppler_annot_mapping_copy(PopplerAnnotMapping * mapping)2062 poppler_annot_mapping_copy (PopplerAnnotMapping *mapping)
2063 {
2064 PopplerAnnotMapping *new_mapping;
2065
2066 new_mapping = g_slice_dup (PopplerAnnotMapping, mapping);
2067
2068 if (mapping->annot)
2069 new_mapping->annot = (PopplerAnnot *) g_object_ref (mapping->annot);
2070
2071 return new_mapping;
2072 }
2073
2074 /**
2075 * poppler_annot_mapping_free:
2076 * @mapping: a #PopplerAnnotMapping
2077 *
2078 * Frees the given #PopplerAnnotMapping
2079 */
2080 void
poppler_annot_mapping_free(PopplerAnnotMapping * mapping)2081 poppler_annot_mapping_free (PopplerAnnotMapping *mapping)
2082 {
2083 if (G_UNLIKELY (!mapping))
2084 return;
2085
2086 if (mapping->annot)
2087 g_object_unref (mapping->annot);
2088
2089 g_slice_free (PopplerAnnotMapping, mapping);
2090 }
2091
2092 /**
2093 * poppler_page_get_crop_box:
2094 * @page: a #PopplerPage
2095 * @rect: (out): a #PopplerRectangle to fill
2096 *
2097 * Retrurns the crop box of @page
2098 */
2099 void
poppler_page_get_crop_box(PopplerPage * page,PopplerRectangle * rect)2100 poppler_page_get_crop_box (PopplerPage *page, PopplerRectangle *rect)
2101 {
2102 PDFRectangle* cropBox = page->page->getCropBox ();
2103
2104 rect->x1 = cropBox->x1;
2105 rect->x2 = cropBox->x2;
2106 rect->y1 = cropBox->y1;
2107 rect->y2 = cropBox->y2;
2108 }
2109
2110 /**
2111 * poppler_page_get_text_layout:
2112 * @page: A #PopplerPage
2113 * @rectangles: (out) (array length=n_rectangles) (transfer container): return location for an array of #PopplerRectangle
2114 * @n_rectangles: (out) length of returned array
2115 *
2116 * Obtains the layout of the text as a list of #PopplerRectangle
2117 * This array must be freed with g_free () when done.
2118 *
2119 * The position in the array represents an offset in the text returned by
2120 * poppler_page_get_text()
2121 *
2122 * Return value: %TRUE if the page contains text, %FALSE otherwise
2123 *
2124 * Since: 0.16
2125 **/
2126 gboolean
poppler_page_get_text_layout(PopplerPage * page,PopplerRectangle ** rectangles,guint * n_rectangles)2127 poppler_page_get_text_layout (PopplerPage *page,
2128 PopplerRectangle **rectangles,
2129 guint *n_rectangles)
2130 {
2131 TextPage *text;
2132 TextWordList *wordlist;
2133 TextWord *word, *nextword;
2134 PopplerRectangle *rect;
2135 int i, j, offset = 0;
2136 gdouble x1, y1, x2, y2;
2137 gdouble x3, y3, x4, y4;
2138
2139 g_return_val_if_fail (POPPLER_IS_PAGE (page), FALSE);
2140
2141 *n_rectangles = 0;
2142
2143 text = poppler_page_get_text_page (page);
2144 wordlist = text->makeWordList (gFalse);
2145
2146 if (wordlist->getLength () <= 0)
2147 {
2148 delete wordlist;
2149 return FALSE;
2150 }
2151
2152 // Getting the array size
2153 for (i = 0; i < wordlist->getLength (); i++)
2154 {
2155 word = wordlist->get (i);
2156 *n_rectangles += word->getLength () + 1;
2157 }
2158
2159 *rectangles = g_new (PopplerRectangle, *n_rectangles);
2160
2161 // Calculating each char position
2162 for (i = 0; i < wordlist->getLength (); i++)
2163 {
2164 word = wordlist->get (i);
2165 for (j = 0; j < word->getLength (); j++)
2166 {
2167 rect = *rectangles + offset;
2168 word->getCharBBox (j,
2169 &(rect->x1),
2170 &(rect->y1),
2171 &(rect->x2),
2172 &(rect->y2));
2173 offset++;
2174 }
2175
2176 // adding spaces and break lines
2177 rect = *rectangles + offset;
2178 word->getBBox (&x1, &y1, &x2, &y2);
2179
2180 nextword = word->getNext ();
2181 if (nextword)
2182 {
2183 nextword->getBBox (&x3, &y3, &x4, &y4);
2184 // space is from one word to other and with the same height as
2185 // first word.
2186 rect->x1 = x2;
2187 rect->y1 = y1;
2188 rect->x2 = x3;
2189 rect->y2 = y2;
2190 }
2191 else
2192 {
2193 // end of line
2194 rect->x1 = x2;
2195 rect->y1 = y2;
2196 rect->x2 = x2;
2197 rect->y2 = y2;
2198 }
2199 offset++;
2200 }
2201
2202 delete wordlist;
2203
2204 return TRUE;
2205 }
2206