source: trunk/poppler/mypoppler/poppler/Page.cc @ 261

Last change on this file since 261 was 261, checked in by Eugene Romanenko, 13 years ago

PDF plugin: Poppler library updated to version 0.10.2

File size: 17.0 KB
Line 
1//========================================================================
2//
3// Page.cc
4//
5// Copyright 1996-2007 Glyph & Cog, LLC
6//
7//========================================================================
8
9//========================================================================
10//
11// Modified under the Poppler project - http://poppler.freedesktop.org
12//
13// All changes made under the Poppler project to this file are licensed
14// under GPL version 2 or later
15//
16// Copyright (C) 2005 Kristian HÞgsberg <krh@redhat.com>
17// Copyright (C) 2005 Jeff Muizelaar <jeff@infidigm.net>
18// Copyright (C) 2005-2008 Albert Astals Cid <aacid@kde.org>
19// Copyright (C) 2006-2008 Pino Toscano <pino@kde.org>
20// Copyright (C) 2006 Nickolay V. Shmyrev <nshmyrev@yandex.ru>
21// Copyright (C) 2006 Scott Turner <scotty1024@mac.com>
22// Copyright (C) 2006-2008 Carlos Garcia Campos <carlosgc@gnome.org>
23// Copyright (C) 2007 Julien Rebetez <julienr@svn.gnome.org>
24// Copyright (C) 2008 Iñigo Martínez <inigomartinez@gmail.com>
25// Copyright (C) 2008 Brad Hards <bradh@kde.org>
26// Copyright (C) 2008 Ilya Gorenbein <igorenbein@finjan.com>
27//
28// To see a description of the changes please see the Changelog file that
29// came with your tarball or type make ChangeLog if you are building from git
30//
31//========================================================================
32
33#include <config.h>
34
35#ifdef USE_GCC_PRAGMAS
36#pragma implementation
37#endif
38
39#include <stddef.h>
40#include <limits.h>
41#include "GlobalParams.h"
42#include "Object.h"
43#include "Array.h"
44#include "Dict.h"
45#include "XRef.h"
46#include "Link.h"
47#include "OutputDev.h"
48#ifndef PDF_PARSER_ONLY
49#include "Gfx.h"
50#include "GfxState.h"
51#include "Annot.h"
52#include "TextOutputDev.h"
53#include "Form.h"
54#endif
55#include "Error.h"
56#include "Page.h"
57#include "Catalog.h"
58#include "Form.h"
59
60//------------------------------------------------------------------------
61// PDFRectangle
62//------------------------------------------------------------------------
63
64void PDFRectangle::clipTo(PDFRectangle *rect) {
65  if (x1 < rect->x1) {
66    x1 = rect->x1;
67  } else if (x1 > rect->x2) {
68    x1 = rect->x2;
69  }
70  if (x2 < rect->x1) {
71    x2 = rect->x1;
72  } else if (x2 > rect->x2) {
73    x2 = rect->x2;
74  }
75  if (y1 < rect->y1) {
76    y1 = rect->y1;
77  } else if (y1 > rect->y2) {
78    y1 = rect->y2;
79  }
80  if (y2 < rect->y1) {
81    y2 = rect->y1;
82  } else if (y2 > rect->y2) {
83    y2 = rect->y2;
84  }
85}
86
87//------------------------------------------------------------------------
88// PageAttrs
89//------------------------------------------------------------------------
90
91PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) {
92  Object obj1;
93  PDFRectangle mBox;
94
95  // get old/default values
96  if (attrs) {
97    mediaBox = attrs->mediaBox;
98    cropBox = attrs->cropBox;
99    haveCropBox = attrs->haveCropBox;
100    rotate = attrs->rotate;
101    attrs->resources.copy(&resources);
102  } else {
103    // set default MediaBox to 8.5" x 11" -- this shouldn't be necessary
104    // but some (non-compliant) PDF files don't specify a MediaBox
105    mediaBox.x1 = 0;
106    mediaBox.y1 = 0;
107    mediaBox.x2 = 612;
108    mediaBox.y2 = 792;
109    cropBox.x1 = cropBox.y1 = cropBox.x2 = cropBox.y2 = 0;
110    haveCropBox = gFalse;
111    rotate = 0;
112    resources.initNull();
113  }
114
115  // media box
116  if (readBox(dict, "MediaBox", &mBox)) {
117    mediaBox = mBox;
118  }
119
120  // crop box
121  if (readBox(dict, "CropBox", &cropBox)) {
122    haveCropBox = gTrue;
123  }
124  if (!haveCropBox) {
125    cropBox = mediaBox;
126  }
127  else
128  {
129    // cropBox can not be bigger than mediaBox
130    if (cropBox.x2 - cropBox.x1 > mediaBox.x2 - mediaBox.x1)
131    {
132      cropBox.x1 = mediaBox.x1;
133      cropBox.x2 = mediaBox.x2;
134    }
135    if (cropBox.y2 - cropBox.y1 > mediaBox.y2 - mediaBox.y1)
136    {
137      cropBox.y1 = mediaBox.y1;
138      cropBox.y2 = mediaBox.y2;
139    }
140  }
141
142  // other boxes
143  bleedBox = cropBox;
144  readBox(dict, "BleedBox", &bleedBox);
145  trimBox = cropBox;
146  readBox(dict, "TrimBox", &trimBox);
147  artBox = cropBox;
148  readBox(dict, "ArtBox", &artBox);
149
150  // clip all other boxes to the media box
151  cropBox.clipTo(&mediaBox);
152  bleedBox.clipTo(&mediaBox);
153  trimBox.clipTo(&mediaBox);
154  artBox.clipTo(&mediaBox);
155
156  // rotate
157  dict->lookup("Rotate", &obj1);
158  if (obj1.isInt()) {
159    rotate = obj1.getInt();
160  }
161  obj1.free();
162  while (rotate < 0) {
163    rotate += 360;
164  }
165  while (rotate >= 360) {
166    rotate -= 360;
167  }
168
169  // misc attributes
170  dict->lookup("LastModified", &lastModified);
171  dict->lookup("BoxColorInfo", &boxColorInfo);
172  dict->lookup("Group", &group);
173  dict->lookup("Metadata", &metadata);
174  dict->lookup("PieceInfo", &pieceInfo);
175  dict->lookup("SeparationInfo", &separationInfo);
176
177  // resource dictionary
178  dict->lookup("Resources", &obj1);
179  if (obj1.isDict()) {
180    resources.free();
181    obj1.copy(&resources);
182  }
183  obj1.free();
184}
185
186PageAttrs::~PageAttrs() {
187  lastModified.free();
188  boxColorInfo.free();
189  group.free();
190  metadata.free();
191  pieceInfo.free();
192  separationInfo.free();
193  resources.free();
194}
195
196GBool PageAttrs::readBox(Dict *dict, char *key, PDFRectangle *box) {
197  PDFRectangle tmp;
198  double t;
199  Object obj1, obj2;
200  GBool ok;
201
202  dict->lookup(key, &obj1);
203  if (obj1.isArray() && obj1.arrayGetLength() == 4) {
204    ok = gTrue;
205    obj1.arrayGet(0, &obj2);
206    if (obj2.isNum()) {
207      tmp.x1 = obj2.getNum();
208    } else {
209      ok = gFalse;
210    }
211    obj2.free();
212    obj1.arrayGet(1, &obj2);
213    if (obj2.isNum()) {
214      tmp.y1 = obj2.getNum();
215    } else {
216      ok = gFalse;
217    }
218    obj2.free();
219    obj1.arrayGet(2, &obj2);
220    if (obj2.isNum()) {
221      tmp.x2 = obj2.getNum();
222    } else {
223      ok = gFalse;
224    }
225    obj2.free();
226    obj1.arrayGet(3, &obj2);
227    if (obj2.isNum()) {
228      tmp.y2 = obj2.getNum();
229    } else {
230      ok = gFalse;
231    }
232    obj2.free();
233    if (tmp.x1 == 0 && tmp.x2 == 0 && tmp.y1 == 0 && tmp.y2 == 0)
234      ok = gFalse;
235    if (ok) {
236      if (tmp.x1 > tmp.x2) {
237        t = tmp.x1; tmp.x1 = tmp.x2; tmp.x2 = t;
238      }
239      if (tmp.y1 > tmp.y2) {
240        t = tmp.y1; tmp.y1 = tmp.y2; tmp.y2 = t;
241      }
242      *box = tmp;
243    }
244  } else {
245    ok = gFalse;
246  }
247  obj1.free();
248  return ok;
249}
250
251//------------------------------------------------------------------------
252// Page
253//------------------------------------------------------------------------
254
255Page::Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA, Form *form) {
256  Object tmp;
257       
258  ok = gTrue;
259  xref = xrefA;
260  num = numA;
261  duration = -1;
262  pageWidgets = NULL;
263
264  // get attributes
265  attrs = attrsA;
266
267  // transtion
268  pageDict->lookupNF("Trans", &trans);
269  if (!(trans.isDict() || trans.isNull())) {
270    error(-1, "Page transition object (page %d) is wrong type (%s)",
271          num, trans.getTypeName());
272    trans.free();
273  }
274
275  // duration
276  pageDict->lookupNF("Dur", &tmp);
277  if (!(tmp.isNum() || tmp.isNull())) {
278    error(-1, "Page duration object (page %d) is wrong type (%s)",
279          num, tmp.getTypeName());
280  } else if (tmp.isNum()) {
281    duration = tmp.getNum();
282  }
283  tmp.free();
284
285  // annotations
286  pageDict->lookupNF("Annots", &annots);
287  if (!(annots.isRef() || annots.isArray() || annots.isNull())) {
288    error(-1, "Page annotations object (page %d) is wrong type (%s)",
289          num, annots.getTypeName());
290    annots.free();
291    goto err2;
292  }
293
294  // forms
295  pageWidgets = new FormPageWidgets(xrefA, this->getAnnots(&tmp),num,form);
296  tmp.free();
297
298  // contents
299  pageDict->lookupNF("Contents", &contents);
300  if (!(contents.isRef() || contents.isArray() ||
301        contents.isNull())) {
302    error(-1, "Page contents object (page %d) is wrong type (%s)",
303          num, contents.getTypeName());
304    contents.free();
305    goto err1;
306  }
307
308  // thumb
309  pageDict->lookupNF("Thumb", &thumb);
310  if (!(thumb.isStream() || thumb.isNull() || thumb.isRef())) {
311      error(-1, "Page thumb object (page %d) is wrong type (%s)",
312            num, thumb.getTypeName());
313      thumb.initNull(); 
314  }
315
316  // actions
317  pageDict->lookupNF("AA", &actions);
318  if (!(actions.isDict() || actions.isNull())) {
319      error(-1, "Page additional action object (page %d) is wrong type (%s)",
320            num, actions.getTypeName());
321      actions.initNull();
322  }
323 
324  return;
325
326  trans.initNull();
327 err2:
328  annots.initNull();
329 err1:
330  contents.initNull();
331  ok = gFalse;
332}
333
334Page::~Page() {
335  delete pageWidgets;
336  delete attrs;
337  annots.free();
338  contents.free();
339  trans.free();
340  thumb.free();
341  actions.free();
342}
343
344Annots *Page::getAnnots(Catalog *catalog) {
345  Annots *annots;
346  Object obj;
347
348  annots = new Annots(xref, catalog, getAnnots(&obj));
349  obj.free();
350  return annots;
351}
352
353Links *Page::getLinks(Catalog *catalog) {
354  Links *links;
355  Object obj;
356
357  links = new Links(getAnnots(&obj), catalog->getBaseURI());
358  obj.free();
359  return links;
360}
361
362void Page::display(OutputDev *out, double hDPI, double vDPI,
363                   int rotate, GBool useMediaBox, GBool crop,
364                   GBool printing, Catalog *catalog,
365                   GBool (*abortCheckCbk)(void *data),
366                   void *abortCheckCbkData,
367                   GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
368                   void *annotDisplayDecideCbkData) {
369  displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop, -1, -1, -1, -1, printing, catalog,
370               abortCheckCbk, abortCheckCbkData,
371               annotDisplayDecideCbk, annotDisplayDecideCbkData);
372}
373
374Gfx *Page::createGfx(OutputDev *out, double hDPI, double vDPI,
375                     int rotate, GBool useMediaBox, GBool crop,
376                     int sliceX, int sliceY, int sliceW, int sliceH,
377                     GBool printing, Catalog *catalog,
378                     GBool (*abortCheckCbk)(void *data),
379                     void *abortCheckCbkData,
380                     GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
381                     void *annotDisplayDecideCbkData) {
382  PDFRectangle *mediaBox, *cropBox;
383  PDFRectangle box;
384  Gfx *gfx;
385
386  rotate += getRotate();
387  if (rotate >= 360) {
388    rotate -= 360;
389  } else if (rotate < 0) {
390    rotate += 360;
391  }
392
393  makeBox(hDPI, vDPI, rotate, useMediaBox, out->upsideDown(),
394          sliceX, sliceY, sliceW, sliceH, &box, &crop);
395  cropBox = getCropBox();
396  mediaBox = getMediaBox();
397
398  if (globalParams->getPrintCommands()) {
399    printf("***** MediaBox = ll:%g,%g ur:%g,%g\n",
400            mediaBox->x1, mediaBox->y1, mediaBox->x2, mediaBox->y2);
401      printf("***** CropBox = ll:%g,%g ur:%g,%g\n",
402             cropBox->x1, cropBox->y1, cropBox->x2, cropBox->y2);
403    printf("***** Rotate = %d\n", attrs->getRotate());
404  }
405
406  gfx = new Gfx(xref, out, num, attrs->getResourceDict(), catalog,
407                hDPI, vDPI, &box, crop ? cropBox : (PDFRectangle *)NULL,
408                rotate, abortCheckCbk, abortCheckCbkData);
409
410  return gfx;
411}
412
413void Page::displaySlice(OutputDev *out, double hDPI, double vDPI,
414                        int rotate, GBool useMediaBox, GBool crop,
415                        int sliceX, int sliceY, int sliceW, int sliceH,
416                        GBool printing, Catalog *catalog,
417                        GBool (*abortCheckCbk)(void *data),
418                        void *abortCheckCbkData,
419                        GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
420                        void *annotDisplayDecideCbkData) {
421  Gfx *gfx;
422  Object obj;
423  Annots *annotList;
424  int i;
425 
426  if (!out->checkPageSlice(this, hDPI, vDPI, rotate, useMediaBox, crop,
427                           sliceX, sliceY, sliceW, sliceH,
428                           printing, catalog,
429                           abortCheckCbk, abortCheckCbkData)) {
430    return;
431  }
432
433  gfx = createGfx(out, hDPI, vDPI, rotate, useMediaBox, crop,
434                  sliceX, sliceY, sliceW, sliceH,
435                  printing, catalog,
436                  abortCheckCbk, abortCheckCbkData,
437                  annotDisplayDecideCbk, annotDisplayDecideCbkData);
438
439  contents.fetch(xref, &obj);
440  if (!obj.isNull()) {
441    gfx->saveState();
442    gfx->display(&obj);
443    gfx->restoreState();
444  }
445  obj.free();
446
447  // draw annotations
448  annotList = new Annots(xref, catalog, getAnnots(&obj));
449  obj.free();
450 
451  if (annotList->getNumAnnots() > 0) {
452    if (globalParams->getPrintCommands()) {
453      printf("***** Annotations\n");
454    }
455    for (i = 0; i < annotList->getNumAnnots(); ++i) {
456        Annot *annot = annotList->getAnnot(i);
457        if ((annotDisplayDecideCbk &&
458             (*annotDisplayDecideCbk)(annot, annotDisplayDecideCbkData)) || 
459            !annotDisplayDecideCbk) {
460             annotList->getAnnot(i)->draw(gfx, printing);
461        }
462    }
463    out->dump();
464  }
465  delete annotList;
466
467  delete gfx;
468}
469
470void Page::display(Gfx *gfx) {
471  Object obj;
472
473  contents.fetch(xref, &obj);
474  if (!obj.isNull()) {
475    gfx->saveState();
476    gfx->display(&obj);
477    gfx->restoreState();
478  }
479  obj.free();
480}
481
482GBool Page::loadThumb(unsigned char **data_out,
483                      int *width_out, int *height_out,
484                      int *rowstride_out)
485{
486  unsigned int pixbufdatasize;
487  int width, height, bits;
488  Object obj1, fetched_thumb;
489  Dict *dict;
490  GfxColorSpace *colorSpace;
491  GBool success = gFalse;
492  Stream *str;
493  GfxImageColorMap *colorMap;
494
495  /* Get stream dict */
496  thumb.fetch(xref, &fetched_thumb);
497  if (!fetched_thumb.isStream()) {
498    fetched_thumb.free();
499    return gFalse;
500  }
501
502  dict = fetched_thumb.streamGetDict();
503  str = fetched_thumb.getStream(); 
504               
505  if (!dict->lookupInt("Width", "W", &width))
506    goto fail1;
507  if (!dict->lookupInt("Height", "H", &height))
508    goto fail1;
509  if (!dict->lookupInt("BitsPerComponent", "BPC", &bits))
510    goto fail1;
511               
512  /* Check for invalid dimensions and integer overflow. */
513  if (width <= 0 || height <= 0)
514    goto fail1;
515  if (width > INT_MAX / 3 / height)
516    goto fail1;
517  pixbufdatasize = width * height * 3;
518
519  /* Get color space */
520  dict->lookup ("ColorSpace", &obj1);
521  if (obj1.isNull ()) {
522    obj1.free ();
523    dict->lookup ("CS", &obj1);
524  }
525  colorSpace = GfxColorSpace::parse(&obj1);
526  obj1.free();
527  if (!colorSpace) {
528    fprintf (stderr, "Error: Cannot parse color space\n");
529    goto fail1;
530  }
531
532  dict->lookup("Decode", &obj1);
533  if (obj1.isNull()) {
534    obj1.free();
535    dict->lookup("D", &obj1);
536  }
537  colorMap = new GfxImageColorMap(bits, &obj1, colorSpace);
538  obj1.free();
539  if (!colorMap->isOk()) {
540    fprintf (stderr, "Error: invalid colormap\n");
541    delete colorMap;
542    goto fail1;
543  }
544
545  if (data_out) {
546    unsigned char *pixbufdata = (unsigned char *) gmalloc(pixbufdatasize);
547    unsigned char *p = pixbufdata;
548    ImageStream *imgstr = new ImageStream(str, width,
549                           colorMap->getNumPixelComps(),
550                           colorMap->getBits());
551    imgstr->reset();
552    for (int row = 0; row < height; ++row) {
553      for (int col = 0; col < width; ++col) {
554        Guchar pix[gfxColorMaxComps];
555        GfxRGB rgb;
556
557        imgstr->getPixel(pix);
558        colorMap->getRGB(pix, &rgb);
559
560        *p++ = colToByte(rgb.r);
561        *p++ = colToByte(rgb.g);
562        *p++ = colToByte(rgb.b);
563      }
564    }
565    *data_out = pixbufdata;
566    delete imgstr;
567  }
568
569  success = gTrue;
570
571  if (width_out)
572    *width_out = width;
573  if (height_out)
574    *height_out = height;
575  if (rowstride_out)
576    *rowstride_out = width * 3;
577
578  delete colorMap;
579 fail1:
580  fetched_thumb.free();
581
582  return success;
583}
584
585void Page::makeBox(double hDPI, double vDPI, int rotate,
586                   GBool useMediaBox, GBool upsideDown,
587                   double sliceX, double sliceY, double sliceW, double sliceH,
588                   PDFRectangle *box, GBool *crop) {
589  PDFRectangle *mediaBox, *cropBox, *baseBox;
590  double kx, ky;
591
592  mediaBox = getMediaBox();
593  cropBox = getCropBox();
594  if (sliceW >= 0 && sliceH >= 0) {
595    baseBox = useMediaBox ? mediaBox : cropBox;
596    kx = 72.0 / hDPI;
597    ky = 72.0 / vDPI;
598    if (rotate == 90) {
599      if (upsideDown) {
600        box->x1 = baseBox->x1 + ky * sliceY;
601        box->x2 = baseBox->x1 + ky * (sliceY + sliceH);
602      } else {
603        box->x1 = baseBox->x2 - ky * (sliceY + sliceH);
604        box->x2 = baseBox->x2 - ky * sliceY;
605      }
606      box->y1 = baseBox->y1 + kx * sliceX;
607      box->y2 = baseBox->y1 + kx * (sliceX + sliceW);
608    } else if (rotate == 180) {
609      box->x1 = baseBox->x2 - kx * (sliceX + sliceW);
610      box->x2 = baseBox->x2 - kx * sliceX;
611      if (upsideDown) {
612        box->y1 = baseBox->y1 + ky * sliceY;
613        box->y2 = baseBox->y1 + ky * (sliceY + sliceH);
614      } else {
615        box->y1 = baseBox->y2 - ky * (sliceY + sliceH);
616        box->y2 = baseBox->y2 - ky * sliceY;
617      }
618    } else if (rotate == 270) {
619      if (upsideDown) {
620        box->x1 = baseBox->x2 - ky * (sliceY + sliceH);
621        box->x2 = baseBox->x2 - ky * sliceY;
622      } else {
623        box->x1 = baseBox->x1 + ky * sliceY;
624        box->x2 = baseBox->x1 + ky * (sliceY + sliceH);
625      }
626      box->y1 = baseBox->y2 - kx * (sliceX + sliceW);
627      box->y2 = baseBox->y2 - kx * sliceX;
628    } else {
629      box->x1 = baseBox->x1 + kx * sliceX;
630      box->x2 = baseBox->x1 + kx * (sliceX + sliceW);
631      if (upsideDown) {
632        box->y1 = baseBox->y2 - ky * (sliceY + sliceH);
633        box->y2 = baseBox->y2 - ky * sliceY;
634      } else {
635        box->y1 = baseBox->y1 + ky * sliceY;
636        box->y2 = baseBox->y1 + ky * (sliceY + sliceH);
637      }
638    }
639  } else if (useMediaBox) {
640    *box = *mediaBox;
641  } else {
642    *box = *cropBox;
643    *crop = gFalse;
644  }
645}
646
647void Page::processLinks(OutputDev *out, Catalog *catalog) {
648  Links *links;
649  int i;
650
651  links = getLinks(catalog);
652  for (i = 0; i < links->getNumLinks(); ++i) {
653    out->processLink(links->getLink(i), catalog);
654  }
655  delete links;
656}
657
658void Page::getDefaultCTM(double *ctm, double hDPI, double vDPI,
659                         int rotate, GBool useMediaBox, GBool upsideDown) {
660  GfxState *state;
661  int i;
662  rotate += getRotate();
663  if (rotate >= 360) {
664    rotate -= 360;
665  } else if (rotate < 0) {
666    rotate += 360;
667  }
668  state = new GfxState(hDPI, vDPI,
669                       useMediaBox ? getMediaBox() : getCropBox(),
670                       rotate, upsideDown);
671  for (i = 0; i < 6; ++i) {
672    ctm[i] = state->getCTM()[i];
673  }
674 delete state;
675}
Note: See TracBrowser for help on using the repository browser.