1584 lines
55 KiB
C
1584 lines
55 KiB
C
#ifndef STBI_INCLUDE_STB_IMAGE_H
|
|
#define STBI_INCLUDE_STB_IMAGE_H
|
|
|
|
char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header);
|
|
unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality);
|
|
|
|
/* PNG decompressor from
|
|
|
|
stb_image - v2.23 - public domain image loader - http://nothings.org/stb_image.h
|
|
*/
|
|
extern const char *stbi__g_failure_reason;
|
|
|
|
enum
|
|
{
|
|
STBI_default = 0,
|
|
|
|
STBI_grey = 1,
|
|
STBI_grey_alpha = 2,
|
|
STBI_rgb = 3,
|
|
STBI_rgb_alpha = 4
|
|
};
|
|
|
|
enum
|
|
{
|
|
STBI__SCAN_load=0,
|
|
STBI__SCAN_type,
|
|
STBI__SCAN_header
|
|
};
|
|
|
|
typedef unsigned short stbi_us;
|
|
|
|
typedef uint16_t stbi__uint16;
|
|
typedef int16_t stbi__int16;
|
|
typedef uint32_t stbi__uint32;
|
|
typedef int32_t stbi__int32;
|
|
|
|
typedef struct
|
|
{
|
|
stbi__uint32 img_x, img_y;
|
|
int img_n, img_out_n;
|
|
|
|
void *io_user_data;
|
|
|
|
int read_from_callbacks;
|
|
int buflen;
|
|
unsigned char buffer_start[128];
|
|
|
|
unsigned char *img_buffer, *img_buffer_end;
|
|
unsigned char *img_buffer_original, *img_buffer_original_end;
|
|
} stbi__context;
|
|
|
|
typedef struct
|
|
{
|
|
int bits_per_channel;
|
|
int num_channels;
|
|
int channel_order;
|
|
} stbi__result_info;
|
|
|
|
#define STBI_ASSERT(v)
|
|
#define STBI_NOTUSED(v) (void)sizeof(v)
|
|
#define STBI__BYTECAST(x) ((unsigned char) ((x) & 255))
|
|
#define STBI_MALLOC(sz) malloc(sz)
|
|
#define STBI_REALLOC(p,newsz) realloc(p,newsz)
|
|
#define STBI_FREE(p) free(p)
|
|
#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz)
|
|
|
|
void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
|
|
unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len);
|
|
|
|
#ifdef STB_IMAGE_IMPLEMENTATION
|
|
const char *stbi__g_failure_reason;
|
|
|
|
_inline static unsigned char stbi__get8(stbi__context *s)
|
|
{
|
|
if (s->img_buffer < s->img_buffer_end)
|
|
return *s->img_buffer++;
|
|
return 0;
|
|
}
|
|
|
|
_inline static int stbi__at_eof(stbi__context *s)
|
|
{
|
|
return s->img_buffer >= s->img_buffer_end;
|
|
}
|
|
|
|
static void stbi__skip(stbi__context *s, int n)
|
|
{
|
|
if (n < 0) {
|
|
s->img_buffer = s->img_buffer_end;
|
|
return;
|
|
}
|
|
s->img_buffer += n;
|
|
}
|
|
|
|
static int stbi__getn(stbi__context *s, unsigned char *buffer, int n)
|
|
{
|
|
if (s->img_buffer+n <= s->img_buffer_end) {
|
|
memcpy(buffer, s->img_buffer, n);
|
|
s->img_buffer += n;
|
|
return 1;
|
|
} else
|
|
return 0;
|
|
}
|
|
|
|
static int stbi__get16be(stbi__context *s)
|
|
{
|
|
int z = stbi__get8(s);
|
|
return (z << 8) + stbi__get8(s);
|
|
}
|
|
|
|
static stbi__uint32 stbi__get32be(stbi__context *s)
|
|
{
|
|
stbi__uint32 z = stbi__get16be(s);
|
|
return (z << 16) + stbi__get16be(s);
|
|
}
|
|
|
|
#define stbi__err(x,y) stbi__errstr(y)
|
|
static int stbi__errstr(const char *str)
|
|
{
|
|
stbi__g_failure_reason = str;
|
|
return 0;
|
|
}
|
|
|
|
_inline static void *stbi__malloc(size_t size)
|
|
{
|
|
return STBI_MALLOC(size);
|
|
}
|
|
|
|
static int stbi__addsizes_valid(int a, int b)
|
|
{
|
|
if (b < 0) return 0;
|
|
return a <= 2147483647 - b;
|
|
}
|
|
|
|
static int stbi__mul2sizes_valid(int a, int b)
|
|
{
|
|
if (a < 0 || b < 0) return 0;
|
|
if (b == 0) return 1;
|
|
return a <= 2147483647/b;
|
|
}
|
|
|
|
static int stbi__mad2sizes_valid(int a, int b, int add)
|
|
{
|
|
return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add);
|
|
}
|
|
|
|
static int stbi__mad3sizes_valid(int a, int b, int c, int add)
|
|
{
|
|
return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) &&
|
|
stbi__addsizes_valid(a*b*c, add);
|
|
}
|
|
|
|
static void *stbi__malloc_mad2(int a, int b, int add)
|
|
{
|
|
if (!stbi__mad2sizes_valid(a, b, add)) return NULL;
|
|
return stbi__malloc(a*b + add);
|
|
}
|
|
|
|
static void *stbi__malloc_mad3(int a, int b, int c, int add)
|
|
{
|
|
if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL;
|
|
return stbi__malloc(a*b*c + add);
|
|
}
|
|
|
|
static unsigned char stbi__compute_y(int r, int g, int b)
|
|
{
|
|
return (unsigned char) (((r*77) + (g*150) + (29*b)) >> 8);
|
|
}
|
|
|
|
static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y)
|
|
{
|
|
int i,j;
|
|
unsigned char *good;
|
|
|
|
if (req_comp == img_n) return data;
|
|
STBI_ASSERT(req_comp >= 1 && req_comp <= 4);
|
|
|
|
good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0);
|
|
if (good == NULL) {
|
|
STBI_FREE(data);
|
|
stbi__err("outofmem", "Out of memory");
|
|
return NULL;
|
|
}
|
|
|
|
for (j=0; j < (int) y; ++j) {
|
|
unsigned char *src = data + j * x * img_n ;
|
|
unsigned char *dest = good + j * x * req_comp;
|
|
|
|
#define STBI__COMBO(a,b) ((a)*8+(b))
|
|
#define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b)
|
|
switch (STBI__COMBO(img_n, req_comp)) {
|
|
STBI__CASE(1,2) { dest[0]=src[0], dest[1]=255; } break;
|
|
STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break;
|
|
STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; } break;
|
|
STBI__CASE(2,1) { dest[0]=src[0]; } break;
|
|
STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break;
|
|
STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break;
|
|
STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; } break;
|
|
STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break;
|
|
STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; } break;
|
|
STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break;
|
|
STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; } break;
|
|
STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break;
|
|
default: STBI_ASSERT(0);
|
|
}
|
|
#undef STBI__CASE
|
|
}
|
|
|
|
STBI_FREE(data);
|
|
return good;
|
|
}
|
|
|
|
static stbi__uint16 stbi__compute_y_16(int r, int g, int b)
|
|
{
|
|
return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8);
|
|
}
|
|
|
|
static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y)
|
|
{
|
|
int i,j;
|
|
stbi__uint16 *good;
|
|
|
|
if (req_comp == img_n) return data;
|
|
STBI_ASSERT(req_comp >= 1 && req_comp <= 4);
|
|
|
|
good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2);
|
|
if (good == NULL) {
|
|
STBI_FREE(data);
|
|
stbi__err("outofmem", "Out of memory");
|
|
return NULL;
|
|
}
|
|
|
|
for (j=0; j < (int) y; ++j) {
|
|
stbi__uint16 *src = data + j * x * img_n ;
|
|
stbi__uint16 *dest = good + j * x * req_comp;
|
|
|
|
#define STBI__COMBO(a,b) ((a)*8+(b))
|
|
#define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b)
|
|
switch (STBI__COMBO(img_n, req_comp)) {
|
|
STBI__CASE(1,2) { dest[0]=src[0], dest[1]=0xffff; } break;
|
|
STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break;
|
|
STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=0xffff; } break;
|
|
STBI__CASE(2,1) { dest[0]=src[0]; } break;
|
|
STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break;
|
|
STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break;
|
|
STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=0xffff; } break;
|
|
STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break;
|
|
STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = 0xffff; } break;
|
|
STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break;
|
|
STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = src[3]; } break;
|
|
STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break;
|
|
default: STBI_ASSERT(0);
|
|
}
|
|
#undef STBI__CASE
|
|
}
|
|
|
|
STBI_FREE(data);
|
|
return good;
|
|
}
|
|
|
|
#define STBI__ZFAST_BITS 9
|
|
#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1)
|
|
|
|
typedef struct
|
|
{
|
|
stbi__uint16 fast[1 << STBI__ZFAST_BITS];
|
|
stbi__uint16 firstcode[16];
|
|
int maxcode[17];
|
|
stbi__uint16 firstsymbol[16];
|
|
unsigned char size[288];
|
|
stbi__uint16 value[288];
|
|
} stbi__zhuffman;
|
|
|
|
_inline static int stbi__bitreverse16(int n)
|
|
{
|
|
n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1);
|
|
n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2);
|
|
n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4);
|
|
n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8);
|
|
return n;
|
|
}
|
|
|
|
_inline static int stbi__bit_reverse(int v, int bits)
|
|
{
|
|
STBI_ASSERT(bits <= 16);
|
|
return stbi__bitreverse16(v) >> (16-bits);
|
|
}
|
|
|
|
static int stbi__zbuild_huffman(stbi__zhuffman *z, unsigned char *sizelist, int num)
|
|
{
|
|
int i,k=0;
|
|
int code, next_code[16], sizes[17];
|
|
|
|
memset(sizes, 0, sizeof(sizes));
|
|
memset(z->fast, 0, sizeof(z->fast));
|
|
for (i=0; i < num; ++i)
|
|
++sizes[sizelist[i]];
|
|
sizes[0] = 0;
|
|
for (i=1; i < 16; ++i)
|
|
if (sizes[i] > (1 << i))
|
|
return stbi__err("bad sizes", "Corrupt PNG");
|
|
code = 0;
|
|
for (i=1; i < 16; ++i) {
|
|
next_code[i] = code;
|
|
z->firstcode[i] = (stbi__uint16) code;
|
|
z->firstsymbol[i] = (stbi__uint16) k;
|
|
code = (code + sizes[i]);
|
|
if (sizes[i])
|
|
if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG");
|
|
z->maxcode[i] = code << (16-i);
|
|
code <<= 1;
|
|
k += sizes[i];
|
|
}
|
|
z->maxcode[16] = 0x10000;
|
|
for (i=0; i < num; ++i) {
|
|
int s = sizelist[i];
|
|
if (s) {
|
|
int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s];
|
|
stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i);
|
|
z->size [c] = (unsigned char ) s;
|
|
z->value[c] = (stbi__uint16) i;
|
|
if (s <= STBI__ZFAST_BITS) {
|
|
int j = stbi__bit_reverse(next_code[s],s);
|
|
while (j < (1 << STBI__ZFAST_BITS)) {
|
|
z->fast[j] = fastv;
|
|
j += (1 << s);
|
|
}
|
|
}
|
|
++next_code[s];
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
typedef struct
|
|
{
|
|
unsigned char *zbuffer, *zbuffer_end;
|
|
int num_bits;
|
|
stbi__uint32 code_buffer;
|
|
|
|
char *zout;
|
|
char *zout_start;
|
|
char *zout_end;
|
|
int z_expandable;
|
|
|
|
stbi__zhuffman z_length, z_distance;
|
|
} stbi__zbuf;
|
|
|
|
_inline static unsigned char stbi__zget8(stbi__zbuf *z)
|
|
{
|
|
if (z->zbuffer >= z->zbuffer_end) return 0;
|
|
return *z->zbuffer++;
|
|
}
|
|
|
|
static void stbi__fill_bits(stbi__zbuf *z)
|
|
{
|
|
do {
|
|
STBI_ASSERT(z->code_buffer < (1U << z->num_bits));
|
|
z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits;
|
|
z->num_bits += 8;
|
|
} while (z->num_bits <= 24);
|
|
}
|
|
|
|
_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n)
|
|
{
|
|
unsigned int k;
|
|
if (z->num_bits < n) stbi__fill_bits(z);
|
|
k = z->code_buffer & ((1 << n) - 1);
|
|
z->code_buffer >>= n;
|
|
z->num_bits -= n;
|
|
return k;
|
|
}
|
|
|
|
static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z)
|
|
{
|
|
int b,s,k;
|
|
k = stbi__bit_reverse(a->code_buffer, 16);
|
|
for (s=STBI__ZFAST_BITS+1; ; ++s)
|
|
if (k < z->maxcode[s])
|
|
break;
|
|
if (s == 16) return -1;
|
|
b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s];
|
|
STBI_ASSERT(z->size[b] == s);
|
|
a->code_buffer >>= s;
|
|
a->num_bits -= s;
|
|
return z->value[b];
|
|
}
|
|
|
|
_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z)
|
|
{
|
|
int b,s;
|
|
if (a->num_bits < 16) stbi__fill_bits(a);
|
|
b = z->fast[a->code_buffer & STBI__ZFAST_MASK];
|
|
if (b) {
|
|
s = b >> 9;
|
|
a->code_buffer >>= s;
|
|
a->num_bits -= s;
|
|
return b & 511;
|
|
}
|
|
return stbi__zhuffman_decode_slowpath(a, z);
|
|
}
|
|
|
|
static int stbi__zexpand(stbi__zbuf *z, char *zout, int n)
|
|
{
|
|
char *q;
|
|
int cur, limit, old_limit;
|
|
z->zout = zout;
|
|
if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG");
|
|
cur = (int) (z->zout - z->zout_start);
|
|
limit = old_limit = (int) (z->zout_end - z->zout_start);
|
|
while (cur + n > limit)
|
|
limit *= 2;
|
|
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");
|
|
z->zout_start = q;
|
|
z->zout = q + cur;
|
|
z->zout_end = q + limit;
|
|
return 1;
|
|
}
|
|
|
|
static int stbi__zlength_base[31] = {
|
|
3,4,5,6,7,8,9,10,11,13,
|
|
15,17,19,23,27,31,35,43,51,59,
|
|
67,83,99,115,131,163,195,227,258,0,0 };
|
|
|
|
static int stbi__zlength_extra[31]=
|
|
{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 };
|
|
|
|
static int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,
|
|
257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};
|
|
|
|
static int stbi__zdist_extra[32] =
|
|
{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
|
|
|
|
static int stbi__parse_huffman_block(stbi__zbuf *a)
|
|
{
|
|
char *zout = a->zout;
|
|
for(;;) {
|
|
int z = stbi__zhuffman_decode(a, &a->z_length);
|
|
if (z < 256) {
|
|
if (z < 0) return stbi__err("bad huffman code","Corrupt PNG");
|
|
if (zout >= a->zout_end) {
|
|
if (!stbi__zexpand(a, zout, 1)) return 0;
|
|
zout = a->zout;
|
|
}
|
|
*zout++ = (char) z;
|
|
} else {
|
|
unsigned char *p;
|
|
int len,dist;
|
|
if (z == 256) {
|
|
a->zout = zout;
|
|
return 1;
|
|
}
|
|
z -= 257;
|
|
len = stbi__zlength_base[z];
|
|
if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]);
|
|
z = stbi__zhuffman_decode(a, &a->z_distance);
|
|
if (z < 0) return stbi__err("bad huffman code","Corrupt PNG");
|
|
dist = stbi__zdist_base[z];
|
|
if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]);
|
|
if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG");
|
|
if (zout + len > a->zout_end) {
|
|
if (!stbi__zexpand(a, zout, len)) return 0;
|
|
zout = a->zout;
|
|
}
|
|
p = (unsigned char *) (zout - dist);
|
|
if (dist == 1) {
|
|
unsigned char v = *p;
|
|
if (len) { do *zout++ = v; while (--len); }
|
|
} else {
|
|
if (len) { do *zout++ = *p++; while (--len); }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static int stbi__compute_huffman_codes(stbi__zbuf *a)
|
|
{
|
|
static unsigned char length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };
|
|
stbi__zhuffman z_codelength;
|
|
unsigned char lencodes[286+32+137];
|
|
unsigned char codelength_sizes[19];
|
|
int i,n;
|
|
|
|
int hlit = stbi__zreceive(a,5) + 257;
|
|
int hdist = stbi__zreceive(a,5) + 1;
|
|
int hclen = stbi__zreceive(a,4) + 4;
|
|
int ntot = hlit + hdist;
|
|
|
|
memset(codelength_sizes, 0, sizeof(codelength_sizes));
|
|
for (i=0; i < hclen; ++i) {
|
|
int s = stbi__zreceive(a,3);
|
|
codelength_sizes[length_dezigzag[i]] = (unsigned char) s;
|
|
}
|
|
if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0;
|
|
|
|
n = 0;
|
|
while (n < ntot) {
|
|
int c = stbi__zhuffman_decode(a, &z_codelength);
|
|
if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG");
|
|
if (c < 16)
|
|
lencodes[n++] = (unsigned char) c;
|
|
else {
|
|
unsigned char fill = 0;
|
|
if (c == 16) {
|
|
c = stbi__zreceive(a,2)+3;
|
|
if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG");
|
|
fill = lencodes[n-1];
|
|
} else if (c == 17)
|
|
c = stbi__zreceive(a,3)+3;
|
|
else {
|
|
STBI_ASSERT(c == 18);
|
|
c = stbi__zreceive(a,7)+11;
|
|
}
|
|
if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG");
|
|
memset(lencodes+n, fill, c);
|
|
n += c;
|
|
}
|
|
}
|
|
if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG");
|
|
if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0;
|
|
if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0;
|
|
return 1;
|
|
}
|
|
|
|
_inline static int stbi__parse_uncompressed_block(stbi__zbuf *a)
|
|
{
|
|
unsigned char header[4];
|
|
int len,nlen,k;
|
|
if (a->num_bits & 7)
|
|
stbi__zreceive(a, a->num_bits & 7);
|
|
k = 0;
|
|
while (a->num_bits > 0) {
|
|
header[k++] = (unsigned char) (a->code_buffer & 255);
|
|
a->code_buffer >>= 8;
|
|
a->num_bits -= 8;
|
|
}
|
|
STBI_ASSERT(a->num_bits == 0);
|
|
while (k < 4)
|
|
header[k++] = stbi__zget8(a);
|
|
len = header[1] * 256 + header[0];
|
|
nlen = header[3] * 256 + header[2];
|
|
if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG");
|
|
if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG");
|
|
if (a->zout + len > a->zout_end)
|
|
if (!stbi__zexpand(a, a->zout, len)) return 0;
|
|
memcpy(a->zout, a->zbuffer, len);
|
|
a->zbuffer += len;
|
|
a->zout += len;
|
|
return 1;
|
|
}
|
|
|
|
static int stbi__parse_zlib_header(stbi__zbuf *a)
|
|
{
|
|
int cmf = stbi__zget8(a);
|
|
int cm = cmf & 15;
|
|
/* int cinfo = cmf >> 4; */
|
|
int flg = stbi__zget8(a);
|
|
if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG");
|
|
if (flg & 32) return stbi__err("no preset dict","Corrupt PNG");
|
|
if (cm != 8) return stbi__err("bad compression","Corrupt PNG");
|
|
return 1;
|
|
}
|
|
|
|
static unsigned char stbi__zdefault_length[288], stbi__zdefault_distance[32];
|
|
static void stbi__init_zdefaults(void)
|
|
{
|
|
int i;
|
|
for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8;
|
|
for ( ; i <= 255; ++i) stbi__zdefault_length[i] = 9;
|
|
for ( ; i <= 279; ++i) stbi__zdefault_length[i] = 7;
|
|
for ( ; i <= 287; ++i) stbi__zdefault_length[i] = 8;
|
|
|
|
for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5;
|
|
}
|
|
|
|
static int stbi__parse_zlib(stbi__zbuf *a, int parse_header)
|
|
{
|
|
int final, type;
|
|
if (parse_header)
|
|
if (!stbi__parse_zlib_header(a)) return 0;
|
|
a->num_bits = 0;
|
|
a->code_buffer = 0;
|
|
do {
|
|
final = stbi__zreceive(a,1);
|
|
type = stbi__zreceive(a,2);
|
|
if (type == 0) {
|
|
if (!stbi__parse_uncompressed_block(a)) return 0;
|
|
} else if (type == 3) {
|
|
return 0;
|
|
} else {
|
|
if (type == 1) {
|
|
if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0;
|
|
if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0;
|
|
} else {
|
|
if (!stbi__compute_huffman_codes(a)) return 0;
|
|
}
|
|
if (!stbi__parse_huffman_block(a)) return 0;
|
|
}
|
|
} while (!final);
|
|
return 1;
|
|
}
|
|
|
|
static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header)
|
|
{
|
|
a->zout_start = obuf;
|
|
a->zout = obuf;
|
|
a->zout_end = obuf + olen;
|
|
a->z_expandable = exp;
|
|
stbi__init_zdefaults();
|
|
return stbi__parse_zlib(a, parse_header);
|
|
}
|
|
|
|
char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header)
|
|
{
|
|
stbi__zbuf a;
|
|
char *p = (char *) stbi__malloc(initial_size);
|
|
if (p == NULL) return NULL;
|
|
a.zbuffer = (unsigned char *) buffer;
|
|
a.zbuffer_end = (unsigned char *) buffer + len;
|
|
if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) {
|
|
if (outlen) *outlen = (int) (a.zout - a.zout_start);
|
|
return a.zout_start;
|
|
} else {
|
|
STBI_FREE(a.zout_start);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
typedef struct
|
|
{
|
|
stbi__uint32 length;
|
|
stbi__uint32 type;
|
|
} stbi__pngchunk;
|
|
|
|
static stbi__pngchunk stbi__get_chunk_header(stbi__context *s)
|
|
{
|
|
stbi__pngchunk c;
|
|
c.length = stbi__get32be(s);
|
|
c.type = stbi__get32be(s);
|
|
return c;
|
|
}
|
|
|
|
_inline static int stbi__check_png_header(stbi__context *s)
|
|
{
|
|
static unsigned char png_sig[8] = { 137,80,78,71,13,10,26,10 };
|
|
int i;
|
|
for (i=0; i < 8; ++i)
|
|
if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG");
|
|
return 1;
|
|
}
|
|
|
|
typedef struct
|
|
{
|
|
stbi__context *s;
|
|
unsigned char *idata, *expanded, *out;
|
|
int depth;
|
|
} stbi__png;
|
|
|
|
|
|
enum {
|
|
STBI__F_none=0,
|
|
STBI__F_sub=1,
|
|
STBI__F_up=2,
|
|
STBI__F_avg=3,
|
|
STBI__F_paeth=4,
|
|
STBI__F_avg_first,
|
|
STBI__F_paeth_first
|
|
};
|
|
|
|
static unsigned char first_row_filter[5] =
|
|
{
|
|
STBI__F_none,
|
|
STBI__F_sub,
|
|
STBI__F_none,
|
|
STBI__F_avg_first,
|
|
STBI__F_paeth_first
|
|
};
|
|
|
|
static int stbi__paeth(int a, int b, int c)
|
|
{
|
|
int p = a + b - c;
|
|
int pa = abs(p-a);
|
|
int pb = abs(p-b);
|
|
int pc = abs(p-c);
|
|
if (pa <= pb && pa <= pc) return a;
|
|
if (pb <= pc) return b;
|
|
return c;
|
|
}
|
|
|
|
static unsigned char stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 };
|
|
|
|
static int stbi__create_png_image_raw(stbi__png *a, unsigned char *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color)
|
|
{
|
|
int bytes = (depth == 16? 2 : 1);
|
|
stbi__context *s = a->s;
|
|
stbi__uint32 i,j,stride = x*out_n*bytes;
|
|
stbi__uint32 img_len, img_width_bytes;
|
|
int k;
|
|
int img_n = s->img_n;
|
|
|
|
int output_bytes = out_n*bytes;
|
|
int filter_bytes = img_n*bytes;
|
|
int width = x;
|
|
|
|
STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1);
|
|
a->out = (unsigned char *) stbi__malloc_mad3(x, y, output_bytes, 0);
|
|
if (!a->out) return stbi__err("outofmem", "Out of memory");
|
|
|
|
if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG");
|
|
img_width_bytes = (((img_n * x * depth) + 7) >> 3);
|
|
img_len = (img_width_bytes + 1) * y;
|
|
if (s->img_x == x && s->img_y == y) {
|
|
if (raw_len != img_len) return stbi__err("not enough pixels","Corrupt PNG");
|
|
} else {
|
|
if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG");
|
|
}
|
|
|
|
for (j=0; j < y; ++j) {
|
|
unsigned char *cur = a->out + stride*j;
|
|
unsigned char *prior = cur - stride;
|
|
int filter = *raw++;
|
|
|
|
if (filter > 4)
|
|
return stbi__err("invalid filter","Corrupt PNG");
|
|
|
|
if (depth < 8) {
|
|
STBI_ASSERT(img_width_bytes <= x);
|
|
cur += x*out_n - img_width_bytes;
|
|
filter_bytes = 1;
|
|
width = img_width_bytes;
|
|
}
|
|
prior = cur - stride;
|
|
|
|
if (j == 0) filter = first_row_filter[filter];
|
|
|
|
for (k=0; k < filter_bytes; ++k) {
|
|
switch (filter) {
|
|
case STBI__F_none : cur[k] = raw[k]; break;
|
|
case STBI__F_sub : cur[k] = raw[k]; break;
|
|
case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break;
|
|
case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break;
|
|
case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break;
|
|
case STBI__F_avg_first : cur[k] = raw[k]; break;
|
|
case STBI__F_paeth_first: cur[k] = raw[k]; break;
|
|
}
|
|
}
|
|
|
|
if (depth == 8) {
|
|
if (img_n != out_n)
|
|
cur[img_n] = 255;
|
|
raw += img_n;
|
|
cur += out_n;
|
|
prior += out_n;
|
|
} else if (depth == 16) {
|
|
if (img_n != out_n) {
|
|
cur[filter_bytes] = 255;
|
|
cur[filter_bytes+1] = 255;
|
|
}
|
|
raw += filter_bytes;
|
|
cur += output_bytes;
|
|
prior += output_bytes;
|
|
} else {
|
|
raw += 1;
|
|
cur += 1;
|
|
prior += 1;
|
|
}
|
|
|
|
if (depth < 8 || img_n == out_n) {
|
|
int nk = (width - 1)*filter_bytes;
|
|
#define STBI__CASE(f) \
|
|
case f: \
|
|
for (k=0; k < nk; ++k)
|
|
switch (filter) {
|
|
case STBI__F_none: memcpy(cur, raw, nk); break;
|
|
STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break;
|
|
STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break;
|
|
STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break;
|
|
STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break;
|
|
STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break;
|
|
STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break;
|
|
}
|
|
#undef STBI__CASE
|
|
raw += nk;
|
|
} else {
|
|
STBI_ASSERT(img_n+1 == out_n);
|
|
#define STBI__CASE(f) \
|
|
case f: \
|
|
for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \
|
|
for (k=0; k < filter_bytes; ++k)
|
|
switch (filter) {
|
|
STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } break;
|
|
STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break;
|
|
STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break;
|
|
STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break;
|
|
STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break;
|
|
STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break;
|
|
STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break;
|
|
}
|
|
#undef STBI__CASE
|
|
|
|
if (depth == 16) {
|
|
cur = a->out + stride*j;
|
|
for (i=0; i < x; ++i,cur+=output_bytes) {
|
|
cur[filter_bytes+1] = 255;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (depth < 8) {
|
|
for (j=0; j < y; ++j) {
|
|
unsigned char *cur = a->out + stride*j;
|
|
unsigned char *in = a->out + stride*j + x*out_n - img_width_bytes;
|
|
unsigned char scale = (color == 0) ? stbi__depth_scale_table[depth] : 1;
|
|
|
|
if (depth == 4) {
|
|
for (k=x*img_n; k >= 2; k-=2, ++in) {
|
|
*cur++ = scale * ((*in >> 4) );
|
|
*cur++ = scale * ((*in ) & 0x0f);
|
|
}
|
|
if (k > 0) *cur++ = scale * ((*in >> 4) );
|
|
} else if (depth == 2) {
|
|
for (k=x*img_n; k >= 4; k-=4, ++in) {
|
|
*cur++ = scale * ((*in >> 6) );
|
|
*cur++ = scale * ((*in >> 4) & 0x03);
|
|
*cur++ = scale * ((*in >> 2) & 0x03);
|
|
*cur++ = scale * ((*in ) & 0x03);
|
|
}
|
|
if (k > 0) *cur++ = scale * ((*in >> 6) );
|
|
if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03);
|
|
if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03);
|
|
} else if (depth == 1) {
|
|
for (k=x*img_n; k >= 8; k-=8, ++in) {
|
|
*cur++ = scale * ((*in >> 7) );
|
|
*cur++ = scale * ((*in >> 6) & 0x01);
|
|
*cur++ = scale * ((*in >> 5) & 0x01);
|
|
*cur++ = scale * ((*in >> 4) & 0x01);
|
|
*cur++ = scale * ((*in >> 3) & 0x01);
|
|
*cur++ = scale * ((*in >> 2) & 0x01);
|
|
*cur++ = scale * ((*in >> 1) & 0x01);
|
|
*cur++ = scale * ((*in ) & 0x01);
|
|
}
|
|
if (k > 0) *cur++ = scale * ((*in >> 7) );
|
|
if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01);
|
|
if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01);
|
|
if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01);
|
|
if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01);
|
|
if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01);
|
|
if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01);
|
|
}
|
|
if (img_n != out_n) {
|
|
int q;
|
|
cur = a->out + stride*j;
|
|
if (img_n == 1) {
|
|
for (q=x-1; q >= 0; --q) {
|
|
cur[q*2+1] = 255;
|
|
cur[q*2+0] = cur[q];
|
|
}
|
|
} else {
|
|
STBI_ASSERT(img_n == 3);
|
|
for (q=x-1; q >= 0; --q) {
|
|
cur[q*4+3] = 255;
|
|
cur[q*4+2] = cur[q*3+2];
|
|
cur[q*4+1] = cur[q*3+1];
|
|
cur[q*4+0] = cur[q*3+0];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if (depth == 16) {
|
|
unsigned char *cur = a->out;
|
|
stbi__uint16 *cur16 = (stbi__uint16*)cur;
|
|
|
|
for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) {
|
|
*cur16 = (cur[0] << 8) | cur[1];
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int stbi__create_png_image(stbi__png *a, unsigned char *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced)
|
|
{
|
|
int bytes = (depth == 16 ? 2 : 1);
|
|
int out_bytes = out_n * bytes;
|
|
unsigned char *final;
|
|
int p;
|
|
if (!interlaced)
|
|
return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color);
|
|
|
|
final = (unsigned char *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0);
|
|
for (p=0; p < 7; ++p) {
|
|
int xorig[] = { 0,4,0,2,0,1,0 };
|
|
int yorig[] = { 0,0,4,0,2,0,1 };
|
|
int xspc[] = { 8,8,4,4,2,2,1 };
|
|
int yspc[] = { 8,8,8,4,4,2,2 };
|
|
int i,j,x,y;
|
|
x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p];
|
|
y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p];
|
|
if (x && y) {
|
|
stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y;
|
|
if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) {
|
|
STBI_FREE(final);
|
|
return 0;
|
|
}
|
|
for (j=0; j < y; ++j) {
|
|
for (i=0; i < x; ++i) {
|
|
int out_y = j*yspc[p]+yorig[p];
|
|
int out_x = i*xspc[p]+xorig[p];
|
|
memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes,
|
|
a->out + (j*x+i)*out_bytes, out_bytes);
|
|
}
|
|
}
|
|
STBI_FREE(a->out);
|
|
image_data += img_len;
|
|
image_data_len -= img_len;
|
|
}
|
|
}
|
|
a->out = final;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int stbi__compute_transparency(stbi__png *z, unsigned char tc[3], int out_n)
|
|
{
|
|
stbi__context *s = z->s;
|
|
stbi__uint32 i, pixel_count = s->img_x * s->img_y;
|
|
unsigned char *p = z->out;
|
|
|
|
STBI_ASSERT(out_n == 2 || out_n == 4);
|
|
|
|
if (out_n == 2) {
|
|
for (i=0; i < pixel_count; ++i) {
|
|
p[1] = (p[0] == tc[0] ? 0 : 255);
|
|
p += 2;
|
|
}
|
|
} else {
|
|
for (i=0; i < pixel_count; ++i) {
|
|
if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])
|
|
p[3] = 0;
|
|
p += 4;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n)
|
|
{
|
|
stbi__context *s = z->s;
|
|
stbi__uint32 i, pixel_count = s->img_x * s->img_y;
|
|
stbi__uint16 *p = (stbi__uint16*) z->out;
|
|
|
|
STBI_ASSERT(out_n == 2 || out_n == 4);
|
|
|
|
if (out_n == 2) {
|
|
for (i = 0; i < pixel_count; ++i) {
|
|
p[1] = (p[0] == tc[0] ? 0 : 65535);
|
|
p += 2;
|
|
}
|
|
} else {
|
|
for (i = 0; i < pixel_count; ++i) {
|
|
if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])
|
|
p[3] = 0;
|
|
p += 4;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int stbi__expand_png_palette(stbi__png *a, unsigned char *palette, int len, int pal_img_n)
|
|
{
|
|
stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y;
|
|
unsigned char *p, *temp_out, *orig = a->out;
|
|
|
|
p = (unsigned char *) stbi__malloc_mad2(pixel_count, pal_img_n, 0);
|
|
if (p == NULL) return stbi__err("outofmem", "Out of memory");
|
|
|
|
temp_out = p;
|
|
|
|
if (pal_img_n == 3) {
|
|
for (i=0; i < pixel_count; ++i) {
|
|
int n = orig[i]*4;
|
|
p[0] = palette[n ];
|
|
p[1] = palette[n+1];
|
|
p[2] = palette[n+2];
|
|
p += 3;
|
|
}
|
|
} else {
|
|
for (i=0; i < pixel_count; ++i) {
|
|
int n = orig[i]*4;
|
|
p[0] = palette[n ];
|
|
p[1] = palette[n+1];
|
|
p[2] = palette[n+2];
|
|
p[3] = palette[n+3];
|
|
p += 4;
|
|
}
|
|
}
|
|
STBI_FREE(a->out);
|
|
a->out = temp_out;
|
|
|
|
STBI_NOTUSED(len);
|
|
|
|
return 1;
|
|
}
|
|
|
|
#define STBI__PNG_TYPE(a,b,c,d) (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d))
|
|
|
|
static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
|
|
{
|
|
unsigned char palette[1024], pal_img_n=0;
|
|
unsigned char has_trans=0, tc[3];
|
|
stbi__uint16 tc16[3];
|
|
stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0;
|
|
int first=1,k,interlace=0, color=0;
|
|
stbi__context *s = z->s;
|
|
|
|
z->expanded = NULL;
|
|
z->idata = NULL;
|
|
z->out = NULL;
|
|
|
|
if (!stbi__check_png_header(s)) return 0;
|
|
|
|
if (scan == STBI__SCAN_type) return 1;
|
|
|
|
for (;;) {
|
|
stbi__pngchunk c = stbi__get_chunk_header(s);
|
|
switch (c.type) {
|
|
case STBI__PNG_TYPE('C','g','B','I'):
|
|
stbi__skip(s, c.length);
|
|
break;
|
|
case STBI__PNG_TYPE('I','H','D','R'): {
|
|
int comp,filter;
|
|
if (!first) return stbi__err("multiple IHDR","Corrupt PNG");
|
|
first = 0;
|
|
if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG");
|
|
s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)");
|
|
s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)");
|
|
z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only");
|
|
color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG");
|
|
if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG");
|
|
if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG");
|
|
comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG");
|
|
filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG");
|
|
interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG");
|
|
if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG");
|
|
if (!pal_img_n) {
|
|
s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0);
|
|
if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode");
|
|
if (scan == STBI__SCAN_header) return 1;
|
|
} else {
|
|
s->img_n = 1;
|
|
if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG");
|
|
}
|
|
break;
|
|
}
|
|
|
|
case STBI__PNG_TYPE('P','L','T','E'): {
|
|
if (first) return stbi__err("first not IHDR", "Corrupt PNG");
|
|
if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG");
|
|
pal_len = c.length / 3;
|
|
if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG");
|
|
for (i=0; i < pal_len; ++i) {
|
|
palette[i*4+0] = stbi__get8(s);
|
|
palette[i*4+1] = stbi__get8(s);
|
|
palette[i*4+2] = stbi__get8(s);
|
|
palette[i*4+3] = 255;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case STBI__PNG_TYPE('t','R','N','S'): {
|
|
if (first) return stbi__err("first not IHDR", "Corrupt PNG");
|
|
if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG");
|
|
if (pal_img_n) {
|
|
if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; }
|
|
if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG");
|
|
if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG");
|
|
pal_img_n = 4;
|
|
for (i=0; i < c.length; ++i)
|
|
palette[i*4+3] = stbi__get8(s);
|
|
} else {
|
|
if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG");
|
|
if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG");
|
|
has_trans = 1;
|
|
if (z->depth == 16) {
|
|
for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s);
|
|
} else {
|
|
for (k = 0; k < s->img_n; ++k) tc[k] = (unsigned char)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth];
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case STBI__PNG_TYPE('I','D','A','T'): {
|
|
if (first) return stbi__err("first not IHDR", "Corrupt PNG");
|
|
if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG");
|
|
if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; }
|
|
if ((int)(ioff + c.length) < (int)ioff) return 0;
|
|
if (ioff + c.length > idata_limit) {
|
|
stbi__uint32 idata_limit_old = idata_limit;
|
|
unsigned char *p;
|
|
if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096;
|
|
while (ioff + c.length > idata_limit)
|
|
idata_limit *= 2;
|
|
STBI_NOTUSED(idata_limit_old);
|
|
p = (unsigned char *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory");
|
|
z->idata = p;
|
|
}
|
|
if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG");
|
|
ioff += c.length;
|
|
break;
|
|
}
|
|
|
|
case STBI__PNG_TYPE('I','E','N','D'): {
|
|
stbi__uint32 raw_len, bpl;
|
|
if (first) return stbi__err("first not IHDR", "Corrupt PNG");
|
|
if (scan != STBI__SCAN_load) return 1;
|
|
if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG");
|
|
bpl = (s->img_x * z->depth + 7) / 8;
|
|
raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */;
|
|
z->expanded = (unsigned char *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, 1);
|
|
if (z->expanded == NULL) return 0;
|
|
STBI_FREE(z->idata); z->idata = NULL;
|
|
if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans)
|
|
s->img_out_n = s->img_n+1;
|
|
else
|
|
s->img_out_n = s->img_n;
|
|
if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0;
|
|
if (has_trans) {
|
|
if (z->depth == 16) {
|
|
if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0;
|
|
} else {
|
|
if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0;
|
|
}
|
|
}
|
|
if (pal_img_n) {
|
|
s->img_n = pal_img_n;
|
|
s->img_out_n = pal_img_n;
|
|
if (req_comp >= 3) s->img_out_n = req_comp;
|
|
if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n))
|
|
return 0;
|
|
} else if (has_trans) {
|
|
++s->img_n;
|
|
}
|
|
STBI_FREE(z->expanded); z->expanded = NULL;
|
|
return 1;
|
|
}
|
|
|
|
default:
|
|
if (first) return stbi__err("first not IHDR", "Corrupt PNG");
|
|
if ((c.type & (1 << 29)) == 0) {
|
|
return stbi__err("invalid_chunk", "PNG not supported: unknown PNG chunk type");
|
|
}
|
|
stbi__skip(s, c.length);
|
|
break;
|
|
}
|
|
stbi__get32be(s);
|
|
}
|
|
}
|
|
|
|
static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri)
|
|
{
|
|
void *result=NULL;
|
|
if (req_comp < 0 || req_comp > 4) { stbi__err("bad req_comp", "Internal error"); return NULL; }
|
|
if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) {
|
|
if (p->depth < 8)
|
|
ri->bits_per_channel = 8;
|
|
else
|
|
ri->bits_per_channel = p->depth;
|
|
result = p->out;
|
|
p->out = NULL;
|
|
if (req_comp && req_comp != p->s->img_out_n) {
|
|
if (ri->bits_per_channel == 8)
|
|
result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);
|
|
else
|
|
result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);
|
|
p->s->img_out_n = req_comp;
|
|
if (result == NULL) return result;
|
|
}
|
|
*x = p->s->img_x;
|
|
*y = p->s->img_y;
|
|
if (n) *n = p->s->img_n;
|
|
}
|
|
STBI_FREE(p->out); p->out = NULL;
|
|
STBI_FREE(p->expanded); p->expanded = NULL;
|
|
STBI_FREE(p->idata); p->idata = NULL;
|
|
|
|
return result;
|
|
}
|
|
|
|
void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
|
|
{
|
|
stbi__png p;
|
|
p.s = s;
|
|
return stbi__do_png(&p, x,y,comp,req_comp, ri);
|
|
}
|
|
|
|
/* zlib_compressor from
|
|
|
|
stb_image_write - v1.13 - public domain - http://nothings.org/stb/stb_image_write.h
|
|
*/
|
|
typedef unsigned char stbiw__uc;
|
|
typedef unsigned short stbiw__us;
|
|
|
|
typedef uint16_t stbiw__uint16;
|
|
typedef int16_t stbiw__int16;
|
|
typedef uint32_t stbiw__uint32;
|
|
typedef int32_t stbiw__int32;
|
|
|
|
#define STBIW_MALLOC(s) STBI_MALLOC(s)
|
|
#define STBIW_REALLOC(p,ns) STBI_REALLOC(p,ns)
|
|
#define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz)
|
|
#define STBIW_FREE STBI_FREE
|
|
#define STBIW_MEMMOVE memmove
|
|
#define STBIW_UCHAR (uint8_t)
|
|
#define STBIW_ASSERT(x)
|
|
#define stbiw___sbraw(a) ((int *) (a) - 2)
|
|
#define stbiw___sbm(a) stbiw___sbraw(a)[0]
|
|
#define stbiw___sbn(a) stbiw___sbraw(a)[1]
|
|
|
|
#define stbiw___sbneedgrow(a,n) ((a)==0 || stbiw___sbn(a)+n >= stbiw___sbm(a))
|
|
#define stbiw___sbmaybegrow(a,n) (stbiw___sbneedgrow(a,(n)) ? stbiw___sbgrow(a,n) : 0)
|
|
#define stbiw___sbgrow(a,n) stbiw___sbgrowf((void **) &(a), (n), sizeof(*(a)))
|
|
|
|
#define stbiw___sbpush(a, v) (stbiw___sbmaybegrow(a,1), (a)[stbiw___sbn(a)++] = (v))
|
|
#define stbiw___sbcount(a) ((a) ? stbiw___sbn(a) : 0)
|
|
#define stbiw___sbfree(a) ((a) ? STBIW_FREE(stbiw___sbraw(a)),0 : 0)
|
|
|
|
static void *stbiw___sbgrowf(void **arr, int increment, int itemsize)
|
|
{
|
|
int m = *arr ? 2*stbiw___sbm(*arr)+increment : increment+1;
|
|
void *p = STBIW_REALLOC_SIZED(*arr ? stbiw___sbraw(*arr) : 0, *arr ? (stbiw___sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2);
|
|
STBIW_ASSERT(p);
|
|
if (p) {
|
|
if (!*arr) ((int *) p)[1] = 0;
|
|
*arr = (void *) ((int *) p + 2);
|
|
stbiw___sbm(*arr) = m;
|
|
}
|
|
return *arr;
|
|
}
|
|
|
|
static unsigned char *stbiw___zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount)
|
|
{
|
|
while (*bitcount >= 8) {
|
|
stbiw___sbpush(data, STBIW_UCHAR(*bitbuffer));
|
|
*bitbuffer >>= 8;
|
|
*bitcount -= 8;
|
|
}
|
|
return data;
|
|
}
|
|
|
|
static int stbiw___zlib_bitrev(int code, int codebits)
|
|
{
|
|
int res=0;
|
|
while (codebits--) {
|
|
res = (res << 1) | (code & 1);
|
|
code >>= 1;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
static unsigned int stbiw___zlib_countm(unsigned char *a, unsigned char *b, int limit)
|
|
{
|
|
int i;
|
|
for (i=0; i < limit && i < 258; ++i)
|
|
if (a[i] != b[i]) break;
|
|
return i;
|
|
}
|
|
|
|
static unsigned int stbiw___zhash(unsigned char *data)
|
|
{
|
|
stbiw__uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16);
|
|
hash ^= hash << 3;
|
|
hash += hash >> 5;
|
|
hash ^= hash << 4;
|
|
hash += hash >> 17;
|
|
hash ^= hash << 25;
|
|
hash += hash >> 6;
|
|
return hash;
|
|
}
|
|
|
|
#define stbiw___zlib_flush() (out = stbiw___zlib_flushf(out, &bitbuf, &bitcount))
|
|
#define stbiw___zlib_add(code,codebits) \
|
|
(bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw___zlib_flush())
|
|
#define stbiw___zlib_huffa(b,c) stbiw___zlib_add(stbiw___zlib_bitrev(b,c),c)
|
|
#define stbiw___zlib_huff1(n) stbiw___zlib_huffa(0x30 + (n), 8)
|
|
#define stbiw___zlib_huff2(n) stbiw___zlib_huffa(0x190 + (n)-144, 9)
|
|
#define stbiw___zlib_huff3(n) stbiw___zlib_huffa(0 + (n)-256,7)
|
|
#define stbiw___zlib_huff4(n) stbiw___zlib_huffa(0xc0 + (n)-280,8)
|
|
#define stbiw___zlib_huff(n) ((n) <= 143 ? stbiw___zlib_huff1(n) : (n) <= 255 ? stbiw___zlib_huff2(n) : (n) <= 279 ? stbiw___zlib_huff3(n) : stbiw___zlib_huff4(n))
|
|
#define stbiw___zlib_huffb(n) ((n) <= 143 ? stbiw___zlib_huff1(n) : stbiw___zlib_huff2(n))
|
|
|
|
#define stbiw___ZHASH 16384
|
|
|
|
unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality)
|
|
{
|
|
static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 };
|
|
static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 };
|
|
static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 };
|
|
static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 };
|
|
unsigned int bitbuf=0;
|
|
int i,j, bitcount=0;
|
|
unsigned char *out = NULL;
|
|
unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw___ZHASH * sizeof(char**));
|
|
if (hash_table == NULL)
|
|
return NULL;
|
|
if (quality < 5) quality = 5;
|
|
|
|
stbiw___sbpush(out, 0x78);
|
|
stbiw___sbpush(out, 0x5e);
|
|
stbiw___zlib_add(1,1);
|
|
stbiw___zlib_add(1,2);
|
|
|
|
for (i=0; i < stbiw___ZHASH; ++i)
|
|
hash_table[i] = NULL;
|
|
|
|
i=0;
|
|
while (i < data_len-3) {
|
|
int h = stbiw___zhash(data+i)&(stbiw___ZHASH-1), best=3;
|
|
unsigned char *bestloc = 0;
|
|
unsigned char **hlist = hash_table[h];
|
|
int n = stbiw___sbcount(hlist);
|
|
for (j=0; j < n; ++j) {
|
|
if (hlist[j]-data > i-32768) {
|
|
int d = stbiw___zlib_countm(hlist[j], data+i, data_len-i);
|
|
if (d >= best) best=d,bestloc=hlist[j];
|
|
}
|
|
}
|
|
if (hash_table[h] && stbiw___sbn(hash_table[h]) == 2*quality) {
|
|
STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality);
|
|
stbiw___sbn(hash_table[h]) = quality;
|
|
}
|
|
stbiw___sbpush(hash_table[h],data+i);
|
|
|
|
if (bestloc) {
|
|
h = stbiw___zhash(data+i+1)&(stbiw___ZHASH-1);
|
|
hlist = hash_table[h];
|
|
n = stbiw___sbcount(hlist);
|
|
for (j=0; j < n; ++j) {
|
|
if (hlist[j]-data > i-32767) {
|
|
int e = stbiw___zlib_countm(hlist[j], data+i+1, data_len-i-1);
|
|
if (e > best) {
|
|
bestloc = NULL;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bestloc) {
|
|
int d = (int) (data+i - bestloc);
|
|
STBIW_ASSERT(d <= 32767 && best <= 258);
|
|
for (j=0; best > lengthc[j+1]-1; ++j);
|
|
stbiw___zlib_huff(j+257);
|
|
if (lengtheb[j]) stbiw___zlib_add(best - lengthc[j], lengtheb[j]);
|
|
for (j=0; d > distc[j+1]-1; ++j);
|
|
stbiw___zlib_add(stbiw___zlib_bitrev(j,5),5);
|
|
if (disteb[j]) stbiw___zlib_add(d - distc[j], disteb[j]);
|
|
i += best;
|
|
} else {
|
|
stbiw___zlib_huffb(data[i]);
|
|
++i;
|
|
}
|
|
}
|
|
for (;i < data_len; ++i)
|
|
stbiw___zlib_huffb(data[i]);
|
|
stbiw___zlib_huff(256);
|
|
while (bitcount)
|
|
stbiw___zlib_add(0,1);
|
|
|
|
for (i=0; i < stbiw___ZHASH; ++i)
|
|
(void) stbiw___sbfree(hash_table[i]);
|
|
STBIW_FREE(hash_table);
|
|
|
|
{
|
|
unsigned int s1=1, s2=0;
|
|
int blocklen = (int) (data_len % 5552);
|
|
j=0;
|
|
while (j < data_len) {
|
|
for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1;
|
|
s1 %= 65521, s2 %= 65521;
|
|
j += blocklen;
|
|
blocklen = 5552;
|
|
}
|
|
stbiw___sbpush(out, STBIW_UCHAR(s2 >> 8));
|
|
stbiw___sbpush(out, STBIW_UCHAR(s2));
|
|
stbiw___sbpush(out, STBIW_UCHAR(s1 >> 8));
|
|
stbiw___sbpush(out, STBIW_UCHAR(s1));
|
|
}
|
|
*out_len = stbiw___sbn(out);
|
|
STBIW_MEMMOVE(stbiw___sbraw(out), out, *out_len);
|
|
return (unsigned char *) stbiw___sbraw(out);
|
|
}
|
|
|
|
static unsigned int stbiw__crc32(unsigned char *buffer, int len)
|
|
{
|
|
#ifdef STBIW_CRC32
|
|
return STBIW_CRC32(buffer, len);
|
|
#else
|
|
static unsigned int crc_table[256] =
|
|
{
|
|
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
|
|
0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
|
|
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
|
|
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
|
|
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
|
|
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
|
|
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
|
|
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
|
|
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
|
|
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
|
|
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
|
|
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
|
|
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
|
|
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
|
|
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
|
|
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
|
|
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
|
|
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
|
|
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
|
|
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
|
|
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
|
|
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
|
|
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
|
|
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
|
|
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
|
|
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
|
|
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
|
|
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
|
|
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
|
|
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
|
|
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
|
|
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
|
|
};
|
|
|
|
unsigned int crc = ~0u;
|
|
int i;
|
|
for (i=0; i < len; ++i)
|
|
crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)];
|
|
return ~crc;
|
|
#endif
|
|
}
|
|
|
|
#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4)
|
|
#define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v));
|
|
#define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3])
|
|
|
|
static void stbiw__wpcrc(unsigned char **data, int len)
|
|
{
|
|
unsigned int crc = stbiw__crc32(*data - len - 4, len+4);
|
|
stbiw__wp32(*data, crc);
|
|
}
|
|
|
|
static unsigned char stbiw__paeth(int a, int b, int c)
|
|
{
|
|
int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c);
|
|
if (pa <= pb && pa <= pc) return STBIW_UCHAR(a);
|
|
if (pb <= pc) return STBIW_UCHAR(b);
|
|
return STBIW_UCHAR(c);
|
|
}
|
|
|
|
static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int width, int y, int n, int filter_type, signed char *line_buffer)
|
|
{
|
|
static int mapping[] = { 0,1,2,3,4 };
|
|
static int firstmap[] = { 0,1,0,5,6 };
|
|
int *mymap = (y != 0) ? mapping : firstmap;
|
|
int i;
|
|
int type = mymap[filter_type];
|
|
unsigned char *z = pixels + stride_bytes * y;
|
|
int signed_stride = stride_bytes;
|
|
|
|
if (type==0) {
|
|
memcpy(line_buffer, z, width*n);
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < n; ++i) {
|
|
switch (type) {
|
|
case 1: line_buffer[i] = z[i]; break;
|
|
case 2: line_buffer[i] = z[i] - z[i-signed_stride]; break;
|
|
case 3: line_buffer[i] = z[i] - (z[i-signed_stride]>>1); break;
|
|
case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-signed_stride],0)); break;
|
|
case 5: line_buffer[i] = z[i]; break;
|
|
case 6: line_buffer[i] = z[i]; break;
|
|
}
|
|
}
|
|
switch (type) {
|
|
case 1: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-n]; break;
|
|
case 2: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-signed_stride]; break;
|
|
case 3: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - ((z[i-n] + z[i-signed_stride])>>1); break;
|
|
case 4: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-signed_stride], z[i-signed_stride-n]); break;
|
|
case 5: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - (z[i-n]>>1); break;
|
|
case 6: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break;
|
|
}
|
|
}
|
|
|
|
unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)
|
|
{
|
|
int force_filter = -1;
|
|
int ctype[5] = { -1, 0, 4, 2, 6 };
|
|
unsigned char sig[8] = { 137,80,78,71,13,10,26,10 };
|
|
unsigned char *out,*o, *filt, *zlib;
|
|
signed char *line_buffer;
|
|
int j,zlen;
|
|
|
|
if (stride_bytes == 0)
|
|
stride_bytes = x * n;
|
|
|
|
if (force_filter >= 5) {
|
|
force_filter = -1;
|
|
}
|
|
|
|
filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0;
|
|
line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; }
|
|
for (j=0; j < y; ++j) {
|
|
int filter_type;
|
|
if (force_filter > -1) {
|
|
filter_type = force_filter;
|
|
stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, j, n, force_filter, line_buffer);
|
|
} else {
|
|
int best_filter = 0, best_filter_val = 0x7fffffff, est, i;
|
|
for (filter_type = 0; filter_type < 5; filter_type++) {
|
|
stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, j, n, filter_type, line_buffer);
|
|
|
|
est = 0;
|
|
for (i = 0; i < x*n; ++i) {
|
|
est += abs((signed char) line_buffer[i]);
|
|
}
|
|
if (est < best_filter_val) {
|
|
best_filter_val = est;
|
|
best_filter = filter_type;
|
|
}
|
|
}
|
|
if (filter_type != best_filter) {
|
|
stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, j, n, best_filter, line_buffer);
|
|
filter_type = best_filter;
|
|
}
|
|
}
|
|
filt[j*(x*n+1)] = (unsigned char) filter_type;
|
|
STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n);
|
|
}
|
|
STBIW_FREE(line_buffer);
|
|
zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8);
|
|
STBIW_FREE(filt);
|
|
if (!zlib) return 0;
|
|
|
|
out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12);
|
|
if (!out) return 0;
|
|
*out_len = 8 + 12+13 + 12+zlen + 12;
|
|
|
|
o=out;
|
|
STBIW_MEMMOVE(o,sig,8); o+= 8;
|
|
stbiw__wp32(o, 13);
|
|
stbiw__wptag(o, "IHDR");
|
|
stbiw__wp32(o, x);
|
|
stbiw__wp32(o, y);
|
|
*o++ = 8;
|
|
*o++ = STBIW_UCHAR(ctype[n]);
|
|
*o++ = 0;
|
|
*o++ = 0;
|
|
*o++ = 0;
|
|
stbiw__wpcrc(&o,13);
|
|
|
|
stbiw__wp32(o, zlen);
|
|
stbiw__wptag(o, "IDAT");
|
|
STBIW_MEMMOVE(o, zlib, zlen);
|
|
o += zlen;
|
|
STBIW_FREE(zlib);
|
|
stbiw__wpcrc(&o, zlen);
|
|
|
|
stbiw__wp32(o,0);
|
|
stbiw__wptag(o, "IEND");
|
|
stbiw__wpcrc(&o,0);
|
|
|
|
STBIW_ASSERT(o == out + *out_len);
|
|
|
|
return out;
|
|
}
|
|
|
|
#endif /* STB_IMAGE_IMPLEMENTATION */
|
|
|
|
#endif
|