Blob


1 /*
2 * pdf.c
3 *
4 * pdf file support for page
5 */
7 #include <u.h>
8 #include <libc.h>
9 #include <draw.h>
10 #include <cursor.h>
11 #include <thread.h>
12 #include <bio.h>
13 #include "page.h"
15 static Image* pdfdrawpage(Document *d, int page);
16 static char* pdfpagename(Document*, int);
18 char *pdfprolog =
19 #include "pdfprolog.c"
20 ;
22 Rectangle
23 pdfbbox(GSInfo *gs)
24 {
25 char *p;
26 char *f[4];
27 Rectangle r;
29 r = Rect(0,0,0,0);
30 waitgs(gs);
31 gscmd(gs, "/CropBox knownoget {} {[0 0 0 0]} ifelse PAGE==\n");
32 p = Brdline(&gs->gsrd, '\n');
33 p[Blinelen(&gs->gsrd)-1] ='\0';
34 if(p[0] != '[')
35 return r;
36 if(tokenize(p+1, f, 4) != 4)
37 return r;
38 r = Rect(atoi(f[0]), atoi(f[1]), atoi(f[2]), atoi(f[3]));
39 waitgs(gs);
40 return r;
41 }
43 Document*
44 initpdf(Biobuf *b, int argc, char **argv, uchar *buf, int nbuf)
45 {
46 Document *d;
47 PDFInfo *pdf;
48 char *p;
49 char *fn;
50 char fdbuf[20];
51 int fd;
52 int i, npage;
53 Rectangle bbox;
55 if(argc > 1) {
56 fprint(2, "can only view one pdf file at a time\n");
57 return nil;
58 }
60 fprint(2, "reading through pdf...\n");
61 if(b == nil){ /* standard input; spool to disk (ouch) */
62 fd = spooltodisk(buf, nbuf, &fn);
63 sprint(fdbuf, "/dev/fd/%d", fd);
64 b = Bopen(fdbuf, OREAD);
65 if(b == nil){
66 fprint(2, "cannot open disk spool file\n");
67 wexits("Bopen temp");
68 }
69 }else
70 fn = argv[0];
72 /* sanity check */
73 Bseek(b, 0, 0);
74 if(!(p = Brdline(b, '\n')) && !(p = Brdline(b, '\r'))) {
75 fprint(2, "cannot find end of first line\n");
76 wexits("initps");
77 }
78 if(strncmp(p, "%PDF-", 5) != 0) {
79 werrstr("not pdf");
80 return nil;
81 }
83 /* setup structures so one free suffices */
84 p = emalloc(sizeof(*d) + sizeof(*pdf));
85 d = (Document*) p;
86 p += sizeof(*d);
87 pdf = (PDFInfo*) p;
89 d->extra = pdf;
90 d->b = b;
91 d->drawpage = pdfdrawpage;
92 d->pagename = pdfpagename;
93 d->fwdonly = 0;
94 d->type = Tpdf;
96 if(spawngs(&pdf->gs, "-dDELAYSAFER") < 0)
97 return nil;
99 gscmd(&pdf->gs, "%s", pdfprolog);
100 waitgs(&pdf->gs);
102 setdim(&pdf->gs, Rect(0,0,0,0), ppi, 0);
103 gscmd(&pdf->gs, "(%s) (r) file { DELAYSAFER { .setsafe } if } stopped pop pdfopen begin\n", fn);
104 gscmd(&pdf->gs, "pdfpagecount PAGE==\n");
105 p = Brdline(&pdf->gs.gsrd, '\n');
106 if(p == nil) {
107 if(Blinelen(&pdf->gs.gsrd) > 0) {
108 fprint(2, "unexpected output (too long) from gs\n");
109 return nil;
111 fprint(2, "early EOF from gs - is ghostscript installed?\n");
112 return nil;
114 npage = atoi(p);
115 if(npage < 1) {
116 fprint(2, "no pages?\n");
117 return nil;
119 d->npage = npage;
120 d->docname = argv[0];
122 gscmd(&pdf->gs, "Trailer\n");
123 bbox = pdfbbox(&pdf->gs);
125 pdf->pagebbox = emalloc(sizeof(Rectangle)*npage);
126 for(i=0; i<npage; i++) {
127 gscmd(&pdf->gs, "%d pdfgetpage\n", i+1);
128 pdf->pagebbox[i] = pdfbbox(&pdf->gs);
129 if(Dx(pdf->pagebbox[i]) <= 0)
130 pdf->pagebbox[i] = bbox;
132 return d;
135 static Image*
136 pdfdrawpage(Document *doc, int page)
138 PDFInfo *pdf = doc->extra;
139 Image *im;
141 gscmd(&pdf->gs, "%d DoPDFPage\n", page+1);
142 im = convert(&pdf->gs.g);
143 if(im == nil) {
144 fprint(2, "fatal: readimage error %r\n");
145 wexits("readimage");
147 waitgs(&pdf->gs);
148 return im;
151 static char*
152 pdfpagename(Document *d, int page)
154 static char str[15];
156 USED(d);
157 sprint(str, "p %d", page+1);
158 return str;