"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.
For more information about "Page.cc" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
4.03_vs_4.04.
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