Re #3167: Update to new stb_image.h library v 2.10 (commit 30015ef464)

This commit is contained in:
Damjan Adamic
2016-02-27 17:33:11 +01:00
parent 4c342a1883
commit 5cc8f41bce
+304 -199
View File
@@ -1,4 +1,4 @@
/* stb_image - v2.08 - public domain image loader - http://nothings.org/stb_image.h /* stb_image - v2.10 - public domain image loader - http://nothings.org/stb_image.h
no warranty implied; use at your own risk no warranty implied; use at your own risk
Do this: Do this:
@@ -146,6 +146,8 @@
Latest revision history: Latest revision history:
2.10 (2016-01-22) avoid warning introduced in 2.09
2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED
2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA
2.07 (2015-09-13) partial animated GIF support 2.07 (2015-09-13) partial animated GIF support
limited 16-bit PSD support limited 16-bit PSD support
@@ -175,44 +177,35 @@
============================ Contributors ========================= ============================ Contributors =========================
Image formats Bug fixes & warning fixes Image formats Extensions, features
Sean Barrett (jpeg, png, bmp) Marc LeBlanc Sean Barrett (jpeg, png, bmp) Jetro Lauha (stbi_info)
Nicolas Schulz (hdr, psd) Christpher Lloyd Nicolas Schulz (hdr, psd) Martin "SpartanJ" Golini (stbi_info)
Jonathan Dummer (tga) Dave Moore Jonathan Dummer (tga) James "moose2000" Brown (iPhone PNG)
Jean-Marc Lienher (gif) Won Chun Jean-Marc Lienher (gif) Ben "Disch" Wenger (io callbacks)
Tom Seddon (pic) the Horde3D community Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG)
Thatcher Ulrich (psd) Janez Zemva Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip)
Ken Miller (pgm, ppm) Jonathan Blow Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD)
urraka@github (animated gif) Laurent Gomila urraka@github (animated gif) Junggon Kim (PNM comments)
Aruelien Pocheville Daniel Gibson (16-bit TGA)
Ryamond Barbiero
David Woo Optimizations & bugfixes
Extensions, features Martin Golini Fabian "ryg" Giesen
Jetro Lauha (stbi_info) Roy Eltham Arseny Kapoulkine
Martin "SpartanJ" Golini (stbi_info) Luke Graham
James "moose2000" Brown (iPhone PNG) Thomas Ruf Bug & warning fixes
Ben "Disch" Wenger (io callbacks) John Bartholomew Marc LeBlanc David Woo Guillaume George Martins Mozeiko
Omar Cornut (1/2/4-bit PNG) Ken Hamada Christpher Lloyd Martin Golini Jerry Jansson Joseph Thomson
Nicolas Guillemot (vertical flip) Cort Stratton Dave Moore Roy Eltham Hayaki Saito Phil Jordan
Richard Mitton (16-bit PSD) Blazej Dariusz Roszkowski Won Chun Luke Graham Johan Duparc Nathan Reed
Thibault Reuille the Horde3D community Thomas Ruf Ronny Chevalier Nick Verigakis
Paul Du Bois Janez Zemva John Bartholomew Michal Cichon svdijk@github
Guillaume George Jonathan Blow Ken Hamada Tero Hanninen Baldur Karlsson
Jerry Jansson Laurent Gomila Cort Stratton Sergio Gonzalez romigrou@github
Hayaki Saito Aruelien Pocheville Thibault Reuille Cass Everitt
Johan Duparc Ryamond Barbiero Paul Du Bois Engin Manap
Ronny Chevalier Blazej Dariusz Roszkowski
Optimizations & bugfixes Michal Cichon Michaelangel007@github
Fabian "ryg" Giesen Tero Hanninen
Arseny Kapoulkine Sergio Gonzalez
Cass Everitt
Engin Manap
If your name should be here but Martins Mozeiko
isn't, let Sean know. Joseph Thomson
Phil Jordan
Nathan Reed
Michaelangel007@github
Nick Verigakis
LICENSE LICENSE
@@ -461,12 +454,12 @@ STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y,
#ifndef STBI_NO_HDR #ifndef STBI_NO_HDR
STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); STBIDEF void stbi_hdr_to_ldr_gamma(float gamma);
STBIDEF void stbi_hdr_to_ldr_scale(float scale); STBIDEF void stbi_hdr_to_ldr_scale(float scale);
#endif #endif // STBI_NO_HDR
#ifndef STBI_NO_LINEAR #ifndef STBI_NO_LINEAR
STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); STBIDEF void stbi_ldr_to_hdr_gamma(float gamma);
STBIDEF void stbi_ldr_to_hdr_scale(float scale); STBIDEF void stbi_ldr_to_hdr_scale(float scale);
#endif // STBI_NO_HDR #endif // STBI_NO_LINEAR
// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR // stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR
STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user);
@@ -630,18 +623,22 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1];
#define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y))))
#endif #endif
#if defined(STBI_MALLOC) && defined(STBI_FREE) && defined(STBI_REALLOC) #if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED))
// ok // ok
#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) #elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED)
// ok // ok
#else #else
#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC." #error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED)."
#endif #endif
#ifndef STBI_MALLOC #ifndef STBI_MALLOC
#define STBI_MALLOC(sz) malloc(sz) #define STBI_MALLOC(sz) malloc(sz)
#define STBI_REALLOC(p,sz) realloc(p,sz) #define STBI_REALLOC(p,newsz) realloc(p,newsz)
#define STBI_FREE(p) free(p) #define STBI_FREE(p) free(p)
#endif
#ifndef STBI_REALLOC_SIZED
#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz)
#endif #endif
// x86/x64 detection // x86/x64 detection
@@ -1186,14 +1183,15 @@ STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void
#endif #endif
} }
static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f; #ifndef STBI_NO_LINEAR
static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f; static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f;
#ifndef STBI_NO_LINEAR
STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; }
STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; }
#endif #endif
static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f;
STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; } STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; }
STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; } STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; }
@@ -3616,14 +3614,15 @@ stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z)
static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes
{ {
char *q; char *q;
int cur, limit; int cur, limit, old_limit;
z->zout = zout; z->zout = zout;
if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG");
cur = (int) (z->zout - z->zout_start); cur = (int) (z->zout - z->zout_start);
limit = (int) (z->zout_end - z->zout_start); limit = old_limit = (int) (z->zout_end - z->zout_start);
while (cur + n > limit) while (cur + n > limit)
limit *= 2; limit *= 2;
q = (char *) STBI_REALLOC(z->zout_start, limit); q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit);
STBI_NOTUSED(old_limit);
if (q == NULL) return stbi__err("outofmem", "Out of memory"); if (q == NULL) return stbi__err("outofmem", "Out of memory");
z->zout_start = q; z->zout_start = q;
z->zout = q + cur; z->zout = q + cur;
@@ -4408,11 +4407,13 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; }
if ((int)(ioff + c.length) < (int)ioff) return 0; if ((int)(ioff + c.length) < (int)ioff) return 0;
if (ioff + c.length > idata_limit) { if (ioff + c.length > idata_limit) {
stbi__uint32 idata_limit_old = idata_limit;
stbi_uc *p; stbi_uc *p;
if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096;
while (ioff + c.length > idata_limit) while (ioff + c.length > idata_limit)
idata_limit *= 2; idata_limit *= 2;
p = (stbi_uc *) STBI_REALLOC(z->idata, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); STBI_NOTUSED(idata_limit_old);
p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory");
z->idata = p; z->idata = p;
} }
if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG");
@@ -4598,19 +4599,22 @@ static int stbi__shiftsigned(int v, int shift, int bits)
return result; return result;
} }
static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) typedef struct
{ {
stbi_uc *out; int bpp, offset, hsz;
unsigned int mr=0,mg=0,mb=0,ma=0, all_a=255; unsigned int mr,mg,mb,ma, all_a;
stbi_uc pal[256][4]; } stbi__bmp_data;
int psize=0,i,j,compress=0,width;
int bpp, flip_vertically, pad, target, offset, hsz; static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
{
int hsz;
if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP"); if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP");
stbi__get32le(s); // discard filesize stbi__get32le(s); // discard filesize
stbi__get16le(s); // discard reserved stbi__get16le(s); // discard reserved
stbi__get16le(s); // discard reserved stbi__get16le(s); // discard reserved
offset = stbi__get32le(s); info->offset = stbi__get32le(s);
hsz = stbi__get32le(s); info->hsz = hsz = stbi__get32le(s);
if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown");
if (hsz == 12) { if (hsz == 12) {
s->img_x = stbi__get16le(s); s->img_x = stbi__get16le(s);
@@ -4620,15 +4624,10 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int
s->img_y = stbi__get32le(s); s->img_y = stbi__get32le(s);
} }
if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP");
bpp = stbi__get16le(s); info->bpp = stbi__get16le(s);
if (bpp == 1) return stbi__errpuc("monochrome", "BMP type not supported: 1-bit"); if (info->bpp == 1) return stbi__errpuc("monochrome", "BMP type not supported: 1-bit");
flip_vertically = ((int) s->img_y) > 0; if (hsz != 12) {
s->img_y = abs((int) s->img_y); int compress = stbi__get32le(s);
if (hsz == 12) {
if (bpp < 24)
psize = (offset - 14 - 24) / 3;
} else {
compress = stbi__get32le(s);
if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE");
stbi__get32le(s); // discard sizeof stbi__get32le(s); // discard sizeof
stbi__get32le(s); // discard hres stbi__get32le(s); // discard hres
@@ -4642,26 +4641,26 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int
stbi__get32le(s); stbi__get32le(s);
stbi__get32le(s); stbi__get32le(s);
} }
if (bpp == 16 || bpp == 32) { if (info->bpp == 16 || info->bpp == 32) {
mr = mg = mb = 0; info->mr = info->mg = info->mb = 0;
if (compress == 0) { if (compress == 0) {
if (bpp == 32) { if (info->bpp == 32) {
mr = 0xffu << 16; info->mr = 0xffu << 16;
mg = 0xffu << 8; info->mg = 0xffu << 8;
mb = 0xffu << 0; info->mb = 0xffu << 0;
ma = 0xffu << 24; info->ma = 0xffu << 24;
all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0
} else { } else {
mr = 31u << 10; info->mr = 31u << 10;
mg = 31u << 5; info->mg = 31u << 5;
mb = 31u << 0; info->mb = 31u << 0;
} }
} else if (compress == 3) { } else if (compress == 3) {
mr = stbi__get32le(s); info->mr = stbi__get32le(s);
mg = stbi__get32le(s); info->mg = stbi__get32le(s);
mb = stbi__get32le(s); info->mb = stbi__get32le(s);
// not documented, but generated by photoshop and handled by mspaint // not documented, but generated by photoshop and handled by mspaint
if (mr == mg && mg == mb) { if (info->mr == info->mg && info->mg == info->mb) {
// ?!?!? // ?!?!?
return stbi__errpuc("bad BMP", "bad BMP"); return stbi__errpuc("bad BMP", "bad BMP");
} }
@@ -4669,11 +4668,13 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int
return stbi__errpuc("bad BMP", "bad BMP"); return stbi__errpuc("bad BMP", "bad BMP");
} }
} else { } else {
STBI_ASSERT(hsz == 108 || hsz == 124); int i;
mr = stbi__get32le(s); if (hsz != 108 && hsz != 124)
mg = stbi__get32le(s); return stbi__errpuc("bad BMP", "bad BMP");
mb = stbi__get32le(s); info->mr = stbi__get32le(s);
ma = stbi__get32le(s); info->mg = stbi__get32le(s);
info->mb = stbi__get32le(s);
info->ma = stbi__get32le(s);
stbi__get32le(s); // discard color space stbi__get32le(s); // discard color space
for (i=0; i < 12; ++i) for (i=0; i < 12; ++i)
stbi__get32le(s); // discard color space parameters stbi__get32le(s); // discard color space parameters
@@ -4684,35 +4685,68 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int
stbi__get32le(s); // discard reserved stbi__get32le(s); // discard reserved
} }
} }
if (bpp < 16)
psize = (offset - 14 - hsz) >> 2;
} }
return (void *) 1;
}
static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)
{
stbi_uc *out;
unsigned int mr=0,mg=0,mb=0,ma=0, all_a;
stbi_uc pal[256][4];
int psize=0,i,j,width;
int flip_vertically, pad, target;
stbi__bmp_data info;
info.all_a = 255;
if (stbi__bmp_parse_header(s, &info) == NULL)
return NULL; // error code already set
flip_vertically = ((int) s->img_y) > 0;
s->img_y = abs((int) s->img_y);
mr = info.mr;
mg = info.mg;
mb = info.mb;
ma = info.ma;
all_a = info.all_a;
if (info.hsz == 12) {
if (info.bpp < 24)
psize = (info.offset - 14 - 24) / 3;
} else {
if (info.bpp < 16)
psize = (info.offset - 14 - info.hsz) >> 2;
}
s->img_n = ma ? 4 : 3; s->img_n = ma ? 4 : 3;
if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 if (req_comp && req_comp >= 3) // we can directly decode 3 or 4
target = req_comp; target = req_comp;
else else
target = s->img_n; // if they want monochrome, we'll post-convert target = s->img_n; // if they want monochrome, we'll post-convert
out = (stbi_uc *) stbi__malloc(target * s->img_x * s->img_y); out = (stbi_uc *) stbi__malloc(target * s->img_x * s->img_y);
if (!out) return stbi__errpuc("outofmem", "Out of memory"); if (!out) return stbi__errpuc("outofmem", "Out of memory");
if (bpp < 16) { if (info.bpp < 16) {
int z=0; int z=0;
if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); } if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); }
for (i=0; i < psize; ++i) { for (i=0; i < psize; ++i) {
pal[i][2] = stbi__get8(s); pal[i][2] = stbi__get8(s);
pal[i][1] = stbi__get8(s); pal[i][1] = stbi__get8(s);
pal[i][0] = stbi__get8(s); pal[i][0] = stbi__get8(s);
if (hsz != 12) stbi__get8(s); if (info.hsz != 12) stbi__get8(s);
pal[i][3] = 255; pal[i][3] = 255;
} }
stbi__skip(s, offset - 14 - hsz - psize * (hsz == 12 ? 3 : 4)); stbi__skip(s, info.offset - 14 - info.hsz - psize * (info.hsz == 12 ? 3 : 4));
if (bpp == 4) width = (s->img_x + 1) >> 1; if (info.bpp == 4) width = (s->img_x + 1) >> 1;
else if (bpp == 8) width = s->img_x; else if (info.bpp == 8) width = s->img_x;
else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); }
pad = (-width)&3; pad = (-width)&3;
for (j=0; j < (int) s->img_y; ++j) { for (j=0; j < (int) s->img_y; ++j) {
for (i=0; i < (int) s->img_x; i += 2) { for (i=0; i < (int) s->img_x; i += 2) {
int v=stbi__get8(s),v2=0; int v=stbi__get8(s),v2=0;
if (bpp == 4) { if (info.bpp == 4) {
v2 = v & 15; v2 = v & 15;
v >>= 4; v >>= 4;
} }
@@ -4721,7 +4755,7 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int
out[z++] = pal[v][2]; out[z++] = pal[v][2];
if (target == 4) out[z++] = 255; if (target == 4) out[z++] = 255;
if (i+1 == (int) s->img_x) break; if (i+1 == (int) s->img_x) break;
v = (bpp == 8) ? stbi__get8(s) : v2; v = (info.bpp == 8) ? stbi__get8(s) : v2;
out[z++] = pal[v][0]; out[z++] = pal[v][0];
out[z++] = pal[v][1]; out[z++] = pal[v][1];
out[z++] = pal[v][2]; out[z++] = pal[v][2];
@@ -4733,14 +4767,14 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int
int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0;
int z = 0; int z = 0;
int easy=0; int easy=0;
stbi__skip(s, offset - 14 - hsz); stbi__skip(s, info.offset - 14 - info.hsz);
if (bpp == 24) width = 3 * s->img_x; if (info.bpp == 24) width = 3 * s->img_x;
else if (bpp == 16) width = 2*s->img_x; else if (info.bpp == 16) width = 2*s->img_x;
else /* bpp = 32 and pad = 0 */ width=0; else /* bpp = 32 and pad = 0 */ width=0;
pad = (-width) & 3; pad = (-width) & 3;
if (bpp == 24) { if (info.bpp == 24) {
easy = 1; easy = 1;
} else if (bpp == 32) { } else if (info.bpp == 32) {
if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000)
easy = 2; easy = 2;
} }
@@ -4765,6 +4799,7 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int
if (target == 4) out[z++] = a; if (target == 4) out[z++] = a;
} }
} else { } else {
int bpp = info.bpp;
for (i=0; i < (int) s->img_x; ++i) { for (i=0; i < (int) s->img_x; ++i) {
stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s)); stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s));
int a; int a;
@@ -4811,20 +4846,55 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int
// Targa Truevision - TGA // Targa Truevision - TGA
// by Jonathan Dummer // by Jonathan Dummer
#ifndef STBI_NO_TGA #ifndef STBI_NO_TGA
// returns STBI_rgb or whatever, 0 on error
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 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;
}
}
static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) 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, tga_colormap_bpp;
int sz; int sz, tga_colormap_type;
stbi__get8(s); // discard Offset stbi__get8(s); // discard Offset
sz = stbi__get8(s); // color type tga_colormap_type = stbi__get8(s); // colormap type
if( sz > 1 ) { if( tga_colormap_type > 1 ) {
stbi__rewind(s); stbi__rewind(s);
return 0; // only RGB or indexed allowed return 0; // only RGB or indexed allowed
} }
sz = stbi__get8(s); // image type tga_image_type = stbi__get8(s); // image type
// only RGB or grey allowed, +/- RLE if ( tga_colormap_type == 1 ) { // colormapped (paletted) image
if ((sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11)) return 0; if (tga_image_type != 1 && tga_image_type != 9) {
stbi__skip(s,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); tga_w = stbi__get16le(s);
if( tga_w < 1 ) { if( tga_w < 1 ) {
stbi__rewind(s); stbi__rewind(s);
@@ -4835,44 +4905,80 @@ static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp)
stbi__rewind(s); stbi__rewind(s);
return 0; // test height return 0; // test height
} }
sz = stbi__get8(s); // bits per pixel tga_bits_per_pixel = stbi__get8(s); // bits per pixel
// only RGB or RGBA or grey allowed stbi__get8(s); // ignore alpha bits
if ((sz != 8) && (sz != 16) && (sz != 24) && (sz != 32)) { if (tga_colormap_bpp != 0) {
stbi__rewind(s); if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) {
return 0; // 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_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL);
} else {
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);
return 0;
} }
tga_comp = sz;
if (x) *x = tga_w; if (x) *x = tga_w;
if (y) *y = tga_h; if (y) *y = tga_h;
if (comp) *comp = tga_comp / 8; if (comp) *comp = tga_comp;
return 1; // seems to have passed everything return 1; // seems to have passed everything
} }
static int stbi__tga_test(stbi__context *s) static int stbi__tga_test(stbi__context *s)
{ {
int res; int res = 0;
int sz; int sz, tga_color_type;
stbi__get8(s); // discard Offset stbi__get8(s); // discard Offset
sz = stbi__get8(s); // color type tga_color_type = stbi__get8(s); // color type
if ( sz > 1 ) return 0; // only RGB or indexed allowed if ( tga_color_type > 1 ) goto errorEnd; // only RGB or indexed allowed
sz = stbi__get8(s); // image type 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 if ( tga_color_type == 1 ) { // colormapped (paletted) image
stbi__get16be(s); // discard palette start if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9
stbi__get16be(s); // discard palette length stbi__skip(s,4); // skip index of first colormap entry and number of entries
stbi__get8(s); // discard bits per palette color entry sz = stbi__get8(s); // check bits per palette color entry
stbi__get16be(s); // discard x origin if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd;
stbi__get16be(s); // discard y origin stbi__skip(s,4); // skip image x and y origin
if ( stbi__get16be(s) < 1 ) return 0; // test width } else { // "normal" image w/o colormap
if ( stbi__get16be(s) < 1 ) return 0; // test height 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 sz = stbi__get8(s); // bits per pixel
if ( (sz != 8) && (sz != 16) && (sz != 24) && (sz != 32) ) if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index
res = 0; if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd;
else
res = 1; res = 1; // if we got this far, everything's good and we can return 1 instead of 0
errorEnd:
stbi__rewind(s); stbi__rewind(s);
return res; return res;
} }
// 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;
// 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;
// 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) static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)
{ {
// read in the TGA header stuff // read in the TGA header stuff
@@ -4888,8 +4994,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_width = stbi__get16le(s);
int tga_height = stbi__get16le(s); int tga_height = stbi__get16le(s);
int tga_bits_per_pixel = stbi__get8(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_inverted = stbi__get8(s);
// int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?)
// image data // image data
unsigned char *tga_data; unsigned char *tga_data;
unsigned char *tga_palette = NULL; unsigned char *tga_palette = NULL;
@@ -4905,25 +5012,14 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int
tga_image_type -= 8; tga_image_type -= 8;
tga_is_RLE = 1; tga_is_RLE = 1;
} }
/* int tga_alpha_bits = tga_inverted & 15; */
tga_inverted = 1 - ((tga_inverted >> 5) & 1); 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 != 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 I'm paletted, then I'll use the number of bits from the palette
if ( tga_indexed ) 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);
tga_comp = tga_palette_bits / 8;
} 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 // tga info
*x = tga_width; *x = tga_width;
@@ -4936,7 +5032,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) // skip to the data's starting position (offset usually = 0)
stbi__skip(s, tga_offset ); 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) { for (i=0; i < tga_height; ++i) {
int row = tga_inverted ? tga_height -i - 1 : i; int row = tga_inverted ? tga_height -i - 1 : i;
stbi_uc *tga_row = tga_data + row*tga_width*tga_comp; stbi_uc *tga_row = tga_data + row*tga_width*tga_comp;
@@ -4949,15 +5045,22 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int
// any data to skip? (offset usually = 0) // any data to skip? (offset usually = 0)
stbi__skip(s, tga_palette_start ); stbi__skip(s, tga_palette_start );
// load the palette // 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) { if (!tga_palette) {
STBI_FREE(tga_data); STBI_FREE(tga_data);
return stbi__errpuc("outofmem", "Out of memory"); return stbi__errpuc("outofmem", "Out of memory");
} }
if (!stbi__getn(s, tga_palette, tga_palette_len * tga_palette_bits / 8 )) { if (tga_rgb16) {
STBI_FREE(tga_data); stbi_uc *pal_entry = tga_palette;
STBI_FREE(tga_palette); STBI_ASSERT(tga_comp == STBI_rgb);
return stbi__errpuc("bad palette", "Corrupt TGA"); for (i=0; i < tga_palette_len; ++i) {
stbi__tga_read_rgb16(s, 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 // load the data
@@ -4987,23 +5090,22 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int
// load however much data we did have // load however much data we did have
if ( tga_indexed ) if ( tga_indexed )
{ {
// read in 1 byte, then perform the lookup // read in index, then perform the lookup
int pal_idx = stbi__get8(s); int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s);
if ( pal_idx >= tga_palette_len ) if ( pal_idx >= tga_palette_len ) {
{ // invalid index
// invalid index
pal_idx = 0; pal_idx = 0;
} }
pal_idx *= tga_bits_per_pixel / 8; pal_idx *= tga_comp;
for (j = 0; j*8 < tga_bits_per_pixel; ++j) for (j = 0; j < tga_comp; ++j) {
{
raw_data[j] = tga_palette[pal_idx+j]; raw_data[j] = tga_palette[pal_idx+j];
} }
} else } else if(tga_rgb16) {
{ STBI_ASSERT(tga_comp == STBI_rgb);
stbi__tga_read_rgb16(s, raw_data);
} else {
// read in the data raw // 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); raw_data[j] = stbi__get8(s);
} }
} }
@@ -5042,8 +5144,8 @@ 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) if (tga_comp >= 3 && !tga_rgb16)
{ {
unsigned char* tga_pixel = tga_data; unsigned char* tga_pixel = tga_data;
for (i=0; i < tga_width * tga_height; ++i) for (i=0; i < tga_width * tga_height; ++i)
@@ -6017,7 +6119,7 @@ static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp)
char *token; char *token;
int valid = 0; int valid = 0;
if (strcmp(stbi__hdr_gettoken(s,buffer), "#?RADIANCE") != 0) { if (stbi__hdr_test(s) == 0) {
stbi__rewind( s ); stbi__rewind( s );
return 0; return 0;
} }
@@ -6054,29 +6156,17 @@ static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp)
#ifndef STBI_NO_BMP #ifndef STBI_NO_BMP
static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp)
{ {
int hsz; void *p;
if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') { stbi__bmp_data info;
stbi__rewind( s );
return 0; info.all_a = 255;
} p = stbi__bmp_parse_header(s, &info);
stbi__skip(s,12); stbi__rewind( s );
hsz = stbi__get32le(s); if (p == NULL)
if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) { return 0;
stbi__rewind( s ); *x = s->img_x;
return 0; *y = s->img_y;
} *comp = info.ma ? 4 : 3;
if (hsz == 12) {
*x = stbi__get16le(s);
*y = stbi__get16le(s);
} else {
*x = stbi__get32le(s);
*y = stbi__get32le(s);
}
if (stbi__get16le(s) != 1) {
stbi__rewind( s );
return 0;
}
*comp = stbi__get16le(s) / 8;
return 1; return 1;
} }
#endif #endif
@@ -6222,8 +6312,16 @@ static int stbi__pnm_isspace(char c)
static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) static void stbi__pnm_skip_whitespace(stbi__context *s, char *c)
{ {
while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) for (;;) {
*c = (char) stbi__get8(s); while (!stbi__at_eof(s) && stbi__pnm_isspace(*c))
*c = (char) stbi__get8(s);
if (stbi__at_eof(s) || *c != '#')
break;
while (!stbi__at_eof(s) && *c != '\n' && *c != '\r' )
*c = (char) stbi__get8(s);
}
} }
static int stbi__pnm_isdigit(char c) static int stbi__pnm_isdigit(char c)
@@ -6361,10 +6459,17 @@ STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int
/* /*
revision history: revision history:
2.10 (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED
2.09 (2016-01-16) allow comments in PNM files
16-bit-per-pixel TGA (not bit-per-component)
info() for TGA could break due to .hdr handling
info() for BMP to shares code instead of sloppy parse
can use STBI_REALLOC_SIZED if allocator doesn't support realloc
code cleanup
2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA
2.07 (2015-09-13) fix compiler warnings 2.07 (2015-09-13) fix compiler warnings
partial animated GIF support partial animated GIF support
limited 16-bit PSD support limited 16-bpc PSD support
#ifdef unused functions #ifdef unused functions
bug with < 92 byte PIC,PNM,HDR,TGA bug with < 92 byte PIC,PNM,HDR,TGA
2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value