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

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

added settings dialog, asynch opening, fixed many crashes and bugs

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
352
353void Page::displaySlice(OutputDev *out, double hDPI, double vDPI,
354                        int rotate, GBool useMediaBox, GBool crop,
355                        int sliceX, int sliceY, int sliceW, int sliceH,
356                        Links *links, Catalog *catalog,
357                        GBool (*abortCheckCbk)(void *data),
358                        void *abortCheckCbkData,
359                        GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
360                        void *annotDisplayDecideCbkData) {
361  Gfx *gfx;
362  Object obj;
363  Link *link;
364  Annots *annotList;
365  int i;
366
367  gfx = createGfx(out, hDPI, vDPI, rotate, useMediaBox, crop,
368                  sliceX, sliceY, sliceW, sliceH,
369                  links, catalog,
370                  abortCheckCbk, abortCheckCbkData,
371                  annotDisplayDecideCbk, annotDisplayDecideCbkData);
372
373  contents.fetch(xref, &obj);
374  if (!obj.isNull()) {
375    gfx->saveState();
376    gfx->display(&obj);
377    gfx->restoreState();
378  }
379  obj.free();
380
381  // draw links
382  if (links) {
383    gfx->saveState();
384    for (i = 0; i < links->getNumLinks(); ++i) {
385      link = links->getLink(i);
386      out->drawLink(link, catalog);
387    }
388    gfx->restoreState();
389    out->dump();
390  }
391
392  // draw non-link annotations
393  annotList = new Annots(xref, catalog, annots.fetch(xref, &obj));
394  obj.free();
395  if (annotList->getNumAnnots() > 0) {
396    if (globalParams->getPrintCommands()) {
397      printf("***** Annotations\n");
398    }
399    for (i = 0; i < annotList->getNumAnnots(); ++i) {
400        Annot *annot = annotList->getAnnot(i);
401        if ((annotDisplayDecideCbk &&
402             (*annotDisplayDecideCbk)(annot, annotDisplayDecideCbkData)) || 
403            !annotDisplayDecideCbk)
404          annot->draw(gfx); 
405    }
406    out->dump();
407  }
408  delete annotList;
409
410  delete gfx;
411}
412
413void Page::display(Gfx *gfx) {
414  Object obj;
415
416  contents.fetch(xref, &obj);
417  if (!obj.isNull()) {
418    gfx->saveState();
419    gfx->display(&obj);
420    gfx->restoreState();
421  }
422  obj.free();
423}
424
425GBool Page::loadThumb(unsigned char **data_out,
426                      int *width_out, int *height_out,
427                      int *rowstride_out)
428{
429  ImageStream *imgstr;
430  unsigned char *pixbufdata;
431  unsigned int pixbufdatasize;
432  int row, col;
433  int width, height, bits;
434  unsigned char *p;
435  Object obj1, fetched_thumb;
436  Dict *dict;
437  GfxColorSpace *colorSpace;
438  GBool success = gFalse;
439  Stream *str;
440  GfxImageColorMap *colorMap;
441
442  /* Get stream dict */
443  thumb.fetch(xref, &fetched_thumb);
444  if (fetched_thumb.isNull()) {
445    fetched_thumb.free();
446    return gFalse;
447  }
448
449  dict = fetched_thumb.streamGetDict();
450  str = fetched_thumb.getStream(); 
451               
452  if (!dict->lookupInt("Width", "W", &width))
453    goto fail1;
454  if (!dict->lookupInt("Height", "H", &height))
455    goto fail1;
456  if (!dict->lookupInt("BitsPerComponent", "BPC", &bits))
457    goto fail1;
458               
459  /* Check for invalid dimensions and integer overflow. */
460  if (width <= 0 || height <= 0)
461    goto fail1;
462  if (width > INT_MAX / 3 / height)
463    goto fail1;
464  pixbufdatasize = width * height * 3;
465
466  /* Get color space */
467  dict->lookup ("ColorSpace", &obj1);
468  if (obj1.isNull ()) {
469    obj1.free ();
470    dict->lookup ("CS", &obj1);
471  }
472  colorSpace = GfxColorSpace::parse(&obj1);
473  obj1.free();
474  if (!colorSpace) {
475    fprintf (stderr, "Error: Cannot parse color space\n");
476    goto fail1;
477  }
478
479  dict->lookup("Decode", &obj1);
480  if (obj1.isNull()) {
481    obj1.free();
482    dict->lookup("D", &obj1);
483  }
484  colorMap = new GfxImageColorMap(bits, &obj1, colorSpace);
485  obj1.free();
486  if (!colorMap->isOk()) {
487    fprintf (stderr, "Error: invalid colormap\n");
488    goto fail1;
489  }
490
491  pixbufdata = (unsigned char *) gmalloc(pixbufdatasize);
492  p = pixbufdata;
493  imgstr = new ImageStream(str, width,
494                           colorMap->getNumPixelComps(),
495                           colorMap->getBits());
496  imgstr->reset();
497  for (row = 0; row < height; ++row) {
498    for (col = 0; col < width; ++col) {
499      Guchar pix[gfxColorMaxComps];
500      GfxRGB rgb;
501
502      imgstr->getPixel(pix);
503      colorMap->getRGB(pix, &rgb);
504
505      *p++ = colToByte(rgb.r);
506      *p++ = colToByte(rgb.g);
507      *p++ = colToByte(rgb.b);
508    }
509  }
510
511  success = gTrue;
512
513  if (data_out)
514    *data_out = pixbufdata;
515  if (width_out)
516    *width_out = width;
517  if (height_out)
518    *height_out = height;
519  if (rowstride_out)
520    *rowstride_out = width * 3;
521
522  delete imgstr;
523  delete colorMap;
524 fail1:
525  fetched_thumb.free();
526
527  return success;
528}
529
530void Page::getDefaultCTM(double *ctm, double hDPI, double vDPI,
531                         int rotate, GBool upsideDown) {
532  GfxState *state;
533  int i;
534  rotate += getRotate();
535  if (rotate >= 360) {
536    rotate -= 360;
537  } else if (rotate < 0) {
538    rotate += 360;
539  }
540  state = new GfxState(hDPI, vDPI, getMediaBox(), rotate, upsideDown);
541  for (i = 0; i < 6; ++i) {
542    ctm[i] = state->getCTM()[i];
543  }
544 delete state;
545}
Note: See TracBrowser for help on using the repository browser.