plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

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 }