xref: /plan9/sys/src/cmd/jpg/ico.c (revision e6d20ddfa7d12e75efbb79fca45df9e14315b5f6)
18fa2b2a7SDavid du Colombier #include <u.h>
28fa2b2a7SDavid du Colombier #include <libc.h>
38fa2b2a7SDavid du Colombier #include <bio.h>
48fa2b2a7SDavid du Colombier #include <draw.h>
58fa2b2a7SDavid du Colombier #include <event.h>
68fa2b2a7SDavid du Colombier #include <cursor.h>
78fa2b2a7SDavid du Colombier 
88fa2b2a7SDavid du Colombier typedef struct Icon Icon;
98fa2b2a7SDavid du Colombier struct Icon
108fa2b2a7SDavid du Colombier {
118fa2b2a7SDavid du Colombier 	Icon	*next;
128fa2b2a7SDavid du Colombier 
138fa2b2a7SDavid du Colombier 	uchar	w;		/* icon width */
148fa2b2a7SDavid du Colombier 	uchar	h;		/* icon height */
158fa2b2a7SDavid du Colombier 	ushort	ncolor;		/* number of colors */
168fa2b2a7SDavid du Colombier 	ushort	nplane;		/* number of bit planes */
178fa2b2a7SDavid du Colombier 	ushort	bits;		/* bits per pixel */
188fa2b2a7SDavid du Colombier 	ulong	len;		/* length of data */
198fa2b2a7SDavid du Colombier 	ulong	offset;		/* file offset to data */
208fa2b2a7SDavid du Colombier 
218fa2b2a7SDavid du Colombier 	Image	*img;
228fa2b2a7SDavid du Colombier 	Image	*mask;
238fa2b2a7SDavid du Colombier 
248fa2b2a7SDavid du Colombier 	Rectangle r;		/* relative */
258fa2b2a7SDavid du Colombier 	Rectangle sr;		/* abs */
268fa2b2a7SDavid du Colombier };
278fa2b2a7SDavid du Colombier 
288fa2b2a7SDavid du Colombier typedef struct Header Header;
298fa2b2a7SDavid du Colombier struct Header
308fa2b2a7SDavid du Colombier {
318fa2b2a7SDavid du Colombier 	uint	n;
328fa2b2a7SDavid du Colombier 	Icon	*first;
338fa2b2a7SDavid du Colombier 	Icon	*last;
348fa2b2a7SDavid du Colombier };
358fa2b2a7SDavid du Colombier 
368fa2b2a7SDavid du Colombier int debug;
378fa2b2a7SDavid du Colombier Mouse mouse;
388fa2b2a7SDavid du Colombier Header h;
398fa2b2a7SDavid du Colombier Image *background;
408fa2b2a7SDavid du Colombier 
418fa2b2a7SDavid du Colombier ushort
gets(uchar * p)428fa2b2a7SDavid du Colombier gets(uchar *p)
438fa2b2a7SDavid du Colombier {
448fa2b2a7SDavid du Colombier 	return p[0] | (p[1]<<8);
458fa2b2a7SDavid du Colombier }
468fa2b2a7SDavid du Colombier 
478fa2b2a7SDavid du Colombier ulong
getl(uchar * p)488fa2b2a7SDavid du Colombier getl(uchar *p)
498fa2b2a7SDavid du Colombier {
508fa2b2a7SDavid du Colombier 	return p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
518fa2b2a7SDavid du Colombier }
528fa2b2a7SDavid du Colombier 
538fa2b2a7SDavid du Colombier int
Bgetheader(Biobuf * b,Header * h)548fa2b2a7SDavid du Colombier Bgetheader(Biobuf *b, Header *h)
558fa2b2a7SDavid du Colombier {
568fa2b2a7SDavid du Colombier 	Icon *icon;
578fa2b2a7SDavid du Colombier 	int i;
588fa2b2a7SDavid du Colombier 	uchar buf[40];
598fa2b2a7SDavid du Colombier 
608fa2b2a7SDavid du Colombier 	memset(h, 0, sizeof(*h));
618fa2b2a7SDavid du Colombier 	if(Bread(b, buf, 6) != 6)
628fa2b2a7SDavid du Colombier 		goto eof;
638fa2b2a7SDavid du Colombier 	if(gets(&buf[0]) != 0)
648fa2b2a7SDavid du Colombier 		goto header;
658fa2b2a7SDavid du Colombier 	if(gets(&buf[2]) != 1)
668fa2b2a7SDavid du Colombier 		goto header;
678fa2b2a7SDavid du Colombier 	h->n = gets(&buf[4]);
688fa2b2a7SDavid du Colombier 
698fa2b2a7SDavid du Colombier 	for(i = 0; i < h->n; i++){
708fa2b2a7SDavid du Colombier 		icon = mallocz(sizeof(*icon), 1);
718fa2b2a7SDavid du Colombier 		if(icon == nil)
728fa2b2a7SDavid du Colombier 			sysfatal("malloc: %r");
738fa2b2a7SDavid du Colombier 		if(Bread(b, buf, 16) != 16)
748fa2b2a7SDavid du Colombier 			goto eof;
758fa2b2a7SDavid du Colombier 		icon->w = buf[0];
768fa2b2a7SDavid du Colombier 		icon->h = buf[1];
778fa2b2a7SDavid du Colombier 		icon->ncolor = buf[2] == 0 ? 256 : buf[2];
788fa2b2a7SDavid du Colombier 		if(buf[3] != 0)
798fa2b2a7SDavid du Colombier 			goto header;
808fa2b2a7SDavid du Colombier 		icon->nplane = gets(&buf[4]);
818fa2b2a7SDavid du Colombier 		icon->bits = gets(&buf[6]);
828fa2b2a7SDavid du Colombier 		icon->len = getl(&buf[8]);
838fa2b2a7SDavid du Colombier 		icon->offset = getl(&buf[12]);
848fa2b2a7SDavid du Colombier 
858fa2b2a7SDavid du Colombier 		if(i == 0)
868fa2b2a7SDavid du Colombier 			h->first = icon;
878fa2b2a7SDavid du Colombier 		else
888fa2b2a7SDavid du Colombier 			h->last->next = icon;
898fa2b2a7SDavid du Colombier 		h->last = icon;
908fa2b2a7SDavid du Colombier 	}
918fa2b2a7SDavid du Colombier 	return 0;
928fa2b2a7SDavid du Colombier 
938fa2b2a7SDavid du Colombier eof:
948fa2b2a7SDavid du Colombier 	werrstr("unexpected EOF");
958fa2b2a7SDavid du Colombier 	return -1;
968fa2b2a7SDavid du Colombier header:
978fa2b2a7SDavid du Colombier 	werrstr("unknown header format");
988fa2b2a7SDavid du Colombier 	return -1;
998fa2b2a7SDavid du Colombier }
1008fa2b2a7SDavid du Colombier 
1018fa2b2a7SDavid du Colombier uchar*
transcmap(Icon * icon,uchar * map)1028fa2b2a7SDavid du Colombier transcmap(Icon *icon, uchar *map)
1038fa2b2a7SDavid du Colombier {
1048fa2b2a7SDavid du Colombier 	uchar *m, *p;
1058fa2b2a7SDavid du Colombier 	int i;
1068fa2b2a7SDavid du Colombier 
1078fa2b2a7SDavid du Colombier 	p = m = malloc(sizeof(int)*(1<<icon->bits));
1088fa2b2a7SDavid du Colombier 	for(i = 0; i < icon->ncolor; i++){
1098fa2b2a7SDavid du Colombier 		*p++ = rgb2cmap(map[2], map[1], map[0]);
1108fa2b2a7SDavid du Colombier 		map += 4;
1118fa2b2a7SDavid du Colombier 	}
1128fa2b2a7SDavid du Colombier 	return m;
1138fa2b2a7SDavid du Colombier }
1148fa2b2a7SDavid du Colombier 
1158fa2b2a7SDavid du Colombier Image*
xor2img(Icon * icon,uchar * xor,uchar * map)1168fa2b2a7SDavid du Colombier xor2img(Icon *icon, uchar *xor, uchar *map)
1178fa2b2a7SDavid du Colombier {
1188fa2b2a7SDavid du Colombier 	uchar *data;
1198fa2b2a7SDavid du Colombier 	Image *img;
1208fa2b2a7SDavid du Colombier 	int inxlen;
1218fa2b2a7SDavid du Colombier 	uchar *from, *to;
1228fa2b2a7SDavid du Colombier 	int s, byte, mask;
1238fa2b2a7SDavid du Colombier 	int x, y;
1248fa2b2a7SDavid du Colombier 
1258fa2b2a7SDavid du Colombier 	inxlen = 4*((icon->bits*icon->w+31)/32);
1268fa2b2a7SDavid du Colombier 	to = data = malloc(icon->w*icon->h);
1278fa2b2a7SDavid du Colombier 
1288fa2b2a7SDavid du Colombier 	/* rotate around the y axis, go to 8 bits, and convert color */
1298fa2b2a7SDavid du Colombier 	mask = (1<<icon->bits)-1;
1308fa2b2a7SDavid du Colombier 	for(y = 0; y < icon->h; y++){
1318fa2b2a7SDavid du Colombier 		s = -1;
1328fa2b2a7SDavid du Colombier 		byte = 0;
1338fa2b2a7SDavid du Colombier 		from = xor + (icon->h - 1 - y)*inxlen;
1348fa2b2a7SDavid du Colombier 		for(x = 0; x < icon->w; x++){
1358fa2b2a7SDavid du Colombier 			if(s < 0){
1368fa2b2a7SDavid du Colombier 				byte = *from++;
1378fa2b2a7SDavid du Colombier 				s = 8-icon->bits;
1388fa2b2a7SDavid du Colombier 			}
1398fa2b2a7SDavid du Colombier 			*to++ = map[(byte>>s) & mask];
1408fa2b2a7SDavid du Colombier 			s -= icon->bits;
1418fa2b2a7SDavid du Colombier 		}
1428fa2b2a7SDavid du Colombier 	}
1438fa2b2a7SDavid du Colombier 
1448fa2b2a7SDavid du Colombier 	/* stick in an image */
1458fa2b2a7SDavid du Colombier 	img = allocimage(display, Rect(0,0,icon->w,icon->h), CMAP8, 0, DNofill);
1468fa2b2a7SDavid du Colombier 	loadimage(img, Rect(0,0,icon->w,icon->h), data, icon->h*icon->w);
1478fa2b2a7SDavid du Colombier 
1488fa2b2a7SDavid du Colombier 	free(data);
1498fa2b2a7SDavid du Colombier 	return img;
1508fa2b2a7SDavid du Colombier }
1518fa2b2a7SDavid du Colombier 
1528fa2b2a7SDavid du Colombier Image*
and2img(Icon * icon,uchar * and)1538fa2b2a7SDavid du Colombier and2img(Icon *icon, uchar *and)
1548fa2b2a7SDavid du Colombier {
1558fa2b2a7SDavid du Colombier 	uchar *data;
1568fa2b2a7SDavid du Colombier 	Image *img;
1578fa2b2a7SDavid du Colombier 	int inxlen;
1588fa2b2a7SDavid du Colombier 	int outxlen;
1598fa2b2a7SDavid du Colombier 	uchar *from, *to;
1608fa2b2a7SDavid du Colombier 	int x, y;
1618fa2b2a7SDavid du Colombier 
1628fa2b2a7SDavid du Colombier 	inxlen = 4*((icon->w+31)/32);
1638fa2b2a7SDavid du Colombier 	to = data = malloc(inxlen*icon->h);
1648fa2b2a7SDavid du Colombier 
1658fa2b2a7SDavid du Colombier 	/* rotate around the y axis and invert bits */
1668fa2b2a7SDavid du Colombier 	outxlen = (icon->w+7)/8;
1678fa2b2a7SDavid du Colombier 	for(y = 0; y < icon->h; y++){
1688fa2b2a7SDavid du Colombier 		from = and + (icon->h - 1 - y)*inxlen;
1698fa2b2a7SDavid du Colombier 		for(x = 0; x < outxlen; x++){
1708fa2b2a7SDavid du Colombier 			*to++ = ~(*from++);
1718fa2b2a7SDavid du Colombier 		}
1728fa2b2a7SDavid du Colombier 	}
1738fa2b2a7SDavid du Colombier 
1748fa2b2a7SDavid du Colombier 	/* stick in an image */
1758fa2b2a7SDavid du Colombier 	img = allocimage(display, Rect(0,0,icon->w,icon->h), GREY1, 0, DNofill);
1768fa2b2a7SDavid du Colombier 	loadimage(img, Rect(0,0,icon->w,icon->h), data, icon->h*outxlen);
1778fa2b2a7SDavid du Colombier 
1788fa2b2a7SDavid du Colombier 	free(data);
1798fa2b2a7SDavid du Colombier 	return img;
1808fa2b2a7SDavid du Colombier }
1818fa2b2a7SDavid du Colombier 
1828fa2b2a7SDavid du Colombier int
Bgeticon(Biobuf * b,Icon * icon)1838fa2b2a7SDavid du Colombier Bgeticon(Biobuf *b, Icon *icon)
1848fa2b2a7SDavid du Colombier {
1858fa2b2a7SDavid du Colombier 	ulong l;
1868fa2b2a7SDavid du Colombier 	ushort s;
1878fa2b2a7SDavid du Colombier 	uchar *xor;
1888fa2b2a7SDavid du Colombier 	uchar *and;
1898fa2b2a7SDavid du Colombier 	uchar *cm;
1908fa2b2a7SDavid du Colombier 	uchar *buf;
1918fa2b2a7SDavid du Colombier 	uchar *map2map;
1928fa2b2a7SDavid du Colombier 	Image *img;
1938fa2b2a7SDavid du Colombier 
1948fa2b2a7SDavid du Colombier 	Bseek(b, icon->offset, 0);
1958fa2b2a7SDavid du Colombier 	buf = malloc(icon->len);
1968fa2b2a7SDavid du Colombier 	if(buf == nil)
1978fa2b2a7SDavid du Colombier 		return -1;
1988fa2b2a7SDavid du Colombier 	if(Bread(b, buf, icon->len) != icon->len){
1998fa2b2a7SDavid du Colombier 		werrstr("unexpected EOF");
2008fa2b2a7SDavid du Colombier 		return -1;
2018fa2b2a7SDavid du Colombier 	}
2028fa2b2a7SDavid du Colombier 
2038fa2b2a7SDavid du Colombier 	/* this header's info takes precedence over previous one */
2048fa2b2a7SDavid du Colombier 	if(getl(buf) != 40){
2058fa2b2a7SDavid du Colombier 		werrstr("bad icon header");
2068fa2b2a7SDavid du Colombier 		return -1;
2078fa2b2a7SDavid du Colombier 	}
2088fa2b2a7SDavid du Colombier 	l = getl(buf+4);
2098fa2b2a7SDavid du Colombier 	if(l != icon->w)
2108fa2b2a7SDavid du Colombier 		icon->w = l;
2118fa2b2a7SDavid du Colombier 	l = getl(buf+8);
2128fa2b2a7SDavid du Colombier 	if(l>>1 != icon->h)
2138fa2b2a7SDavid du Colombier 		icon->h = l>>1;
2148fa2b2a7SDavid du Colombier 	s = gets(buf+12);
2158fa2b2a7SDavid du Colombier 	if(s != icon->nplane)
2168fa2b2a7SDavid du Colombier 		icon->nplane = s;
2178fa2b2a7SDavid du Colombier 	s = gets(buf+14);
2188fa2b2a7SDavid du Colombier 	if(s != icon->bits)
2198fa2b2a7SDavid du Colombier 		icon->bits = s;
2208fa2b2a7SDavid du Colombier 
2218fa2b2a7SDavid du Colombier 	/* limit what we handle */
2228fa2b2a7SDavid du Colombier 	switch(icon->bits){
2238fa2b2a7SDavid du Colombier 	case 1:
2248fa2b2a7SDavid du Colombier 	case 2:
2258fa2b2a7SDavid du Colombier 	case 4:
2268fa2b2a7SDavid du Colombier 	case 8:
2278fa2b2a7SDavid du Colombier 		break;
2288fa2b2a7SDavid du Colombier 	default:
2298fa2b2a7SDavid du Colombier 		werrstr("don't support %d bit pixels", icon->bits);
2308fa2b2a7SDavid du Colombier 		return -1;
2318fa2b2a7SDavid du Colombier 	}
2328fa2b2a7SDavid du Colombier 	if(icon->nplane != 1){
2338fa2b2a7SDavid du Colombier 		werrstr("don't support %d planes", icon->nplane);
2348fa2b2a7SDavid du Colombier 		return -1;
2358fa2b2a7SDavid du Colombier 	}
2368fa2b2a7SDavid du Colombier 
2378fa2b2a7SDavid du Colombier 	cm = buf + 40;
2388fa2b2a7SDavid du Colombier 	xor = cm + 4*icon->ncolor;
2398fa2b2a7SDavid du Colombier 	and = xor + icon->h*4*((icon->bits*icon->w+31)/32);
2408fa2b2a7SDavid du Colombier 
2418fa2b2a7SDavid du Colombier 	/* translate the color map to a plan 9 one */
2428fa2b2a7SDavid du Colombier 	map2map = transcmap(icon, cm);
2438fa2b2a7SDavid du Colombier 
2448fa2b2a7SDavid du Colombier 	/* convert the images */
2458fa2b2a7SDavid du Colombier 	icon->img = xor2img(icon, xor, map2map);
2468fa2b2a7SDavid du Colombier 	icon->mask = and2img(icon, and);
2478fa2b2a7SDavid du Colombier 
2488fa2b2a7SDavid du Colombier 	/* so that we save an image with a white background */
2498fa2b2a7SDavid du Colombier 	img = allocimage(display, icon->img->r, CMAP8, 0, DWhite);
2508fa2b2a7SDavid du Colombier 	draw(img, icon->img->r, icon->img, icon->mask, ZP);
2518fa2b2a7SDavid du Colombier 	icon->img = img;
2528fa2b2a7SDavid du Colombier 
2538fa2b2a7SDavid du Colombier 	free(buf);
2548fa2b2a7SDavid du Colombier 	free(map2map);
2558fa2b2a7SDavid du Colombier 	return 0;
2568fa2b2a7SDavid du Colombier }
2578fa2b2a7SDavid du Colombier 
2588fa2b2a7SDavid du Colombier void
usage(void)2598fa2b2a7SDavid du Colombier usage(void)
2608fa2b2a7SDavid du Colombier {
2618fa2b2a7SDavid du Colombier 	fprint(2, "usage: %s [file]\n", argv0);
2628fa2b2a7SDavid du Colombier 	exits("usage");
2638fa2b2a7SDavid du Colombier }
2648fa2b2a7SDavid du Colombier 
2658fa2b2a7SDavid du Colombier enum
2668fa2b2a7SDavid du Colombier {
2678fa2b2a7SDavid du Colombier 	Mimage,
2688fa2b2a7SDavid du Colombier 	Mmask,
2698fa2b2a7SDavid du Colombier 	Mexit,
2708fa2b2a7SDavid du Colombier 
2718fa2b2a7SDavid du Colombier 	Up= 1,
2728fa2b2a7SDavid du Colombier 	Down= 0,
2738fa2b2a7SDavid du Colombier };
2748fa2b2a7SDavid du Colombier 
2758fa2b2a7SDavid du Colombier char	*menu3str[] = {
2768fa2b2a7SDavid du Colombier 	[Mimage]	"write image",
2778fa2b2a7SDavid du Colombier 	[Mmask]		"write mask",
2788fa2b2a7SDavid du Colombier 	[Mexit]		"exit",
2798fa2b2a7SDavid du Colombier 	0,
2808fa2b2a7SDavid du Colombier };
2818fa2b2a7SDavid du Colombier 
2828fa2b2a7SDavid du Colombier Menu	menu3 = {
2838fa2b2a7SDavid du Colombier 	menu3str
2848fa2b2a7SDavid du Colombier };
2858fa2b2a7SDavid du Colombier 
2868fa2b2a7SDavid du Colombier Cursor sight = {
2878fa2b2a7SDavid du Colombier 	{-7, -7},
2888fa2b2a7SDavid du Colombier 	{0x1F, 0xF8, 0x3F, 0xFC, 0x7F, 0xFE, 0xFB, 0xDF,
2898fa2b2a7SDavid du Colombier 	 0xF3, 0xCF, 0xE3, 0xC7, 0xFF, 0xFF, 0xFF, 0xFF,
2908fa2b2a7SDavid du Colombier 	 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0xC7, 0xF3, 0xCF,
2918fa2b2a7SDavid du Colombier 	 0x7B, 0xDF, 0x7F, 0xFE, 0x3F, 0xFC, 0x1F, 0xF8,},
2928fa2b2a7SDavid du Colombier 	{0x00, 0x00, 0x0F, 0xF0, 0x31, 0x8C, 0x21, 0x84,
2938fa2b2a7SDavid du Colombier 	 0x41, 0x82, 0x41, 0x82, 0x41, 0x82, 0x7F, 0xFE,
2948fa2b2a7SDavid du Colombier 	 0x7F, 0xFE, 0x41, 0x82, 0x41, 0x82, 0x41, 0x82,
2958fa2b2a7SDavid du Colombier 	 0x21, 0x84, 0x31, 0x8C, 0x0F, 0xF0, 0x00, 0x00,}
2968fa2b2a7SDavid du Colombier };
2978fa2b2a7SDavid du Colombier 
2988fa2b2a7SDavid du Colombier void
buttons(int ud)2998fa2b2a7SDavid du Colombier buttons(int ud)
3008fa2b2a7SDavid du Colombier {
3018fa2b2a7SDavid du Colombier 	while((mouse.buttons==0) != ud)
3028fa2b2a7SDavid du Colombier 		mouse = emouse();
3038fa2b2a7SDavid du Colombier }
3048fa2b2a7SDavid du Colombier 
3058fa2b2a7SDavid du Colombier void
mesg(char * fmt,...)3068fa2b2a7SDavid du Colombier mesg(char *fmt, ...)
3078fa2b2a7SDavid du Colombier {
3088fa2b2a7SDavid du Colombier 	va_list arg;
3098fa2b2a7SDavid du Colombier 	char buf[1024];
3108fa2b2a7SDavid du Colombier 	static char obuf[1024];
3118fa2b2a7SDavid du Colombier 
3128fa2b2a7SDavid du Colombier 	va_start(arg, fmt);
3138fa2b2a7SDavid du Colombier 	vseprint(buf, buf+sizeof(buf), fmt, arg);
3148fa2b2a7SDavid du Colombier 	va_end(arg);
3158fa2b2a7SDavid du Colombier 	string(screen, screen->r.min, background, ZP, font, obuf);
3168fa2b2a7SDavid du Colombier 	string(screen, screen->r.min, display->white, ZP, font, buf);
3178fa2b2a7SDavid du Colombier 	strcpy(obuf, buf);
3188fa2b2a7SDavid du Colombier }
3198fa2b2a7SDavid du Colombier 
3208fa2b2a7SDavid du Colombier void
doimage(Icon * icon)3218fa2b2a7SDavid du Colombier doimage(Icon *icon)
3228fa2b2a7SDavid du Colombier {
3238fa2b2a7SDavid du Colombier 	int rv;
3248fa2b2a7SDavid du Colombier 	char file[256];
3258fa2b2a7SDavid du Colombier 	int fd;
3268fa2b2a7SDavid du Colombier 
3278fa2b2a7SDavid du Colombier 	rv = -1;
3288fa2b2a7SDavid du Colombier 	snprint(file, sizeof(file), "%dx%d.img", icon->w, icon->h);
3298fa2b2a7SDavid du Colombier 	fd = create(file, OWRITE, 0664);
3308fa2b2a7SDavid du Colombier 	if(fd >= 0){
3318fa2b2a7SDavid du Colombier 		rv = writeimage(fd, icon->img, 0);
3328fa2b2a7SDavid du Colombier 		close(fd);
3338fa2b2a7SDavid du Colombier 	}
3348fa2b2a7SDavid du Colombier 	if(rv < 0)
3358fa2b2a7SDavid du Colombier 		mesg("error writing %s: %r", file);
3368fa2b2a7SDavid du Colombier 	else
3378fa2b2a7SDavid du Colombier 		mesg("created %s", file);
3388fa2b2a7SDavid du Colombier }
3398fa2b2a7SDavid du Colombier 
3408fa2b2a7SDavid du Colombier void
domask(Icon * icon)3418fa2b2a7SDavid du Colombier domask(Icon *icon)
3428fa2b2a7SDavid du Colombier {
3438fa2b2a7SDavid du Colombier 	int rv;
3448fa2b2a7SDavid du Colombier 	char file[64];
3458fa2b2a7SDavid du Colombier 	int fd;
3468fa2b2a7SDavid du Colombier 
3478fa2b2a7SDavid du Colombier 	rv = -1;
3488fa2b2a7SDavid du Colombier 	snprint(file, sizeof(file), "%dx%d.mask", icon->w, icon->h);
3498fa2b2a7SDavid du Colombier 	fd = create(file, OWRITE, 0664);
3508fa2b2a7SDavid du Colombier 	if(fd >= 0){
3518fa2b2a7SDavid du Colombier 		rv = writeimage(fd, icon->mask, 0);
3528fa2b2a7SDavid du Colombier 		close(fd);
3538fa2b2a7SDavid du Colombier 	}
3548fa2b2a7SDavid du Colombier 	if(rv < 0)
3558fa2b2a7SDavid du Colombier 		mesg("error writing %s: %r", file);
3568fa2b2a7SDavid du Colombier 	else
3578fa2b2a7SDavid du Colombier 		mesg("created %s", file);
3588fa2b2a7SDavid du Colombier }
3598fa2b2a7SDavid du Colombier 
3608fa2b2a7SDavid du Colombier void
apply(void (* f)(Icon *))3618fa2b2a7SDavid du Colombier apply(void (*f)(Icon*))
3628fa2b2a7SDavid du Colombier {
3638fa2b2a7SDavid du Colombier 	Icon *icon;
3648fa2b2a7SDavid du Colombier 
3658fa2b2a7SDavid du Colombier 	esetcursor(&sight);
3668fa2b2a7SDavid du Colombier 	buttons(Down);
3678fa2b2a7SDavid du Colombier 	if(mouse.buttons == 4)
3688fa2b2a7SDavid du Colombier 		for(icon = h.first; icon; icon = icon->next)
3698fa2b2a7SDavid du Colombier 			if(ptinrect(mouse.xy, icon->sr)){
3708fa2b2a7SDavid du Colombier 				buttons(Up);
3718fa2b2a7SDavid du Colombier 				f(icon);
3728fa2b2a7SDavid du Colombier 				break;
3738fa2b2a7SDavid du Colombier 			}
3748fa2b2a7SDavid du Colombier 	buttons(Up);
3758fa2b2a7SDavid du Colombier 	esetcursor(0);
3768fa2b2a7SDavid du Colombier }
3778fa2b2a7SDavid du Colombier 
3788fa2b2a7SDavid du Colombier void
menu(void)3798fa2b2a7SDavid du Colombier menu(void)
3808fa2b2a7SDavid du Colombier {
3818fa2b2a7SDavid du Colombier 	int sel;
3828fa2b2a7SDavid du Colombier 
3838fa2b2a7SDavid du Colombier 	sel = emenuhit(3, &mouse, &menu3);
3848fa2b2a7SDavid du Colombier 	switch(sel){
3858fa2b2a7SDavid du Colombier 	case Mimage:
3868fa2b2a7SDavid du Colombier 		apply(doimage);
3878fa2b2a7SDavid du Colombier 		break;
3888fa2b2a7SDavid du Colombier 	case Mmask:
3898fa2b2a7SDavid du Colombier 		apply(domask);
3908fa2b2a7SDavid du Colombier 		break;
3918fa2b2a7SDavid du Colombier 	case Mexit:
3928fa2b2a7SDavid du Colombier 		exits(0);
3938fa2b2a7SDavid du Colombier 		break;
3948fa2b2a7SDavid du Colombier 	}
3958fa2b2a7SDavid du Colombier }
3968fa2b2a7SDavid du Colombier 
3978fa2b2a7SDavid du Colombier void
mousemoved(void)3988fa2b2a7SDavid du Colombier mousemoved(void)
3998fa2b2a7SDavid du Colombier {
4008fa2b2a7SDavid du Colombier 	Icon *icon;
4018fa2b2a7SDavid du Colombier 
4028fa2b2a7SDavid du Colombier 	for(icon = h.first; icon; icon = icon->next)
4038fa2b2a7SDavid du Colombier 		if(ptinrect(mouse.xy, icon->sr)){
4048fa2b2a7SDavid du Colombier 			mesg("%dx%d", icon->w, icon->h);
4058fa2b2a7SDavid du Colombier 			return;
4068fa2b2a7SDavid du Colombier 		}
4078fa2b2a7SDavid du Colombier 	mesg("");
4088fa2b2a7SDavid du Colombier }
4098fa2b2a7SDavid du Colombier 
4108fa2b2a7SDavid du Colombier enum
4118fa2b2a7SDavid du Colombier {
4128fa2b2a7SDavid du Colombier 	BORDER= 1,
4138fa2b2a7SDavid du Colombier };
4148fa2b2a7SDavid du Colombier 
4158fa2b2a7SDavid du Colombier void
eresized(int new)4168fa2b2a7SDavid du Colombier eresized(int new)
4178fa2b2a7SDavid du Colombier {
4188fa2b2a7SDavid du Colombier 	Icon *icon;
4198fa2b2a7SDavid du Colombier 	Rectangle r;
4208fa2b2a7SDavid du Colombier 
4218fa2b2a7SDavid du Colombier 	if(new && getwindow(display, Refnone) < 0)
4228fa2b2a7SDavid du Colombier 		sysfatal("can't reattach to window");
4238fa2b2a7SDavid du Colombier 	draw(screen, screen->clipr, background, nil, ZP);
4248fa2b2a7SDavid du Colombier 	r.max.x = screen->r.min.x;
4258fa2b2a7SDavid du Colombier 	r.min.y = screen->r.min.y + font->height + 2*BORDER;
4268fa2b2a7SDavid du Colombier 	for(icon = h.first; icon != nil; icon = icon->next){
4278fa2b2a7SDavid du Colombier 		r.min.x = r.max.x + BORDER;
4288fa2b2a7SDavid du Colombier 		r.max.x = r.min.x + Dx(icon->img->r);
4298fa2b2a7SDavid du Colombier 		r.max.y = r.min.y + Dy(icon->img->r);
4308fa2b2a7SDavid du Colombier 		draw(screen, r, icon->img, nil, ZP);
4318fa2b2a7SDavid du Colombier 		border(screen, r, -BORDER, display->black, ZP);
4328fa2b2a7SDavid du Colombier 		icon->sr = r;
4338fa2b2a7SDavid du Colombier 	}
4348fa2b2a7SDavid du Colombier 	flushimage(display, 1);
4358fa2b2a7SDavid du Colombier }
4368fa2b2a7SDavid du Colombier 
4378fa2b2a7SDavid du Colombier void
main(int argc,char ** argv)4388fa2b2a7SDavid du Colombier main(int argc, char **argv)
4398fa2b2a7SDavid du Colombier {
4408fa2b2a7SDavid du Colombier 	Biobuf in;
4418fa2b2a7SDavid du Colombier 	Icon *icon;
442*e6d20ddfSDavid du Colombier 	int num, fd;
4438fa2b2a7SDavid du Colombier 	Rectangle r;
4448fa2b2a7SDavid du Colombier 	Event e;
4458fa2b2a7SDavid du Colombier 
4468fa2b2a7SDavid du Colombier 	ARGBEGIN{
4478fa2b2a7SDavid du Colombier 	case 'd':
4488fa2b2a7SDavid du Colombier 		debug = 1;
4498fa2b2a7SDavid du Colombier 		break;
4508fa2b2a7SDavid du Colombier 	}ARGEND;
4518fa2b2a7SDavid du Colombier 
4528fa2b2a7SDavid du Colombier 	fd = -1;
4538fa2b2a7SDavid du Colombier 	switch(argc){
4548fa2b2a7SDavid du Colombier 	case 0:
4558fa2b2a7SDavid du Colombier 		fd = 0;
4568fa2b2a7SDavid du Colombier 		break;
4578fa2b2a7SDavid du Colombier 	case 1:
4588fa2b2a7SDavid du Colombier 		fd = open(argv[0], OREAD);
4598fa2b2a7SDavid du Colombier 		if(fd < 0)
4608fa2b2a7SDavid du Colombier 			sysfatal("opening: %r");
4618fa2b2a7SDavid du Colombier 		break;
4628fa2b2a7SDavid du Colombier 	default:
4638fa2b2a7SDavid du Colombier 		usage();
4648fa2b2a7SDavid du Colombier 		break;
4658fa2b2a7SDavid du Colombier 	}
4668fa2b2a7SDavid du Colombier 
4678fa2b2a7SDavid du Colombier 	Binit(&in, fd, OREAD);
4688fa2b2a7SDavid du Colombier 
4698fa2b2a7SDavid du Colombier 	if(Bgetheader(&in, &h) < 0)
4708fa2b2a7SDavid du Colombier 		sysfatal("reading header: %r");
4718fa2b2a7SDavid du Colombier 
4728fa2b2a7SDavid du Colombier 	initdraw(nil, nil, "ico");
4738fa2b2a7SDavid du Colombier 	background = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, (128<<24)|(128<<16)|(128<<8)|0xFF);
4748fa2b2a7SDavid du Colombier 
4758fa2b2a7SDavid du Colombier 	einit(Emouse|Ekeyboard);
4768fa2b2a7SDavid du Colombier 
477*e6d20ddfSDavid du Colombier 	num = 0;
4788fa2b2a7SDavid du Colombier 	r.min = Pt(4, 4);
4798fa2b2a7SDavid du Colombier 	for(icon = h.first; icon != nil; icon = icon->next){
4808fa2b2a7SDavid du Colombier 		if(Bgeticon(&in, icon) < 0){
481*e6d20ddfSDavid du Colombier 			fprint(2, "%s: read fail: %r\n", argv0);
4828fa2b2a7SDavid du Colombier 			continue;
4838fa2b2a7SDavid du Colombier 		}
4848fa2b2a7SDavid du Colombier 		if(debug)
4858fa2b2a7SDavid du Colombier 			fprint(2, "w %ud h %ud ncolor %ud bits %ud len %lud offset %lud\n",
4868fa2b2a7SDavid du Colombier 			   icon->w, icon->h, icon->ncolor, icon->bits, icon->len, icon->offset);
4878fa2b2a7SDavid du Colombier 		r.max = addpt(r.min, Pt(icon->w, icon->h));
4888fa2b2a7SDavid du Colombier 		icon->r = r;
4898fa2b2a7SDavid du Colombier 		r.min.x += r.max.x;
490*e6d20ddfSDavid du Colombier 		num++;
4918fa2b2a7SDavid du Colombier 	}
492*e6d20ddfSDavid du Colombier 
493*e6d20ddfSDavid du Colombier 	if(num == 0)
494*e6d20ddfSDavid du Colombier 		exits("no images");
4958fa2b2a7SDavid du Colombier 	eresized(0);
4968fa2b2a7SDavid du Colombier 
4978fa2b2a7SDavid du Colombier 	for(;;)
4988fa2b2a7SDavid du Colombier 		switch(event(&e)){
4998fa2b2a7SDavid du Colombier 		case Ekeyboard:
5008fa2b2a7SDavid du Colombier 			break;
5018fa2b2a7SDavid du Colombier 		case Emouse:
5028fa2b2a7SDavid du Colombier 			mouse = e.mouse;
5038fa2b2a7SDavid du Colombier 			if(mouse.buttons & 4)
5048fa2b2a7SDavid du Colombier 				menu();
5058fa2b2a7SDavid du Colombier 			else
5068fa2b2a7SDavid du Colombier 				mousemoved();
5078fa2b2a7SDavid du Colombier 			break;
5088fa2b2a7SDavid du Colombier 		}
509b85a8364SDavid du Colombier 	/* not reached */
5108fa2b2a7SDavid du Colombier }
511