1 //========================================================================
5 // Copyright 1996-2003 Glyph & Cog, LLC
7 //========================================================================
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
17 #include "GlobalParams.h"
23 #include "OutputDev.h"
24 #ifndef PDF_PARSER_ONLY
28 #include "TextOutputDev.h"
32 #include "UGooString.h"
34 //------------------------------------------------------------------------
36 //------------------------------------------------------------------------
38 PageAttrs::PageAttrs(PageAttrs
*attrs
, Dict
*dict
) {
41 // get old/default values
43 mediaBox
= attrs
->mediaBox
;
44 cropBox
= attrs
->cropBox
;
45 haveCropBox
= attrs
->haveCropBox
;
46 rotate
= attrs
->rotate
;
47 attrs
->resources
.copy(&resources
);
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
55 cropBox
.x1
= cropBox
.y1
= cropBox
.x2
= cropBox
.y2
= 0;
62 readBox(dict
, "MediaBox", &mediaBox
);
65 if (readBox(dict
, "CropBox", &cropBox
)) {
73 // cropBox can not be bigger than mediaBox
74 if (cropBox
.x2
- cropBox
.x1
> mediaBox
.x2
- mediaBox
.x1
)
76 cropBox
.x1
= mediaBox
.x1
;
77 cropBox
.x2
= mediaBox
.x2
;
79 if (cropBox
.y2
- cropBox
.y1
> mediaBox
.y2
- mediaBox
.y1
)
81 cropBox
.y1
= mediaBox
.y1
;
82 cropBox
.y2
= mediaBox
.y2
;
88 readBox(dict
, "BleedBox", &bleedBox
);
90 readBox(dict
, "TrimBox", &trimBox
);
92 readBox(dict
, "ArtBox", &artBox
);
95 dict
->lookup("Rotate", &obj1
);
97 rotate
= obj1
.getInt();
103 while (rotate
>= 360) {
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
);
115 // resource dictionary
116 dict
->lookup("Resources", &obj1
);
119 obj1
.copy(&resources
);
124 PageAttrs::~PageAttrs() {
130 separationInfo
.free();
134 GBool
PageAttrs::readBox(Dict
*dict
, char *key
, PDFRectangle
*box
) {
140 dict
->lookup(key
, &obj1
);
141 if (obj1
.isArray() && obj1
.arrayGetLength() == 4) {
143 obj1
.arrayGet(0, &obj2
);
145 tmp
.x1
= obj2
.getNum();
150 obj1
.arrayGet(1, &obj2
);
152 tmp
.y1
= obj2
.getNum();
157 obj1
.arrayGet(2, &obj2
);
159 tmp
.x2
= obj2
.getNum();
164 obj1
.arrayGet(3, &obj2
);
166 tmp
.y2
= obj2
.getNum();
172 if (tmp
.x1
> tmp
.x2
) {
173 t
= tmp
.x1
; tmp
.x1
= tmp
.x2
; tmp
.x2
= t
;
175 if (tmp
.y1
> tmp
.y2
) {
176 t
= tmp
.y1
; tmp
.y1
= tmp
.y2
; tmp
.y2
= t
;
187 //------------------------------------------------------------------------
189 //------------------------------------------------------------------------
191 Page::Page(XRef
*xrefA
, int numA
, Dict
*pageDict
, PageAttrs
*attrsA
) {
203 pageDict
->lookupNF("Trans", &trans
);
204 if (!(trans
.isDict() || trans
.isNull())) {
205 error(-1, "Page transition object (page %d) is wrong type (%s)",
206 num
, trans
.getTypeName());
211 pageDict
->lookupNF("Dur", &tmp
);
212 if (!(tmp
.isNum() || tmp
.isNull())) {
213 error(-1, "Page duration object (page %d) is wrong type (%s)",
214 num
, tmp
.getTypeName());
215 } else if (tmp
.isNum()) {
216 duration
= tmp
.getNum();
221 pageDict
->lookupNF("Annots", &annots
);
222 if (!(annots
.isRef() || annots
.isArray() || annots
.isNull())) {
223 error(-1, "Page annotations object (page %d) is wrong type (%s)",
224 num
, annots
.getTypeName());
230 pageDict
->lookupNF("Contents", &contents
);
231 if (!(contents
.isRef() || contents
.isArray() ||
232 contents
.isNull())) {
233 error(-1, "Page contents object (page %d) is wrong type (%s)",
234 num
, contents
.getTypeName());
240 pageDict
->lookupNF("Thumb", &thumb
);
241 if (!(thumb
.isStream() || thumb
.isNull() || thumb
.isRef())) {
242 error(-1, "Page thumb object (page %d) is wrong type (%s)",
243 num
, thumb
.getTypeName());
248 pageDict
->lookupNF("AA", &actions
);
249 if (!(actions
.isDict() || actions
.isNull())) {
250 error(-1, "Page additional action object (page %d) is wrong type (%s)",
251 num
, actions
.getTypeName());
271 void Page::display(OutputDev
*out
, double hDPI
, double vDPI
,
272 int rotate
, GBool useMediaBox
, GBool crop
,
273 Links
*links
, Catalog
*catalog
,
274 GBool (*abortCheckCbk
)(void *data
),
275 void *abortCheckCbkData
,
276 GBool (*annotDisplayDecideCbk
)(Annot
*annot
, void *user_data
),
277 void *annotDisplayDecideCbkData
) {
278 displaySlice(out
, hDPI
, vDPI
, rotate
, useMediaBox
, crop
, -1, -1, -1, -1, links
, catalog
,
279 abortCheckCbk
, abortCheckCbkData
,
280 annotDisplayDecideCbk
, annotDisplayDecideCbkData
);
283 Gfx
*Page::createGfx(OutputDev
*out
, double hDPI
, double vDPI
,
284 int rotate
, GBool useMediaBox
, GBool crop
,
285 int sliceX
, int sliceY
, int sliceW
, int sliceH
,
286 Links
*links
, Catalog
*catalog
,
287 GBool (*abortCheckCbk
)(void *data
),
288 void *abortCheckCbkData
,
289 GBool (*annotDisplayDecideCbk
)(Annot
*annot
, void *user_data
),
290 void *annotDisplayDecideCbkData
) {
291 PDFRectangle
*mediaBox
, *cropBox
, *baseBox
;
296 rotate
+= getRotate();
299 } else if (rotate
< 0) {
303 mediaBox
= getMediaBox();
304 cropBox
= getCropBox();
305 if (sliceW
>= 0 && sliceH
>= 0) {
306 baseBox
= useMediaBox
? mediaBox
: cropBox
;
310 if (out
->upsideDown()) {
311 box
.x1
= baseBox
->x1
+ ky
* sliceY
;
312 box
.x2
= baseBox
->x1
+ ky
* (sliceY
+ sliceH
);
314 box
.x1
= baseBox
->x2
- ky
* (sliceY
+ sliceH
);
315 box
.x2
= baseBox
->x2
- ky
* sliceY
;
317 box
.y1
= baseBox
->y1
+ kx
* sliceX
;
318 box
.y2
= baseBox
->y1
+ kx
* (sliceX
+ sliceW
);
319 } else if (rotate
== 180) {
320 box
.x1
= baseBox
->x2
- kx
* (sliceX
+ sliceW
);
321 box
.x2
= baseBox
->x2
- kx
* sliceX
;
322 if (out
->upsideDown()) {
323 box
.y1
= baseBox
->y1
+ ky
* sliceY
;
324 box
.y2
= baseBox
->y1
+ ky
* (sliceY
+ sliceH
);
326 box
.y1
= baseBox
->y2
- ky
* (sliceY
+ sliceH
);
327 box
.y2
= baseBox
->y2
- ky
* sliceY
;
329 } else if (rotate
== 270) {
330 if (out
->upsideDown()) {
331 box
.x1
= baseBox
->x2
- ky
* (sliceY
+ sliceH
);
332 box
.x2
= baseBox
->x2
- ky
* sliceY
;
334 box
.x1
= baseBox
->x1
+ ky
* sliceY
;
335 box
.x2
= baseBox
->x1
+ ky
* (sliceY
+ sliceH
);
337 box
.y1
= baseBox
->y2
- kx
* (sliceX
+ sliceW
);
338 box
.y2
= baseBox
->y2
- kx
* sliceX
;
340 box
.x1
= baseBox
->x1
+ kx
* sliceX
;
341 box
.x2
= baseBox
->x1
+ kx
* (sliceX
+ sliceW
);
342 if (out
->upsideDown()) {
343 box
.y1
= baseBox
->y2
- ky
* (sliceY
+ sliceH
);
344 box
.y2
= baseBox
->y2
- ky
* sliceY
;
346 box
.y1
= baseBox
->y1
+ ky
* sliceY
;
347 box
.y2
= baseBox
->y1
+ ky
* (sliceY
+ sliceH
);
350 } else if (useMediaBox
) {
357 if (globalParams
->getPrintCommands()) {
358 printf("***** MediaBox = ll:%g,%g ur:%g,%g\n",
359 mediaBox
->x1
, mediaBox
->y1
, mediaBox
->x2
, mediaBox
->y2
);
360 printf("***** CropBox = ll:%g,%g ur:%g,%g\n",
361 cropBox
->x1
, cropBox
->y1
, cropBox
->x2
, cropBox
->y2
);
362 printf("***** Rotate = %d\n", attrs
->getRotate());
365 gfx
= new Gfx(xref
, out
, num
, attrs
->getResourceDict(),
366 hDPI
, vDPI
, &box
, crop
? cropBox
: (PDFRectangle
*)NULL
,
367 rotate
, abortCheckCbk
, abortCheckCbkData
);
372 void Page::displaySlice(OutputDev
*out
, double hDPI
, double vDPI
,
373 int rotate
, GBool useMediaBox
, GBool crop
,
374 int sliceX
, int sliceY
, int sliceW
, int sliceH
,
375 Links
*links
, Catalog
*catalog
,
376 GBool (*abortCheckCbk
)(void *data
),
377 void *abortCheckCbkData
,
378 GBool (*annotDisplayDecideCbk
)(Annot
*annot
, void *user_data
),
379 void *annotDisplayDecideCbkData
) {
386 gfx
= createGfx(out
, hDPI
, vDPI
, rotate
, useMediaBox
, crop
,
387 sliceX
, sliceY
, sliceW
, sliceH
,
389 abortCheckCbk
, abortCheckCbkData
,
390 annotDisplayDecideCbk
, annotDisplayDecideCbkData
);
392 contents
.fetch(xref
, &obj
);
403 for (i
= 0; i
< links
->getNumLinks(); ++i
) {
404 link
= links
->getLink(i
);
405 out
->drawLink(link
, catalog
);
411 // draw non-link annotations
412 annotList
= new Annots(xref
, catalog
, annots
.fetch(xref
, &obj
));
414 if (annotList
->getNumAnnots() > 0) {
415 if (globalParams
->getPrintCommands()) {
416 printf("***** Annotations\n");
418 for (i
= 0; i
< annotList
->getNumAnnots(); ++i
) {
419 Annot
*annot
= annotList
->getAnnot(i
);
420 if ((annotDisplayDecideCbk
&&
421 (*annotDisplayDecideCbk
)(annot
, annotDisplayDecideCbkData
)) ||
422 !annotDisplayDecideCbk
)
432 void Page::display(Gfx
*gfx
) {
435 contents
.fetch(xref
, &obj
);
444 GBool
Page::loadThumb(unsigned char **data_out
,
445 int *width_out
, int *height_out
,
448 ImageStream
*imgstr
= NULL
;
449 unsigned char *pixbufdata
;
450 unsigned int pixbufdatasize
;
452 int width
, height
, bits
;
454 Object obj1
, fetched_thumb
;
456 GfxColorSpace
*colorSpace
;
457 GBool success
= gFalse
;
459 GfxImageColorMap
*colorMap
= NULL
;
461 /* Get stream dict */
462 thumb
.fetch(xref
, &fetched_thumb
);
463 if (fetched_thumb
.isNull()) {
464 fetched_thumb
.free();
468 dict
= fetched_thumb
.streamGetDict();
469 str
= fetched_thumb
.getStream();
471 if (!dict
->lookupInt("Width", "W", &width
))
473 if (!dict
->lookupInt("Height", "H", &height
))
475 if (!dict
->lookupInt("BitsPerComponent", "BPC", &bits
))
478 /* Check for invalid dimensions and integer overflow. */
479 if (width
<= 0 || height
<= 0)
481 if (width
> INT_MAX
/ 3 / height
)
483 pixbufdatasize
= width
* height
* 3;
485 /* Get color space */
486 dict
->lookup ("ColorSpace", &obj1
);
487 if (obj1
.isNull ()) {
489 dict
->lookup ("CS", &obj1
);
491 colorSpace
= GfxColorSpace::parse(&obj1
);
494 fprintf (stderr
, "Error: Cannot parse color space\n");
498 dict
->lookup("Decode", &obj1
);
501 dict
->lookup("D", &obj1
);
503 colorMap
= new GfxImageColorMap(bits
, &obj1
, colorSpace
);
505 if (!colorMap
->isOk()) {
506 fprintf (stderr
, "Error: invalid colormap\n");
510 pixbufdata
= (unsigned char *) gmalloc(pixbufdatasize
);
512 imgstr
= new ImageStream(str
, width
,
513 colorMap
->getNumPixelComps(),
514 colorMap
->getBits());
516 for (row
= 0; row
< height
; ++row
) {
517 for (col
= 0; col
< width
; ++col
) {
518 Guchar pix
[gfxColorMaxComps
];
521 imgstr
->getPixel(pix
);
522 colorMap
->getRGB(pix
, &rgb
);
524 *p
++ = colToByte(rgb
.r
);
525 *p
++ = colToByte(rgb
.g
);
526 *p
++ = colToByte(rgb
.b
);
533 *data_out
= pixbufdata
;
539 *height_out
= height
;
541 *rowstride_out
= width
* 3;
546 fetched_thumb
.free();
551 void Page::getDefaultCTM(double *ctm
, double hDPI
, double vDPI
,
552 int rotate
, GBool upsideDown
) {
555 rotate
+= getRotate();
558 } else if (rotate
< 0) {
561 state
= new GfxState(hDPI
, vDPI
, getMediaBox(), rotate
, upsideDown
);
562 for (i
= 0; i
< 6; ++i
) {
563 ctm
[i
] = state
->getCTM()[i
];