|  | /* | 
|  | * pdf.c | 
|  | * | 
|  | * pdf file support for page | 
|  | */ | 
|  |  | 
|  | #include <u.h> | 
|  | #include <libc.h> | 
|  | #include <draw.h> | 
|  | #include <cursor.h> | 
|  | #include <thread.h> | 
|  | #include <bio.h> | 
|  | #include "page.h" | 
|  |  | 
|  | static Image*	pdfdrawpage(Document *d, int page); | 
|  | static char*	pdfpagename(Document*, int); | 
|  |  | 
|  | char *pdfprolog = | 
|  | #include "pdfprolog.c" | 
|  | ; | 
|  |  | 
|  | Rectangle | 
|  | pdfbbox(GSInfo *gs) | 
|  | { | 
|  | char *p; | 
|  | char *f[4]; | 
|  | Rectangle r; | 
|  |  | 
|  | r = Rect(0,0,0,0); | 
|  | waitgs(gs); | 
|  | gscmd(gs, "/CropBox knownoget {} {[0 0 0 0]} ifelse PAGE==\n"); | 
|  | p = Brdline(&gs->gsrd, '\n'); | 
|  | p[Blinelen(&gs->gsrd)-1] ='\0'; | 
|  | if(p[0] != '[') | 
|  | return r; | 
|  | if(tokenize(p+1, f, 4) != 4) | 
|  | return r; | 
|  | r = Rect(atoi(f[0]), atoi(f[1]), atoi(f[2]), atoi(f[3])); | 
|  | waitgs(gs); | 
|  | return r; | 
|  | } | 
|  |  | 
|  | Document* | 
|  | initpdf(Biobuf *b, int argc, char **argv, uchar *buf, int nbuf) | 
|  | { | 
|  | Document *d; | 
|  | PDFInfo *pdf; | 
|  | char *p; | 
|  | char *fn; | 
|  | char fdbuf[20]; | 
|  | int fd; | 
|  | int i, npage; | 
|  | Rectangle bbox; | 
|  |  | 
|  | if(argc > 1) { | 
|  | fprint(2, "can only view one pdf file at a time\n"); | 
|  | return nil; | 
|  | } | 
|  |  | 
|  | fprint(2, "reading through pdf...\n"); | 
|  | if(b == nil){	/* standard input; spool to disk (ouch) */ | 
|  | fd = spooltodisk(buf, nbuf, &fn); | 
|  | sprint(fdbuf, "/dev/fd/%d", fd); | 
|  | b = Bopen(fdbuf, OREAD); | 
|  | if(b == nil){ | 
|  | fprint(2, "cannot open disk spool file\n"); | 
|  | wexits("Bopen temp"); | 
|  | } | 
|  | }else | 
|  | fn = argv[0]; | 
|  |  | 
|  | /* sanity check */ | 
|  | Bseek(b, 0, 0); | 
|  | if(!(p = Brdline(b, '\n')) && !(p = Brdline(b, '\r'))) { | 
|  | fprint(2, "cannot find end of first line\n"); | 
|  | wexits("initps"); | 
|  | } | 
|  | if(strncmp(p, "%PDF-", 5) != 0) { | 
|  | werrstr("not pdf"); | 
|  | return nil; | 
|  | } | 
|  |  | 
|  | /* setup structures so one free suffices */ | 
|  | p = emalloc(sizeof(*d) + sizeof(*pdf)); | 
|  | d = (Document*) p; | 
|  | p += sizeof(*d); | 
|  | pdf = (PDFInfo*) p; | 
|  |  | 
|  | d->extra = pdf; | 
|  | d->b = b; | 
|  | d->drawpage = pdfdrawpage; | 
|  | d->pagename = pdfpagename; | 
|  | d->fwdonly = 0; | 
|  | d->type = Tpdf; | 
|  |  | 
|  | if(spawngs(&pdf->gs, "-dDELAYSAFER") < 0) | 
|  | return nil; | 
|  |  | 
|  | gscmd(&pdf->gs, "%s", pdfprolog); | 
|  | waitgs(&pdf->gs); | 
|  |  | 
|  | setdim(&pdf->gs, Rect(0,0,0,0), ppi, 0); | 
|  | gscmd(&pdf->gs, "(%s) (r) file { DELAYSAFER { .setsafe } if } stopped pop pdfopen begin\n", fn); | 
|  | gscmd(&pdf->gs, "pdfpagecount PAGE==\n"); | 
|  | p = Brdline(&pdf->gs.gsrd, '\n'); | 
|  | if(p == nil) { | 
|  | if(Blinelen(&pdf->gs.gsrd) > 0) { | 
|  | fprint(2, "unexpected output (too long) from gs\n"); | 
|  | return nil; | 
|  | } | 
|  | fprint(2, "early EOF from gs - is ghostscript installed?\n"); | 
|  | return nil; | 
|  | } | 
|  | npage = atoi(p); | 
|  | if(npage < 1) { | 
|  | fprint(2, "no pages?\n"); | 
|  | return nil; | 
|  | } | 
|  | d->npage = npage; | 
|  | d->docname = argv[0]; | 
|  |  | 
|  | gscmd(&pdf->gs, "Trailer\n"); | 
|  | bbox = pdfbbox(&pdf->gs); | 
|  |  | 
|  | pdf->pagebbox = emalloc(sizeof(Rectangle)*npage); | 
|  | for(i=0; i<npage; i++) { | 
|  | gscmd(&pdf->gs, "%d pdfgetpage\n", i+1); | 
|  | pdf->pagebbox[i] = pdfbbox(&pdf->gs); | 
|  | if(Dx(pdf->pagebbox[i]) <= 0) | 
|  | pdf->pagebbox[i] = bbox; | 
|  | } | 
|  | return d; | 
|  | } | 
|  |  | 
|  | static Image* | 
|  | pdfdrawpage(Document *doc, int page) | 
|  | { | 
|  | PDFInfo *pdf = doc->extra; | 
|  | Image *im; | 
|  |  | 
|  | gscmd(&pdf->gs, "%d DoPDFPage\n", page+1); | 
|  | im = convert(&pdf->gs.g); | 
|  | if(im == nil) { | 
|  | fprint(2, "fatal: readimage error %r\n"); | 
|  | wexits("readimage"); | 
|  | } | 
|  | waitgs(&pdf->gs); | 
|  | return im; | 
|  | } | 
|  |  | 
|  | static char* | 
|  | pdfpagename(Document *d, int page) | 
|  | { | 
|  | static char str[15]; | 
|  |  | 
|  | USED(d); | 
|  | sprint(str, "p %d", page+1); | 
|  | return str; | 
|  | } |