123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332 |
- /*
- * graphics file reading for page
- */
- #include <u.h>
- #include <libc.h>
- #include <draw.h>
- #include <event.h>
- #include <bio.h>
- #include "page.h"
- typedef struct Convert Convert;
- typedef struct GfxInfo GfxInfo;
- typedef struct Graphic Graphic;
- struct Convert {
- char *name;
- char *cmd;
- char *truecmd; /* cmd for true color */
- };
- struct GfxInfo {
- Graphic *g;
- };
- struct Graphic {
- int type;
- char *name;
- uchar *buf; /* if stdin */
- int nbuf;
- };
- enum {
- Ipic,
- Itiff,
- Ijpeg,
- Igif,
- Iinferno,
- Ifax,
- Icvt2pic,
- Iplan9bm,
- Iccittg4,
- Ippm,
- Ipng,
- Iyuv,
- Ibmp,
- };
- /*
- * N.B. These commands need to read stdin if %a is replaced
- * with an empty string.
- */
- Convert cvt[] = {
- [Ipic] { "plan9", "fb/3to1 rgbv %a |fb/pcp -tplan9" },
- [Itiff] { "tiff", "fb/tiff2pic %a | fb/3to1 rgbv | fb/pcp -tplan9" },
- [Iplan9bm] { "plan9bm", nil },
- [Ijpeg] { "jpeg", "jpg -9 %a", "jpg -t9 %a" },
- [Igif] { "gif", "gif -9 %a", "gif -t9 %a" },
- [Iinferno] { "inferno", nil },
- [Ifax] { "fax", "aux/g3p9bit -g %a" },
- [Icvt2pic] { "unknown", "fb/cvt2pic %a |fb/3to1 rgbv" },
- [Ippm] { "ppm", "ppm -9 %a", "ppm -t9 %a" },
- /* ``temporary'' hack for hobby */
- [Iccittg4] { "ccitt-g4", "cat %a|rx nslocum /usr/lib/ocr/bin/bcp -M|fb/pcp -tcompressed -l0" },
- [Ipng] { "png", "png -9 %a", "png -t9 %a" },
- [Iyuv] { "yuv", "yuv -9 %a", "yuv -t9 %a" },
- [Ibmp] { "bmp", "bmp -9 %a", "bmp -t9 %a" },
- };
- static Image* convert(Graphic*);
- static Image* gfxdrawpage(Document *d, int page);
- static char* gfxpagename(Document*, int);
- static int spawnrc(char*, uchar*, int);
- 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*, int argc, char **argv, uchar *buf, int nbuf)
- {
- GfxInfo *gfx;
- Document *doc;
- int i;
- 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;
- 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=ccitt-g4", 13) == 0)
- g->type = Iccittg4;
- 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);
- else{
- g->name = estrdup("stdin"); /* so it can be freed */
- g->buf = buf;
- g->nbuf = 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;
- }
- static Image*
- convert(Graphic *g)
- {
- int fd;
- Convert c;
- char *cmd;
- char *name, buf[1000];
- Image *im;
- int rcspawned = 0;
- Waitmsg *w;
- c = cvt[g->type];
- if(c.cmd == nil) {
- if(chatty) fprint(2, "no conversion for bitmap \"%s\"...\n", g->name);
- if(g->buf == nil){ /* not stdin */
- fd = open(g->name, OREAD);
- if(fd < 0) {
- fprint(2, "cannot open file: %r\n");
- wexits("open");
- }
- }else
- fd = stdinpipe(g->buf, g->nbuf);
- } else {
- cmd = c.cmd;
- if(truecolor && c.truecmd)
- cmd = c.truecmd;
- if(g->buf != nil) /* is stdin */
- 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->buf, g->nbuf);
- 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);
- /* for some reason rx doesn't work well with wait */
- /* for some reason 3to1 exits on success with a non-null status of |3to1 */
- if(rcspawned && g->type != Iccittg4) {
- if((w=wait())!=nil && w->msg[0] && !strstr(w->msg, "3to1"))
- fprint(2, "slave wait error: %s\n", w->msg);
- free(w);
- }
- return im;
- }
- static int
- spawnrc(char *cmd, uchar *stdinbuf, int nstdinbuf)
- {
- int pfd[2];
- int pid;
- if(chatty) fprint(2, "spawning(%s)...", cmd);
- if(pipe(pfd) < 0)
- return -1;
- if((pid = fork()) < 0)
- return -1;
- if(pid == 0) {
- close(pfd[1]);
- if(stdinbuf)
- dup(stdinpipe(stdinbuf, nstdinbuf), 0);
- else
- dup(open("/dev/null", OREAD), 0);
- dup(pfd[0], 1);
- //dup(pfd[0], 2);
- execl("/bin/rc", "rc", "-c", cmd, nil);
- wexits("exec");
- }
- close(pfd[0]);
- return pfd[1];
- }
|