upgraded to xpdf-3.01pl1
[swftools.git] / pdf2swf / xpdf / Page.cc
1 //========================================================================
2 //
3 // Page.cc
4 //
5 // Copyright 1996-2003 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 "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 }