plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

pdf.c (3167B)


      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 <cursor.h>
     11 #include <thread.h>
     12 #include <bio.h>
     13 #include "page.h"
     14 
     15 static Image*	pdfdrawpage(Document *d, int page);
     16 static char*	pdfpagename(Document*, int);
     17 
     18 char *pdfprolog =
     19 #include "pdfprolog.c"
     20 	;
     21 
     22 Rectangle
     23 pdfbbox(GSInfo *gs)
     24 {
     25 	char *p;
     26 	char *f[4];
     27 	Rectangle r;
     28 
     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 }
     42 
     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;
     54 
     55 	if(argc > 1) {
     56 		fprint(2, "can only view one pdf file at a time\n");
     57 		return nil;
     58 	}
     59 
     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];
     71 
     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 	}
     82 
     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;
     88 
     89 	d->extra = pdf;
     90 	d->b = b;
     91 	d->drawpage = pdfdrawpage;
     92 	d->pagename = pdfpagename;
     93 	d->fwdonly = 0;
     94 	d->type = Tpdf;
     95 
     96 	if(spawngs(&pdf->gs, "-dDELAYSAFER") < 0)
     97 		return nil;
     98 
     99 	gscmd(&pdf->gs, "%s", pdfprolog);
    100 	waitgs(&pdf->gs);
    101 
    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;
    110 		}
    111 		fprint(2, "early EOF from gs - is ghostscript installed?\n");
    112 		return nil;
    113 	}
    114 	npage = atoi(p);
    115 	if(npage < 1) {
    116 		fprint(2, "no pages?\n");
    117 		return nil;
    118 	}
    119 	d->npage = npage;
    120 	d->docname = argv[0];
    121 
    122 	gscmd(&pdf->gs, "Trailer\n");
    123 	bbox = pdfbbox(&pdf->gs);
    124 
    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;
    131 	}
    132 	return d;
    133 }
    134 
    135 static Image*
    136 pdfdrawpage(Document *doc, int page)
    137 {
    138 	PDFInfo *pdf = doc->extra;
    139 	Image *im;
    140 
    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");
    146 	}
    147 	waitgs(&pdf->gs);
    148 	return im;
    149 }
    150 
    151 static char*
    152 pdfpagename(Document *d, int page)
    153 {
    154 	static char str[15];
    155 
    156 	USED(d);
    157 	sprint(str, "p %d", page+1);
    158 	return str;
    159 }