xref: /plan9/sys/src/cmd/page/gfx.c (revision ad6ca847b1a6a504acb0003cd6c5c6d92687369b)
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