git: 9front

Download patch

ref: 2b5e9756f86ce90bec3f739037a0ee192e16fafe
parent: 86e36cfa87edfc317a50a15fc031d16473c3cb72
author: ftrvxmtrx <ftrvxmtrx@gmail.com>
date: Sun Jan 20 17:35:03 EST 2013

readtga: fix b/w, add color-mapped images support

--- a/sys/src/cmd/jpg/readtga.c
+++ b/sys/src/cmd/jpg/readtga.c
@@ -2,7 +2,7 @@
  * TGA is a fairly dead standard, however in the video industry
  * it is still used a little for test patterns and the like.
  *
- * Thus we ignore any alpha channels, and colour mapped images.
+ * Thus we ignore any alpha channels.
  */
 
 #include <u.h>
@@ -37,15 +37,15 @@
  * d0-3 = number of attribute bits per pixel
  * d4 	= reserved, always zero
  * d6-7	= origin: 0=lower left, 1=upper left, 2=lower right, 3=upper right
- * d8-9 = interleave: 0=progressive, 1=2 way, 3 = 4 way, 4 = reserved.
+ * d8-9 = interleave: 0=progressive, 1=2 way, 3=4 way, 4=reserved.
  */
 
 char *datatype[] = {
 	[0]		"No image data",
-	[1]		"Color mapped",
+	[1]		"Color-mapped",
 	[2]		"RGB",
 	[3]		"B&W",
-	[9]		"RLE color mapped",
+	[9]		"RLE color-mapped",
 	[10]	"RLE RGB",
 	[11]	"RLE B&W",
 	[32]	"Compressed color",
@@ -64,6 +64,52 @@
 	return (y<<8)|x;
 }
 
