Compare commits

...

26 Commits

Author SHA1 Message Date
NRK c7e124bad2
Merge 3bf639bb3c into ae721c50ea 2024-03-19 01:10:44 -03:00
Sean Barrett ae721c50ea
Merge pull request #1609 from jeffrbig2/fix_coeffs
Fix bug in coeff gen on more than 3x downsamples with w and h equal
2024-02-12 23:49:35 -08:00
Jeff Roberts (Bellevue) 2fb057af65 remove test 2024-02-12 22:14:27 -08:00
Jeff Roberts (Bellevue) 1828f357dc Fix bug in coeff generation on more than 3x downsamples with width and height scale equal 2024-02-12 22:10:02 -08:00
Sean Barrett b7cf124628 stb_image: fix VC6 2024-02-08 13:24:06 -08:00
Jeff Roberts (Bellevue) c59da6729e Mark row0 as unused 2024-02-08 12:53:51 -08:00
Jeff Roberts (Bellevue) 7f7e3469cf clean up comments 2024-02-08 10:36:54 -08:00
Jeff Roberts (Bellevue) 7a075fe7c7 Fix 2 pixel to 1 pixel with wrap
Fix output buffer for output callback
2024-02-04 14:42:51 -08:00
Sean Barrett f4a71b1337 README.md: tweak credits 2023-12-14 10:59:23 -08:00
Sean Barrett a8a25e17b5 update readme version numbers 2023-12-14 03:13:59 -08:00
Sean Barrett 0bc88af4de stb_image: optimizations 2023-12-14 03:13:59 -08:00
Sean Barrett 0ca75da4ec stb_image_resize2: remove whitespace 2023-12-14 03:13:59 -08:00
Sean Barrett 9d924f8a47 stb_image_resize: 2.04 2023-12-14 03:13:59 -08:00
Fabian Giesen 4da08a1dbd stb_image: create_png_image_raw restructuring
Allocate filter_buf for two scan lines that we do all the filter
processing in, then do all other conversions (bit depth,
endianness, inserting alpha=255 values) on the way out.

Separating the two concerns makes everything much clearer.
2023-12-14 03:13:59 -08:00
Fabian Giesen c6d7c32e5d stb_image: Two warning fixes 2023-12-14 03:13:59 -08:00
Fabian Giesen 07268cbf36 stb_image: New Paeth filter
This formulation is equivalent to the original (reference)
implementation but runs _significantly_ faster - this speeds up
the filtering portion of a Paeth-heavy 8192x8192 16-bit/channel
image by a factor of more than 2 on a Zen2 CPU.

I'm investigating doing a more thorough restructuring of this pass,
but this seems like a good first step.
2023-12-14 03:13:59 -08:00
Fabian Giesen ed64333410 tests: test_png_regress
I want to make some changes to the PNG loader, this is to get some
test coverage at least to make it easier not to break anything.

The two ref_results files that are "corrupt" files that stb_image
nevertheless loads without error are checksum failures; this is
by design, since stb_image does not verify checksums.
2023-12-14 03:13:59 -08:00
Fabian Giesen 45eb4ac158 global: very basic .gitignore for object files 2023-12-14 03:13:59 -08:00
Fabian Giesen e5f0e18d0f stb_image: Small PNG filter simplification
Paeth on the first scanline is not a separate filter, it
happens to be equivalent to the "sub" filter which is already
an option.
2023-12-14 03:13:59 -08:00
Fabian Giesen d373674115 stb_image: Fix zlib decoder end-of-stream handling
We speculatively try to fill our bit buffer to always contain
at least 16 bits for stbi__zhuffman_decode. It's not a sign of
a malformed stream for us to be reading past the end there,
because the contents of that bit buffer are speculative; it's
only a malformed stream if we actually _consume_ the extra bits.

This fix adds some extra logic where we the first time we hit
zeof, we add an explicit 16 extra zero bits at the top of the
bit buffer just so that for the purposes of the decoder, we have
16 bits in the buffer.

However, if at the end of stream, we have the "hit zeof once"
flag set and less than 16 bits remaining in the bit buffer, we
know some of those implicit zero bits got read, which indicates
we actually had a past-end-of-stream read. In that case, flag
it as an error.

While I'm in here, also rephrase the length-too-large check to
not do any potentially-overflowing pointer arithmetic.

Fixes issue #1456.
2023-12-14 03:13:59 -08:00
Sean Barrett 03f50e343d security notice 2023-11-15 09:36:28 -08:00
Sean Barrett 1d878bd2a3 security notice 2023-11-15 09:35:21 -08:00
Sean Barrett beebb24b94 README.md: fix reference to stb_image_resize2.h 2023-10-11 17:32:00 -07:00
Sean Barrett e81f294b16 stb_image_resize: switch GNU/clang from "asm" to "__asm__" for -c99 compatibility 2023-10-11 17:28:56 -07:00
Sean Barrett c4bbb6e75f stb_image_resize2.h 2.00 2023-10-09 17:23:04 -07:00
NRK 3bf639bb3c stb_include: close file if malloc fails 2022-03-12 16:49:10 +06:00
21 changed files with 15963 additions and 198 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
*.o
*.obj
*.exe

View File

@ -5,16 +5,18 @@ stb
single-file public domain (or MIT licensed) libraries for C/C++
# This project discusses security-relevant bugs in public in Github Issues and Pull Requests, and it may take significant time for security fixes to be implemented or merged. If this poses an unreasonable risk to your project, do not use stb libraries.
Noteworthy:
* image loader: [stb_image.h](stb_image.h)
* image writer: [stb_image_write.h](stb_image_write.h)
* image resizer: [stb_image_resize.h](stb_image_resize.h)
* image resizer: [stb_image_resize2.h](stb_image_resize2.h)
* font text rasterizer: [stb_truetype.h](stb_truetype.h)
* typesafe containers: [stb_ds.h](stb_ds.h)
Most libraries by stb, except: stb_dxt by Fabian "ryg" Giesen, stb_image_resize
by Jorge L. "VinoBS" Rodriguez, and stb_sprintf by Jeff Roberts.
Most libraries by stb, except: stb_dxt by Fabian "ryg" Giesen, original stb_image_resize
by Jorge L. "VinoBS" Rodriguez, and stb_image_resize2 and stb_sprintf by Jeff Roberts.
<a name="stb_libs"></a>
@ -22,10 +24,10 @@ library | lastest version | category | LoC | description
--------------------- | ---- | -------- | --- | --------------------------------
**[stb_vorbis.c](stb_vorbis.c)** | 1.22 | audio | 5584 | decode ogg vorbis files from file/memory to float/16-bit signed output
**[stb_hexwave.h](stb_hexwave.h)** | 0.5 | audio | 680 | audio waveform synthesizer
**[stb_image.h](stb_image.h)** | 2.28 | graphics | 7987 | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC
**[stb_image.h](stb_image.h)** | 2.29 | graphics | 7985 | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC
**[stb_truetype.h](stb_truetype.h)** | 1.26 | graphics | 5077 | parse, decode, and rasterize characters from truetype fonts
**[stb_image_write.h](stb_image_write.h)** | 1.16 | graphics | 1724 | image writing to disk: PNG, TGA, BMP
**[stb_image_resize.h](stb_image_resize.h)** | 0.97 | graphics | 2634 | resize images larger/smaller with good quality
**[stb_image_resize2.h](stb_image_resize2.h)** | 2.04 | graphics | 10325 | resize images larger/smaller with good quality
**[stb_rect_pack.h](stb_rect_pack.h)** | 1.01 | graphics | 623 | simple 2D rectangle packer with decent quality
**[stb_perlin.h](stb_perlin.h)** | 0.5 | graphics | 428 | perlin's revised simplex noise w/ different seeds
**[stb_ds.h](stb_ds.h)** | 0.67 | utility | 1895 | typesafe dynamic array and hash tables for C, will compile in C++
@ -43,7 +45,7 @@ library | lastest version | category | LoC | description
**[stb_include.h](stb_include.h)** | 0.02 | misc | 295 | implement recursive #include support, particularly for GLSL
Total libraries: 21
Total lines of C code: 43117
Total lines of C code: 50806
FAQ

View File

@ -1,4 +1,4 @@
/* stb_image - v2.28 - public domain image loader - http://nothings.org/stb
/* stb_image - v2.29 - public domain image loader - http://nothings.org/stb
no warranty implied; use at your own risk
Do this:
@ -48,6 +48,7 @@ LICENSE
RECENT REVISION HISTORY:
2.29 (2023-05-xx) optimizations
2.28 (2023-01-29) many error fixes, security errors, just tons of stuff
2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes
2.26 (2020-07-13) many minor fixes
@ -1072,8 +1073,8 @@ static int stbi__addints_valid(int a, int b)
return a <= INT_MAX - b;
}
// returns 1 if the product of two signed shorts is valid, 0 on overflow.
static int stbi__mul2shorts_valid(short a, short b)
// returns 1 if the product of two ints fits in a signed short, 0 on overflow.
static int stbi__mul2shorts_valid(int a, int b)
{
if (b == 0 || b == -1) return 1; // multiplication by 0 is always 0; check for -1 so SHRT_MIN/b doesn't overflow
if ((a >= 0) == (b >= 0)) return a <= SHRT_MAX/b; // product is positive, so similar to mul2sizes_valid
@ -3384,13 +3385,13 @@ static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan)
return 1;
}
static int stbi__skip_jpeg_junk_at_end(stbi__jpeg *j)
static stbi_uc stbi__skip_jpeg_junk_at_end(stbi__jpeg *j)
{
// some JPEGs have junk at end, skip over it but if we find what looks
// like a valid marker, resume there
while (!stbi__at_eof(j->s)) {
int x = stbi__get8(j->s);
while (x == 255) { // might be a marker
stbi_uc x = stbi__get8(j->s);
while (x == 0xff) { // might be a marker
if (stbi__at_eof(j->s)) return STBI__MARKER_none;
x = stbi__get8(j->s);
if (x != 0x00 && x != 0xff) {
@ -4176,6 +4177,7 @@ typedef struct
{
stbi_uc *zbuffer, *zbuffer_end;
int num_bits;
int hit_zeof_once;
stbi__uint32 code_buffer;
char *zout;
@ -4242,9 +4244,20 @@ stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z)
int b,s;
if (a->num_bits < 16) {
if (stbi__zeof(a)) {
return -1; /* report error for unexpected end of data. */
if (!a->hit_zeof_once) {
// This is the first time we hit eof, insert 16 extra padding btis
// to allow us to keep going; if we actually consume any of them
// though, that is invalid data. This is caught later.
a->hit_zeof_once = 1;
a->num_bits += 16; // add 16 implicit zero bits
} else {
// We already inserted our extra 16 padding bits and are again
// out, this stream is actually prematurely terminated.
return -1;
}
} else {
stbi__fill_bits(a);
}
stbi__fill_bits(a);
}
b = z->fast[a->code_buffer & STBI__ZFAST_MASK];
if (b) {
@ -4309,6 +4322,13 @@ static int stbi__parse_huffman_block(stbi__zbuf *a)
int len,dist;
if (z == 256) {
a->zout = zout;
if (a->hit_zeof_once && a->num_bits < 16) {
// The first time we hit zeof, we inserted 16 extra zero bits into our bit
// buffer so the decoder can just do its speculative decoding. But if we
// actually consumed any of those bits (which is the case when num_bits < 16),
// the stream actually read past the end so it is malformed.
return stbi__err("unexpected end","Corrupt PNG");
}
return 1;
}
if (z >= 286) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, length codes 286 and 287 must not appear in compressed data
@ -4320,7 +4340,7 @@ static int stbi__parse_huffman_block(stbi__zbuf *a)
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 (len > a->zout_end - zout) {
if (!stbi__zexpand(a, zout, len)) return 0;
zout = a->zout;
}
@ -4464,6 +4484,7 @@ static int stbi__parse_zlib(stbi__zbuf *a, int parse_header)
if (!stbi__parse_zlib_header(a)) return 0;
a->num_bits = 0;
a->code_buffer = 0;
a->hit_zeof_once = 0;
do {
final = stbi__zreceive(a,1);
type = stbi__zreceive(a,2);
@ -4619,9 +4640,8 @@ enum {
STBI__F_up=2,
STBI__F_avg=3,
STBI__F_paeth=4,
// synthetic filters used for first scanline to avoid needing a dummy row of 0s
STBI__F_avg_first,
STBI__F_paeth_first
// synthetic filter used for first scanline to avoid needing a dummy row of 0s
STBI__F_avg_first
};
static stbi_uc first_row_filter[5] =
@ -4630,29 +4650,56 @@ static stbi_uc first_row_filter[5] =
STBI__F_sub,
STBI__F_none,
STBI__F_avg_first,
STBI__F_paeth_first
STBI__F_sub // Paeth with b=c=0 turns out to be equivalent to sub
};
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;
// This formulation looks very different from the reference in the PNG spec, but is
// actually equivalent and has favorable data dependencies and admits straightforward
// generation of branch-free code, which helps performance significantly.
int thresh = c*3 - (a + b);
int lo = a < b ? a : b;
int hi = a < b ? b : a;
int t0 = (hi <= thresh) ? lo : c;
int t1 = (thresh <= lo) ? hi : t0;
return t1;
}
static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 };
// adds an extra all-255 alpha channel
// dest == src is legal
// img_n must be 1 or 3
static void stbi__create_png_alpha_expand8(stbi_uc *dest, stbi_uc *src, stbi__uint32 x, int img_n)
{
int i;
// must process data backwards since we allow dest==src
if (img_n == 1) {
for (i=x-1; i >= 0; --i) {
dest[i*2+1] = 255;
dest[i*2+0] = src[i];
}
} else {
STBI_ASSERT(img_n == 3);
for (i=x-1; i >= 0; --i) {
dest[i*4+3] = 255;
dest[i*4+2] = src[i*3+2];
dest[i*4+1] = src[i*3+1];
dest[i*4+0] = src[i*3+0];
}
}
}
// create the png data from post-deflated data
static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color)
{
int bytes = (depth == 16? 2 : 1);
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;
stbi_uc *filter_buf;
int all_ok = 1;
int k;
int img_n = s->img_n; // copy it into a local for later
@ -4664,8 +4711,11 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r
a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into
if (!a->out) return stbi__err("outofmem", "Out of memory");
// note: error exits here don't need to clean up a->out individually,
// stbi__do_png always does on error.
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);
if (!stbi__mad2sizes_valid(img_width_bytes, y, img_width_bytes)) return stbi__err("too large", "Corrupt PNG");
img_len = (img_width_bytes + 1) * y;
// we used to check for exact match between raw_len and img_len on non-interlaced PNGs,
@ -4673,189 +4723,137 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r
// so just check for raw_len < img_len always.
if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG");
// Allocate two scan lines worth of filter workspace buffer.
filter_buf = (stbi_uc *) stbi__malloc_mad2(img_width_bytes, 2, 0);
if (!filter_buf) return stbi__err("outofmem", "Out of memory");
// Filtering for low-bit-depth images
if (depth < 8) {
filter_bytes = 1;
width = img_width_bytes;
}
for (j=0; j < y; ++j) {
stbi_uc *cur = a->out + stride*j;
stbi_uc *prior;
// cur/prior filter buffers alternate
stbi_uc *cur = filter_buf + (j & 1)*img_width_bytes;
stbi_uc *prior = filter_buf + (~j & 1)*img_width_bytes;
stbi_uc *dest = a->out + stride*j;
int nk = width * filter_bytes;
int filter = *raw++;
if (filter > 4)
return stbi__err("invalid filter","Corrupt PNG");
if (depth < 8) {
if (img_width_bytes > x) return stbi__err("invalid width","Corrupt PNG");
cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place
filter_bytes = 1;
width = img_width_bytes;
// check filter type
if (filter > 4) {
all_ok = stbi__err("invalid filter","Corrupt PNG");
break;
}
prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above
// if first row, use special filter that doesn't sample previous row
if (j == 0) filter = first_row_filter[filter];
// handle first byte explicitly
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;
}
// perform actual filtering
switch (filter) {
case STBI__F_none:
memcpy(cur, raw, nk);
break;
case STBI__F_sub:
memcpy(cur, raw, filter_bytes);
for (k = filter_bytes; k < nk; ++k)
cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]);
break;
case STBI__F_up:
for (k = 0; k < nk; ++k)
cur[k] = STBI__BYTECAST(raw[k] + prior[k]);
break;
case STBI__F_avg:
for (k = 0; k < filter_bytes; ++k)
cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1));
for (k = filter_bytes; k < nk; ++k)
cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1));
break;
case STBI__F_paeth:
for (k = 0; k < filter_bytes; ++k)
cur[k] = STBI__BYTECAST(raw[k] + prior[k]); // prior[k] == stbi__paeth(0,prior[k],0)
for (k = filter_bytes; k < nk; ++k)
cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes], prior[k], prior[k-filter_bytes]));
break;
case STBI__F_avg_first:
memcpy(cur, raw, filter_bytes);
for (k = filter_bytes; k < nk; ++k)
cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1));
break;
}
if (depth == 8) {
if (img_n != out_n)
cur[img_n] = 255; // first pixel
raw += img_n;
cur += out_n;
prior += out_n;
} else if (depth == 16) {
if (img_n != out_n) {
cur[filter_bytes] = 255; // first pixel top byte
cur[filter_bytes+1] = 255; // first pixel bottom byte
}
raw += filter_bytes;
cur += output_bytes;
prior += output_bytes;
} else {
raw += 1;
cur += 1;
prior += 1;
}
raw += nk;
// this is a little gross, so that we don't switch per-pixel or per-component
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) {
// "none" filter turns into a memcpy here; make that explicit.
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
// the loop above sets the high byte of the pixels' alpha, but for
// 16 bit png files we also need the low byte set. we'll do that here.
if (depth == 16) {
cur = a->out + stride*j; // start at the beginning of the row again
for (i=0; i < x; ++i,cur+=output_bytes) {
cur[filter_bytes+1] = 255;
}
}
}
}
// we make a separate pass to expand bits to pixels; for performance,
// this could run two scanlines behind the above code, so it won't
// intefere with filtering but will still be in the cache.
if (depth < 8) {
for (j=0; j < y; ++j) {
stbi_uc *cur = a->out + stride*j;
stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes;
// unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit
// png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop
// expand decoded bits in cur to dest, also adding an extra alpha channel if desired
if (depth < 8) {
stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range
stbi_uc *in = cur;
stbi_uc *out = dest;
stbi_uc inb = 0;
stbi__uint32 nsmp = x*img_n;
// note that the final byte might overshoot and write more data than desired.
// we can allocate enough data that this never writes out of memory, but it
// could also overwrite the next scanline. can it overwrite non-empty data
// on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel.
// so we need to explicitly clamp the final ones
// expand bits to bytes first
if (depth == 4) {
for (k=x*img_n; k >= 2; k-=2, ++in) {
*cur++ = scale * ((*in >> 4) );
*cur++ = scale * ((*in ) & 0x0f);
for (i=0; i < nsmp; ++i) {
if ((i & 1) == 0) inb = *in++;
*out++ = scale * (inb >> 4);
inb <<= 4;
}
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);
for (i=0; i < nsmp; ++i) {
if ((i & 3) == 0) inb = *in++;
*out++ = scale * (inb >> 6);
inb <<= 2;
}
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);
} else {
STBI_ASSERT(depth == 1);
for (i=0; i < nsmp; ++i) {
if ((i & 7) == 0) inb = *in++;
*out++ = scale * (inb >> 7);
inb <<= 1;
}
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;
// insert alpha = 255
cur = a->out + stride*j;
// insert alpha=255 values if desired
if (img_n != out_n)
stbi__create_png_alpha_expand8(dest, dest, x, img_n);
} else if (depth == 8) {
if (img_n == out_n)
memcpy(dest, cur, x*img_n);
else
stbi__create_png_alpha_expand8(dest, cur, x, img_n);
} else if (depth == 16) {
// convert the image data from big-endian to platform-native
stbi__uint16 *dest16 = (stbi__uint16*)dest;
stbi__uint32 nsmp = x*img_n;
if (img_n == out_n) {
for (i = 0; i < nsmp; ++i, ++dest16, cur += 2)
*dest16 = (cur[0] << 8) | cur[1];
} else {
STBI_ASSERT(img_n+1 == out_n);
if (img_n == 1) {
for (q=x-1; q >= 0; --q) {
cur[q*2+1] = 255;
cur[q*2+0] = cur[q];
for (i = 0; i < x; ++i, dest16 += 2, cur += 2) {
dest16[0] = (cur[0] << 8) | cur[1];
dest16[1] = 0xffff;
}
} 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];
for (i = 0; i < x; ++i, dest16 += 4, cur += 6) {
dest16[0] = (cur[0] << 8) | cur[1];
dest16[1] = (cur[2] << 8) | cur[3];
dest16[2] = (cur[4] << 8) | cur[5];
dest16[3] = 0xffff;
}
}
}
}
} else if (depth == 16) {
// force the image data from big-endian to platform-native.
// this is done in a separate pass due to the decoding relying
// on the data being untouched, but could probably be done
// per-line during decode if care is taken.
stbi_uc *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];
}
}
STBI_FREE(filter_buf);
if (!all_ok) return 0;
return 1;
}

