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