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