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