git: 9front

Download patch

ref: 81652c664317a96fe28dda30cb647b6d8b93094d
parent: 9e6ebfbb5631b47b6b5a6fcb939ecb5c48828937
author: cinap_lenrek <cinap_lenrek@gmx.de>
date: Tue Apr 17 13:32:34 EDT 2012

ico: support > 8bit color icons

--- a/sys/src/cmd/jpg/ico.c
+++ b/sys/src/cmd/jpg/ico.c
@@ -73,11 +73,9 @@
 			sysfatal("malloc: %r");
 		if(Breadn(b, buf, 16) != 16)
 			goto eof;
-		icon->w = buf[0];
-		icon->h = buf[1];
+		icon->w = buf[0] == 0 ? 256 : buf[0];
+		icon->h = buf[1] == 0 ? 256 : buf[1];
 		icon->ncolor = buf[2] == 0 ? 256 : buf[2];
-		if(buf[3] != 0)
-			goto header;
 		icon->nplane = gets(&buf[4]);
 		icon->bits = gets(&buf[6]);
 		icon->len = getl(&buf[8]);
@@ -99,13 +97,13 @@
 }
 
 uchar*
-transcmap(Icon *icon, uchar *map)
+transcmap(Icon *icon, int ncolor, uchar *map)
 {
 	uchar *m, *p;
 	int i;
 
-	p = m = malloc(sizeof(int)*(1<<icon->bits));
-	for(i = 0; i < icon->ncolor; i++){
+	p = m = mallocz(sizeof(int)*(1<<icon->bits), 1);
+	for(i = 0; i < ncolor; i++){
 		*p++ = rgb2cmap(map[2], map[1], map[0]);
 		map += 4;
 	}
@@ -113,7 +111,7 @@
 }
 
 Memimage*
-xor2img(Icon *icon, uchar *xor, uchar *map)
+xor2img(Icon *icon, long chan, uchar *xor, uchar *map)
 {
 	uchar *data;
 	Memimage *img;
@@ -123,8 +121,18 @@
 	int x, y;
 
 	inxlen = 4*((icon->bits*icon->w+31)/32);
-	to = data = malloc(icon->w*icon->h);
+	img = allocmemimage(Rect(0,0,icon->w,icon->h), chan);
 
+	if(chan != CMAP8){
+		from = xor + icon->h*inxlen;
+		for(y = 0; y < icon->h; y++){
+			from -= inxlen;
+			loadmemimage(img, Rect(0,y,icon->w,y+1), from, inxlen);
+		}
+		return img;
+	}
+
+	to = data = malloc(icon->w*icon->h);
 	/* rotate around the y axis, go to 8 bits, and convert color */
 	mask = (1<<icon->bits)-1;
 	for(y = 0; y < icon->h; y++){
@@ -140,11 +148,8 @@
 			s -= icon->bits;
 		}
 	}
-
 	/* stick in an image */
-	img = allocmemimage(Rect(0,0,icon->w,icon->h), CMAP8);
 	loadmemimage(img, Rect(0,0,icon->w,icon->h), data, icon->h*icon->w);
-
 	free(data);
 	return img;
 }
@@ -182,7 +187,6 @@
 int
 Bgeticon(Biobuf *b, Icon *icon)
 {
-	ulong l;
 	uchar *end;
 	uchar *xor;
 	uchar *and;
@@ -190,6 +194,8 @@
 	uchar *buf;
 	uchar *map2map;
 	Memimage *img;
+	int ncolor;
+	long chan;
 
 	if(icon->len < 40){
 		werrstr("bad icon header length");
@@ -208,9 +214,10 @@
 		werrstr("bad icon header");
 		return -1;
 	}
+
+	ncolor = 0;
 	icon->w = getl(buf+4);
-	l = getl(buf+8);
-	icon->h = l>>1;
+	icon->h = getl(buf+8)>>1;
 	icon->nplane = gets(buf+12);
 	icon->bits = gets(buf+14);
 
@@ -220,7 +227,21 @@
 	case 2:
 	case 4:
 	case 8:
+		ncolor = icon->ncolor;
+		if(ncolor > (1<<icon->bits))
+			ncolor = 1<<icon->bits;
+		chan = CMAP8;
 		break;
+	case 15:
+	case 16:
+		chan = RGB16;
+		break;
+	case 24:
+		chan = RGB24;
+		break;
+	case 32:
+		chan = ARGB32;
+		break;
 	default:
 		werrstr("don't support %d bit pixels", icon->bits);
 		return -1;
@@ -230,10 +251,10 @@
 		return -1;
 	}
 
-	cm = buf + 40;
-	xor = cm + 4*icon->ncolor;
-	and = xor + icon->h*4*((icon->bits*icon->w+31)/32);
-	end = and + icon->h*4*((icon->w+31)/32);
+	xor = cm = buf + 40;
+	if(chan == CMAP8)
+		xor += 4*ncolor;
+	end = xor + icon->h*4*((icon->bits*icon->w+31)/32);
 	if(end < buf || end > buf+icon->len){
 		werrstr("bad icon length %lux != %lux", end - buf, icon->len);
 		return -1;
@@ -240,12 +261,20 @@
 	}
 
 	/* translate the color map to a plan 9 one */
-	map2map = transcmap(icon, cm);
+	map2map = nil;
+	if(chan == CMAP8)
+		map2map = transcmap(icon, ncolor, cm);
 
 	/* convert the images */
-	icon->img = xor2img(icon, xor, map2map);
-	icon->mask = and2img(icon, and);
+	icon->img = xor2img(icon, chan, xor, map2map);
+	icon->mask = nil;
 
+	/* check for and mask */
+	and = end;
+	end += icon->h*4*((icon->w+31)/32);
+	if(end <= buf+icon->len)
+		icon->mask = and2img(icon, and);
+
 	/* so that we save an image with a white background */
 	if(img = allocmemimage(icon->img->r, icon->img->chan)){
 		memfillcolor(img, DWhite);
@@ -426,7 +455,7 @@
 		r = m->r;
 		while(r.min.y < m->r.max.y){
 			r.max.y = r.min.y+1;
-			loadimage(i, r, byteaddr(m, r.min), Dx(r));
+			loadimage(i, r, byteaddr(m, r.min), bytesperline(r, m->depth));
 			r.min.y++;
 		}
 	}
--