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