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 }