xref: /plan9/sys/src/cmd/page/pdf.c (revision 306ddfb62542c069ceb2810f968d09ea5505d2db)
17dd7cddfSDavid du Colombier /*
27dd7cddfSDavid du Colombier  * pdf.c
37dd7cddfSDavid du Colombier  *
47dd7cddfSDavid du Colombier  * pdf file support for page
57dd7cddfSDavid du Colombier  */
67dd7cddfSDavid du Colombier 
77dd7cddfSDavid du Colombier #include <u.h>
87dd7cddfSDavid du Colombier #include <libc.h>
97dd7cddfSDavid du Colombier #include <draw.h>
107dd7cddfSDavid du Colombier #include <event.h>
117dd7cddfSDavid du Colombier #include <bio.h>
127dd7cddfSDavid du Colombier #include "page.h"
137dd7cddfSDavid du Colombier 
147dd7cddfSDavid du Colombier typedef struct PDFInfo	PDFInfo;
157dd7cddfSDavid du Colombier struct PDFInfo {
167dd7cddfSDavid du Colombier 	GSInfo;
177dd7cddfSDavid du Colombier 	Rectangle *pagebbox;
187dd7cddfSDavid du Colombier };
197dd7cddfSDavid du Colombier 
207dd7cddfSDavid du Colombier static Image*	pdfdrawpage(Document *d, int page);
217dd7cddfSDavid du Colombier static char*	pdfpagename(Document*, int);
227dd7cddfSDavid du Colombier 
237dd7cddfSDavid du Colombier char *pdfprolog =
24d9306527SDavid du Colombier #include "pdfprolog.c"
25d9306527SDavid du Colombier 	;
267dd7cddfSDavid du Colombier 
277dd7cddfSDavid du Colombier Rectangle
pdfbbox(GSInfo * gs)287dd7cddfSDavid du Colombier pdfbbox(GSInfo *gs)
297dd7cddfSDavid du Colombier {
307dd7cddfSDavid du Colombier 	char *p;
317dd7cddfSDavid du Colombier 	char *f[4];
327dd7cddfSDavid du Colombier 	Rectangle r;
337dd7cddfSDavid du Colombier 
347dd7cddfSDavid du Colombier 	r = Rect(0,0,0,0);
357dd7cddfSDavid du Colombier 	waitgs(gs);
367dd7cddfSDavid du Colombier 	gscmd(gs, "/CropBox knownoget {} {[0 0 0 0]} ifelse PAGE==\n");
377dd7cddfSDavid du Colombier 	p = Brdline(&gs->gsrd, '\n');
38d9306527SDavid du Colombier 	p[Blinelen(&gs->gsrd)-1] ='\0';
397dd7cddfSDavid du Colombier 	if(p[0] != '[')
407dd7cddfSDavid du Colombier 		return r;
41d9306527SDavid du Colombier 	if(tokenize(p+1, f, 4) != 4)
427dd7cddfSDavid du Colombier 		return r;
437dd7cddfSDavid du Colombier 	r = Rect(atoi(f[0]), atoi(f[1]), atoi(f[2]), atoi(f[3]));
447dd7cddfSDavid du Colombier 	waitgs(gs);
457dd7cddfSDavid du Colombier 	return r;
467dd7cddfSDavid du Colombier }
477dd7cddfSDavid du Colombier 
487dd7cddfSDavid du Colombier Document*
initpdf(Biobuf * b,int argc,char ** argv,uchar * buf,int nbuf)497dd7cddfSDavid du Colombier initpdf(Biobuf *b, int argc, char **argv, uchar *buf, int nbuf)
507dd7cddfSDavid du Colombier {
517dd7cddfSDavid du Colombier 	Document *d;
527dd7cddfSDavid du Colombier 	PDFInfo *pdf;
537dd7cddfSDavid du Colombier 	char *p;
547dd7cddfSDavid du Colombier 	char *fn;
557dd7cddfSDavid du Colombier 	char fdbuf[20];
567dd7cddfSDavid du Colombier 	int fd;
577dd7cddfSDavid du Colombier 	int i, npage;
587dd7cddfSDavid du Colombier 	Rectangle bbox;
597dd7cddfSDavid du Colombier 
607dd7cddfSDavid du Colombier 	if(argc > 1) {
617dd7cddfSDavid du Colombier 		fprint(2, "can only view one pdf file at a time\n");
627dd7cddfSDavid du Colombier 		return nil;
637dd7cddfSDavid du Colombier 	}
647dd7cddfSDavid du Colombier 
657dd7cddfSDavid du Colombier 	fprint(2, "reading through pdf...\n");
667dd7cddfSDavid du Colombier 	if(b == nil){	/* standard input; spool to disk (ouch) */
677dd7cddfSDavid du Colombier 		fd = spooltodisk(buf, nbuf, &fn);
687dd7cddfSDavid du Colombier 		sprint(fdbuf, "/fd/%d", fd);
697dd7cddfSDavid du Colombier 		b = Bopen(fdbuf, OREAD);
707dd7cddfSDavid du Colombier 		if(b == nil){
717dd7cddfSDavid du Colombier 			fprint(2, "cannot open disk spool file\n");
727dd7cddfSDavid du Colombier 			wexits("Bopen temp");
737dd7cddfSDavid du Colombier 		}
747dd7cddfSDavid du Colombier 	}else
757dd7cddfSDavid du Colombier 		fn = argv[0];
767dd7cddfSDavid du Colombier 
777dd7cddfSDavid du Colombier 	/* sanity check */
787dd7cddfSDavid du Colombier 	Bseek(b, 0, 0);
797dd7cddfSDavid du Colombier 	if(!(p = Brdline(b, '\n')) && !(p = Brdline(b, '\r'))) {
807dd7cddfSDavid du Colombier 		fprint(2, "cannot find end of first line\n");
817dd7cddfSDavid du Colombier 		wexits("initps");
827dd7cddfSDavid du Colombier 	}
837dd7cddfSDavid du Colombier 	if(strncmp(p, "%PDF-", 5) != 0) {
847dd7cddfSDavid du Colombier 		werrstr("not pdf");
857dd7cddfSDavid du Colombier 		return nil;
867dd7cddfSDavid du Colombier 	}
877dd7cddfSDavid du Colombier 
887dd7cddfSDavid du Colombier 	/* setup structures so one free suffices */
897dd7cddfSDavid du Colombier 	p = emalloc(sizeof(*d) + sizeof(*pdf));
907dd7cddfSDavid du Colombier 	d = (Document*) p;
917dd7cddfSDavid du Colombier 	p += sizeof(*d);
927dd7cddfSDavid du Colombier 	pdf = (PDFInfo*) p;
937dd7cddfSDavid du Colombier 
947dd7cddfSDavid du Colombier 	d->extra = pdf;
957dd7cddfSDavid du Colombier 	d->b = b;
967dd7cddfSDavid du Colombier 	d->drawpage = pdfdrawpage;
977dd7cddfSDavid du Colombier 	d->pagename = pdfpagename;
987dd7cddfSDavid du Colombier 	d->fwdonly = 0;
997dd7cddfSDavid du Colombier 
100593dc095SDavid du Colombier 	if(spawngs(pdf, "-dDELAYSAFER") < 0)
1017dd7cddfSDavid du Colombier 		return nil;
1027dd7cddfSDavid du Colombier 
1037dd7cddfSDavid du Colombier 	gscmd(pdf, "%s", pdfprolog);
1047dd7cddfSDavid du Colombier 	waitgs(pdf);
1057dd7cddfSDavid du Colombier 
106d9306527SDavid du Colombier 	setdim(pdf, Rect(0,0,0,0), ppi, 0);
107593dc095SDavid du Colombier 	gscmd(pdf, "(%s) (r) file { DELAYSAFER { .setsafe } if } stopped pop pdfopen begin\n", fn);
1087dd7cddfSDavid du Colombier 	gscmd(pdf, "pdfpagecount PAGE==\n");
1097dd7cddfSDavid du Colombier 	p = Brdline(&pdf->gsrd, '\n');
110*306ddfb6SDavid du Colombier 	npage = (p != nil? atoi(p): 0);
1117dd7cddfSDavid du Colombier 	if(npage < 1) {
1127dd7cddfSDavid du Colombier 		fprint(2, "no pages?\n");
1137dd7cddfSDavid du Colombier 		return nil;
1147dd7cddfSDavid du Colombier 	}
1157dd7cddfSDavid du Colombier 	d->npage = npage;
1167dd7cddfSDavid du Colombier 	d->docname = argv[0];
1177dd7cddfSDavid du Colombier 
1187dd7cddfSDavid du Colombier 	gscmd(pdf, "Trailer\n");
1197dd7cddfSDavid du Colombier 	bbox = pdfbbox(pdf);
1207dd7cddfSDavid du Colombier 
1217dd7cddfSDavid du Colombier 	pdf->pagebbox = emalloc(sizeof(Rectangle)*npage);
1227dd7cddfSDavid du Colombier 	for(i=0; i<npage; i++) {
1237dd7cddfSDavid du Colombier 		gscmd(pdf, "%d pdfgetpage\n", i+1);
1247dd7cddfSDavid du Colombier 		pdf->pagebbox[i] = pdfbbox(pdf);
1257dd7cddfSDavid du Colombier 		if(Dx(pdf->pagebbox[i]) <= 0)
1267dd7cddfSDavid du Colombier 			pdf->pagebbox[i] = bbox;
1277dd7cddfSDavid du Colombier 	}
1287dd7cddfSDavid du Colombier 	return d;
1297dd7cddfSDavid du Colombier }
1307dd7cddfSDavid du Colombier 
1317dd7cddfSDavid du Colombier static Image*
pdfdrawpage(Document * doc,int page)1327dd7cddfSDavid du Colombier pdfdrawpage(Document *doc, int page)
1337dd7cddfSDavid du Colombier {
1347dd7cddfSDavid du Colombier 	PDFInfo *pdf = doc->extra;
1357dd7cddfSDavid du Colombier 	Image *im;
1367dd7cddfSDavid du Colombier 
1377dd7cddfSDavid du Colombier 	gscmd(pdf, "%d DoPDFPage\n", page+1);
1387dd7cddfSDavid du Colombier 	im = readimage(display, pdf->gsdfd, 0);
1397dd7cddfSDavid du Colombier 	if(im == nil) {
1407dd7cddfSDavid du Colombier 		fprint(2, "fatal: readimage error %r\n");
1417dd7cddfSDavid du Colombier 		wexits("readimage");
1427dd7cddfSDavid du Colombier 	}
1437dd7cddfSDavid du Colombier 	waitgs(pdf);
1447dd7cddfSDavid du Colombier 	return im;
1457dd7cddfSDavid du Colombier }
1467dd7cddfSDavid du Colombier 
1477dd7cddfSDavid du Colombier static char*
pdfpagename(Document *,int page)1487dd7cddfSDavid du Colombier pdfpagename(Document*, int page)
1497dd7cddfSDavid du Colombier {
1507dd7cddfSDavid du Colombier 	static char str[15];
1517dd7cddfSDavid du Colombier 	sprint(str, "p %d", page+1);
1527dd7cddfSDavid du Colombier 	return str;
1537dd7cddfSDavid du Colombier }
154