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);
--
⑨