From 7453e1bfa417453db9b57091b71ad428ba0a6462 Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Sat, 5 Dec 2015 23:23:12 +0100 Subject: [PATCH] stb_image.h: Support 15/16bit per pixel RGB(A) TGAs stbi__tga_* assumed that 16bit TGAs were Grayscale + Alpha. However, if the TGA imagetype is not one of the gray ones, it's 16Bit RGB data, with 5 Bits per channel. If the TGA image descriptor field has alpha bits (the 3 least significant ones) set, the pixel's most significant bit is for alpha: 1 for opaque and 0 for translucent. Furthermore people claim that TGAs can also pretend to have 15bpp, which is the same as 16bpp but definitely without alpha. So 15/16bpp TGAs are now decoded to STBI_rgb(_alpha). --- stb_image.h | 68 ++++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 52 insertions(+), 16 deletions(-) diff --git a/stb_image.h b/stb_image.h index 0a9de39..82a0ad8 100644 --- a/stb_image.h +++ b/stb_image.h @@ -4813,7 +4813,7 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int #ifndef STBI_NO_TGA static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) { - int tga_w, tga_h, tga_comp; + int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel; int sz; stbi__get8(s); // discard Offset sz = stbi__get8(s); // color type @@ -4824,6 +4824,7 @@ static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) sz = stbi__get8(s); // image type // only RGB or grey allowed, +/- RLE if ((sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11)) return 0; + tga_image_type = sz; stbi__skip(s,9); tga_w = stbi__get16le(s); if( tga_w < 1 ) { @@ -4835,16 +4836,24 @@ static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) stbi__rewind(s); return 0; // test height } - sz = stbi__get8(s); // bits per pixel - // only RGB or RGBA or grey allowed - if ((sz != 8) && (sz != 16) && (sz != 24) && (sz != 32)) { - stbi__rewind(s); - return 0; + tga_bits_per_pixel = stbi__get8(s); // bits per pixel + sz = stbi__get8(s) & 15; // alpha bits + // only RGB or RGBA (incl. 16bit) or grey allowed + // FIXME: don't we have to use the colormap's bpp if indexed? + switch(tga_bits_per_pixel) { + case 8: tga_comp = STBI_grey; break; + case 15: tga_comp = STBI_rgb; break; + case 16: + if((tga_image_type == 3) || (tga_image_type == 11)) tga_comp = STBI_grey_alpha; + else tga_comp = sz ? STBI_rgb_alpha : STBI_rgb; // most signif. bit might be for alpha + break; + case 24: // fall-through + case 32: tga_comp = tga_bits_per_pixel/8; break; + default: stbi__rewind(s); return 0; } - tga_comp = sz; if (x) *x = tga_w; if (y) *y = tga_h; - if (comp) *comp = tga_comp / 8; + if (comp) *comp = tga_comp; return 1; // seems to have passed everything } @@ -4865,7 +4874,7 @@ static int stbi__tga_test(stbi__context *s) if ( stbi__get16be(s) < 1 ) return 0; // test width if ( stbi__get16be(s) < 1 ) return 0; // test height sz = stbi__get8(s); // bits per pixel - if ( (sz != 8) && (sz != 16) && (sz != 24) && (sz != 32) ) + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) res = 0; else res = 1; @@ -4888,8 +4897,9 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int int tga_width = stbi__get16le(s); int tga_height = stbi__get16le(s); int tga_bits_per_pixel = stbi__get8(s); - int tga_comp = tga_bits_per_pixel / 8; + int tga_comp, tga_rgb16=0; int tga_inverted = stbi__get8(s); + int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits // image data unsigned char *tga_data; unsigned char *tga_palette = NULL; @@ -4905,14 +4915,13 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int tga_image_type -= 8; tga_is_RLE = 1; } - /* int tga_alpha_bits = tga_inverted & 15; */ tga_inverted = 1 - ((tga_inverted >> 5) & 1); // error check if ( //(tga_indexed) || (tga_width < 1) || (tga_height < 1) || (tga_image_type < 1) || (tga_image_type > 3) || - ((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16) && + ((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 15) && (tga_bits_per_pixel != 16) && (tga_bits_per_pixel != 24) && (tga_bits_per_pixel != 32)) ) { @@ -4924,6 +4933,17 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int { tga_comp = tga_palette_bits / 8; } + else { + switch(tga_bits_per_pixel) { + case 8: tga_comp = STBI_grey; break; + case 15: tga_comp = STBI_rgb; tga_rgb16=1; break; + case 16: + if (tga_image_type == 3) tga_comp = STBI_grey_alpha; + else { tga_comp = tga_alpha_bits ? STBI_rgb_alpha : STBI_rgb; tga_rgb16=1; } + break; + default: tga_comp = tga_bits_per_pixel / 8; // incl. 24 and 32 + } + } // tga info *x = tga_width; @@ -4936,7 +4956,7 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int // skip to the data's starting position (offset usually = 0) stbi__skip(s, tga_offset ); - if ( !tga_indexed && !tga_is_RLE) { + if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) { for (i=0; i < tga_height; ++i) { int row = tga_inverted ? tga_height -i - 1 : i; stbi_uc *tga_row = tga_data + row*tga_width*tga_comp; @@ -4999,8 +5019,24 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int { raw_data[j] = tga_palette[pal_idx+j]; } - } else - { + } else if(tga_rgb16) { + // convert from 16bit RGB(A) to 24/32bit RGB(A) + stbi__uint16 px = stbi__get16le(s); + stbi__uint16 fiveBitMask = 31; + // we have 3 channels with 5bits each + int r = (px >> 10) & fiveBitMask; + int g = (px >> 5) & fiveBitMask; + int b = px & fiveBitMask; + raw_data[0] = (r * 255)/31; + raw_data[1] = (g * 255)/31; + raw_data[2] = (b * 255)/31; + + if(tga_comp == STBI_rgb_alpha) { + // most significant bit set to 1 for opaque, 0 for trans., according to + // http://www.imagemagick.org/discourse-server/viewtopic.php?t=27469 + raw_data[3] = !(px & 0x8000) * 255; + } + } else { // read in the data raw for (j = 0; j*8 < tga_bits_per_pixel; ++j) { @@ -5043,7 +5079,7 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int } // swap RGB - if (tga_comp >= 3) + if (tga_comp >= 3 && !tga_rgb16) { unsigned char* tga_pixel = tga_data; for (i=0; i < tga_width * tga_height; ++i)