10365
stb_image_resize2.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,224 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _MSC_VER
#define stop() __debugbreak()
#include <windows.h>
#define int64 __int64
#pragma warning(disable:4127)
#define get_milliseconds GetTickCount
#else
#define stop() __builtin_trap()
#define int64 long long
typedef unsigned int U32;
typedef unsigned long long U64;
#include <time.h>
static int get_milliseconds()
{
struct timespec ts;
clock_gettime( CLOCK_MONOTONIC, &ts );
return (U32) ( ( ((U64)(U32)ts.tv_sec) * 1000LL ) + (U64)(((U32)ts.tv_nsec+500000)/1000000) );
}
#endif
#if defined(TIME_SIMD)
// default for most platforms
#elif defined(TIME_SCALAR)
#define STBIR_NO_SIMD
#else
#error You must define TIME_SIMD or TIME_SCALAR when compiling this file.
#endif
#define STBIR_PROFILE
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#define STBIR__V_FIRST_INFO_BUFFER v_info
#include "stb_image_resize2.h" // new one!
#if defined(TIME_SIMD) && !defined(STBIR_SIMD)
#error Timing SIMD, but scalar was ON!
#endif
#if defined(TIME_SCALAR) && defined(STBIR_SIMD)
#error Timing scalar, but SIMD was ON!
#endif
#define HEADER 32
static int file_write( const char *filename, void * buffer, size_t size )
{
FILE * f = fopen( filename, "wb" );
if ( f == 0 ) return 0;
if ( fwrite( buffer, 1, size, f) != size ) return 0;
fclose(f);
return 1;
}
int64 nresize( void * o, int ox, int oy, int op, void * i, int ix, int iy, int ip, int buf, int type, int edg, int flt )
{
STBIR_RESIZE resize;
int t;
int64 b;
stbir_resize_init( &resize, i, ix, iy, ip, o, ox, oy, op, buf, type );
stbir_set_edgemodes( &resize, edg, edg );
stbir_set_filters( &resize, flt, flt );
stbir_build_samplers_with_splits( &resize, 1 );
b = 0x7fffffffffffffffULL;
for( t = 0 ; t < 16 ; t++ )
{
STBIR_PROFILE_INFO profile;
int64 v;
if(!stbir_resize_extended( &resize ) )
stop();
stbir_resize_extended_profile_info( &profile, &resize );
v = profile.clocks[1]+profile.clocks[2];
if ( v < b )
{
b = v;
t = 0;
}
}
stbir_free_samplers( &resize );
return b;
}
#define INSIZES 5
#define TYPESCOUNT 5
#define NUM 64
static const int sizes[INSIZES]={63,126,252,520,772};
static const int types[TYPESCOUNT]={STBIR_1CHANNEL,STBIR_2CHANNEL,STBIR_RGB,STBIR_4CHANNEL,STBIR_RGBA};
static const int effective[TYPESCOUNT]={1,2,3,4,7};
int main( int argc, char ** argv )
{
unsigned char * input;
unsigned char * output;
int dimensionx, dimensiony;
int scalex, scaley;
int totalms;
int timing_count;
int ir;
int * file;
int * ts;
int64 totalcycles;
if ( argc != 6 )
{
printf("command: dotimings x_samps y_samps x_scale y_scale outfilename\n");
exit(1);
}
input = malloc( 4*1200*1200 );
memset( input, 0x80, 4*1200*1200 );
output = malloc( 4*10000*10000ULL );
dimensionx = atoi( argv[1] );
dimensiony = atoi( argv[2] );
scalex = atoi( argv[3] );
scaley = atoi( argv[4] );
timing_count = dimensionx * dimensiony * INSIZES * TYPESCOUNT;
file = malloc( sizeof(int) * ( 2 * timing_count + HEADER ) );
ts = file + HEADER;
totalms = get_milliseconds();
totalcycles = STBIR_PROFILE_FUNC();
for( ir = 0 ; ir < INSIZES ; ir++ )
{
int ix, iy, ty;
ix = iy = sizes[ir];
for( ty = 0 ; ty < TYPESCOUNT ; ty++ )
{
int h, hh;
h = 1;
for( hh = 0 ; hh < dimensiony; hh++ )
{
int ww, w = 1;
for( ww = 0 ; ww < dimensionx; ww++ )
{
int64 VF, HF;
int good;
v_info.control_v_first = 2; // vertical first
VF = nresize( output, w, h, (w*4*1)&~3, input, ix, iy, ix*4*1, types[ty], STBIR_TYPE_UINT8, STBIR_EDGE_CLAMP, STBIR_FILTER_MITCHELL );
v_info.control_v_first = 1; // horizonal first
HF = nresize( output, w, h, (w*4*1)&~3, input, ix, iy, ix*4*1, types[ty], STBIR_TYPE_UINT8, STBIR_EDGE_CLAMP, STBIR_FILTER_MITCHELL );
good = ( ((HF<=VF) && (!v_info.v_first)) || ((VF<=HF) && (v_info.v_first)));
// printf("\r%d,%d, %d,%d, %d, %I64d,%I64d, // Good: %c(%c-%d) CompEst: %.1f %.1f\n", ix, iy, w, h, ty, VF, HF, good?'y':'n', v_info.v_first?'v':'h', v_info.v_resize_classification, v_info.v_cost,v_info.h_cost );
ts[0] = (int)VF;
ts[1] = (int)HF;
ts += 2;
w += scalex;
}
printf(".");
h += scaley;
}
}
}
totalms = get_milliseconds() - totalms;
totalcycles = STBIR_PROFILE_FUNC() - totalcycles;
printf("\n");
file[0] = 'VFT1';
#if defined(_x86_64) || defined( __x86_64__ ) || defined( _M_X64 ) || defined(__x86_64) || defined(__SSE2__) || defined( _M_IX86_FP ) || defined(__i386) || defined( __i386__ ) || defined( _M_IX86 ) || defined( _X86_ )
file[1] = 1; // x64
#elif defined( _M_AMD64 ) || defined( __aarch64__ ) || defined( __arm64__ ) || defined(__ARM_NEON__) || defined(__ARM_NEON) || defined(__arm__) || defined( _M_ARM )
file[1] = 2; // arm
#else
file[1] = 99; // who knows???
#endif
#ifdef STBIR_SIMD8
file[2] = 2; // simd-8
#elif defined( STBIR_SIMD )
file[2] = 1; // simd-4
#else
file[2] = 0; // nosimd
#endif
file[3] = dimensionx; // dimx
file[4] = dimensiony; // dimy
file[5] = TYPESCOUNT; // channel types
file[ 6] = types[0]; file[7] = types[1]; file[8] = types[2]; file[9] = types[3]; file[10] = types[4]; // buffer_type
file[11] = effective[0]; file[12] = effective[1]; file[13] = effective[2]; file[14] = effective[3]; file[15] = effective[4]; // effective channels
file[16] = INSIZES; // resizes
file[17] = sizes[0]; file[18] = sizes[0]; // input sizes (w x h)
file[19] = sizes[1]; file[20] = sizes[1];
file[21] = sizes[2]; file[22] = sizes[2];
file[23] = sizes[3]; file[24] = sizes[3];
file[25] = sizes[4]; file[26] = sizes[4];
file[27] = scalex; file[28] = scaley; // scale the dimx and dimy amount ( for(i=0;i<dimx) outputx = 1 + i*scalex; )
file[29] = totalms;
((int64*)(file+30))[0] = totalcycles;
if ( !file_write( argv[5], file, sizeof(int) * ( 2 * timing_count + HEADER ) ) )
printf( "Error writing file: %s\n", argv[5] );
else
printf( "Successfully wrote timing file: %s\n", argv[5] );
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,56 @@
#include <stdio.h>
#include <stdlib.h>
#ifdef _MSC_VER
#define stop() __debugbreak()
#else
#define stop() __builtin_trap()
#endif
//#define HEAVYTM
#include "tm.h"
#define STBIR_SATURATE_INT
#define STB_IMAGE_RESIZE_STATIC
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#include "old_image_resize.h"
static int types[4] = { STBIR_TYPE_UINT8, STBIR_TYPE_UINT8, STBIR_TYPE_UINT16, STBIR_TYPE_FLOAT };
static int edges[4] = { STBIR_EDGE_CLAMP, STBIR_EDGE_REFLECT, STBIR_EDGE_ZERO, STBIR_EDGE_WRAP };
static int flts[5] = { STBIR_FILTER_BOX, STBIR_FILTER_TRIANGLE, STBIR_FILTER_CUBICBSPLINE, STBIR_FILTER_CATMULLROM, STBIR_FILTER_MITCHELL };
static int channels[20] = { 1, 2, 3, 4, 4,4, 2,2, 4,4, 2,2, 4,4, 2,2, 4,4, 2,2 };
static int alphapos[20] = { -1, -1, -1, -1, 3,0, 1,0, 3,0, 1,0, 3,0, 1,0, 3,0, 1,0 };
void oresize( void * o, int ox, int oy, int op, void * i, int ix, int iy, int ip, int buf, int type, int edg, int flt )
{
int t = types[type];
int ic = channels[buf];
int alpha = alphapos[buf];
int e = edges[edg];
int f = flts[flt];
int space = ( type == 1 ) ? STBIR_COLORSPACE_SRGB : 0;
int flags = ( buf >= 16 ) ? STBIR_FLAG_ALPHA_PREMULTIPLIED : ( ( buf >= 12 ) ? STBIR_FLAG_ALPHA_OUT_PREMULTIPLIED : ( ( buf >= 8 ) ? (STBIR_FLAG_ALPHA_PREMULTIPLIED|STBIR_FLAG_ALPHA_OUT_PREMULTIPLIED) : 0 ) );
stbir_uint64 start;
ENTER( "Resize (old)" );
start = tmGetAccumulationStart( tm_mask );
if(!stbir_resize( i, ix, iy, ip, o, ox, oy, op, t, ic, alpha, flags, e, e, f, f, space, 0 ) )
stop();
#ifdef STBIR_PROFILE
tmEmitAccumulationZone( 0, 0, (tm_uint64 *)&start, 0, oldprofile.named.setup, "Setup (old)" );
tmEmitAccumulationZone( 0, 0, (tm_uint64 *)&start, 0, oldprofile.named.filters, "Filters (old)" );
tmEmitAccumulationZone( 0, 0, (tm_uint64 *)&start, 0, oldprofile.named.looping, "Looping (old)" );
tmEmitAccumulationZone( 0, 0, (tm_uint64 *)&start, 0, oldprofile.named.vertical, "Vertical (old)" );
tmEmitAccumulationZone( 0, 0, (tm_uint64 *)&start, 0, oldprofile.named.horizontal, "Horizontal (old)" );
tmEmitAccumulationZone( 0, 0, (tm_uint64 *)&start, 0, oldprofile.named.decode, "Scanline input (old)" );
tmEmitAccumulationZone( 0, 0, (tm_uint64 *)&start, 0, oldprofile.named.encode, "Scanline output (old)" );
tmEmitAccumulationZone( 0, 0, (tm_uint64 *)&start, 0, oldprofile.named.alpha, "Alpha weighting (old)" );
tmEmitAccumulationZone( 0, 0, (tm_uint64 *)&start, 0, oldprofile.named.unalpha, "Alpha unweighting (old)" );
#endif
LEAVE();
}

View File

@ -0,0 +1,992 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#define HEAVYTM
#include "tm.h"
#ifdef RADUSETM3
tm_api * g_tm_api;
//#define PROFILE_MODE
#endif
#include <math.h>
#ifdef _MSC_VER
#define stop() __debugbreak()
#include <windows.h>
#define int64 __int64
#define uint64 unsigned __int64
#else
#define stop() __builtin_trap()
#define int64 long long
#define uint64 unsigned long long
#endif
#ifdef _MSC_VER
#pragma warning(disable:4127)
#endif
//#define NOCOMP
//#define PROFILE_NEW_ONLY
//#define PROFILE_MODE
#if defined(_x86_64) || defined( __x86_64__ ) || defined( _M_X64 ) || defined(__x86_64) || defined(__SSE2__) || defined(STBIR_SSE) || defined( _M_IX86_FP ) || defined(__i386) || defined( __i386__ ) || defined( _M_IX86 ) || defined( _X86_ )
#ifdef _MSC_VER
uint64 __rdtsc();
#define __cycles() __rdtsc()
#else // non msvc
static inline uint64 __cycles()
{
unsigned int lo, hi;
asm volatile ("rdtsc" : "=a" (lo), "=d" (hi) );
return ( ( (uint64) hi ) << 32 ) | ( (uint64) lo );
}
#endif // msvc
#elif defined( _M_ARM64 ) || defined( __aarch64__ ) || defined( __arm64__ ) || defined(__ARM_NEON__)
#ifdef _MSC_VER
#define __cycles() _ReadStatusReg(ARM64_CNTVCT)
#else
static inline uint64 __cycles()
{
uint64 tsc;
asm volatile("mrs %0, cntvct_el0" : "=r" (tsc));
return tsc;
}
#endif
#else // x64, arm
#error Unknown platform for timing.
#endif //x64 and
#ifdef PROFILE_MODE
#define STBIR_ASSERT(cond)
#endif
#ifdef _DEBUG
#undef STBIR_ASSERT
#define STBIR_ASSERT(cond) { if (!(cond)) stop(); }
#endif
#define SHRINKBYW 2
#define ZOOMBYW 2
#define SHRINKBYH 2
#define ZOOMBYH 2
int mem_count = 0;
#ifdef TEST_WITH_VALLOC
#define STBIR__SEPARATE_ALLOCATIONS
#if TEST_WITH_LIMIT_AT_FRONT
void * wmalloc(SIZE_T size)
{
static unsigned int pagesize=0;
void* p;
SIZE_T s;
// get the page size, if we haven't yet
if (pagesize==0)
{
SYSTEM_INFO si;
GetSystemInfo(&si);
pagesize=si.dwPageSize;
}
// we need room for the size, 8 bytes to hide the original pointer and a
// validation dword, and enough data to completely fill one page
s=(size+(pagesize-1))&~(pagesize-1);
// allocate the size plus a page (for the guard)
p=VirtualAlloc(0,(SIZE_T)s,MEM_RESERVE|MEM_COMMIT,PAGE_READWRITE);
return p;
}
void wfree(void * ptr)
{
if (ptr)
{
if ( ((ptrdiff_t)ptr) & 4095 ) stop();
if ( VirtualFree(ptr,0,MEM_RELEASE) == 0 ) stop();
}
}
#else
void * wmalloc(SIZE_T size)
{
static unsigned int pagesize=0;
void* p;
SIZE_T s;
// get the page size, if we haven't yet
if (pagesize==0)
{
SYSTEM_INFO si;
GetSystemInfo(&si);
pagesize=si.dwPageSize;
}
// we need room for the size, 8 bytes to hide the original pointer and a
// validation dword, and enough data to completely fill one page
s=(size+16+(pagesize-1))&~(pagesize-1);
// allocate the size plus a page (for the guard)
p=VirtualAlloc(0,(SIZE_T)(s+pagesize+pagesize),MEM_RESERVE|MEM_COMMIT,PAGE_READWRITE);
if (p)
{
DWORD oldprot;
void* orig=p;
// protect the first page
VirtualProtect(((char*)p),pagesize,PAGE_NOACCESS,&oldprot);
// protect the final page
VirtualProtect(((char*)p)+s+pagesize,pagesize,PAGE_NOACCESS,&oldprot);
// now move the returned pointer so that it bumps right up against the
// the next (protected) page (this may result in unaligned return
// addresses - pre-align the sizes if you always want aligned ptrs)
//#define ERROR_ON_FRONT
#ifdef ERROR_ON_FRONT
p=((char*)p)+pagesize+16;
#else
p=((char*)p)+(s-size)+pagesize;
#endif
// hide the validation value and the original pointer (which we'll
// need used for freeing) right behind the returned pointer
((unsigned int*)p)[-1]=0x98765432;
((void**)p)[-2]=orig;
++mem_count;
//printf("aloc: %p bytes: %d\n",p,(int)size);
return(p);
}
return 0;
}
void wfree(void * ptr)
{
if (ptr)
{
int err=0;
// is this one of our allocations?
if (((((unsigned int*)ptr)[-1])!=0x98765432) || ((((void**)ptr)[-2])==0))
{
err=1;
}
if (err)
{
__debugbreak();
}
else
{
// back up to find the original pointer
void* p=((void**)ptr)[-2];
// clear the validation value and the original pointer
((unsigned int*)ptr)[-1]=0;
((void**)ptr)[-2]=0;
//printf("free: %p\n",ptr);
--mem_count;
// now free the pages
if (p)
VirtualFree(p,0,MEM_RELEASE);
}
}
}
#endif
#define STBIR_MALLOC(size,user_data) ((void)(user_data), wmalloc(size))
#define STBIR_FREE(ptr,user_data) ((void)(user_data), wfree(ptr))
#endif
#define STBIR_PROFILE
//#define STBIR_NO_SIMD
//#define STBIR_AVX
//#define STBIR_AVX2
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#include "stb_image_resize2.h" // new one!
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
int tsizes[5] = { 1, 1, 2, 4, 2 };
int ttypes[5] = { STBIR_TYPE_UINT8, STBIR_TYPE_UINT8_SRGB, STBIR_TYPE_UINT16, STBIR_TYPE_FLOAT, STBIR_TYPE_HALF_FLOAT };
int cedges[4] = { STBIR_EDGE_CLAMP, STBIR_EDGE_REFLECT, STBIR_EDGE_ZERO, STBIR_EDGE_WRAP };
int flts[5] = { STBIR_FILTER_BOX, STBIR_FILTER_TRIANGLE, STBIR_FILTER_CUBICBSPLINE, STBIR_FILTER_CATMULLROM, STBIR_FILTER_MITCHELL };
int buffers[20] = { STBIR_1CHANNEL, STBIR_2CHANNEL, STBIR_RGB, STBIR_4CHANNEL,
STBIR_BGRA, STBIR_ARGB, STBIR_RA, STBIR_AR,
STBIR_RGBA_PM, STBIR_ARGB_PM, STBIR_RA_PM, STBIR_AR_PM,
STBIR_RGBA, STBIR_ARGB, STBIR_RA, STBIR_AR,
STBIR_RGBA_PM, STBIR_ARGB_PM, STBIR_RA_PM, STBIR_AR_PM,
};
int obuffers[20] = { STBIR_1CHANNEL, STBIR_2CHANNEL, STBIR_RGB, STBIR_4CHANNEL,
STBIR_BGRA, STBIR_ARGB, STBIR_RA, STBIR_AR,
STBIR_RGBA_PM, STBIR_ARGB_PM, STBIR_RA_PM, STBIR_AR_PM,
STBIR_RGBA_PM, STBIR_ARGB_PM, STBIR_RA_PM, STBIR_AR_PM,
STBIR_RGBA, STBIR_ARGB, STBIR_RA, STBIR_AR,
};
int bchannels[20] = { 1, 2, 3, 4, 4,4, 2,2, 4,4, 2,2, 4,4, 2,2, 4,4, 2,2 };
int alphapos[20] = { -1, -1, -1, -1, 3,0, 1,0, 3,0, 1,0, 3,0, 1,0,3,0, 1,0 };
char const * buffstrs[20] = { "1ch", "2ch", "3ch", "4ch", "RGBA", "ARGB", "RA", "AR", "RGBA_both_pre", "ARGB_both_pre", "RA_both_pre", "AR_both_pre", "RGBA_out_pre", "ARGB_out_pre", "RA_out_pre", "AR_out_pre", "RGBA_in_pre", "ARGB_in_pre", "RA_in_pre", "AR_in_pre" };
char const * typestrs[5] = { "Bytes", "BytesSRGB", "Shorts", "Floats", "Half Floats"};
char const * edgestrs[4] = { "Clamp", "Reflect", "Zero", "Wrap" };
char const * fltstrs[5] = { "Box", "Triangle", "Cubic", "Catmullrom", "Mitchell" };
#ifdef STBIR_PROFILE
static void do_acc_zones( STBIR_PROFILE_INFO * profile )
{
stbir_uint32 j;
stbir_uint64 start = tmGetAccumulationStart( tm_mask ); start=start;
for( j = 0 ; j < profile->count ; j++ )
{
if ( profile->clocks[j] )
tmEmitAccumulationZone( 0, 0, (tm_uint64*)&start, 0, profile->clocks[j], profile->descriptions[j] );
}
}
#else
#define do_acc_zones(...)
#endif
int64 vert;
//#define WINTHREADTEST
#ifdef WINTHREADTEST
static STBIR_RESIZE * thread_resize;
static LONG which;
static int threads_started = 0;
static HANDLE threads[32];
static HANDLE starts,stops;
static DWORD resize_shim( LPVOID p )
{
for(;;)
{
LONG wh;
WaitForSingleObject( starts, INFINITE );
wh = InterlockedAdd( &which, 1 ) - 1;
ENTER( "Split %d", wh );
stbir_resize_split( thread_resize, wh, 1 );
#ifdef STBIR_PROFILE
{ STBIR_PROFILE_INFO profile; stbir_resize_split_profile_info( &profile, thread_resize, wh, 1 ); do_acc_zones( &profile ); vert = profile.clocks[1]; }
#endif
LEAVE();
ReleaseSemaphore( stops, 1, 0 );
}
}
#endif
void nresize( void * o, int ox, int oy, int op, void * i, int ix, int iy, int ip, int buf, int type, int edg, int flt )
{
STBIR_RESIZE resize;
stbir_resize_init( &resize, i, ix, iy, ip, o, ox, oy, op, buffers[buf], ttypes[type] );
stbir_set_pixel_layouts( &resize, buffers[buf], obuffers[buf] );
stbir_set_edgemodes( &resize, cedges[edg], cedges[edg] );
stbir_set_filters( &resize, flts[flt], /*STBIR_FILTER_POINT_SAMPLE */ flts[flt] );
//stbir_set_input_subrect( &resize, 0.55f,0.333f,0.75f,0.50f);
//stbir_set_output_pixel_subrect( &resize, 00, 00, ox/2,oy/2);
//stbir_set_pixel_subrect(&resize, 1430,1361,30,30);
ENTER( "Resize" );
#ifndef WINTHREADTEST
ENTER( "Filters" );
stbir_build_samplers_with_splits( &resize, 1 );
#ifdef STBIR_PROFILE
{ STBIR_PROFILE_INFO profile; stbir_resize_build_profile_info( &profile, &resize ); do_acc_zones( &profile ); }
#endif
LEAVE();
ENTER( "Resize" );
if(!stbir_resize_extended( &resize ) )
stop();
#ifdef STBIR_PROFILE
{ STBIR_PROFILE_INFO profile; stbir_resize_extended_profile_info( &profile, &resize ); do_acc_zones( &profile ); vert = profile.clocks[1]; }
#endif
LEAVE();
#else
{
int c, cnt;
ENTER( "Filters" );
cnt = stbir_build_samplers_with_splits( &resize, 4 );
#ifdef STBIR_PROFILE
{ STBIR_PROFILE_INFO profile; stbir_resize_build_profile_info( &profile, &resize ); do_acc_zones( &profile ); }
#endif
LEAVE();
ENTER( "Thread start" );
if ( threads_started == 0 )
{
starts = CreateSemaphore( 0, 0, 32, 0 );
stops = CreateSemaphore( 0, 0, 32, 0 );
}
for( c = threads_started ; c < cnt ; c++ )
threads[ c ] = CreateThread( 0, 2048*1024, resize_shim, 0, 0, 0 );
threads_started = cnt;
thread_resize = &resize;
which = 0;
LEAVE();
// starts the threads
ReleaseSemaphore( starts, cnt, 0 );
ENTER( "Wait" );
for( c = 0 ; c < cnt; c++ )
WaitForSingleObject( stops, INFINITE );
LEAVE();
}
#endif
ENTER( "Free" );
stbir_free_samplers( &resize );
LEAVE();
LEAVE();
}
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
extern void oresize( void * o, int ox, int oy, int op, void * i, int ix, int iy, int ip, int buf, int type, int edg, int flt );
#define TYPESTART 0
#define TYPEEND 4
#define LAYOUTSTART 0
#define LAYOUTEND 19
#define SIZEWSTART 0
#define SIZEWEND 2
#define SIZEHSTART 0
#define SIZEHEND 2
#define EDGESTART 0
#define EDGEEND 3
#define FILTERSTART 0
#define FILTEREND 4
#define HEIGHTSTART 0
#define HEIGHTEND 2
#define WIDTHSTART 0
#define WIDTHEND 2
static void * convert8to16( unsigned char * i, int w, int h, int c )
{
unsigned short * ret;
int p;
ret = malloc( w*h*c*sizeof(short) );
for(p = 0 ; p < (w*h*c) ; p++ )
{
ret[p]=(short)((((int)i[p])<<8)+i[p]);
}
return ret;
}
static void * convert8tof( unsigned char * i, int w, int h, int c )
{
float * ret;
int p;
ret = malloc( w*h*c*sizeof(float) );
for(p = 0 ; p < (w*h*c) ; p++ )
{
ret[p]=((float)i[p])*(1.0f/255.0f);
}
return ret;
}
static void * convert8tohf( unsigned char * i, int w, int h, int c )
{
stbir__FP16 * ret;
int p;
ret = malloc( w*h*c*sizeof(stbir__FP16) );
for(p = 0 ; p < (w*h*c) ; p++ )
{
ret[p]=stbir__float_to_half(((float)i[p])*(1.0f/255.0f));
}
return ret;
}
static void * convert8tohff( unsigned char * i, int w, int h, int c )
{
float * ret;
int p;
ret = malloc( w*h*c*sizeof(float) );
for(p = 0 ; p < (w*h*c) ; p++ )
{
ret[p]=stbir__half_to_float(stbir__float_to_half(((float)i[p])*(1.0f/255.0f)));
}
return ret;
}
static int isprime( int v )
{
int i;
if ( v <= 3 )
return ( v > 1 );
if ( ( v & 1 ) == 0 )
return 0;
if ( ( v % 3 ) == 0 )
return 0;
i = 5;
while ( (i*i) <= v )
{
if ( ( v % i ) == 0 )
return 0;
if ( ( v % ( i + 2 ) ) == 0 )
return 0;
i += 6;
}
return 1;
}
static int getprime( int v )
{
int i;
i = 0;
for(;;)
{
if ( i >= v )
return v; // can't find any, just return orig
if (isprime(v - i))
return v - i;
if (isprime(v + i))
return v + i;
++i;
}
}
int main( int argc, char ** argv )
{
int ix, iy, ic;
unsigned char * input[6];
char * ir1;
char * ir2;
int szhs[3];
int szws[3];
int aw, ah, ac;
unsigned char * correctalpha;
int layouts, types, heights, widths, edges, filters;
if ( argc != 2 )
{
printf("command: stbirtest [imagefile]\n");
exit(1);
}
SetupTM( "127.0.0.1" );
correctalpha = stbi_load( "correctalpha.png", &aw, &ah, &ac, 0 );
input[0] = stbi_load( argv[1], &ix, &iy, &ic, 0 );
input[1] = input[0];
input[2] = convert8to16( input[0], ix, iy, ic );
input[3] = convert8tof( input[0], ix, iy, ic );
input[4] = convert8tohf( input[0], ix, iy, ic );
input[5] = convert8tohff( input[0], ix, iy, ic );
printf("Input %dx%d (%d channels)\n",ix,iy,ic);
ir1 = malloc( 4 * 4 * 3000 * 3000ULL );
ir2 = malloc( 4 * 4 * 3000 * 3000ULL );
szhs[0] = getprime( iy/SHRINKBYH );
szhs[1] = iy;
szhs[2] = getprime( iy*ZOOMBYH );
szws[0] = getprime( ix/SHRINKBYW );
szws[1] = ix;
szws[2] = getprime( ix*ZOOMBYW );
#if 1
for( types = TYPESTART ; types <= TYPEEND ; types++ )
#else
for( types = 1 ; types <= 1 ; types++ )
#endif
{
ENTER( "Test type: %s",typestrs[types]);
#if 1
for( layouts = LAYOUTSTART ; layouts <= LAYOUTEND ; layouts++ )
#else
for( layouts = 16; layouts <= 16 ; layouts++ )
#endif
{
ENTER( "Test layout: %s",buffstrs[layouts]);
#if 0
for( heights = HEIGHTSTART ; heights <= HEIGHTEND ; heights++ )
{
int w, h = szhs[heights];
#else
for( heights = 0 ; heights <= 11 ; heights++ )
{
static int szhsz[12]={32, 200, 350, 400, 450, 509, 532, 624, 700, 824, 1023, 2053 };
int w, h = szhsz[heights];
#endif
ENTER( "Test height: %d %s %d",iy,(h<iy)?"Down":((h>iy)?"Up":"Same"),h);
#if 0
for( widths = WIDTHSTART ; widths <= WIDTHEND ; widths++ )
{
w = szws[widths];
#else
for( widths = 0 ; widths <= 12 ; widths++ )
{
static int szwsz[13]={2, 32, 200, 350, 400, 450, 509, 532, 624, 700, 824, 1023, 2053 };
w = szwsz[widths];
#endif
ENTER( "Test width: %d %s %d",ix, (w<ix)?"Down":((w>ix)?"Up":"Same"), w);
#if 0
for( edges = EDGESTART ; edges <= EDGEEND ; edges++ )
#else
for( edges = 0 ; edges <= 0 ; edges++ )
#endif
{
ENTER( "Test edge: %s",edgestrs[edges]);
#if 0
for( filters = FILTERSTART ; filters <= FILTEREND ; filters++ )
#else
for( filters = 3 ; filters <= 3 ; filters++ )
#endif
{
int op, opw, np,npw, c, a;
#ifdef COMPARE_SAME
int oldtypes = types;
#else
int oldtypes = (types==4)?3:types;
#endif
ENTER( "Test filter: %s",fltstrs[filters]);
{
c = bchannels[layouts];
a = alphapos[layouts];
op = w*tsizes[oldtypes]*c + 60;
opw = w*tsizes[oldtypes]*c;
np = w*tsizes[types]*c + 60;
npw = w*tsizes[types]*c;
printf( "%s:layout: %s w: %d h: %d edge: %s filt: %s\n", typestrs[types],buffstrs[layouts], w, h, edgestrs[edges], fltstrs[filters] );
// clear pixel area to different, right edge to zero
#ifndef NOCLEAR
ENTER( "Test clear padding" );
{
int d;
for( d = 0 ; d < h ; d++ )
{
int oofs = d * op;
int nofs = d * np;
memset( ir1 + oofs, 192, opw );
memset( ir1 + oofs+opw, 79, op-opw );
memset( ir2 + nofs, 255, npw );
memset( ir2 + nofs+npw, 79, np-npw );
}
}
LEAVE();
#endif
#ifdef COMPARE_SAME
#define TIMINGS 1
#else
#define TIMINGS 1
#endif
ENTER( "Test both" );
{
#ifndef PROFILE_NEW_ONLY
{
int ttt, max = 0x7fffffff;
ENTER( "Test old" );
for( ttt = 0 ; ttt < TIMINGS ; ttt++ )
{
int64 m = __cycles();
oresize( ir1, w, h, op,
#ifdef COMPARE_SAME
input[types],
#else
input[(types==4)?5:types],
#endif
ix, iy, ix*ic*tsizes[oldtypes], layouts, oldtypes, edges, filters );
m = __cycles() - m;
if ( ( (int)m ) < max )
max = (int) m;
}
LEAVE();
printf("old: %d\n", max );
}
#endif
{
int ttt, max = 0x7fffffff, maxv = 0x7fffffff;
ENTER( "Test new" );
for( ttt = 0 ; ttt < TIMINGS ; ttt++ )
{
int64 m = __cycles();
nresize( ir2, w, h, np, input[types], ix, iy, ix*ic*tsizes[types], layouts, types, edges, filters );
m = __cycles() - m;
if ( ( (int)m ) < max )
max = (int) m;
if ( ( (int)vert ) < maxv )
maxv = (int) vert;
}
LEAVE(); // test new
printf("new: %d (v: %d)\n", max, maxv );
}
}
LEAVE(); // test both
if ( mem_count!= 0 )
stop();
#ifndef NOCOMP
ENTER( "Test compare" );
{
int x,y,ch;
int nums = 0;
for( y = 0 ; y < h ; y++ )
{
for( x = 0 ; x < w ; x++ )
{
switch(types)
{
case 0:
case 1: //SRGB
{
unsigned char * p1 = (unsigned char *)&ir1[y*op+x*c];
unsigned char * p2 = (unsigned char *)&ir2[y*np+x*c];
for( ch = 0 ; ch < c ; ch++ )
{
float pp1,pp2,d;
float av = (a==-1)?1.0f:((float)p1[a]/255.0f);
pp1 = p1[ch];
pp2 = p2[ch];
// compare in premult space
#ifndef COMPARE_SAME
if ( ( ( layouts >=4 ) && ( layouts <= 7 ) ) || ( ( layouts >=16 ) && ( layouts <= 19 ) ) )
{
pp1 *= av;
pp2 *= av;
}
#endif
d = pp1 - pp2;
if ( d < 0 ) d = -d;
#ifdef COMPARE_SAME
if ( d > 0 )
#else
if ( d > 1 )
#endif
{
printf("Error at %d x %d (chan %d) (d: %g a: %g) [%d %d %d %d] [%d %d %d %d]\n",x,y,ch, d,av, p1[0],p1[1],p1[2],p1[3], p2[0],p2[1],p2[2],p2[3]);
++nums;
if ( nums > 16 ) goto ex;
//if (d) exit(1);
//goto ex;
}
}
}
break;
case 2:
{
unsigned short * p1 = (unsigned short *)&ir1[y*op+x*c*sizeof(short)];
unsigned short * p2 = (unsigned short *)&ir2[y*np+x*c*sizeof(short)];
for( ch = 0 ; ch < c ; ch++ )
{
float thres,pp1,pp2,d;
float av = (a==-1)?1.0f:((float)p1[a]/65535.0f);
pp1 = p1[ch];
pp2 = p2[ch];
// compare in premult space
#ifndef COMPARE_SAME
if ( ( ( layouts >=4 ) && ( layouts <= 7 ) ) || ( ( layouts >= 16 ) && ( layouts <= 19 ) ) )
{
pp1 *= av;
pp2 *= av;
}
#endif
d = pp1 - pp2;
if ( d < 0 ) d = -d;
thres=((float)p1[ch]*0.007f)+2.0f;
if (thres<4) thres = 4;
#ifdef COMPARE_SAME
if ( d > 0 )
#else
if ( d > thres)
#endif
{
printf("Error at %d x %d (chan %d) %d %d [df: %g th: %g al: %g] (%d %d %d %d) (%d %d %d %d)\n",x,y,ch, p1[ch],p2[ch],d,thres,av,p1[0],p1[1],p1[2],p1[3],p2[0],p2[1],p2[2],p2[3]);
++nums;
if ( nums > 16 ) goto ex;
//if (d) exit(1);
//goto ex;
}
}
}
break;
case 3:
{
float * p1 = (float *)&ir1[y*op+x*c*sizeof(float)];
float * p2 = (float *)&ir2[y*np+x*c*sizeof(float)];
for( ch = 0 ; ch < c ; ch++ )
{
float pp1 = p1[ch], pp2 = p2[ch];
float av = (a==-1)?1.0f:p1[a];
float thres, d;
// clamp
if (pp1<=0.0f) pp1 = 0;
if (pp2<=0.0f) pp2 = 0;
if (av<=0.0f) av = 0;
if (pp1>1.0f) pp1 = 1.0f;
if (pp2>1.0f) pp2 = 1.0f;
if (av>1.0f) av = 1.0f;
// compare in premult space
#ifndef COMPARE_SAME
if ( ( ( layouts >=4 ) && ( layouts <= 7 ) ) || ( ( layouts >= 16 ) && ( layouts <= 19 ) ) )
{
pp1 *= av;
pp2 *= av;
}
#endif
d = pp1 - pp2;
if ( d < 0 ) d = -d;
thres=(p1[ch]*0.002f)+0.0002f;
if ( thres < 0 ) thres = -thres;
#ifdef COMPARE_SAME
if ( d != 0.0f )
#else
if ( d > thres )
#endif
{
printf("Error at %d x %d (chan %d) %g %g [df: %g th: %g al: %g] (%g %g %g %g) (%g %g %g %g)\n",x,y,ch, p1[ch],p2[ch],d,thres,av,p1[0],p1[1],p1[2],p1[3],p2[0],p2[1],p2[2],p2[3]);
++nums;
if ( nums > 16 ) goto ex;
//if (d) exit(1);
//goto ex;
}
}
}
break;
case 4:
{
#ifdef COMPARE_SAME
stbir__FP16 * p1 = (stbir__FP16 *)&ir1[y*op+x*c*sizeof(stbir__FP16)];
#else
float * p1 = (float *)&ir1[y*op+x*c*sizeof(float)];
#endif
stbir__FP16 * p2 = (stbir__FP16 *)&ir2[y*np+x*c*sizeof(stbir__FP16)];
for( ch = 0 ; ch < c ; ch++ )
{
#ifdef COMPARE_SAME
float pp1 = stbir__half_to_float(p1[ch]);
float av = (a==-1)?1.0f:stbir__half_to_float(p1[a]);
#else
float pp1 = stbir__half_to_float(stbir__float_to_half(p1[ch]));
float av = (a==-1)?1.0f:stbir__half_to_float(stbir__float_to_half(p1[a]));
#endif
float pp2 = stbir__half_to_float(p2[ch]);
float d, thres;
// clamp
if (pp1<=0.0f) pp1 = 0;
if (pp2<=0.0f) pp2 = 0;
if (av<=0.0f) av = 0;
if (pp1>1.0f) pp1 = 1.0f;
if (pp2>1.0f) pp2 = 1.0f;
if (av>1.0f) av = 1.0f;
thres=(pp1*0.002f)+0.0002f;
// compare in premult space
#ifndef COMPARE_SAME
if ( ( ( layouts >=4 ) && ( layouts <= 7 ) ) || ( ( layouts >= 16 ) && ( layouts <= 19 ) ) )
{
pp1 *= av;
pp2 *= av;
}
#endif
d = pp1 - pp2;
if ( d < 0 ) d = -d;
#ifdef COMPARE_SAME
if ( d != 0.0f )
#else
if ( d > thres )
#endif
{
printf("Error at %d x %d (chan %d) %g %g [df: %g th: %g al: %g] (%g %g %g %g) (%g %g %g %g)\n",x,y,ch,
#ifdef COMPARE_SAME
stbir__half_to_float(p1[ch]),
#else
p1[ch],
#endif
stbir__half_to_float(p2[ch]),
d,thres,av,
#ifdef COMPARE_SAME
stbir__half_to_float(p1[0]),stbir__half_to_float(p1[1]),stbir__half_to_float(p1[2]),stbir__half_to_float(p1[3]),
#else
p1[0],p1[1],p1[2],p1[3],
#endif
stbir__half_to_float(p2[0]),stbir__half_to_float(p2[1]),stbir__half_to_float(p2[2]),stbir__half_to_float(p2[3]) );
++nums;
if ( nums > 16 ) goto ex;
//if (d) exit(1);
//goto ex;
}
}
}
break;
}
}
for( x = (w*c)*tsizes[oldtypes]; x < op; x++ )
{
if ( ir1[y*op+x] != 79 )
{
printf("Margin error at %d x %d %d (should be 79) OLD!\n",x,y,(unsigned char)ir1[y*op+x]);
goto ex;
}
}
for( x = (w*c)*tsizes[types]; x < np; x++ )
{
if ( ir2[y*np+x] != 79 )
{
printf("Margin error at %d x %d %d (should be 79) NEW\n",x,y,(unsigned char)ir2[y*np+x]);
goto ex;
}
}
}
ex:
ENTER( "OUTPUT IMAGES" );
printf(" tot pix: %d, errs: %d\n", w*h*c,nums );
if (nums)
{
stbi_write_png("old.png", w, h, c, ir1, op);
stbi_write_png("new.png", w, h, c, ir2, np);
exit(1);
}
LEAVE(); // output images
}
LEAVE(); //test compare
#endif
}
LEAVE(); // test filter
}
LEAVE(); // test edge
}
LEAVE(); // test width
}
LEAVE(); // test height
}
LEAVE(); // test type
}
LEAVE(); // test layout
}
CloseTM();
return 0;
}

View File

@ -0,0 +1,999 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define stop() __debugbreak()
#include <windows.h>
#define int64 __int64
#pragma warning(disable:4127)
#define STBIR__WEIGHT_TABLES
#define STBIR_PROFILE
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#include "stb_image_resize2.h"
static int * file_read( char const * filename )
{
size_t s;
int * m;
FILE * f = fopen( filename, "rb" );
if ( f == 0 ) return 0;
fseek( f, 0, SEEK_END);
s = ftell( f );
fseek( f, 0, SEEK_SET);
m = malloc( s + 4 );
m[0] = (int)s;
fread( m+1, 1, s, f);
fclose(f);
return( m );
}
typedef struct fileinfo
{
int * timings;
int timing_count;
int dimensionx, dimensiony;
int numtypes;
int * types;
int * effective;
int cpu;
int simd;
int numinputrects;
int * inputrects;
int outputscalex, outputscaley;
int milliseconds;
int64 cycles;
double scale_time;
int bitmapx, bitmapy;
char const * filename;
} fileinfo;
int numfileinfo;
fileinfo fi[256];
unsigned char * bitmap;
int bitmapw, bitmaph, bitmapp;
static int use_timing_file( char const * filename, int index )
{
int * base = file_read( filename );
int * file = base;
if ( base == 0 ) return 0;
++file; // skip file image size;
if ( *file++ != 'VFT1' ) return 0;
fi[index].cpu = *file++;
fi[index].simd = *file++;
fi[index].dimensionx = *file++;
fi[index].dimensiony = *file++;
fi[index].numtypes = *file++;
fi[index].types = file; file += fi[index].numtypes;
fi[index].effective = file; file += fi[index].numtypes;
fi[index].numinputrects = *file++;
fi[index].inputrects = file; file += fi[index].numinputrects * 2;
fi[index].outputscalex = *file++;
fi[index].outputscaley = *file++;
fi[index].milliseconds = *file++;
fi[index].cycles = ((int64*)file)[0]; file += 2;
fi[index].filename = filename;
fi[index].timings = file;
fi[index].timing_count = (int) ( ( base[0] - ( ((char*)file - (char*)base - sizeof(int) ) ) ) / (sizeof(int)*2) );
fi[index].scale_time = (double)fi[index].milliseconds / (double)fi[index].cycles;
return 1;
}
static int vert_first( float weights_table[STBIR_RESIZE_CLASSIFICATIONS][4], int ox, int oy, int ix, int iy, int filter, STBIR__V_FIRST_INFO * v_info )
{
float h_scale=(float)ox/(float)(ix);
float v_scale=(float)oy/(float)(iy);
stbir__support_callback * support = stbir__builtin_supports[filter];
int vertical_filter_width = stbir__get_filter_pixel_width(support,v_scale,0);
int vertical_gather = ( v_scale >= ( 1.0f - stbir__small_float ) ) || ( vertical_filter_width <= STBIR_FORCE_GATHER_FILTER_SCANLINES_AMOUNT );
return stbir__should_do_vertical_first( weights_table, stbir__get_filter_pixel_width(support,h_scale,0), h_scale, ox, vertical_filter_width, v_scale, oy, vertical_gather, v_info );
}
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
static void alloc_bitmap()
{
int findex;
int x = 0, y = 0;
int w = 0, h = 0;
for( findex = 0 ; findex < numfileinfo ; findex++ )
{
int nx, ny;
int thisw, thish;
thisw = ( fi[findex].dimensionx * fi[findex].numtypes ) + ( fi[findex].numtypes - 1 );
thish = ( fi[findex].dimensiony * fi[findex].numinputrects ) + ( fi[findex].numinputrects - 1 );
for(;;)
{
nx = x + ((x)?4:0) + thisw;
ny = y + ((y)?4:0) + thish;
if ( ( nx <= 3600 ) || ( x == 0 ) )
{
fi[findex].bitmapx = x + ((x)?4:0);
fi[findex].bitmapy = y + ((y)?4:0);
x = nx;
if ( x > w ) w = x;
if ( ny > h ) h = ny;
break;
}
else
{
x = 0;
y = h;
}
}
}
w = (w+3) & ~3;
bitmapw = w;
bitmaph = h;
bitmapp = w * 3; // RGB
bitmap = malloc( bitmapp * bitmaph );
memset( bitmap, 0, bitmapp * bitmaph );
}
static void build_bitmap( float weights[STBIR_RESIZE_CLASSIFICATIONS][4], int do_channel_count_index, int findex )
{
static int colors[STBIR_RESIZE_CLASSIFICATIONS];
STBIR__V_FIRST_INFO v_info = {0};
int * ts;
int ir;
unsigned char * bitm = bitmap + ( fi[findex].bitmapx*3 ) + ( fi[findex].bitmapy*bitmapp) ;
for( ir = 0; ir < STBIR_RESIZE_CLASSIFICATIONS ; ir++ ) colors[ ir ] = 127*ir/STBIR_RESIZE_CLASSIFICATIONS+128;
ts = fi[findex].timings;
for( ir = 0 ; ir < fi[findex].numinputrects ; ir++ )
{
int ix, iy, chanind;
ix = fi[findex].inputrects[ir*2];
iy = fi[findex].inputrects[ir*2+1];
for( chanind = 0 ; chanind < fi[findex].numtypes ; chanind++ )
{
int ofs, h, hh;
// just do the type that we're on
if ( chanind != do_channel_count_index )
{
ts += 2 * fi[findex].dimensionx * fi[findex].dimensiony;
continue;
}
// bitmap offset
ofs=chanind*(fi[findex].dimensionx+1)*3+ir*(fi[findex].dimensiony+1)*bitmapp;
h = 1;
for( hh = 0 ; hh < fi[findex].dimensiony; hh++ )
{
int ww, w = 1;
for( ww = 0 ; ww < fi[findex].dimensionx; ww++ )
{
int good, v_first, VF, HF;
VF = ts[0];
HF = ts[1];
v_first = vert_first( weights, w, h, ix, iy, STBIR_FILTER_MITCHELL, &v_info );
good = ( ((HF<=VF) && (!v_first)) || ((VF<=HF) && (v_first)));
if ( good )
{
bitm[ofs+2] = 0;
bitm[ofs+1] = (unsigned char)colors[v_info.v_resize_classification];
}
else
{
double r;
if ( HF < VF )
r = (double)(VF-HF)/(double)HF;
else
r = (double)(HF-VF)/(double)VF;
if ( r > 0.4f) r = 0.4;
r *= 1.0f/0.4f;
bitm[ofs+2] = (char)(255.0f*r);
bitm[ofs+1] = (char)(((float)colors[v_info.v_resize_classification])*(1.0f-r));
}
bitm[ofs] = 0;
ofs += 3;
ts += 2;
w += fi[findex].outputscalex;
}
ofs += bitmapp - fi[findex].dimensionx*3;
h += fi[findex].outputscaley;
}
}
}
}
static void build_comp_bitmap( float weights[STBIR_RESIZE_CLASSIFICATIONS][4], int do_channel_count_index )
{
int * ts0;
int * ts1;
int ir;
unsigned char * bitm = bitmap + ( fi[0].bitmapx*3 ) + ( fi[0].bitmapy*bitmapp) ;
ts0 = fi[0].timings;
ts1 = fi[1].timings;
for( ir = 0 ; ir < fi[0].numinputrects ; ir++ )
{
int ix, iy, chanind;
ix = fi[0].inputrects[ir*2];
iy = fi[0].inputrects[ir*2+1];
for( chanind = 0 ; chanind < fi[0].numtypes ; chanind++ )
{
int ofs, h, hh;
// just do the type that we're on
if ( chanind != do_channel_count_index )
{
ts0 += 2 * fi[0].dimensionx * fi[0].dimensiony;
ts1 += 2 * fi[0].dimensionx * fi[0].dimensiony;
continue;
}
// bitmap offset
ofs=chanind*(fi[0].dimensionx+1)*3+ir*(fi[0].dimensiony+1)*bitmapp;
h = 1;
for( hh = 0 ; hh < fi[0].dimensiony; hh++ )
{
int ww, w = 1;
for( ww = 0 ; ww < fi[0].dimensionx; ww++ )
{
int v_first, time0, time1;
v_first = vert_first( weights, w, h, ix, iy, STBIR_FILTER_MITCHELL, 0 );
time0 = ( v_first ) ? ts0[0] : ts0[1];
time1 = ( v_first ) ? ts1[0] : ts1[1];
if ( time0 < time1 )
{
double r = (double)(time1-time0)/(double)time0;
if ( r > 0.4f) r = 0.4;
r *= 1.0f/0.4f;
bitm[ofs+2] = 0;
bitm[ofs+1] = (char)(255.0f*r);
bitm[ofs] = (char)(64.0f*(1.0f-r));
}
else
{
double r = (double)(time0-time1)/(double)time1;
if ( r > 0.4f) r = 0.4;
r *= 1.0f/0.4f;
bitm[ofs+2] = (char)(255.0f*r);
bitm[ofs+1] = 0;
bitm[ofs] = (char)(64.0f*(1.0f-r));
}
ofs += 3;
ts0 += 2;
ts1 += 2;
w += fi[0].outputscalex;
}
ofs += bitmapp - fi[0].dimensionx*3;
h += fi[0].outputscaley;
}
}
}
}
static void write_bitmap()
{
stbi_write_png( "results.png", bitmapp / 3, bitmaph, 3|STB_IMAGE_BGR, bitmap, bitmapp );
}
static void calc_errors( float weights_table[STBIR_RESIZE_CLASSIFICATIONS][4], int * curtot, double * curerr, int do_channel_count_index )
{
int th, findex;
STBIR__V_FIRST_INFO v_info = {0};
for(th=0;th<STBIR_RESIZE_CLASSIFICATIONS;th++)
{
curerr[th]=0;
curtot[th]=0;
}
for( findex = 0 ; findex < numfileinfo ; findex++ )
{
int * ts;
int ir;
ts = fi[findex].timings;
for( ir = 0 ; ir < fi[findex].numinputrects ; ir++ )
{
int ix, iy, chanind;
ix = fi[findex].inputrects[ir*2];
iy = fi[findex].inputrects[ir*2+1];
for( chanind = 0 ; chanind < fi[findex].numtypes ; chanind++ )
{
int h, hh;
// just do the type that we're on
if ( chanind != do_channel_count_index )
{
ts += 2 * fi[findex].dimensionx * fi[findex].dimensiony;
continue;
}
h = 1;
for( hh = 0 ; hh < fi[findex].dimensiony; hh++ )
{
int ww, w = 1;
for( ww = 0 ; ww < fi[findex].dimensionx; ww++ )
{
int good, v_first, VF, HF;
VF = ts[0];
HF = ts[1];
v_first = vert_first( weights_table, w, h, ix, iy, STBIR_FILTER_MITCHELL, &v_info );
good = ( ((HF<=VF) && (!v_first)) || ((VF<=HF) && (v_first)));
if ( !good )
{
double diff;
if ( VF < HF )
diff = ((double)HF-(double)VF) * fi[findex].scale_time;
else
diff = ((double)VF-(double)HF) * fi[findex].scale_time;
curtot[v_info.v_resize_classification] += 1;
curerr[v_info.v_resize_classification] += diff;
}
ts += 2;
w += fi[findex].outputscalex;
}
h += fi[findex].outputscaley;
}
}
}
}
}
#define TRIESPERWEIGHT 32
#define MAXRANGE ((TRIESPERWEIGHT+1) * (TRIESPERWEIGHT+1) * (TRIESPERWEIGHT+1) * (TRIESPERWEIGHT+1) - 1)
static void expand_to_floats( float * weights, int range )
{
weights[0] = (float)( range % (TRIESPERWEIGHT+1) ) / (float)TRIESPERWEIGHT;
weights[1] = (float)( range/(TRIESPERWEIGHT+1) % (TRIESPERWEIGHT+1) ) / (float)TRIESPERWEIGHT;
weights[2] = (float)( range/(TRIESPERWEIGHT+1)/(TRIESPERWEIGHT+1) % (TRIESPERWEIGHT+1) ) / (float)TRIESPERWEIGHT;
weights[3] = (float)( range/(TRIESPERWEIGHT+1)/(TRIESPERWEIGHT+1)/(TRIESPERWEIGHT+1) % (TRIESPERWEIGHT+1) ) / (float)TRIESPERWEIGHT;
}
static char const * expand_to_string( int range )
{
static char str[128];
int w0,w1,w2,w3;
w0 = range % (TRIESPERWEIGHT+1);
w1 = range/(TRIESPERWEIGHT+1) % (TRIESPERWEIGHT+1);
w2 = range/(TRIESPERWEIGHT+1)/(TRIESPERWEIGHT+1) % (TRIESPERWEIGHT+1);
w3 = range/(TRIESPERWEIGHT+1)/(TRIESPERWEIGHT+1)/(TRIESPERWEIGHT+1) % (TRIESPERWEIGHT+1);
sprintf( str, "[ %2d/%d %2d/%d %2d/%d %2d/%d ]",w0,TRIESPERWEIGHT,w1,TRIESPERWEIGHT,w2,TRIESPERWEIGHT,w3,TRIESPERWEIGHT );
return str;
}
static void print_weights( float weights[STBIR_RESIZE_CLASSIFICATIONS][4], int channel_count_index, int * tots, double * errs )
{
int th;
printf("ChInd: %d Weights:\n",channel_count_index);
for(th=0;th<STBIR_RESIZE_CLASSIFICATIONS;th++)
{
float * w = weights[th];
printf(" %d: [%1.5f %1.5f %1.5f %1.5f] (%d %.4f)\n",th, w[0], w[1], w[2], w[3], tots[th], errs[th] );
}
printf("\n");
}
static int windowranges[ 16 ];
static int windowstatus = 0;
static DWORD trainstart = 0;
static void opt_channel( float best_output_weights[STBIR_RESIZE_CLASSIFICATIONS][4], int channel_count_index )
{
int newbest = 0;
float weights[STBIR_RESIZE_CLASSIFICATIONS][4] = {0};
double besterr[STBIR_RESIZE_CLASSIFICATIONS];
int besttot[STBIR_RESIZE_CLASSIFICATIONS];
int best[STBIR_RESIZE_CLASSIFICATIONS]={0};
double curerr[STBIR_RESIZE_CLASSIFICATIONS];
int curtot[STBIR_RESIZE_CLASSIFICATIONS];
int th, range;
DWORD lasttick = 0;
for(th=0;th<STBIR_RESIZE_CLASSIFICATIONS;th++)
{
besterr[th]=1000000000000.0;
besttot[th]=0x7fffffff;
}
newbest = 0;
// try the whole range
range = MAXRANGE;
do
{
for(th=0;th<STBIR_RESIZE_CLASSIFICATIONS;th++)
expand_to_floats( weights[th], range );
calc_errors( weights, curtot, curerr, channel_count_index );
for(th=0;th<STBIR_RESIZE_CLASSIFICATIONS;th++)
{
if ( curerr[th] < besterr[th] )
{
besterr[th] = curerr[th];
besttot[th] = curtot[th];
best[th] = range;
expand_to_floats( best_output_weights[th], best[th] );
newbest = 1;
}
}
{
DWORD t = GetTickCount();
if ( range == 0 )
goto do_bitmap;
if ( newbest )
{
if ( ( GetTickCount() - lasttick ) > 200 )
{
int findex;
do_bitmap:
lasttick = t;
newbest = 0;
for( findex = 0 ; findex < numfileinfo ; findex++ )
build_bitmap( best_output_weights, channel_count_index, findex );
lasttick = GetTickCount();
}
}
}
windowranges[ channel_count_index ] = range;
// advance all the weights and loop
--range;
} while( ( range >= 0 ) && ( !windowstatus ) );
// if we hit here, then we tried all weights for this opt, so save them
}
static void print_struct( float weight[5][STBIR_RESIZE_CLASSIFICATIONS][4], char const * name )
{
printf("\n\nstatic float %s[5][STBIR_RESIZE_CLASSIFICATIONS][4]=\n{", name );
{
int i;
for(i=0;i<5;i++)
{
int th;
for(th=0;th<STBIR_RESIZE_CLASSIFICATIONS;th++)
{
int j;
printf("\n ");
for(j=0;j<4;j++)
printf("%1.5ff, ", weight[i][th][j] );
}
printf("\n");
}
printf("\n};\n");
}
}
static float retrain_weights[5][STBIR_RESIZE_CLASSIFICATIONS][4];
static DWORD __stdcall retrain_shim( LPVOID p )
{
int chanind = (int) (size_t)p;
opt_channel( retrain_weights[chanind], chanind );
return 0;
}
static char const * gettime( int ms )
{
static char time[32];
if (ms > 60000)
sprintf( time, "%dm %ds",ms/60000, (ms/1000)%60 );
else
sprintf( time, "%ds",ms/1000 );
return time;
}
static BITMAPINFOHEADER bmiHeader;
static DWORD extrawindoww, extrawindowh;
static HINSTANCE instance;
static int curzoom = 1;
static LRESULT WINAPI WindowProc( HWND window,
UINT message,
WPARAM wparam,
LPARAM lparam )
{
switch( message )
{
case WM_CHAR:
if ( wparam != 27 )
break;
// falls through
case WM_CLOSE:
{
int i;
int max = 0;
for( i = 0 ; i < fi[0].numtypes ; i++ )
if( windowranges[i] > max ) max = windowranges[i];
if ( ( max == 0 ) || ( MessageBox( window, "Cancel before training is finished?", "Vertical First Training", MB_OKCANCEL|MB_ICONSTOP ) == IDOK ) )
{
for( i = 0 ; i < fi[0].numtypes ; i++ )
if( windowranges[i] > max ) max = windowranges[i];
if ( max )
windowstatus = 1;
DestroyWindow( window );
}
}
return 0;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC dc;
dc = BeginPaint( window, &ps );
StretchDIBits( dc,
0, 0, bitmapw*curzoom, bitmaph*curzoom,
0, 0, bitmapw, bitmaph,
bitmap, (BITMAPINFO*)&bmiHeader, DIB_RGB_COLORS, SRCCOPY );
PatBlt( dc, bitmapw*curzoom, 0, 4096, 4096, WHITENESS );
PatBlt( dc, 0, bitmaph*curzoom, 4096, 4096, WHITENESS );
SetTextColor( dc, RGB(0,0,0) );
SetBkColor( dc, RGB(255,255,255) );
SetBkMode( dc, OPAQUE );
{
int i, l = 0, max = 0;
char buf[1024];
RECT rc;
POINT p;
for( i = 0 ; i < fi[0].numtypes ; i++ )
{
l += sprintf( buf + l, "channels: %d %s\n", fi[0].effective[i], windowranges[i] ? expand_to_string( windowranges[i] ) : "Done." );
if ( windowranges[i] > max ) max = windowranges[i];
}
rc.left = 32; rc.top = bitmaph*curzoom+10;
rc.right = 512; rc.bottom = rc.top + 512;
DrawText( dc, buf, -1, &rc, DT_TOP );
l = 0;
if ( max == 0 )
{
static DWORD traindone = 0;
if ( traindone == 0 ) traindone = GetTickCount();
l = sprintf( buf, "Finished in %s.", gettime( traindone - trainstart ) );
}
else if ( max != MAXRANGE )
l = sprintf( buf, "Done in %s...", gettime( (int) ( ( ( (int64)max * ( (int64)GetTickCount() - (int64)trainstart ) ) ) / (int64) ( MAXRANGE - max ) ) ) );
GetCursorPos( &p );
ScreenToClient( window, &p );
if ( ( p.x >= 0 ) && ( p.y >= 0 ) && ( p.x < (bitmapw*curzoom) ) && ( p.y < (bitmaph*curzoom) ) )
{
int findex;
int x, y, w, h, sx, sy, ix, iy, ox, oy;
int ir, chanind;
int * ts;
char badstr[64];
STBIR__V_FIRST_INFO v_info={0};
p.x /= curzoom;
p.y /= curzoom;
for( findex = 0 ; findex < numfileinfo ; findex++ )
{
x = fi[findex].bitmapx;
y = fi[findex].bitmapy;
w = x + ( fi[findex].dimensionx + 1 ) * fi[findex].numtypes;
h = y + ( fi[findex].dimensiony + 1 ) * fi[findex].numinputrects;
if ( ( p.x >= x ) && ( p.y >= y ) && ( p.x < w ) && ( p.y < h ) )
goto found;
}
goto nope;
found:
ir = ( p.y - y ) / ( fi[findex].dimensiony + 1 );
sy = ( p.y - y ) % ( fi[findex].dimensiony + 1 );
if ( sy >= fi[findex].dimensiony ) goto nope;
chanind = ( p.x - x ) / ( fi[findex].dimensionx + 1 );
sx = ( p.x - x ) % ( fi[findex].dimensionx + 1 );
if ( sx >= fi[findex].dimensionx ) goto nope;
ix = fi[findex].inputrects[ir*2];
iy = fi[findex].inputrects[ir*2+1];
ts = fi[findex].timings + ( ( fi[findex].dimensionx * fi[findex].dimensiony * fi[findex].numtypes * ir ) + ( fi[findex].dimensionx * fi[findex].dimensiony * chanind ) + ( fi[findex].dimensionx * sy ) + sx ) * 2;
ox = 1+fi[findex].outputscalex*sx;
oy = 1+fi[findex].outputscaley*sy;
if ( windowstatus != 2 )
{
int VF, HF, v_first, good;
VF = ts[0];
HF = ts[1];
v_first = vert_first( retrain_weights[chanind], ox, oy, ix, iy, STBIR_FILTER_MITCHELL, &v_info );
good = ( ((HF<=VF) && (!v_first)) || ((VF<=HF) && (v_first)));
if ( good )
badstr[0] = 0;
else
{
double r;
if ( HF < VF )
r = (double)(VF-HF)/(double)HF;
else
r = (double)(HF-VF)/(double)VF;
sprintf( badstr, " %.1f%% off", r*100 );
}
sprintf( buf + l, "\n\n%s\nCh: %d Resize: %dx%d to %dx%d\nV: %d H: %d Order: %c (%s%s)\nClass: %d Scale: %.2f %s", fi[findex].filename,fi[findex].effective[chanind], ix,iy,ox,oy, VF, HF, v_first?'V':'H', good?"Good":"Wrong", badstr, v_info.v_resize_classification, (double)oy/(double)iy, v_info.is_gather ? "Gather" : "Scatter" );
}
else
{
int v_first, time0, time1;
float (* weights)[4] = stbir__compute_weights[chanind];
int * ts1;
char b0[32], b1[32];
ts1 = fi[1].timings + ( ts - fi[0].timings );
v_first = vert_first( weights, ox, oy, ix, iy, STBIR_FILTER_MITCHELL, &v_info );
time0 = ( v_first ) ? ts[0] : ts[1];
time1 = ( v_first ) ? ts1[0] : ts1[1];
b0[0] = b1[0] = 0;
if ( time0 < time1 )
sprintf( b0," (%.f%% better)", ((double)time1-(double)time0)*100.0f/(double)time0);
else
sprintf( b1," (%.f%% better)", ((double)time0-(double)time1)*100.0f/(double)time1);
sprintf( buf + l, "\n\n0: %s\n1: %s\nCh: %d Resize: %dx%d to %dx%d\nClass: %d Scale: %.2f %s\nTime0: %d%s\nTime1: %d%s", fi[0].filename, fi[1].filename, fi[0].effective[chanind], ix,iy,ox,oy, v_info.v_resize_classification, (double)oy/(double)iy, v_info.is_gather ? "Gather" : "Scatter", time0, b0, time1, b1 );
}
}
nope:
rc.left = 32+320; rc.right = 512+320;
SetTextColor( dc, RGB(0,0,128) );
DrawText( dc, buf, -1, &rc, DT_TOP );
}
EndPaint( window, &ps );
return 0;
}
case WM_TIMER:
InvalidateRect( window, 0, 0 );
return 0;
case WM_DESTROY:
PostQuitMessage( 0 );
return 0;
}
return DefWindowProc( window, message, wparam, lparam );
}
static void SetHighDPI(void)
{
typedef HRESULT WINAPI setdpitype(int v);
HMODULE h=LoadLibrary("Shcore.dll");
if (h)
{
setdpitype * sd = (setdpitype*)GetProcAddress(h,"SetProcessDpiAwareness");
if (sd )
sd(1);
}
}
static void draw_window()
{
WNDCLASS wc;
HWND w;
MSG msg;
instance = GetModuleHandle(NULL);
wc.style = 0;
wc.lpfnWndProc = WindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = instance;
wc.hIcon = 0;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = 0;
wc.lpszMenuName = 0;
wc.lpszClassName = "WHTrain";
if ( !RegisterClass( &wc ) )
exit(1);
SetHighDPI();
bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmiHeader.biWidth = bitmapp/3;
bmiHeader.biHeight = -bitmaph;
bmiHeader.biPlanes = 1;
bmiHeader.biBitCount = 24;
bmiHeader.biCompression = BI_RGB;
w = CreateWindow( "WHTrain",
"Vertical First Training",
WS_CAPTION | WS_POPUP| WS_CLIPCHILDREN |
WS_SYSMENU | WS_MINIMIZEBOX | WS_SIZEBOX,
CW_USEDEFAULT,CW_USEDEFAULT,
CW_USEDEFAULT,CW_USEDEFAULT,
0, 0, instance, 0 );
{
RECT r, c;
GetWindowRect( w, &r );
GetClientRect( w, &c );
extrawindoww = ( r.right - r.left ) - ( c.right - c.left );
extrawindowh = ( r.bottom - r.top ) - ( c.bottom - c.top );
SetWindowPos( w, 0, 0, 0, bitmapw * curzoom + extrawindoww, bitmaph * curzoom + extrawindowh + 164, SWP_NOMOVE );
}
ShowWindow( w, SW_SHOWNORMAL );
SetTimer( w, 1, 250, 0 );
{
BOOL ret;
while( ( ret = GetMessage( &msg, w, 0, 0 ) ) != 0 )
{
if ( ret == -1 )
break;
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
}
static void retrain()
{
HANDLE threads[ 16 ];
int chanind;
trainstart = GetTickCount();
for( chanind = 0 ; chanind < fi[0].numtypes ; chanind++ )
threads[ chanind ] = CreateThread( 0, 2048*1024, retrain_shim, (LPVOID)(size_t)chanind, 0, 0 );
draw_window();
for( chanind = 0 ; chanind < fi[0].numtypes ; chanind++ )
{
WaitForSingleObject( threads[ chanind ], INFINITE );
CloseHandle( threads[ chanind ] );
}
write_bitmap();
print_struct( retrain_weights, "retained_weights" );
if ( windowstatus ) printf( "CANCELLED!\n" );
}
static void info()
{
int findex;
// display info about each input file
for( findex = 0 ; findex < numfileinfo ; findex++ )
{
int i, h,m,s;
if ( findex ) printf( "\n" );
printf( "Timing file: %s\n", fi[findex].filename );
printf( "CPU type: %d %s\n", fi[findex].cpu, fi[findex].simd?(fi[findex].simd==2?"SIMD8":"SIMD4"):"Scalar" );
h = fi[findex].milliseconds/3600000;
m = (fi[findex].milliseconds-h*3600000)/60000;
s = (fi[findex].milliseconds-h*3600000-m*60000)/1000;
printf( "Total time in test: %dh %dm %ds Cycles/sec: %.f\n", h,m,s, 1000.0/fi[findex].scale_time );
printf( "Each tile of samples is %dx%d, and is scaled by %dx%d.\n", fi[findex].dimensionx,fi[findex].dimensiony, fi[findex].outputscalex,fi[findex].outputscaley );
printf( "So the x coords are: " );
for( i=0; i < fi[findex].dimensionx ; i++ ) printf( "%d ",1+i*fi[findex].outputscalex );
printf( "\n" );
printf( "And the y coords are: " );
for( i=0; i < fi[findex].dimensiony ; i++ ) printf( "%d ",1+i*fi[findex].outputscaley );
printf( "\n" );
printf( "There are %d channel counts and they are: ", fi[findex].numtypes );
for( i=0; i < fi[findex].numtypes ; i++ ) printf( "%d ",fi[findex].effective[i] );
printf( "\n" );
printf( "There are %d input rect sizes and they are: ", fi[findex].numinputrects );
for( i=0; i < fi[findex].numtypes ; i++ ) printf( "%dx%d ",fi[findex].inputrects[i*2],fi[findex].inputrects[i*2+1] );
printf( "\n" );
}
}
static void current( int do_win, int do_bitmap )
{
int i, findex;
trainstart = GetTickCount();
// clear progress
memset( windowranges, 0, sizeof( windowranges ) );
// copy in appropriate weights
memcpy( retrain_weights, stbir__compute_weights, sizeof( retrain_weights ) );
// build and print current errors and build current bitmap
for( i = 0 ; i < fi[0].numtypes ; i++ )
{
double curerr[STBIR_RESIZE_CLASSIFICATIONS];
int curtot[STBIR_RESIZE_CLASSIFICATIONS];
float (* weights)[4] = retrain_weights[i];
calc_errors( weights, curtot, curerr, i );
if ( !do_bitmap )
print_weights( weights, i, curtot, curerr );
for( findex = 0 ; findex < numfileinfo ; findex++ )
build_bitmap( weights, i, findex );
}
if ( do_win )
draw_window();
if ( do_bitmap )
write_bitmap();
}
static void compare()
{
int i;
trainstart = GetTickCount();
windowstatus = 2; // comp mode
// clear progress
memset( windowranges, 0, sizeof( windowranges ) );
if ( ( fi[0].numtypes != fi[1].numtypes ) || ( fi[0].numinputrects != fi[1].numinputrects ) ||
( fi[0].dimensionx != fi[1].dimensionx ) || ( fi[0].dimensiony != fi[1].dimensiony ) ||
( fi[0].outputscalex != fi[1].outputscalex ) || ( fi[0].outputscaley != fi[1].outputscaley ) )
{
err:
printf( "Timing files don't match.\n" );
exit(5);
}
for( i=0; i < fi[0].numtypes ; i++ )
{
if ( fi[0].effective[i] != fi[1].effective[i] ) goto err;
if ( fi[0].inputrects[i*2] != fi[1].inputrects[i*2] ) goto err;
if ( fi[0].inputrects[i*2+1] != fi[1].inputrects[i*2+1] ) goto err;
}
alloc_bitmap( 1 );
for( i = 0 ; i < fi[0].numtypes ; i++ )
{
float (* weights)[4] = stbir__compute_weights[i];
build_comp_bitmap( weights, i );
}
draw_window();
}
static void load_files( char ** args, int count )
{
int i;
if ( count == 0 )
{
printf( "No timing files listed!" );
exit(3);
}
for ( i = 0 ; i < count ; i++ )
{
if ( !use_timing_file( args[i], i ) )
{
printf( "Bad timing file %s\n", args[i] );
exit(2);
}
}
numfileinfo = count;
}
int main( int argc, char ** argv )
{
int check;
if ( argc < 3 )
{
err:
printf( "vf_train retrain [timing_filenames....] - recalcs weights for all the files on the command line.\n");
printf( "vf_train info [timing_filenames....] - shows info about each timing file.\n");
printf( "vf_train check [timing_filenames...] - show results for the current weights for all files listed.\n");
printf( "vf_train compare <timing file1> <timing file2> - compare two timing files (must only be two files and same resolution).\n");
printf( "vf_train bitmap [timing_filenames...] - write out results.png, comparing against the current weights for all files listed.\n");
exit(1);
}
check = ( strcmp( argv[1], "check" ) == 0 );
if ( ( check ) || ( strcmp( argv[1], "bitmap" ) == 0 ) )
{
load_files( argv + 2, argc - 2 );
alloc_bitmap( numfileinfo );
current( check, !check );
}
else if ( strcmp( argv[1], "info" ) == 0 )
{
load_files( argv + 2, argc - 2 );
info();
}
else if ( strcmp( argv[1], "compare" ) == 0 )
{
if ( argc != 4 )
{
printf( "You must specify two files to compare.\n" );
exit(4);
}
load_files( argv + 2, argc - 2 );
compare();
}
else if ( strcmp( argv[1], "retrain" ) == 0 )
{
load_files( argv + 2, argc - 2 );
alloc_bitmap( numfileinfo );
retrain();
}
else
{
goto err;
}
return 0;
}

View File

@ -66,7 +66,10 @@ static char *stb_include_load_file(char *filename, size_t *plen)
len = (size_t) ftell(f);
if (plen) *plen = len;
text = (char *) malloc(len+1);
if (text == 0) return 0;
if (text == 0) {
fclose(f);
return 0;
}
fseek(f, 0, SEEK_SET);
fread(text, 1, len, f);
fclose(f);

View File

@ -0,0 +1,259 @@
filename,width,height,ncomp,error,hash
pngsuite/16bit/basi0g16.png,32,32,1,,0xfc8f2f99
pngsuite/16bit/basi2c16.png,32,32,3,,0x65567ed5
pngsuite/16bit/basi4a16.png,32,32,2,,0x198cf245
pngsuite/16bit/basi6a16.png,32,32,4,,0x3016e9b5
pngsuite/16bit/basn0g16.png,32,32,1,,0xfc8f2f99
pngsuite/16bit/basn2c16.png,32,32,3,,0x65567ed5
pngsuite/16bit/basn4a16.png,32,32,2,,0x198cf245
pngsuite/16bit/basn6a16.png,32,32,4,,0x3016e9b5
pngsuite/16bit/bgai4a16.png,32,32,2,,0x198cf245
pngsuite/16bit/bgan6a16.png,32,32,4,,0x3016e9b5
pngsuite/16bit/bggn4a16.png,32,32,2,,0x198cf245
pngsuite/16bit/bgyn6a16.png,32,32,4,,0x3016e9b5
pngsuite/16bit/oi1n0g16.png,32,32,1,,0xfc8f2f99
pngsuite/16bit/oi1n2c16.png,32,32,3,,0x65567ed5
pngsuite/16bit/oi2n0g16.png,32,32,1,,0xfc8f2f99
pngsuite/16bit/oi2n2c16.png,32,32,3,,0x65567ed5
pngsuite/16bit/oi4n0g16.png,32,32,1,,0xfc8f2f99
pngsuite/16bit/oi4n2c16.png,32,32,3,,0x65567ed5
pngsuite/16bit/oi9n0g16.png,32,32,1,,0xfc8f2f99
pngsuite/16bit/oi9n2c16.png,32,32,3,,0x65567ed5
pngsuite/16bit/tbbn2c16.png,32,32,4,,0xaa9bfe44
pngsuite/16bit/tbgn2c16.png,32,32,4,,0xaa9bfe44
pngsuite/16bit/tbwn0g16.png,32,32,2,,0x075e519a
pngsuite/corrupt/xc1n0g08.png,32,32,2,bad ctype,0x00000000
pngsuite/corrupt/xc9n2c08.png,32,32,2,bad ctype,0x00000000
pngsuite/corrupt/xcrn0g04.png,32,32,2,unknown image type,0x00000000
pngsuite/corrupt/xcsn0g01.png,32,32,1,,0x43b9891f
pngsuite/corrupt/xd0n2c08.png,32,32,1,1/2/4/8/16-bit only,0x00000000
pngsuite/corrupt/xd3n2c08.png,32,32,1,1/2/4/8/16-bit only,0x00000000
pngsuite/corrupt/xd9n2c08.png,32,32,1,1/2/4/8/16-bit only,0x00000000
pngsuite/corrupt/xdtn0g01.png,32,32,1,no IDAT,0x00000000
pngsuite/corrupt/xhdn0g08.png,32,32,1,,0x414f1ca9
pngsuite/corrupt/xlfn0g04.png,32,32,1,unknown image type,0x00000000
pngsuite/corrupt/xs1n0g01.png,32,32,1,unknown image type,0x00000000
pngsuite/corrupt/xs2n0g01.png,32,32,1,unknown image type,0x00000000
pngsuite/corrupt/xs4n0g01.png,32,32,1,unknown image type,0x00000000
pngsuite/corrupt/xs7n0g01.png,32,32,1,unknown image type,0x00000000
pngsuite/iphone/iphone_basi0g01.png,32,32,4,,0x5fb33cfd
pngsuite/iphone/iphone_basi0g02.png,32,32,4,,0x5bbe95c5
pngsuite/iphone/iphone_basi3p02.png,32,32,4,,0x50ba29c5
pngsuite/iphone/iphone_bgwn6a08.png,32,32,4,,0x45d8548a
pngsuite/iphone/iphone_bgyn6a16.png,32,32,4,,0x4b2b7545
pngsuite/iphone/iphone_tbyn3p08.png,32,32,4,,0x8ea9aaaf
pngsuite/iphone/iphone_z06n2c08.png,32,32,4,,0xb5dd034b
pngsuite/primary/basi0g01.png,32,32,1,,0x43b9891f
pngsuite/primary/basi0g02.png,32,32,1,,0xaf0bb3c5
pngsuite/primary/basi0g04.png,32,32,1,,0x6fbaeb45
pngsuite/primary/basi0g08.png,32,32,1,,0x414f1ca9
pngsuite/primary/basi2c08.png,32,32,3,,0x522345c5
pngsuite/primary/basi3p01.png,32,32,3,,0x9c5b75c5
pngsuite/primary/basi3p02.png,32,32,3,,0x46f26ec5
pngsuite/primary/basi3p04.png,32,32,3,,0x35b2e4a5
pngsuite/primary/basi3p08.png,32,32,3,,0xfe066865
pngsuite/primary/basi4a08.png,32,32,2,,0x77cbbfa5
pngsuite/primary/basi6a08.png,32,32,4,,0xb472197d
pngsuite/primary/basn0g01.png,32,32,1,,0x43b9891f
pngsuite/primary/basn0g02.png,32,32,1,,0xaf0bb3c5
pngsuite/primary/basn0g04.png,32,32,1,,0x6fbaeb45
pngsuite/primary/basn0g08.png,32,32,1,,0x414f1ca9
pngsuite/primary/basn2c08.png,32,32,3,,0x522345c5
pngsuite/primary/basn3p01.png,32,32,3,,0x9c5b75c5
pngsuite/primary/basn3p02.png,32,32,3,,0x46f26ec5
pngsuite/primary/basn3p04.png,32,32,3,,0x35b2e4a5
pngsuite/primary/basn3p08.png,32,32,3,,0xfe066865
pngsuite/primary/basn4a08.png,32,32,2,,0x77cbbfa5
pngsuite/primary/basn6a08.png,32,32,4,,0xb472197d
pngsuite/primary/bgai4a08.png,32,32,2,,0x77cbbfa5
pngsuite/primary/bgan6a08.png,32,32,4,,0xb472197d
pngsuite/primary/bgbn4a08.png,32,32,2,,0x77cbbfa5
pngsuite/primary/bgwn6a08.png,32,32,4,,0xb472197d
pngsuite/primary/s01i3p01.png,1,1,3,,0xafb003b6
pngsuite/primary/s01n3p01.png,1,1,3,,0xafb003b6
pngsuite/primary/s02i3p01.png,2,2,3,,0x96f3dd85
pngsuite/primary/s02n3p01.png,2,2,3,,0x96f3dd85
pngsuite/primary/s03i3p01.png,3,3,3,,0xb0cf1241
pngsuite/primary/s03n3p01.png,3,3,3,,0xb0cf1241
pngsuite/primary/s04i3p01.png,4,4,3,,0xbfcedd75
pngsuite/primary/s04n3p01.png,4,4,3,,0xbfcedd75
pngsuite/primary/s05i3p02.png,5,5,3,,0xc322cedd
pngsuite/primary/s05n3p02.png,5,5,3,,0xc322cedd
pngsuite/primary/s06i3p02.png,6,6,3,,0x46916799
pngsuite/primary/s06n3p02.png,6,6,3,,0x46916799
pngsuite/primary/s07i3p02.png,7,7,3,,0xfdabc297
pngsuite/primary/s07n3p02.png,7,7,3,,0xfdabc297
pngsuite/primary/s08i3p02.png,8,8,3,,0x8f036d09
pngsuite/primary/s08n3p02.png,8,8,3,,0x8f036d09
pngsuite/primary/s09i3p02.png,9,9,3,,0x16a46830
pngsuite/primary/s09n3p02.png,9,9,3,,0x16a46830
pngsuite/primary/s32i3p04.png,32,32,3,,0x4bd4fbd3
pngsuite/primary/s32n3p04.png,32,32,3,,0x4bd4fbd3
pngsuite/primary/s33i3p04.png,33,33,3,,0x51aa005e
pngsuite/primary/s33n3p04.png,33,33,3,,0x51aa005e
pngsuite/primary/s34i3p04.png,34,34,3,,0x84818775
pngsuite/primary/s34n3p04.png,34,34,3,,0x84818775
pngsuite/primary/s35i3p04.png,35,35,3,,0x6359ec75
pngsuite/primary/s35n3p04.png,35,35,3,,0x6359ec75
pngsuite/primary/s36i3p04.png,36,36,3,,0xe4878065
pngsuite/primary/s36n3p04.png,36,36,3,,0xe4878065
pngsuite/primary/s37i3p04.png,37,37,3,,0x3cefc423
pngsuite/primary/s37n3p04.png,37,37,3,,0x3cefc423
pngsuite/primary/s38i3p04.png,38,38,3,,0xffc55a2b
pngsuite/primary/s38n3p04.png,38,38,3,,0xffc55a2b
pngsuite/primary/s39i3p04.png,39,39,3,,0x0c790240
pngsuite/primary/s39n3p04.png,39,39,3,,0x0c790240
pngsuite/primary/s40i3p04.png,40,40,3,,0x951a316d
pngsuite/primary/s40n3p04.png,40,40,3,,0x951a316d
pngsuite/primary/tbbn0g04.png,32,32,2,,0x9c8410ea
pngsuite/primary/tbbn3p08.png,32,32,4,,0x82bf9a57
pngsuite/primary/tbgn3p08.png,32,32,4,,0x82bf9a57
pngsuite/primary/tbrn2c08.png,32,32,4,,0xaa9bfe44
pngsuite/primary/tbwn3p08.png,32,32,4,,0x82bf9a57
pngsuite/primary/tbyn3p08.png,32,32,4,,0x82bf9a57
pngsuite/primary/tm3n3p02.png,32,32,4,,0xf59745c5
pngsuite/primary/tp0n0g08.png,32,32,1,,0xbac0864c
pngsuite/primary/tp0n2c08.png,32,32,3,,0x82687c37
pngsuite/primary/tp0n3p08.png,32,32,3,,0x61f54e37
pngsuite/primary/tp1n3p08.png,32,32,4,,0x82bf9a57
pngsuite/primary/z00n2c08.png,32,32,3,,0x65b4a72f
pngsuite/primary/z03n2c08.png,32,32,3,,0x65b4a72f
pngsuite/primary/z06n2c08.png,32,32,3,,0x65b4a72f
pngsuite/primary/z09n2c08.png,32,32,3,,0x65b4a72f
pngsuite/primary_check/basi0g01.png,32,32,4,,0x5fb33cfd
pngsuite/primary_check/basi0g02.png,32,32,4,,0x5bbe95c5
pngsuite/primary_check/basi0g04.png,32,32,4,,0x3468b9c5
pngsuite/primary_check/basi0g08.png,32,32,4,,0x262ef46d
pngsuite/primary_check/basi2c08.png,32,32,4,,0x1fc92bc5
pngsuite/primary_check/basi3p01.png,32,32,4,,0x28a3e1c5
pngsuite/primary_check/basi3p02.png,32,32,4,,0x803be5c5
pngsuite/primary_check/basi3p04.png,32,32,4,,0xf3fc60e5
pngsuite/primary_check/basi3p08.png,32,32,4,,0x30ef4f45
pngsuite/primary_check/basi4a08.png,32,32,4,,0x23c8536d
pngsuite/primary_check/basi6a08.png,32,32,4,,0xb472197d
pngsuite/primary_check/basn0g01.png,32,32,4,,0x5fb33cfd
pngsuite/primary_check/basn0g02.png,32,32,4,,0x5bbe95c5
pngsuite/primary_check/basn0g04.png,32,32,4,,0x3468b9c5
pngsuite/primary_check/basn0g08.png,32,32,4,,0x262ef46d
pngsuite/primary_check/basn2c08.png,32,32,4,,0x1fc92bc5
pngsuite/primary_check/basn3p01.png,32,32,4,,0x28a3e1c5
pngsuite/primary_check/basn3p02.png,32,32,4,,0x803be5c5
pngsuite/primary_check/basn3p04.png,32,32,4,,0xf3fc60e5
pngsuite/primary_check/basn3p08.png,32,32,4,,0x30ef4f45
pngsuite/primary_check/basn4a08.png,32,32,4,,0x23c8536d
pngsuite/primary_check/basn6a08.png,32,32,4,,0xb472197d
pngsuite/primary_check/bgai4a08.png,32,32,4,,0x23c8536d
pngsuite/primary_check/bgan6a08.png,32,32,4,,0xb472197d
pngsuite/primary_check/bgbn4a08.png,32,32,4,,0x23c8536d
pngsuite/primary_check/bgwn6a08.png,32,32,4,,0xb472197d
pngsuite/primary_check/s01i3p01.png,1,1,4,,0xdb152beb
pngsuite/primary_check/s01n3p01.png,1,1,4,,0xdb152beb
pngsuite/primary_check/s02i3p01.png,2,2,4,,0xa344a3a5
pngsuite/primary_check/s02n3p01.png,2,2,4,,0xa344a3a5
pngsuite/primary_check/s03i3p01.png,3,3,4,,0x594d3bfa
pngsuite/primary_check/s03n3p01.png,3,3,4,,0x594d3bfa
pngsuite/primary_check/s04i3p01.png,4,4,4,,0xd59d4605
pngsuite/primary_check/s04n3p01.png,4,4,4,,0xd59d4605
pngsuite/primary_check/s05i3p02.png,5,5,4,,0x41e58366
pngsuite/primary_check/s05n3p02.png,5,5,4,,0x41e58366
pngsuite/primary_check/s06i3p02.png,6,6,4,,0xcad1a885
pngsuite/primary_check/s06n3p02.png,6,6,4,,0xcad1a885
pngsuite/primary_check/s07i3p02.png,7,7,4,,0x09184108
pngsuite/primary_check/s07n3p02.png,7,7,4,,0x09184108
pngsuite/primary_check/s08i3p02.png,8,8,4,,0x4fd11cad
pngsuite/primary_check/s08n3p02.png,8,8,4,,0x4fd11cad
pngsuite/primary_check/s09i3p02.png,9,9,4,,0xc50dbecd
pngsuite/primary_check/s09n3p02.png,9,9,4,,0xc50dbecd
pngsuite/primary_check/s32i3p04.png,32,32,4,,0x95cbb1d3
pngsuite/primary_check/s32n3p04.png,32,32,4,,0x95cbb1d3
pngsuite/primary_check/s33i3p04.png,33,33,4,,0x6649fc5b
pngsuite/primary_check/s33n3p04.png,33,33,4,,0x6649fc5b
pngsuite/primary_check/s34i3p04.png,34,34,4,,0x35b98e15
pngsuite/primary_check/s34n3p04.png,34,34,4,,0x35b98e15
pngsuite/primary_check/s35i3p04.png,35,35,4,,0xc9ddf938
pngsuite/primary_check/s35n3p04.png,35,35,4,,0xc9ddf938
pngsuite/primary_check/s36i3p04.png,36,36,4,,0x7bb4e1cd
pngsuite/primary_check/s36n3p04.png,36,36,4,,0x7bb4e1cd
pngsuite/primary_check/s37i3p04.png,37,37,4,,0xee50001c
pngsuite/primary_check/s37n3p04.png,37,37,4,,0xee50001c
pngsuite/primary_check/s38i3p04.png,38,38,4,,0x51b76813
pngsuite/primary_check/s38n3p04.png,38,38,4,,0x51b76813
pngsuite/primary_check/s39i3p04.png,39,39,4,,0x42f23327
pngsuite/primary_check/s39n3p04.png,39,39,4,,0x42f23327
pngsuite/primary_check/s40i3p04.png,40,40,4,,0xf91b6a7d
pngsuite/primary_check/s40n3p04.png,40,40,4,,0xf91b6a7d
pngsuite/primary_check/tbbn0g04.png,32,32,4,,0x8a0117a4
pngsuite/primary_check/tbbn3p08.png,32,32,4,,0x82bf9a57
pngsuite/primary_check/tbgn3p08.png,32,32,4,,0x82bf9a57
pngsuite/primary_check/tbrn2c08.png,32,32,4,,0xaa9bfe44
pngsuite/primary_check/tbwn3p08.png,32,32,4,,0x82bf9a57
pngsuite/primary_check/tbyn3p08.png,32,32,4,,0x82bf9a57
pngsuite/primary_check/tm3n3p02.png,32,32,4,,0xf59745c5
pngsuite/primary_check/tp0n0g08.png,32,32,4,,0xd405ad2e
pngsuite/primary_check/tp0n2c08.png,32,32,4,,0x5a66ca09
pngsuite/primary_check/tp0n3p08.png,32,32,4,,0x06e81adf
pngsuite/primary_check/tp1n3p08.png,32,32,4,,0x82bf9a57
pngsuite/primary_check/z00n2c08.png,32,32,4,,0xaa698493
pngsuite/primary_check/z03n2c08.png,32,32,4,,0xaa698493
pngsuite/primary_check/z06n2c08.png,32,32,4,,0xaa698493
pngsuite/primary_check/z09n2c08.png,32,32,4,,0xaa698493
pngsuite/unused/ccwn2c08.png,32,32,3,,0xbb576418
pngsuite/unused/ccwn3p08.png,32,32,3,,0x5c4df060
pngsuite/unused/cdfn2c08.png,8,32,3,,0xe30ed48f
pngsuite/unused/cdhn2c08.png,32,8,3,,0x999321f5
pngsuite/unused/cdsn2c08.png,8,8,3,,0x7f63fa01
pngsuite/unused/cdun2c08.png,32,32,3,,0xbd325d71
pngsuite/unused/ch1n3p04.png,32,32,3,,0x35b2e4a5
pngsuite/unused/ch2n3p08.png,32,32,3,,0xfe066865
pngsuite/unused/cm0n0g04.png,32,32,1,,0xe9f53e6c
pngsuite/unused/cm7n0g04.png,32,32,1,,0xe9f53e6c
pngsuite/unused/cm9n0g04.png,32,32,1,,0xe9f53e6c
pngsuite/unused/cs3n2c16.png,32,32,3,,0x7f0fa2c5
pngsuite/unused/cs3n3p08.png,32,32,3,,0x5533bac5
pngsuite/unused/cs5n2c08.png,32,32,3,,0x8a80f8c5
pngsuite/unused/cs5n3p08.png,32,32,3,,0x8a80f8c5
pngsuite/unused/cs8n2c08.png,32,32,3,,0x7f0fa2c5
pngsuite/unused/cs8n3p08.png,32,32,3,,0x7f0fa2c5
pngsuite/unused/ct0n0g04.png,32,32,1,,0xe9f53e6c
pngsuite/unused/ct1n0g04.png,32,32,1,,0xe9f53e6c
pngsuite/unused/cten0g04.png,32,32,1,,0x1c073b45
pngsuite/unused/ctfn0g04.png,32,32,1,,0xfa9fd205
pngsuite/unused/ctgn0g04.png,32,32,1,,0xf28c8085
pngsuite/unused/cthn0g04.png,32,32,1,,0x7c039595
pngsuite/unused/ctjn0g04.png,32,32,1,,0xc520f455
pngsuite/unused/ctzn0g04.png,32,32,1,,0xe9f53e6c
pngsuite/unused/f00n0g08.png,32,32,1,,0x21db411b
pngsuite/unused/f00n2c08.png,32,32,3,,0x1f25ded0
pngsuite/unused/f01n0g08.png,32,32,1,,0x7437b32a
pngsuite/unused/f01n2c08.png,32,32,3,,0x0d4507ae
pngsuite/unused/f02n0g08.png,32,32,1,,0x6b633c7c
pngsuite/unused/f02n2c08.png,32,32,3,,0x4b278986
pngsuite/unused/f03n0g08.png,32,32,1,,0x2f31c08e
pngsuite/unused/f03n2c08.png,32,32,3,,0x843ecc7e
pngsuite/unused/f04n0g08.png,32,32,1,,0xfd3a0b73
pngsuite/unused/f04n2c08.png,32,32,3,,0x557174bc
pngsuite/unused/f99n0g04.png,32,32,1,,0xb79aa6e1
pngsuite/unused/g03n0g16.png,32,32,1,,0xecd13817
pngsuite/unused/g03n2c08.png,32,32,3,,0x242407a8
pngsuite/unused/g03n3p04.png,32,32,3,,0xe801ecc8
pngsuite/unused/g04n0g16.png,32,32,1,,0xc11bc972
pngsuite/unused/g04n2c08.png,32,32,3,,0xdf843cc4
pngsuite/unused/g04n3p04.png,32,32,3,,0x60e41f3b
pngsuite/unused/g05n0g16.png,32,32,1,,0xbe6615a5
pngsuite/unused/g05n2c08.png,32,32,3,,0x5c312116
pngsuite/unused/g05n3p04.png,32,32,3,,0x2e0fbf86
pngsuite/unused/g07n0g16.png,32,32,1,,0x2b54a398
pngsuite/unused/g07n2c08.png,32,32,3,,0xf765fb10
pngsuite/unused/g07n3p04.png,32,32,3,,0x9a8c3338
pngsuite/unused/g10n0g16.png,32,32,1,,0xb08a92e1
pngsuite/unused/g10n2c08.png,32,32,3,,0xa43f2291
pngsuite/unused/g10n3p04.png,32,32,3,,0xb733194c
pngsuite/unused/g25n0g16.png,32,32,1,,0xa6b1f5dd
pngsuite/unused/g25n2c08.png,32,32,3,,0x767aee0c
pngsuite/unused/g25n3p04.png,32,32,3,,0x4cf349a8
pngsuite/unused/pp0n2c16.png,32,32,3,,0x65567ed5
pngsuite/unused/pp0n6a08.png,32,32,4,,0x3188c645
pngsuite/unused/ps1n0g08.png,32,32,1,,0x414f1ca9
pngsuite/unused/ps1n2c16.png,32,32,3,,0x65567ed5
pngsuite/unused/ps2n0g08.png,32,32,1,,0x414f1ca9
pngsuite/unused/ps2n2c16.png,32,32,3,,0x65567ed5
1 filename width height ncomp error hash
2 pngsuite/16bit/basi0g16.png 32 32 1 0xfc8f2f99
3 pngsuite/16bit/basi2c16.png 32 32 3 0x65567ed5
4 pngsuite/16bit/basi4a16.png 32 32 2 0x198cf245
5 pngsuite/16bit/basi6a16.png 32 32 4 0x3016e9b5
6 pngsuite/16bit/basn0g16.png 32 32 1 0xfc8f2f99
7 pngsuite/16bit/basn2c16.png 32 32 3 0x65567ed5
8 pngsuite/16bit/basn4a16.png 32 32 2 0x198cf245
9 pngsuite/16bit/basn6a16.png 32 32 4 0x3016e9b5
10 pngsuite/16bit/bgai4a16.png 32 32 2 0x198cf245
11 pngsuite/16bit/bgan6a16.png 32 32 4 0x3016e9b5
12 pngsuite/16bit/bggn4a16.png 32 32 2 0x198cf245
13 pngsuite/16bit/bgyn6a16.png 32 32 4 0x3016e9b5
14 pngsuite/16bit/oi1n0g16.png 32 32 1 0xfc8f2f99
15 pngsuite/16bit/oi1n2c16.png 32 32 3 0x65567ed5
16 pngsuite/16bit/oi2n0g16.png 32 32 1 0xfc8f2f99
17 pngsuite/16bit/oi2n2c16.png 32 32 3 0x65567ed5
18 pngsuite/16bit/oi4n0g16.png 32 32 1 0xfc8f2f99
19 pngsuite/16bit/oi4n2c16.png 32 32 3 0x65567ed5
20 pngsuite/16bit/oi9n0g16.png 32 32 1 0xfc8f2f99
21 pngsuite/16bit/oi9n2c16.png 32 32 3 0x65567ed5
22 pngsuite/16bit/tbbn2c16.png 32 32 4 0xaa9bfe44
23 pngsuite/16bit/tbgn2c16.png 32 32 4 0xaa9bfe44
24 pngsuite/16bit/tbwn0g16.png 32 32 2 0x075e519a
25 pngsuite/corrupt/xc1n0g08.png 32 32 2 bad ctype 0x00000000
26 pngsuite/corrupt/xc9n2c08.png 32 32 2 bad ctype 0x00000000
27 pngsuite/corrupt/xcrn0g04.png 32 32 2 unknown image type 0x00000000
28 pngsuite/corrupt/xcsn0g01.png 32 32 1 0x43b9891f
29 pngsuite/corrupt/xd0n2c08.png 32 32 1 1/2/4/8/16-bit only 0x00000000
30 pngsuite/corrupt/xd3n2c08.png 32 32 1 1/2/4/8/16-bit only 0x00000000
31 pngsuite/corrupt/xd9n2c08.png 32 32 1 1/2/4/8/16-bit only 0x00000000
32 pngsuite/corrupt/xdtn0g01.png 32 32 1 no IDAT 0x00000000
33 pngsuite/corrupt/xhdn0g08.png 32 32 1 0x414f1ca9
34 pngsuite/corrupt/xlfn0g04.png 32 32 1 unknown image type 0x00000000
35 pngsuite/corrupt/xs1n0g01.png 32 32 1 unknown image type 0x00000000
36 pngsuite/corrupt/xs2n0g01.png 32 32 1 unknown image type 0x00000000
37 pngsuite/corrupt/xs4n0g01.png 32 32 1 unknown image type 0x00000000
38 pngsuite/corrupt/xs7n0g01.png 32 32 1 unknown image type 0x00000000
39 pngsuite/iphone/iphone_basi0g01.png 32 32 4 0x5fb33cfd
40 pngsuite/iphone/iphone_basi0g02.png 32 32 4 0x5bbe95c5
41 pngsuite/iphone/iphone_basi3p02.png 32 32 4 0x50ba29c5
42 pngsuite/iphone/iphone_bgwn6a08.png 32 32 4 0x45d8548a
43 pngsuite/iphone/iphone_bgyn6a16.png 32 32 4 0x4b2b7545
44 pngsuite/iphone/iphone_tbyn3p08.png 32 32 4 0x8ea9aaaf
45 pngsuite/iphone/iphone_z06n2c08.png 32 32 4 0xb5dd034b
46 pngsuite/primary/basi0g01.png 32 32 1 0x43b9891f
47 pngsuite/primary/basi0g02.png 32 32 1 0xaf0bb3c5
48 pngsuite/primary/basi0g04.png 32 32 1 0x6fbaeb45
49 pngsuite/primary/basi0g08.png 32 32 1 0x414f1ca9
50 pngsuite/primary/basi2c08.png 32 32 3 0x522345c5
51 pngsuite/primary/basi3p01.png 32 32 3 0x9c5b75c5
52 pngsuite/primary/basi3p02.png 32 32 3 0x46f26ec5
53 pngsuite/primary/basi3p04.png 32 32 3 0x35b2e4a5
54 pngsuite/primary/basi3p08.png 32 32 3 0xfe066865
55 pngsuite/primary/basi4a08.png 32 32 2 0x77cbbfa5
56 pngsuite/primary/basi6a08.png 32 32 4 0xb472197d
57 pngsuite/primary/basn0g01.png 32 32 1 0x43b9891f
58 pngsuite/primary/basn0g02.png 32 32 1 0xaf0bb3c5
59 pngsuite/primary/basn0g04.png 32 32 1 0x6fbaeb45
60 pngsuite/primary/basn0g08.png 32 32 1 0x414f1ca9
61 pngsuite/primary/basn2c08.png 32 32 3 0x522345c5
62 pngsuite/primary/basn3p01.png 32 32 3 0x9c5b75c5
63 pngsuite/primary/basn3p02.png 32 32 3 0x46f26ec5
64 pngsuite/primary/basn3p04.png 32 32 3 0x35b2e4a5
65 pngsuite/primary/basn3p08.png 32 32 3 0xfe066865
66 pngsuite/primary/basn4a08.png 32 32 2 0x77cbbfa5
67 pngsuite/primary/basn6a08.png 32 32 4 0xb472197d
68 pngsuite/primary/bgai4a08.png 32 32 2 0x77cbbfa5
69 pngsuite/primary/bgan6a08.png 32 32 4 0xb472197d
70 pngsuite/primary/bgbn4a08.png 32 32 2 0x77cbbfa5
71 pngsuite/primary/bgwn6a08.png 32 32 4 0xb472197d
72 pngsuite/primary/s01i3p01.png 1 1 3 0xafb003b6
73 pngsuite/primary/s01n3p01.png 1 1 3 0xafb003b6
74 pngsuite/primary/s02i3p01.png 2 2 3 0x96f3dd85
75 pngsuite/primary/s02n3p01.png 2 2 3 0x96f3dd85
76 pngsuite/primary/s03i3p01.png 3 3 3 0xb0cf1241
77 pngsuite/primary/s03n3p01.png 3 3 3 0xb0cf1241
78 pngsuite/primary/s04i3p01.png 4 4 3 0xbfcedd75
79 pngsuite/primary/s04n3p01.png 4 4 3 0xbfcedd75
80 pngsuite/primary/s05i3p02.png 5 5 3 0xc322cedd
81 pngsuite/primary/s05n3p02.png 5 5 3 0xc322cedd
82 pngsuite/primary/s06i3p02.png 6 6 3 0x46916799
83 pngsuite/primary/s06n3p02.png 6 6 3 0x46916799
84 pngsuite/primary/s07i3p02.png 7 7 3 0xfdabc297
85 pngsuite/primary/s07n3p02.png 7 7 3 0xfdabc297
86 pngsuite/primary/s08i3p02.png 8 8 3 0x8f036d09
87 pngsuite/primary/s08n3p02.png 8 8 3 0x8f036d09
88 pngsuite/primary/s09i3p02.png 9 9 3 0x16a46830
89 pngsuite/primary/s09n3p02.png 9 9 3 0x16a46830
90 pngsuite/primary/s32i3p04.png 32 32 3 0x4bd4fbd3
91 pngsuite/primary/s32n3p04.png 32 32 3 0x4bd4fbd3
92 pngsuite/primary/s33i3p04.png 33 33 3 0x51aa005e
93 pngsuite/primary/s33n3p04.png 33 33 3 0x51aa005e
94 pngsuite/primary/s34i3p04.png 34 34 3 0x84818775
95 pngsuite/primary/s34n3p04.png 34 34 3 0x84818775
96 pngsuite/primary/s35i3p04.png 35 35 3 0x6359ec75
97 pngsuite/primary/s35n3p04.png 35 35 3 0x6359ec75
98 pngsuite/primary/s36i3p04.png 36 36 3 0xe4878065
99 pngsuite/primary/s36n3p04.png 36 36 3 0xe4878065
100 pngsuite/primary/s37i3p04.png 37 37 3 0x3cefc423
101 pngsuite/primary/s37n3p04.png 37 37 3 0x3cefc423
102 pngsuite/primary/s38i3p04.png 38 38 3 0xffc55a2b
103 pngsuite/primary/s38n3p04.png 38 38 3 0xffc55a2b
104 pngsuite/primary/s39i3p04.png 39 39 3 0x0c790240
105 pngsuite/primary/s39n3p04.png 39 39 3 0x0c790240
106 pngsuite/primary/s40i3p04.png 40 40 3 0x951a316d
107 pngsuite/primary/s40n3p04.png 40 40 3 0x951a316d
108 pngsuite/primary/tbbn0g04.png 32 32 2 0x9c8410ea
109 pngsuite/primary/tbbn3p08.png 32 32 4 0x82bf9a57
110 pngsuite/primary/tbgn3p08.png 32 32 4 0x82bf9a57
111 pngsuite/primary/tbrn2c08.png 32 32 4 0xaa9bfe44
112 pngsuite/primary/tbwn3p08.png 32 32 4 0x82bf9a57
113 pngsuite/primary/tbyn3p08.png 32 32 4 0x82bf9a57
114 pngsuite/primary/tm3n3p02.png 32 32 4 0xf59745c5
115 pngsuite/primary/tp0n0g08.png 32 32 1 0xbac0864c
116 pngsuite/primary/tp0n2c08.png 32 32 3 0x82687c37
117 pngsuite/primary/tp0n3p08.png 32 32 3 0x61f54e37
118 pngsuite/primary/tp1n3p08.png 32 32 4 0x82bf9a57
119 pngsuite/primary/z00n2c08.png 32 32 3 0x65b4a72f
120 pngsuite/primary/z03n2c08.png 32 32 3 0x65b4a72f
121 pngsuite/primary/z06n2c08.png 32 32 3 0x65b4a72f
122 pngsuite/primary/z09n2c08.png 32 32 3 0x65b4a72f
123 pngsuite/primary_check/basi0g01.png 32 32 4 0x5fb33cfd
124 pngsuite/primary_check/basi0g02.png 32 32 4 0x5bbe95c5
125 pngsuite/primary_check/basi0g04.png 32 32 4 0x3468b9c5
126 pngsuite/primary_check/basi0g08.png 32 32 4 0x262ef46d
127 pngsuite/primary_check/basi2c08.png 32 32 4 0x1fc92bc5
128 pngsuite/primary_check/basi3p01.png 32 32 4 0x28a3e1c5
129 pngsuite/primary_check/basi3p02.png 32 32 4 0x803be5c5
130 pngsuite/primary_check/basi3p04.png 32 32 4 0xf3fc60e5
131 pngsuite/primary_check/basi3p08.png 32 32 4 0x30ef4f45
132 pngsuite/primary_check/basi4a08.png 32 32 4 0x23c8536d
133 pngsuite/primary_check/basi6a08.png 32 32 4 0xb472197d
134 pngsuite/primary_check/basn0g01.png 32 32 4 0x5fb33cfd
135 pngsuite/primary_check/basn0g02.png 32 32 4 0x5bbe95c5
136 pngsuite/primary_check/basn0g04.png 32 32 4 0x3468b9c5
137 pngsuite/primary_check/basn0g08.png 32 32 4 0x262ef46d
138 pngsuite/primary_check/basn2c08.png 32 32 4 0x1fc92bc5
139 pngsuite/primary_check/basn3p01.png 32 32 4 0x28a3e1c5
140 pngsuite/primary_check/basn3p02.png 32 32 4 0x803be5c5
141 pngsuite/primary_check/basn3p04.png 32 32 4 0xf3fc60e5
142 pngsuite/primary_check/basn3p08.png 32 32 4 0x30ef4f45
143 pngsuite/primary_check/basn4a08.png 32 32 4 0x23c8536d
144 pngsuite/primary_check/basn6a08.png 32 32 4 0xb472197d
145 pngsuite/primary_check/bgai4a08.png 32 32 4 0x23c8536d
146 pngsuite/primary_check/bgan6a08.png 32 32 4 0xb472197d
147 pngsuite/primary_check/bgbn4a08.png 32 32 4 0x23c8536d
148 pngsuite/primary_check/bgwn6a08.png 32 32 4 0xb472197d
149 pngsuite/primary_check/s01i3p01.png 1 1 4 0xdb152beb
150 pngsuite/primary_check/s01n3p01.png 1 1 4 0xdb152beb
151 pngsuite/primary_check/s02i3p01.png 2 2 4 0xa344a3a5
152 pngsuite/primary_check/s02n3p01.png 2 2 4 0xa344a3a5
153 pngsuite/primary_check/s03i3p01.png 3 3 4 0x594d3bfa
154 pngsuite/primary_check/s03n3p01.png 3 3 4 0x594d3bfa
155 pngsuite/primary_check/s04i3p01.png 4 4 4 0xd59d4605
156 pngsuite/primary_check/s04n3p01.png 4 4 4 0xd59d4605
157 pngsuite/primary_check/s05i3p02.png 5 5 4 0x41e58366
158 pngsuite/primary_check/s05n3p02.png 5 5 4 0x41e58366
159 pngsuite/primary_check/s06i3p02.png 6 6 4 0xcad1a885
160 pngsuite/primary_check/s06n3p02.png 6 6 4 0xcad1a885
161 pngsuite/primary_check/s07i3p02.png 7 7 4 0x09184108
162 pngsuite/primary_check/s07n3p02.png 7 7 4 0x09184108
163 pngsuite/primary_check/s08i3p02.png 8 8 4 0x4fd11cad
164 pngsuite/primary_check/s08n3p02.png 8 8 4 0x4fd11cad
165 pngsuite/primary_check/s09i3p02.png 9 9 4 0xc50dbecd
166 pngsuite/primary_check/s09n3p02.png 9 9 4 0xc50dbecd
167 pngsuite/primary_check/s32i3p04.png 32 32 4 0x95cbb1d3
168 pngsuite/primary_check/s32n3p04.png 32 32 4 0x95cbb1d3
169 pngsuite/primary_check/s33i3p04.png 33 33 4 0x6649fc5b
170 pngsuite/primary_check/s33n3p04.png 33 33 4 0x6649fc5b
171 pngsuite/primary_check/s34i3p04.png 34 34 4 0x35b98e15
172 pngsuite/primary_check/s34n3p04.png 34 34 4 0x35b98e15
173 pngsuite/primary_check/s35i3p04.png 35 35 4 0xc9ddf938
174 pngsuite/primary_check/s35n3p04.png 35 35 4 0xc9ddf938
175 pngsuite/primary_check/s36i3p04.png 36 36 4 0x7bb4e1cd
176 pngsuite/primary_check/s36n3p04.png 36 36 4 0x7bb4e1cd
177 pngsuite/primary_check/s37i3p04.png 37 37 4 0xee50001c
178 pngsuite/primary_check/s37n3p04.png 37 37 4 0xee50001c
179 pngsuite/primary_check/s38i3p04.png 38 38 4 0x51b76813
180 pngsuite/primary_check/s38n3p04.png 38 38 4 0x51b76813
181 pngsuite/primary_check/s39i3p04.png 39 39 4 0x42f23327
182 pngsuite/primary_check/s39n3p04.png 39 39 4 0x42f23327
183 pngsuite/primary_check/s40i3p04.png 40 40 4 0xf91b6a7d
184 pngsuite/primary_check/s40n3p04.png 40 40 4 0xf91b6a7d
185 pngsuite/primary_check/tbbn0g04.png 32 32 4 0x8a0117a4
186 pngsuite/primary_check/tbbn3p08.png 32 32 4 0x82bf9a57
187 pngsuite/primary_check/tbgn3p08.png 32 32 4 0x82bf9a57
188 pngsuite/primary_check/tbrn2c08.png 32 32 4 0xaa9bfe44
189 pngsuite/primary_check/tbwn3p08.png 32 32 4 0x82bf9a57
190 pngsuite/primary_check/tbyn3p08.png 32 32 4 0x82bf9a57
191 pngsuite/primary_check/tm3n3p02.png 32 32 4 0xf59745c5
192 pngsuite/primary_check/tp0n0g08.png 32 32 4 0xd405ad2e
193 pngsuite/primary_check/tp0n2c08.png 32 32 4 0x5a66ca09
194 pngsuite/primary_check/tp0n3p08.png 32 32 4 0x06e81adf
195 pngsuite/primary_check/tp1n3p08.png 32 32 4 0x82bf9a57
196 pngsuite/primary_check/z00n2c08.png 32 32 4 0xaa698493
197 pngsuite/primary_check/z03n2c08.png 32 32 4 0xaa698493
198 pngsuite/primary_check/z06n2c08.png 32 32 4 0xaa698493
199 pngsuite/primary_check/z09n2c08.png 32 32 4 0xaa698493
200 pngsuite/unused/ccwn2c08.png 32 32 3 0xbb576418
201 pngsuite/unused/ccwn3p08.png 32 32 3 0x5c4df060
202 pngsuite/unused/cdfn2c08.png 8 32 3 0xe30ed48f
203 pngsuite/unused/cdhn2c08.png 32 8 3 0x999321f5
204 pngsuite/unused/cdsn2c08.png 8 8 3 0x7f63fa01
205 pngsuite/unused/cdun2c08.png 32 32 3 0xbd325d71
206 pngsuite/unused/ch1n3p04.png 32 32 3 0x35b2e4a5
207 pngsuite/unused/ch2n3p08.png 32 32 3 0xfe066865
208 pngsuite/unused/cm0n0g04.png 32 32 1 0xe9f53e6c
209 pngsuite/unused/cm7n0g04.png 32 32 1 0xe9f53e6c
210 pngsuite/unused/cm9n0g04.png 32 32 1 0xe9f53e6c
211 pngsuite/unused/cs3n2c16.png 32 32 3 0x7f0fa2c5
212 pngsuite/unused/cs3n3p08.png 32 32 3 0x5533bac5
213 pngsuite/unused/cs5n2c08.png 32 32 3 0x8a80f8c5
214 pngsuite/unused/cs5n3p08.png 32 32 3 0x8a80f8c5
215 pngsuite/unused/cs8n2c08.png 32 32 3 0x7f0fa2c5
216 pngsuite/unused/cs8n3p08.png 32 32 3 0x7f0fa2c5
217 pngsuite/unused/ct0n0g04.png 32 32 1 0xe9f53e6c
218 pngsuite/unused/ct1n0g04.png 32 32 1 0xe9f53e6c
219 pngsuite/unused/cten0g04.png 32 32 1 0x1c073b45
220 pngsuite/unused/ctfn0g04.png 32 32 1 0xfa9fd205
221 pngsuite/unused/ctgn0g04.png 32 32 1 0xf28c8085
222 pngsuite/unused/cthn0g04.png 32 32 1 0x7c039595
223 pngsuite/unused/ctjn0g04.png 32 32 1 0xc520f455
224 pngsuite/unused/ctzn0g04.png 32 32 1 0xe9f53e6c
225 pngsuite/unused/f00n0g08.png 32 32 1 0x21db411b
226 pngsuite/unused/f00n2c08.png 32 32 3 0x1f25ded0
227 pngsuite/unused/f01n0g08.png 32 32 1 0x7437b32a
228 pngsuite/unused/f01n2c08.png 32 32 3 0x0d4507ae
229 pngsuite/unused/f02n0g08.png 32 32 1 0x6b633c7c
230 pngsuite/unused/f02n2c08.png 32 32 3 0x4b278986
231 pngsuite/unused/f03n0g08.png 32 32 1 0x2f31c08e
232 pngsuite/unused/f03n2c08.png 32 32 3 0x843ecc7e
233 pngsuite/unused/f04n0g08.png 32 32 1 0xfd3a0b73
234 pngsuite/unused/f04n2c08.png 32 32 3 0x557174bc
235 pngsuite/unused/f99n0g04.png 32 32 1 0xb79aa6e1
236 pngsuite/unused/g03n0g16.png 32 32 1 0xecd13817
237 pngsuite/unused/g03n2c08.png 32 32 3 0x242407a8
238 pngsuite/unused/g03n3p04.png 32 32 3 0xe801ecc8
239 pngsuite/unused/g04n0g16.png 32 32 1 0xc11bc972
240 pngsuite/unused/g04n2c08.png 32 32 3 0xdf843cc4
241 pngsuite/unused/g04n3p04.png 32 32 3 0x60e41f3b
242 pngsuite/unused/g05n0g16.png 32 32 1 0xbe6615a5
243 pngsuite/unused/g05n2c08.png 32 32 3 0x5c312116
244 pngsuite/unused/g05n3p04.png 32 32 3 0x2e0fbf86
245 pngsuite/unused/g07n0g16.png 32 32 1 0x2b54a398
246 pngsuite/unused/g07n2c08.png 32 32 3 0xf765fb10
247 pngsuite/unused/g07n3p04.png 32 32 3 0x9a8c3338
248 pngsuite/unused/g10n0g16.png 32 32 1 0xb08a92e1
249 pngsuite/unused/g10n2c08.png 32 32 3 0xa43f2291
250 pngsuite/unused/g10n3p04.png 32 32 3 0xb733194c
251 pngsuite/unused/g25n0g16.png 32 32 1 0xa6b1f5dd
252 pngsuite/unused/g25n2c08.png 32 32 3 0x767aee0c
253 pngsuite/unused/g25n3p04.png 32 32 3 0x4cf349a8
254 pngsuite/unused/pp0n2c16.png 32 32 3 0x65567ed5
255 pngsuite/unused/pp0n6a08.png 32 32 4 0x3188c645
256 pngsuite/unused/ps1n0g08.png 32 32 1 0x414f1ca9
257 pngsuite/unused/ps1n2c16.png 32 32 3 0x65567ed5
258 pngsuite/unused/ps2n0g08.png 32 32 1 0x414f1ca9
259 pngsuite/unused/ps2n2c16.png 32 32 3 0x65567ed5

View File

@ -64,7 +64,7 @@ void stbir_progress(float p)
#define STBIR_PROGRESS_REPORT stbir_progress
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#define STB_IMAGE_RESIZE_STATIC
#include "stb_image_resize.h"
#include "stb_image_resize2.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
@ -143,7 +143,7 @@ void resizer(int argc, char **argv)
out_h = h*3;
output_pixels = (unsigned char*) malloc(out_w*out_h*n);
//stbir_resize_uint8_srgb(input_pixels, w, h, 0, output_pixels, out_w, out_h, 0, n, -1,0);
stbir_resize_uint8(input_pixels, w, h, 0, output_pixels, out_w, out_h, 0, n);
stbir_resize_uint8_linear(input_pixels, w, h, 0, output_pixels, out_w, out_h, 0, (stbir_pixel_layout) n);
stbi_write_png("output.png", out_w, out_h, n, output_pixels, 0);
exit(0);
}
@ -171,9 +171,9 @@ void performance(int argc, char **argv)
output_pixels = (unsigned char*) malloc(out_w*out_h*n);
for (i=0; i < count; ++i)
if (srgb)
stbir_resize_uint8_srgb(input_pixels, w, h, 0, output_pixels, out_w, out_h, 0, n,-1,0);
stbir_resize_uint8_srgb(input_pixels, w, h, 0, output_pixels, out_w, out_h, 0, (stbir_pixel_layout) n);
else
stbir_resize(input_pixels, w, h, 0, output_pixels, out_w, out_h, 0, STBIR_TYPE_UINT8, n,-1, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT, STBIR_COLORSPACE_LINEAR, NULL);
stbir_resize_uint8_linear(input_pixels, w, h, 0, output_pixels, out_w, out_h, 0, (stbir_pixel_layout) n);
exit(0);
}
@ -188,6 +188,7 @@ int main(int argc, char** argv)
return 0;
}
#if 0
void resize_image(const char* filename, float width_percent, float height_percent, stbir_filter filter, stbir_edge edge, stbir_colorspace colorspace, const char* output_filename)
{
int w, h, n;
@ -1120,3 +1121,7 @@ void test_suite(int argc, char **argv)
resize_image("gamma_2.2.jpg", .5f, .5f, STBIR_FILTER_CATMULLROM, STBIR_EDGE_REFLECT, STBIR_COLORSPACE_SRGB, "test-output/gamma_2.2.jpg");
resize_image("gamma_dalai_lama_gray.jpg", .5f, .5f, STBIR_FILTER_CATMULLROM, STBIR_EDGE_REFLECT, STBIR_COLORSPACE_SRGB, "test-output/gamma_dalai_lama_gray.jpg");
}
#endif
void test_suite(int argc, char **argv)
{
}

View File

@ -88,7 +88,7 @@ SOURCE=.\resample_test.cpp
# End Source File
# Begin Source File
SOURCE=..\stb_image_resize.h
SOURCE=..\stb_image_resize2.h
# End Source File
# End Target
# End Project

View File

@ -130,10 +130,6 @@ SOURCE=..\stb_image.h
# End Source File
# Begin Source File
SOURCE=..\stb_image_resize.h
# End Source File
# Begin Source File
SOURCE=..\stb_image_write.h
# End Source File
# Begin Source File

View File

@ -1,3 +1,6 @@
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#include "stb_image_resize2.h"
#define STB_SPRINTF_IMPLEMENTATION
#include "stb_sprintf.h"
@ -7,7 +10,6 @@
#define STB_DIVIDE_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION
#define STB_HERRINGBONE_WANG_TILE_IMEPLEMENTATIOn
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#define STB_RECT_PACK_IMPLEMENTATION
#define STB_VOXEL_RENDER_IMPLEMENTATION
#define STB_EASY_FONT_IMPLEMENTATION
@ -20,7 +22,6 @@
#include "stb_perlin.h"
#include "stb_c_lexer.h"
#include "stb_divide.h"
#include "stb_image_resize.h"
#include "stb_rect_pack.h"
#include "stb_dxt.h"
#include "stb_include.h"

View File

@ -70,7 +70,7 @@ void my_free(void *) { }
#include "stb_leakcheck.h"
#define STB_IMAGE_RESIZE_IMPLEMENTATION
#include "stb_image_resize.h"
#include "stb_image_resize2.h"
//#include "stretchy_buffer.h" // deprecating

47
tests/test_png_paeth.c Normal file
View File

@ -0,0 +1,47 @@
#include <stdio.h>
#include <stdlib.h>
// Reference Paeth filter as per PNG spec
static int ref_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;
}
// Optimized Paeth filter
static int opt_paeth(int a, int b, int c)
{
int thresh = c*3 - (a + b);
int lo = a < b ? a : b;
int hi = a < b ? b : a;
int t0 = (hi <= thresh) ? lo : c;
int t1 = (thresh <= lo) ? hi : t0;
return t1;
}
int main()
{
// Exhaustively test the functions match for all byte inputs a, b,c in [0,255]
for (int i = 0; i < (1 << 24); ++i) {
int a = i & 0xff;
int b = (i >> 8) & 0xff;
int c = (i >> 16) & 0xff;
int ref = ref_paeth(a, b, c);
int opt = opt_paeth(a, b, c);
if (ref != opt) {
fprintf(stderr, "mismatch at a=%3d b=%3d c=%3d: ref=%3d opt=%3d\n", a, b, c, ref, opt);
return 1;
}
}
printf("all ok!\n");
return 0;
}
// vim:sw=3:sts=3:et

