c601857730d131a9e384083ed2f7a0fbb15c26ea
[swftools.git] / pdf2swf / xpdf / Page.cc
1 //========================================================================
2 //
3 // Page.cc
4 //
5 // Copyright 1996-2002 Glyph & Cog, LLC
6 //
7 //========================================================================
8
9 #ifdef __GNUC__
10 #pragma implementation
11 #endif
12
13 #include <aconf.h>
14 #include <stddef.h>
15 #include "Object.h"
16 #include "Array.h"
17 #include "Dict.h"
18 #include "XRef.h"
19 #include "Link.h"
20 #include "OutputDev.h"
21 #ifndef PDF_PARSER_ONLY
22 #include "Gfx.h"
23 #include "Annot.h"
24 #endif
25 #include "Error.h"
26 #include "Page.h"
27
28 //------------------------------------------------------------------------
29 // PageAttrs
30 //------------------------------------------------------------------------
31
32 PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) {
33   Object obj1;
34   double w, h;
35
36   // get old/default values
37   if (attrs) {
38     mediaBox = attrs->mediaBox;
39     cropBox = attrs->cropBox;
40     haveCropBox = attrs->haveCropBox;
41     rotate = attrs->rotate;
42     attrs->resources.copy(&resources);
43   } else {
44     // set default MediaBox to 8.5" x 11" -- this shouldn't be necessary
45     // but some (non-compliant) PDF files don't specify a MediaBox
46     mediaBox.x1 = 0;
47     mediaBox.y1 = 0;
48     mediaBox.x2 = 612;
49     mediaBox.y2 = 792;
50     cropBox.x1 = cropBox.y1 = cropBox.x2 = cropBox.y2 = 0;
51     haveCropBox = gFalse;
52     rotate = 0;
53     resources.initNull();
54   }
55
56   // media box
57   readBox(dict, "MediaBox", &mediaBox);
58
59   // crop box
60   cropBox = mediaBox;
61   haveCropBox = readBox(dict, "CropBox", &cropBox);
62
63   // if the MediaBox is excessively larger than the CropBox,
64   // just use the CropBox
65   limitToCropBox = gFalse;
66   if (haveCropBox) {
67     w = 0.25 * (cropBox.x2 - cropBox.x1);
68     h = 0.25 * (cropBox.y2 - cropBox.y1);
69     if ((cropBox.x1 - mediaBox.x1) + (mediaBox.x2 - cropBox.x2) > w ||
70         (cropBox.y1 - mediaBox.y1) + (mediaBox.y2 - cropBox.y2) > h) {
71       limitToCropBox = gTrue;
72     }
73   }
74
75   // other boxes
76   bleedBox = cropBox;
77   readBox(dict, "BleedBox", &bleedBox);
78   trimBox = cropBox;
79   readBox(dict, "TrimBox", &trimBox);
80   artBox = cropBox;
81   readBox(dict, "ArtBox", &artBox);
82
83   // rotate
84   dict->lookup("Rotate", &obj1);
85   if (obj1.isInt()) {
86     rotate = obj1.getInt();
87   }
88   obj1.free();
89   while (rotate < 0) {
90     rotate += 360;
91   }
92   while (rotate >= 360) {
93     rotate -= 360;
94   }
95
96   // misc attributes
97   dict->lookup("LastModified", &lastModified);
98   dict->lookup("BoxColorInfo", &boxColorInfo);
99   dict->lookup("Group", &group);
100   dict->lookup("Metadata", &metadata);
101   dict->lookup("PieceInfo", &pieceInfo);
102   dict->lookup("SeparationInfo", &separationInfo);
103
104   // resource dictionary
105   dict->lookup("Resources", &obj1);
106   if (obj1.isDict()) {
107     resources.free();
108     obj1.copy(&resources);
109   }
110   obj1.free();
111 }
112
113 PageAttrs::~PageAttrs() {
114   lastModified.free();
115   boxColorInfo.free();
116   group.free();
117   metadata.free();
118   pieceInfo.free();
119   separationInfo.free();
120   resources.free();
121 }
122
123 GBool PageAttrs::readBox(Dict *dict, char *key, PDFRectangle *box) {
124   PDFRectangle tmp;
125   Object obj1, obj2;
126   GBool ok;
127
128   dict->lookup(key, &obj1);
129   if (obj1.isArray() && obj1.arrayGetLength() == 4) {
130     ok = gTrue;
131     obj1.arrayGet(0, &obj2);
132     if (obj2.isNum()) {
133       tmp.x1 = obj2.getNum();
134     } else {
135       ok = gFalse;
136     }
137     obj2.free();
138     obj1.arrayGet(1, &obj2);
139     if (obj2.isNum()) {
140       tmp.y1 = obj2.getNum();
141     } else {
142       ok = gFalse;
143     }
144     obj2.free();
145     obj1.arrayGet(2, &obj2);
146     if (obj2.isNum()) {
147       tmp.x2 = obj2.getNum();
148     } else {
149       ok = gFalse;
150     }
151     obj2.free();
152     obj1.arrayGet(3, &obj2);
153     if (obj2.isNum()) {
154       tmp.y2 = obj2.getNum();
155     } else {
156       ok = gFalse;
157     }
158     obj2.free();
159     if (ok) {
160       *box = tmp;
161     }
162   } else {
163     ok = gFalse;
164   }
165   obj1.free();
166   return ok;
167 }
168
169 //------------------------------------------------------------------------
170 // Page
171 //------------------------------------------------------------------------
172
173 Page::Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA,
174            GBool printCommandsA) {
175
176   ok = gTrue;
177   xref = xrefA;
178   num = numA;
179   printCommands = printCommandsA;
180
181   // get attributes
182   attrs = attrsA;
183
184   // annotations
185   pageDict->lookupNF("Annots", &annots);
186   if (!(annots.isRef() || annots.isArray() || annots.isNull())) {
187     error(-1, "Page annotations object (page %d) is wrong type (%s)",
188           num, annots.getTypeName());
189     annots.free();
190     goto err2;
191   }
192
193   // contents
194   pageDict->lookupNF("Contents", &contents);
195   if (!(contents.isRef() || contents.isArray() ||
196         contents.isNull())) {
197     error(-1, "Page contents object (page %d) is wrong type (%s)",
198           num, contents.getTypeName());
199     contents.free();
200     goto err1;
201   }
202
203   return;
204
205  err2:
206   annots.initNull();
207  err1:
208   contents.initNull();
209   ok = gFalse;
210 }
211
212 Page::~Page() {
213   delete attrs;
214   annots.free();
215   contents.free();
216 }
217
218 void Page::display(OutputDev *out, double dpi, int rotate,
219                    Links *links, Catalog *catalog) {
220 #ifndef PDF_PARSER_ONLY
221   PDFRectangle *box, *cropBox;
222   Gfx *gfx;
223   Object obj;
224   Link *link;
225   int i;
226   Annots *annotList;
227
228   box = getBox();
229   cropBox = getCropBox();
230
231   if (printCommands) {
232     printf("***** MediaBox = ll:%g,%g ur:%g,%g\n",
233            box->x1, box->y1, box->x2, box->y2);
234     if (isCropped()) {
235       printf("***** CropBox = ll:%g,%g ur:%g,%g\n",
236              cropBox->x1, cropBox->y1, cropBox->x2, cropBox->y2);
237     }
238     printf("***** Rotate = %d\n", attrs->getRotate());
239   }
240
241   rotate += getRotate();
242   if (rotate >= 360) {
243     rotate -= 360;
244   } else if (rotate < 0) {
245     rotate += 360;
246   }
247   gfx = new Gfx(xref, out, num, attrs->getResourceDict(),
248                 dpi, box, isCropped(), cropBox, rotate, printCommands);
249   contents.fetch(xref, &obj);
250   if (!obj.isNull()) {
251     gfx->display(&obj);
252   }
253   obj.free();
254
255   // draw links
256   if (links) {
257     for (i = 0; i < links->getNumLinks(); ++i) {
258       link = links->getLink(i);
259       out->drawLink(link, catalog);
260     }
261     out->dump();
262   }
263
264   // draw non-link annotations
265   //~ need to reset CTM ???
266   annotList = new Annots(xref, annots.fetch(xref, &obj));
267   obj.free();
268   if (annotList->getNumAnnots() > 0) {
269     if (printCommands) {
270       printf("***** Annotations\n");
271     }
272     for (i = 0; i < annotList->getNumAnnots(); ++i) {
273       annotList->getAnnot(i)->draw(gfx);
274     }
275     out->dump();
276   }
277   delete annotList;
278
279   delete gfx;
280 #endif
281 }