]>
Commit | Line | Data |
---|---|---|
ef416fc2 | 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 "GlobalParams.h" | |
17 | #include "Object.h" | |
18 | #include "Array.h" | |
19 | #include "Dict.h" | |
20 | #include "XRef.h" | |
21 | #include "Link.h" | |
22 | #include "OutputDev.h" | |
23 | #ifndef PDF_PARSER_ONLY | |
24 | #include "Gfx.h" | |
25 | #include "GfxState.h" | |
26 | #include "Annot.h" | |
27 | #endif | |
28 | #include "Error.h" | |
29 | #include "Page.h" | |
30 | ||
31 | //------------------------------------------------------------------------ | |
32 | // PageAttrs | |
33 | //------------------------------------------------------------------------ | |
34 | ||
35 | PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) { | |
36 | Object obj1; | |
37 | ||
38 | // get old/default values | |
39 | if (attrs) { | |
40 | mediaBox = attrs->mediaBox; | |
41 | cropBox = attrs->cropBox; | |
42 | haveCropBox = attrs->haveCropBox; | |
43 | rotate = attrs->rotate; | |
44 | attrs->resources.copy(&resources); | |
45 | } else { | |
46 | // set default MediaBox to 8.5" x 11" -- this shouldn't be necessary | |
47 | // but some (non-compliant) PDF files don't specify a MediaBox | |
48 | mediaBox.x1 = 0; | |
49 | mediaBox.y1 = 0; | |
50 | mediaBox.x2 = 612; | |
51 | mediaBox.y2 = 792; | |
52 | cropBox.x1 = cropBox.y1 = cropBox.x2 = cropBox.y2 = 0; | |
53 | haveCropBox = gFalse; | |
54 | rotate = 0; | |
55 | resources.initNull(); | |
56 | } | |
57 | ||
58 | // media box | |
59 | readBox(dict, "MediaBox", &mediaBox); | |
60 | ||
61 | // crop box | |
62 | if (readBox(dict, "CropBox", &cropBox)) { | |
63 | haveCropBox = gTrue; | |
64 | } | |
65 | if (!haveCropBox) { | |
66 | cropBox = mediaBox; | |
67 | } | |
68 | ||
69 | // other boxes | |
70 | bleedBox = cropBox; | |
71 | readBox(dict, "BleedBox", &bleedBox); | |
72 | trimBox = cropBox; | |
73 | readBox(dict, "TrimBox", &trimBox); | |
74 | artBox = cropBox; | |
75 | readBox(dict, "ArtBox", &artBox); | |
76 | ||
77 | // rotate | |
78 | dict->lookup("Rotate", &obj1); | |
79 | if (obj1.isInt()) { | |
80 | rotate = obj1.getInt(); | |
81 | } | |
82 | obj1.free(); | |
83 | while (rotate < 0) { | |
84 | rotate += 360; | |
85 | } | |
86 | while (rotate >= 360) { | |
87 | rotate -= 360; | |
88 | } | |
89 | ||
90 | // misc attributes | |
91 | dict->lookup("LastModified", &lastModified); | |
92 | dict->lookup("BoxColorInfo", &boxColorInfo); | |
93 | dict->lookup("Group", &group); | |
94 | dict->lookup("Metadata", &metadata); | |
95 | dict->lookup("PieceInfo", &pieceInfo); | |
96 | dict->lookup("SeparationInfo", &separationInfo); | |
97 | ||
98 | // resource dictionary | |
99 | dict->lookup("Resources", &obj1); | |
100 | if (obj1.isDict()) { | |
101 | resources.free(); | |
102 | obj1.copy(&resources); | |
103 | } | |
104 | obj1.free(); | |
105 | } | |
106 | ||
107 | PageAttrs::~PageAttrs() { | |
108 | lastModified.free(); | |
109 | boxColorInfo.free(); | |
110 | group.free(); | |
111 | metadata.free(); | |
112 | pieceInfo.free(); | |
113 | separationInfo.free(); | |
114 | resources.free(); | |
115 | } | |
116 | ||
117 | GBool PageAttrs::readBox(Dict *dict, char *key, PDFRectangle *box) { | |
118 | PDFRectangle tmp; | |
119 | double t; | |
120 | Object obj1, obj2; | |
121 | GBool ok; | |
122 | ||
123 | dict->lookup(key, &obj1); | |
124 | if (obj1.isArray() && obj1.arrayGetLength() == 4) { | |
125 | ok = gTrue; | |
126 | obj1.arrayGet(0, &obj2); | |
127 | if (obj2.isNum()) { | |
128 | tmp.x1 = obj2.getNum(); | |
129 | } else { | |
130 | ok = gFalse; | |
131 | } | |
132 | obj2.free(); | |
133 | obj1.arrayGet(1, &obj2); | |
134 | if (obj2.isNum()) { | |
135 | tmp.y1 = obj2.getNum(); | |
136 | } else { | |
137 | ok = gFalse; | |
138 | } | |
139 | obj2.free(); | |
140 | obj1.arrayGet(2, &obj2); | |
141 | if (obj2.isNum()) { | |
142 | tmp.x2 = obj2.getNum(); | |
143 | } else { | |
144 | ok = gFalse; | |
145 | } | |
146 | obj2.free(); | |
147 | obj1.arrayGet(3, &obj2); | |
148 | if (obj2.isNum()) { | |
149 | tmp.y2 = obj2.getNum(); | |
150 | } else { | |
151 | ok = gFalse; | |
152 | } | |
153 | obj2.free(); | |
154 | if (ok) { | |
155 | if (tmp.x1 > tmp.x2) { | |
156 | t = tmp.x1; tmp.x1 = tmp.x2; tmp.x2 = t; | |
157 | } | |
158 | if (tmp.y1 > tmp.y2) { | |
159 | t = tmp.y1; tmp.y1 = tmp.y2; tmp.y2 = t; | |
160 | } | |
161 | *box = tmp; | |
162 | } | |
163 | } else { | |
164 | ok = gFalse; | |
165 | } | |
166 | obj1.free(); | |
167 | return ok; | |
168 | } | |
169 | ||
170 | //------------------------------------------------------------------------ | |
171 | // Page | |
172 | //------------------------------------------------------------------------ | |
173 | ||
174 | Page::Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA) { | |
175 | ok = gTrue; | |
176 | xref = xrefA; | |
177 | num = numA; | |
178 | ||
179 | // get attributes | |
180 | attrs = attrsA; | |
181 | ||
182 | // annotations | |
183 | pageDict->lookupNF("Annots", &annots); | |
184 | if (!(annots.isRef() || annots.isArray() || annots.isNull())) { | |
185 | error(-1, "Page annotations object (page %d) is wrong type (%s)", | |
186 | num, annots.getTypeName()); | |
187 | annots.free(); | |
188 | goto err2; | |
189 | } | |
190 | ||
191 | // contents | |
192 | pageDict->lookupNF("Contents", &contents); | |
193 | if (!(contents.isRef() || contents.isArray() || | |
194 | contents.isNull())) { | |
195 | error(-1, "Page contents object (page %d) is wrong type (%s)", | |
196 | num, contents.getTypeName()); | |
197 | contents.free(); | |
198 | goto err1; | |
199 | } | |
200 | ||
201 | return; | |
202 | ||
203 | err2: | |
204 | annots.initNull(); | |
205 | err1: | |
206 | contents.initNull(); | |
207 | ok = gFalse; | |
208 | } | |
209 | ||
210 | Page::~Page() { | |
211 | delete attrs; | |
212 | annots.free(); | |
213 | contents.free(); | |
214 | } | |
215 | ||
216 | void Page::display(OutputDev *out, double hDPI, double vDPI, | |
217 | int rotate, GBool useMediaBox, GBool crop, | |
218 | Links *links, Catalog *catalog, | |
219 | GBool (*abortCheckCbk)(void *data), | |
220 | void *abortCheckCbkData) { | |
221 | displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop, | |
222 | -1, -1, -1, -1, links, catalog, | |
223 | abortCheckCbk, abortCheckCbkData); | |
224 | } | |
225 | ||
226 | void Page::displaySlice(OutputDev *out, double hDPI, double vDPI, | |
227 | int rotate, GBool useMediaBox, GBool crop, | |
228 | int sliceX, int sliceY, int sliceW, int sliceH, | |
229 | Links *links, Catalog *catalog, | |
230 | GBool (*abortCheckCbk)(void *data), | |
231 | void *abortCheckCbkData) { | |
232 | #ifndef PDF_PARSER_ONLY | |
233 | PDFRectangle *mediaBox, *cropBox, *baseBox; | |
234 | PDFRectangle box; | |
235 | Gfx *gfx; | |
236 | Object obj; | |
237 | Link *link; | |
238 | Annots *annotList; | |
239 | double kx, ky; | |
240 | int i; | |
241 | ||
242 | rotate += getRotate(); | |
243 | if (rotate >= 360) { | |
244 | rotate -= 360; | |
245 | } else if (rotate < 0) { | |
246 | rotate += 360; | |
247 | } | |
248 | ||
249 | mediaBox = getMediaBox(); | |
250 | cropBox = getCropBox(); | |
251 | if (sliceW >= 0 && sliceH >= 0) { | |
252 | baseBox = useMediaBox ? mediaBox : cropBox; | |
253 | kx = 72.0 / hDPI; | |
254 | ky = 72.0 / vDPI; | |
255 | if (rotate == 90) { | |
256 | if (out->upsideDown()) { | |
257 | box.x1 = baseBox->x1 + ky * sliceY; | |
258 | box.x2 = baseBox->x1 + ky * (sliceY + sliceH); | |
259 | } else { | |
260 | box.x1 = baseBox->x2 - ky * (sliceY + sliceH); | |
261 | box.x2 = baseBox->x2 - ky * sliceY; | |
262 | } | |
263 | box.y1 = baseBox->y1 + kx * sliceX; | |
264 | box.y2 = baseBox->y1 + kx * (sliceX + sliceW); | |
265 | } else if (rotate == 180) { | |
266 | box.x1 = baseBox->x2 - kx * (sliceX + sliceW); | |
267 | box.x2 = baseBox->x2 - kx * sliceX; | |
268 | if (out->upsideDown()) { | |
269 | box.y1 = baseBox->y1 + ky * sliceY; | |
270 | box.y2 = baseBox->y1 + ky * (sliceY + sliceH); | |
271 | } else { | |
272 | box.y1 = baseBox->y2 - ky * (sliceY + sliceH); | |
273 | box.y2 = baseBox->y2 - ky * sliceY; | |
274 | } | |
275 | } else if (rotate == 270) { | |
276 | if (out->upsideDown()) { | |
277 | box.x1 = baseBox->x2 - ky * (sliceY + sliceH); | |
278 | box.x2 = baseBox->x2 - ky * sliceY; | |
279 | } else { | |
280 | box.x1 = baseBox->x1 + ky * sliceY; | |
281 | box.x2 = baseBox->x1 + ky * (sliceY + sliceH); | |
282 | } | |
283 | box.y1 = baseBox->y2 - kx * (sliceX + sliceW); | |
284 | box.y2 = baseBox->y2 - kx * sliceX; | |
285 | } else { | |
286 | box.x1 = baseBox->x1 + kx * sliceX; | |
287 | box.x2 = baseBox->x1 + kx * (sliceX + sliceW); | |
288 | if (out->upsideDown()) { | |
289 | box.y1 = baseBox->y2 - ky * (sliceY + sliceH); | |
290 | box.y2 = baseBox->y2 - ky * sliceY; | |
291 | } else { | |
292 | box.y1 = baseBox->y1 + ky * sliceY; | |
293 | box.y2 = baseBox->y1 + ky * (sliceY + sliceH); | |
294 | } | |
295 | } | |
296 | } else if (useMediaBox) { | |
297 | box = *mediaBox; | |
298 | } else { | |
299 | box = *cropBox; | |
300 | crop = gFalse; | |
301 | } | |
302 | ||
303 | if (globalParams->getPrintCommands()) { | |
304 | printf("***** MediaBox = ll:%g,%g ur:%g,%g\n", | |
305 | mediaBox->x1, mediaBox->y1, mediaBox->x2, mediaBox->y2); | |
306 | printf("***** CropBox = ll:%g,%g ur:%g,%g\n", | |
307 | cropBox->x1, cropBox->y1, cropBox->x2, cropBox->y2); | |
308 | printf("***** Rotate = %d\n", attrs->getRotate()); | |
309 | } | |
310 | ||
311 | gfx = new Gfx(xref, out, num, attrs->getResourceDict(), | |
312 | hDPI, vDPI, &box, crop ? cropBox : (PDFRectangle *)NULL, | |
313 | rotate, abortCheckCbk, abortCheckCbkData); | |
314 | contents.fetch(xref, &obj); | |
315 | if (!obj.isNull()) { | |
316 | gfx->saveState(); | |
317 | gfx->display(&obj); | |
318 | gfx->restoreState(); | |
319 | } | |
320 | obj.free(); | |
321 | ||
322 | // draw links | |
323 | if (links) { | |
324 | gfx->saveState(); | |
325 | for (i = 0; i < links->getNumLinks(); ++i) { | |
326 | link = links->getLink(i); | |
327 | out->drawLink(link, catalog); | |
328 | } | |
329 | gfx->restoreState(); | |
330 | out->dump(); | |
331 | } | |
332 | ||
333 | // draw non-link annotations | |
334 | annotList = new Annots(xref, catalog, annots.fetch(xref, &obj)); | |
335 | obj.free(); | |
336 | if (annotList->getNumAnnots() > 0) { | |
337 | if (globalParams->getPrintCommands()) { | |
338 | printf("***** Annotations\n"); | |
339 | } | |
340 | for (i = 0; i < annotList->getNumAnnots(); ++i) { | |
341 | annotList->getAnnot(i)->draw(gfx); | |
342 | } | |
343 | out->dump(); | |
344 | } | |
345 | delete annotList; | |
346 | ||
347 | delete gfx; | |
348 | #endif | |
349 | } | |
350 | ||
351 | void Page::getDefaultCTM(double *ctm, double hDPI, double vDPI, | |
352 | int rotate, GBool upsideDown) { | |
353 | GfxState *state; | |
354 | int i; | |
355 | ||
356 | rotate += getRotate(); | |
357 | if (rotate >= 360) { | |
358 | rotate -= 360; | |
359 | } else if (rotate < 0) { | |
360 | rotate += 360; | |
361 | } | |
362 | state = new GfxState(hDPI, vDPI, getMediaBox(), rotate, upsideDown); | |
363 | for (i = 0; i < 6; ++i) { | |
364 | ctm[i] = state->getCTM()[i]; | |
365 | } | |
366 | delete state; | |
367 | } |