mirror of
https://github.com/nothings/stb-imv
synced 2024-11-22 05:21:30 +03:00
verbose errors
This commit is contained in:
parent
1ea6375d82
commit
67742db7b1
2
imv.c
2
imv.c
@ -28,6 +28,8 @@
|
|||||||
|
|
||||||
#define STB_DEFINE
|
#define STB_DEFINE
|
||||||
#include "stb.h" /* http://nothings.org/stb.h */
|
#include "stb.h" /* http://nothings.org/stb.h */
|
||||||
|
|
||||||
|
#define STB_IMAGE_FAILURE_USERMSG
|
||||||
#include "stb_image.c" /* http://nothings.org/stb_image.c */
|
#include "stb_image.c" /* http://nothings.org/stb_image.c */
|
||||||
|
|
||||||
#include "resource.h"
|
#include "resource.h"
|
||||||
|
181
stb_image.c
181
stb_image.c
@ -1,10 +1,11 @@
|
|||||||
/* stbi-0.92 - public domain JPEG/PNG reader - http://nothings.org/stb_image.c
|
/* stbi-0.93 - public domain JPEG/PNG reader - http://nothings.org/stb_image.c
|
||||||
when you control the images you're loading
|
when you control the images you're loading
|
||||||
|
|
||||||
TODO:
|
TODO:
|
||||||
stbi_info_*
|
stbi_info_*
|
||||||
|
|
||||||
history:
|
history:
|
||||||
|
0.93 handle jpegtran output; verbose errors
|
||||||
0.92 read 4,8,16,24,32-bit BMP files of several formats
|
0.92 read 4,8,16,24,32-bit BMP files of several formats
|
||||||
0.91 output 24-bit Windows 3.0 BMP files
|
0.91 output 24-bit Windows 3.0 BMP files
|
||||||
0.90 fix a few more warnings; bump version number to approach 1.0
|
0.90 fix a few more warnings; bump version number to approach 1.0
|
||||||
@ -211,10 +212,14 @@ static int e(char *str)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef STB_IMAGE_NO_FAILURE_STRINGS
|
#ifdef STB_IMAGE_NO_FAILURE_STRINGS
|
||||||
#define e(x) 0
|
#define e(x,y) 0
|
||||||
|
#elif defined(STB_IMAGE_FAILURE_USERMSG)
|
||||||
|
#define e(x,y) e(y)
|
||||||
|
#else
|
||||||
|
#define e(x,y) e(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define ep(x) (e(x),NULL)
|
#define ep(x,y) (e(x,y),NULL)
|
||||||
|
|
||||||
void stbi_image_free(unsigned char *retval_from_stbi_load)
|
void stbi_image_free(unsigned char *retval_from_stbi_load)
|
||||||
{
|
{
|
||||||
@ -225,7 +230,7 @@ unsigned char *stbi_load(char *filename, int *x, int *y, int *comp, int req_comp
|
|||||||
{
|
{
|
||||||
FILE *f = fopen(filename, "rb");
|
FILE *f = fopen(filename, "rb");
|
||||||
unsigned char *result;
|
unsigned char *result;
|
||||||
if (!f) return ep("can't fopen");
|
if (!f) return ep("can't fopen", "Unable to open file");
|
||||||
result = stbi_load_from_file(f,x,y,comp,req_comp);
|
result = stbi_load_from_file(f,x,y,comp,req_comp);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return result;
|
return result;
|
||||||
@ -239,7 +244,7 @@ unsigned char *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_c
|
|||||||
return stbi_png_load_from_file(f,x,y,comp,req_comp);
|
return stbi_png_load_from_file(f,x,y,comp,req_comp);
|
||||||
if (stbi_bmp_test_file(f))
|
if (stbi_bmp_test_file(f))
|
||||||
return stbi_bmp_load_from_file(f,x,y,comp,req_comp);
|
return stbi_bmp_load_from_file(f,x,y,comp,req_comp);
|
||||||
return ep("unknown image type");
|
return ep("unknown image type", "Image not of any known type, or corrupt");
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char *stbi_load_from_memory(stbi_uc *buffer, int len, int *x, int *y, int *comp, int req_comp)
|
unsigned char *stbi_load_from_memory(stbi_uc *buffer, int len, int *x, int *y, int *comp, int req_comp)
|
||||||
@ -250,7 +255,7 @@ unsigned char *stbi_load_from_memory(stbi_uc *buffer, int len, int *x, int *y, i
|
|||||||
return stbi_png_load_from_memory(buffer,len,x,y,comp,req_comp);
|
return stbi_png_load_from_memory(buffer,len,x,y,comp,req_comp);
|
||||||
if (stbi_bmp_test_memory(buffer,len))
|
if (stbi_bmp_test_memory(buffer,len))
|
||||||
return stbi_bmp_load_from_memory(buffer,len,x,y,comp,req_comp);
|
return stbi_bmp_load_from_memory(buffer,len,x,y,comp,req_comp);
|
||||||
return ep("unknown image type");
|
return ep("unknown image type", "Image not of any known type, or corrupt");
|
||||||
}
|
}
|
||||||
|
|
||||||
// @TODO: get image dimensions & components without fully decoding
|
// @TODO: get image dimensions & components without fully decoding
|
||||||
@ -377,7 +382,7 @@ static unsigned char *convert_format(unsigned char *data, int img_n, int req_com
|
|||||||
good = (unsigned char *) malloc(req_comp * img_x * img_y);
|
good = (unsigned char *) malloc(req_comp * img_x * img_y);
|
||||||
if (good == NULL) {
|
if (good == NULL) {
|
||||||
free(data);
|
free(data);
|
||||||
return ep("outofmem");
|
return ep("outofmem", "Out of memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (j=0; j < img_y; ++j) {
|
for (j=0; j < img_y; ++j) {
|
||||||
@ -478,7 +483,7 @@ static int build_huffman(huffman *h, int *count)
|
|||||||
if (h->size[k] == j) {
|
if (h->size[k] == j) {
|
||||||
while (h->size[k] == j)
|
while (h->size[k] == j)
|
||||||
h->code[k++] = (uint16) (code++);
|
h->code[k++] = (uint16) (code++);
|
||||||
if (code-1 >= (1 << j)) return e("bad code lengths");
|
if (code-1 >= (1 << j)) return e("bad code lengths","Corrupt JPEG");
|
||||||
}
|
}
|
||||||
// compute largest code + 1 for this size, preshifted as needed later
|
// compute largest code + 1 for this size, preshifted as needed later
|
||||||
h->maxcode[j] = code << (16-j);
|
h->maxcode[j] = code << (16-j);
|
||||||
@ -634,7 +639,7 @@ static int decode_block(short data[64], huffman *hdc, huffman *hac, int b)
|
|||||||
{
|
{
|
||||||
int diff,dc,k;
|
int diff,dc,k;
|
||||||
int t = decode(hdc);
|
int t = decode(hdc);
|
||||||
if (t < 0) return e("bad huffman code");
|
if (t < 0) return e("bad huffman code","Corrupt JPEG");
|
||||||
|
|
||||||
// 0 all the ac values now so we can do it 32-bits at a time
|
// 0 all the ac values now so we can do it 32-bits at a time
|
||||||
memset(data,0,64*sizeof(data[0]));
|
memset(data,0,64*sizeof(data[0]));
|
||||||
@ -649,7 +654,7 @@ static int decode_block(short data[64], huffman *hdc, huffman *hac, int b)
|
|||||||
do {
|
do {
|
||||||
int r,s;
|
int r,s;
|
||||||
int rs = decode(hac);
|
int rs = decode(hac);
|
||||||
if (rs < 0) return e("bad huffman code");
|
if (rs < 0) return e("bad huffman code","Corrupt JPEG");
|
||||||
s = rs & 15;
|
s = rs & 15;
|
||||||
r = rs >> 4;
|
r = rs >> 4;
|
||||||
if (s == 0) {
|
if (s == 0) {
|
||||||
@ -881,13 +886,13 @@ static int process_marker(int m)
|
|||||||
int L;
|
int L;
|
||||||
switch (m) {
|
switch (m) {
|
||||||
case MARKER_none: // no marker found
|
case MARKER_none: // no marker found
|
||||||
return e("expected marker");
|
return e("expected marker","Corrupt JPEG");
|
||||||
|
|
||||||
case 0xC2: // SOF - progressive
|
case 0xC2: // SOF - progressive
|
||||||
return e("progressive jpeg");
|
return e("progressive jpeg","JPEG format not supported (progressive)");
|
||||||
|
|
||||||
case 0xDD: // DRI - specify restart interval
|
case 0xDD: // DRI - specify restart interval
|
||||||
if (get16() != 4) return e("bad DRI len");
|
if (get16() != 4) return e("bad DRI len","Corrupt JPEG");
|
||||||
restart_interval = get16();
|
restart_interval = get16();
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
@ -897,8 +902,8 @@ static int process_marker(int m)
|
|||||||
int z = get8();
|
int z = get8();
|
||||||
int p = z >> 4;
|
int p = z >> 4;
|
||||||
int t = z & 15,i;
|
int t = z & 15,i;
|
||||||
if (p != 0) return e("bad DQT type");
|
if (p != 0) return e("bad DQT type","Corrupt JPEG");
|
||||||
if (t > 3) return e("bad DQT table");
|
if (t > 3) return e("bad DQT table","Corrupt JPEG");
|
||||||
for (i=0; i < 64; ++i)
|
for (i=0; i < 64; ++i)
|
||||||
dequant[t][dezigzag[i]] = get8u();
|
dequant[t][dezigzag[i]] = get8u();
|
||||||
L -= 65;
|
L -= 65;
|
||||||
@ -913,7 +918,7 @@ static int process_marker(int m)
|
|||||||
int z = get8();
|
int z = get8();
|
||||||
int tc = z >> 4;
|
int tc = z >> 4;
|
||||||
int th = z & 15;
|
int th = z & 15;
|
||||||
if (tc > 1 || th > 3) return e("bad DHT header");
|
if (tc > 1 || th > 3) return e("bad DHT header","Corrupt JPEG");
|
||||||
for (i=0; i < 16; ++i) {
|
for (i=0; i < 16; ++i) {
|
||||||
sizes[i] = get8();
|
sizes[i] = get8();
|
||||||
m += sizes[i];
|
m += sizes[i];
|
||||||
@ -946,8 +951,8 @@ static int process_scan_header(void)
|
|||||||
int i;
|
int i;
|
||||||
int Ls = get16();
|
int Ls = get16();
|
||||||
scan_n = get8();
|
scan_n = get8();
|
||||||
if (scan_n < 1 || scan_n > 4 || scan_n > (int) img_n) return e("bad SOS component count");
|
if (scan_n < 1 || scan_n > 4 || scan_n > (int) img_n) return e("bad SOS component count","Corrupt JPEG");
|
||||||
if (Ls != 6+2*scan_n) return e("bad SOS len");
|
if (Ls != 6+2*scan_n) return e("bad SOS len","Corrupt JPEG");
|
||||||
for (i=0; i < scan_n; ++i) {
|
for (i=0; i < scan_n; ++i) {
|
||||||
int id = get8(), which;
|
int id = get8(), which;
|
||||||
int z = get8();
|
int z = get8();
|
||||||
@ -955,13 +960,13 @@ static int process_scan_header(void)
|
|||||||
if (img_comp[which].id == id)
|
if (img_comp[which].id == id)
|
||||||
break;
|
break;
|
||||||
if (which == img_n) return 0;
|
if (which == img_n) return 0;
|
||||||
img_comp[which].hd = z >> 4; if (img_comp[which].hd > 3) return e("bad DC huff");
|
img_comp[which].hd = z >> 4; if (img_comp[which].hd > 3) return e("bad DC huff","Corrupt JPEG");
|
||||||
img_comp[which].ha = z & 15; if (img_comp[which].ha > 3) return e("bad AC huff");
|
img_comp[which].ha = z & 15; if (img_comp[which].ha > 3) return e("bad AC huff","Corrupt JPEG");
|
||||||
order[i] = which;
|
order[i] = which;
|
||||||
}
|
}
|
||||||
if (get8() != 0) return e("bad SOS");
|
if (get8() != 0) return e("bad SOS","Corrupt JPEG");
|
||||||
get8(); // should be 63, but might be 0
|
get8(); // should be 63, but might be 0
|
||||||
if (get8() != 0) return e("bad SOS");
|
if (get8() != 0) return e("bad SOS","Corrupt JPEG");
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -969,24 +974,24 @@ static int process_scan_header(void)
|
|||||||
static int process_frame_header(int scan)
|
static int process_frame_header(int scan)
|
||||||
{
|
{
|
||||||
int Lf,p,i,z, h_max=1,v_max=1;
|
int Lf,p,i,z, h_max=1,v_max=1;
|
||||||
Lf = get16(); if (Lf < 11) return e("bad SOF len"); // JPEG
|
Lf = get16(); if (Lf < 11) return e("bad SOF len","Corrupt JPEG"); // JPEG
|
||||||
p = get8(); if (p != 8) return e("only 8-bit"); // JPEG baseline
|
p = get8(); if (p != 8) return e("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline
|
||||||
img_y = get16(); if (img_y == 0) return e("no header height"); // Legal, but we don't handle it!
|
img_y = get16(); if (img_y == 0) return e("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG
|
||||||
img_x = get16(); if (img_x == 0) return e("0 width"); // JPEG requires
|
img_x = get16(); if (img_x == 0) return e("0 width","Corrupt JPEG"); // JPEG requires
|
||||||
img_n = get8();
|
img_n = get8();
|
||||||
if (img_n != 3 && img_n != 1) return e("bad component count"); // JFIF requires
|
if (img_n != 3 && img_n != 1) return e("bad component count","Corrupt JPEG"); // JFIF requires
|
||||||
|
|
||||||
if (Lf != 8+3*img_n) return e("bad SOF len");
|
if (Lf != 8+3*img_n) return e("bad SOF len","Corrupt JPEG");
|
||||||
|
|
||||||
for (i=0; i < img_n; ++i) {
|
for (i=0; i < img_n; ++i) {
|
||||||
img_comp[i].id = get8();
|
img_comp[i].id = get8();
|
||||||
if (img_comp[i].id != i+1) // JFIF requires
|
if (img_comp[i].id != i+1) // JFIF requires
|
||||||
if (img_comp[i].id != i) // jpegtran outputs non-JFIF-compliant files!
|
if (img_comp[i].id != i) // jpegtran outputs non-JFIF-compliant files!
|
||||||
return e("bad component ID");
|
return e("bad component ID","Corrupt JPEG");
|
||||||
z = get8();
|
z = get8();
|
||||||
img_comp[i].h = (z >> 4); if (!img_comp[i].h || img_comp[i].h > 4) return e("bad H");
|
img_comp[i].h = (z >> 4); if (!img_comp[i].h || img_comp[i].h > 4) return e("bad H","Corrupt JPEG");
|
||||||
img_comp[i].v = z & 15; if (!img_comp[i].h || img_comp[i].h > 4) return e("bad V");
|
img_comp[i].v = z & 15; if (!img_comp[i].h || img_comp[i].h > 4) return e("bad V","Corrupt JPEG");
|
||||||
img_comp[i].tq = get8(); if (img_comp[i].tq > 3) return e("bad TQ");
|
img_comp[i].tq = get8(); if (img_comp[i].tq > 3) return e("bad TQ","Corrupt JPEG");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scan != SCAN_load) return 1;
|
if (scan != SCAN_load) return 1;
|
||||||
@ -1032,7 +1037,7 @@ static int decode_jpeg_header(int scan)
|
|||||||
int m;
|
int m;
|
||||||
marker = MARKER_none; // initialize cached marker to empty
|
marker = MARKER_none; // initialize cached marker to empty
|
||||||
m = get_marker();
|
m = get_marker();
|
||||||
if (!SOI(m)) return e("no SOI");
|
if (!SOI(m)) return e("no SOI","Corrupt JPEG");
|
||||||
if (scan == SCAN_type) return 1;
|
if (scan == SCAN_type) return 1;
|
||||||
m = get_marker();
|
m = get_marker();
|
||||||
while (!SOF(m)) {
|
while (!SOF(m)) {
|
||||||
@ -1199,7 +1204,7 @@ static uint8 *load_jpeg_image(int *out_x, int *out_y, int *comp, int req_comp)
|
|||||||
{
|
{
|
||||||
int i, n;
|
int i, n;
|
||||||
// validate req_comp
|
// validate req_comp
|
||||||
if (req_comp < 0 || req_comp > 4) return ep("bad req_comp");
|
if (req_comp < 0 || req_comp > 4) return ep("bad req_comp", "Internal error");
|
||||||
|
|
||||||
// load a jpeg image from whichever source
|
// load a jpeg image from whichever source
|
||||||
if (!decode_jpeg_image()) { cleanup_jpeg(); return NULL; }
|
if (!decode_jpeg_image()) { cleanup_jpeg(); return NULL; }
|
||||||
@ -1235,7 +1240,7 @@ static uint8 *load_jpeg_image(int *out_x, int *out_y, int *comp, int req_comp)
|
|||||||
// @TODO resample uncommon sampling pattern with nearest neighbor
|
// @TODO resample uncommon sampling pattern with nearest neighbor
|
||||||
free(new_data);
|
free(new_data);
|
||||||
cleanup_jpeg();
|
cleanup_jpeg();
|
||||||
return ep("uncommon H or V");
|
return ep("uncommon H or V", "JPEG not supported: atypical downsampling mode");
|
||||||
}
|
}
|
||||||
img_comp[i].w2 = stride;
|
img_comp[i].w2 = stride;
|
||||||
free(img_comp[i].data);
|
free(img_comp[i].data);
|
||||||
@ -1384,7 +1389,7 @@ static int zbuild_huffman(zhuffman *z, uint8 *sizelist, int num)
|
|||||||
z->firstsymbol[i] = (uint16) k;
|
z->firstsymbol[i] = (uint16) k;
|
||||||
code = (code + sizes[i]);
|
code = (code + sizes[i]);
|
||||||
if (sizes[i])
|
if (sizes[i])
|
||||||
if (code-1 >= (1 << i)) return e("bad codelengths");
|
if (code-1 >= (1 << i)) return e("bad codelengths","Corrupt JPEG");
|
||||||
z->maxcode[i] = code << (16-i); // preshift for inner loop
|
z->maxcode[i] = code << (16-i); // preshift for inner loop
|
||||||
code <<= 1;
|
code <<= 1;
|
||||||
k += sizes[i];
|
k += sizes[i];
|
||||||
@ -1481,13 +1486,13 @@ static int expand(int n) // need to make room for n bytes
|
|||||||
{
|
{
|
||||||
char *q;
|
char *q;
|
||||||
int cur, limit;
|
int cur, limit;
|
||||||
if (!z_expandable) return e("output buffer limit");
|
if (!z_expandable) return e("output buffer limit","Corrupt PNG");
|
||||||
cur = (int) (zout - zout_start);
|
cur = (int) (zout - zout_start);
|
||||||
limit = (int) (zout_end - zout_start);
|
limit = (int) (zout_end - zout_start);
|
||||||
while (cur + n > limit)
|
while (cur + n > limit)
|
||||||
limit *= 2;
|
limit *= 2;
|
||||||
q = (char *) realloc(zout_start, limit);
|
q = (char *) realloc(zout_start, limit);
|
||||||
if (q == NULL) return e("outofmem");
|
if (q == NULL) return e("outofmem", "Out of memory");
|
||||||
zout_start = q;
|
zout_start = q;
|
||||||
zout = q + cur;
|
zout = q + cur;
|
||||||
zout_end = q + limit;
|
zout_end = q + limit;
|
||||||
@ -1515,7 +1520,7 @@ static int parse_huffman_block(void)
|
|||||||
for(;;) {
|
for(;;) {
|
||||||
int z = zhuffman_decode(&z_length);
|
int z = zhuffman_decode(&z_length);
|
||||||
if (z < 256) {
|
if (z < 256) {
|
||||||
if (z < 0) return e("bad huffman code"); // error in huffman codes
|
if (z < 0) return e("bad huffman code","Corrupt PNG"); // error in huffman codes
|
||||||
if (zout >= zout_end) if (!expand(1)) return 0;
|
if (zout >= zout_end) if (!expand(1)) return 0;
|
||||||
*zout++ = (char) z;
|
*zout++ = (char) z;
|
||||||
} else {
|
} else {
|
||||||
@ -1526,10 +1531,10 @@ static int parse_huffman_block(void)
|
|||||||
len = length_base[z];
|
len = length_base[z];
|
||||||
if (length_extra[z]) len += zreceive(length_extra[z]);
|
if (length_extra[z]) len += zreceive(length_extra[z]);
|
||||||
z = zhuffman_decode(&z_distance);
|
z = zhuffman_decode(&z_distance);
|
||||||
if (z < 0) return e("bad huffman code");
|
if (z < 0) return e("bad huffman code","Corrupt PNG");
|
||||||
dist = dist_base[z];
|
dist = dist_base[z];
|
||||||
if (dist_extra[z]) dist += zreceive(dist_extra[z]);
|
if (dist_extra[z]) dist += zreceive(dist_extra[z]);
|
||||||
if (zout - zout_start < dist) return e("bad dist");
|
if (zout - zout_start < dist) return e("bad dist","Corrupt PNG");
|
||||||
if (zout + len > zout_end) if (!expand(len)) return 0;
|
if (zout + len > zout_end) if (!expand(len)) return 0;
|
||||||
p = (uint8 *) (zout - dist);
|
p = (uint8 *) (zout - dist);
|
||||||
while (len--)
|
while (len--)
|
||||||
@ -1578,7 +1583,7 @@ static int compute_huffman_codes(void)
|
|||||||
n += c;
|
n += c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (n != hlit+hdist) return e("bad codelengths");
|
if (n != hlit+hdist) return e("bad codelengths","Corrupt PNG");
|
||||||
if (!zbuild_huffman(&z_length, lencodes, hlit)) return 0;
|
if (!zbuild_huffman(&z_length, lencodes, hlit)) return 0;
|
||||||
if (!zbuild_huffman(&z_distance, lencodes+hlit, hdist)) return 0;
|
if (!zbuild_huffman(&z_distance, lencodes+hlit, hdist)) return 0;
|
||||||
return 1;
|
return 1;
|
||||||
@ -1603,8 +1608,8 @@ static int parse_uncompressed_block(void)
|
|||||||
header[k++] = (uint8) zget8();
|
header[k++] = (uint8) zget8();
|
||||||
len = header[1] * 256 + header[0];
|
len = header[1] * 256 + header[0];
|
||||||
nlen = header[3] * 256 + header[2];
|
nlen = header[3] * 256 + header[2];
|
||||||
if (nlen != (len ^ 0xffff)) return e("zlib corrupt");
|
if (nlen != (len ^ 0xffff)) return e("zlib corrupt","Corrupt PNG");
|
||||||
if (zbuffer + len > zbuffer_end) return e("read past buffer");
|
if (zbuffer + len > zbuffer_end) return e("read past buffer","Corrupt PNG");
|
||||||
if (zout + len > zout_end)
|
if (zout + len > zout_end)
|
||||||
if (!expand(len)) return 0;
|
if (!expand(len)) return 0;
|
||||||
memcpy(zout, zbuffer, len);
|
memcpy(zout, zbuffer, len);
|
||||||
@ -1619,9 +1624,9 @@ static int parse_zlib_header(void)
|
|||||||
int cm = cmf & 15;
|
int cm = cmf & 15;
|
||||||
/* int cinfo = cmf >> 4; */
|
/* int cinfo = cmf >> 4; */
|
||||||
int flg = zget8();
|
int flg = zget8();
|
||||||
if ((cmf*256+flg) % 31 != 0) return e("bad zlib header"); // zlib spec
|
if ((cmf*256+flg) % 31 != 0) return e("bad zlib header","Corrupt PNG"); // zlib spec
|
||||||
if (flg & 32) return e("no preset dict"); // preset dictionary not allowed in png
|
if (flg & 32) return e("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png
|
||||||
if (cm != 8) return e("bad compression"); // DEFLATE required for png
|
if (cm != 8) return e("bad compression","Corrupt PNG"); // DEFLATE required for png
|
||||||
// window = 1 << (8 + cinfo)... but who cares, we fully buffer output
|
// window = 1 << (8 + cinfo)... but who cares, we fully buffer output
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -1737,7 +1742,7 @@ static int check_png_header(void)
|
|||||||
static uint8 png_sig[8] = { 137,80,78,71,13,10,26,10 };
|
static uint8 png_sig[8] = { 137,80,78,71,13,10,26,10 };
|
||||||
int i;
|
int i;
|
||||||
for (i=0; i < 8; ++i)
|
for (i=0; i < 8; ++i)
|
||||||
if (get8() != png_sig[i]) return e("bad png sig");
|
if (get8() != png_sig[i]) return e("bad png sig","Not a PNG");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1771,13 +1776,13 @@ static int create_png_image(uint8 *raw, uint32 raw_len, int out_n)
|
|||||||
int k;
|
int k;
|
||||||
assert(out_n == img_n || out_n == img_n+1);
|
assert(out_n == img_n || out_n == img_n+1);
|
||||||
out = (uint8 *) malloc(img_x * img_y * out_n);
|
out = (uint8 *) malloc(img_x * img_y * out_n);
|
||||||
if (!out) return e("outofmem");
|
if (!out) return e("outofmem", "Out of memory");
|
||||||
if (raw_len != (img_n * img_x + 1) * img_y) return e("not enough pixels");
|
if (raw_len != (img_n * img_x + 1) * img_y) return e("not enough pixels","Corrupt PNG");
|
||||||
for (j=0; j < img_y; ++j) {
|
for (j=0; j < img_y; ++j) {
|
||||||
uint8 *cur = out + stride*j;
|
uint8 *cur = out + stride*j;
|
||||||
uint8 *prior = cur - stride;
|
uint8 *prior = cur - stride;
|
||||||
int filter = *raw++;
|
int filter = *raw++;
|
||||||
if (filter > 4) return e("invalid filter");
|
if (filter > 4) return e("invalid filter","Corrupt PNG");
|
||||||
// if first row, use special filter that doesn't sample previous row
|
// if first row, use special filter that doesn't sample previous row
|
||||||
if (j == 0) filter = first_row_filter[filter];
|
if (j == 0) filter = first_row_filter[filter];
|
||||||
// handle first pixel explicitly
|
// handle first pixel explicitly
|
||||||
@ -1864,7 +1869,7 @@ static int expand_palette(uint8 *palette, int len, int pal_img_n)
|
|||||||
uint8 *p, *temp_out, *orig = out;
|
uint8 *p, *temp_out, *orig = out;
|
||||||
|
|
||||||
p = (uint8 *) malloc(pixel_count * pal_img_n);
|
p = (uint8 *) malloc(pixel_count * pal_img_n);
|
||||||
if (p == NULL) return e("outofmem");
|
if (p == NULL) return e("outofmem", "Out of memory");
|
||||||
|
|
||||||
// between here and free(out) below, exitting would leak
|
// between here and free(out) below, exitting would leak
|
||||||
temp_out = p;
|
temp_out = p;
|
||||||
@ -1899,46 +1904,46 @@ static int parse_png_file(int scan, int req_comp)
|
|||||||
uint32 ioff=0, idata_limit=0, i, pal_len=0;
|
uint32 ioff=0, idata_limit=0, i, pal_len=0;
|
||||||
int first=1,k;
|
int first=1,k;
|
||||||
|
|
||||||
if (!check_png_header()) return e("not png");
|
if (!check_png_header()) return 0;
|
||||||
|
|
||||||
if (scan == SCAN_type) return 1;
|
if (scan == SCAN_type) return 1;
|
||||||
|
|
||||||
for(;;first=0) {
|
for(;;first=0) {
|
||||||
chunk c = get_chunk_header();
|
chunk c = get_chunk_header();
|
||||||
if (first && c.type != PNG_TYPE('I','H','D','R'))
|
if (first && c.type != PNG_TYPE('I','H','D','R'))
|
||||||
return e("first not IHDR");
|
return e("first not IHDR","Corrupt PNG");
|
||||||
switch (c.type) {
|
switch (c.type) {
|
||||||
case PNG_TYPE('I','H','D','R'): {
|
case PNG_TYPE('I','H','D','R'): {
|
||||||
int depth,color,interlace,comp,filter;
|
int depth,color,interlace,comp,filter;
|
||||||
if (!first) return e("multiple IHDR");
|
if (!first) return e("multiple IHDR","Corrupt PNG");
|
||||||
if (c.length != 13) return e("bad IHDR len");
|
if (c.length != 13) return e("bad IHDR len","Corrupt PNG");
|
||||||
img_x = get32(); if (img_x > (1 << 24)) return e("too large");
|
img_x = get32(); if (img_x > (1 << 24)) return e("too large","Corrupt PNG");
|
||||||
img_y = get32(); if (img_y > (1 << 24)) return e("too large");
|
img_y = get32(); if (img_y > (1 << 24)) return e("too large","Corrupt PNG");
|
||||||
depth = get8(); if (depth != 8) return e("8bit only");
|
depth = get8(); if (depth != 8) return e("8bit only","PNG not supported: 8-bit only");
|
||||||
color = get8(); if (color > 6) return e("bad ctype");
|
color = get8(); if (color > 6) return e("bad ctype","Corrupt PNG");
|
||||||
if (color == 3) pal_img_n = 3; else if (color & 1) return e("bad ctype");
|
if (color == 3) pal_img_n = 3; else if (color & 1) return e("bad ctype","Corrupt PNG");
|
||||||
comp = get8(); if (comp) return e("bad comp method");
|
comp = get8(); if (comp) return e("bad comp method","Corrupt PNG");
|
||||||
filter= get8(); if (filter) return e("bad filter method");
|
filter= get8(); if (filter) return e("bad filter method","Corrupt PNG");
|
||||||
interlace = get8(); if (interlace) return e("interlaced");
|
interlace = get8(); if (interlace) return e("interlaced","PNG not supported: interlaced mode");
|
||||||
if (!img_x || !img_y) return e("0-pixel image");
|
if (!img_x || !img_y) return e("0-pixel image","Corrupt PNG");
|
||||||
if (!pal_img_n) {
|
if (!pal_img_n) {
|
||||||
img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0);
|
img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0);
|
||||||
if ((1 << 30) / img_x / img_n < img_y) return e("too large");
|
if ((1 << 30) / img_x / img_n < img_y) return e("too large", "Corrupt PNG");
|
||||||
if (scan == SCAN_header) return 1;
|
if (scan == SCAN_header) return 1;
|
||||||
} else {
|
} else {
|
||||||
// if paletted, then pal_n is our final components, and
|
// if paletted, then pal_n is our final components, and
|
||||||
// img_n is # components to decompress/filter.
|
// img_n is # components to decompress/filter.
|
||||||
img_n = 1;
|
img_n = 1;
|
||||||
if ((1 << 30) / img_x / 4 < img_y) return e("too large");
|
if ((1 << 30) / img_x / 4 < img_y) return e("too large","Corrupt PNG");
|
||||||
// if SCAN_header, have to scan to see if we have a tRNS
|
// if SCAN_header, have to scan to see if we have a tRNS
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case PNG_TYPE('P','L','T','E'): {
|
case PNG_TYPE('P','L','T','E'): {
|
||||||
if (c.length > 256*3) return e("invalid PLTE");
|
if (c.length > 256*3) return e("invalid PLTE","Corrupt PNG");
|
||||||
pal_len = c.length / 3;
|
pal_len = c.length / 3;
|
||||||
if (pal_len * 3 != c.length) return e("invalid PLTE");
|
if (pal_len * 3 != c.length) return e("invalid PLTE","Corrupt PNG");
|
||||||
for (i=0; i < pal_len; ++i) {
|
for (i=0; i < pal_len; ++i) {
|
||||||
palette[i*4+0] = get8u();
|
palette[i*4+0] = get8u();
|
||||||
palette[i*4+1] = get8u();
|
palette[i*4+1] = get8u();
|
||||||
@ -1949,16 +1954,16 @@ static int parse_png_file(int scan, int req_comp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
case PNG_TYPE('t','R','N','S'): {
|
case PNG_TYPE('t','R','N','S'): {
|
||||||
if (idata) return e("tRNS after IDAT");
|
if (idata) return e("tRNS after IDAT","Corrupt PNG");
|
||||||
if (pal_img_n) {
|
if (pal_img_n) {
|
||||||
if (scan == SCAN_header) { img_n = 4; return 1; }
|
if (scan == SCAN_header) { img_n = 4; return 1; }
|
||||||
if (pal_len == 0) return e("tRNS before PLTE");
|
if (pal_len == 0) return e("tRNS before PLTE","Corrupt PNG");
|
||||||
if (c.length > pal_len) return e("bad tRNS len");
|
if (c.length > pal_len) return e("bad tRNS len","Corrupt PNG");
|
||||||
for (i=0; i < c.length; ++i)
|
for (i=0; i < c.length; ++i)
|
||||||
palette[i*4+3] = get8u();
|
palette[i*4+3] = get8u();
|
||||||
} else {
|
} else {
|
||||||
if (!(img_n & 1)) return e("tRNS with alpha");
|
if (!(img_n & 1)) return e("tRNS with alpha","Corrupt PNG");
|
||||||
if (c.length != (uint32) img_n*2) return e("bad tRNS len");
|
if (c.length != (uint32) img_n*2) return e("bad tRNS len","Corrupt PNG");
|
||||||
has_trans = 1;
|
has_trans = 1;
|
||||||
for (k=0; k < img_n; ++k)
|
for (k=0; k < img_n; ++k)
|
||||||
tc[k] = (uint8) get16(); // non 8-bit images will be larger
|
tc[k] = (uint8) get16(); // non 8-bit images will be larger
|
||||||
@ -1967,18 +1972,18 @@ static int parse_png_file(int scan, int req_comp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
case PNG_TYPE('I','D','A','T'): {
|
case PNG_TYPE('I','D','A','T'): {
|
||||||
if (pal_img_n && !pal_len) return e("no PLTE");
|
if (pal_img_n && !pal_len) return e("no PLTE","Corrupt PNG");
|
||||||
if (scan == SCAN_header) { img_n = pal_img_n; return 1; }
|
if (scan == SCAN_header) { img_n = pal_img_n; return 1; }
|
||||||
if (ioff + c.length > idata_limit) {
|
if (ioff + c.length > idata_limit) {
|
||||||
uint8 *p;
|
uint8 *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 = (uint8 *) realloc(idata, idata_limit); if (p == NULL) return e("outofmem");
|
p = (uint8 *) realloc(idata, idata_limit); if (p == NULL) return e("outofmem", "Out of memory");
|
||||||
idata = p;
|
idata = p;
|
||||||
}
|
}
|
||||||
if (img_file) {
|
if (img_file) {
|
||||||
if (fread(idata+ioff,1,c.length,img_file) != c.length) return e("outofdata");
|
if (fread(idata+ioff,1,c.length,img_file) != c.length) return e("outofdata","Corrupt PNG");
|
||||||
} else {
|
} else {
|
||||||
memcpy(idata+ioff, img_buffer, c.length);
|
memcpy(idata+ioff, img_buffer, c.length);
|
||||||
img_buffer += c.length;
|
img_buffer += c.length;
|
||||||
@ -1990,7 +1995,7 @@ static int parse_png_file(int scan, int req_comp)
|
|||||||
case PNG_TYPE('I','E','N','D'): {
|
case PNG_TYPE('I','E','N','D'): {
|
||||||
uint32 raw_len;
|
uint32 raw_len;
|
||||||
if (scan != SCAN_load) return 1;
|
if (scan != SCAN_load) return 1;
|
||||||
if (idata == NULL) return e("no IDAT");
|
if (idata == NULL) return e("no IDAT","Corrupt PNG");
|
||||||
expanded = (uint8 *) stbi_zlib_decode_malloc((char *) idata, ioff, (int *) &raw_len);
|
expanded = (uint8 *) stbi_zlib_decode_malloc((char *) idata, ioff, (int *) &raw_len);
|
||||||
if (expanded == NULL) return 0; // zlib should set error
|
if (expanded == NULL) return 0; // zlib should set error
|
||||||
free(idata); idata = NULL;
|
free(idata); idata = NULL;
|
||||||
@ -2023,7 +2028,7 @@ static int parse_png_file(int scan, int req_comp)
|
|||||||
invalid_chunk[2] = (uint8) (c.type >> 8);
|
invalid_chunk[2] = (uint8) (c.type >> 8);
|
||||||
invalid_chunk[3] = (uint8) (c.type >> 0);
|
invalid_chunk[3] = (uint8) (c.type >> 0);
|
||||||
#endif
|
#endif
|
||||||
return e(invalid_chunk);
|
return e(invalid_chunk, "PNG not supported: unknown chunk type");
|
||||||
}
|
}
|
||||||
skip(c.length);
|
skip(c.length);
|
||||||
break;
|
break;
|
||||||
@ -2036,7 +2041,7 @@ static int parse_png_file(int scan, int req_comp)
|
|||||||
static unsigned char *do_png(int *x, int *y, int *n, int req_comp)
|
static unsigned char *do_png(int *x, int *y, int *n, int req_comp)
|
||||||
{
|
{
|
||||||
unsigned char *result=NULL;
|
unsigned char *result=NULL;
|
||||||
if (req_comp < 0 || req_comp > 4) return ep("bad req_comp");
|
if (req_comp < 0 || req_comp > 4) return ep("bad req_comp", "Internal error");
|
||||||
if (parse_png_file(SCAN_load, req_comp)) {
|
if (parse_png_file(SCAN_load, req_comp)) {
|
||||||
result = out;
|
result = out;
|
||||||
out = NULL;
|
out = NULL;
|
||||||
@ -2177,19 +2182,19 @@ static stbi_uc *bmp_load(int *x, int *y, int *comp, int req_comp)
|
|||||||
stbi_uc pal[256][4];
|
stbi_uc pal[256][4];
|
||||||
int psize=0,i,j,compress=0,width;
|
int psize=0,i,j,compress=0,width;
|
||||||
int bpp, flip_vertically, pad, target, offset, hsz;
|
int bpp, flip_vertically, pad, target, offset, hsz;
|
||||||
if (get8() != 'B' || get8() != 'M') return ep("not BMP");
|
if (get8() != 'B' || get8() != 'M') return ep("not BMP", "Corrupt BMP");
|
||||||
get32le(); // discard filesize
|
get32le(); // discard filesize
|
||||||
get16le(); // discard reserved
|
get16le(); // discard reserved
|
||||||
get16le(); // discard reserved
|
get16le(); // discard reserved
|
||||||
offset = get32le();
|
offset = get32le();
|
||||||
hsz = get32le();
|
hsz = get32le();
|
||||||
if (hsz != 12 && hsz != 40 && hsz != 108) return ep("unknown BMP");
|
if (hsz != 12 && hsz != 40 && hsz != 108) return ep("unknown BMP", "BMP type not supported: unknown");
|
||||||
failure_reason = "bad BMP";
|
failure_reason = "bad BMP";
|
||||||
img_x = get32le();
|
img_x = get32le();
|
||||||
img_y = get32le();
|
img_y = get32le();
|
||||||
if (get16le() != 1) return 0;
|
if (get16le() != 1) return 0;
|
||||||
bpp = get16le();
|
bpp = get16le();
|
||||||
if (bpp == 1) return ep("monochrome");
|
if (bpp == 1) return ep("monochrome", "BMP type not supported: 1-bit");
|
||||||
flip_vertically = img_y > 0;
|
flip_vertically = img_y > 0;
|
||||||
img_y = abs(img_y);
|
img_y = abs(img_y);
|
||||||
if (hsz == 12) {
|
if (hsz == 12) {
|
||||||
@ -2197,7 +2202,7 @@ static stbi_uc *bmp_load(int *x, int *y, int *comp, int req_comp)
|
|||||||
psize = (offset - 14 - 24) / 3;
|
psize = (offset - 14 - 24) / 3;
|
||||||
} else {
|
} else {
|
||||||
compress = get32();
|
compress = get32();
|
||||||
if (compress == 1 || compress == 2) return ep("BMP RLE");
|
if (compress == 1 || compress == 2) return ep("BMP RLE", "BMP type not supported: RLE");
|
||||||
get32le(); // discard sizeof
|
get32le(); // discard sizeof
|
||||||
get32le(); // discard hres
|
get32le(); // discard hres
|
||||||
get32le(); // discard vres
|
get32le(); // discard vres
|
||||||
@ -2241,10 +2246,10 @@ static stbi_uc *bmp_load(int *x, int *y, int *comp, int req_comp)
|
|||||||
else
|
else
|
||||||
target = img_n; // if they want monochrome, we'll post-convert
|
target = img_n; // if they want monochrome, we'll post-convert
|
||||||
out = (stbi_uc *) malloc(target * img_x * img_y);
|
out = (stbi_uc *) malloc(target * img_x * img_y);
|
||||||
if (!out) return ep("outofmem");
|
if (!out) return ep("outofmem", "Out of memory");
|
||||||
if (bpp < 16) {
|
if (bpp < 16) {
|
||||||
int z=0;
|
int z=0;
|
||||||
if (psize == 0 || psize > 256) return ep("invalid");
|
if (psize == 0 || psize > 256) return ep("invalid", "Corrupt BMP");
|
||||||
for (i=0; i < psize; ++i) {
|
for (i=0; i < psize; ++i) {
|
||||||
pal[i][2] = get8();
|
pal[i][2] = get8();
|
||||||
pal[i][1] = get8();
|
pal[i][1] = get8();
|
||||||
@ -2255,7 +2260,7 @@ static stbi_uc *bmp_load(int *x, int *y, int *comp, int req_comp)
|
|||||||
skip(offset - 14 - hsz - psize * (hsz == 12 ? 3 : 4));
|
skip(offset - 14 - hsz - psize * (hsz == 12 ? 3 : 4));
|
||||||
if (bpp == 4) width = (img_x + 1) >> 1;
|
if (bpp == 4) width = (img_x + 1) >> 1;
|
||||||
else if (bpp == 8) width = img_x;
|
else if (bpp == 8) width = img_x;
|
||||||
else return ep("bad bpp");
|
else return ep("bad bpp", "Corrupt BMP");
|
||||||
pad = (-width)&3;
|
pad = (-width)&3;
|
||||||
for (j=0; j < (int) img_y; ++j) {
|
for (j=0; j < (int) img_y; ++j) {
|
||||||
for (i=0; i < (int) img_x; i += 2) {
|
for (i=0; i < (int) img_x; i += 2) {
|
||||||
@ -2293,7 +2298,7 @@ static stbi_uc *bmp_load(int *x, int *y, int *comp, int req_comp)
|
|||||||
easy = 2;
|
easy = 2;
|
||||||
}
|
}
|
||||||
if (!easy) {
|
if (!easy) {
|
||||||
if (!mr || !mg || !mb) return ep("bad masks");
|
if (!mr || !mg || !mb) return ep("bad masks", "Corrupt BMP");
|
||||||
// right shift amt to put high bit in position #7
|
// right shift amt to put high bit in position #7
|
||||||
rshift = high_bit(mr)-7; rcount = bitcount(mr);
|
rshift = high_bit(mr)-7; rcount = bitcount(mr);
|
||||||
gshift = high_bit(mg)-7; gcount = bitcount(mr);
|
gshift = high_bit(mg)-7; gcount = bitcount(mr);
|
||||||
|
@ -41,6 +41,7 @@ RSC=rc.exe
|
|||||||
# PROP Use_Debug_Libraries 0
|
# PROP Use_Debug_Libraries 0
|
||||||
# PROP Output_Dir "Release"
|
# PROP Output_Dir "Release"
|
||||||
# PROP Intermediate_Dir "Release"
|
# PROP Intermediate_Dir "Release"
|
||||||
|
# PROP Ignore_Export_Lib 0
|
||||||
# PROP Target_Dir ""
|
# PROP Target_Dir ""
|
||||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
|
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
|
||||||
# ADD CPP /nologo /G6 /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c
|
# ADD CPP /nologo /G6 /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c
|
||||||
@ -54,7 +55,7 @@ BSC32=bscmake.exe
|
|||||||
# ADD BSC32 /nologo
|
# ADD BSC32 /nologo
|
||||||
LINK32=link.exe
|
LINK32=link.exe
|
||||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
|
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
|
||||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
|
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib advapi32.lib /nologo /subsystem:windows /machine:I386
|
||||||
|
|
||||||
!ELSEIF "$(CFG)" == "stb_imv - Win32 Debug"
|
!ELSEIF "$(CFG)" == "stb_imv - Win32 Debug"
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user