75
tests/test_png_regress.c Normal file
View File

@ -0,0 +1,75 @@
#include <stdio.h>
#include <stdlib.h>
#define STBI_WINDOWS_UTF8
#ifdef _WIN32
#define WIN32 // what stb.h checks
#pragma comment(lib, "advapi32.lib")
#endif
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#define STB_DEFINE
#include "deprecated/stb.h"
static unsigned int fnv1a_hash32(const stbi_uc *bytes, size_t len)
{
unsigned int hash = 0x811c9dc5;
unsigned int mul = 0x01000193;
size_t i;
for (i = 0; i < len; ++i)
hash = (hash ^ bytes[i]) * mul;
return hash;
}
// The idea for this test is to leave pngsuite/ref_results.csv checked in,
// and then you can run this test after making PNG loader changes. If the
// ref results change (as per git diff), confirm that the change was
// intentional. If so, commit them as well; if not, undo.
int main()
{
char **files;
FILE *csv_file;
int i;
files = stb_readdir_recursive("pngsuite", "*.png");
if (!files) {
fprintf(stderr, "pngsuite files not found!\n");
return 1;
}
// sort files by name
qsort(files, stb_arr_len(files), sizeof(char*), stb_qsort_strcmp(0));
csv_file = fopen("pngsuite/ref_results.csv", "w");
if (!csv_file) {
fprintf(stderr, "error opening ref results for writing!\n");
stb_readdir_free(files);
return 1;
}
fprintf(csv_file, "filename,width,height,ncomp,error,hash\n");
for (i = 0; i < stb_arr_len(files); ++i) {
char *filename = files[i];
int width, height, ncomp;
stbi_uc *pixels = stbi_load(filename, &width, &height, &ncomp, 0);
const char *error = "";
unsigned int hash = 0;
if (!pixels)
error = stbi_failure_reason();
else {
hash = fnv1a_hash32(pixels, width * height * ncomp);
stbi_image_free(pixels);
}
fprintf(csv_file, "%s,%d,%d,%d,%s,0x%08x\n", filename, width, height, ncomp, error, hash);
}
fclose(csv_file);
stb_readdir_free(files);
}

