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 typedef struct PDFInfo PDFInfo;
16 struct PDFInfo {
17 GSInfo gs;
18 Rectangle *pagebbox;
19 };
21 static Image* pdfdrawpage(Document *d, int page);
22 static char* pdfpagename(Document*, int);
24 char *pdfprolog =
25 #include "pdfprolog.c"
26 ;
28 Rectangle
29 pdfbbox(GSInfo *gs)
30 {
31 char *p;
32 char *f[4];
33 Rectangle r;
35 r = Rect(0,0,0,0);
36 waitgs(gs);
37 gscmd(gs, "/CropBox knownoget {} {[0 0 0 0]} ifelse PAGE==\n");
38 p = Brdline(&gs->gsrd, '\n');
39 p[Blinelen(&gs->gsrd)-1] ='\0';
40 if(p[0] != '[')
41 return r;
42 if(tokenize(p+1, f, 4) != 4)
43 return r;
44 r = Rect(atoi(f[0]), atoi(f[1]), atoi(f[2]), atoi(f[3]));
45 waitgs(gs);
46 return r;
47 }
49 Document*
50 initpdf(Biobuf *b, int argc, char **argv, uchar *buf, int nbuf)
51 {
52 Document *d;
53 PDFInfo *pdf;
54 char *p;
55 char *fn;
56 char fdbuf[20];
57 int fd;
58 int i, npage;
59 Rectangle bbox;
61 if(argc > 1) {
62 fprint(2, "can only view one pdf file at a time\n");
63 return nil;
64 }
66 fprint(2, "reading through pdf...\n");
67 if(b == nil){ /* standard input; spool to disk (ouch) */
68 fd = spooltodisk(buf, nbuf, &fn);
69 sprint(fdbuf, "/dev/fd/%d", fd);
70 b = Bopen(fdbuf, OREAD);
71 if(b == nil){
72 fprint(2, "cannot open disk spool file\n");
73 wexits("Bopen temp");
74 }
75 }else
76 fn = argv[0];
78 /* sanity check */
79 Bseek(b, 0, 0);
80 if(!(p = Brdline(b, '\n')) && !(p = Brdline(b, '\r'))) {
81 fprint(2, "cannot find end of first line\n");
82 wexits("initps");
83 }
84 if(strncmp(p, "%PDF-", 5) != 0) {
85 werrstr("not pdf");
86 return nil;
87 }
89 /* setup structures so one free suffices */
90 p = emalloc(sizeof(*d) + sizeof(*pdf));
91 d = (Document*) p;
92 p += sizeof(*d);
93 pdf = (PDFInfo*) p;
95 d->extra = pdf;
96 d->b = b;
97 d->drawpage = pdfdrawpage;
98 d->pagename = pdfpagename;
99 d->fwdonly = 0;
101 if(spawngs(&pdf->gs, "-dDELAYSAFER") < 0)
102 return nil;
104 gscmd(&pdf->gs, "%s", pdfprolog);
105 waitgs(&pdf->gs);
107 setdim(&pdf->gs, Rect(0,0,0,0), ppi, 0);
108 gscmd(&pdf->gs, "(%s) (r) file { DELAYSAFER { .setsafe } if } stopped pop pdfopen begin\n", fn);
109 gscmd(&pdf->gs, "pdfpagecount PAGE==\n");
110 p = Brdline(&pdf->gs.gsrd, '\n');
111 npage = atoi(p);
112 if(npage < 1) {
113 fprint(2, "no pages?\n");
114 return nil;
116 d->npage = npage;
117 d->docname = argv[0];
119 gscmd(&pdf->gs, "Trailer\n");
120 bbox = pdfbbox(&pdf->gs);
122 pdf->pagebbox = emalloc(sizeof(Rectangle)*npage);
123 for(i=0; i<npage; i++) {
124 gscmd(&pdf->gs, "%d pdfgetpage\n", i+1);
125 pdf->pagebbox[i] = pdfbbox(&pdf->gs);
126 if(Dx(pdf->pagebbox[i]) <= 0)
127 pdf->pagebbox[i] = bbox;
129 return d;
132 static Image*
133 pdfdrawpage(Document *doc, int page)
135 PDFInfo *pdf = doc->extra;
136 Image *im;
138 gscmd(&pdf->gs, "%d DoPDFPage\n", page+1);
139 im = convert(&pdf->gs.g);
140 if(im == nil) {
141 fprint(2, "fatal: readimage error %r\n");
142 wexits("readimage");
144 waitgs(&pdf->gs);
145 return im;
148 static char*
149 pdfpagename(Document *d, int page)
151 static char str[15];
153 USED(d);
154 sprint(str, "p %d", page+1);
155 return str;