From 63849198b9ba4a6b464edb70527058a53865a302 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Sat, 21 Nov 2015 03:22:21 -0800 Subject: [PATCH 1/8] Update other_libs.md --- docs/other_libs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/other_libs.md b/docs/other_libs.md index a5c944c..a9b9d0e 100644 --- a/docs/other_libs.md +++ b/docs/other_libs.md @@ -35,7 +35,7 @@ Not public domain: - **multithreading** [mts](https://github.com/vurtun/mts): cross-platform multithreaded task scheduler (zlib license) - **parsing** [SLRE](https://github.com/cesanta/slre): regular expression matcher (GPL v2) - **parsing** [PicoJSON](https://github.com/kazuho/picojson): JSON parse/serializer for C++ (BSD license) -- _**parsing** [zange](https://github.com/vurtun/zange): JSON parser (MIT license)_ +- _**parsing** [mm_json](https://github.com/vurtun/mmx): JSON parser (zlib license)_ - **tests** [utest](https://github.com/evolutional/utest): unit testing (MIT license) - **tests** [catch](https://github.com/philsquared/Catch): unit testing (Boost license) - **tests** [SPUT](http://www.lingua-systems.com/unit-testing/): unit testing (BSD license) From 657eda21550bda493439f153730e4a00334e31ec Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Sat, 21 Nov 2015 03:29:15 -0800 Subject: [PATCH 2/8] Update other_libs.md --- docs/other_libs.md | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/docs/other_libs.md b/docs/other_libs.md index a9b9d0e..3b90230 100644 --- a/docs/other_libs.md +++ b/docs/other_libs.md @@ -11,14 +11,14 @@ free to tell me about their quality.) _Newest additions are in italics._ - **images** [tiny_jpeg.h](https://github.com/serge-rgb/TinyJPEG/blob/master/tiny_jpeg.h): JPEG encoder (public domain) - **images** [miniexr](https://github.com/aras-p/miniexr): OpenEXR writer (public domain) - **geometry** [nv_voronoi.h](http://www.icculus.org/~mordred/nvlib/): find voronoi regions on lattice w/ integer inputs (public domain) -- _**geometry** [sobol.h](https://github.com/Marc-B-Reynolds/Stand-alone-junk/blob/master/src/SFH/Sobol.h): sobol & stratified sampling sequences (public domain)_ +- **geometry** [sobol.h](https://github.com/Marc-B-Reynolds/Stand-alone-junk/blob/master/src/SFH/Sobol.h): sobol & stratified sampling sequences (public domain) - **network** [zed_net](https://github.com/ZedZull/zed_net): cross-platform socket wrapper (public domain) - **strings**; **files & filenames** [DG_misc.h](https://github.com/DanielGibson/Snippets/): Daniel Gibson's stb.h-esque cross-platform helpers: path/file, strings (public domain) - **strings** [utf8](https://github.com/sheredom/utf8.h): utf8 string library (public domain) - **misc** [MakeID.h](http://www.humus.name/3D/MakeID.h): allocate/deallocate small integer IDs efficiently (public domain) - **misc** [gb_string.h](https://github.com/gingerBill/gb): dynamic strings for C (public domain) -- _**misc** [loguru](https://github.com/emilk/loguru): flexible logging for C++ (public domain)_ -- _**hardware** [EasyTab](https://github.com/ApoorvaJ/EasyTab): multi-platform tablet input (public domain)_ +- **misc** [loguru](https://github.com/emilk/loguru): flexible logging for C++ (public domain) +- **hardware** [EasyTab](https://github.com/ApoorvaJ/EasyTab): multi-platform tablet input (public domain) Not public domain: @@ -27,19 +27,21 @@ Not public domain: - **images** [nanoSVG](https://github.com/memononen/nanosvg): 1-file SVG parser; 1-file SVG rasterizer (zlib license) - **3D** [tinyobjloader](https://github.com/syoyo/tinyobjloader): wavefront OBJ file loader (BSD license) - **2D** [blendish](https://bitbucket.org/duangle/oui-blendish/src): blender-style widget rendering (MIT license) +- _**math** [mm_vec.h](https://github.com/vurtun/mmx): vector math (BSD license)_ - **geometry** [sdf.h](https://github.com/memononen/SDF): compute signed-distance field from antialiased image (MIT license) - **geometry** [nanoflann](https://github.com/jlblancoc/nanoflann): build KD trees for point clouds (BSD license) - **geometry** [jc_voronoi](https://github.com/JCash/voronoi): find voronoi regions on float/double data (MIT license) -- _**network** [wby](https://github.com/vurtun/wby): lightweight webserver, fork of webby (BSD license)_ +- **network** [mm_web.h](https://github.com/vurtun/mmx): lightweight webserver, fork of webby (BSD license) - **audio** [aw_ima.h](https://github.com/afterwise/aw-ima/blob/master/aw-ima.h): IMA-ADPCM audio decoder (MIT license) -- **multithreading** [mts](https://github.com/vurtun/mts): cross-platform multithreaded task scheduler (zlib license) +- **multithreading** [mm_sched.h](https://github.com/vurtun/mts): cross-platform multithreaded task scheduler (zlib license) - **parsing** [SLRE](https://github.com/cesanta/slre): regular expression matcher (GPL v2) - **parsing** [PicoJSON](https://github.com/kazuho/picojson): JSON parse/serializer for C++ (BSD license) -- _**parsing** [mm_json](https://github.com/vurtun/mmx): JSON parser (zlib license)_ +- _**parsing** [mm_json.h](https://github.com/vurtun/mmx): JSON parser (zlib license)_ +- _**parsing** [mm_lexer.h](https://github.com/vurtun/mmx): C-esque language lexer (zlib license)_ - **tests** [utest](https://github.com/evolutional/utest): unit testing (MIT license) - **tests** [catch](https://github.com/philsquared/Catch): unit testing (Boost license) - **tests** [SPUT](http://www.lingua-systems.com/unit-testing/): unit testing (BSD license) -- _**misc** [lualite](https://github.com/janezz55/lualite/): generate lua bindings in C++ (MIT license)_ +- **misc** [lualite](https://github.com/janezz55/lualite/): generate lua bindings in C++ (MIT license) There are some that have a source file and require a separate header file (which they may not even supply). That's twice as many files, and we at nothings/stb cannot condone @@ -52,11 +54,11 @@ this! But you might like them anyway: - **2D** [noc_turtle](https://github.com/guillaumechereau/noc): procedural graphics generator (public domain) - **geometry** [Tomas Akenine-Moller snippets](http://fileadmin.cs.lth.se/cs/Personal/Tomas_Akenine-Moller/code/): various 3D intersection calculations, not lib-ified (public domain) - **geometry** [Clipper](http://www.angusj.com/delphi/clipper.php): line & polygon clipping & offsetting (Boost license) -- _**geometry** [PolyPartition](https://github.com/ivanfratric/polypartition): polygon triangulation, partitioning (MIT license)_ +- **geometry** [PolyPartition](https://github.com/ivanfratric/polypartition): polygon triangulation, partitioning (MIT license) - **network** [yocto](https://github.com/tom-seddon/yhs): non-production-use http server (public domain) - **network** [happyhttp](http://scumways.com/happyhttp/happyhttp.html): http client requests (zlib license) - **network** [mongoose](https://github.com/cesanta/mongoose): http server (GPL v2) -- _**crypto** [TweetNaCl](http://tweetnacl.cr.yp.to/software.html): high-quality tiny cryptography library (public domain)_ +- **crypto** [TweetNaCl](http://tweetnacl.cr.yp.to/software.html): high-quality tiny cryptography library (public domain) - **AI** [micropather](http://www.grinninglizard.com/MicroPather/): pathfinding with A* (zlib license) - **compression** [miniz.c](https://github.com/richgel999/miniz): zlib compression,decompression, zip file, png writing (public domain) - **compression** [lz4](https://github.com/Cyan4973/lz4): fast but larger LZ compression (BSD license) @@ -65,16 +67,16 @@ this! But you might like them anyway: - **profiling** [Remotery](https://github.com/Celtoys/Remotery): CPU/GPU profiler Win/Mac/Linux, using web browser for viewer (Apache 2.0 license) - **profiling** [MicroProfile](https://bitbucket.org/jonasmeyer/microprofile): CPU (and GPU?) profiler, 1-3 header files (unlicense) *uses miniz internally* - **parsing** [json.h](https://github.com/sheredom/json.h): JSON parser (public domain) -- _**parsing** [jzon.h](https://github.com/Zguy/Jzon): JSON parser, C++ (MIT license)_ +- **parsing** [jzon.h](https://github.com/Zguy/Jzon): JSON parser, C++ (MIT license) - **strings** [dfa](http://bjoern.hoehrmann.de/utf-8/decoder/dfa/): fast utf8 decoder (MIT license) - **data structures** [klib](http://attractivechaos.github.io/klib/): many 2-file libs: hash, sort, b-tree, etc (MIT license) -- _**data structures** [uthash](https://github.com/troydhanson/uthash): several 1-header, 1-license-file libs: generic hash, list, etc (BSD license)_ -- _**data structures** [PackedArray](https://github.com/gpakosz/PackedArray): memory-efficient array of elements with non-pow2 bitcount (WTFPL v2 license)_ +- **data structures** [uthash](https://github.com/troydhanson/uthash): several 1-header, 1-license-file libs: generic hash, list, etc (BSD license) +- **data structures** [PackedArray](https://github.com/gpakosz/PackedArray): memory-efficient array of elements with non-pow2 bitcount (WTFPL v2 license) - **data structures**; **algorithms** [minilibs](https://github.com/ccxvii/minilibs): two-file regex, binary tree (public domain) - **files & filenames** [whereami](https://github.com/gpakosz/whereami): get path/filename of executable or module (WTFPL v2 license) - **misc** [dbgtools](https://github.com/wc-duck/dbgtools): cross-platform debug util libraries (zlib license) -- _**misc** [stmr](https://github.com/wooorm/stmr.c): extract English word stems (MIT license)_ -- _**misc** [levenshtein](https://github.com/wooorm/levenshtein.c): compute edit distance between two strings (MIT license)_ +- **misc** [stmr](https://github.com/wooorm/stmr.c): extract English word stems (MIT license) +- **misc** [levenshtein](https://github.com/wooorm/levenshtein.c): compute edit distance between two strings (MIT license) - **tests** [pempek_assert.cpp](https://github.com/gpakosz/Assert/tree/master/src): flexible assertions in C++ (WTFPL v2 license) There is also these XML libraries, but if you're using XML, shame on you: From 2161d1e12a411e74b6893a262f7cf9025cb0d737 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Mon, 30 Nov 2015 01:01:28 -0800 Subject: [PATCH 3/8] Update other_libs.md --- docs/other_libs.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/other_libs.md b/docs/other_libs.md index 3b90230..781c2a2 100644 --- a/docs/other_libs.md +++ b/docs/other_libs.md @@ -15,6 +15,7 @@ free to tell me about their quality.) _Newest additions are in italics._ - **network** [zed_net](https://github.com/ZedZull/zed_net): cross-platform socket wrapper (public domain) - **strings**; **files & filenames** [DG_misc.h](https://github.com/DanielGibson/Snippets/): Daniel Gibson's stb.h-esque cross-platform helpers: path/file, strings (public domain) - **strings** [utf8](https://github.com/sheredom/utf8.h): utf8 string library (public domain) +- _**strings** [strpool.h](https://github.com/mattiasgustavsson/libs): string interning (public domain/MIT) - **misc** [MakeID.h](http://www.humus.name/3D/MakeID.h): allocate/deallocate small integer IDs efficiently (public domain) - **misc** [gb_string.h](https://github.com/gingerBill/gb): dynamic strings for C (public domain) - **misc** [loguru](https://github.com/emilk/loguru): flexible logging for C++ (public domain) From 64fa9a3d95efdea727cef159fb6768c046d0a3ba Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Mon, 30 Nov 2015 01:01:42 -0800 Subject: [PATCH 4/8] Update other_libs.md --- docs/other_libs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/other_libs.md b/docs/other_libs.md index 781c2a2..e00f37f 100644 --- a/docs/other_libs.md +++ b/docs/other_libs.md @@ -15,7 +15,7 @@ free to tell me about their quality.) _Newest additions are in italics._ - **network** [zed_net](https://github.com/ZedZull/zed_net): cross-platform socket wrapper (public domain) - **strings**; **files & filenames** [DG_misc.h](https://github.com/DanielGibson/Snippets/): Daniel Gibson's stb.h-esque cross-platform helpers: path/file, strings (public domain) - **strings** [utf8](https://github.com/sheredom/utf8.h): utf8 string library (public domain) -- _**strings** [strpool.h](https://github.com/mattiasgustavsson/libs): string interning (public domain/MIT) +- _**strings** [strpool.h](https://github.com/mattiasgustavsson/libs): string interning (public domain/MIT)_ - **misc** [MakeID.h](http://www.humus.name/3D/MakeID.h): allocate/deallocate small integer IDs efficiently (public domain) - **misc** [gb_string.h](https://github.com/gingerBill/gb): dynamic strings for C (public domain) - **misc** [loguru](https://github.com/emilk/loguru): flexible logging for C++ (public domain) From 7453e1bfa417453db9b57091b71ad428ba0a6462 Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Sat, 5 Dec 2015 23:23:12 +0100 Subject: [PATCH 5/8] 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) From 57409c3d159af0bb72dac2411fa3183d39202674 Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Sun, 6 Dec 2015 00:30:16 +0100 Subject: [PATCH 6/8] stb_image.h: Improve stbi__tga_info() and stbi__tga_test() * for paletted images, .._info()'s comp should be based on the palette's bits per pixel, not the images bits per pixel (which describes the size of an index into the palette and is also checked now) * make sure the color (map) type and the image type fields of the header are consistent (=> if TGA color type is 1 for paletted, the TGA image type must be 1 or 9) * .._test() does some more checks and uses stbi__get16le() instead of stbi__get16be() - TGA is little endian. * .._test() now always rewinds (sometimes it used to do only return 0; without rewinding) * remove "error check" at the beginning of stbi__tga_load(), because all that is already tested in stbi__tga_test() --- stb_image.h | 94 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 57 insertions(+), 37 deletions(-) diff --git a/stb_image.h b/stb_image.h index 82a0ad8..f627fc0 100644 --- a/stb_image.h +++ b/stb_image.h @@ -4813,19 +4813,36 @@ 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, tga_image_type, tga_bits_per_pixel; - int sz; + int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp; + int sz, tga_colormap_type; stbi__get8(s); // discard Offset - sz = stbi__get8(s); // color type - if( sz > 1 ) { + tga_colormap_type = stbi__get8(s); // colormap type + if( tga_colormap_type > 1 ) { stbi__rewind(s); return 0; // only RGB or indexed allowed } - 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_image_type = stbi__get8(s); // image type + if ( tga_colormap_type == 1 ) { // colormapped (paletted) image + if (tga_image_type != 1 && tga_image_type != 9) { + stbi__rewind(s); + return 0; + } + stbi__skip(s,4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) { + stbi__rewind(s); + return 0; + } + stbi__skip(s,4); // skip image x and y origin + tga_colormap_bpp = sz; + } else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE + if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) { + stbi__rewind(s); + return 0; // only RGB or grey allowed, +/- RLE + } + stbi__skip(s,9); // skip colormap specification and image x/y origin + tga_colormap_bpp = 0; + } tga_w = stbi__get16le(s); if( tga_w < 1 ) { stbi__rewind(s); @@ -4837,9 +4854,17 @@ static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) return 0; // test height } tga_bits_per_pixel = stbi__get8(s); // bits per pixel + if (tga_colormap_bpp != 0) { + if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) { + // when using a colormap, tga_bits_per_pixel is the size of the indexes + // I don't think anything but 8 or 16bit indexes makes sense + stbi__rewind(s); + return 0; + } + tga_bits_per_pixel = tga_colormap_bpp; // make sure colormap's bpp are tested for tga_comp + } 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; @@ -4859,25 +4884,31 @@ static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) static int stbi__tga_test(stbi__context *s) { - int res; - int sz; + int res = 0; + int sz, tga_color_type; stbi__get8(s); // discard Offset - sz = stbi__get8(s); // color type - if ( sz > 1 ) return 0; // only RGB or indexed allowed + tga_color_type = stbi__get8(s); // color type + if ( tga_color_type > 1 ) goto errorEnd; // only RGB or indexed allowed sz = stbi__get8(s); // image type - if ( (sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11) ) return 0; // only RGB or grey allowed, +/- RLE - stbi__get16be(s); // discard palette start - stbi__get16be(s); // discard palette length - stbi__get8(s); // discard bits per palette color entry - stbi__get16be(s); // discard x origin - stbi__get16be(s); // discard y origin - if ( stbi__get16be(s) < 1 ) return 0; // test width - if ( stbi__get16be(s) < 1 ) return 0; // test height + if ( tga_color_type == 1 ) { // colormapped (paletted) image + if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9 + stbi__skip(s,4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + stbi__skip(s,4); // skip image x and y origin + } else { // "normal" image w/o colormap + if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE + stbi__skip(s,9); // skip colormap specification and image x/y origin + } + if ( stbi__get16le(s) < 1 ) goto errorEnd; // test width + if ( stbi__get16le(s) < 1 ) goto errorEnd; // test height sz = stbi__get8(s); // bits per pixel - if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) - res = 0; - else - res = 1; + if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + + res = 1; // if we got this far, everything's good and we can return 1 instead of 0 + +errorEnd: stbi__rewind(s); return res; } @@ -4917,17 +4948,6 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int } 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 != 15) && (tga_bits_per_pixel != 16) && - (tga_bits_per_pixel != 24) && (tga_bits_per_pixel != 32)) - ) - { - return NULL; // we don't report this as a bad TGA because we don't even know if it's TGA - } - // If I'm paletted, then I'll use the number of bits from the palette if ( tga_indexed ) { From d23504932293f7a7b8bb13eae033eff5a03a68df Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Sun, 6 Dec 2015 04:33:37 +0100 Subject: [PATCH 7/8] stb_image.h: Fix TGA colormap support * Calculate correct stb format (incl. proper 16bit support) also when using a colormap (palette) * Create colormap with tga_comp, to correctly support 16bit RGB (instead of using tga_palette_bits/8 and just copying the data) * For TGAs with colormap, the TGA bits per pixel field specifies the size of an index to the colormap - the "real" color depth of the image is saved in the color map specification's bits per pixel field. I think only 8 and 16bit indices make sense (16 should be supported, otherwise the colormap length could be u8 instead of u16), so I added support for both. * Helper functions stbi__tga_get_comp() to calculate stb pixelformat and stbi__tga_read_rgb16() to read one 16bit pixel and convert it to 24/32bit RGB(A) - for less duplicate code --- stb_image.h | 134 +++++++++++++++++++++++++++++----------------------- 1 file changed, 74 insertions(+), 60 deletions(-) diff --git a/stb_image.h b/stb_image.h index f627fc0..b0aca9d 100644 --- a/stb_image.h +++ b/stb_image.h @@ -4811,6 +4811,26 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int // Targa Truevision - TGA // by Jonathan Dummer #ifndef STBI_NO_TGA +// returns STBI_rgb or whatever, 0 on error +static int stbi__tga_get_comp(int bits_per_pixel, int alpha_bits, int is_grey, int* is_rgb16) +{ + // only RGB or RGBA (incl. 16bit) or grey allowed + if(is_rgb16) *is_rgb16 = 0; + switch(bits_per_pixel) { + case 8: return STBI_grey; + case 15: if(is_rgb16) *is_rgb16 = 1; return STBI_rgb; + case 16: + if(is_grey) return STBI_grey_alpha; + else { + if(is_rgb16) *is_rgb16 = 1; + return alpha_bits ? STBI_rgb_alpha : STBI_rgb; // most signif. bit might be for alpha + } + case 24: // fall-through + case 32: return bits_per_pixel/8; + default: return 0; + } +} + static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) { int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp; @@ -4854,6 +4874,7 @@ static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) return 0; // test height } tga_bits_per_pixel = stbi__get8(s); // bits per pixel + sz = stbi__get8(s) & 15; // alpha bits if (tga_colormap_bpp != 0) { if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) { // when using a colormap, tga_bits_per_pixel is the size of the indexes @@ -4861,20 +4882,13 @@ static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) stbi__rewind(s); return 0; } - tga_bits_per_pixel = tga_colormap_bpp; // make sure colormap's bpp are tested for tga_comp + tga_comp = stbi__tga_get_comp(tga_colormap_bpp, sz, 0, NULL); + } else { + tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, sz, (tga_image_type == 3) || (tga_image_type == 11), NULL); } - sz = stbi__get8(s) & 15; // alpha bits - // only RGB or RGBA (incl. 16bit) or grey allowed - 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; + if(!tga_comp) { + stbi__rewind(s); + return 0; } if (x) *x = tga_w; if (y) *y = tga_h; @@ -4913,6 +4927,27 @@ errorEnd: return res; } +// read 16bit value and convert to 24/32bit RGB(A) +void stbi__tga_read_rgb16(stbi__context *s, int has_alpha, stbi_uc* out) +{ + 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; + // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later + out[0] = (r * 255)/31; + out[1] = (g * 255)/31; + out[2] = (b * 255)/31; + + if(has_alpha) { + // most significant bit set to 1 for opaque, 0 for trans., according to + // http://www.imagemagick.org/discourse-server/viewtopic.php?t=27469 + out[3] = !(px & 0x8000) * 255; + } +} + static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) { // read in the TGA header stuff @@ -4949,21 +4984,11 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int tga_inverted = 1 - ((tga_inverted >> 5) & 1); // If I'm paletted, then I'll use the number of bits from the palette - if ( tga_indexed ) - { - 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 - } - } + if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, tga_alpha_bits, 0, &tga_rgb16); + else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, tga_alpha_bits, (tga_image_type == 3), &tga_rgb16); + + if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency + return stbi__errpuc("bad format", "Can't find out TGA pixelformat"); // tga info *x = tga_width; @@ -4989,15 +5014,22 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int // any data to skip? (offset usually = 0) stbi__skip(s, tga_palette_start ); // load the palette - tga_palette = (unsigned char*)stbi__malloc( tga_palette_len * tga_palette_bits / 8 ); + tga_palette = (unsigned char*)stbi__malloc( tga_palette_len * tga_comp ); if (!tga_palette) { STBI_FREE(tga_data); return stbi__errpuc("outofmem", "Out of memory"); } - if (!stbi__getn(s, tga_palette, tga_palette_len * tga_palette_bits / 8 )) { - STBI_FREE(tga_data); - STBI_FREE(tga_palette); - return stbi__errpuc("bad palette", "Corrupt TGA"); + if (tga_rgb16) { + stbi_uc *pal_entry = tga_palette; + STBI_ASSERT(tga_comp == STBI_rgb || tga_comp == STBI_rgb_alpha); + for (i=0; i < tga_palette_len; ++i) { + stbi__tga_read_rgb16(s, tga_comp == STBI_rgb_alpha, pal_entry); + pal_entry += tga_comp; + } + } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) { + STBI_FREE(tga_data); + STBI_FREE(tga_palette); + return stbi__errpuc("bad palette", "Corrupt TGA"); } } // load the data @@ -5027,39 +5059,21 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int // load however much data we did have if ( tga_indexed ) { - // read in 1 byte, then perform the lookup - int pal_idx = stbi__get8(s); - if ( pal_idx >= tga_palette_len ) - { - // invalid index + // read in index, then perform the lookup + int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s); + if ( pal_idx >= tga_palette_len ) { + // invalid index pal_idx = 0; } - pal_idx *= tga_bits_per_pixel / 8; - for (j = 0; j*8 < tga_bits_per_pixel; ++j) - { + pal_idx *= tga_comp; + for (j = 0; j < tga_comp; ++j) { raw_data[j] = tga_palette[pal_idx+j]; } } 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; - } + stbi__tga_read_rgb16(s, tga_comp == STBI_rgb_alpha, raw_data); } else { // read in the data raw - for (j = 0; j*8 < tga_bits_per_pixel; ++j) - { + for (j = 0; j < tga_comp; ++j) { raw_data[j] = stbi__get8(s); } } @@ -5098,7 +5112,7 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int } } - // swap RGB + // swap RGB - if the source data was RGB16, it already is in the right order if (tga_comp >= 3 && !tga_rgb16) { unsigned char* tga_pixel = tga_data; From 87a0396922d2b49ea46d519bd69378761cf9d941 Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Sun, 6 Dec 2015 05:47:47 +0100 Subject: [PATCH 8/8] stb_image.h: 16 bit TGAs don't really have an alpha channel I claimed that if the most significant bit of a 16bit pixel is set, it should be opaque (as is suggested by some sources on the internet), but implemented the opposite. If implemented "correctly", lots of 16bit TGAs become invisible.. so I guess 16bit TGAs aren't really supposed to have an alpha-channel, or at least most 16bit TGAs (despite having set an "alpha-bit" in the "image descriptor byte") in the wild don't seem to work like that. So just assume 16bit non-greyscale TGAs are always STBI_rgb without an alpha channel. --- stb_image.h | 45 +++++++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/stb_image.h b/stb_image.h index b0aca9d..8af5565 100644 --- a/stb_image.h +++ b/stb_image.h @@ -4812,19 +4812,16 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int // by Jonathan Dummer #ifndef STBI_NO_TGA // returns STBI_rgb or whatever, 0 on error -static int stbi__tga_get_comp(int bits_per_pixel, int alpha_bits, int is_grey, int* is_rgb16) +static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16) { // only RGB or RGBA (incl. 16bit) or grey allowed if(is_rgb16) *is_rgb16 = 0; switch(bits_per_pixel) { case 8: return STBI_grey; - case 15: if(is_rgb16) *is_rgb16 = 1; return STBI_rgb; - case 16: - if(is_grey) return STBI_grey_alpha; - else { - if(is_rgb16) *is_rgb16 = 1; - return alpha_bits ? STBI_rgb_alpha : STBI_rgb; // most signif. bit might be for alpha - } + case 16: if(is_grey) return STBI_grey_alpha; + // else: fall-through + case 15: if(is_rgb16) *is_rgb16 = 1; + return STBI_rgb; case 24: // fall-through case 32: return bits_per_pixel/8; default: return 0; @@ -4874,7 +4871,7 @@ static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) return 0; // test height } tga_bits_per_pixel = stbi__get8(s); // bits per pixel - sz = stbi__get8(s) & 15; // alpha bits + stbi__get8(s); // ignore alpha bits if (tga_colormap_bpp != 0) { if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) { // when using a colormap, tga_bits_per_pixel is the size of the indexes @@ -4882,9 +4879,9 @@ static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) stbi__rewind(s); return 0; } - tga_comp = stbi__tga_get_comp(tga_colormap_bpp, sz, 0, NULL); + tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL); } else { - tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, sz, (tga_image_type == 3) || (tga_image_type == 11), NULL); + tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL); } if(!tga_comp) { stbi__rewind(s); @@ -4927,8 +4924,8 @@ errorEnd: return res; } -// read 16bit value and convert to 24/32bit RGB(A) -void stbi__tga_read_rgb16(stbi__context *s, int has_alpha, stbi_uc* out) +// read 16bit value and convert to 24bit RGB +void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out) { stbi__uint16 px = stbi__get16le(s); stbi__uint16 fiveBitMask = 31; @@ -4941,11 +4938,10 @@ void stbi__tga_read_rgb16(stbi__context *s, int has_alpha, stbi_uc* out) out[1] = (g * 255)/31; out[2] = (b * 255)/31; - if(has_alpha) { - // most significant bit set to 1 for opaque, 0 for trans., according to - // http://www.imagemagick.org/discourse-server/viewtopic.php?t=27469 - out[3] = !(px & 0x8000) * 255; - } + // some people claim that the most significant bit might be used for alpha + // (possibly if an alpha-bit is set in the "image descriptor byte") + // but that only made 16bit test images completely translucent.. + // so let's treat all 15 and 16bit TGAs as RGB with no alpha. } static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) @@ -4965,7 +4961,7 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int int tga_bits_per_pixel = stbi__get8(s); int tga_comp, tga_rgb16=0; int tga_inverted = stbi__get8(s); - int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits + // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?) // image data unsigned char *tga_data; unsigned char *tga_palette = NULL; @@ -4984,8 +4980,8 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int tga_inverted = 1 - ((tga_inverted >> 5) & 1); // If I'm paletted, then I'll use the number of bits from the palette - if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, tga_alpha_bits, 0, &tga_rgb16); - else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, tga_alpha_bits, (tga_image_type == 3), &tga_rgb16); + if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16); + else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16); if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency return stbi__errpuc("bad format", "Can't find out TGA pixelformat"); @@ -5021,9 +5017,9 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int } if (tga_rgb16) { stbi_uc *pal_entry = tga_palette; - STBI_ASSERT(tga_comp == STBI_rgb || tga_comp == STBI_rgb_alpha); + STBI_ASSERT(tga_comp == STBI_rgb); for (i=0; i < tga_palette_len; ++i) { - stbi__tga_read_rgb16(s, tga_comp == STBI_rgb_alpha, pal_entry); + stbi__tga_read_rgb16(s, pal_entry); pal_entry += tga_comp; } } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) { @@ -5070,7 +5066,8 @@ 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 if(tga_rgb16) { - stbi__tga_read_rgb16(s, tga_comp == STBI_rgb_alpha, raw_data); + STBI_ASSERT(tga_comp == STBI_rgb); + stbi__tga_read_rgb16(s, raw_data); } else { // read in the data raw for (j = 0; j < tga_comp; ++j) {