1 /* 2 * graphics file reading for page 3 */ 4 5 #include <u.h> 6 #include <libc.h> 7 #include <draw.h> 8 #include <event.h> 9 #include <bio.h> 10 #include "page.h" 11 12 typedef struct Convert Convert; 13 typedef struct GfxInfo GfxInfo; 14 typedef struct Graphic Graphic; 15 16 struct Convert { 17 char *name; 18 char *cmd; 19 char *truecmd; /* cmd for true color */ 20 }; 21 22 struct GfxInfo { 23 Graphic *g; 24 }; 25 26 struct Graphic { 27 int type; 28 char *name; 29 uchar *buf; /* if stdin */ 30 int nbuf; 31 }; 32 33 enum { 34 Ipic, 35 Itiff, 36 Ijpeg, 37 Igif, 38 Iinferno, 39 Ifax, 40 Icvt2pic, 41 Iplan9bm, 42 Iccittg4, 43 Ippm, 44 }; 45 46 Convert cvt[] = { 47 [Ipic] { "plan9", "fb/3to1 rgbv %s |fb/pcp -tplan9" }, 48 [Itiff] { "tiff", "fb/tiff2pic %s | fb/3to1 rgbv | fb/pcp -tplan9" }, 49 [Iplan9bm] { "plan9bm", nil }, 50 [Ijpeg] { "jpeg", "jpg -9 %s", "jpg -t9 %s", }, 51 [Igif] { "gif", "gif -9 %s", "gif -t9 %s" }, 52 [Iinferno] { "inferno", nil }, 53 [Ifax] { "fax", "aux/g3p9bit -g %s" }, 54 [Icvt2pic] { "unknown", "fb/cvt2pic %s |fb/3to1 rgbv" }, 55 [Ippm] { "ppm", "ppm -9 %s", "ppm -t9 %s" }, 56 /* ``temporary'' hack for hobby */ 57 [Iccittg4] { "ccitt-g4", "cat %s|rx nslocum /usr/lib/ocr/bin/bcp -M|fb/pcp -tcompressed -l0" }, 58 }; 59 60 static Image* convert(Graphic*); 61 static Image* gfxdrawpage(Document *d, int page); 62 static char* gfxpagename(Document*, int); 63 static int spawnrc(char*, uchar*, int); 64 static void waitrc(void); 65 static int spawnpost(int); 66 static int addpage(Document*, char*); 67 static int rmpage(Document*, int); 68 static int genaddpage(Document*, char*, uchar*, int); 69 70 static char* 71 gfxpagename(Document *doc, int page) 72 { 73 GfxInfo *gfx = doc->extra; 74 return gfx->g[page].name; 75 } 76 77 static Image* 78 gfxdrawpage(Document *doc, int page) 79 { 80 GfxInfo *gfx = doc->extra; 81 return convert(gfx->g+page); 82 } 83 84 Document* 85 initgfx(Biobuf*, int argc, char **argv, uchar *buf, int nbuf) 86 { 87 GfxInfo *gfx; 88 Document *doc; 89 int i; 90 91 doc = emalloc(sizeof(*doc)); 92 gfx = emalloc(sizeof(*gfx)); 93 gfx->g = nil; 94 95 doc->npage = 0; 96 doc->drawpage = gfxdrawpage; 97 doc->pagename = gfxpagename; 98 doc->addpage = addpage; 99 doc->rmpage = rmpage; 100 doc->extra = gfx; 101 doc->fwdonly = 0; 102 103 fprint(2, "reading through graphics...\n"); 104 if(argc==0 && buf) 105 genaddpage(doc, nil, buf, nbuf); 106 else{ 107 for(i=0; i<argc; i++) 108 if(addpage(doc, argv[i]) < 0) 109 fprint(2, "warning: not including %s: %r\n", argv[i]); 110 } 111 112 return doc; 113 } 114 115 static int 116 genaddpage(Document *doc, char *name, uchar *buf, int nbuf) 117 { 118 Graphic *g; 119 GfxInfo *gfx; 120 Biobuf *b; 121 uchar xbuf[32]; 122 int i; 123 124 gfx = doc->extra; 125 126 assert((name == nil) ^ (buf == nil)); 127 assert(name != nil || doc->npage == 0); 128 129 for(i=0; i<doc->npage; i++) 130 if(strcmp(gfx->g[i].name, name) == 0) 131 return i; 132 133 if(name){ 134 if((b = Bopen(name, OREAD)) == nil) { 135 werrstr("Bopen: %r"); 136 return -1; 137 } 138 139 if(Bread(b, xbuf, sizeof xbuf) != sizeof xbuf) { 140 werrstr("short read: %r"); 141 return -1; 142 } 143 Bterm(b); 144 buf = xbuf; 145 nbuf = sizeof xbuf; 146 } 147 148 149 gfx->g = erealloc(gfx->g, (doc->npage+1)*(sizeof(*gfx->g))); 150 g = &gfx->g[doc->npage]; 151 152 memset(g, 0, sizeof *g); 153 if(memcmp(buf, "GIF", 3) == 0) 154 g->type = Igif; 155 else if(memcmp(buf, "\111\111\052\000", 4) == 0) 156 g->type = Itiff; 157 else if(memcmp(buf, "\115\115\000\052", 4) == 0) 158 g->type = Itiff; 159 else if(memcmp(buf, "\377\330\377", 3) == 0) 160 g->type = Ijpeg; 161 else if(memcmp(buf, "compressed\n", 11) == 0) 162 g->type = Iinferno; 163 else if(memcmp(buf, "\0PC Research, Inc", 17) == 0) 164 g->type = Ifax; 165 else if(memcmp(buf, "TYPE=ccitt-g31", 14) == 0) 166 g->type = Ifax; 167 else if(memcmp(buf, "II*", 3) == 0) 168 g->type = Ifax; 169 else if(memcmp(buf, "TYPE=ccitt-g4", 13) == 0) 170 g->type = Iccittg4; 171 else if(memcmp(buf, "TYPE=", 5) == 0) 172 g->type = Ipic; 173 else if(buf[0] == 'P' && '0' <= buf[1] && buf[1] <= '9') 174 g->type = Ippm; 175 else if(memcmp(buf, " ", 10) == 0 && 176 '0' <= buf[10] && buf[10] <= '9' && 177 buf[11] == ' ') 178 g->type = Iplan9bm; 179 else if(strtochan((char*)buf) != 0) 180 g->type = Iplan9bm; 181 else 182 g->type = Icvt2pic; 183 184 if(name) 185 g->name = estrdup(name); 186 else{ 187 g->name = estrdup("stdin"); /* so it can be freed */ 188 g->buf = buf; 189 g->nbuf = nbuf; 190 } 191 192 if(chatty) fprint(2, "classified \"%s\" as \"%s\"\n", g->name, cvt[g->type].name); 193 return doc->npage++; 194 } 195 196 static int 197 addpage(Document *doc, char *name) 198 { 199 return genaddpage(doc, name, nil, 0); 200 } 201 202 static int 203 rmpage(Document *doc, int n) 204 { 205 int i; 206 GfxInfo *gfx; 207 208 if(n < 0 || n >= doc->npage) 209 return -1; 210 211 gfx = doc->extra; 212 doc->npage--; 213 free(gfx->g[n].name); 214 215 for(i=n; i<doc->npage; i++) 216 gfx->g[i] = gfx->g[i+1]; 217 218 if(n < doc->npage) 219 return n; 220 if(n == 0) 221 return 0; 222 return n-1; 223 } 224 225 226 static Image* 227 convert(Graphic *g) 228 { 229 int fd; 230 Convert c; 231 char *cmd; 232 char *name, buf[1000]; 233 Image *im; 234 int rcspawned = 0; 235 Waitmsg w; 236 237 c = cvt[g->type]; 238 if(c.cmd == nil) { 239 if(chatty) fprint(2, "no conversion for bitmap \"%s\"...\n", g->name); 240 if(g->buf == nil){ /* not stdin */ 241 fd = open(g->name, OREAD); 242 if(fd < 0) { 243 fprint(2, "cannot open file: %r\n"); 244 wexits("open"); 245 } 246 }else 247 fd = stdinpipe(g->buf, g->nbuf); 248 } else { 249 cmd = c.cmd; 250 if(truecolor && c.truecmd) 251 cmd = c.truecmd; 252 253 if(g->buf != nil) /* is stdin */ 254 name = ""; 255 else 256 name = g->name; 257 if(strlen(cmd)+strlen(name) > sizeof buf) { 258 fprint(2, "command too long\n"); 259 wexits("convert"); 260 } 261 snprint(buf, sizeof buf, cmd, name); 262 if(chatty) fprint(2, "using \"%s\" to convert \"%s\"...\n", buf, g->name); 263 fd = spawnrc(buf, g->buf, g->nbuf); 264 rcspawned++; 265 if(fd < 0) { 266 fprint(2, "cannot spawn converter: %r\n"); 267 wexits("convert"); 268 } 269 } 270 271 im = readimage(display, fd, 0); 272 if(im == nil) { 273 fprint(2, "warning: couldn't read image: %r\n"); 274 } 275 close(fd); 276 277 /* for some reason rx doesn't work well with wait */ 278 /* for some reason 3to1 wexits on success with a non-null status of |3to1 */ 279 if(rcspawned && g->type != Iccittg4) { 280 if(wait(&w)>=0 && w.msg[0] != '\0' && !strstr(w.msg, "3to1")) 281 fprint(2, "slave wait error: %s\n", w.msg); 282 } 283 return im; 284 } 285 286 static int 287 spawnrc(char *cmd, uchar *stdinbuf, int nstdinbuf) 288 { 289 int pfd[2]; 290 int pid; 291 292 if(chatty) fprint(2, "spawning(%s)...", cmd); 293 294 if(pipe(pfd) < 0) 295 return -1; 296 if((pid = fork()) < 0) 297 return -1; 298 299 if(pid == 0) { 300 close(pfd[1]); 301 if(stdinbuf) 302 dup(stdinpipe(stdinbuf, nstdinbuf), 0); 303 else 304 dup(open("/dev/null", OREAD), 0); 305 dup(pfd[0], 1); 306 //dup(pfd[0], 2); 307 execl("/bin/rc", "rc", "-c", cmd, nil); 308 wexits("exec"); 309 } 310 close(pfd[0]); 311 return pfd[1]; 312 } 313 314