53d95cc4422ce2b46d3b8a240501c908afdfafc6
[swftools.git] / lib / pdf / pdf.cc
1 #include "../gfxdevice.h"
2 #include "../gfxsource.h"
3 #include "../log.h"
4 #include "config.h"
5 #include "GlobalParams.h"
6 #include "InfoOutputDev.h"
7 #include "GFXOutputDev.h"
8 #include "../mem.h"
9 #include "pdf.h"
10 #define NO_ARGPARSER
11 #include "../args.h"
12
13 static parameter_t* device_config = 0;
14 static parameter_t* device_config_next = 0;
15
16 int jpeg_dpi = 0;
17 int ppm_dpi = 0;
18
19 static double zoom = 72; /* xpdf: 86 */
20
21 static char* global_page_range = 0;
22
23 typedef struct _pdf_page_info
24 {
25     int xMin, yMin, xMax, yMax;
26     int width,height;
27     int number_of_images;
28     int number_of_links;
29     int number_of_fonts;
30     char has_info;
31 } pdf_page_info_t;
32
33 typedef struct _pdf_doc_internal
34 {
35     int protect;
36     PDFDoc*doc;
37     InfoOutputDev*info;
38     GFXOutputDev*outputDev;
39     pdf_page_info_t*pages;
40 } pdf_doc_internal_t;
41
42 typedef struct _pdf_page_internal
43 {
44 } pdf_page_internal_t;
45
46 typedef struct _dev_output_internal
47 {
48     GFXOutputDev*outputDev;
49 } dev_output_internal_t;
50
51
52 static char* dirseparator()
53 {
54 #ifdef WIN32
55     return "\\";
56 #else
57     return "/";
58 #endif
59 }
60
61
62 void pdfpage_destroy(gfxpage_t*pdf_page)
63 {
64     pdf_page_internal_t*i= (pdf_page_internal_t*)pdf_page->internal;
65     free(pdf_page->internal);pdf_page->internal = 0;
66     free(pdf_page);pdf_page=0;
67 }
68
69 void render2(gfxpage_t*page, gfxdevice_t*output)
70 {
71     pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
72
73     if(!pi) {
74         msg("<fatal> pdf_page_render: Parent PDF this page belongs to doesn't exist yet/anymore");
75         return;
76     }
77
78     if(!pi->pages[page->nr-1].has_info) {
79         msg("<fatal> pdf_page_render: page %d was previously set as not-to-render via the \"pages\" option", page->nr);
80         return;
81     }
82
83     if(pi->protect) {
84         gfxdevice_t*dev = pi->outputDev->device;
85         dev->setparameter(dev, "protect", "1");
86     }
87     pi->outputDev->setInfo(pi->info);
88     pi->outputDev->setXRef(pi->doc, pi->doc->getXRef());
89     pi->doc->displayPage((OutputDev*)pi->outputDev, page->nr, zoom, zoom, /*rotate*/0, true, true, /*doLinks*/(int)1);
90 }
91
92     
93 void pdfpage_render(gfxpage_t*page, gfxdevice_t*output)
94 {
95     pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
96     pi->outputDev->setDevice(output);
97     pi->outputDev->setMove(0,0);
98     pi->outputDev->setClip(0,0,0,0);
99     render2(page, output);
100     pi->outputDev->setDevice(0);
101 }
102
103 void pdfpage_rendersection(gfxpage_t*page, gfxdevice_t*output, gfxcoord_t x, gfxcoord_t y, gfxcoord_t _x1, gfxcoord_t _y1, gfxcoord_t _x2, gfxcoord_t _y2)
104 {
105     int x1=(int)_x1,y1=(int)_y1,x2=(int)_x2,y2=(int)_y2;
106     pdf_doc_internal_t*pi = (pdf_doc_internal_t*)page->parent->internal;
107     pi->outputDev->setDevice(output);
108     pi->outputDev->setMove((int)x,(int)y);
109     if((x1|y1|x2|y2)==0) x2++;
110     pi->outputDev->setClip((int)x1,(int)y1,(int)x2,(int)y2);
111     render2(page, output);
112     pi->outputDev->setDevice(0);
113 }
114
115 void pdf_doc_destroy(gfxdocument_t*gfx)
116 {
117     pdf_doc_internal_t*i= (pdf_doc_internal_t*)gfx->internal;
118
119     delete i->doc; i->doc=0;
120     free(i->pages); i->pages = 0;
121     
122     if(i->info) {
123         delete i->info;i->info=0;
124     }
125
126     free(gfx->internal);gfx->internal=0;
127     free(gfx);gfx=0;
128
129     if(global_page_range) {
130         free(global_page_range);
131         global_page_range = 0;
132     }
133 }
134
135 void pdf_doc_set_parameter(gfxdocument_t*gfx, char*name, char*value)
136 {
137     pdf_doc_internal_t*i= (pdf_doc_internal_t*)gfx->internal;
138     if(!strcmp(name, "pagemap")) {
139         GFXOutputDev*o = i->outputDev;
140         int pdfpage=0, outputpage=0;
141         sscanf(value,"%d:%d", &pdfpage, &outputpage);
142         o->preparePage(pdfpage, outputpage);
143     } else {
144         msg("<warning> Ignored parameter: %s=%s", name, value);
145     }
146 }
147
148 gfxpage_t* pdf_doc_getpage(gfxdocument_t*doc, int page)
149 {
150     pdf_doc_internal_t*di= (pdf_doc_internal_t*)doc->internal;
151
152     if(page < 1 || page > doc->num_pages)
153         return 0;
154     
155     gfxpage_t* pdf_page = (gfxpage_t*)malloc(sizeof(gfxpage_t));
156     pdf_page_internal_t*pi= (pdf_page_internal_t*)malloc(sizeof(pdf_page_internal_t));
157     memset(pi, 0, sizeof(pdf_page_internal_t));
158     pdf_page->internal = pi;
159
160     pdf_page->destroy = pdfpage_destroy;
161     pdf_page->render = pdfpage_render;
162     pdf_page->rendersection = pdfpage_rendersection;
163     pdf_page->width = di->pages[page-1].width;
164     pdf_page->height = di->pages[page-1].height;
165
166     pdf_page->parent = doc;
167     pdf_page->nr = page;
168     return pdf_page;
169 }
170
171 void storeDeviceParameter(char*name, char*value)
172 {
173     parameter_t*p = new parameter_t();
174     p->name = strdup(name);
175     p->value = strdup(value);
176     p->next = 0;
177     if(device_config_next) {
178         device_config_next->next = p;
179         device_config_next = p;
180     } else {
181         device_config = p;
182         device_config_next = p;
183     }
184 }
185
186 void pdf_set_parameter(char*name, char*value)
187 {
188     msg("<verbose> setting parameter %s to \"%s\"", name, value);
189     if(!strncmp(name, "fontdir", strlen("fontdir"))) {
190         addGlobalFontDir(value);
191     } else if(!strcmp(name, "pages")) {
192         global_page_range = strdup(value);
193     } else if(!strncmp(name, "font", strlen("font"))) {
194         addGlobalFont(value);
195     } else if(!strncmp(name, "languagedir", strlen("languagedir"))) {
196         addGlobalLanguageDir(value);
197     } else if(!strcmp(name, "zoom")) {
198         char buf[80];
199         zoom = atof(value);
200         sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
201         storeDeviceParameter("jpegsubpixels", buf);
202         sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
203         storeDeviceParameter("ppmsubpixels", buf);
204     } else if(!strcmp(name, "jpegdpi")) {
205         char buf[80];
206         jpeg_dpi = atoi(value);
207         sprintf(buf, "%f", (double)jpeg_dpi/(double)zoom);
208         storeDeviceParameter("jpegsubpixels", buf);
209     } else if(!strcmp(name, "ppmdpi")) {
210         char buf[80];
211         ppm_dpi = atoi(value);
212         sprintf(buf, "%f", (double)ppm_dpi/(double)zoom);
213         storeDeviceParameter("ppmsubpixels", buf);
214     } else {
215         storeDeviceParameter(name,value);
216     }
217 }
218
219 static void printInfoString(Dict *infoDict, char *key, char *fmt) {
220   Object obj;
221   GString *s1, *s2;
222   int i;
223
224   if (infoDict->lookup(key, &obj)->isString()) {
225     s1 = obj.getString();
226     if ((s1->getChar(0) & 0xff) == 0xfe &&
227         (s1->getChar(1) & 0xff) == 0xff) {
228       s2 = new GString();
229       for (i = 2; i < obj.getString()->getLength(); i += 2) {
230         if (s1->getChar(i) == '\0') {
231           s2->append(s1->getChar(i+1));
232         } else {
233           delete s2;
234           s2 = new GString("<unicode>");
235           break;
236         }
237       }
238       printf(fmt, s2->getCString());
239       delete s2;
240     } else {
241       printf(fmt, s1->getCString());
242     }
243   }
244   obj.free();
245 }
246
247 static void printInfoDate(Dict *infoDict, char *key, char *fmt) {
248   Object obj;
249   char *s;
250
251   if (infoDict->lookup(key, &obj)->isString()) {
252     s = obj.getString()->getCString();
253     if (s[0] == 'D' && s[1] == ':') {
254       s += 2;
255     }
256     printf(fmt, s);
257   }
258   obj.free();
259 }
260
261
262
263 gfxdocument_t*pdf_open(char*filename)
264 {
265     gfxdocument_t*pdf_doc = (gfxdocument_t*)malloc(sizeof(gfxdocument_t));
266     memset(pdf_doc, 0, sizeof(gfxdocument_t));
267     pdf_doc_internal_t*i= (pdf_doc_internal_t*)malloc(sizeof(pdf_doc_internal_t));
268     memset(i, 0, sizeof(pdf_doc_internal_t));
269     pdf_doc->internal = i;
270     char*userPassword=0;
271     
272     filename = strdup(filename);
273
274     char*x = 0;
275     if((x = strchr(filename, '|'))) {
276         *x = 0;
277         userPassword = x+1;
278     }
279     
280     GString *fileName = new GString(filename);
281     GString *userPW;
282     Object info;
283
284     // read config file
285     if(!globalParams)
286         globalParams = new GlobalParams("");
287
288     // open PDF file
289     if (userPassword && userPassword[0]) {
290       userPW = new GString(userPassword);
291     } else {
292       userPW = NULL;
293     }
294     i->doc = new PDFDoc(fileName, userPW);
295     if (userPW) {
296       delete userPW;
297     }
298     if (!i->doc->isOk()) {
299         printf("xpdf reports document as broken.\n");
300         return 0;
301     }
302
303     // print doc info
304     i->doc->getDocInfo(&info);
305     if (info.isDict() &&
306       (getScreenLogLevel()>=LOGLEVEL_NOTICE)) {
307       printInfoString(info.getDict(), "Title",        "Title:        %s\n");
308       printInfoString(info.getDict(), "Subject",      "Subject:      %s\n");
309       printInfoString(info.getDict(), "Keywords",     "Keywords:     %s\n");
310       printInfoString(info.getDict(), "Author",       "Author:       %s\n");
311       printInfoString(info.getDict(), "Creator",      "Creator:      %s\n");
312       printInfoString(info.getDict(), "Producer",     "Producer:     %s\n");
313       printInfoDate(info.getDict(),   "CreationDate", "CreationDate: %s\n");
314       printInfoDate(info.getDict(),   "ModDate",      "ModDate:      %s\n");
315       printf("Pages:        %d\n", i->doc->getNumPages());
316       printf("Linearized:   %s\n", i->doc->isLinearized() ? "yes" : "no");
317       printf("Encrypted:    ");
318       if (i->doc->isEncrypted()) {
319         printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
320                i->doc->okToPrint() ? "yes" : "no",
321                i->doc->okToCopy() ? "yes" : "no",
322                i->doc->okToChange() ? "yes" : "no",
323                i->doc->okToAddNotes() ? "yes" : "no");
324       } else {
325         printf("no\n");
326       }
327     }
328     info.free();
329                    
330     pdf_doc->num_pages = i->doc->getNumPages();
331     i->protect = 0;
332     if (i->doc->isEncrypted()) {
333           if(!i->doc->okToCopy()) {
334               printf("PDF disallows copying.\n");
335               return 0;
336           }
337           if(!i->doc->okToChange() || !i->doc->okToAddNotes())
338               i->protect = 1;
339     }
340
341     InfoOutputDev*io = new InfoOutputDev();
342     int t;
343     i->pages = (pdf_page_info_t*)malloc(sizeof(pdf_page_info_t)*pdf_doc->num_pages);
344     memset(i->pages,0,sizeof(pdf_page_info_t)*pdf_doc->num_pages);
345     for(t=1;t<=pdf_doc->num_pages;t++) {
346         if(!global_page_range || is_in_range(t, global_page_range)) {
347             i->doc->displayPage((OutputDev*)io, t, zoom, zoom, /*rotate*/0, /*usemediabox*/true, /*crop*/true, /*doLinks*/(int)1);
348 #if xpdfUpdateVersion >= 16
349             i->doc->processLinks((OutputDev*)io, t);
350 #endif
351             i->pages[t-1].xMin = io->x1;
352             i->pages[t-1].yMin = io->y1;
353             i->pages[t-1].xMax = io->x2;
354             i->pages[t-1].yMax = io->y2;
355             i->pages[t-1].width = io->x2 - io->x1;
356             i->pages[t-1].height = io->y2 - io->y1;
357             i->pages[t-1].number_of_images = io->num_images;
358             i->pages[t-1].number_of_links = io->num_links;
359             i->pages[t-1].number_of_fonts = io->num_fonts;
360             i->pages[t-1].has_info = 1;
361         }
362     }
363     i->info = io;
364     i->outputDev = new GFXOutputDev(device_config);
365
366     pdf_doc->get = 0;
367     pdf_doc->destroy = pdf_doc_destroy;
368     pdf_doc->set_parameter = pdf_doc_set_parameter;
369     pdf_doc->getpage = pdf_doc_getpage;
370
371
372     return pdf_doc;
373
374 }
375
376 gfxsource_t*gfxsource_pdf_create()
377 {
378     gfxsource_t*src = (gfxsource_t*)malloc(sizeof(gfxsource_t));
379     memset(src, 0, sizeof(gfxsource_t));
380     src->set_parameter = pdf_set_parameter;
381     src->open = pdf_open;
382     return src;
383 }