diff options
author | ftrvxmtrx <ftrvxmtrx@gmail.com> | 2013-01-20 22:35:03 +0100 |
---|---|---|
committer | ftrvxmtrx <ftrvxmtrx@gmail.com> | 2013-01-20 22:35:03 +0100 |
commit | d5c0fe22e3641d241a4fd1250896baa1fc413c51 (patch) | |
tree | 52c031f26cefad58bfa3033d48314d408347cb44 /sys/src/cmd/jpg | |
parent | 311a8ef0769bd44f3f2d9a1e2f46815a81a5e0be (diff) |
readtga: fix b/w, add color-mapped images support
Diffstat (limited to 'sys/src/cmd/jpg')
-rw-r--r-- | sys/src/cmd/jpg/readtga.c | 168 |
1 files changed, 134 insertions, 34 deletions
diff --git a/sys/src/cmd/jpg/readtga.c b/sys/src/cmd/jpg/readtga.c index 9e1deaf97..a3be48c30 100644 --- 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 @@ typedef struct { * 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 @@ Bgeti(Biobuf *bp) 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 @@ rdhdr(Biobuf *bp) 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,59 +172,89 @@ rdhdr(Biobuf *bp) 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: 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 @@ rgba_rle(Biobuf *bp, int bpp, uchar *r, uchar *g, uchar *b, int num) 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 @@ Breadtga(Biobuf *bp) 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 @@ Breadtga(Biobuf *bp) 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 @@ Breadtga(Biobuf *bp) if(h->yorigin == 0) flip(ar); - free(h->cmap); free(h); return array; Error: @@ -398,7 +498,7 @@ readtga(int fd) Rawimage * *a; Biobuf b; - if (Binit(&b, fd, OREAD) < 0) + if(Binit(&b, fd, OREAD) < 0) return nil; a = Breadtga(&b); Bterm(&b); |