17dd7cddfSDavid du Colombier /*
27dd7cddfSDavid du Colombier * graphics file reading for page
37dd7cddfSDavid du Colombier */
47dd7cddfSDavid du Colombier
57dd7cddfSDavid du Colombier #include <u.h>
67dd7cddfSDavid du Colombier #include <libc.h>
77dd7cddfSDavid du Colombier #include <draw.h>
87dd7cddfSDavid du Colombier #include <event.h>
97dd7cddfSDavid du Colombier #include <bio.h>
107dd7cddfSDavid du Colombier #include "page.h"
117dd7cddfSDavid du Colombier
127dd7cddfSDavid du Colombier typedef struct Convert Convert;
137dd7cddfSDavid du Colombier typedef struct GfxInfo GfxInfo;
147dd7cddfSDavid du Colombier typedef struct Graphic Graphic;
157dd7cddfSDavid du Colombier
167dd7cddfSDavid du Colombier struct Convert {
177dd7cddfSDavid du Colombier char *name;
187dd7cddfSDavid du Colombier char *cmd;
197dd7cddfSDavid du Colombier char *truecmd; /* cmd for true color */
207dd7cddfSDavid du Colombier };
217dd7cddfSDavid du Colombier
227dd7cddfSDavid du Colombier struct GfxInfo {
237dd7cddfSDavid du Colombier Graphic *g;
247dd7cddfSDavid du Colombier };
257dd7cddfSDavid du Colombier
267dd7cddfSDavid du Colombier struct Graphic {
277dd7cddfSDavid du Colombier int type;
287dd7cddfSDavid du Colombier char *name;
297dd7cddfSDavid du Colombier uchar *buf; /* if stdin */
307dd7cddfSDavid du Colombier int nbuf;
317dd7cddfSDavid du Colombier };
327dd7cddfSDavid du Colombier
337dd7cddfSDavid du Colombier enum {
347dd7cddfSDavid du Colombier Ipic,
357dd7cddfSDavid du Colombier Itiff,
367dd7cddfSDavid du Colombier Ijpeg,
377dd7cddfSDavid du Colombier Igif,
387dd7cddfSDavid du Colombier Iinferno,
397dd7cddfSDavid du Colombier Ifax,
407dd7cddfSDavid du Colombier Icvt2pic,
417dd7cddfSDavid du Colombier Iplan9bm,
427dd7cddfSDavid du Colombier Iccittg4,
437dd7cddfSDavid du Colombier Ippm,
449a747e4fSDavid du Colombier Ipng,
45da51d93aSDavid du Colombier Iyuv,
46da51d93aSDavid du Colombier Ibmp,
477dd7cddfSDavid du Colombier };
487dd7cddfSDavid du Colombier
493ff48bf5SDavid du Colombier /*
503ff48bf5SDavid du Colombier * N.B. These commands need to read stdin if %a is replaced
513ff48bf5SDavid du Colombier * with an empty string.
523ff48bf5SDavid du Colombier */
537dd7cddfSDavid du Colombier Convert cvt[] = {
543ff48bf5SDavid du Colombier [Ipic] { "plan9", "fb/3to1 rgbv %a |fb/pcp -tplan9" },
553ff48bf5SDavid du Colombier [Itiff] { "tiff", "fb/tiff2pic %a | fb/3to1 rgbv | fb/pcp -tplan9" },
567dd7cddfSDavid du Colombier [Iplan9bm] { "plan9bm", nil },
57da51d93aSDavid du Colombier [Ijpeg] { "jpeg", "jpg -9 %a", "jpg -t9 %a" },
583ff48bf5SDavid du Colombier [Igif] { "gif", "gif -9 %a", "gif -t9 %a" },
597dd7cddfSDavid du Colombier [Iinferno] { "inferno", nil },
603ff48bf5SDavid du Colombier [Ifax] { "fax", "aux/g3p9bit -g %a" },
613ff48bf5SDavid du Colombier [Icvt2pic] { "unknown", "fb/cvt2pic %a |fb/3to1 rgbv" },
623ff48bf5SDavid du Colombier [Ippm] { "ppm", "ppm -9 %a", "ppm -t9 %a" },
637dd7cddfSDavid du Colombier /* ``temporary'' hack for hobby */
643ff48bf5SDavid du Colombier [Iccittg4] { "ccitt-g4", "cat %a|rx nslocum /usr/lib/ocr/bin/bcp -M|fb/pcp -tcompressed -l0" },
653ff48bf5SDavid du Colombier [Ipng] { "png", "png -9 %a", "png -t9 %a" },
66da51d93aSDavid du Colombier [Iyuv] { "yuv", "yuv -9 %a", "yuv -t9 %a" },
67da51d93aSDavid du Colombier [Ibmp] { "bmp", "bmp -9 %a", "bmp -t9 %a" },
687dd7cddfSDavid du Colombier };
697dd7cddfSDavid du Colombier
707dd7cddfSDavid du Colombier static Image* convert(Graphic*);
717dd7cddfSDavid du Colombier static Image* gfxdrawpage(Document *d, int page);
727dd7cddfSDavid du Colombier static char* gfxpagename(Document*, int);
737dd7cddfSDavid du Colombier static int spawnrc(char*, uchar*, int);
747dd7cddfSDavid du Colombier static void waitrc(void);
757dd7cddfSDavid du Colombier static int spawnpost(int);
767dd7cddfSDavid du Colombier static int addpage(Document*, char*);
777dd7cddfSDavid du Colombier static int rmpage(Document*, int);
787dd7cddfSDavid du Colombier static int genaddpage(Document*, char*, uchar*, int);
797dd7cddfSDavid du Colombier
807dd7cddfSDavid du Colombier static char*
gfxpagename(Document * doc,int page)817dd7cddfSDavid du Colombier gfxpagename(Document *doc, int page)
827dd7cddfSDavid du Colombier {
837dd7cddfSDavid du Colombier GfxInfo *gfx = doc->extra;
847dd7cddfSDavid du Colombier return gfx->g[page].name;
857dd7cddfSDavid du Colombier }
867dd7cddfSDavid du Colombier
877dd7cddfSDavid du Colombier static Image*
gfxdrawpage(Document * doc,int page)887dd7cddfSDavid du Colombier gfxdrawpage(Document *doc, int page)
897dd7cddfSDavid du Colombier {
90*ad6ca847SDavid du Colombier setlabel(gfxpagename(doc, page));
917dd7cddfSDavid du Colombier GfxInfo *gfx = doc->extra;
927dd7cddfSDavid du Colombier return convert(gfx->g+page);
937dd7cddfSDavid du Colombier }
947dd7cddfSDavid du Colombier
957dd7cddfSDavid du Colombier Document*
initgfx(Biobuf *,int argc,char ** argv,uchar * buf,int nbuf)967dd7cddfSDavid du Colombier initgfx(Biobuf*, int argc, char **argv, uchar *buf, int nbuf)
977dd7cddfSDavid du Colombier {
987dd7cddfSDavid du Colombier GfxInfo *gfx;
997dd7cddfSDavid du Colombier Document *doc;
1007dd7cddfSDavid du Colombier int i;
1017dd7cddfSDavid du Colombier
1027dd7cddfSDavid du Colombier doc = emalloc(sizeof(*doc));
1037dd7cddfSDavid du Colombier gfx = emalloc(sizeof(*gfx));
1047dd7cddfSDavid du Colombier gfx->g = nil;
1057dd7cddfSDavid du Colombier
1067dd7cddfSDavid du Colombier doc->npage = 0;
1077dd7cddfSDavid du Colombier doc->drawpage = gfxdrawpage;
1087dd7cddfSDavid du Colombier doc->pagename = gfxpagename;
1097dd7cddfSDavid du Colombier doc->addpage = addpage;
1107dd7cddfSDavid du Colombier doc->rmpage = rmpage;
1117dd7cddfSDavid du Colombier doc->extra = gfx;
1127dd7cddfSDavid du Colombier doc->fwdonly = 0;
1137dd7cddfSDavid du Colombier
1147dd7cddfSDavid du Colombier fprint(2, "reading through graphics...\n");
1157dd7cddfSDavid du Colombier if(argc==0 && buf)
1167dd7cddfSDavid du Colombier genaddpage(doc, nil, buf, nbuf);
1177dd7cddfSDavid du Colombier else{
1187dd7cddfSDavid du Colombier for(i=0; i<argc; i++)
1197dd7cddfSDavid du Colombier if(addpage(doc, argv[i]) < 0)
1207dd7cddfSDavid du Colombier fprint(2, "warning: not including %s: %r\n", argv[i]);
1217dd7cddfSDavid du Colombier }
1227dd7cddfSDavid du Colombier
1237dd7cddfSDavid du Colombier return doc;
1247dd7cddfSDavid du Colombier }
1257dd7cddfSDavid du Colombier
1267dd7cddfSDavid du Colombier static int
genaddpage(Document * doc,char * name,uchar * buf,int nbuf)1277dd7cddfSDavid du Colombier genaddpage(Document *doc, char *name, uchar *buf, int nbuf)
1287dd7cddfSDavid du Colombier {
1297dd7cddfSDavid du Colombier Graphic *g;
1307dd7cddfSDavid du Colombier GfxInfo *gfx;
1317dd7cddfSDavid du Colombier Biobuf *b;
1327dd7cddfSDavid du Colombier uchar xbuf[32];
133da51d93aSDavid du Colombier int i, l;
1347dd7cddfSDavid du Colombier
135da51d93aSDavid du Colombier l = 0;
1367dd7cddfSDavid du Colombier gfx = doc->extra;
1377dd7cddfSDavid du Colombier
1387dd7cddfSDavid du Colombier assert((name == nil) ^ (buf == nil));
1397dd7cddfSDavid du Colombier assert(name != nil || doc->npage == 0);
1407dd7cddfSDavid du Colombier
1417dd7cddfSDavid du Colombier for(i=0; i<doc->npage; i++)
1427dd7cddfSDavid du Colombier if(strcmp(gfx->g[i].name, name) == 0)
1437dd7cddfSDavid du Colombier return i;
1447dd7cddfSDavid du Colombier
1457dd7cddfSDavid du Colombier if(name){
146da51d93aSDavid du Colombier l = strlen(name);
1477dd7cddfSDavid du Colombier if((b = Bopen(name, OREAD)) == nil) {
1487dd7cddfSDavid du Colombier werrstr("Bopen: %r");
1497dd7cddfSDavid du Colombier return -1;
1507dd7cddfSDavid du Colombier }
1517dd7cddfSDavid du Colombier
1527dd7cddfSDavid du Colombier if(Bread(b, xbuf, sizeof xbuf) != sizeof xbuf) {
1537dd7cddfSDavid du Colombier werrstr("short read: %r");
1547dd7cddfSDavid du Colombier return -1;
1557dd7cddfSDavid du Colombier }
1567dd7cddfSDavid du Colombier Bterm(b);
1577dd7cddfSDavid du Colombier buf = xbuf;
1587dd7cddfSDavid du Colombier nbuf = sizeof xbuf;
1597dd7cddfSDavid du Colombier }
1607dd7cddfSDavid du Colombier
1617dd7cddfSDavid du Colombier
1627dd7cddfSDavid du Colombier gfx->g = erealloc(gfx->g, (doc->npage+1)*(sizeof(*gfx->g)));
1637dd7cddfSDavid du Colombier g = &gfx->g[doc->npage];
1647dd7cddfSDavid du Colombier
1657dd7cddfSDavid du Colombier memset(g, 0, sizeof *g);
1667dd7cddfSDavid du Colombier if(memcmp(buf, "GIF", 3) == 0)
1677dd7cddfSDavid du Colombier g->type = Igif;
1687dd7cddfSDavid du Colombier else if(memcmp(buf, "\111\111\052\000", 4) == 0)
1697dd7cddfSDavid du Colombier g->type = Itiff;
1707dd7cddfSDavid du Colombier else if(memcmp(buf, "\115\115\000\052", 4) == 0)
1717dd7cddfSDavid du Colombier g->type = Itiff;
1727dd7cddfSDavid du Colombier else if(memcmp(buf, "\377\330\377", 3) == 0)
1737dd7cddfSDavid du Colombier g->type = Ijpeg;
1749a747e4fSDavid du Colombier else if(memcmp(buf, "\211PNG\r\n\032\n", 3) == 0)
1759a747e4fSDavid du Colombier g->type = Ipng;
1767dd7cddfSDavid du Colombier else if(memcmp(buf, "compressed\n", 11) == 0)
1777dd7cddfSDavid du Colombier g->type = Iinferno;
1787dd7cddfSDavid du Colombier else if(memcmp(buf, "\0PC Research, Inc", 17) == 0)
1797dd7cddfSDavid du Colombier g->type = Ifax;
1807dd7cddfSDavid du Colombier else if(memcmp(buf, "TYPE=ccitt-g31", 14) == 0)
1817dd7cddfSDavid du Colombier g->type = Ifax;
1827dd7cddfSDavid du Colombier else if(memcmp(buf, "II*", 3) == 0)
1837dd7cddfSDavid du Colombier g->type = Ifax;
1847dd7cddfSDavid du Colombier else if(memcmp(buf, "TYPE=ccitt-g4", 13) == 0)
1857dd7cddfSDavid du Colombier g->type = Iccittg4;
1867dd7cddfSDavid du Colombier else if(memcmp(buf, "TYPE=", 5) == 0)
1877dd7cddfSDavid du Colombier g->type = Ipic;
1887dd7cddfSDavid du Colombier else if(buf[0] == 'P' && '0' <= buf[1] && buf[1] <= '9')
1897dd7cddfSDavid du Colombier g->type = Ippm;
190da51d93aSDavid du Colombier else if(memcmp(buf, "BM", 2) == 0)
191da51d93aSDavid du Colombier g->type = Ibmp;
1927dd7cddfSDavid du Colombier else if(memcmp(buf, " ", 10) == 0 &&
1937dd7cddfSDavid du Colombier '0' <= buf[10] && buf[10] <= '9' &&
1947dd7cddfSDavid du Colombier buf[11] == ' ')
1957dd7cddfSDavid du Colombier g->type = Iplan9bm;
1967dd7cddfSDavid du Colombier else if(strtochan((char*)buf) != 0)
1977dd7cddfSDavid du Colombier g->type = Iplan9bm;
198da51d93aSDavid du Colombier else if (l > 4 && strcmp(name + l -4, ".yuv") == 0)
199da51d93aSDavid du Colombier g->type = Iyuv;
2007dd7cddfSDavid du Colombier else
2017dd7cddfSDavid du Colombier g->type = Icvt2pic;
2027dd7cddfSDavid du Colombier
2037dd7cddfSDavid du Colombier if(name)
2047dd7cddfSDavid du Colombier g->name = estrdup(name);
2057dd7cddfSDavid du Colombier else{
2067dd7cddfSDavid du Colombier g->name = estrdup("stdin"); /* so it can be freed */
2077dd7cddfSDavid du Colombier g->buf = buf;
2087dd7cddfSDavid du Colombier g->nbuf = nbuf;
2097dd7cddfSDavid du Colombier }
2107dd7cddfSDavid du Colombier
2117dd7cddfSDavid du Colombier if(chatty) fprint(2, "classified \"%s\" as \"%s\"\n", g->name, cvt[g->type].name);
2127dd7cddfSDavid du Colombier return doc->npage++;
2137dd7cddfSDavid du Colombier }
2147dd7cddfSDavid du Colombier
2157dd7cddfSDavid du Colombier static int
addpage(Document * doc,char * name)2167dd7cddfSDavid du Colombier addpage(Document *doc, char *name)
2177dd7cddfSDavid du Colombier {
2187dd7cddfSDavid du Colombier return genaddpage(doc, name, nil, 0);
2197dd7cddfSDavid du Colombier }
2207dd7cddfSDavid du Colombier
2217dd7cddfSDavid du Colombier static int
rmpage(Document * doc,int n)2227dd7cddfSDavid du Colombier rmpage(Document *doc, int n)
2237dd7cddfSDavid du Colombier {
2247dd7cddfSDavid du Colombier int i;
2257dd7cddfSDavid du Colombier GfxInfo *gfx;
2267dd7cddfSDavid du Colombier
2277dd7cddfSDavid du Colombier if(n < 0 || n >= doc->npage)
2287dd7cddfSDavid du Colombier return -1;
2297dd7cddfSDavid du Colombier
2307dd7cddfSDavid du Colombier gfx = doc->extra;
2317dd7cddfSDavid du Colombier doc->npage--;
2327dd7cddfSDavid du Colombier free(gfx->g[n].name);
2337dd7cddfSDavid du Colombier
2347dd7cddfSDavid du Colombier for(i=n; i<doc->npage; i++)
2357dd7cddfSDavid du Colombier gfx->g[i] = gfx->g[i+1];
2367dd7cddfSDavid du Colombier
2377dd7cddfSDavid du Colombier if(n < doc->npage)
2387dd7cddfSDavid du Colombier return n;
2397dd7cddfSDavid du Colombier if(n == 0)
2407dd7cddfSDavid du Colombier return 0;
2417dd7cddfSDavid du Colombier return n-1;
2427dd7cddfSDavid du Colombier }
2437dd7cddfSDavid du Colombier
2447dd7cddfSDavid du Colombier
2457dd7cddfSDavid du Colombier static Image*
convert(Graphic * g)2467dd7cddfSDavid du Colombier convert(Graphic *g)
2477dd7cddfSDavid du Colombier {
2487dd7cddfSDavid du Colombier int fd;
2497dd7cddfSDavid du Colombier Convert c;
2507dd7cddfSDavid du Colombier char *cmd;
2517dd7cddfSDavid du Colombier char *name, buf[1000];
2527dd7cddfSDavid du Colombier Image *im;
2537dd7cddfSDavid du Colombier int rcspawned = 0;
2549a747e4fSDavid du Colombier Waitmsg *w;
2557dd7cddfSDavid du Colombier
2567dd7cddfSDavid du Colombier c = cvt[g->type];
2577dd7cddfSDavid du Colombier if(c.cmd == nil) {
2587dd7cddfSDavid du Colombier if(chatty) fprint(2, "no conversion for bitmap \"%s\"...\n", g->name);
2597dd7cddfSDavid du Colombier if(g->buf == nil){ /* not stdin */
2607dd7cddfSDavid du Colombier fd = open(g->name, OREAD);
2617dd7cddfSDavid du Colombier if(fd < 0) {
2627dd7cddfSDavid du Colombier fprint(2, "cannot open file: %r\n");
2637dd7cddfSDavid du Colombier wexits("open");
2647dd7cddfSDavid du Colombier }
2657dd7cddfSDavid du Colombier }else
2667dd7cddfSDavid du Colombier fd = stdinpipe(g->buf, g->nbuf);
2677dd7cddfSDavid du Colombier } else {
2687dd7cddfSDavid du Colombier cmd = c.cmd;
2697dd7cddfSDavid du Colombier if(truecolor && c.truecmd)
2707dd7cddfSDavid du Colombier cmd = c.truecmd;
2717dd7cddfSDavid du Colombier
2727dd7cddfSDavid du Colombier if(g->buf != nil) /* is stdin */
2737dd7cddfSDavid du Colombier name = "";
2747dd7cddfSDavid du Colombier else
2757dd7cddfSDavid du Colombier name = g->name;
2767dd7cddfSDavid du Colombier if(strlen(cmd)+strlen(name) > sizeof buf) {
2777dd7cddfSDavid du Colombier fprint(2, "command too long\n");
2787dd7cddfSDavid du Colombier wexits("convert");
2797dd7cddfSDavid du Colombier }
2807dd7cddfSDavid du Colombier snprint(buf, sizeof buf, cmd, name);
2817dd7cddfSDavid du Colombier if(chatty) fprint(2, "using \"%s\" to convert \"%s\"...\n", buf, g->name);
2827dd7cddfSDavid du Colombier fd = spawnrc(buf, g->buf, g->nbuf);
2837dd7cddfSDavid du Colombier rcspawned++;
2847dd7cddfSDavid du Colombier if(fd < 0) {
2857dd7cddfSDavid du Colombier fprint(2, "cannot spawn converter: %r\n");
2867dd7cddfSDavid du Colombier wexits("convert");
2877dd7cddfSDavid du Colombier }
2887dd7cddfSDavid du Colombier }
2897dd7cddfSDavid du Colombier
2907dd7cddfSDavid du Colombier im = readimage(display, fd, 0);
2917dd7cddfSDavid du Colombier if(im == nil) {
2927dd7cddfSDavid du Colombier fprint(2, "warning: couldn't read image: %r\n");
2937dd7cddfSDavid du Colombier }
2947dd7cddfSDavid du Colombier close(fd);
2957dd7cddfSDavid du Colombier
2967dd7cddfSDavid du Colombier /* for some reason rx doesn't work well with wait */
2979a747e4fSDavid du Colombier /* for some reason 3to1 exits on success with a non-null status of |3to1 */
2987dd7cddfSDavid du Colombier if(rcspawned && g->type != Iccittg4) {
2999a747e4fSDavid du Colombier if((w=wait())!=nil && w->msg[0] && !strstr(w->msg, "3to1"))
3009a747e4fSDavid du Colombier fprint(2, "slave wait error: %s\n", w->msg);
3019a747e4fSDavid du Colombier free(w);
3027dd7cddfSDavid du Colombier }
3037dd7cddfSDavid du Colombier return im;
3047dd7cddfSDavid du Colombier }
3057dd7cddfSDavid du Colombier
3067dd7cddfSDavid du Colombier static int
spawnrc(char * cmd,uchar * stdinbuf,int nstdinbuf)3077dd7cddfSDavid du Colombier spawnrc(char *cmd, uchar *stdinbuf, int nstdinbuf)
3087dd7cddfSDavid du Colombier {
3097dd7cddfSDavid du Colombier int pfd[2];
3107dd7cddfSDavid du Colombier int pid;
3117dd7cddfSDavid du Colombier
3127dd7cddfSDavid du Colombier if(chatty) fprint(2, "spawning(%s)...", cmd);
3137dd7cddfSDavid du Colombier
3147dd7cddfSDavid du Colombier if(pipe(pfd) < 0)
3157dd7cddfSDavid du Colombier return -1;
3167dd7cddfSDavid du Colombier if((pid = fork()) < 0)
3177dd7cddfSDavid du Colombier return -1;
3187dd7cddfSDavid du Colombier
3197dd7cddfSDavid du Colombier if(pid == 0) {
3207dd7cddfSDavid du Colombier close(pfd[1]);
3217dd7cddfSDavid du Colombier if(stdinbuf)
3227dd7cddfSDavid du Colombier dup(stdinpipe(stdinbuf, nstdinbuf), 0);
3237dd7cddfSDavid du Colombier else
3247dd7cddfSDavid du Colombier dup(open("/dev/null", OREAD), 0);
3257dd7cddfSDavid du Colombier dup(pfd[0], 1);
3267dd7cddfSDavid du Colombier //dup(pfd[0], 2);
3277dd7cddfSDavid du Colombier execl("/bin/rc", "rc", "-c", cmd, nil);
3287dd7cddfSDavid du Colombier wexits("exec");
3297dd7cddfSDavid du Colombier }
3307dd7cddfSDavid du Colombier close(pfd[0]);
3317dd7cddfSDavid du Colombier return pfd[1];
3327dd7cddfSDavid du Colombier }
3337dd7cddfSDavid du Colombier
334