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 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* 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 = atoi(p); 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* 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* 148 pdfpagename(Document*, int page) 149 { 150 static char str[15]; 151 sprint(str, "p %d", page+1); 152 return str; 153 } 154