| /* |
| * graphics file reading for page |
| */ |
| |
| #include <u.h> |
| #include <libc.h> |
| #include <draw.h> |
| #include <thread.h> |
| #include <bio.h> |
| #include <cursor.h> |
| #include "page.h" |
| |
| typedef struct Convert Convert; |
| typedef struct GfxInfo GfxInfo; |
| |
| struct Convert { |
| char *name; |
| char *cmd; |
| char *truecmd; /* cmd for true color */ |
| }; |
| |
| struct GfxInfo { |
| Graphic *g; |
| }; |
| |
| /* |
| * N.B. These commands need to read stdin if %a is replaced |
| * with an empty string. |
| */ |
| Convert cvt[] = { |
| { "plan9", "fb/3to1 rgbv %a |fb/pcp -tplan9" }, |
| { "tiff", "fb/tiff2pic %a | fb/3to1 rgbv | fb/pcp -tplan9" }, |
| { "jpeg", "jpg -9 %a", "jpg -t9 %a" }, |
| { "gif", "gif -9 %a", "gif -t9 %a" }, |
| { "inferno", nil }, |
| { "fax", "aux/g3p9bit -g %a" }, |
| { "unknown", "fb/cvt2pic %a |fb/3to1 rgbv" }, |
| { "plan9bm", nil }, |
| { "ppm", "ppm -9 %a", "ppm -t9 %a" }, |
| { "png", "png -9 %a", "png -t9 %a" }, |
| { "yuv", "yuv -9 %a", "yuv -t9 %a" }, |
| { "bmp", "bmp -9 %a", "bmp -t9 %a" }, |
| }; |
| |
| static Image* gfxdrawpage(Document *d, int page); |
| static char* gfxpagename(Document*, int); |
| static int spawnrc(char*, Graphic*); |
| //static void waitrc(void); |
| //static int spawnpost(int); |
| static int addpage(Document*, char*); |
| static int rmpage(Document*, int); |
| static int genaddpage(Document*, char*, uchar*, int); |
| |
| static char* |
| gfxpagename(Document *doc, int page) |
| { |
| GfxInfo *gfx = doc->extra; |
| return gfx->g[page].name; |
| } |
| |
| static Image* |
| gfxdrawpage(Document *doc, int page) |
| { |
| GfxInfo *gfx = doc->extra; |
| return convert(gfx->g+page); |
| } |
| |
| Document* |
| initgfx(Biobuf *b, int argc, char **argv, uchar *buf, int nbuf) |
| { |
| GfxInfo *gfx; |
| Document *doc; |
| int i; |
| |
| USED(b); |
| |
| doc = emalloc(sizeof(*doc)); |
| gfx = emalloc(sizeof(*gfx)); |
| gfx->g = nil; |
| |
| doc->npage = 0; |
| doc->drawpage = gfxdrawpage; |
| doc->pagename = gfxpagename; |
| doc->addpage = addpage; |
| doc->rmpage = rmpage; |
| doc->extra = gfx; |
| doc->fwdonly = 0; |
| doc->type = Tgfx; |
| |
| fprint(2, "reading through graphics...\n"); |
| if(argc==0 && buf) |
| genaddpage(doc, nil, buf, nbuf); |
| else{ |
| for(i=0; i<argc; i++) |
| if(addpage(doc, argv[i]) < 0) |
| fprint(2, "warning: not including %s: %r\n", argv[i]); |
| } |
| |
| return doc; |
| } |
| |
| static int |
| genaddpage(Document *doc, char *name, uchar *buf, int nbuf) |
| { |
| Graphic *g; |
| GfxInfo *gfx; |
| Biobuf *b; |
| uchar xbuf[32]; |
| int i, l; |
| |
| l = 0; |
| gfx = doc->extra; |
| |
| assert((name == nil) ^ (buf == nil)); |
| assert(name != nil || doc->npage == 0); |
| |
| for(i=0; i<doc->npage; i++) |
| if(strcmp(gfx->g[i].name, name) == 0) |
| return i; |
| |
| if(name){ |
| l = strlen(name); |
| if((b = Bopen(name, OREAD)) == nil) { |
| werrstr("Bopen: %r"); |
| return -1; |
| } |
| |
| if(Bread(b, xbuf, sizeof xbuf) != sizeof xbuf) { |
| werrstr("short read: %r"); |
| return -1; |
| } |
| Bterm(b); |
| buf = xbuf; |
| nbuf = sizeof xbuf; |
| } |
| |
| |
| gfx->g = erealloc(gfx->g, (doc->npage+1)*(sizeof(*gfx->g))); |
| g = &gfx->g[doc->npage]; |
| |
| memset(g, 0, sizeof *g); |
| if(memcmp(buf, "GIF", 3) == 0) |
| g->type = Igif; |
| else if(memcmp(buf, "\111\111\052\000", 4) == 0) |
| g->type = Itiff; |
| else if(memcmp(buf, "\115\115\000\052", 4) == 0) |
| g->type = Itiff; |
| else if(memcmp(buf, "\377\330\377", 3) == 0) |
| g->type = Ijpeg; |
| else if(memcmp(buf, "\211PNG\r\n\032\n", 3) == 0) |
| g->type = Ipng; |
| else if(memcmp(buf, "compressed\n", 11) == 0) |
| g->type = Iinferno; |
| else if(memcmp(buf, "\0PC Research, Inc", 17) == 0) |
| g->type = Ifax; |
| else if(memcmp(buf, "TYPE=ccitt-g31", 14) == 0) |
| g->type = Ifax; |
| else if(memcmp(buf, "II*", 3) == 0) |
| g->type = Ifax; |
| else if(memcmp(buf, "TYPE=", 5) == 0) |
| g->type = Ipic; |
| else if(buf[0] == 'P' && '0' <= buf[1] && buf[1] <= '9') |
| g->type = Ippm; |
| else if(memcmp(buf, "BM", 2) == 0) |
| g->type = Ibmp; |
| else if(memcmp(buf, " ", 10) == 0 && |
| '0' <= buf[10] && buf[10] <= '9' && |
| buf[11] == ' ') |
| g->type = Iplan9bm; |
| else if(strtochan((char*)buf) != 0) |
| g->type = Iplan9bm; |
| else if (l > 4 && strcmp(name + l -4, ".yuv") == 0) |
| g->type = Iyuv; |
| else |
| g->type = Icvt2pic; |
| |
| if(name){ |
| g->name = estrdup(name); |
| g->fd = -1; |
| }else{ |
| g->name = estrdup("stdin"); /* so it can be freed */ |
| g->fd = stdinpipe(buf, nbuf); |
| } |
| |
| if(chatty) fprint(2, "classified \"%s\" as \"%s\"\n", g->name, cvt[g->type].name); |
| return doc->npage++; |
| } |
| |
| static int |
| addpage(Document *doc, char *name) |
| { |
| return genaddpage(doc, name, nil, 0); |
| } |
| |
| static int |
| rmpage(Document *doc, int n) |
| { |
| int i; |
| GfxInfo *gfx; |
| |
| if(n < 0 || n >= doc->npage) |
| return -1; |
| |
| gfx = doc->extra; |
| doc->npage--; |
| free(gfx->g[n].name); |
| |
| for(i=n; i<doc->npage; i++) |
| gfx->g[i] = gfx->g[i+1]; |
| |
| if(n < doc->npage) |
| return n; |
| if(n == 0) |
| return 0; |
| return n-1; |
| } |
| |
| |
| Image* |
| convert(Graphic *g) |
| { |
| int fd; |
| Convert c; |
| char *cmd; |
| char *name, buf[1000]; |
| Image *im; |
| int rcspawned = 0; |
| |
| c = cvt[g->type]; |
| if(c.cmd == nil) { |
| if(chatty) fprint(2, "no conversion for bitmap \"%s\"...\n", g->name); |
| if(g->fd < 0){ /* not stdin */ |
| fd = open(g->name, OREAD); |
| if(fd < 0) { |
| fprint(2, "cannot open file: %r\n"); |
| wexits("open"); |
| } |
| }else |
| fd = g->fd; |
| } else { |
| cmd = c.cmd; |
| if(truecolor && c.truecmd) |
| cmd = c.truecmd; |
| |
| if(g->fd >= 0) /* is pipe */ |
| name = ""; |
| else |
| name = g->name; |
| if(strlen(cmd)+strlen(name) > sizeof buf) { |
| fprint(2, "command too long\n"); |
| wexits("convert"); |
| } |
| snprint(buf, sizeof buf, cmd, name); |
| if(chatty) fprint(2, "using \"%s\" to convert \"%s\"...\n", buf, g->name); |
| fd = spawnrc(buf, g); |
| rcspawned++; |
| if(fd < 0) { |
| fprint(2, "cannot spawn converter: %r\n"); |
| wexits("convert"); |
| } |
| } |
| |
| im = readimage(display, fd, 0); |
| if(im == nil) { |
| fprint(2, "warning: couldn't read image: %r\n"); |
| } |
| |
| close(fd); |
| return im; |
| } |
| |
| static int |
| spawnrc(char *cmd, Graphic *g) |
| { |
| int pfd[2]; |
| int fd[3]; |
| |
| if(chatty) fprint(2, "spawning(%s)...", cmd); |
| |
| if(pipe(pfd) < 0) |
| return -1; |
| |
| if(g->fd > 0) |
| fd[0] = dup(g->fd, -1); |
| else |
| fd[0] = open("/dev/null", OREAD); |
| fd[1] = pfd[1]; |
| fd[2] = dup(2, -1); |
| |
| if(threadspawnl(fd, "rc", "rc", "-c", cmd, nil) == -1) |
| return -1; |
| |
| return pfd[0]; |
| } |