"Fossies" - the Fresh Open Source Software Archive 
Member "xpdf-4.04/xpdf/Page.cc" (18 Apr 2022, 13874 Bytes) of package /linux/misc/xpdf-4.04.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 //========================================================================
2 //
3 // Page.cc
4 //
5 // Copyright 1996-2007 Glyph & Cog, LLC
6 //
7 //========================================================================
8
9 #include <aconf.h>
10
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
13 #endif
14
15 #include <stddef.h>
16 #include "gmempp.h"
17 #include "Trace.h"
18 #include "GlobalParams.h"
19 #include "Object.h"
20 #include "Array.h"
21 #include "Dict.h"
22 #include "PDFDoc.h"
23 #include "XRef.h"
24 #include "Link.h"
25 #include "OutputDev.h"
26 #ifndef PDF_PARSER_ONLY
27 #include "Gfx.h"
28 #include "GfxState.h"
29 #include "Annot.h"
30 #include "AcroForm.h"
31 #endif
32 #include "Error.h"
33 #include "Catalog.h"
34 #include "Page.h"
35
36 //------------------------------------------------------------------------
37 // PDFRectangle
38 //------------------------------------------------------------------------
39
40 void PDFRectangle::clipTo(PDFRectangle *rect) {
41 if (x1 < rect->x1) {
42 x1 = rect->x1;
43 } else if (x1 > rect->x2) {
44 x1 = rect->x2;
45 }
46 if (x2 < rect->x1) {
47 x2 = rect->x1;
48 } else if (x2 > rect->x2) {
49 x2 = rect->x2;
50 }
51 if (y1 < rect->y1) {
52 y1 = rect->y1;
53 } else if (y1 > rect->y2) {
54 y1 = rect->y2;
55 }
56 if (y2 < rect->y1) {
57 y2 = rect->y1;
58 } else if (y2 > rect->y2) {
59 y2 = rect->y2;
60 }
61 }
62
63 //------------------------------------------------------------------------
64 // PageAttrs
65 //------------------------------------------------------------------------
66
67 PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict, XRef *xref) {
68 Object obj1;
69
70 // get old/default values
71 if (attrs) {
72 mediaBox = attrs->mediaBox;
73 cropBox = attrs->cropBox;
74 haveCropBox = attrs->haveCropBox;
75 rotate = attrs->rotate;
76 } else {
77 // set default MediaBox to 8.5" x 11" -- this shouldn't be necessary
78 // but some (non-compliant) PDF files don't specify a MediaBox
79 mediaBox.x1 = 0;
80 mediaBox.y1 = 0;
81 mediaBox.x2 = 612;
82 mediaBox.y2 = 792;
83 cropBox.x1 = cropBox.y1 = cropBox.x2 = cropBox.y2 = 0;
84 haveCropBox = gFalse;
85 rotate = 0;
86 }
87
88 // media box
89 readBox(dict, "MediaBox", &mediaBox);
90
91 // crop box
92 if (readBox(dict, "CropBox", &cropBox)) {
93 haveCropBox = gTrue;
94 }
95 if (!haveCropBox) {
96 cropBox = mediaBox;
97 }
98
99 // other boxes
100 bleedBox = cropBox;
101 readBox(dict, "BleedBox", &bleedBox);
102 trimBox = cropBox;
103 readBox(dict, "TrimBox", &trimBox);
104 artBox = cropBox;
105 readBox(dict, "ArtBox", &artBox);
106
107 // rotate
108 dict->lookup("Rotate", &obj1);
109 if (obj1.isInt()) {
110 rotate = obj1.getInt();
111 }
112 obj1.free();
113 while (rotate < 0) {
114 rotate += 360;
115 }
116 while (rotate >= 360) {
117 rotate -= 360;
118 }
119
120 // misc attributes
121 dict->lookup("LastModified", &lastModified);
122 dict->lookup("BoxColorInfo", &boxColorInfo);
123 dict->lookup("Group", &group);
124 dict->lookup("Metadata", &metadata);
125 dict->lookup("PieceInfo", &pieceInfo);
126 dict->lookup("SeparationInfo", &separationInfo);
127 if (dict->lookup("UserUnit", &obj1)->isNum()) {
128 userUnit = obj1.getNum();
129 if (userUnit < 1) {
130 userUnit = 1;
131 }
132 } else {
133 userUnit = 1;
134 }
135 obj1.free();
136
137 // resource dictionary
138 Object childResDictObj;
139 dict->lookup("Resources", &childResDictObj);
140 if (attrs && attrs->resources.isDict() && childResDictObj.isDict()) {
141 // merge this node's resources into the parent's resources
142 // (some PDF files violate the PDF spec and expect this merging)
143 resources.initDict(xref);
144 Dict *resDict = resources.getDict();
145 Dict *parentResDict = attrs->resources.getDict();
146 for (int i = 0; i < parentResDict->getLength(); ++i) {
147 char *resType = parentResDict->getKey(i);
148 Object subdictObj1;
149 if (parentResDict->getVal(i, &subdictObj1)->isDict()) {
150 Dict *subdict1 = subdictObj1.getDict();
151 Object subdictObj2;
152 subdictObj2.initDict(xref);
153 Dict *subdict2 = subdictObj2.getDict();
154 for (int j = 0; j < subdict1->getLength(); ++j) {
155 subdict1->getValNF(j, &obj1);
156 subdict2->add(copyString(subdict1->getKey(j)), &obj1);
157 }
158 resDict->add(copyString(resType), &subdictObj2);
159 }
160 subdictObj1.free();
161 }
162 Dict *childResDict = childResDictObj.getDict();
163 for (int i = 0; i < childResDict->getLength(); ++i) {
164 char *resType = childResDict->getKey(i);
165 Object subdictObj1;
166 if (childResDict->getVal(i, &subdictObj1)->isDict()) {
167 Object subdictObj2;
168 if (resDict->lookup(resType, &subdictObj2)->isDict()) {
169 Dict *subdict1 = subdictObj1.getDict();
170 Dict *subdict2 = subdictObj2.getDict();
171 for (int j = 0; j < subdict1->getLength(); ++j) {
172 subdict1->getValNF(j, &obj1);
173 subdict2->add(copyString(subdict1->getKey(j)), &obj1);
174 }
175 subdictObj2.free();
176 } else {
177 subdictObj2.free();
178 resDict->add(copyString(resType), subdictObj1.copy(&subdictObj2));
179 }
180 }
181 subdictObj1.free();
182 }
183 } else if (attrs && attrs->resources.isDict()) {
184 attrs->resources.copy(&resources);
185 } else if (childResDictObj.isDict()) {
186 childResDictObj.copy(&resources);
187 } else {
188 resources.initNull();
189 }
190 childResDictObj.free();
191 }
192
193 PageAttrs::PageAttrs() {
194 mediaBox.x1 = mediaBox.y1 = 0;
195 mediaBox.x2 = mediaBox.y2 = 50;
196 cropBox = mediaBox;
197 haveCropBox = gFalse;
198 bleedBox = cropBox;
199 trimBox = cropBox;
200 artBox = cropBox;
201 rotate = 0;
202 lastModified.initNull();
203 boxColorInfo.initNull();
204 group.initNull();
205 metadata.initNull();
206 pieceInfo.initNull();
207 separationInfo.initNull();
208 userUnit = 1;
209 resources.initNull();
210 }
211
212 PageAttrs::~PageAttrs() {
213 lastModified.free();
214 boxColorInfo.free();
215 group.free();
216 metadata.free();
217 pieceInfo.free();
218 separationInfo.free();
219 resources.free();
220 }
221
222 void PageAttrs::clipBoxes() {
223 cropBox.clipTo(&mediaBox);
224 bleedBox.clipTo(&mediaBox);
225 trimBox.clipTo(&mediaBox);
226 artBox.clipTo(&mediaBox);
227 }
228
229 GBool PageAttrs::readBox(Dict *dict, const char *key, PDFRectangle *box) {
230 PDFRectangle tmp;
231 double t;
232 Object obj1, obj2;
233 GBool ok;
234
235 dict->lookup(key, &obj1);
236 if (obj1.isArray() && obj1.arrayGetLength() == 4) {
237 ok = gTrue;
238 obj1.arrayGet(0, &obj2);
239 if (obj2.isNum()) {
240 tmp.x1 = obj2.getNum();
241 } else {
242 ok = gFalse;
243 }
244 obj2.free();
245 obj1.arrayGet(1, &obj2);
246 if (obj2.isNum()) {
247 tmp.y1 = obj2.getNum();
248 } else {
249 ok = gFalse;
250 }
251 obj2.free();
252 obj1.arrayGet(2, &obj2);
253 if (obj2.isNum()) {
254 tmp.x2 = obj2.getNum();
255 } else {
256 ok = gFalse;
257 }
258 obj2.free();
259 obj1.arrayGet(3, &obj2);
260 if (obj2.isNum()) {
261 tmp.y2 = obj2.getNum();
262 } else {
263 ok = gFalse;
264 }
265 obj2.free();
266 if (ok) {
267 if (tmp.x1 > tmp.x2) {
268 t = tmp.x1; tmp.x1 = tmp.x2; tmp.x2 = t;
269 }
270 if (tmp.y1 > tmp.y2) {
271 t = tmp.y1; tmp.y1 = tmp.y2; tmp.y2 = t;
272 }
273 *box = tmp;
274 }
275 } else {
276 ok = gFalse;
277 }
278 obj1.free();
279 return ok;
280 }
281
282 //------------------------------------------------------------------------
283 // Page
284 //------------------------------------------------------------------------
285
286 Page::Page(PDFDoc *docA, int numA, Dict *pageDict, PageAttrs *attrsA) {
287 ok = gTrue;
288 doc = docA;
289 xref = doc->getXRef();
290 num = numA;
291
292 // get attributes
293 attrs = attrsA;
294 attrs->clipBoxes();
295
296 // annotations
297 pageDict->lookupNF("Annots", &annots);
298 if (!(annots.isRef() || annots.isArray() || annots.isNull())) {
299 error(errSyntaxError, -1,
300 "Page annotations object (page {0:d}) is wrong type ({1:s})",
301 num, annots.getTypeName());
302 annots.free();
303 goto err2;
304 }
305
306 // contents
307 pageDict->lookupNF("Contents", &contents);
308 if (!(contents.isRef() || contents.isArray() ||
309 contents.isNull())) {
310 error(errSyntaxError, -1,
311 "Page contents object (page {0:d}) is wrong type ({1:s})",
312 num, contents.getTypeName());
313 contents.free();
314 goto err1;
315 }
316
317 // thumbnail
318 pageDict->lookupNF("Thumb", &thumbnail);
319 if (!thumbnail.isRef()) {
320 if (!thumbnail.isNull()) {
321 thumbnail.free();
322 thumbnail.initNull();
323 }
324 }
325
326 return;
327
328 err2:
329 annots.initNull();
330 err1:
331 contents.initNull();
332 thumbnail.initNull();
333 ok = gFalse;
334 }
335
336 Page::Page(PDFDoc *docA, int numA) {
337 doc = docA;
338 xref = doc->getXRef();
339 num = numA;
340 attrs = new PageAttrs();
341 annots.initNull();
342 contents.initNull();
343 thumbnail.initNull();
344 ok = gTrue;
345 }
346
347 Page::~Page() {
348 delete attrs;
349 annots.free();
350 contents.free();
351 thumbnail.free();
352 }
353
354 Links *Page::getLinks() {
355 Links *links;
356 Object obj;
357
358 links = new Links(getAnnots(&obj), doc->getCatalog()->getBaseURI());
359 obj.free();
360 return links;
361 }
362
363 void Page::display(OutputDev *out, double hDPI, double vDPI,
364 int rotate, GBool useMediaBox, GBool crop,
365 GBool printing,
366 GBool (*abortCheckCbk)(void *data),
367 void *abortCheckCbkData) {
368 displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop,
369 -1, -1, -1, -1, printing,
370 abortCheckCbk, abortCheckCbkData);
371 }
372
373 void Page::displaySlice(OutputDev *out, double hDPI, double vDPI,
374 int rotate, GBool useMediaBox, GBool crop,
375 int sliceX, int sliceY, int sliceW, int sliceH,
376 GBool printing,
377 GBool (*abortCheckCbk)(void *data),
378 void *abortCheckCbkData) {
379 #ifndef PDF_PARSER_ONLY
380 PDFRectangle *mediaBox, *cropBox;
381 PDFRectangle box;
382 Gfx *gfx;
383 Object obj;
384 Annots *annotList;
385 AcroForm *form;
386 int i;
387
388 if (!out->checkPageSlice(this, hDPI, vDPI, rotate, useMediaBox, crop,
389 sliceX, sliceY, sliceW, sliceH,
390 printing, abortCheckCbk, abortCheckCbkData)) {
391 return;
392 }
393
394 traceBegin(this, "begin page");
395
396 rotate += getRotate();
397 if (rotate >= 360) {
398 rotate -= 360;
399 } else if (rotate < 0) {
400 rotate += 360;
401 }
402
403 makeBox(hDPI, vDPI, rotate, useMediaBox, out->upsideDown(),
404 sliceX, sliceY, sliceW, sliceH, &box, &crop);
405 cropBox = getCropBox();
406
407 if (globalParams->getPrintCommands()) {
408 mediaBox = getMediaBox();
409 printf("***** MediaBox = ll:%g,%g ur:%g,%g\n",
410 mediaBox->x1, mediaBox->y1, mediaBox->x2, mediaBox->y2);
411 printf("***** CropBox = ll:%g,%g ur:%g,%g\n",
412 cropBox->x1, cropBox->y1, cropBox->x2, cropBox->y2);
413 printf("***** Rotate = %d\n", attrs->getRotate());
414 }
415
416 gfx = new Gfx(doc, out, num, attrs->getResourceDict(),
417 hDPI, vDPI, &box, crop ? cropBox : (PDFRectangle *)NULL,
418 rotate, abortCheckCbk, abortCheckCbkData);
419 contents.fetch(xref, &obj);
420 if (!obj.isNull()) {
421 gfx->saveState();
422 gfx->display(&contents);
423 gfx->endOfPage();
424 }
425 obj.free();
426
427 // draw (non-form) annotations
428 if (globalParams->getDrawAnnotations()) {
429 annotList = new Annots(doc, getAnnots(&obj));
430 obj.free();
431 annotList->generateAnnotAppearances();
432 if (annotList->getNumAnnots() > 0) {
433 if (globalParams->getPrintCommands()) {
434 printf("***** Annotations\n");
435 }
436 for (i = 0; i < annotList->getNumAnnots(); ++i) {
437 if (abortCheckCbk && (*abortCheckCbk)(abortCheckCbkData)) {
438 break;
439 }
440 annotList->getAnnot(i)->draw(gfx, printing);
441 }
442 }
443 delete annotList;
444 }
445
446 // draw form fields
447 if (globalParams->getDrawFormFields()) {
448 if ((form = doc->getCatalog()->getForm())) {
449 if (!(abortCheckCbk && (*abortCheckCbk)(abortCheckCbkData))) {
450 form->draw(num, gfx, printing);
451 }
452 }
453 }
454
455 delete gfx;
456 #endif // PDF_PARSER_ONLY
457
458 traceEnd(this, "end page");
459 }
460
461 void Page::makeBox(double hDPI, double vDPI, int rotate,
462 GBool useMediaBox, GBool upsideDown,
463 double sliceX, double sliceY, double sliceW, double sliceH,
464 PDFRectangle *box, GBool *crop) {
465 PDFRectangle *mediaBox, *cropBox, *baseBox;
466 double kx, ky;
467
468 mediaBox = getMediaBox();
469 cropBox = getCropBox();
470 if (sliceW >= 0 && sliceH >= 0) {
471 baseBox = useMediaBox ? mediaBox : cropBox;
472 kx = 72.0 / hDPI;
473 ky = 72.0 / vDPI;
474 if (rotate == 90) {
475 if (upsideDown) {
476 box->x1 = baseBox->x1 + ky * sliceY;
477 box->x2 = baseBox->x1 + ky * (sliceY + sliceH);
478 } else {
479 box->x1 = baseBox->x2 - ky * (sliceY + sliceH);
480 box->x2 = baseBox->x2 - ky * sliceY;
481 }
482 box->y1 = baseBox->y1 + kx * sliceX;
483 box->y2 = baseBox->y1 + kx * (sliceX + sliceW);
484 } else if (rotate == 180) {
485 box->x1 = baseBox->x2 - kx * (sliceX + sliceW);
486 box->x2 = baseBox->x2 - kx * sliceX;
487 if (upsideDown) {
488 box->y1 = baseBox->y1 + ky * sliceY;
489 box->y2 = baseBox->y1 + ky * (sliceY + sliceH);
490 } else {
491 box->y1 = baseBox->y2 - ky * (sliceY + sliceH);
492 box->y2 = baseBox->y2 - ky * sliceY;
493 }
494 } else if (rotate == 270) {
495 if (upsideDown) {
496 box->x1 = baseBox->x2 - ky * (sliceY + sliceH);
497 box->x2 = baseBox->x2 - ky * sliceY;
498 } else {
499 box->x1 = baseBox->x1 + ky * sliceY;
500 box->x2 = baseBox->x1 + ky * (sliceY + sliceH);
501 }
502 box->y1 = baseBox->y2 - kx * (sliceX + sliceW);
503 box->y2 = baseBox->y2 - kx * sliceX;
504 } else {
505 box->x1 = baseBox->x1 + kx * sliceX;
506 box->x2 = baseBox->x1 + kx * (sliceX + sliceW);
507 if (upsideDown) {
508 box->y1 = baseBox->y2 - ky * (sliceY + sliceH);
509 box->y2 = baseBox->y2 - ky * sliceY;
510 } else {
511 box->y1 = baseBox->y1 + ky * sliceY;
512 box->y2 = baseBox->y1 + ky * (sliceY + sliceH);
513 }
514 }
515 } else if (useMediaBox) {
516 *box = *mediaBox;
517 } else {
518 *box = *cropBox;
519 *crop = gFalse;
520 }
521 }
522
523 void Page::processLinks(OutputDev *out) {
524 Links *links;
525 int i;
526
527 links = getLinks();
528 for (i = 0; i < links->getNumLinks(); ++i) {
529 out->processLink(links->getLink(i));
530 }
531 delete links;
532 }
533
534 #ifndef PDF_PARSER_ONLY
535 void Page::getDefaultCTM(double *ctm, double hDPI, double vDPI,
536 int rotate, GBool useMediaBox, GBool upsideDown) {
537 GfxState *state;
538 int i;
539
540 rotate += getRotate();
541 if (rotate >= 360) {
542 rotate -= 360;
543 } else if (rotate < 0) {
544 rotate += 360;
545 }
546 state = new GfxState(hDPI, vDPI,
547 useMediaBox ? getMediaBox() : getCropBox(),
548 rotate, upsideDown);
549 for (i = 0; i < 6; ++i) {
550 ctm[i] = state->getCTM()[i];
551 }
552 delete state;
553 }
554 #endif