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

Last change on this file since 27 was 27, checked in by Eugene Romanenko, 16 years ago

poppler updated to version 0.5.2, also needed changes to be compatible with new poppler

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.