View File

@ -3,16 +3,18 @@ stb
single-file public domain (or MIT licensed) libraries for C/C++
# This project discusses security-relevant bugs in public in Github Issues and Pull Requests, and it may take significant time for security fixes to be implemented or merged. If this poses an unreasonable risk to your project, do not use stb libraries.
Noteworthy:
* image loader: [stb_image.h](stb_image.h)
* image writer: [stb_image_write.h](stb_image_write.h)
* image resizer: [stb_image_resize.h](stb_image_resize.h)
* image resizer: [stb_image_resize2.h](stb_image_resize2.h)
* font text rasterizer: [stb_truetype.h](stb_truetype.h)
* typesafe containers: [stb_ds.h](stb_ds.h)
Most libraries by stb, except: stb_dxt by Fabian "ryg" Giesen, stb_image_resize
by Jorge L. "VinoBS" Rodriguez, and stb_sprintf by Jeff Roberts.
Most libraries by stb, except: stb_dxt by Fabian "ryg" Giesen, original stb_image_resize
by Jorge L. "VinoBS" Rodriguez, and stb_image_resize2 and stb_sprintf by Jeff Roberts.
<a name="stb_libs"></a>

View File

@ -3,7 +3,7 @@ stb_hexwave.h | audio | audio waveform synthesizer
stb_image.h | graphics | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC
stb_truetype.h | graphics | parse, decode, and rasterize characters from truetype fonts
stb_image_write.h | graphics | image writing to disk: PNG, TGA, BMP
stb_image_resize.h | graphics | resize images larger/smaller with good quality
stb_image_resize2.h | graphics | resize images larger/smaller with good quality
stb_rect_pack.h | graphics | simple 2D rectangle packer with decent quality
stb_perlin.h | graphics | perlin's revised simplex noise w/ different seeds
stb_ds.h | utility | typesafe dynamic array and hash tables for C, will compile in C++