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

Last change on this file since 134 was 134, checked in by Eugene Romanenko, 15 years ago

poppler updated to version 0.5.4

File size: 13.2 KB
Line 
1//========================================================================
2//
3// Page.cc
4//
5// Copyright 1996-2003 Glyph & Cog, LLC
6//
7//========================================================================
8
9#include <config.h>
10
11#ifdef USE_GCC_PRAGMAS
12#pragma implementation
13#endif
14
15#include <stddef.h>
16#include <limits.h>
17#include "GlobalParams.h"
18#include "Object.h"
19#include "Array.h"
20#include "Dict.h"
21#include "XRef.h"
22#include "Link.h"
23#include "OutputDev.h"
24#ifndef PDF_PARSER_ONLY
25#include "Gfx.h"
26#include "GfxState.h"
27#include "Annot.h"
28#include "TextOutputDev.h"
29#endif
30#include "Error.h"
31#include "Page.h"
32#include "UGooString.h"
33
34//------------------------------------------------------------------------
35// PageAttrs
36//------------------------------------------------------------------------
37
38PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) {
39  Object obj1;
40
41  // get old/default values
42  if (attrs) {
43    mediaBox = attrs->mediaBox;
44    cropBox = attrs->cropBox;
45    haveCropBox = attrs->haveCropBox;
46    rotate = attrs->rotate;
47    attrs->resources.copy(&resources);
48  } else {
49    // set default MediaBox to 8.5" x 11" -- this shouldn't be necessary
50    // but some (non-compliant) PDF files don't specify a MediaBox
51    mediaBox.x1 = 0;
52    mediaBox.y1 = 0;
53    mediaBox.x2 = 612;
54    mediaBox.y2 = 792;
55    cropBox.x1 = cropBox.y1 = cropBox.x2 = cropBox.y2 = 0;
56    haveCropBox = gFalse;
57    rotate = 0;
58    resources.initNull();
59  }
60
61  // media box
62  readBox(dict, "MediaBox", &mediaBox);
63
64  // crop box
65  if (readBox(dict, "CropBox", &cropBox)) {
66    haveCropBox = gTrue;
67  }
68  if (!haveCropBox) {
69    cropBox = mediaBox;
70  }
71  else
72  {
73    // cropBox can not be bigger than mediaBox
74    if (cropBox.x2 - cropBox.x1 > mediaBox.x2 - mediaBox.x1)
75    {
76      cropBox.x1 = mediaBox.x1;
77      cropBox.x2 = mediaBox.x2;
78    }
79    if (cropBox.y2 - cropBox.y1 > mediaBox.y2 - mediaBox.y1)
80    {
81      cropBox.y1 = mediaBox.y1;
82      cropBox.y2 = mediaBox.y2;
83    }
84  }
85
86  // other boxes
87  bleedBox = cropBox;
88  readBox(dict, "BleedBox", &bleedBox);
89  trimBox = cropBox;
90  readBox(dict, "TrimBox", &trimBox);
91  artBox = cropBox;
92  readBox(dict, "ArtBox", &artBox);
93
94  // rotate
95  dict->lookup("Rotate", &obj1);
96  if (obj1.isInt()) {
97    rotate = obj1.getInt();
98  }
99  obj1.free();
100  while (rotate < 0) {
101    rotate += 360;
102  }
103  while (rotate >= 360) {
104    rotate -= 360;
105  }
106
107  // misc attributes
108  dict->lookup("LastModified", &lastModified);
109  dict->lookup("BoxColorInfo", &boxColorInfo);
110  dict->lookup("Group", &group);
111  dict->lookup("Metadata", &metadata);
112  dict->lookup("PieceInfo", &pieceInfo);
113  dict->lookup("SeparationInfo", &separationInfo);
114
115  // resource dictionary
116  dict->lookup("Resources", &obj1);
117  if (obj1.isDict()) {
118    resources.free();
119    obj1.copy(&resources);
120  }
121  obj1.free();
122}
123
124PageAttrs::~PageAttrs() {
125  lastModified.free();
126  boxColorInfo.free();
127  group.free();
128  metadata.free();
129  pieceInfo.free();
130  separationInfo.free();
131  resources.free();
132}
133
134GBool PageAttrs::readBox(Dict *dict, char *key, PDFRectangle *box) {
135  PDFRectangle tmp;
136  double t;
137  Object obj1, obj2;
138  GBool ok;
139
140  dict->lookup(key, &obj1);
141  if (obj1.isArray() && obj1.arrayGetLength() == 4) {
142    ok = gTrue;
143    obj1.arrayGet(0, &obj2);
144    if (obj2.isNum()) {
145      tmp.x1 = obj2.getNum();
146    } else {
147      ok = gFalse;
148    }
149    obj2.free();
150    obj1.arrayGet(1, &obj2);
151    if (obj2.isNum()) {
152      tmp.y1 = obj2.getNum();
153    } else {
154      ok = gFalse;
155    }
156    obj2.free();
157    obj1.arrayGet(2, &obj2);
158    if (obj2.isNum()) {
159      tmp.x2 = obj2.getNum();
160    } else {
161      ok = gFalse;
162    }
163    obj2.free();
164    obj1.arrayGet(3, &obj2);
165    if (obj2.isNum()) {
166      tmp.y2 = obj2.getNum();
167    } else {
168      ok = gFalse;
169    }
170    obj2.free();
171    if (ok) {
172      if (tmp.x1 > tmp.x2) {
173        t = tmp.x1; tmp.x1 = tmp.x2; tmp.x2 = t;
174      }
175      if (tmp.y1 > tmp.y2) {
176        t = tmp.y1; tmp.y1 = tmp.y2; tmp.y2 = t;
177      }
178      *box = tmp;
179    }
180  } else {
181    ok = gFalse;
182  }
183  obj1.free();
184  return ok;
185}
186
187//------------------------------------------------------------------------
188// Page
189//------------------------------------------------------------------------
190
191Page::Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA) {
192  ok = gTrue;
193  xref = xrefA;
194  num = numA;
195
196  // get attributes
197  attrs = attrsA;
198
199  // transtion
200  pageDict->lookupNF("Trans", &trans);
201  if (!(trans.isDict() || trans.isNull())) {
202    error(-1, "Page transition object (page %d) is wrong type (%s)",
203          num, trans.getTypeName());
204    trans.free();
205  }
206
207  // annotations
208  pageDict->lookupNF("Annots", &annots);
209  if (!(annots.isRef() || annots.isArray() || annots.isNull())) {
210    error(-1, "Page annotations object (page %d) is wrong type (%s)",
211          num, annots.getTypeName());
212    annots.free();
213    goto err2;
214  }
215
216  // contents
217  pageDict->lookupNF("Contents", &contents);
218  if (!(contents.isRef() || contents.isArray() ||
219        contents.isNull())) {
220    error(-1, "Page contents object (page %d) is wrong type (%s)",
221          num, contents.getTypeName());
222    contents.free();
223    goto err1;
224  }
225
226  // thumb
227  pageDict->lookupNF("Thumb", &thumb);
228  if (!(thumb.isStream() || thumb.isNull() || thumb.isRef())) {
229      error(-1, "Page thumb object (page %d) is wrong type (%s)",
230            num, thumb.getTypeName());
231      thumb.initNull(); 
232  }
233 
234  return;
235
236 err3:
237  trans.initNull();
238 err2:
239  annots.initNull();
240 err1:
241  contents.initNull();
242  ok = gFalse;
243}
244
245Page::~Page() {
246  delete attrs;
247  annots.free();
248  contents.free();
249}
250
251void Page::display(OutputDev *out, double hDPI, double vDPI,
252                   int rotate, GBool useMediaBox, GBool crop,
253                   Links *links, Catalog *catalog,
254                   GBool (*abortCheckCbk)(void *data),
255                   void *abortCheckCbkData,
256                   GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
257                   void *annotDisplayDecideCbkData) {
258  displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop, -1, -1, -1, -1, links, catalog,
259               abortCheckCbk, abortCheckCbkData,
260               annotDisplayDecideCbk, annotDisplayDecideCbkData);
261}
262
263Gfx *Page::createGfx(OutputDev *out, double hDPI, double vDPI,
264                     int rotate, GBool useMediaBox, GBool crop,
265                     int sliceX, int sliceY, int sliceW, int sliceH,
266                     Links *links, Catalog *catalog,
267                     GBool (*abortCheckCbk)(void *data),
268                     void *abortCheckCbkData,
269                     GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
270                     void *annotDisplayDecideCbkData) {
271  PDFRectangle *mediaBox, *cropBox, *baseBox;
272  PDFRectangle box;
273  Gfx *gfx;
274  double kx, ky;
275
276  rotate += getRotate();
277  if (rotate >= 360) {
278    rotate -= 360;
279  } else if (rotate < 0) {
280    rotate += 360;
281  }
282
283  mediaBox = getMediaBox();
284  cropBox = getCropBox();
285  if (sliceW >= 0 && sliceH >= 0) {
286    baseBox =  useMediaBox ? mediaBox : cropBox;
287    kx = 72.0 / hDPI;
288    ky = 72.0 / vDPI;
289    if (rotate == 90) {
290      if (out->upsideDown()) {
291        box.x1 = baseBox->x1 + ky * sliceY;
292        box.x2 = baseBox->x1 + ky * (sliceY + sliceH);
293      } else {
294        box.x1 = baseBox->x2 - ky * (sliceY + sliceH);
295        box.x2 = baseBox->x2 - ky * sliceY;
296      }
297      box.y1 = baseBox->y1 + kx * sliceX;
298      box.y2 = baseBox->y1 + kx * (sliceX + sliceW);
299    } else if (rotate == 180) {
300      box.x1 = baseBox->x2 - kx * (sliceX + sliceW);
301      box.x2 = baseBox->x2 - kx * sliceX;
302      if (out->upsideDown()) {
303        box.y1 = baseBox->y1 + ky * sliceY;
304        box.y2 = baseBox->y1 + ky * (sliceY + sliceH);
305      } else {
306        box.y1 = baseBox->y2 - ky * (sliceY + sliceH);
307        box.y2 = baseBox->y2 - ky * sliceY;
308      }
309    } else if (rotate == 270) {
310      if (out->upsideDown()) {
311        box.x1 = baseBox->x2 - ky * (sliceY + sliceH);
312        box.x2 = baseBox->x2 - ky * sliceY;
313      } else {
314        box.x1 = baseBox->x1 + ky * sliceY;
315        box.x2 = baseBox->x1 + ky * (sliceY + sliceH);
316      }
317      box.y1 = baseBox->y2 - kx * (sliceX + sliceW);
318      box.y2 = baseBox->y2 - kx * sliceX;
319    } else {
320      box.x1 = baseBox->x1 + kx * sliceX;
321      box.x2 = baseBox->x1 + kx * (sliceX + sliceW);
322      if (out->upsideDown()) {
323        box.y1 = baseBox->y2 - ky * (sliceY + sliceH);
324        box.y2 = baseBox->y2 - ky * sliceY;
325      } else {
326        box.y1 = baseBox->y1 + ky * sliceY;
327        box.y2 = baseBox->y1 + ky * (sliceY + sliceH);
328      }
329    }
330  } else if (useMediaBox) {
331    box = *mediaBox;
332  } else {
333    box = *cropBox;
334    crop = gFalse;
335  }
336
337  if (globalParams->getPrintCommands()) {
338    printf("***** MediaBox = ll:%g,%g ur:%g,%g\n",
339            mediaBox->x1, mediaBox->y1, mediaBox->x2, mediaBox->y2);
340      printf("***** CropBox = ll:%g,%g ur:%g,%g\n",
341             cropBox->x1, cropBox->y1, cropBox->x2, cropBox->y2);
342    printf("***** Rotate = %d\n", attrs->getRotate());
343  }
344
345  gfx = new Gfx(xref, out, num, attrs->getResourceDict(),
346                hDPI, vDPI, &box, crop ? cropBox : (PDFRectangle *)NULL,
347                rotate, abortCheckCbk, abortCheckCbkData);
348
349  return gfx;
350}
351
352void Page::displaySlice(OutputDev *out, double hDPI, double vDPI,
353                        int rotate, GBool useMediaBox, GBool crop,
354                        int sliceX, int sliceY, int sliceW, int sliceH,
355                        Links *links, Catalog *catalog,
356                        GBool (*abortCheckCbk)(void *data),
357                        void *abortCheckCbkData,
358                        GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
359                        void *annotDisplayDecideCbkData) {
360  Gfx *gfx;
361  Object obj;
362  Link *link;
363  Annots *annotList;
364  int i;
365
366  gfx = createGfx(out, hDPI, vDPI, rotate, useMediaBox, crop,
367                  sliceX, sliceY, sliceW, sliceH,
368                  links, catalog,
369                  abortCheckCbk, abortCheckCbkData,
370                  annotDisplayDecideCbk, annotDisplayDecideCbkData);
371
372  contents.fetch(xref, &obj);
373  if (!obj.isNull()) {
374    gfx->saveState();
375    gfx->display(&obj);
376    gfx->restoreState();
377  }
378  obj.free();
379
380  // draw links
381  if (links) {
382    gfx->saveState();
383    for (i = 0; i < links->getNumLinks(); ++i) {
384      link = links->getLink(i);
385      out->drawLink(link, catalog);
386    }
387    gfx->restoreState();
388    out->dump();
389  }
390
391  // draw non-link annotations
392  annotList = new Annots(xref, catalog, annots.fetch(xref, &obj));
393  obj.free();
394  if (annotList->getNumAnnots() > 0) {
395    if (globalParams->getPrintCommands()) {
396      printf("***** Annotations\n");
397    }
398    for (i = 0; i < annotList->getNumAnnots(); ++i) {
399        Annot *annot = annotList->getAnnot(i);
400        if ((annotDisplayDecideCbk &&
401             (*annotDisplayDecideCbk)(annot, annotDisplayDecideCbkData)) || 
402            !annotDisplayDecideCbk)
403          annot->draw(gfx); 
404    }
405    out->dump();
406  }
407  delete annotList;
408
409  delete gfx;
410}
411
412void Page::display(Gfx *gfx) {
413  Object obj;
414
415  contents.fetch(xref, &obj);
416  if (!obj.isNull()) {
417    gfx->saveState();
418    gfx->display(&obj);
419    gfx->restoreState();
420  }
421  obj.free();
422}
423
424GBool Page::loadThumb(unsigned char **data_out,
425                      int *width_out, int *height_out,
426                      int *rowstride_out)
427{
428  ImageStream *imgstr;
429  unsigned char *pixbufdata;
430  unsigned int pixbufdatasize;
431  int row, col;
432  int width, height, bits;
433  unsigned char *p;
434  Object obj1, fetched_thumb;
435  Dict *dict;
436  GfxColorSpace *colorSpace;
437  GBool success = gFalse;
438  Stream *str;
439  GfxImageColorMap *colorMap;
440
441  /* Get stream dict */
442  thumb.fetch(xref, &fetched_thumb);
443  if (fetched_thumb.isNull()) {
444    fetched_thumb.free();
445    return gFalse;
446  }
447
448  dict = fetched_thumb.streamGetDict();
449  str = fetched_thumb.getStream(); 
450               
451  if (!dict->lookupInt("Width", "W", &width))
452    goto fail1;
453  if (!dict->lookupInt("Height", "H", &height))
454    goto fail1;
455  if (!dict->lookupInt("BitsPerComponent", "BPC", &bits))
456    goto fail1;
457               
458  /* Check for invalid dimensions and integer overflow. */
459  if (width <= 0 || height <= 0)
460    goto fail1;
461  if (width > INT_MAX / 3 / height)
462    goto fail1;
463  pixbufdatasize = width * height * 3;
464
465  /* Get color space */
466  dict->lookup ("ColorSpace", &obj1);
467  if (obj1.isNull ()) {
468    obj1.free ();
469    dict->lookup ("CS", &obj1);
470  }
471  colorSpace = GfxColorSpace::parse(&obj1);
472  obj1.free();
473  if (!colorSpace) {
474    fprintf (stderr, "Error: Cannot parse color space\n");
475    goto fail1;
476  }
477
478  dict->lookup("Decode", &obj1);
479  if (obj1.isNull()) {
480    obj1.free();
481    dict->lookup("D", &obj1);
482  }
483  colorMap = new GfxImageColorMap(bits, &obj1, colorSpace);
484  obj1.free();
485  if (!colorMap->isOk()) {
486    fprintf (stderr, "Error: invalid colormap\n");
487    goto fail1;
488  }
489
490  pixbufdata = (unsigned char *) gmalloc(pixbufdatasize);
491  p = pixbufdata;
492  imgstr = new ImageStream(str, width,
493                           colorMap->getNumPixelComps(),
494                           colorMap->getBits());
495  imgstr->reset();
496  for (row = 0; row < height; ++row) {
497    for (col = 0; col < width; ++col) {
498      Guchar pix[gfxColorMaxComps];
499      GfxRGB rgb;
500
501      imgstr->getPixel(pix);
502      colorMap->getRGB(pix, &rgb);
503
504      *p++ = colToByte(rgb.r);
505      *p++ = colToByte(rgb.g);
506      *p++ = colToByte(rgb.b);
507    }
508  }
509
510  success = gTrue;
511
512  if (data_out)
513    *data_out = pixbufdata;
514  if (width_out)
515    *width_out = width;
516  if (height_out)
517    *height_out = height;
518  if (rowstride_out)
519    *rowstride_out = width * 3;
520
521  delete imgstr;
522  delete colorMap;
523 fail1:
524  fetched_thumb.free();
525
526  return success;
527}
528
529void Page::getDefaultCTM(double *ctm, double hDPI, double vDPI,
530                         int rotate, GBool upsideDown) {
531  GfxState *state;
532  int i;
533  rotate += getRotate();
534  if (rotate >= 360) {
535    rotate -= 360;
536  } else if (rotate < 0) {
537    rotate += 360;
538  }
539  state = new GfxState(hDPI, vDPI, getMediaBox(), rotate, upsideDown);
540  for (i = 0; i < 6; ++i) {
541    ctm[i] = state->getCTM()[i];
542  }
543 delete state;
544}
Note: See TracBrowser for help on using the repository browser.