+static int
+fixcmap(uchar *cmap, int *cmapbpp, int cmaplen)
+{
+	int i;
+	ushort x;
+	uchar tmp;
+
+	switch(*cmapbpp){
+	case 32:
+		/* swap B with R */
+		for(i = 0; i < cmaplen; i++){
+			tmp = cmap[4*i+0];
+			cmap[4*i+0] = cmap[4*i+2];
+			cmap[4*i+2] = tmp;
+		}
+		break;
+	case 24:
+		/* swap B with R */
+		for(i = 0; i < cmaplen; i++){
+			tmp = cmap[3*i+0];
+			cmap[3*i+0] = cmap[3*i+2];
+			cmap[3*i+2] = tmp;
+		}
+		break;
+	case 16:
+		/* convert to 24-bit colormap */
+		if((cmap = realloc(cmap, 3*cmaplen)) == nil)
+			return -1;
+		for(i = cmaplen-1; i >= 0; i--){
+			x = (cmap[2*i+1]<<8) | cmap[2*i+0];
+			tmp = (x>>0)&0x1f;
+			cmap[3*i+2] = (tmp<<3) | (tmp>>2);
+			tmp = (x>>5)&0x1f;
+			cmap[3*i+1] = (tmp<<3) | (tmp>>2);
+			tmp = (x>>10)&0x1f;
+			cmap[3*i+0] = (tmp<<3) | (tmp>>2);
+		}
+		*cmapbpp = 24;
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
 static Tga *
 rdhdr(Biobuf *bp)
 {
@@ -108,6 +154,14 @@
 		return h;
 	}
 
+	/* skip over unused color map data */
+	n = (h->cmapbpp/8)*h->cmaporigin;
+	if(Bseek(bp, n, 1) < 0){
+		free(h);
+		return nil;
+	}
+	h->cmaplen -= h->cmaporigin;
+
 	n = (h->cmapbpp/8)*h->cmaplen;
 	if((h->cmap = malloc(n)) == nil){
 		free(h);
@@ -118,48 +172,76 @@
 		free(h->cmap);
 		return nil;
 	}
+	if(fixcmap(h->cmap, &h->cmapbpp, h->cmaplen) != 0){
+		free(h);
+		free(h->cmap);
+		return nil;
+	}
 	return h;
 }
 
 static int
-luma(Biobuf *bp, uchar *l, int num)
+cmap(Biobuf *bp, uchar *l, int num)
 {
 	return Bread(bp, l, num);
 }
 
 static int
-luma_rle(Biobuf *bp, uchar *l, int num)
+luma(Biobuf *bp, int bpp, uchar *l, int num)
 {
-	uchar len;
-	int i, got;
+	char tmp[2];
+	int got;
 
-	for(got = 0; got < num; got += len){
+	if(bpp == 8){
+		got = Bread(bp, l, num);
+	}
+	else{
+		for(got = 0; got < num; got++){
+			if(Bread(bp, tmp, 2) != 2)
+				break;
+			*l++ = tmp[0];
+		}
+	}
+	return got;
+}
+
+static int
+luma_rle(Biobuf *bp, int bpp, uchar *l, int num)
+{
+	uchar len, p;
+	int got;
+
+	for(got = 0; got < num;){
 		if(Bread(bp, &len, 1) != 1)
 			break;
 		if(len & 0x80){
 			len &= 0x7f;
-			len += 1;	/* run of zero is meaningless */
-			if(luma(bp, l, 1) != 1)
+			if(luma(bp, bpp, &p, 1) != 1)
 				break;
-			for(i = 0; i < len && got < num; i++)
-				l[i+1] = *l;
+			for(len++; len > 0 && got < num; len--, got++)
+				*l++ = p;
 		}
 		else{
-			len += 1;	/* raw block of zero is meaningless */
-			if(luma(bp, l, len) != len)
-				break;
+			for(len++; len > 0 && got < num; len--, got++)
+				if(luma(bp, bpp, l++, 1) != 1)
+					return got;
 		}
-		l += len;
 	}
 	return got;
 }
 
+static int
+cmap_rle(Biobuf *bp, uchar *l, int num)
+{
+	return luma_rle(bp, 8, l, num);
+}
 
 static int
 rgba(Biobuf *bp, int bpp, uchar *r, uchar *g, uchar *b, int num)
 {
 	int i;
-	uchar x, y, buf[4];
+	uchar buf[4], tmp;
+	ushort x;
 
 	switch(bpp){
 	case 16:
@@ -166,11 +248,13 @@
 		for(i = 0; i < num; i++){
 			if(Bread(bp, buf, 2) != 2)
 				break;
-			x = buf[0];
-			y = buf[1];
-			*b++ = (x&0x1f)<<3;
-			*g++ = ((y&0x03)<<6) | ((x&0xe0)>>2);
-			*r++ = (y&0x1f)<<3;
+			x = (buf[1]<<8) | buf[0];
+			tmp = (x>>0)&0x1f;
+			*b++ = (tmp<<3) | (tmp>>2);
+			tmp = (x>>5)&0x1f;
+			*g++ = (tmp<<3) | (tmp>>2);
+			tmp = (x>>10)&0x1f;
+			*r++ = (tmp<<3) | (tmp>>2);
 		}
 		break;
 	case 24:
@@ -212,11 +296,12 @@
 			len += 1;	/* run of zero is meaningless */
 			if(rgba(bp, bpp, r, g, b, 1) != 1)
 				break;
-			for(i = 0; i < len-1 && got < num; i++){
-				r[i+1] = *r;
-				g[i+1] = *g;
-				b[i+1] = *b;
+			for(i = 1; i < len && got+i < num; i++){
+				r[i] = *r;
+				g[i] = *g;
+				b[i] = *b;
 			}
+			len = i;
 		}
 		else{
 			len += 1;	/* raw block of zero is meaningless */
@@ -329,19 +414,29 @@
 	array[0] = ar;
 	array[1] = nil;
 
-	if(h->datatype == 3){
+	if(h->datatype == 3 || h->datatype == 11){
 		ar->nchans = 1;
 		ar->chandesc = CY;
 	}
+	else if(h->datatype == 1){
+		ar->nchans = 1;
+		ar->chandesc = CRGB1;
+	}
+	else if(h->datatype == 9){
+		ar->nchans = 1;
+		ar->chandesc = (h->cmapbpp == 32) ? CRGBV : CRGB1;
+	}
 	else{
 		ar->nchans = 3;
 		ar->chandesc = CRGB;
 	}
 
+	ar->cmap = h->cmap;
+	ar->cmaplen = (h->cmapbpp/8)*h->cmaplen;
 	ar->chanlen = h->width*h->height;
 	ar->r = Rect(0, 0, h->width, h->height);
-	for (c = 0; c < ar->nchans; c++)
-		if ((ar->chans[c] = malloc(h->width*h->height)) == nil){
+	for(c = 0; c < ar->nchans; c++)
+		if((ar->chans[c] = malloc(h->width*h->height)) == nil){
 			werrstr("ReadTGA: no memory - %r\n");
 			goto Error;
 		}
@@ -351,17 +446,23 @@
 
 	num = h->width*h->height;
 	switch(h->datatype){
+	case 1:
+		n = cmap(bp, r, num);
+		break;
 	case 2:
 		n = rgba(bp, h->bpp, r, g, b, num);
 		break;
 	case 3:
-		n = luma(bp, r, num);
+		n = luma(bp, h->bpp, r, num);
 		break;
+	case 9:
+		n = cmap_rle(bp, r, num);
+		break;
 	case 10:
 		n = rgba_rle(bp, h->bpp, r, g, b, num);
 		break;
 	case 11:
-		n = luma_rle(bp, r, num);
+		n = luma_rle(bp, h->bpp, r, num);
 		break;
 	default:
 		werrstr("ReadTGA: type=%d (%s) unsupported\n", h->datatype, datatype[h->datatype]);
@@ -377,7 +478,6 @@
 	if(h->yorigin == 0)
 		flip(ar);
 
-	free(h->cmap);
 	free(h);
 	return array;
 Error:
@@ -398,7 +498,7 @@
 	Rawimage * *a;
 	Biobuf b;
 
-	if (Binit(&b, fd, OREAD) < 0)
+	if(Binit(&b, fd, OREAD) < 0)
 		return nil;
 	a = Breadtga(&b);
 	Bterm(&b);
--