From f2b3ebd47008d1c3675d85ca0b7a72eeb15fd392 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 25 Sep 2014 19:30:47 +0100 Subject: [PATCH 01/46] Support for 1/2/4-bit palettized PNG --- stb_image.h | 110 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 72 insertions(+), 38 deletions(-) diff --git a/stb_image.h b/stb_image.h index 90d0d15..2339db9 100644 --- a/stb_image.h +++ b/stb_image.h @@ -63,7 +63,7 @@ James "moose2000" Brown (iPhone PNG) David Woo Ben "Disch" Wenger (io callbacks) Roy Eltham Martin "SpartanJ" Golini Luke Graham - Thomas Ruf + Omar Cornut (1/2/4-bit palettized PNG) Thomas Ruf John Bartholomew Optimizations & bugfixes Ken Hamada Fabian "ryg" Giesen Cort Stratton @@ -2487,20 +2487,40 @@ static int stbi__paeth(int a, int b, int c) #define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings // 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) +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) { stbi__context *s = a->s; stbi__uint32 i,j,stride = x*out_n; + stbi__uint32 img_len; int k; int img_n = s->img_n; // copy it into a local for later + int addr_shift; + unsigned int pixel_data_shift_addr_mask; + unsigned int pixel_data_shift_addr_lshift; + stbi_uc pixel_data_mask; + STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); a->out = (stbi_uc *) stbi__malloc(x * y * out_n); if (!a->out) return stbi__err("outofmem", "Out of memory"); + + img_len = (img_n * x) * y; + if (depth<8) img_len /= (8/depth); + else if (depth>8) img_len *= depth>>3; + img_len += y; if (s->img_x == x && s->img_y == y) { - if (raw_len != (img_n * x + 1) * y) return stbi__err("not enough pixels","Corrupt PNG"); + if (raw_len != img_len) return stbi__err("not enough pixels","Corrupt PNG"); } else { // interlaced: - if (raw_len < (img_n * x + 1) * y) return stbi__err("not enough pixels","Corrupt PNG"); + if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); } + + switch (depth) + { + case 8: addr_shift = 0; pixel_data_shift_addr_mask = 0x00; pixel_data_shift_addr_lshift = 0; pixel_data_mask = 0xFF; break; + case 4: addr_shift = 1; pixel_data_shift_addr_mask = 0x01; pixel_data_shift_addr_lshift = 2; pixel_data_mask = 0x0F; break; + case 2: addr_shift = 2; pixel_data_shift_addr_mask = 0x03; pixel_data_shift_addr_lshift = 1; pixel_data_mask = 0x03; break; + case 1: addr_shift = 3; pixel_data_shift_addr_mask = 0x07; pixel_data_shift_addr_lshift = 0; pixel_data_mask = 0x01; break; + } + for (j=0; j < y; ++j) { stbi_uc *cur = a->out + stride*j; stbi_uc *prior = cur - stride; @@ -2508,65 +2528,74 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r if (filter > 4) return stbi__err("invalid filter","Corrupt PNG"); // if first row, use special filter that doesn't sample previous row if (j == 0) filter = first_row_filter[filter]; + + // Expanding the macro for reference (probably worth inlining the whole loop or at least splitting 8 vs 1/2/4) + // - Depth 8 (((ARR[K ]) + // - Depth 4 (((ARR[K >> 1]) >> ((k & 0x01) << 2)) & 0x0F) + // - Depth 2 (((ARR[K >> 2]) >> ((k & 0x03) << 1)) & 0x03) + // - Depth 1 (((ARR[K >> 3]) >> ((k & 0x07) ) & 0x01) + #define PIXEL(ARR,K) (((ARR[(K) >> addr_shift]) >> (((7-K) & pixel_data_shift_addr_mask) << pixel_data_shift_addr_lshift)) & pixel_data_mask) + // handle first pixel explicitly - for (k=0; k < img_n; ++k) { + int rawk=0; + for (k=0; k < img_n; ++k, ++rawk) { 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; + case STBI__F_none : cur[k] = PIXEL(raw,rawk); break; + case STBI__F_sub : cur[k] = PIXEL(raw,rawk); break; + case STBI__F_up : cur[k] = STBI__BYTECAST(PIXEL(raw,rawk) + prior[k]); break; + case STBI__F_avg : cur[k] = STBI__BYTECAST(PIXEL(raw,rawk) + (prior[k]>>1)); break; + case STBI__F_paeth : cur[k] = STBI__BYTECAST(PIXEL(raw,rawk) + stbi__paeth(0,prior[k],0)); break; + case STBI__F_avg_first : cur[k] = PIXEL(raw,rawk); break; + case STBI__F_paeth_first: cur[k] = PIXEL(raw,rawk); break; } } if (img_n != out_n) cur[img_n] = 255; - raw += img_n; cur += out_n; prior += out_n; // this is a little gross, so that we don't switch per-pixel or per-component if (img_n == out_n) { #define CASE(f) \ case f: \ - for (i=x-1; i >= 1; --i, raw+=img_n,cur+=img_n,prior+=img_n) \ - for (k=0; k < img_n; ++k) + for (i=x-1; i >= 1; --i, cur+=img_n,prior+=img_n) \ + for (k=0; k < img_n; ++k, ++rawk) switch (filter) { - CASE(STBI__F_none) cur[k] = raw[k]; break; - CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(raw[k] + cur[k-img_n]); 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] + cur[k-img_n])>>1)); break; - CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-img_n],prior[k],prior[k-img_n])); break; - CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(raw[k] + (cur[k-img_n] >> 1)); break; - CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-img_n],0,0)); break; + CASE(STBI__F_none) cur[k] = PIXEL(raw,rawk); break; + CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(PIXEL(raw,rawk) + cur[k-img_n]); break; + CASE(STBI__F_up) cur[k] = STBI__BYTECAST(PIXEL(raw,rawk) + prior[k]); break; + CASE(STBI__F_avg) cur[k] = STBI__BYTECAST(PIXEL(raw,rawk) + ((prior[k] + cur[k-img_n])>>1)); break; + CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(PIXEL(raw,rawk) + stbi__paeth(cur[k-img_n],prior[k],prior[k-img_n])); break; + CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(PIXEL(raw,rawk) + (cur[k-img_n] >> 1)); break; + CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(PIXEL(raw,rawk) + stbi__paeth(cur[k-img_n],0,0)); break; } #undef CASE } else { STBI_ASSERT(img_n+1 == out_n); #define CASE(f) \ case f: \ - for (i=x-1; i >= 1; --i, cur[img_n]=255,raw+=img_n,cur+=out_n,prior+=out_n) \ - for (k=0; k < img_n; ++k) + for (i=x-1; i >= 1; --i, cur[img_n]=255,cur+=out_n,prior+=out_n) \ + for (k=0; k < img_n; ++k, ++rawk) switch (filter) { - CASE(STBI__F_none) cur[k] = raw[k]; break; - CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(raw[k] + cur[k-out_n]); 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] + cur[k-out_n])>>1)); break; - CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-out_n],prior[k],prior[k-out_n])); break; - CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(raw[k] + (cur[k-out_n] >> 1)); break; - CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-out_n],0,0)); break; + CASE(STBI__F_none) cur[k] = PIXEL(raw,k); break; + CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(PIXEL(raw,rawk) + cur[k-out_n]); break; + CASE(STBI__F_up) cur[k] = STBI__BYTECAST(PIXEL(raw,rawk) + prior[k]); break; + CASE(STBI__F_avg) cur[k] = STBI__BYTECAST(PIXEL(raw,rawk) + ((prior[k] + cur[k-out_n])>>1)); break; + CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(PIXEL(raw,rawk) + stbi__paeth(cur[k-out_n],prior[k],prior[k-out_n])); break; + CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(PIXEL(raw,rawk) + (cur[k-out_n] >> 1)); break; + CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(PIXEL(raw,rawk) + stbi__paeth(cur[k-out_n],0,0)); break; } #undef CASE } + raw+=(rawk+pixel_data_shift_addr_mask)>>addr_shift; // scanlines are aligned on byte boundaries } return 1; } -static int stbi__create_png_image(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, int interlaced) +static int stbi__create_png_image(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, int depth, int interlaced) { stbi_uc *final; int p; if (!interlaced) - return stbi__create_png_image_raw(a, raw, raw_len, out_n, a->s->img_x, a->s->img_y); + return stbi__create_png_image_raw(a, raw, raw_len, out_n, a->s->img_x, a->s->img_y, depth); // de-interlacing final = (stbi_uc *) stbi__malloc(a->s->img_x * a->s->img_y * out_n); @@ -2580,7 +2609,7 @@ static int stbi__create_png_image(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_l x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; if (x && y) { - if (!stbi__create_png_image_raw(a, raw, raw_len, out_n, x, y)) { + if (!stbi__create_png_image_raw(a, raw, raw_len, out_n, x, y, depth)) { free(final); return 0; } @@ -2720,7 +2749,7 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) stbi_uc palette[1024], pal_img_n=0; stbi_uc has_trans=0, tc[3]; stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; - int first=1,k,interlace=0, is_iphone=0; + int first=1,k,interlace=0, depth=0, is_iphone=0; stbi__context *s = z->s; z->expanded = NULL; @@ -2739,14 +2768,19 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) stbi__skip(s, c.length); break; case PNG_TYPE('I','H','D','R'): { - int depth,color,comp,filter; + int color,comp,filter; if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); first = 0; if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); - depth = stbi__get8(s); if (depth != 8) return stbi__err("8bit only","PNG not supported: 8-bit only"); + depth = stbi__get8(s); color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3) { + if (depth != 1 && depth != 2 && depth != 4 && depth != 8) return stbi__err("1/2/4/8-bit only","PNG not supported: 1/2/4/8-bit only for palettized images"); // support 1/2/4 bpp for palettized. + } else { + if (depth != 8) return stbi__err("8-bit only","PNG not supported: 8-bit only"); // greyscale images (color==0) would need the pixel data to be scaled (see PIXEL macro) + } if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); @@ -2829,7 +2863,7 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) s->img_out_n = s->img_n+1; else s->img_out_n = s->img_n; - if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, interlace)) return 0; + if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, depth, interlace)) return 0; if (has_trans) if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) From 3b3e2996e7a1a2b312cb9b891e7db347c02e7a68 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 25 Sep 2014 21:59:50 +0100 Subject: [PATCH 02/46] Unpack 1/2/4 bpp into 8 bpp scanline buffer + support grayscale 1/2/4 bpp --- stb_image.h | 148 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 88 insertions(+), 60 deletions(-) diff --git a/stb_image.h b/stb_image.h index 2339db9..ac1fab4 100644 --- a/stb_image.h +++ b/stb_image.h @@ -63,7 +63,7 @@ James "moose2000" Brown (iPhone PNG) David Woo Ben "Disch" Wenger (io callbacks) Roy Eltham Martin "SpartanJ" Golini Luke Graham - Omar Cornut (1/2/4-bit palettized PNG) Thomas Ruf + Omar Cornut (1/2/4-bit png) Thomas Ruf John Bartholomew Optimizations & bugfixes Ken Hamada Fabian "ryg" Giesen Cort Stratton @@ -2487,17 +2487,14 @@ static int stbi__paeth(int a, int b, int c) #define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings // 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) +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) { stbi__context *s = a->s; stbi__uint32 i,j,stride = x*out_n; stbi__uint32 img_len; int k; int img_n = s->img_n; // copy it into a local for later - int addr_shift; - unsigned int pixel_data_shift_addr_mask; - unsigned int pixel_data_shift_addr_lshift; - stbi_uc pixel_data_mask; + stbi_uc* line8 = NULL; // point into raw when depth==8 else temporary local buffer STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); a->out = (stbi_uc *) stbi__malloc(x * y * out_n); @@ -2513,89 +2510,125 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); } - switch (depth) - { - case 8: addr_shift = 0; pixel_data_shift_addr_mask = 0x00; pixel_data_shift_addr_lshift = 0; pixel_data_mask = 0xFF; break; - case 4: addr_shift = 1; pixel_data_shift_addr_mask = 0x01; pixel_data_shift_addr_lshift = 2; pixel_data_mask = 0x0F; break; - case 2: addr_shift = 2; pixel_data_shift_addr_mask = 0x03; pixel_data_shift_addr_lshift = 1; pixel_data_mask = 0x03; break; - case 1: addr_shift = 3; pixel_data_shift_addr_mask = 0x07; pixel_data_shift_addr_lshift = 0; pixel_data_mask = 0x01; break; + if (depth != 8) { + line8 = (stbi_uc *) stbi__malloc((x+3) * out_n); // allocate buffer for one scanline + if (!line8) return stbi__err("outofmem", "Out of memory"); } for (j=0; j < y; ++j) { + stbi_uc *in; stbi_uc *cur = a->out + stride*j; stbi_uc *prior = cur - stride; int filter = *raw++; - if (filter > 4) return stbi__err("invalid filter","Corrupt PNG"); + if (filter > 4) { + if (depth != 8) free(line8); + return stbi__err("invalid filter","Corrupt PNG"); + } + + if (depth == 8) { + in = raw; + raw += x*img_n; + } + else { + // 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 + in = line8; + stbi_uc* decode_in = raw; + stbi_uc* decode_out = line8; + stbi_uc scale = (color == 0) ? 0xFF/((1<= 1; i-=2, decode_in++) { + *decode_out++ = scale * ((*decode_in >> 4) ); + *decode_out++ = scale * ((*decode_in ) & 0x0f); + } + raw+=(x*img_n+1)>>1; + } else if (depth == 2) { + for (i=x*img_n; i >= 1; i-=4, decode_in++) { + *decode_out++ = scale * ((*decode_in >> 6) ); + *decode_out++ = scale * ((*decode_in >> 4) & 0x03); + *decode_out++ = scale * ((*decode_in >> 2) & 0x03); + *decode_out++ = scale * ((*decode_in ) & 0x03); + } + raw+=(x*img_n+3)>>2; + } else if (depth == 1) { + for (i=x*img_n; i >= 1; i-=8, decode_in++) { + *decode_out++ = scale * ((*decode_in >> 7) ); + *decode_out++ = scale * ((*decode_in >> 6) & 0x01); + *decode_out++ = scale * ((*decode_in >> 5) & 0x01); + *decode_out++ = scale * ((*decode_in >> 4) & 0x01); + *decode_out++ = scale * ((*decode_in >> 3) & 0x01); + *decode_out++ = scale * ((*decode_in >> 2) & 0x01); + *decode_out++ = scale * ((*decode_in >> 1) & 0x01); + *decode_out++ = scale * ((*decode_in ) & 0x01); + } + raw+=(x*img_n+7)>>3; + } + } + // if first row, use special filter that doesn't sample previous row if (j == 0) filter = first_row_filter[filter]; - - // Expanding the macro for reference (probably worth inlining the whole loop or at least splitting 8 vs 1/2/4) - // - Depth 8 (((ARR[K ]) - // - Depth 4 (((ARR[K >> 1]) >> ((k & 0x01) << 2)) & 0x0F) - // - Depth 2 (((ARR[K >> 2]) >> ((k & 0x03) << 1)) & 0x03) - // - Depth 1 (((ARR[K >> 3]) >> ((k & 0x07) ) & 0x01) - #define PIXEL(ARR,K) (((ARR[(K) >> addr_shift]) >> (((7-K) & pixel_data_shift_addr_mask) << pixel_data_shift_addr_lshift)) & pixel_data_mask) // handle first pixel explicitly - int rawk=0; - for (k=0; k < img_n; ++k, ++rawk) { + for (k=0; k < img_n; ++k) { switch (filter) { - case STBI__F_none : cur[k] = PIXEL(raw,rawk); break; - case STBI__F_sub : cur[k] = PIXEL(raw,rawk); break; - case STBI__F_up : cur[k] = STBI__BYTECAST(PIXEL(raw,rawk) + prior[k]); break; - case STBI__F_avg : cur[k] = STBI__BYTECAST(PIXEL(raw,rawk) + (prior[k]>>1)); break; - case STBI__F_paeth : cur[k] = STBI__BYTECAST(PIXEL(raw,rawk) + stbi__paeth(0,prior[k],0)); break; - case STBI__F_avg_first : cur[k] = PIXEL(raw,rawk); break; - case STBI__F_paeth_first: cur[k] = PIXEL(raw,rawk); break; + case STBI__F_none : cur[k] = in[k]; break; + case STBI__F_sub : cur[k] = in[k]; break; + case STBI__F_up : cur[k] = STBI__BYTECAST(in[k] + prior[k]); break; + case STBI__F_avg : cur[k] = STBI__BYTECAST(in[k] + (prior[k]>>1)); break; + case STBI__F_paeth : cur[k] = STBI__BYTECAST(in[k] + stbi__paeth(0,prior[k],0)); break; + case STBI__F_avg_first : cur[k] = in[k]; break; + case STBI__F_paeth_first: cur[k] = in[k]; break; } } if (img_n != out_n) cur[img_n] = 255; + in += img_n; cur += out_n; prior += out_n; // this is a little gross, so that we don't switch per-pixel or per-component if (img_n == out_n) { #define CASE(f) \ case f: \ - for (i=x-1; i >= 1; --i, cur+=img_n,prior+=img_n) \ - for (k=0; k < img_n; ++k, ++rawk) + for (i=x-1; i >= 1; --i, in+=img_n,cur+=img_n,prior+=img_n) \ + for (k=0; k < img_n; ++k) switch (filter) { - CASE(STBI__F_none) cur[k] = PIXEL(raw,rawk); break; - CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(PIXEL(raw,rawk) + cur[k-img_n]); break; - CASE(STBI__F_up) cur[k] = STBI__BYTECAST(PIXEL(raw,rawk) + prior[k]); break; - CASE(STBI__F_avg) cur[k] = STBI__BYTECAST(PIXEL(raw,rawk) + ((prior[k] + cur[k-img_n])>>1)); break; - CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(PIXEL(raw,rawk) + stbi__paeth(cur[k-img_n],prior[k],prior[k-img_n])); break; - CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(PIXEL(raw,rawk) + (cur[k-img_n] >> 1)); break; - CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(PIXEL(raw,rawk) + stbi__paeth(cur[k-img_n],0,0)); break; + CASE(STBI__F_none) cur[k] = in[k]; break; + CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(in[k] + cur[k-img_n]); break; + CASE(STBI__F_up) cur[k] = STBI__BYTECAST(in[k] + prior[k]); break; + CASE(STBI__F_avg) cur[k] = STBI__BYTECAST(in[k] + ((prior[k] + cur[k-img_n])>>1)); break; + CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(in[k] + stbi__paeth(cur[k-img_n],prior[k],prior[k-img_n])); break; + CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(in[k] + (cur[k-img_n] >> 1)); break; + CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(in[k] + stbi__paeth(cur[k-img_n],0,0)); break; } #undef CASE } else { STBI_ASSERT(img_n+1 == out_n); #define CASE(f) \ case f: \ - for (i=x-1; i >= 1; --i, cur[img_n]=255,cur+=out_n,prior+=out_n) \ - for (k=0; k < img_n; ++k, ++rawk) + for (i=x-1; i >= 1; --i, cur[img_n]=255,in+=img_n,cur+=out_n,prior+=out_n) \ + for (k=0; k < img_n; ++k) switch (filter) { - CASE(STBI__F_none) cur[k] = PIXEL(raw,k); break; - CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(PIXEL(raw,rawk) + cur[k-out_n]); break; - CASE(STBI__F_up) cur[k] = STBI__BYTECAST(PIXEL(raw,rawk) + prior[k]); break; - CASE(STBI__F_avg) cur[k] = STBI__BYTECAST(PIXEL(raw,rawk) + ((prior[k] + cur[k-out_n])>>1)); break; - CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(PIXEL(raw,rawk) + stbi__paeth(cur[k-out_n],prior[k],prior[k-out_n])); break; - CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(PIXEL(raw,rawk) + (cur[k-out_n] >> 1)); break; - CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(PIXEL(raw,rawk) + stbi__paeth(cur[k-out_n],0,0)); break; + CASE(STBI__F_none) cur[k] = in[k]; break; + CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(in[k] + cur[k-out_n]); break; + CASE(STBI__F_up) cur[k] = STBI__BYTECAST(in[k] + prior[k]); break; + CASE(STBI__F_avg) cur[k] = STBI__BYTECAST(in[k] + ((prior[k] + cur[k-out_n])>>1)); break; + CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(in[k] + stbi__paeth(cur[k-out_n],prior[k],prior[k-out_n])); break; + CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(in[k] + (cur[k-out_n] >> 1)); break; + CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(in[k] + stbi__paeth(cur[k-out_n],0,0)); break; } #undef CASE } - raw+=(rawk+pixel_data_shift_addr_mask)>>addr_shift; // scanlines are aligned on byte boundaries } + + if (depth != 8) free(line8); return 1; } -static int stbi__create_png_image(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, int depth, int interlaced) +static int stbi__create_png_image(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, int depth, int color, int interlaced) { stbi_uc *final; int p; if (!interlaced) - return stbi__create_png_image_raw(a, raw, raw_len, out_n, a->s->img_x, a->s->img_y, depth); + return stbi__create_png_image_raw(a, raw, raw_len, out_n, a->s->img_x, a->s->img_y, depth, color); // de-interlacing final = (stbi_uc *) stbi__malloc(a->s->img_x * a->s->img_y * out_n); @@ -2609,7 +2642,7 @@ static int stbi__create_png_image(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_l x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; if (x && y) { - if (!stbi__create_png_image_raw(a, raw, raw_len, out_n, x, y, depth)) { + if (!stbi__create_png_image_raw(a, raw, raw_len, out_n, x, y, depth, color)) { free(final); return 0; } @@ -2749,7 +2782,7 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) stbi_uc palette[1024], pal_img_n=0; stbi_uc has_trans=0, tc[3]; stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; - int first=1,k,interlace=0, depth=0, is_iphone=0; + int first=1,k,interlace=0, color=0, depth=0, is_iphone=0; stbi__context *s = z->s; z->expanded = NULL; @@ -2768,19 +2801,14 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) stbi__skip(s, c.length); break; case PNG_TYPE('I','H','D','R'): { - int color,comp,filter; + int comp,filter; if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); first = 0; if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); - depth = stbi__get8(s); + depth = stbi__get8(s); if (depth != 1 && depth != 2 && depth != 4 && depth != 8) return stbi__err("1/2/4/8-bit only","PNG not supported: 1/2/4/8-bit only"); color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); - if (color == 3) { - if (depth != 1 && depth != 2 && depth != 4 && depth != 8) return stbi__err("1/2/4/8-bit only","PNG not supported: 1/2/4/8-bit only for palettized images"); // support 1/2/4 bpp for palettized. - } else { - if (depth != 8) return stbi__err("8-bit only","PNG not supported: 8-bit only"); // greyscale images (color==0) would need the pixel data to be scaled (see PIXEL macro) - } if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); @@ -2863,7 +2891,7 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) s->img_out_n = s->img_n+1; else s->img_out_n = s->img_n; - if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, depth, interlace)) return 0; + if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, depth, color, interlace)) return 0; if (has_trans) if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) From 09a1ab87a0af969b99f325577520033667a83f1a Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 25 Sep 2014 23:52:24 +0100 Subject: [PATCH 03/46] Fix for interlaced and small images + cleanup --- stb_image.h | 50 ++++++++++++++++++++++---------------------------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/stb_image.h b/stb_image.h index ac1fab4..543e696 100644 --- a/stb_image.h +++ b/stb_image.h @@ -2500,10 +2500,7 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r a->out = (stbi_uc *) stbi__malloc(x * y * out_n); if (!a->out) return stbi__err("outofmem", "Out of memory"); - img_len = (img_n * x) * y; - if (depth<8) img_len /= (8/depth); - else if (depth>8) img_len *= depth>>3; - img_len += y; + img_len = ((((img_n * x * depth) + 7) >> 3) + 1) * y; if (s->img_x == x && s->img_y == y) { if (raw_len != img_len) return stbi__err("not enough pixels","Corrupt PNG"); } else { // interlaced: @@ -2511,7 +2508,7 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r } if (depth != 8) { - line8 = (stbi_uc *) stbi__malloc((x+3) * out_n); // allocate buffer for one scanline + line8 = (stbi_uc *) stbi__malloc((x+7) * out_n); // allocate buffer for one scanline if (!line8) return stbi__err("outofmem", "Out of memory"); } @@ -2533,35 +2530,31 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r // 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 in = line8; - stbi_uc* decode_in = raw; stbi_uc* decode_out = line8; stbi_uc scale = (color == 0) ? 0xFF/((1<= 1; i-=2, decode_in++) { - *decode_out++ = scale * ((*decode_in >> 4) ); - *decode_out++ = scale * ((*decode_in ) & 0x0f); + for (k=x*img_n; k >= 1; k-=2, raw++) { + *decode_out++ = scale * ((*raw >> 4) ); + *decode_out++ = scale * ((*raw ) & 0x0f); } - raw+=(x*img_n+1)>>1; } else if (depth == 2) { - for (i=x*img_n; i >= 1; i-=4, decode_in++) { - *decode_out++ = scale * ((*decode_in >> 6) ); - *decode_out++ = scale * ((*decode_in >> 4) & 0x03); - *decode_out++ = scale * ((*decode_in >> 2) & 0x03); - *decode_out++ = scale * ((*decode_in ) & 0x03); + for (k=x*img_n; k >= 1; k-=4, raw++) { + *decode_out++ = scale * ((*raw >> 6) ); + *decode_out++ = scale * ((*raw >> 4) & 0x03); + *decode_out++ = scale * ((*raw >> 2) & 0x03); + *decode_out++ = scale * ((*raw ) & 0x03); } - raw+=(x*img_n+3)>>2; } else if (depth == 1) { - for (i=x*img_n; i >= 1; i-=8, decode_in++) { - *decode_out++ = scale * ((*decode_in >> 7) ); - *decode_out++ = scale * ((*decode_in >> 6) & 0x01); - *decode_out++ = scale * ((*decode_in >> 5) & 0x01); - *decode_out++ = scale * ((*decode_in >> 4) & 0x01); - *decode_out++ = scale * ((*decode_in >> 3) & 0x01); - *decode_out++ = scale * ((*decode_in >> 2) & 0x01); - *decode_out++ = scale * ((*decode_in >> 1) & 0x01); - *decode_out++ = scale * ((*decode_in ) & 0x01); + for (k=x*img_n; k >= 1; k-=8, raw++) { + *decode_out++ = scale * ((*raw >> 7) ); + *decode_out++ = scale * ((*raw >> 6) & 0x01); + *decode_out++ = scale * ((*raw >> 5) & 0x01); + *decode_out++ = scale * ((*raw >> 4) & 0x01); + *decode_out++ = scale * ((*raw >> 3) & 0x01); + *decode_out++ = scale * ((*raw >> 2) & 0x01); + *decode_out++ = scale * ((*raw >> 1) & 0x01); + *decode_out++ = scale * ((*raw ) & 0x01); } - raw+=(x*img_n+7)>>3; } } @@ -2642,6 +2635,7 @@ static int stbi__create_png_image(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_l x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; if (x && y) { + stbi__uint32 img_len = ((((out_n * x * depth) + 7) >> 3) + 1) * y; if (!stbi__create_png_image_raw(a, raw, raw_len, out_n, x, y, depth, color)) { free(final); return 0; @@ -2651,8 +2645,8 @@ static int stbi__create_png_image(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_l memcpy(final + (j*yspc[p]+yorig[p])*a->s->img_x*out_n + (i*xspc[p]+xorig[p])*out_n, a->out + (j*x+i)*out_n, out_n); free(a->out); - raw += (x*out_n+1)*y; - raw_len -= (x*out_n+1)*y; + raw += img_len; + raw_len -= img_len; } } a->out = final; From 50d975261296fd7be2849f98defdc3f3f8f389c6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 26 Sep 2014 00:01:45 +0100 Subject: [PATCH 04/46] Removing tabs and using 3-spaces indents to match local coding style --- stb_image.h | 88 ++++++++++++++++++++++++++--------------------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/stb_image.h b/stb_image.h index 543e696..93c2d4a 100644 --- a/stb_image.h +++ b/stb_image.h @@ -2508,55 +2508,55 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r } if (depth != 8) { - line8 = (stbi_uc *) stbi__malloc((x+7) * out_n); // allocate buffer for one scanline - if (!line8) return stbi__err("outofmem", "Out of memory"); + line8 = (stbi_uc *) stbi__malloc((x+7) * out_n); // allocate buffer for one scanline + if (!line8) return stbi__err("outofmem", "Out of memory"); } for (j=0; j < y; ++j) { - stbi_uc *in; + stbi_uc *in; stbi_uc *cur = a->out + stride*j; stbi_uc *prior = cur - stride; int filter = *raw++; if (filter > 4) { - if (depth != 8) free(line8); - return stbi__err("invalid filter","Corrupt PNG"); - } + if (depth != 8) free(line8); + return stbi__err("invalid filter","Corrupt PNG"); + } - if (depth == 8) { - in = raw; - raw += x*img_n; - } - else { - // 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 - in = line8; - stbi_uc* decode_out = line8; - stbi_uc scale = (color == 0) ? 0xFF/((1<= 1; k-=2, raw++) { - *decode_out++ = scale * ((*raw >> 4) ); - *decode_out++ = scale * ((*raw ) & 0x0f); - } - } else if (depth == 2) { - for (k=x*img_n; k >= 1; k-=4, raw++) { - *decode_out++ = scale * ((*raw >> 6) ); - *decode_out++ = scale * ((*raw >> 4) & 0x03); - *decode_out++ = scale * ((*raw >> 2) & 0x03); - *decode_out++ = scale * ((*raw ) & 0x03); - } - } else if (depth == 1) { - for (k=x*img_n; k >= 1; k-=8, raw++) { - *decode_out++ = scale * ((*raw >> 7) ); - *decode_out++ = scale * ((*raw >> 6) & 0x01); - *decode_out++ = scale * ((*raw >> 5) & 0x01); - *decode_out++ = scale * ((*raw >> 4) & 0x01); - *decode_out++ = scale * ((*raw >> 3) & 0x01); - *decode_out++ = scale * ((*raw >> 2) & 0x01); - *decode_out++ = scale * ((*raw >> 1) & 0x01); - *decode_out++ = scale * ((*raw ) & 0x01); - } - } - } + if (depth == 8) { + in = raw; + raw += x*img_n; + } + else { + // 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 + in = line8; + stbi_uc* decode_out = line8; + stbi_uc scale = (color == 0) ? 0xFF/((1<= 1; k-=2, raw++) { + *decode_out++ = scale * ((*raw >> 4) ); + *decode_out++ = scale * ((*raw ) & 0x0f); + } + } else if (depth == 2) { + for (k=x*img_n; k >= 1; k-=4, raw++) { + *decode_out++ = scale * ((*raw >> 6) ); + *decode_out++ = scale * ((*raw >> 4) & 0x03); + *decode_out++ = scale * ((*raw >> 2) & 0x03); + *decode_out++ = scale * ((*raw ) & 0x03); + } + } else if (depth == 1) { + for (k=x*img_n; k >= 1; k-=8, raw++) { + *decode_out++ = scale * ((*raw >> 7) ); + *decode_out++ = scale * ((*raw >> 6) & 0x01); + *decode_out++ = scale * ((*raw >> 5) & 0x01); + *decode_out++ = scale * ((*raw >> 4) & 0x01); + *decode_out++ = scale * ((*raw >> 3) & 0x01); + *decode_out++ = scale * ((*raw >> 2) & 0x01); + *decode_out++ = scale * ((*raw >> 1) & 0x01); + *decode_out++ = scale * ((*raw ) & 0x01); + } + } + } // if first row, use special filter that doesn't sample previous row if (j == 0) filter = first_row_filter[filter]; @@ -2574,7 +2574,7 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r } } if (img_n != out_n) cur[img_n] = 255; - in += img_n; + in += img_n; cur += out_n; prior += out_n; // this is a little gross, so that we don't switch per-pixel or per-component @@ -2635,7 +2635,7 @@ static int stbi__create_png_image(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_l x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; if (x && y) { - stbi__uint32 img_len = ((((out_n * x * depth) + 7) >> 3) + 1) * y; + stbi__uint32 img_len = ((((out_n * x * depth) + 7) >> 3) + 1) * y; if (!stbi__create_png_image_raw(a, raw, raw_len, out_n, x, y, depth, color)) { free(final); return 0; @@ -4626,7 +4626,7 @@ STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int 1.45 (2014-08-16) fix MSVC-ARM internal compiler error by wrapping malloc 1.44 (2014-08-07) - various warning fixes from Ronny Chevalier + various warning fixes from Ronny Chevalier 1.43 (2014-07-15) fix MSVC-only compiler problem in code changed in 1.42 1.42 (2014-07-09) From 1be86b37d66b7675ad90bd81e22db417f6beef08 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 26 Sep 2014 00:06:30 +0100 Subject: [PATCH 05/46] Documentation --- stb_image.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stb_image.h b/stb_image.h index 93c2d4a..5ab9c58 100644 --- a/stb_image.h +++ b/stb_image.h @@ -13,7 +13,7 @@ avoid problematic images and only need the trivial interface JPEG baseline (no JPEG progressive) - PNG 8-bit-per-channel only + PNG 1/2/4/8-bit-per-channel (16 bpc not supported) TGA (not sure what subset, if a subset) BMP non-1bpp, non-RLE @@ -28,6 +28,7 @@ - overridable dequantizing-IDCT, YCbCr-to-RGB conversion (define STBI_SIMD) Latest revisions: + 1.xx (2014-09-26) 1/2/4-bit PNG support (both grayscale and paletted) 1.46 (2014-08-26) fix broken tRNS chunk in non-paletted PNG 1.45 (2014-08-16) workaround MSVC-ARM internal compiler error by wrapping malloc 1.44 (2014-08-07) warnings From 5f81a92cdd432e7785026f26bb760338725e5c86 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Tue, 2 Dec 2014 02:58:08 -0800 Subject: [PATCH 06/46] use explicit float constants to avoid warnings in some compilers --- stb_tilemap_editor.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/stb_tilemap_editor.h b/stb_tilemap_editor.h index 161b0d7..ed56a10 100644 --- a/stb_tilemap_editor.h +++ b/stb_tilemap_editor.h @@ -1971,14 +1971,14 @@ static int stbte__float_control(int x0, int y0, int w, float minv, float maxv, f stbte__ui.accum_y -= ay*STBTE_FLOAT_CONTROL_GRANULARITY; if (stbte__ui.shift) { if (stbte__ui.active_event == STBTE__leftdown) - delta = ax * 16 + ay; + delta = ax * 16.0f + ay; else - delta = ax / 16.0 + ay / 256.0; + delta = ax / 16.0f + ay / 256.0f; } else { if (stbte__ui.active_event == STBTE__leftdown) - delta = ax*10 + ay; + delta = ax*10.0f + ay; else - delta = ax * 0.1 + ay * 0.01; + delta = ax * 0.1f + ay * 0.01f; } v += delta * scale; if (v < minv) v = minv; @@ -3553,8 +3553,8 @@ static void stbte__props_panel(stbte_tilemap *tm, int x0, int y0, int w, int h) int flag = (int) p[i]; if (stbte__layerbutton(x,y, flag ? 'x' : ' ', STBTE__ID(STBTE__prop_flag,i), flag, 0, 2)) { stbte__begin_undo(tm); - stbte__undo_record_prop_float(tm,mx,my,i,flag); - p[i] = !flag; + stbte__undo_record_prop_float(tm,mx,my,i,(float) flag); + p[i] = (float) !flag; stbte__end_undo(tm); } stbte__draw_text(x+13,y+1,s,x1-(x+13)-2,STBTE__TEXTCOLOR(STBTE__cpanel)); @@ -3568,7 +3568,7 @@ static void stbte__props_panel(stbte_tilemap *tm, int x0, int y0, int w, int h) if (a+v != p[i] || v < 0 || v > b-a) { if (v < 0) v = 0; if (v > b-a) v = b-a; - p[i] = a+v; // @TODO undo + p[i] = (float) (a+v); // @TODO undo } switch (stbte__slider(x, slider_width, y+7, b-a, &v, STBTE__ID(STBTE__prop_int,i))) { @@ -3576,7 +3576,7 @@ static void stbte__props_panel(stbte_tilemap *tm, int x0, int y0, int w, int h) stbte__saved = p[i]; // fallthrough case STBTE__change: - p[i] = a+v; // @TODO undo + p[i] = (float) (a+v); // @TODO undo break; case STBTE__end: if (p[i] != stbte__saved) { From 37c95d8d55f495b15a51dba2170b3a865e463110 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Tue, 2 Dec 2014 02:59:05 -0800 Subject: [PATCH 07/46] add internal version number for use by stb_truetype --- stb_rect_pack.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/stb_rect_pack.h b/stb_rect_pack.h index 373b105..76a02cb 100644 --- a/stb_rect_pack.h +++ b/stb_rect_pack.h @@ -1,4 +1,4 @@ -// stb_rect_pack.h - v0.02 - public domain - rectangle packing +// stb_rect_pack.h - v0.03 - public domain - rectangle packing // Sean Barrett 2014 // // Useful for e.g. packing rectangular textures into an atlas. @@ -29,6 +29,8 @@ #ifndef STB_INCLUDE_STB_RECT_PACK_H #define STB_INCLUDE_STB_RECT_PACK_H +#define STB_RECT_PACK_VERSION 1 + #ifdef STBRP_STATIC #define STBRP_DEF static #else From 0a3dd5aff36e7265d1a439bed3dfc80c3f7e31b8 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Tue, 2 Dec 2014 02:59:44 -0800 Subject: [PATCH 08/46] new font bitmap baking API --- stb_truetype.h | 187 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 186 insertions(+), 1 deletion(-) diff --git a/stb_truetype.h b/stb_truetype.h index 1c0ab4b..8aea661 100644 --- a/stb_truetype.h +++ b/stb_truetype.h @@ -463,6 +463,44 @@ extern void stbtt_GetBakedQuad(stbtt_bakedchar *chardata, int pw, int ph, // sa // It's inefficient; you might want to c&p it and optimize it. + +////////////////////////////////////////////////////////////////////////////// +// +// NEW TEXTURE BAKING API +// +// This provides options for packing multiple fonts into one atlas, not +// perfectly but better than nothing. + +typedef struct stbtt_pack_context stbtt_pack_context; +typedef struct +{ + float font_size; // if positive, pixel height; if negative, points + int first_unicode_char_in_range; + int num_chars_in_range; + stbtt_bakedchar *chardata_for_range; // output +} stbtt_pack_range; + +extern int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int ph, int stride_in_bytes, void *alloc_context); +// returns 0 if the allocations fail + +extern void stbtt_PackEnd (stbtt_pack_context *spc); +extern int stbtt_PackFontRange(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, float font_size, + int first_unicode_char_in_range, int num_chars_in_range, stbtt_bakedchar *chardata_for_range); +extern int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges); + + +// this is an opaque structure that you shouldn't mess with which holds +// all the context needed from PackBegin to PackEnd. +struct stbtt_pack_context { + void *user_allocator_context; + void *pack_info; + int width; + int height; + int stride_in_bytes; + unsigned char *pixels; + void *nodes; +}; + ////////////////////////////////////////////////////////////////////////////// // // FONT LOADING @@ -1880,7 +1918,8 @@ extern int stbtt_BakeFontBitmap(const unsigned char *data, int offset, // font float scale; int x,y,bottom_y, i; stbtt_fontinfo f; - stbtt_InitFont(&f, data, offset); + if (!stbtt_InitFont(&f, data, offset)) + return -1; STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels x=y=1; bottom_y = 1; @@ -1936,6 +1975,152 @@ void stbtt_GetBakedQuad(stbtt_bakedchar *chardata, int pw, int ph, int char_inde *xpos += b->xadvance; } +////////////////////////////////////////////////////////////////////////////// +// +// bitmap baking +// +// This is SUPER-AWESOME (tm Ryan Gordon) packing using stb_rect_pack.h. If +// stb_rect_pack.h isn't available, it uses the BakeFontBitmap strategy. + +#ifndef STB_RECT_PACK_VERSION +// @TODO: simulate STB_RECT_PACK API with trivial logic from BakeFontBitmap, +// try to share code?!? +#error "no stb_rect_pack" +#endif + +#if 0 +struct stbtt_pack_context { + void *user_allocator_context; + void *pack_info; + int width; + int height; + unsigned char *pixels; +}; +#endif + +int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int ph, int stride_in_bytes, void *alloc_context) +{ + stbrp_context *context = (stbrp_context *) STBTT_malloc(sizeof(*context) ,alloc_context); + int num_nodes = pw-1; + stbrp_node *nodes = (stbrp_node *) STBTT_malloc(sizeof(*nodes ) * num_nodes,alloc_context); + + if (context == NULL || nodes == NULL) { + if (context != NULL) STBTT_free(context, alloc_context); + if (nodes != NULL) STBTT_free(nodes , alloc_context); + return 0; + } + + spc->user_allocator_context = alloc_context; + spc->width = pw; + spc->height = ph; + spc->pixels = pixels; + spc->pack_info = context; + spc->nodes = nodes; + spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw; + + stbrp_init_target(context, pw-1, ph-1, nodes, num_nodes); + + STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels + + return 1; +} + +void stbtt_PackEnd (stbtt_pack_context *spc) +{ + STBTT_free(spc->nodes , spc->user_allocator_context); + STBTT_free(spc->pack_info, spc->user_allocator_context); +} + +int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges) +{ + stbtt_fontinfo info; + int i,j,k,n, return_value = 1; + stbrp_context *context = (stbrp_context *) spc->pack_info; + stbrp_rect *rects; + + // flag all characters as NOT packed + for (i=0; i < num_ranges; ++i) + for (j=0; j < ranges[i].num_chars_in_range; ++j) + ranges[i].chardata_for_range[j].x0 = + ranges[i].chardata_for_range[j].y0 = + ranges[i].chardata_for_range[j].x1 = + ranges[i].chardata_for_range[j].y1 = 0; + + n = 0; + for (i=0; i < num_ranges; ++i) + n += ranges[i].num_chars_in_range; + + rects = STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context); + if (rects == NULL) + return 0; + + stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index)); + k=0; + for (i=0; i < num_ranges; ++i) { + float fh = ranges[i].font_size; + //float scale = fh > 0 ? stbtt_ScaleForPixelHeight(&info, fh) : stbtt_ScaleForPointSize(&info, fh); + float scale = stbtt_ScaleForPixelHeight(&info, fh); + for (j=0; j < ranges[i].num_chars_in_range; ++j) { + int x0,y0,x1,y1; + stbtt_GetCodepointBitmapBox(&info, ranges[i].first_unicode_char_in_range + j, scale,scale, &x0,&y0,&x1,&y1); + rects[k].w = x1-x0+1; + rects[k].h = y1-y0+1; + ++k; + } + } + + stbrp_pack_rects(context, rects, k); + + k = 0; + for (i=0; i < num_ranges; ++i) { + float fh = ranges[i].font_size; + //float scale = fh > 0 ? stbtt_ScaleForPixelHeight(&info, fh) : stbtt_ScaleForPointSize(&info, fh); + float scale = stbtt_ScaleForPixelHeight(&info, fh); + for (j=0; j < ranges[i].num_chars_in_range; ++j) { + stbrp_rect *r = &rects[k]; + if (r->was_packed) { + stbtt_bakedchar *bc = &ranges[i].chardata_for_range[j]; + int advance, lsb, x0,y0,x1,y1; + int glyph = stbtt_FindGlyphIndex(&info, ranges[i].first_unicode_char_in_range + j); + + stbtt_GetGlyphHMetrics(&info, glyph, &advance, &lsb); + stbtt_GetGlyphBitmapBox(&info, glyph, scale,scale, &x0,&y0,&x1,&y1); + stbtt_MakeGlyphBitmapSubpixel(&info, + spc->pixels + r->x + r->y*spc->stride_in_bytes, + r->w-1, r->h-1, + spc->stride_in_bytes, + scale,scale, + 0.0f, 0.0f, + glyph); + bc->x0 = (stbtt_int16) r->x; + bc->y0 = (stbtt_int16) r->y; + bc->x1 = (stbtt_int16) (r->x + r->w-1); + bc->y1 = (stbtt_int16) (r->y + r->h-1); + bc->xadvance = scale * advance; + bc->xoff = (float) x0; + bc->yoff = (float) y0; + } else { + return_value = 0; // if any fail, report failure + } + + ++k; + } + } + + return return_value; +} + +int stbtt_PackFontRange(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, float font_size, + int first_unicode_char_in_range, int num_chars_in_range, stbtt_bakedchar *chardata_for_range) +{ + stbtt_pack_range range; + range.first_unicode_char_in_range = first_unicode_char_in_range; + range.num_chars_in_range = num_chars_in_range; + range.chardata_for_range = chardata_for_range; + range.font_size = font_size; + return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1); +} + ////////////////////////////////////////////////////////////////////////////// // // font name matching -- recommended not to use this From b6f8358f47a814055d04a4de09fdc336d94d5d3c Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Tue, 2 Dec 2014 03:00:08 -0800 Subject: [PATCH 09/46] various fixes for compilation test --- tests/resize.dsp | 2 +- tests/stb.dsp | 8 +++++++ tests/test_c_compilation.c | 7 +++--- tests/test_cpp_compilation.cpp | 6 +++-- tests/test_truetype.c | 43 +++++++++++++++++++++++++++++++++- 5 files changed, 59 insertions(+), 7 deletions(-) diff --git a/tests/resize.dsp b/tests/resize.dsp index e670af2..ee7e7d7 100644 --- a/tests/resize.dsp +++ b/tests/resize.dsp @@ -65,7 +65,7 @@ LINK32=link.exe # PROP Intermediate_Dir "Debug" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /WX /Gm /GX /ZI /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe diff --git a/tests/stb.dsp b/tests/stb.dsp index a68755a..98039d0 100644 --- a/tests/stb.dsp +++ b/tests/stb.dsp @@ -126,10 +126,18 @@ SOURCE=..\stb_perlin.h # End Source File # Begin Source File +SOURCE=..\stb_rect_pack.h +# End Source File +# Begin Source File + SOURCE=..\stb_textedit.h # End Source File # Begin Source File +SOURCE=..\stb_tilemap_editor.h +# End Source File +# Begin Source File + SOURCE=..\stb_truetype.h # End Source File # Begin Source File diff --git a/tests/test_c_compilation.c b/tests/test_c_compilation.c index 25ff374..2aa85b0 100644 --- a/tests/test_c_compilation.c +++ b/tests/test_c_compilation.c @@ -6,6 +6,7 @@ #define STB_IMAGE_IMPLEMENTATION #define STB_HERRINGBONE_WANG_TILE_IMEPLEMENTATIOn #define STB_IMAGE_RESIZE_IMPLEMENTATION +#define STB_RECT_PACK_IMPLEMENTATION #include "stb_herringbone_wang_tile.h" #include "stb_image.h" @@ -15,9 +16,9 @@ #include "stb_c_lexer.h" #include "stb_divide.h" #include "stb_image_resize.h" +#include "stb_rect_pack.h" - -#define STBTE_DRAW_RECT(x0,y0,x1,y1,color) 0 -#define STBTE_DRAW_TILE(x,y,id,highlight) 0 +#define STBTE_DRAW_RECT(x0,y0,x1,y1,color) 0 +#define STBTE_DRAW_TILE(x,y,id,highlight,data) 0 #define STB_TILEMAP_EDITOR_IMPLEMENTATION #include "stb_tilemap_editor.h" diff --git a/tests/test_cpp_compilation.cpp b/tests/test_cpp_compilation.cpp index 3f33d89..20a2eb7 100644 --- a/tests/test_cpp_compilation.cpp +++ b/tests/test_cpp_compilation.cpp @@ -6,6 +6,7 @@ #define STB_DIVIDE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION #define STB_HERRINGBONE_WANG_TILE_IMPLEMENTATION +#define STB_RECT_PACK_IMPLEMENTATION #include "stb_truetype.h" #include "stb_image_write.h" @@ -15,8 +16,9 @@ #include "stb_divide.h" #include "stb_image.h" #include "stb_herringbone_wang_tile.h" +#include "stb_rect_pack.h" -#define STBTE_DRAW_RECT(x0,y0,x1,y1,color) -#define STBTE_DRAW_TILE(x,y,id,highlight) +#define STBTE_DRAW_RECT(x0,y0,x1,y1,color) do ; while(0) +#define STBTE_DRAW_TILE(x,y,id,highlight,data) do ; while(0) #define STB_TILEMAP_EDITOR_IMPLEMENTATION #include "stb_tilemap_editor.h" diff --git a/tests/test_truetype.c b/tests/test_truetype.c index 4706f22..07fae7d 100644 --- a/tests/test_truetype.c +++ b/tests/test_truetype.c @@ -1,5 +1,7 @@ +#include "stb_rect_pack.h" #define STB_TRUETYPE_IMPLEMENTATION #include "stb_truetype.h" +#include "stb_image_write.h" #include @@ -17,16 +19,55 @@ void debug(void) stbtt_MakeGlyphBitmap(&font, output, 6, 9, 512, 5.172414E-03f, 5.172414E-03f, 54); } +#define BITMAP_W 256 +#define BITMAP_H 400 +unsigned char temp_bitmap[BITMAP_H][BITMAP_W]; +stbtt_bakedchar cdata[256*2]; // ASCII 32..126 is 95 glyphs int main(int argc, char **argv) { stbtt_fontinfo font; unsigned char *bitmap; int w,h,i,j,c = (argc > 1 ? atoi(argv[1]) : 34807), s = (argc > 2 ? atoi(argv[2]) : 32); - debug(); + //debug(); + // @TODO: why is minglui.ttc failing? fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/mingliu.ttc", "rb")); + stbtt_BakeFontBitmap(ttf_buffer,stbtt_GetFontOffsetForIndex(ttf_buffer,0), 40.0, temp_bitmap[0],BITMAP_W,BITMAP_H, 32,96, cdata); // no guarantee this fits! + stbi_write_png("fonttest1.png", BITMAP_W, BITMAP_H, 1, temp_bitmap, 0); + + stbtt_BakeFontBitmap(ttf_buffer,stbtt_GetFontOffsetForIndex(ttf_buffer,0), 40.0, temp_bitmap[0],BITMAP_W,BITMAP_H, 32,96, cdata); // no guarantee this fits! + + { + stbtt_pack_context pc; + stbtt_PackBegin(&pc, temp_bitmap[0], BITMAP_W, BITMAP_H, 0, NULL); + stbtt_PackFontRange(&pc, ttf_buffer, 0, 40.0, 32, 95, cdata); + stbtt_PackFontRange(&pc, ttf_buffer, 0, 40.0, 0xa0, 0x100-0xa0, cdata); + stbtt_PackEnd(&pc); + stbi_write_png("fonttest2.png", BITMAP_W, BITMAP_H, 1, temp_bitmap, 0); + } + + { + stbtt_pack_context pc; + stbtt_pack_range pr[2]; + stbtt_PackBegin(&pc, temp_bitmap[0], BITMAP_W, BITMAP_H, 0, NULL); + + pr[0].chardata_for_range = cdata; + pr[0].first_unicode_char_in_range = 32; + pr[0].num_chars_in_range = 95; + pr[0].font_size = 40.0; + pr[1].chardata_for_range = cdata+256; + pr[1].first_unicode_char_in_range = 0xa0; + pr[1].num_chars_in_range = 0x100 - 0xa0; + pr[1].font_size = 40.0; + + stbtt_PackFontRanges(&pc, ttf_buffer, 0, pr, 2); + stbtt_PackEnd(&pc); + stbi_write_png("fonttest3.png", BITMAP_W, BITMAP_H, 1, temp_bitmap, 0); + } + return 0; + stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0)); bitmap = stbtt_GetCodepointBitmap(&font, 0,stbtt_ScaleForPixelHeight(&font, (float)s), c, &w, &h, 0,0); From f03e35209306fe5348330ce968f9282df88cca1b Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Sat, 6 Dec 2014 12:28:46 -0800 Subject: [PATCH 10/46] stb_rect_pack: fix LARGE_RECT bug stb_truetype: oversampling, including oversampling demo app --- stb_rect_pack.h | 10 +- stb_truetype.h | 343 +++++++++++-- tests/image_test.dsp | 2 +- tests/oversample/main.c | 272 +++++++++++ tests/oversample/oversample.dsp | 97 ++++ tests/oversample/oversample.dsw | 29 ++ tests/oversample/stb_wingraph.h | 824 ++++++++++++++++++++++++++++++++ tests/stb.dsp | 2 +- tests/stb_cpp.dsp | 2 +- tests/stretch_test.dsp | 6 +- tests/test_truetype.c | 22 +- 11 files changed, 1551 insertions(+), 58 deletions(-) create mode 100644 tests/oversample/main.c create mode 100644 tests/oversample/oversample.dsp create mode 100644 tests/oversample/oversample.dsw create mode 100644 tests/oversample/stb_wingraph.h diff --git a/stb_rect_pack.h b/stb_rect_pack.h index 76a02cb..5462379 100644 --- a/stb_rect_pack.h +++ b/stb_rect_pack.h @@ -495,6 +495,12 @@ static int rect_original_order(const void *a, const void *b) return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed); } +#ifdef STBRP_LARGE_RECTS +#define STBRP__MAXVAL 0xffffffff +#else +#define STBRP__MAXVAL 0xffff +#endif + STBRP_DEF void stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects) { int i; @@ -516,7 +522,7 @@ STBRP_DEF void stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int n rects[i].x = (stbrp_coord) fr.x; rects[i].y = (stbrp_coord) fr.y; } else { - rects[i].x = rects[i].y = 0xffff; + rects[i].x = rects[i].y = STBRP__MAXVAL; } } @@ -525,6 +531,6 @@ STBRP_DEF void stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int n // set was_packed flags for (i=0; i < num_rects; ++i) - rects[i].was_packed = !(rects[i].x == 0xffff && rects[i].y == 0xffff); + rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL); } #endif diff --git a/stb_truetype.h b/stb_truetype.h index 8aea661..4b7db1a 100644 --- a/stb_truetype.h +++ b/stb_truetype.h @@ -35,6 +35,9 @@ // Hou Qiming // Fabian "ryg" Giesen // +// Misc other: +// Ryan Gordon +// // VERSION HISTORY // // 0.99 (2014-09-18) fix multiple bugs with subpixel rendering (ryg) @@ -428,7 +431,7 @@ extern "C" { typedef struct { unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap - float xoff,yoff,xadvance; + float xoff,yoff,xadvance; } stbtt_bakedchar; extern int stbtt_BakeFontBitmap(const unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) @@ -471,24 +474,38 @@ extern void stbtt_GetBakedQuad(stbtt_bakedchar *chardata, int pw, int ph, // sa // This provides options for packing multiple fonts into one atlas, not // perfectly but better than nothing. +typedef struct +{ + unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap + float xoff,yoff,xadvance; + float xoff2,yoff2; +} stbtt_packedchar; + typedef struct stbtt_pack_context stbtt_pack_context; typedef struct { float font_size; // if positive, pixel height; if negative, points int first_unicode_char_in_range; int num_chars_in_range; - stbtt_bakedchar *chardata_for_range; // output + stbtt_packedchar *chardata_for_range; // output } stbtt_pack_range; -extern int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int ph, int stride_in_bytes, void *alloc_context); +extern int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int ph, int stride_in_bytes, int padding, void *alloc_context); // returns 0 if the allocations fail +extern void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample); extern void stbtt_PackEnd (stbtt_pack_context *spc); extern int stbtt_PackFontRange(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, float font_size, - int first_unicode_char_in_range, int num_chars_in_range, stbtt_bakedchar *chardata_for_range); + int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range); extern int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges); +extern void stbtt_GetPackedQuad(stbtt_packedchar *chardata, int pw, int ph, // same data as above + int char_index, // character to display + float *xpos, float *ypos, // pointers to current position in screen pixel space + stbtt_aligned_quad *q, // output: quad to draw + int align_to_integer); + // this is an opaque structure that you shouldn't mess with which holds // all the context needed from PackBegin to PackEnd. struct stbtt_pack_context { @@ -497,6 +514,8 @@ struct stbtt_pack_context { int width; int height; int stride_in_bytes; + int padding; + unsigned int h_oversample, v_oversample; unsigned char *pixels; void *nodes; }; @@ -808,6 +827,12 @@ enum { // languageID for STBTT_PLATFORM_ID_MAC #ifdef STB_TRUETYPE_IMPLEMENTATION +#ifndef STBTT_MAX_OVERSAMPLE +#define STBTT_MAX_OVERSAMPLE 8 +#endif + +typedef stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE-1)) == 0 ? 1 : -1]; + ////////////////////////////////////////////////////////////////////////// // // accessors to parse data from file @@ -1947,9 +1972,9 @@ extern int stbtt_BakeFontBitmap(const unsigned char *data, int offset, // font chardata[i].xadvance = scale * advance; chardata[i].xoff = (float) x0; chardata[i].yoff = (float) y0; - x = x + gw + 2; - if (y+gh+2 > bottom_y) - bottom_y = y+gh+2; + x = x + gw + 1; + if (y+gh+1 > bottom_y) + bottom_y = y+gh+1; } return bottom_y; } @@ -1975,6 +2000,78 @@ void stbtt_GetBakedQuad(stbtt_bakedchar *chardata, int pw, int ph, int char_inde *xpos += b->xadvance; } +////////////////////////////////////////////////////////////////////////////// +// +// rectangle packing replacement routines if you don't have stb_rect_pack.h +// + +#ifndef STB_RECT_PACK_VERSION +#ifdef _MSC_VER +#define STBTT__NOTUSED(v) (void)(v) +#else +#define STBTT__NOTUSED(v) (void)sizeof(v) +#endif + +//////////////////////////////////////////////////////////////////////////////////// +// // +// // +// COMPILER WARNING ?!?!? // +// // +// // +// if you get a compile warning due to these symbols being defined more than // +// once, move #include "stb_rect_pack.h" before #include "stb_truetype.h" // +// // +//////////////////////////////////////////////////////////////////////////////////// + +typedef struct +{ + int width,height; + int x,y,bottom_y; +} stbrp_context; + +typedef struct +{ + unsigned char x; +} stbrp_node; + +typedef struct +{ + int id,w,h,x,y,was_packed; +} stbrp_rect; + +static void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *nodes, int num_nodes) +{ + con->width = pw; + con->height = ph; + con->x = 0; + con->y = 0; + con->bottom_y = 0; + STBTT__NOTUSED(nodes); + STBTT__NOTUSED(num_nodes); +} + +static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects) +{ + int i; + for (i=0; i < num_rects; ++i) { + if (con->x + rects[i].w > con->width) { + con->x = 0; + con->y = con->bottom_y; + } + if (con->y + rects[i].h > con->height) + break; + rects[i].x = con->x; + rects[i].y = con->y; + rects[i].was_packed = 1; + con->x += rects[i].w; + if (con->y + rects[i].h > con->bottom_y) + con->bottom_y = con->y + rects[i].h; + } + for ( ; i < num_rects; ++i) + rects[i].was_packed = 0; +} +#endif + ////////////////////////////////////////////////////////////////////////////// // // bitmap baking @@ -1982,26 +2079,10 @@ void stbtt_GetBakedQuad(stbtt_bakedchar *chardata, int pw, int ph, int char_inde // This is SUPER-AWESOME (tm Ryan Gordon) packing using stb_rect_pack.h. If // stb_rect_pack.h isn't available, it uses the BakeFontBitmap strategy. -#ifndef STB_RECT_PACK_VERSION -// @TODO: simulate STB_RECT_PACK API with trivial logic from BakeFontBitmap, -// try to share code?!? -#error "no stb_rect_pack" -#endif - -#if 0 -struct stbtt_pack_context { - void *user_allocator_context; - void *pack_info; - int width; - int height; - unsigned char *pixels; -}; -#endif - -int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int ph, int stride_in_bytes, void *alloc_context) +int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int ph, int stride_in_bytes, int padding, void *alloc_context) { stbrp_context *context = (stbrp_context *) STBTT_malloc(sizeof(*context) ,alloc_context); - int num_nodes = pw-1; + int num_nodes = pw - padding; stbrp_node *nodes = (stbrp_node *) STBTT_malloc(sizeof(*nodes ) * num_nodes,alloc_context); if (context == NULL || nodes == NULL) { @@ -2016,9 +2097,12 @@ int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int spc->pixels = pixels; spc->pack_info = context; spc->nodes = nodes; + spc->padding = padding; spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw; + spc->h_oversample = 1; + spc->v_oversample = 1; - stbrp_init_target(context, pw-1, ph-1, nodes, num_nodes); + stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes); STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels @@ -2031,9 +2115,135 @@ void stbtt_PackEnd (stbtt_pack_context *spc) STBTT_free(spc->pack_info, spc->user_allocator_context); } +void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample) +{ + assert(h_oversample <= STBTT_MAX_OVERSAMPLE); + assert(v_oversample <= STBTT_MAX_OVERSAMPLE); + if (h_oversample <= STBTT_MAX_OVERSAMPLE) + spc->h_oversample = h_oversample; + if (v_oversample <= STBTT_MAX_OVERSAMPLE) + spc->v_oversample = v_oversample; +} + +#define STBTT__OVER_MASK (STBTT_MAX_OVERSAMPLE-1) + +static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) +{ + unsigned char buffer[STBTT_MAX_OVERSAMPLE]; + int safe_w = w - kernel_width; + int j; + for (j=0; j < h; ++j) { + int i; + unsigned int total; + unsigned char *pixels_ahead = pixels + (kernel_width); + memset(buffer, 0, kernel_width); + + total = 0; + + // make kernel_width a constant in common cases so compiler can optimize out the divide + switch (kernel_width) { + case 2: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = total / 2; + } + break; + case 3: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = total / 3; + } + break; + case 4: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = total / 4; + } + break; + default: + for (i=0; i <= safe_w; ++i) { + total += pixels[i] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; + pixels[i] = total / kernel_width; + } + break; + } + + for (; i < w; ++i) { + assert(pixels[i] == 0); + total -= buffer[i & STBTT__OVER_MASK]; + pixels[i] = total / kernel_width; + } + + pixels += stride_in_bytes; + } +} + +static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) +{ + unsigned char buffer[STBTT_MAX_OVERSAMPLE]; + int safe_h = h - kernel_width; + int j; + for (j=0; j < w; ++j) { + int i; + unsigned int total; + unsigned char *pixels_ahead = pixels + (kernel_width)*stride_in_bytes; + memset(buffer, 0, kernel_width); + + total = 0; + + // make kernel_width a constant in common cases so compiler can optimize out the divide + switch (kernel_width) { + case 2: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = total / 2; + } + break; + case 3: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = total / 3; + } + break; + case 4: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = total / 4; + } + break; + default: + for (i=0; i <= safe_h; ++i) { + total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; + buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; + pixels[i*stride_in_bytes] = total / kernel_width; + } + break; + } + + for (; i < h; ++i) { + assert(pixels[i*stride_in_bytes] == 0); + total -= buffer[i & STBTT__OVER_MASK]; + pixels[i*stride_in_bytes] = total / kernel_width; + } + + pixels += 1; + } +} + int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges) { stbtt_fontinfo info; + float recip_h = 1.0f / spc->h_oversample; + float recip_v = 1.0f / spc->v_oversample; + float sub_x = spc->h_oversample ? recip_h : 0; + float sub_y = spc->v_oversample ? recip_v : 0; int i,j,k,n, return_value = 1; stbrp_context *context = (stbrp_context *) spc->pack_info; stbrp_rect *rects; @@ -2062,9 +2272,13 @@ int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontdata, int f float scale = stbtt_ScaleForPixelHeight(&info, fh); for (j=0; j < ranges[i].num_chars_in_range; ++j) { int x0,y0,x1,y1; - stbtt_GetCodepointBitmapBox(&info, ranges[i].first_unicode_char_in_range + j, scale,scale, &x0,&y0,&x1,&y1); - rects[k].w = x1-x0+1; - rects[k].h = y1-y0+1; + stbtt_GetCodepointBitmapBoxSubpixel(&info, ranges[i].first_unicode_char_in_range + j, + scale * spc->h_oversample, + scale * spc->v_oversample, + 0,0, + &x0,&y0,&x1,&y1); + rects[k].w = x1-x0 + spc->padding + spc->h_oversample-1; + rects[k].h = y1-y0 + spc->padding + spc->v_oversample-1; ++k; } } @@ -2079,26 +2293,49 @@ int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontdata, int f for (j=0; j < ranges[i].num_chars_in_range; ++j) { stbrp_rect *r = &rects[k]; if (r->was_packed) { - stbtt_bakedchar *bc = &ranges[i].chardata_for_range[j]; + stbtt_packedchar *bc = &ranges[i].chardata_for_range[j]; int advance, lsb, x0,y0,x1,y1; int glyph = stbtt_FindGlyphIndex(&info, ranges[i].first_unicode_char_in_range + j); + // pad on left and top + r->x += spc->padding; + r->y += spc->padding; + r->w -= spc->padding; + r->h -= spc->padding; stbtt_GetGlyphHMetrics(&info, glyph, &advance, &lsb); - stbtt_GetGlyphBitmapBox(&info, glyph, scale,scale, &x0,&y0,&x1,&y1); + stbtt_GetGlyphBitmapBox(&info, glyph, + scale * spc->h_oversample, + scale * spc->v_oversample, + &x0,&y0,&x1,&y1); stbtt_MakeGlyphBitmapSubpixel(&info, spc->pixels + r->x + r->y*spc->stride_in_bytes, - r->w-1, r->h-1, + r->w - spc->h_oversample+1, + r->h - spc->v_oversample+1, spc->stride_in_bytes, - scale,scale, - 0.0f, 0.0f, + scale * spc->h_oversample, + scale * spc->v_oversample, + 0,0, glyph); + + if (spc->h_oversample > 1) + stbtt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, + r->w, r->h, spc->stride_in_bytes, + spc->h_oversample); + + if (spc->v_oversample > 1) + stbtt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, + r->w, r->h, spc->stride_in_bytes, + spc->v_oversample); + bc->x0 = (stbtt_int16) r->x; bc->y0 = (stbtt_int16) r->y; - bc->x1 = (stbtt_int16) (r->x + r->w-1); - bc->y1 = (stbtt_int16) (r->y + r->h-1); + bc->x1 = (stbtt_int16) (r->x + r->w); + bc->y1 = (stbtt_int16) (r->y + r->h); bc->xadvance = scale * advance; - bc->xoff = (float) x0; - bc->yoff = (float) y0; + bc->xoff = (float) x0 * recip_h + sub_x; + bc->yoff = (float) y0 * recip_v + sub_y; + bc->xoff2 = (x0 + r->w) * recip_h + sub_x; + bc->yoff2 = (y0 + r->h) * recip_v + sub_y; } else { return_value = 0; // if any fail, report failure } @@ -2111,7 +2348,7 @@ int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontdata, int f } int stbtt_PackFontRange(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, float font_size, - int first_unicode_char_in_range, int num_chars_in_range, stbtt_bakedchar *chardata_for_range) + int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range) { stbtt_pack_range range; range.first_unicode_char_in_range = first_unicode_char_in_range; @@ -2121,6 +2358,34 @@ int stbtt_PackFontRange(stbtt_pack_context *spc, unsigned char *fontdata, int fo return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1); } +void stbtt_GetPackedQuad(stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer) +{ + float ipw = 1.0f / pw, iph = 1.0f / ph; + stbtt_packedchar *b = chardata + char_index; + + if (align_to_integer) { + float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5); + float y = (float) STBTT_ifloor((*ypos + b->yoff) + 0.5); + q->x0 = x; + q->y0 = y; + q->x1 = x + b->xoff2 - b->xoff; + q->y1 = y + b->yoff2 - b->yoff; + } else { + q->x0 = *xpos + b->xoff; + q->y0 = *ypos + b->yoff; + q->x1 = *xpos + b->xoff2; + q->y1 = *ypos + b->yoff2; + } + + q->s0 = b->x0 * ipw; + q->t0 = b->y0 * iph; + q->s1 = b->x1 * ipw; + q->t1 = b->y1 * iph; + + *xpos += b->xadvance; +} + + ////////////////////////////////////////////////////////////////////////////// // // font name matching -- recommended not to use this diff --git a/tests/image_test.dsp b/tests/image_test.dsp index 5cabd09..2ab6734 100644 --- a/tests/image_test.dsp +++ b/tests/image_test.dsp @@ -41,7 +41,7 @@ RSC=rc.exe # PROP Intermediate_Dir "Release" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I ".." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe diff --git a/tests/oversample/main.c b/tests/oversample/main.c new file mode 100644 index 0000000..f9f4d76 --- /dev/null +++ b/tests/oversample/main.c @@ -0,0 +1,272 @@ +#pragma warning(disable:4244; disable:4305; disable:4018) +#include +#include + +#define STB_DEFINE +#define STB_WINMAIN +#define STB_NO_REGISTRY +#include "stb_wingraph.h" +#include "stb.h" + +#define STB_TRUETYPE_IMPLEMENTATION +#define STB_RECT_PACK_IMPLEMENTATION +#include "stb_rect_pack.h" +#include "stb_truetype.h" + +#ifndef WINGDIAPI +#define CALLBACK __stdcall +#define WINGDIAPI __declspec(dllimport) +#define APIENTRY __stdcall +#endif + +#include +#include + + +#define SIZE_X 1024 +#define SIZE_Y 768 + +stbtt_packedchar chardata[3][128]; + +int sx=SIZE_X, sy=SIZE_Y; + +#define BITMAP_W 512 +#define BITMAP_H 512 +unsigned char temp_bitmap[BITMAP_W][BITMAP_H]; +unsigned char ttf_buffer[1 << 25]; +GLuint font_tex; + +void load_fonts(void) +{ + stbtt_pack_context pc; + FILE *f = fopen("c:/windows/fonts/times.ttf", "rb"); + if (!f) exit(0); + fread(ttf_buffer, 1, 1<<25, f); + + stbtt_PackBegin(&pc, temp_bitmap[0], BITMAP_W, BITMAP_H, 0, 1, NULL); + stbtt_PackFontRange(&pc, ttf_buffer, 0, 24.0, 32, 95, chardata[0]+32); + stbtt_PackSetOversampling(&pc, 2, 2); + stbtt_PackFontRange(&pc, ttf_buffer, 0, 24.0, 32, 95, chardata[1]+32); + stbtt_PackSetOversampling(&pc, 3, 1); + stbtt_PackFontRange(&pc, ttf_buffer, 0, 24.0, 32, 95, chardata[2]+32); + stbtt_PackEnd(&pc); + + glGenTextures(1, &font_tex); + glBindTexture(GL_TEXTURE_2D, font_tex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, BITMAP_W, BITMAP_H, 0, GL_ALPHA, GL_UNSIGNED_BYTE, temp_bitmap); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +} + +void draw_init(void) +{ + glDisable(GL_CULL_FACE); + glDisable(GL_TEXTURE_2D); + glDisable(GL_LIGHTING); + glDisable(GL_DEPTH_TEST); + + glViewport(0,0,sx,sy); + glClearColor(0,0,0,0); + glClear(GL_COLOR_BUFFER_BIT); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluOrtho2D(0,sx,sy,0); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); +} + + +void drawBoxTC(float x0, float y0, float x1, float y1, float s0, float t0, float s1, float t1) +{ + glTexCoord2f(s0,t0); glVertex2f(x0,y0); + glTexCoord2f(s1,t0); glVertex2f(x1,y0); + glTexCoord2f(s1,t1); glVertex2f(x1,y1); + glTexCoord2f(s0,t1); glVertex2f(x0,y1); +} + +int integer_align; + +void print(float x, float y, int font, char *text) +{ + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, font_tex); + glBegin(GL_QUADS); + while (*text) { + stbtt_aligned_quad q; + stbtt_GetPackedQuad(chardata[font], BITMAP_W, BITMAP_H, *text++, &x, &y, &q, font ? 0 : integer_align); + drawBoxTC(q.x0,q.y0,q.x1,q.y1, q.s0,q.t0,q.s1,q.t1); + } + glEnd(); +} + +int font=0; +int translating; +int rotating=0; +float rotate_t, translate_t; +int show_tex; + +void draw_world(void) +{ + float x = 20; + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glColor3f(1,1,1); + + if (font==1) + print(100, 50, font, "2x2 oversampled text at 1:1"); + else if (font == 2) + print(100, 50, font, "3x1 oversampled text at 1:1"); + else if (integer_align) + print(100, 50, font, "1:1 text, one texel = one pixel, snapped to integer coordinates"); + else + print(100, 50, font, "1:1 text, one texel = one pixel"); + + print(100, 80, font, "O: toggle oversampling"); + print(100,105, font, "T: toggle translation"); + print(100,130, font, "R: toggle rotation"); + print(100,155, font, "P: toggle pixel-snap (only non-oversampled)"); + print(100,180, font, "V: view font texture"); + + if (show_tex) { + glBegin(GL_QUADS); + drawBoxTC(200,200, 200+BITMAP_W,200+BITMAP_H, 0,0,1,1); + glEnd(); + } else { + glMatrixMode(GL_MODELVIEW); + glTranslatef(200,250,0); + + if (translating) + x += fmod(translate_t*8,30); + + if (rotating) { + glTranslatef(100,150,0); + glRotatef(rotate_t*2,0,0,1); + glTranslatef(-100,-150,0); + } + print(x,100, font, "This is a test"); + print(x,130, font, "Now is the time for all good men to come to the aid of their country."); + print(x,160, font, "The quick brown fox jumps over the lazy dog."); + print(x,190, font, "0123456789"); + } +} + +void draw(void) +{ + draw_init(); + draw_world(); + stbwingraph_SwapBuffers(NULL); +} + +static int initialized=0; +static float last_dt; + +int move[4]; +int raw_mouse_x, raw_mouse_y; + +int loopmode(float dt, int real, int in_client) +{ + float actual_dt = dt; + + if (!initialized) return 0; + + rotate_t += dt; + translate_t += dt; + +// music_sim(); + if (!real) + return 0; + + if (dt > 0.25) dt = 0.25; + if (dt < 0.01) dt = 0.01; + + draw(); + + return 0; +} + +int winproc(void *data, stbwingraph_event *e) +{ + switch (e->type) { + case STBWGE_create: + break; + + case STBWGE_char: + switch(e->key) { + case 27: + stbwingraph_ShowCursor(NULL,1); + return STBWINGRAPH_winproc_exit; + break; + case 'o': case 'O': + font = (font+1) % 3; + break; + case 't': case 'T': + translating = !translating; + translate_t = 0; + break; + case 'r': case 'R': + rotating = !rotating; + rotate_t = 0; + break; + case 'p': case 'P': + integer_align = !integer_align; + break; + case 'v': case 'V': + show_tex = !show_tex; + break; + } + break; + + case STBWGE_mousemove: + raw_mouse_x = e->mx; + raw_mouse_y = e->my; + break; + +#if 0 + case STBWGE_mousewheel: do_mouse(e,0,0); break; + case STBWGE_leftdown: do_mouse(e, 1,0); break; + case STBWGE_leftup: do_mouse(e,-1,0); break; + case STBWGE_rightdown: do_mouse(e,0, 1); break; + case STBWGE_rightup: do_mouse(e,0,-1); break; +#endif + + case STBWGE_keydown: + if (e->key == VK_RIGHT) move[0] = 1; + if (e->key == VK_LEFT) move[1] = 1; + if (e->key == VK_UP) move[2] = 1; + if (e->key == VK_DOWN) move[3] = 1; + break; + case STBWGE_keyup: + if (e->key == VK_RIGHT) move[0] = 0; + if (e->key == VK_LEFT) move[1] = 0; + if (e->key == VK_UP) move[2] = 0; + if (e->key == VK_DOWN) move[3] = 0; + break; + + case STBWGE_size: + sx = e->width; + sy = e->height; + loopmode(0,1,0); + break; + + case STBWGE_draw: + if (initialized) + loopmode(0,1,0); + break; + + default: + return STBWINGRAPH_unprocessed; + } + return 0; +} + +void stbwingraph_main(void) +{ + stbwingraph_Priority(2); + stbwingraph_CreateWindow(1, winproc, NULL, "tt", SIZE_X,SIZE_Y, 0, 1, 0, 0); + stbwingraph_ShowCursor(NULL, 0); + load_fonts(); + initialized = 1; + stbwingraph_MainLoop(loopmode, 0.016f); // 30 fps = 0.33 +} + diff --git a/tests/oversample/oversample.dsp b/tests/oversample/oversample.dsp new file mode 100644 index 0000000..cc1edc3 --- /dev/null +++ b/tests/oversample/oversample.dsp @@ -0,0 +1,97 @@ +# Microsoft Developer Studio Project File - Name="oversample" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=oversample - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "oversample.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "oversample.mak" CFG="oversample - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "oversample - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "oversample - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "oversample - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /WX /GX /O2 /I "c:\sean\prj\stb" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# SUBTRACT LINK32 /map /debug + +!ELSEIF "$(CFG)" == "oversample - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /WX /Gm /GX /Zi /Od /I "c:\sean\prj\stb" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib advapi32.lib winspool.lib comdlg32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /incremental:no /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "oversample - Win32 Release" +# Name "oversample - Win32 Debug" +# Begin Source File + +SOURCE=.\main.c +# End Source File +# End Target +# End Project diff --git a/tests/oversample/oversample.dsw b/tests/oversample/oversample.dsw new file mode 100644 index 0000000..0f5aa7f --- /dev/null +++ b/tests/oversample/oversample.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "oversample"=.\oversample.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/tests/oversample/stb_wingraph.h b/tests/oversample/stb_wingraph.h new file mode 100644 index 0000000..d48065f --- /dev/null +++ b/tests/oversample/stb_wingraph.h @@ -0,0 +1,824 @@ +// stb_wingraph.h v0.01 - public domain windows graphics programming +// wraps WinMain, ChoosePixelFormat, ChangeDisplayResolution, etc. for +// doing OpenGL graphics +// +// in ONE source file, put '#define STB_DEFINE' before including this +// OR put '#define STB_WINMAIN' to define a WinMain that calls stbwingraph_main(void) +// +// @TODO: +// 2d rendering interface (that can be done easily in software) +// STB_WINGRAPH_SOFTWARE -- 2d software rendering only +// STB_WINGRAPH_OPENGL -- OpenGL only + + +#ifndef INCLUDE_STB_WINGRAPH_H +#define INCLUDE_STB_WINGRAPH_H + +#ifdef STB_WINMAIN + #ifndef STB_DEFINE + #define STB_DEFINE + #define STB_WINGRAPH_DISABLE_DEFINE_AT_END + #endif +#endif + +#ifdef STB_DEFINE + #pragma comment(lib, "opengl32.lib") + #pragma comment(lib, "glu32.lib") + #pragma comment(lib, "winmm.lib") +#endif + +#ifdef __cplusplus +#define STB_EXTERN extern "C" +#else +#define STB_EXTERN +#endif + +#ifdef STB_DEFINE +#ifndef _WINDOWS_ + #ifdef APIENTRY + #undef APIENTRY + #endif + #ifdef WINGDIAPI + #undef WINGDIAPI + #endif + #define _WIN32_WINNT 0x0400 // WM_MOUSEWHEEL + #include +#endif +#include +#include +#include +#include +#include +#endif + +typedef void * stbwingraph_hwnd; +typedef void * stbwingraph_hinstance; + +enum +{ + STBWINGRAPH_unprocessed = -(1 << 24), + STBWINGRAPH_do_not_show, + STBWINGRAPH_winproc_exit, + STBWINGRAPH_winproc_update, + STBWINGRAPH_update_exit, + STBWINGRAPH_update_pause, +}; + +typedef enum +{ + STBWGE__none=0, + + STBWGE_create, + STBWGE_create_postshow, + STBWGE_draw, + STBWGE_destroy, + STBWGE_char, + STBWGE_keydown, + STBWGE_syskeydown, + STBWGE_keyup, + STBWGE_syskeyup, + STBWGE_deactivate, + STBWGE_activate, + STBWGE_size, + + STBWGE_mousemove , + STBWGE_leftdown , STBWGE_leftup , + STBWGE_middledown, STBWGE_middleup, + STBWGE_rightdown , STBWGE_rightup , + STBWGE_mousewheel, +} stbwingraph_event_type; + +typedef struct +{ + stbwingraph_event_type type; + + // for input events (mouse, keyboard) + int mx,my; // mouse x & y + int dx,dy; + int shift, ctrl, alt; + + // for keyboard events + int key; + + // for STBWGE_size: + int width, height; + + // for STBWGE_crate + int did_share_lists; // if true, wglShareLists succeeded + + void *handle; + +} stbwingraph_event; + +typedef int (*stbwingraph_window_proc)(void *data, stbwingraph_event *event); + +extern stbwingraph_hinstance stbwingraph_app; +extern stbwingraph_hwnd stbwingraph_primary_window; +extern int stbwingraph_request_fullscreen; +extern int stbwingraph_request_windowed; + +STB_EXTERN void stbwingraph_ods(char *str, ...); +STB_EXTERN int stbwingraph_MessageBox(stbwingraph_hwnd win, unsigned int type, + char *caption, char *text, ...); +STB_EXTERN int stbwingraph_ChangeResolution(unsigned int w, unsigned int h, + unsigned int bits, int use_message_box); +STB_EXTERN int stbwingraph_SetPixelFormat(stbwingraph_hwnd win, int color_bits, + int alpha_bits, int depth_bits, int stencil_bits, int accum_bits); +STB_EXTERN int stbwingraph_DefineClass(void *hinstance, char *iconname); +STB_EXTERN void stbwingraph_SwapBuffers(void *win); +STB_EXTERN void stbwingraph_Priority(int n); + +STB_EXTERN void stbwingraph_MakeFonts(void *window, int font_base); +STB_EXTERN void stbwingraph_ShowWindow(void *window); +STB_EXTERN void *stbwingraph_CreateWindow(int primary, stbwingraph_window_proc func, void *data, char *text, int width, int height, int fullscreen, int resizeable, int dest_alpha, int stencil); +STB_EXTERN void *stbwingraph_CreateWindowSimple(stbwingraph_window_proc func, int width, int height); +STB_EXTERN void *stbwingraph_CreateWindowSimpleFull(stbwingraph_window_proc func, int fullscreen, int ww, int wh, int fw, int fh); +STB_EXTERN void stbwingraph_DestroyWindow(void *window); +STB_EXTERN void stbwingraph_ShowCursor(void *window, int visible); +STB_EXTERN float stbwingraph_GetTimestep(float minimum_time); +STB_EXTERN void stbwingraph_SetGLWindow(void *win); +typedef int (*stbwingraph_update)(float timestep, int real, int in_client); +STB_EXTERN int stbwingraph_MainLoop(stbwingraph_update func, float mintime); + +#ifdef STB_DEFINE +stbwingraph_hinstance stbwingraph_app; +stbwingraph_hwnd stbwingraph_primary_window; +int stbwingraph_request_fullscreen; +int stbwingraph_request_windowed; + +void stbwingraph_ods(char *str, ...) +{ + char buffer[1024]; + va_list v; + va_start(v,str); + vsprintf(buffer, str, v); + va_end(v); + OutputDebugString(buffer); +} + +int stbwingraph_MessageBox(stbwingraph_hwnd win, unsigned int type, char *caption, char *text, ...) +{ + va_list v; + char buffer[1024]; + va_start(v, text); + vsprintf(buffer, text, v); + va_end(v); + return MessageBox(win, buffer, caption, type); +} + +void stbwingraph_Priority(int n) +{ + int p; + switch (n) { + case -1: p = THREAD_PRIORITY_BELOW_NORMAL; break; + case 0: p = THREAD_PRIORITY_NORMAL; break; + case 1: p = THREAD_PRIORITY_ABOVE_NORMAL; break; + default: + if (n < 0) p = THREAD_PRIORITY_LOWEST; + else p = THREAD_PRIORITY_HIGHEST; + } + SetThreadPriority(GetCurrentThread(), p); +} + +static void stbwingraph_ResetResolution(void) +{ + ChangeDisplaySettings(NULL, 0); +} + +static void stbwingraph_RegisterResetResolution(void) +{ + static int done=0; + if (!done) { + done = 1; + atexit(stbwingraph_ResetResolution); + } +} + +int stbwingraph_ChangeResolution(unsigned int w, unsigned int h, unsigned int bits, int use_message_box) +{ + DEVMODE mode; + int res; + + int i, tries=0; + for (i=0; ; ++i) { + int success = EnumDisplaySettings(NULL, i, &mode); + if (!success) break; + if (mode.dmBitsPerPel == bits && mode.dmPelsWidth == w && mode.dmPelsHeight == h) { + ++tries; + success = ChangeDisplaySettings(&mode, CDS_FULLSCREEN); + if (success == DISP_CHANGE_SUCCESSFUL) { + stbwingraph_RegisterResetResolution(); + return TRUE; + } + break; + } + } + + if (!tries) { + if (use_message_box) + stbwingraph_MessageBox(stbwingraph_primary_window, MB_ICONERROR, NULL, "The resolution %d x %d x %d-bits is not supported.", w, h, bits); + return FALSE; + } + + // we tried but failed, so try explicitly doing it without specifying refresh rate + + // Win95 support logic + mode.dmBitsPerPel = bits; + mode.dmPelsWidth = w; + mode.dmPelsHeight = h; + mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; + + res = ChangeDisplaySettings(&mode, CDS_FULLSCREEN); + + switch (res) { + case DISP_CHANGE_SUCCESSFUL: + stbwingraph_RegisterResetResolution(); + return TRUE; + + case DISP_CHANGE_RESTART: + if (use_message_box) + stbwingraph_MessageBox(stbwingraph_primary_window, MB_ICONERROR, NULL, "Please set your desktop to %d-bit color and then try again."); + return FALSE; + + case DISP_CHANGE_FAILED: + if (use_message_box) + stbwingraph_MessageBox(stbwingraph_primary_window, MB_ICONERROR, NULL, "The hardware failed to change modes."); + return FALSE; + + case DISP_CHANGE_BADMODE: + if (use_message_box) + stbwingraph_MessageBox(stbwingraph_primary_window, MB_ICONERROR, NULL, "The resolution %d x %d x %d-bits is not supported.", w, h, bits); + return FALSE; + + default: + if (use_message_box) + stbwingraph_MessageBox(stbwingraph_primary_window, MB_ICONERROR, NULL, "An unknown error prevented a change to a %d x %d x %d-bit display.", w, h, bits); + return FALSE; + } +} + +int stbwingraph_SetPixelFormat(stbwingraph_hwnd win, int color_bits, int alpha_bits, int depth_bits, int stencil_bits, int accum_bits) +{ + HDC dc = GetDC(win); + PIXELFORMATDESCRIPTOR pfd = { sizeof(pfd) }; + int pixel_format; + + pfd.nVersion = 1; + pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER; + pfd.dwLayerMask = PFD_MAIN_PLANE; + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.cColorBits = color_bits; + pfd.cAlphaBits = alpha_bits; + pfd.cDepthBits = depth_bits; + pfd.cStencilBits = stencil_bits; + pfd.cAccumBits = accum_bits; + + pixel_format = ChoosePixelFormat(dc, &pfd); + if (!pixel_format) return FALSE; + + if (!DescribePixelFormat(dc, pixel_format, sizeof(PIXELFORMATDESCRIPTOR), &pfd)) + return FALSE; + SetPixelFormat(dc, pixel_format, &pfd); + + return TRUE; +} + +typedef struct +{ + // app data + stbwingraph_window_proc func; + void *data; + // creation parameters + int color, alpha, depth, stencil, accum; + HWND share_window; + HWND window; + // internal data + HGLRC rc; + HDC dc; + int hide_mouse; + int in_client; + int active; + int did_share_lists; + int mx,my; // last mouse positions +} stbwingraph__window; + +static void stbwingraph__inclient(stbwingraph__window *win, int state) +{ + if (state != win->in_client) { + win->in_client = state; + if (win->hide_mouse) + ShowCursor(!state); + } +} + +static void stbwingraph__key(stbwingraph_event *e, int type, int key, stbwingraph__window *z) +{ + e->type = type; + e->key = key; + e->shift = (GetKeyState(VK_SHIFT) < 0); + e->ctrl = (GetKeyState(VK_CONTROL) < 0); + e->alt = (GetKeyState(VK_MENU) < 0); + if (z) { + e->mx = z->mx; + e->my = z->my; + } else { + e->mx = e->my = 0; + } + e->dx = e->dy = 0; +} + +static void stbwingraph__mouse(stbwingraph_event *e, int type, WPARAM wparam, LPARAM lparam, int capture, void *wnd, stbwingraph__window *z) +{ + static int captured = 0; + e->type = type; + e->mx = (short) LOWORD(lparam); + e->my = (short) HIWORD(lparam); + if (!z || z->mx == -(1 << 30)) { + e->dx = e->dy = 0; + } else { + e->dx = e->mx - z->mx; + e->dy = e->my - z->my; + } + e->shift = (wparam & MK_SHIFT) != 0; + e->ctrl = (wparam & MK_CONTROL) != 0; + e->alt = (wparam & MK_ALT) != 0; + if (z) { + z->mx = e->mx; + z->my = e->my; + } + if (capture) { + if (!captured && capture == 1) + SetCapture(wnd); + captured += capture; + if (!captured && capture == -1) + ReleaseCapture(); + if (captured < 0) captured = 0; + } +} + +static void stbwingraph__mousewheel(stbwingraph_event *e, int type, WPARAM wparam, LPARAM lparam, int capture, void *wnd, stbwingraph__window *z) +{ + // lparam seems bogus! + static int captured = 0; + e->type = type; + if (z) { + e->mx = z->mx; + e->my = z->my; + } + e->dx = e->dy = 0; + e->shift = (wparam & MK_SHIFT) != 0; + e->ctrl = (wparam & MK_CONTROL) != 0; + e->alt = (GetKeyState(VK_MENU) < 0); + e->key = ((int) wparam >> 16); +} + +int stbwingraph_force_update; +static int WINAPI stbwingraph_WinProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + int allow_default = TRUE; + stbwingraph_event e = { STBWGE__none }; + // the following line is wrong for 64-bit windows, but VC6 doesn't have GetWindowLongPtr + stbwingraph__window *z = (stbwingraph__window *) GetWindowLong(wnd, GWL_USERDATA); + + switch (msg) { + + case WM_CREATE: + { + LPCREATESTRUCT lpcs = (LPCREATESTRUCT) lparam; + assert(z == NULL); + z = (stbwingraph__window *) lpcs->lpCreateParams; + SetWindowLong(wnd, GWL_USERDATA, (LONG) z); + z->dc = GetDC(wnd); + if (stbwingraph_SetPixelFormat(wnd, z->color, z->alpha, z->depth, z->stencil, z->accum)) { + z->rc = wglCreateContext(z->dc); + if (z->rc) { + e.type = STBWGE_create; + z->did_share_lists = FALSE; + if (z->share_window) { + stbwingraph__window *y = (stbwingraph__window *) GetWindowLong(z->share_window, GWL_USERDATA); + if (wglShareLists(z->rc, y->rc)) + z->did_share_lists = TRUE; + } + wglMakeCurrent(z->dc, z->rc); + return 0; + } + } + return -1; + } + + case WM_PAINT: { + PAINTSTRUCT ps; + HDC hdc = BeginPaint(wnd, &ps); + SelectObject(hdc, GetStockObject(NULL_BRUSH)); + e.type = STBWGE_draw; + e.handle = wnd; + z->func(z->data, &e); + EndPaint(wnd, &ps); + return 0; + } + + case WM_DESTROY: + e.type = STBWGE_destroy; + e.handle = wnd; + if (z && z->func) + z->func(z->data, &e); + wglMakeCurrent(NULL, NULL) ; + if (z) { + if (z->rc) wglDeleteContext(z->rc); + z->dc = 0; + z->rc = 0; + } + if (wnd == stbwingraph_primary_window) + PostQuitMessage (0); + return 0; + + case WM_CHAR: stbwingraph__key(&e, STBWGE_char , wparam, z); break; + case WM_KEYDOWN: stbwingraph__key(&e, STBWGE_keydown, wparam, z); break; + case WM_KEYUP: stbwingraph__key(&e, STBWGE_keyup , wparam, z); break; + + case WM_NCMOUSEMOVE: stbwingraph__inclient(z,0); break; + case WM_MOUSEMOVE: stbwingraph__inclient(z,1); stbwingraph__mouse(&e, STBWGE_mousemove, wparam, lparam,0,wnd, z); break; + case WM_LBUTTONDOWN: stbwingraph__mouse(&e, STBWGE_leftdown, wparam, lparam,1,wnd, z); break; + case WM_MBUTTONDOWN: stbwingraph__mouse(&e, STBWGE_middledown, wparam, lparam,1,wnd, z); break; + case WM_RBUTTONDOWN: stbwingraph__mouse(&e, STBWGE_rightdown, wparam, lparam,1,wnd, z); break; + case WM_LBUTTONUP: stbwingraph__mouse(&e, STBWGE_leftup, wparam, lparam,-1,wnd, z); break; + case WM_MBUTTONUP: stbwingraph__mouse(&e, STBWGE_middleup, wparam, lparam,-1,wnd, z); break; + case WM_RBUTTONUP: stbwingraph__mouse(&e, STBWGE_rightup, wparam, lparam,-1,wnd, z); break; + case WM_MOUSEWHEEL: stbwingraph__mousewheel(&e, STBWGE_mousewheel, wparam, lparam,0,wnd, z); break; + + case WM_ACTIVATE: + allow_default = FALSE; + if (LOWORD(wparam)==WA_INACTIVE ) { + wglMakeCurrent(z->dc, NULL); + e.type = STBWGE_deactivate; + z->active = FALSE; + } else { + wglMakeCurrent(z->dc, z->rc); + e.type = STBWGE_activate; + z->active = TRUE; + } + e.handle = wnd; + z->func(z->data, &e); + return 0; + + case WM_SIZE: { + RECT rect; + allow_default = FALSE; + GetClientRect(wnd, &rect); + e.type = STBWGE_size; + e.width = rect.right; + e.height = rect.bottom; + e.handle = wnd; + z->func(z->data, &e); + return 0; + } + + default: + return DefWindowProc (wnd, msg, wparam, lparam); + } + + if (e.type != STBWGE__none) { + int n; + e.handle = wnd; + n = z->func(z->data, &e); + if (n == STBWINGRAPH_winproc_exit) { + PostQuitMessage(0); + n = 0; + } + if (n == STBWINGRAPH_winproc_update) { + stbwingraph_force_update = TRUE; + return 1; + } + if (n != STBWINGRAPH_unprocessed) + return n; + } + return DefWindowProc (wnd, msg, wparam, lparam); +} + +int stbwingraph_DefineClass(HINSTANCE hInstance, char *iconname) +{ + WNDCLASSEX wndclass; + + stbwingraph_app = hInstance; + + wndclass.cbSize = sizeof(wndclass); + wndclass.style = CS_OWNDC; + wndclass.lpfnWndProc = (WNDPROC) stbwingraph_WinProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = hInstance; + wndclass.hIcon = LoadIcon(hInstance, iconname); + wndclass.hCursor = LoadCursor(NULL,IDC_ARROW); + wndclass.hbrBackground = GetStockObject(NULL_BRUSH); + wndclass.lpszMenuName = "zwingraph"; + wndclass.lpszClassName = "zwingraph"; + wndclass.hIconSm = NULL; + + if (!RegisterClassEx(&wndclass)) + return FALSE; + return TRUE; +} + +void stbwingraph_ShowWindow(void *window) +{ + stbwingraph_event e = { STBWGE_create_postshow }; + stbwingraph__window *z = (stbwingraph__window *) GetWindowLong(window, GWL_USERDATA); + ShowWindow(window, SW_SHOWNORMAL); + InvalidateRect(window, NULL, TRUE); + UpdateWindow(window); + e.handle = window; + z->func(z->data, &e); +} + +void *stbwingraph_CreateWindow(int primary, stbwingraph_window_proc func, void *data, char *text, + int width, int height, int fullscreen, int resizeable, int dest_alpha, int stencil) +{ + HWND win; + DWORD dwstyle; + stbwingraph__window *z = (stbwingraph__window *) malloc(sizeof(*z)); + + if (z == NULL) return NULL; + memset(z, 0, sizeof(*z)); + z->color = 24; + z->depth = 24; + z->alpha = dest_alpha; + z->stencil = stencil; + z->func = func; + z->data = data; + z->mx = -(1 << 30); + z->my = 0; + + if (primary) { + if (stbwingraph_request_windowed) + fullscreen = FALSE; + else if (stbwingraph_request_fullscreen) + fullscreen = TRUE; + } + + if (fullscreen) { + #ifdef STB_SIMPLE + stbwingraph_ChangeResolution(width, height, 32, 1); + #else + if (!stbwingraph_ChangeResolution(width, height, 32, 0)) + return NULL; + #endif + dwstyle = WS_POPUP | WS_CLIPSIBLINGS; + } else { + RECT rect; + dwstyle = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; + if (resizeable) + dwstyle |= WS_SIZEBOX | WS_MAXIMIZEBOX; + rect.top = 0; + rect.left = 0; + rect.right = width; + rect.bottom = height; + AdjustWindowRect(&rect, dwstyle, FALSE); + width = rect.right - rect.left; + height = rect.bottom - rect.top; + } + + win = CreateWindow("zwingraph", text ? text : "sample", dwstyle, + CW_USEDEFAULT,0, width, height, + NULL, NULL, stbwingraph_app, z); + + if (win == NULL) return win; + + if (primary) { + if (stbwingraph_primary_window) + stbwingraph_DestroyWindow(stbwingraph_primary_window); + stbwingraph_primary_window = win; + } + + { + stbwingraph_event e = { STBWGE_create }; + stbwingraph__window *z = (stbwingraph__window *) GetWindowLong(win, GWL_USERDATA); + z->window = win; + e.did_share_lists = z->did_share_lists; + e.handle = win; + if (z->func(z->data, &e) != STBWINGRAPH_do_not_show) + stbwingraph_ShowWindow(win); + } + + return win; +} + +void *stbwingraph_CreateWindowSimple(stbwingraph_window_proc func, int width, int height) +{ + int fullscreen = 0; + #ifndef _DEBUG + if (width == 640 && height == 480) fullscreen = 1; + if (width == 800 && height == 600) fullscreen = 1; + if (width == 1024 && height == 768) fullscreen = 1; + if (width == 1280 && height == 1024) fullscreen = 1; + if (width == 1600 && height == 1200) fullscreen = 1; + //@TODO: widescreen widths + #endif + return stbwingraph_CreateWindow(1, func, NULL, NULL, width, height, fullscreen, 1, 0, 0); +} + +void *stbwingraph_CreateWindowSimpleFull(stbwingraph_window_proc func, int fullscreen, int ww, int wh, int fw, int fh) +{ + if (fullscreen == -1) { + #ifdef _DEBUG + fullscreen = 0; + #else + fullscreen = 1; + #endif + } + + if (fullscreen) { + if (fw) ww = fw; + if (fh) wh = fh; + } + return stbwingraph_CreateWindow(1, func, NULL, NULL, ww, wh, fullscreen, 1, 0, 0); +} + +void stbwingraph_DestroyWindow(void *window) +{ + stbwingraph__window *z = (stbwingraph__window *) GetWindowLong(window, GWL_USERDATA); + DestroyWindow(window); + free(z); + if (stbwingraph_primary_window == window) + stbwingraph_primary_window = NULL; +} + +void stbwingraph_ShowCursor(void *window, int visible) +{ + int hide; + stbwingraph__window *win; + if (!window) + window = stbwingraph_primary_window; + win = (stbwingraph__window *) GetWindowLong((HWND) window, GWL_USERDATA); + hide = !visible; + if (hide != win->hide_mouse) { + win->hide_mouse = hide; + if (!hide) + ShowCursor(TRUE); + else if (win->in_client) + ShowCursor(FALSE); + } +} + +float stbwingraph_GetTimestep(float minimum_time) +{ + float elapsedTime; + double thisTime; + static double lastTime = -1; + + if (lastTime == -1) + lastTime = timeGetTime() / 1000.0 - minimum_time; + + for(;;) { + thisTime = timeGetTime() / 1000.0; + elapsedTime = (float) (thisTime - lastTime); + if (elapsedTime >= minimum_time) { + lastTime = thisTime; + return elapsedTime; + } + #if 1 + Sleep(2); + #endif + } +} + +void stbwingraph_SetGLWindow(void *win) +{ + stbwingraph__window *z = (stbwingraph__window *) GetWindowLong(win, GWL_USERDATA); + if (z) + wglMakeCurrent(z->dc, z->rc); +} + +void stbwingraph_MakeFonts(void *window, int font_base) +{ + wglUseFontBitmaps(GetDC(window ? window : stbwingraph_primary_window), 0, 256, font_base); +} + +// returns 1 if WM_QUIT, 0 if 'func' returned 0 +int stbwingraph_MainLoop(stbwingraph_update func, float mintime) +{ + int needs_drawing = FALSE; + MSG msg; + + int is_animating = TRUE; + if (mintime <= 0) mintime = 0.01f; + + for(;;) { + int n; + + is_animating = TRUE; + // wait for a message if: (a) we're animating and there's already a message + // or (b) we're not animating + if (!is_animating || PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) { + stbwingraph_force_update = FALSE; + if (GetMessage(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } else { + return 1; // WM_QUIT + } + + // only force a draw for certain messages... + // if I don't do this, we peg at 50% for some reason... must + // be a bug somewhere, because we peg at 100% when rendering... + // very weird... looks like NVIDIA is pumping some messages + // through our pipeline? well, ok, I guess if we can get + // non-user-generated messages we have to do this + if (!stbwingraph_force_update) { + switch (msg.message) { + case WM_MOUSEMOVE: + case WM_NCMOUSEMOVE: + break; + case WM_CHAR: + case WM_KEYDOWN: + case WM_KEYUP: + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + case WM_TIMER: + case WM_SIZE: + case WM_ACTIVATE: + needs_drawing = TRUE; + break; + } + } else + needs_drawing = TRUE; + } + + // if another message, process that first + // @TODO: i don't think this is working, because I can't key ahead + // in the SVT demo app + if (PeekMessage(&msg, NULL, 0,0, PM_NOREMOVE)) + continue; + + // and now call update + if (needs_drawing || is_animating) { + int real=1, in_client=1; + if (stbwingraph_primary_window) { + stbwingraph__window *z = (stbwingraph__window *) GetWindowLong(stbwingraph_primary_window, GWL_USERDATA); + if (z && !z->active) { + real = 0; + } + if (z) + in_client = z->in_client; + } + + if (stbwingraph_primary_window) + stbwingraph_SetGLWindow(stbwingraph_primary_window); + n = func(stbwingraph_GetTimestep(mintime), real, in_client); + if (n == STBWINGRAPH_update_exit) + return 0; // update_quit + + is_animating = (n != STBWINGRAPH_update_pause); + + needs_drawing = FALSE; + } + } +} + +void stbwingraph_SwapBuffers(void *win) +{ + stbwingraph__window *z; + if (win == NULL) win = stbwingraph_primary_window; + z = (stbwingraph__window *) GetWindowLong(win, GWL_USERDATA); + if (z && z->dc) + SwapBuffers(z->dc); +} +#endif + +#ifdef STB_WINMAIN +void stbwingraph_main(void); + +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) +{ + { + char buffer[1024]; + // add spaces to either side of the string + buffer[0] = ' '; + strcpy(buffer+1, lpCmdLine); + strcat(buffer, " "); + if (strstr(buffer, " -reset ")) { + ChangeDisplaySettings(NULL, 0); + exit(0); + } + if (strstr(buffer, " -window ") || strstr(buffer, " -windowed ")) + stbwingraph_request_windowed = TRUE; + else if (strstr(buffer, " -full ") || strstr(buffer, " -fullscreen ")) + stbwingraph_request_fullscreen = TRUE; + } + + stbwingraph_DefineClass(hInstance, "appicon"); + stbwingraph_main(); + + return 0; +} +#endif + +#undef STB_EXTERN +#ifdef STB_WINGRAPH_DISABLE_DEFINE_AT_END +#undef STB_DEFINE +#endif + +#endif // INCLUDE_STB_WINGRAPH_H diff --git a/tests/stb.dsp b/tests/stb.dsp index 98039d0..3d642a1 100644 --- a/tests/stb.dsp +++ b/tests/stb.dsp @@ -42,7 +42,7 @@ RSC=rc.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /G6 /MT /W3 /GX /Z7 /O2 /Ob2 /I ".." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "MAIN_TEST" /FD /c +# ADD CPP /nologo /G6 /MT /W3 /GX /Z7 /O2 /Ob2 /I ".." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "TT_TEST" /FD /c # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe diff --git a/tests/stb_cpp.dsp b/tests/stb_cpp.dsp index f14aa82..e763d33 100644 --- a/tests/stb_cpp.dsp +++ b/tests/stb_cpp.dsp @@ -41,7 +41,7 @@ RSC=rc.exe # PROP Intermediate_Dir "Release" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /GX /O2 /I ".." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I ".." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe diff --git a/tests/stretch_test.dsp b/tests/stretch_test.dsp index f9af713..eed15e8 100644 --- a/tests/stretch_test.dsp +++ b/tests/stretch_test.dsp @@ -41,7 +41,7 @@ RSC=rc.exe # PROP Intermediate_Dir "Release" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /GX /O2 /I "..\.." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\.." /I ".." /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "TT_TEST" /YX /FD /c # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe @@ -63,8 +63,8 @@ LINK32=link.exe # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug\stretch_test" # PROP Target_Dir "" -# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I ".." /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe diff --git a/tests/test_truetype.c b/tests/test_truetype.c index 07fae7d..c151533 100644 --- a/tests/test_truetype.c +++ b/tests/test_truetype.c @@ -20,9 +20,10 @@ void debug(void) } #define BITMAP_W 256 -#define BITMAP_H 400 +#define BITMAP_H 512 unsigned char temp_bitmap[BITMAP_H][BITMAP_W]; stbtt_bakedchar cdata[256*2]; // ASCII 32..126 is 95 glyphs +stbtt_packedchar pdata[256*2]; int main(int argc, char **argv) { stbtt_fontinfo font; @@ -37,13 +38,11 @@ int main(int argc, char **argv) stbtt_BakeFontBitmap(ttf_buffer,stbtt_GetFontOffsetForIndex(ttf_buffer,0), 40.0, temp_bitmap[0],BITMAP_W,BITMAP_H, 32,96, cdata); // no guarantee this fits! stbi_write_png("fonttest1.png", BITMAP_W, BITMAP_H, 1, temp_bitmap, 0); - stbtt_BakeFontBitmap(ttf_buffer,stbtt_GetFontOffsetForIndex(ttf_buffer,0), 40.0, temp_bitmap[0],BITMAP_W,BITMAP_H, 32,96, cdata); // no guarantee this fits! - { stbtt_pack_context pc; - stbtt_PackBegin(&pc, temp_bitmap[0], BITMAP_W, BITMAP_H, 0, NULL); - stbtt_PackFontRange(&pc, ttf_buffer, 0, 40.0, 32, 95, cdata); - stbtt_PackFontRange(&pc, ttf_buffer, 0, 40.0, 0xa0, 0x100-0xa0, cdata); + stbtt_PackBegin(&pc, temp_bitmap[0], BITMAP_W, BITMAP_H, 0, 1, NULL); + stbtt_PackFontRange(&pc, ttf_buffer, 0, 20.0, 32, 95, pdata); + stbtt_PackFontRange(&pc, ttf_buffer, 0, 20.0, 0xa0, 0x100-0xa0, pdata); stbtt_PackEnd(&pc); stbi_write_png("fonttest2.png", BITMAP_W, BITMAP_H, 1, temp_bitmap, 0); } @@ -51,17 +50,18 @@ int main(int argc, char **argv) { stbtt_pack_context pc; stbtt_pack_range pr[2]; - stbtt_PackBegin(&pc, temp_bitmap[0], BITMAP_W, BITMAP_H, 0, NULL); + stbtt_PackBegin(&pc, temp_bitmap[0], BITMAP_W, BITMAP_H, 0, 1, NULL); - pr[0].chardata_for_range = cdata; + pr[0].chardata_for_range = pdata; pr[0].first_unicode_char_in_range = 32; pr[0].num_chars_in_range = 95; - pr[0].font_size = 40.0; - pr[1].chardata_for_range = cdata+256; + pr[0].font_size = 20.0f; + pr[1].chardata_for_range = pdata+256; pr[1].first_unicode_char_in_range = 0xa0; pr[1].num_chars_in_range = 0x100 - 0xa0; - pr[1].font_size = 40.0; + pr[1].font_size = 20.0f; + stbtt_PackSetOversampling(&pc, 2, 2); stbtt_PackFontRanges(&pc, ttf_buffer, 0, pr, 2); stbtt_PackEnd(&pc); stbi_write_png("fonttest3.png", BITMAP_W, BITMAP_H, 1, temp_bitmap, 0); From 22dbcffef714461ca29694bf71deeff38bf5522d Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Sat, 6 Dec 2014 23:00:59 -0800 Subject: [PATCH 11/46] stbtt_Pack* documentation oversample test tweaks --- stb_rect_pack.h | 8 ++- stb_truetype.h | 62 +++++++++++++---- tests/oversample/main.c | 118 ++++++++++++++++++++++++-------- tests/oversample/oversample.exe | Bin 0 -> 54272 bytes tests/oversample/stb_wingraph.h | 3 + 5 files changed, 148 insertions(+), 43 deletions(-) create mode 100644 tests/oversample/oversample.exe diff --git a/stb_rect_pack.h b/stb_rect_pack.h index 5462379..6a9e8d3 100644 --- a/stb_rect_pack.h +++ b/stb_rect_pack.h @@ -1,4 +1,4 @@ -// stb_rect_pack.h - v0.03 - public domain - rectangle packing +// stb_rect_pack.h - v0.04 - public domain - rectangle packing // Sean Barrett 2014 // // Useful for e.g. packing rectangular textures into an atlas. @@ -19,7 +19,11 @@ // Please note: better rectangle packers are welcome! Please // implement them to the same API, but with a different init // function. - +// +// Version history: +// +// 0.04: fixed minor bug in STBRP_LARGE_RECTS support +// 0.01: initial release ////////////////////////////////////////////////////////////////////////////// // diff --git a/stb_truetype.h b/stb_truetype.h index 4b7db1a..f57ec09 100644 --- a/stb_truetype.h +++ b/stb_truetype.h @@ -1,4 +1,4 @@ -// stb_truetype.h - v0.99 - public domain +// stb_truetype.h - v1.00 - public domain // authored from 2009-2014 by Sean Barrett / RAD Game Tools // // This library processes TrueType files: @@ -40,6 +40,7 @@ // // VERSION HISTORY // +// 1.00 (2014-12-06) add new PackBegin etc. API, w/ support for oversampling // 0.99 (2014-09-18) fix multiple bugs with subpixel rendering (ryg) // 0.9 (2014-08-07) support certain mac/iOS fonts without an MS platformID // 0.8b (2014-07-07) fix a warning @@ -61,7 +62,7 @@ // updated Hello World! sample to use kerning and subpixel // fixed some warnings // 0.3 (2009-06-24) cmap fmt=12, compound shapes (MM) -// userdata, malloc-from-userdata, non-zero fill (STB) +// userdata, malloc-from-userdata, non-zero fill (stb) // 0.2 (2009-03-11) Fix unsigned/signed char warnings // 0.1 (2009-03-09) First public release // @@ -79,11 +80,18 @@ // before the #include of this file. This expands out the actual // implementation into that C/C++ file. // -// Simple 3D API (don't ship this, but it's fine for tools and quick start, -// and you can cut and paste from it to move to more advanced) +// Simple 3D API (don't ship this, but it's fine for tools and quick start) // stbtt_BakeFontBitmap() -- bake a font to a bitmap for use as texture // stbtt_GetBakedQuad() -- compute quad to draw for a given char // +// Improved 3D API (more shippable): +// #include "stb_rect_pack.h" -- optional, but you really want it +// stbtt_PackBegin() +// stbtt_PackSetOversample() -- for improved quality on small fonts +// stbtt_PackFontRanges() +// stbtt_PackEnd() +// stbtt_GetPackedQuad() +// // "Load" a font file from a memory buffer (you have to keep the buffer loaded) // stbtt_InitFont() // stbtt_GetFontOffsetForIndex() -- use for TTC font collections @@ -484,21 +492,51 @@ typedef struct typedef struct stbtt_pack_context stbtt_pack_context; typedef struct { - float font_size; // if positive, pixel height; if negative, points + float font_size; int first_unicode_char_in_range; int num_chars_in_range; stbtt_packedchar *chardata_for_range; // output } stbtt_pack_range; -extern int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int ph, int stride_in_bytes, int padding, void *alloc_context); -// returns 0 if the allocations fail +extern int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context); +// Initializes a packing context stored in the passed-in stbtt_pack_context. +// Future calls using this context will pack characters into the bitmap passed +// in here: a 1-channel bitmap that is weight x height. stride_in_bytes is +// the distance from one row to the next (or 0 to mean they are packed tightly +// together). "padding" is // the amount of padding to leave between each +// character (normally you want '1' for bitmaps you'll use as textures with +// bilinear filtering). +// +// Returns 0 on failure, 1 on success. + +extern void stbtt_PackEnd (stbtt_pack_context *spc); +// Cleans up the packing context and frees all memory. + +extern int stbtt_PackFontRange(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, float pixel_height, + int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range); +// Creates character bitmaps from the font_index'th font found in fontdata (use +// font_index=0 if you don't know what that is). It creates num_chars_in_range +// bitmaps for characters with unicode values starting at first_unicode_char_in_range +// and increasing. Data for how to render them is stored in chardata_for_range; +// pass these to stbtt_GetPackedQuad to get back renderable quads. + +extern int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges); +// Creates character bitmaps from multiple ranges of characters stored in +// ranges. This will usually create a better-packed bitmap than multiple +// calls to stbtt_PackFontRange. + extern void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample); -extern void stbtt_PackEnd (stbtt_pack_context *spc); -extern int stbtt_PackFontRange(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, float font_size, - int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range); -extern int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges); - +// Oversampling a font increases the quality by allowing higher-quality subpixel +// positioning, and is especially valuable at smaller text sizes. +// +// This function sets the amount of oversampling for all following calls to +// stbtt_PackFontRange(s). The default (no oversampling) is achieved by +// h_oversample=1, v_oversample=1. The total number of pixels required is +// h_oversample*v_oversample larger than the default; for example, 2x2 +// oversampling requires 4x the storage of 1x1. For best results, render +// oversampled textures with bilinear filtering. Look at the readme in +// stb/tests/oversample for information about oversampled fonts extern void stbtt_GetPackedQuad(stbtt_packedchar *chardata, int pw, int ph, // same data as above int char_index, // character to display diff --git a/tests/oversample/main.c b/tests/oversample/main.c index f9f4d76..bc6bd0f 100644 --- a/tests/oversample/main.c +++ b/tests/oversample/main.c @@ -2,11 +2,8 @@ #include #include -#define STB_DEFINE #define STB_WINMAIN -#define STB_NO_REGISTRY #include "stb_wingraph.h" -#include "stb.h" #define STB_TRUETYPE_IMPLEMENTATION #define STB_RECT_PACK_IMPLEMENTATION @@ -22,11 +19,12 @@ #include #include +#define GL_FRAMEBUFFER_SRGB_EXT 0x8DB9 #define SIZE_X 1024 #define SIZE_Y 768 -stbtt_packedchar chardata[3][128]; +stbtt_packedchar chardata[6][128]; int sx=SIZE_X, sy=SIZE_Y; @@ -36,19 +34,40 @@ unsigned char temp_bitmap[BITMAP_W][BITMAP_H]; unsigned char ttf_buffer[1 << 25]; GLuint font_tex; +float scale[2] = { 24.0f, 14.0f }; + +int sf[6] = { 0,1,2, 0,1,2 }; + void load_fonts(void) { stbtt_pack_context pc; - FILE *f = fopen("c:/windows/fonts/times.ttf", "rb"); - if (!f) exit(0); + int i; + FILE *f; + char filename[256]; + char *win = getenv("windir"); + if (win == NULL) win = getenv("SystemRoot"); + + f = fopen(stb_wingraph_commandline, "rb"); + if (!f) { + if (win == NULL) + sprintf(filename, "arial.ttf", win); + else + sprintf(filename, "%s/fonts/arial.ttf", win); + f = fopen(filename, "rb"); + if (!f) exit(0); + } + fread(ttf_buffer, 1, 1<<25, f); stbtt_PackBegin(&pc, temp_bitmap[0], BITMAP_W, BITMAP_H, 0, 1, NULL); - stbtt_PackFontRange(&pc, ttf_buffer, 0, 24.0, 32, 95, chardata[0]+32); - stbtt_PackSetOversampling(&pc, 2, 2); - stbtt_PackFontRange(&pc, ttf_buffer, 0, 24.0, 32, 95, chardata[1]+32); - stbtt_PackSetOversampling(&pc, 3, 1); - stbtt_PackFontRange(&pc, ttf_buffer, 0, 24.0, 32, 95, chardata[2]+32); + for (i=0; i < 2; ++i) { + stbtt_PackSetOversampling(&pc, 1, 1); + stbtt_PackFontRange(&pc, ttf_buffer, 0, scale[i], 32, 95, chardata[i*3+0]+32); + stbtt_PackSetOversampling(&pc, 2, 2); + stbtt_PackFontRange(&pc, ttf_buffer, 0, scale[i], 32, 95, chardata[i*3+1]+32); + stbtt_PackSetOversampling(&pc, 3, 1); + stbtt_PackFontRange(&pc, ttf_buffer, 0, scale[i], 32, 95, chardata[i*3+2]+32); + } stbtt_PackEnd(&pc); glGenTextures(1, &font_tex); @@ -58,6 +77,8 @@ void load_fonts(void) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } +int black_on_white; + void draw_init(void) { glDisable(GL_CULL_FACE); @@ -66,7 +87,10 @@ void draw_init(void) glDisable(GL_DEPTH_TEST); glViewport(0,0,sx,sy); - glClearColor(0,0,0,0); + if (black_on_white) + glClearColor(255,255,255,0); + else + glClearColor(0,0,0,0); glClear(GL_COLOR_BUFFER_BIT); glMatrixMode(GL_PROJECTION); @@ -100,41 +124,64 @@ void print(float x, float y, int font, char *text) glEnd(); } -int font=0; +int font=3; int translating; int rotating=0; +int srgb=0; float rotate_t, translate_t; int show_tex; void draw_world(void) { + int sfont = sf[font]; float x = 20; glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glColor3f(1,1,1); - if (font==1) - print(100, 50, font, "2x2 oversampled text at 1:1"); - else if (font == 2) - print(100, 50, font, "3x1 oversampled text at 1:1"); - else if (integer_align) - print(100, 50, font, "1:1 text, one texel = one pixel, snapped to integer coordinates"); + if (black_on_white) + glColor3f(0,0,0); else - print(100, 50, font, "1:1 text, one texel = one pixel"); + glColor3f(1,1,1); - print(100, 80, font, "O: toggle oversampling"); - print(100,105, font, "T: toggle translation"); - print(100,130, font, "R: toggle rotation"); - print(100,155, font, "P: toggle pixel-snap (only non-oversampled)"); - print(100,180, font, "V: view font texture"); + + print(80, 30, sfont, "Controls:"); + print(100, 60, sfont, "S: toggle font size"); + print(100, 85, sfont, "O: toggle oversampling"); + print(100,110, sfont, "T: toggle translation"); + print(100,135, sfont, "R: toggle rotation"); + print(100,160, sfont, "P: toggle pixel-snap (only non-oversampled)"); + print(100,185, sfont, "G: toggle srgb gamma-correction"); + if (black_on_white) + print(100,210, sfont, "B: toggle to white-on-black"); + else + print(100,210, sfont, "B: toggle to black-on-white"); + print(100,235, sfont, "V: view font texture"); + + print(80, 300, sfont, "Current font:"); + + if (!show_tex) { + if (font < 3) + print(100, 350, sfont, "Font height: 24 pixels"); + else + print(100, 350, sfont, "Font height: 14 pixels"); + } + + if (font%3==1) + print(100, 325, sfont, "2x2 oversampled text at 1:1"); + else if (font%3 == 2) + print(100, 325, sfont, "3x1 oversampled text at 1:1"); + else if (integer_align) + print(100, 325, sfont, "1:1 text, one texel = one pixel, snapped to integer coordinates"); + else + print(100, 325, sfont, "1:1 text, one texel = one pixel"); if (show_tex) { glBegin(GL_QUADS); - drawBoxTC(200,200, 200+BITMAP_W,200+BITMAP_H, 0,0,1,1); + drawBoxTC(200,400, 200+BITMAP_W,300+BITMAP_H, 0,0,1,1); glEnd(); } else { glMatrixMode(GL_MODELVIEW); - glTranslatef(200,250,0); + glTranslatef(200,350,0); if (translating) x += fmod(translate_t*8,30); @@ -198,7 +245,10 @@ int winproc(void *data, stbwingraph_event *e) return STBWINGRAPH_winproc_exit; break; case 'o': case 'O': - font = (font+1) % 3; + font = (font+1) % 3 + (font/3)*3; + break; + case 's': case 'S': + font = (font+3) % 6; break; case 't': case 'T': translating = !translating; @@ -211,9 +261,19 @@ int winproc(void *data, stbwingraph_event *e) case 'p': case 'P': integer_align = !integer_align; break; + case 'g': case 'G': + srgb = !srgb; + if (srgb) + glEnable(GL_FRAMEBUFFER_SRGB_EXT); + else + glDisable(GL_FRAMEBUFFER_SRGB_EXT); + break; case 'v': case 'V': show_tex = !show_tex; break; + case 'b': case 'B': + black_on_white = !black_on_white; + break; } break; diff --git a/tests/oversample/oversample.exe b/tests/oversample/oversample.exe new file mode 100644 index 0000000000000000000000000000000000000000..004069318671fd3a7d13d393cd70a9c7b77a2207 GIT binary patch literal 54272 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\-(aEl(~6QB;ZpG>kn>^Ha6=B3)9zXH``ux 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 GTF?Ob0~1mJ literal 0 HcmV?d00001 diff --git a/tests/oversample/stb_wingraph.h b/tests/oversample/stb_wingraph.h index d48065f..ee16923 100644 --- a/tests/oversample/stb_wingraph.h +++ b/tests/oversample/stb_wingraph.h @@ -791,6 +791,8 @@ void stbwingraph_SwapBuffers(void *win) #ifdef STB_WINMAIN void stbwingraph_main(void); +char *stb_wingraph_commandline; + int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { { @@ -808,6 +810,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine else if (strstr(buffer, " -full ") || strstr(buffer, " -fullscreen ")) stbwingraph_request_fullscreen = TRUE; } + stb_wingraph_commandline = lpCmdLine; stbwingraph_DefineClass(hInstance, "appicon"); stbwingraph_main(); From 0a1d82f9e327e796792a5886448ed6e42746fad1 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Sat, 6 Dec 2014 23:02:10 -0800 Subject: [PATCH 12/46] readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4283d3a..2fa86e1 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ library | lastest version | category | description --------------------- | ---- | -------- | -------------------------------- **stb_vorbis.c** | 1.04 | audio | decode ogg vorbis files from file/memory to float/16-bit signed output **stb_image.h** | 1.46 | graphics | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC -**stb_truetype.h** | 0.99 | graphics | parse, decode, and rasterize characters from truetype fonts +**stb_truetype.h** | 1.00 | graphics | parse, decode, and rasterize characters from truetype fonts **stb_image_write.h** | 0.95 | graphics | image writing to disk: PNG, TGA, BMP **stb_image_resize.h** | 0.90 | graphics | resize images larger/smaller with good quality **stretchy_buffer.h** | 1.01 | utility | typesafe dynamic array for C (i.e. approximation to vector<>), doesn't compile as C++ From c6e1ec0cecf14a64d7047530bd41b8bd7b8c0d32 Mon Sep 17 00:00:00 2001 From: nothings Date: Sat, 6 Dec 2014 23:17:44 -0800 Subject: [PATCH 13/46] Create README.md --- tests/oversample/README.md | 44 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 tests/oversample/README.md diff --git a/tests/oversample/README.md b/tests/oversample/README.md new file mode 100644 index 0000000..f2edeca --- /dev/null +++ b/tests/oversample/README.md @@ -0,0 +1,44 @@ +# Font character oversampling for rendering from atlas textures + +TL,DR: Run oversample.exe on a windows machine to see the +benefits of oversampling. Type the name of a .ttf file on +the command-line, or it will look for Arial in the Windows +font directory. + +## About oversampling + +A common strategy for rendering text is to cache character bitmaps +and reuse them. For hinted characters, every instance of a given +character is always identical, so this works fine. However, stb_truetype +doesn't do hinting. + +For anti-aliased characters, you can actually position the characters +with subpixel precision, and get different bitmaps based on that positioning +if you re-render the vector data. + +However, if you simply cache a single version of the bitmap and +draw it at different subpixel positions with a GPU, you will get +either the exact same result (if you use point-sampling on the +texture) or linear filtering. Linear filtering will cause a sub-pixel +positioned bitmap to blur further, causing a visible desharpening +of the character. (And, since the character wasn't hinted, it was +already blurrier than a hinted one would be, and not it gets even +more blurry.) + +You can avoid this by caching multiple variants of a character which +were rendered independently from the vector data. For example, you +might cache 3 versions of a char, at 0, 1/3, and 2/3rds of a pixel +horizontal offset, and always require characters to fall on integer +positions vertically. + +When creating a texture atlas for use on GPUs, which support bilinear +filtering, there is a better approach than caching several indepdent +positions, which is to allow lerping between the versions to allow +finer subpixel positioning. You can achieve these by interleaving +each of the cached bitmaps, but this turns out to be mathematically +equivalent to a simpler operation: oversampling and prefiltering the +characters. + +So, setting oversampling of 2x2 in stb_truetype is equivalent to caching +each character in 4 different variations, 1 for each subpixel position +in a 2x2 set. From 19b24bba1a02d617443e7316c324c93b56cd042d Mon Sep 17 00:00:00 2001 From: nothings Date: Sat, 6 Dec 2014 23:19:25 -0800 Subject: [PATCH 14/46] Update README.md --- tests/oversample/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/oversample/README.md b/tests/oversample/README.md index f2edeca..4b72edd 100644 --- a/tests/oversample/README.md +++ b/tests/oversample/README.md @@ -20,9 +20,9 @@ However, if you simply cache a single version of the bitmap and draw it at different subpixel positions with a GPU, you will get either the exact same result (if you use point-sampling on the texture) or linear filtering. Linear filtering will cause a sub-pixel -positioned bitmap to blur further, causing a visible desharpening +positioned bitmap to blur further, causing a visible de-sharpening of the character. (And, since the character wasn't hinted, it was -already blurrier than a hinted one would be, and not it gets even +already blurrier than a hinted one would be, and now it gets even more blurry.) You can avoid this by caching multiple variants of a character which @@ -32,7 +32,7 @@ horizontal offset, and always require characters to fall on integer positions vertically. When creating a texture atlas for use on GPUs, which support bilinear -filtering, there is a better approach than caching several indepdent +filtering, there is a better approach than caching several independent positions, which is to allow lerping between the versions to allow finer subpixel positioning. You can achieve these by interleaving each of the cached bitmaps, but this turns out to be mathematically From 539dc3996bc9a8f575373067d77e03a83fc2b4e9 Mon Sep 17 00:00:00 2001 From: nothings Date: Sat, 6 Dec 2014 23:21:11 -0800 Subject: [PATCH 15/46] Update README.md --- tests/oversample/README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/oversample/README.md b/tests/oversample/README.md index 4b72edd..c07fd0c 100644 --- a/tests/oversample/README.md +++ b/tests/oversample/README.md @@ -42,3 +42,10 @@ characters. So, setting oversampling of 2x2 in stb_truetype is equivalent to caching each character in 4 different variations, 1 for each subpixel position in a 2x2 set. + +The advantage of this formulation is that no changes are required to +the rendering code; the exact same quad-rendering code works, it just +uses different texture coordinates. (Note this does potentially increase +texture bandwidth for text rendering since we end up minifying the texture +without using mipmapping, but you probably are not going to be fill-bound +by your text rendering.) From 4b87ba76fe2dd24b4fcbfdee216f0da3d60b7c0c Mon Sep 17 00:00:00 2001 From: nothings Date: Sat, 6 Dec 2014 23:22:14 -0800 Subject: [PATCH 16/46] Update README.md --- tests/oversample/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/oversample/README.md b/tests/oversample/README.md index c07fd0c..29e4d32 100644 --- a/tests/oversample/README.md +++ b/tests/oversample/README.md @@ -1,9 +1,9 @@ # Font character oversampling for rendering from atlas textures TL,DR: Run oversample.exe on a windows machine to see the -benefits of oversampling. Type the name of a .ttf file on -the command-line, or it will look for Arial in the Windows -font directory. +benefits of oversampling. It will try to use arial.ttf from the +Windows font directory unless you type the name of a .ttf file as +a command-line argument. ## About oversampling From 7d0cec62c887103d986db1f62daa7ceb3f5c23ae Mon Sep 17 00:00:00 2001 From: nothings Date: Sat, 6 Dec 2014 23:28:04 -0800 Subject: [PATCH 17/46] Update README.md --- tests/oversample/README.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/tests/oversample/README.md b/tests/oversample/README.md index 29e4d32..be50058 100644 --- a/tests/oversample/README.md +++ b/tests/oversample/README.md @@ -5,7 +5,16 @@ benefits of oversampling. It will try to use arial.ttf from the Windows font directory unless you type the name of a .ttf file as a command-line argument. -## About oversampling +## Benefits of oversampling + +Improving subpixel has a few benefits: + +* Text can remain sharper while still being sub-pixel positioned for better kerning +* Horizontally-oversampled text significantly reduces aliasing when text animates horizontally +* Vertically-oversampled text significantly reduces aliasing when text animates vertically +* Text oversampled in both directions significantly reduces aliasing when text rotates + +## What text oversampling is A common strategy for rendering text is to cache character bitmaps and reuse them. For hinted characters, every instance of a given @@ -43,9 +52,10 @@ So, setting oversampling of 2x2 in stb_truetype is equivalent to caching each character in 4 different variations, 1 for each subpixel position in a 2x2 set. -The advantage of this formulation is that no changes are required to +An advantage of this formulation is that no changes are required to the rendering code; the exact same quad-rendering code works, it just uses different texture coordinates. (Note this does potentially increase texture bandwidth for text rendering since we end up minifying the texture without using mipmapping, but you probably are not going to be fill-bound by your text rendering.) + From 9b1e1c50c0027eb0c0574de471e9bfd415fc7206 Mon Sep 17 00:00:00 2001 From: nothings Date: Sat, 6 Dec 2014 23:28:28 -0800 Subject: [PATCH 18/46] Update README.md --- tests/oversample/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/oversample/README.md b/tests/oversample/README.md index be50058..e20ae5b 100644 --- a/tests/oversample/README.md +++ b/tests/oversample/README.md @@ -7,6 +7,8 @@ a command-line argument. ## Benefits of oversampling +Oversampling is a mechanism for improving subpixel rendering of characters. + Improving subpixel has a few benefits: * Text can remain sharper while still being sub-pixel positioned for better kerning From ae5bc8dfe9e881a073537debf8a9fe46b8d7b5df Mon Sep 17 00:00:00 2001 From: nothings Date: Sat, 6 Dec 2014 23:30:46 -0800 Subject: [PATCH 19/46] Update README.md --- tests/oversample/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/oversample/README.md b/tests/oversample/README.md index e20ae5b..bac1b7e 100644 --- a/tests/oversample/README.md +++ b/tests/oversample/README.md @@ -11,7 +11,7 @@ Oversampling is a mechanism for improving subpixel rendering of characters. Improving subpixel has a few benefits: -* Text can remain sharper while still being sub-pixel positioned for better kerning +* With horizontally-oversampling, text can remain sharper while still being sub-pixel positioned for better kerning * Horizontally-oversampled text significantly reduces aliasing when text animates horizontally * Vertically-oversampled text significantly reduces aliasing when text animates vertically * Text oversampled in both directions significantly reduces aliasing when text rotates From b62bc08c340d2983c2daec6b4e97ade61c78d6d9 Mon Sep 17 00:00:00 2001 From: nothings Date: Sat, 6 Dec 2014 23:31:12 -0800 Subject: [PATCH 20/46] Update README.md --- tests/oversample/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/oversample/README.md b/tests/oversample/README.md index bac1b7e..61f3cf8 100644 --- a/tests/oversample/README.md +++ b/tests/oversample/README.md @@ -11,7 +11,7 @@ Oversampling is a mechanism for improving subpixel rendering of characters. Improving subpixel has a few benefits: -* With horizontally-oversampling, text can remain sharper while still being sub-pixel positioned for better kerning +* With horizontal-oversampling, text can remain sharper while still being sub-pixel positioned for better kerning * Horizontally-oversampled text significantly reduces aliasing when text animates horizontally * Vertically-oversampled text significantly reduces aliasing when text animates vertically * Text oversampled in both directions significantly reduces aliasing when text rotates From cd5b5a56848ba7e5258cb2c678f6a8707c08e4f3 Mon Sep 17 00:00:00 2001 From: nothings Date: Sat, 6 Dec 2014 23:46:40 -0800 Subject: [PATCH 21/46] Update README.md --- tests/oversample/README.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/oversample/README.md b/tests/oversample/README.md index 61f3cf8..bc786d0 100644 --- a/tests/oversample/README.md +++ b/tests/oversample/README.md @@ -61,3 +61,28 @@ texture bandwidth for text rendering since we end up minifying the texture without using mipmapping, but you probably are not going to be fill-bound by your text rendering.) +## What about gamma? + +Gamma-correction for fonts just doesn't work. This doesn't seem to make +much sense -- it's physically correct, it simulates what we'd see if you +shrunk a font down really far, right? + +But you can play with it in the oversample.exe app. If you turn it on, +white-on-black fonts become too thick (i.e. they become too bright), and +black-on-white fonts become too thin (i.e. they are too dark). There is +no way to adjust the font's inherent thickness (i.e. by switching to +bold) to fix this for both; making the font thicker will make white +text worse, and making the font thinner will make black text worse. + +Multiple people who have experimented with this independently (me, +Fabian Giesen,and Maxim Shemanarev of Anti-Grain Geometry) have all +oncluded that font rendering just generally looks better without +gamma correction (or probably with some arbitrary power stuck in +there, but it's not really correcting for gamma at that point). Maybe +this is in part a product of how we're used to fonts being on screens +which has changed how we expect them to look (e.g. perhaps hinting +oversharpens them and prevents the real-world thinning you'd see in +a black-on-white text). + +Nevertheless, even if you turn on gamma-correction, you will find that +oversampling still helps in many cases for small fonts. From 916800aae5bcdb55226449d3a93f9889ec393d12 Mon Sep 17 00:00:00 2001 From: nothings Date: Sat, 6 Dec 2014 23:48:10 -0800 Subject: [PATCH 22/46] Update README.md --- tests/oversample/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/oversample/README.md b/tests/oversample/README.md index bc786d0..8ea1564 100644 --- a/tests/oversample/README.md +++ b/tests/oversample/README.md @@ -76,7 +76,8 @@ text worse, and making the font thinner will make black text worse. Multiple people who have experimented with this independently (me, Fabian Giesen,and Maxim Shemanarev of Anti-Grain Geometry) have all -oncluded that font rendering just generally looks better without +concluded that correct gamma-correction does not produce the best +results for fonts. font rendering just generally looks better without gamma correction (or probably with some arbitrary power stuck in there, but it's not really correcting for gamma at that point). Maybe this is in part a product of how we're used to fonts being on screens From 49d5456de9b8771975456ec325db873d9ff73279 Mon Sep 17 00:00:00 2001 From: nothings Date: Sat, 6 Dec 2014 23:49:29 -0800 Subject: [PATCH 23/46] Update README.md --- tests/oversample/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/oversample/README.md b/tests/oversample/README.md index 8ea1564..83018e7 100644 --- a/tests/oversample/README.md +++ b/tests/oversample/README.md @@ -73,6 +73,8 @@ black-on-white fonts become too thin (i.e. they are too dark). There is no way to adjust the font's inherent thickness (i.e. by switching to bold) to fix this for both; making the font thicker will make white text worse, and making the font thinner will make black text worse. +Obviously you could use different fonts for light and dark cases, but +this doesn't like a very good way for fonts to work. Multiple people who have experimented with this independently (me, Fabian Giesen,and Maxim Shemanarev of Anti-Grain Geometry) have all From 3a5caacaaeb520184f7d8a2b392fc2589780c678 Mon Sep 17 00:00:00 2001 From: nothings Date: Sat, 6 Dec 2014 23:50:34 -0800 Subject: [PATCH 24/46] Update README.md --- tests/oversample/README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/oversample/README.md b/tests/oversample/README.md index 83018e7..adcd872 100644 --- a/tests/oversample/README.md +++ b/tests/oversample/README.md @@ -79,13 +79,16 @@ this doesn't like a very good way for fonts to work. Multiple people who have experimented with this independently (me, Fabian Giesen,and Maxim Shemanarev of Anti-Grain Geometry) have all concluded that correct gamma-correction does not produce the best -results for fonts. font rendering just generally looks better without -gamma correction (or probably with some arbitrary power stuck in +results for fonts. Font rendering just generally looks better without +gamma correction (or possibly with some arbitrary power stuck in there, but it's not really correcting for gamma at that point). Maybe this is in part a product of how we're used to fonts being on screens which has changed how we expect them to look (e.g. perhaps hinting oversharpens them and prevents the real-world thinning you'd see in a black-on-white text). +(AGG link on text rendering, including mention of gamma: + http://www.antigrain.com/research/font_rasterization/ ) + Nevertheless, even if you turn on gamma-correction, you will find that oversampling still helps in many cases for small fonts. From 8ac41a413d397a91056f97f6d50932b6b479888c Mon Sep 17 00:00:00 2001 From: nothings Date: Mon, 8 Dec 2014 11:42:47 -0800 Subject: [PATCH 25/46] fix typo --- tests/oversample/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/oversample/README.md b/tests/oversample/README.md index adcd872..cdfdfff 100644 --- a/tests/oversample/README.md +++ b/tests/oversample/README.md @@ -69,12 +69,12 @@ shrunk a font down really far, right? But you can play with it in the oversample.exe app. If you turn it on, white-on-black fonts become too thick (i.e. they become too bright), and -black-on-white fonts become too thin (i.e. they are too dark). There is +black-on-white fonts become too thin (i.e. they are insufficiently dark). There is no way to adjust the font's inherent thickness (i.e. by switching to bold) to fix this for both; making the font thicker will make white text worse, and making the font thinner will make black text worse. Obviously you could use different fonts for light and dark cases, but -this doesn't like a very good way for fonts to work. +this doesn't seem like a very good way for fonts to work. Multiple people who have experimented with this independently (me, Fabian Giesen,and Maxim Shemanarev of Anti-Grain Geometry) have all From 5f674fc7e58206ba458b2c407d15dd76a813744d Mon Sep 17 00:00:00 2001 From: Fabian Giesen Date: Mon, 8 Dec 2014 19:20:41 -0800 Subject: [PATCH 26/46] stb_truetype: Cancel out phase offset from box filter correctly. --- stb_truetype.h | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/stb_truetype.h b/stb_truetype.h index f57ec09..9a1715b 100644 --- a/stb_truetype.h +++ b/stb_truetype.h @@ -2275,13 +2275,25 @@ static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_i } } +static float stbtt__oversample_shift(int oversample) +{ + if (!oversample) + return 0.0f; + + // The prefilter is a box filter of width "oversample", + // which shifts phase by (oversample - 1)/2 pixels in + // oversampled space. We want to shift in the opposite + // direction to counter this. + return (float)-(oversample - 1) / (2.0f * (float)oversample); +} + int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges) { stbtt_fontinfo info; float recip_h = 1.0f / spc->h_oversample; float recip_v = 1.0f / spc->v_oversample; - float sub_x = spc->h_oversample ? recip_h : 0; - float sub_y = spc->v_oversample ? recip_v : 0; + float sub_x = stbtt__oversample_shift(spc->h_oversample); + float sub_y = stbtt__oversample_shift(spc->v_oversample); int i,j,k,n, return_value = 1; stbrp_context *context = (stbrp_context *) spc->pack_info; stbrp_rect *rects; From ffbea74703c902a12390e10a869e605a4b3bebe6 Mon Sep 17 00:00:00 2001 From: Fabian Giesen Date: Mon, 8 Dec 2014 19:39:49 -0800 Subject: [PATCH 27/46] stb_rect_pack.h: Impl must include assert.h --- stb_rect_pack.h | 1 + 1 file changed, 1 insertion(+) diff --git a/stb_rect_pack.h b/stb_rect_pack.h index 6a9e8d3..c30654f 100644 --- a/stb_rect_pack.h +++ b/stb_rect_pack.h @@ -169,6 +169,7 @@ struct stbrp_context #ifdef STB_RECT_PACK_IMPLEMENTATION #include +#include enum { From 27974c42f956886ec810e2b6130b1ccb11858b59 Mon Sep 17 00:00:00 2001 From: Fabian Giesen Date: Mon, 8 Dec 2014 19:43:27 -0800 Subject: [PATCH 28/46] stb_truetype: Negative size = pixels for EM square. --- stb_truetype.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/stb_truetype.h b/stb_truetype.h index 9a1715b..cc0173d 100644 --- a/stb_truetype.h +++ b/stb_truetype.h @@ -2318,8 +2318,7 @@ int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontdata, int f k=0; for (i=0; i < num_ranges; ++i) { float fh = ranges[i].font_size; - //float scale = fh > 0 ? stbtt_ScaleForPixelHeight(&info, fh) : stbtt_ScaleForPointSize(&info, fh); - float scale = stbtt_ScaleForPixelHeight(&info, fh); + float scale = fh > 0 ? stbtt_ScaleForPixelHeight(&info, fh) : stbtt_ScaleForMappingEmToPixels(&info, -fh); for (j=0; j < ranges[i].num_chars_in_range; ++j) { int x0,y0,x1,y1; stbtt_GetCodepointBitmapBoxSubpixel(&info, ranges[i].first_unicode_char_in_range + j, @@ -2338,8 +2337,7 @@ int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontdata, int f k = 0; for (i=0; i < num_ranges; ++i) { float fh = ranges[i].font_size; - //float scale = fh > 0 ? stbtt_ScaleForPixelHeight(&info, fh) : stbtt_ScaleForPointSize(&info, fh); - float scale = stbtt_ScaleForPixelHeight(&info, fh); + float scale = fh > 0 ? stbtt_ScaleForPixelHeight(&info, fh) : stbtt_ScaleForMappingEmToPixels(&info, -fh); for (j=0; j < ranges[i].num_chars_in_range; ++j) { stbrp_rect *r = &rects[k]; if (r->was_packed) { From 82677e551820b74eb366ca60060d18acb3a12f69 Mon Sep 17 00:00:00 2001 From: Fabian Giesen Date: Mon, 8 Dec 2014 19:51:39 -0800 Subject: [PATCH 29/46] stb_truetype: Fix implicit conversion warnings. --- stb_truetype.h | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/stb_truetype.h b/stb_truetype.h index cc0173d..85d47c1 100644 --- a/stb_truetype.h +++ b/stb_truetype.h @@ -869,7 +869,7 @@ enum { // languageID for STBTT_PLATFORM_ID_MAC #define STBTT_MAX_OVERSAMPLE 8 #endif -typedef stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE-1)) == 0 ? 1 : -1]; +typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE-1)) == 0 ? 1 : -1]; ////////////////////////////////////////////////////////////////////////// // @@ -2173,7 +2173,6 @@ static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_i for (j=0; j < h; ++j) { int i; unsigned int total; - unsigned char *pixels_ahead = pixels + (kernel_width); memset(buffer, 0, kernel_width); total = 0; @@ -2184,28 +2183,28 @@ static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_i for (i=0; i <= safe_w; ++i) { total += pixels[i] - buffer[i & STBTT__OVER_MASK]; buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; - pixels[i] = total / 2; + pixels[i] = (unsigned char) (total / 2); } break; case 3: for (i=0; i <= safe_w; ++i) { total += pixels[i] - buffer[i & STBTT__OVER_MASK]; buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; - pixels[i] = total / 3; + pixels[i] = (unsigned char) (total / 3); } break; case 4: for (i=0; i <= safe_w; ++i) { total += pixels[i] - buffer[i & STBTT__OVER_MASK]; buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; - pixels[i] = total / 4; + pixels[i] = (unsigned char) (total / 4); } break; default: for (i=0; i <= safe_w; ++i) { total += pixels[i] - buffer[i & STBTT__OVER_MASK]; buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; - pixels[i] = total / kernel_width; + pixels[i] = (unsigned char) (total / kernel_width); } break; } @@ -2213,7 +2212,7 @@ static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_i for (; i < w; ++i) { assert(pixels[i] == 0); total -= buffer[i & STBTT__OVER_MASK]; - pixels[i] = total / kernel_width; + pixels[i] = (unsigned char) (total / kernel_width); } pixels += stride_in_bytes; @@ -2228,7 +2227,6 @@ static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_i for (j=0; j < w; ++j) { int i; unsigned int total; - unsigned char *pixels_ahead = pixels + (kernel_width)*stride_in_bytes; memset(buffer, 0, kernel_width); total = 0; @@ -2239,28 +2237,28 @@ static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_i for (i=0; i <= safe_h; ++i) { total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = total / 2; + pixels[i*stride_in_bytes] = (unsigned char) (total / 2); } break; case 3: for (i=0; i <= safe_h; ++i) { total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = total / 3; + pixels[i*stride_in_bytes] = (unsigned char) (total / 3); } break; case 4: for (i=0; i <= safe_h; ++i) { total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = total / 4; + pixels[i*stride_in_bytes] = (unsigned char) (total / 4); } break; default: for (i=0; i <= safe_h; ++i) { total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = total / kernel_width; + pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); } break; } @@ -2268,7 +2266,7 @@ static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_i for (; i < h; ++i) { assert(pixels[i*stride_in_bytes] == 0); total -= buffer[i & STBTT__OVER_MASK]; - pixels[i*stride_in_bytes] = total / kernel_width; + pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); } pixels += 1; @@ -2326,8 +2324,8 @@ int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontdata, int f scale * spc->v_oversample, 0,0, &x0,&y0,&x1,&y1); - rects[k].w = x1-x0 + spc->padding + spc->h_oversample-1; - rects[k].h = y1-y0 + spc->padding + spc->v_oversample-1; + rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1); + rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1); ++k; } } @@ -2344,12 +2342,13 @@ int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontdata, int f stbtt_packedchar *bc = &ranges[i].chardata_for_range[j]; int advance, lsb, x0,y0,x1,y1; int glyph = stbtt_FindGlyphIndex(&info, ranges[i].first_unicode_char_in_range + j); + stbrp_coord pad = (stbrp_coord) spc->padding; // pad on left and top - r->x += spc->padding; - r->y += spc->padding; - r->w -= spc->padding; - r->h -= spc->padding; + r->x += pad; + r->y += pad; + r->w -= pad; + r->h -= pad; stbtt_GetGlyphHMetrics(&info, glyph, &advance, &lsb); stbtt_GetGlyphBitmapBox(&info, glyph, scale * spc->h_oversample, From d9e121f4c73e34ec1f9b7dd6dac19a11c1cd1ee1 Mon Sep 17 00:00:00 2001 From: Fabian Giesen Date: Mon, 8 Dec 2014 19:53:12 -0800 Subject: [PATCH 30/46] stb_rect_pack: Fix implicit conversion warnings. --- stb_rect_pack.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stb_rect_pack.h b/stb_rect_pack.h index c30654f..74eb61d 100644 --- a/stb_rect_pack.h +++ b/stb_rect_pack.h @@ -231,7 +231,7 @@ STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, context->extra[0].x = 0; context->extra[0].y = 0; context->extra[0].next = &context->extra[1]; - context->extra[1].x = width; + context->extra[1].x = (stbrp_coord) width; #ifdef STBRP_LARGE_RECTS context->extra[1].y = (1<<30); #else @@ -406,8 +406,8 @@ static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, i // on success, create new node node = context->free_head; - node->x = res.x; - node->y = res.y + height; + node->x = (stbrp_coord) res.x; + node->y = (stbrp_coord) (res.y + height); context->free_head = node->next; @@ -439,7 +439,7 @@ static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, i node->next = cur; if (cur->x < res.x + width) - cur->x = res.x+width; + cur->x = (stbrp_coord) (res.x + width); #ifdef _DEBUG cur = context->active_head; From 97037461d9dce859f0be5985d17203db96867844 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Mon, 8 Dec 2014 19:56:39 -0800 Subject: [PATCH 31/46] stb_truetype: STBTT_POINT_SIZE documentation for above stb_rect_pack: STBRP_ASSERT --- stb_rect_pack.h | 33 +++++++++++++++++++-------------- stb_truetype.h | 28 ++++++++++++++++++++-------- 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/stb_rect_pack.h b/stb_rect_pack.h index c30654f..e32aa5c 100644 --- a/stb_rect_pack.h +++ b/stb_rect_pack.h @@ -22,6 +22,7 @@ // // Version history: // +// 0.05: added STBRP_ASSERT to allow replacing assert // 0.04: fixed minor bug in STBRP_LARGE_RECTS support // 0.01: initial release @@ -169,7 +170,11 @@ struct stbrp_context #ifdef STB_RECT_PACK_IMPLEMENTATION #include + +#ifndef STBRP_ASSERT #include +#define STBRP_ASSERT assert +#endif enum { @@ -180,11 +185,11 @@ STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic) { switch (context->init_mode) { case STBRP__INIT_skyline: - assert(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight); + STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight); context->heuristic = heuristic; break; default: - assert(0); + STBRP_ASSERT(0); } } @@ -212,7 +217,7 @@ STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, { int i; #ifndef STBRP_LARGE_RECTS - assert(width <= 0xffff && height <= 0xffff); + STBRP_ASSERT(width <= 0xffff && height <= 0xffff); #endif for (i=0; i < num_nodes-1; ++i) @@ -246,17 +251,17 @@ static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0 stbrp_node *node = first; int x1 = x0 + width; int min_y, visited_width, waste_area; - assert(first->x <= x0); + STBRP_ASSERT(first->x <= x0); #if 0 // skip in case we're past the node while (node->next->x <= x0) ++node; #else - assert(node->next->x > x0); // we ended up handling this in the caller for efficiency + STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency #endif - assert(node->x <= x0); + STBRP_ASSERT(node->x <= x0); min_y = 0; waste_area = 0; @@ -303,7 +308,7 @@ static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int widt // align to multiple of c->align width = (width + c->align - 1); width -= width % c->align; - assert(width % c->align == 0); + STBRP_ASSERT(width % c->align == 0); node = c->active_head; prev = &c->active_head; @@ -360,19 +365,19 @@ static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int widt while (tail) { int xpos = tail->x - width; int y,waste; - assert(xpos >= 0); + STBRP_ASSERT(xpos >= 0); // find the left position that matches this while (node->next->x <= xpos) { prev = &node->next; node = node->next; } - assert(node->next->x > xpos && node->x <= xpos); + STBRP_ASSERT(node->next->x > xpos && node->x <= xpos); y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste); if (y + height < c->height) { if (y <= best_y) { if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) { best_x = xpos; - assert(y <= best_y); + STBRP_ASSERT(y <= best_y); best_y = y; best_waste = waste; best = prev; @@ -444,10 +449,10 @@ static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, i #ifdef _DEBUG cur = context->active_head; while (cur->x < context->width) { - assert(cur->x < cur->next->x); + STBRP_ASSERT(cur->x < cur->next->x); cur = cur->next; } - assert(cur->next == NULL); + STBRP_ASSERT(cur->next == NULL); { stbrp_node *L1 = NULL, *L2 = NULL; @@ -464,7 +469,7 @@ static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, i cur = cur->next; ++count; } - assert(count == context->num_nodes+2); + STBRP_ASSERT(count == context->num_nodes+2); } #endif @@ -514,7 +519,7 @@ STBRP_DEF void stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int n for (i=0; i < num_rects; ++i) { rects[i].was_packed = i; #ifndef STBRP_LARGE_RECTS - assert(rects[i].w <= 0xffff && rects[i].h <= 0xffff); + STBRP_ASSERT(rects[i].w <= 0xffff && rects[i].h <= 0xffff); #endif } diff --git a/stb_truetype.h b/stb_truetype.h index cc0173d..33a10ee 100644 --- a/stb_truetype.h +++ b/stb_truetype.h @@ -40,6 +40,8 @@ // // VERSION HISTORY // +// 1.01 (2014-12-08) fix subpixel position when oversampling to exactly match +// non-oversampled; STBTT_POINT_SIZE for packed case only // 1.00 (2014-12-06) add new PackBegin etc. API, w/ support for oversampling // 0.99 (2014-09-18) fix multiple bugs with subpixel rendering (ryg) // 0.9 (2014-08-07) support certain mac/iOS fonts without an MS platformID @@ -490,13 +492,6 @@ typedef struct } stbtt_packedchar; typedef struct stbtt_pack_context stbtt_pack_context; -typedef struct -{ - float font_size; - int first_unicode_char_in_range; - int num_chars_in_range; - stbtt_packedchar *chardata_for_range; // output -} stbtt_pack_range; extern int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context); // Initializes a packing context stored in the passed-in stbtt_pack_context. @@ -512,13 +507,30 @@ extern int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int extern void stbtt_PackEnd (stbtt_pack_context *spc); // Cleans up the packing context and frees all memory. -extern int stbtt_PackFontRange(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, float pixel_height, +#define STBTT_POINT_SIZE(x) (-(x)) + +extern int stbtt_PackFontRange(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, float font_size, int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range); // Creates character bitmaps from the font_index'th font found in fontdata (use // font_index=0 if you don't know what that is). It creates num_chars_in_range // bitmaps for characters with unicode values starting at first_unicode_char_in_range // and increasing. Data for how to render them is stored in chardata_for_range; // pass these to stbtt_GetPackedQuad to get back renderable quads. +// +// font_size is the full height of the character from ascender to descender, +// as computed by stbtt_ScaleForPixelHeight. To use a point size as computed +// by stbtt_ScaleForMappingEmToPixels, wrap the point size in STBTT_POINT_SIZE() +// and pass that result as 'font_size': +// ..., 20 , ... // font max minus min y is 20 pixels tall +// ..., STBTT_POINT_SIZE(20), ... // 'M' is 20 pixels tall + +typedef struct +{ + float font_size; + int first_unicode_char_in_range; + int num_chars_in_range; + stbtt_packedchar *chardata_for_range; // output +} stbtt_pack_range; extern int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges); // Creates character bitmaps from multiple ranges of characters stored in From d1c85eac78c878109b366d6ef1d9c06a9fa8ad38 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Mon, 8 Dec 2014 19:58:51 -0800 Subject: [PATCH 32/46] update version numbers --- README.md | 3 ++- stb_rect_pack.h | 2 +- stb_truetype.h | 2 +- tools/README.list | 1 + 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2fa86e1..31108a9 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,10 @@ library | lastest version | category | description --------------------- | ---- | -------- | -------------------------------- **stb_vorbis.c** | 1.04 | audio | decode ogg vorbis files from file/memory to float/16-bit signed output **stb_image.h** | 1.46 | graphics | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC -**stb_truetype.h** | 1.00 | graphics | parse, decode, and rasterize characters from truetype fonts +**stb_truetype.h** | 1.01 | graphics | parse, decode, and rasterize characters from truetype fonts **stb_image_write.h** | 0.95 | graphics | image writing to disk: PNG, TGA, BMP **stb_image_resize.h** | 0.90 | graphics | resize images larger/smaller with good quality +**stb_rect_pack.h** | 0.05 | graphics | simple 2D rectangle packer with decent quality **stretchy_buffer.h** | 1.01 | utility | typesafe dynamic array for C (i.e. approximation to vector<>), doesn't compile as C++ **stb_textedit.h** | 1.5 | UI | guts of a text editor for games etc implementing them from scratch **stb_dxt.h** | 1.04 | 3D graphics | Fabian "ryg" Giesen's real-time DXT compressor diff --git a/stb_rect_pack.h b/stb_rect_pack.h index e32aa5c..a5a190d 100644 --- a/stb_rect_pack.h +++ b/stb_rect_pack.h @@ -1,4 +1,4 @@ -// stb_rect_pack.h - v0.04 - public domain - rectangle packing +// stb_rect_pack.h - v0.05 - public domain - rectangle packing // Sean Barrett 2014 // // Useful for e.g. packing rectangular textures into an atlas. diff --git a/stb_truetype.h b/stb_truetype.h index 33a10ee..cb10f5e 100644 --- a/stb_truetype.h +++ b/stb_truetype.h @@ -1,4 +1,4 @@ -// stb_truetype.h - v1.00 - public domain +// stb_truetype.h - v1.01 - public domain // authored from 2009-2014 by Sean Barrett / RAD Game Tools // // This library processes TrueType files: diff --git a/tools/README.list b/tools/README.list index de628e8..c53b0db 100644 --- a/tools/README.list +++ b/tools/README.list @@ -3,6 +3,7 @@ stb_image.h | graphics | image loading/decoding from file/mem 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_rect_pack.h | graphics | simple 2D rectangle packer with decent quality stretchy_buffer.h | utility | typesafe dynamic array for C (i.e. approximation to vector<>), doesn't compile as C++ stb_textedit.h | UI | guts of a text editor for games etc implementing them from scratch stb_dxt.h | 3D graphics | Fabian "ryg" Giesen's real-time DXT compressor From 26439254e81b8a27f84fca911820f4a8ca1f6a02 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Wed, 10 Dec 2014 00:27:11 -0800 Subject: [PATCH 33/46] fix use of stbrp_coord if no stb_rect_pack; fix a few assert()s that weren't STBTT_asserts(); fix missing cast for C++ fix typo in C++ test compilation that prevented it from trying to compile stb_truetype --- stb_truetype.h | 15 +++++++++------ tests/stretch_test.c | 4 ++++ tests/test_cpp_compilation.cpp | 4 ++-- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/stb_truetype.h b/stb_truetype.h index b1c22c9..2cf598f 100644 --- a/stb_truetype.h +++ b/stb_truetype.h @@ -2062,6 +2062,8 @@ void stbtt_GetBakedQuad(stbtt_bakedchar *chardata, int pw, int ph, int char_inde #define STBTT__NOTUSED(v) (void)sizeof(v) #endif +typedef int stbrp_coord; + //////////////////////////////////////////////////////////////////////////////////// // // // // @@ -2086,7 +2088,8 @@ typedef struct typedef struct { - int id,w,h,x,y,was_packed; + stbrp_coord x,y; + int id,w,h,was_packed; } stbrp_rect; static void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *nodes, int num_nodes) @@ -2167,8 +2170,8 @@ void stbtt_PackEnd (stbtt_pack_context *spc) void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample) { - assert(h_oversample <= STBTT_MAX_OVERSAMPLE); - assert(v_oversample <= STBTT_MAX_OVERSAMPLE); + STBTT_assert(h_oversample <= STBTT_MAX_OVERSAMPLE); + STBTT_assert(v_oversample <= STBTT_MAX_OVERSAMPLE); if (h_oversample <= STBTT_MAX_OVERSAMPLE) spc->h_oversample = h_oversample; if (v_oversample <= STBTT_MAX_OVERSAMPLE) @@ -2222,7 +2225,7 @@ static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_i } for (; i < w; ++i) { - assert(pixels[i] == 0); + STBTT_assert(pixels[i] == 0); total -= buffer[i & STBTT__OVER_MASK]; pixels[i] = (unsigned char) (total / kernel_width); } @@ -2276,7 +2279,7 @@ static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_i } for (; i < h; ++i) { - assert(pixels[i*stride_in_bytes] == 0); + STBTT_assert(pixels[i*stride_in_bytes] == 0); total -= buffer[i & STBTT__OVER_MASK]; pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); } @@ -2320,7 +2323,7 @@ int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontdata, int f for (i=0; i < num_ranges; ++i) n += ranges[i].num_chars_in_range; - rects = STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context); + rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context); if (rects == NULL) return 0; diff --git a/tests/stretch_test.c b/tests/stretch_test.c index 2c097bd..8caf43f 100644 --- a/tests/stretch_test.c +++ b/tests/stretch_test.c @@ -1,3 +1,7 @@ +// check that stb_truetype compiles with no stb_rect_pack.h +#define STB_TRUETYPE_IMPLEMENTATION +#include "stb_truetype.h" + #include "stretchy_buffer.h" #include diff --git a/tests/test_cpp_compilation.cpp b/tests/test_cpp_compilation.cpp index 20a2eb7..bc31a76 100644 --- a/tests/test_cpp_compilation.cpp +++ b/tests/test_cpp_compilation.cpp @@ -1,4 +1,4 @@ -#define STB_TRUETYPE_IMPLEMENTATIOn +#define STB_TRUETYPE_IMPLEMENTATION #define STB_PERLIN_IMPLEMENTATION #define STB_IMAGE_WRITE_IMPLEMENTATION #define STB_DXT_IMPLEMENATION @@ -8,6 +8,7 @@ #define STB_HERRINGBONE_WANG_TILE_IMPLEMENTATION #define STB_RECT_PACK_IMPLEMENTATION +#include "stb_rect_pack.h" #include "stb_truetype.h" #include "stb_image_write.h" #include "stb_perlin.h" @@ -16,7 +17,6 @@ #include "stb_divide.h" #include "stb_image.h" #include "stb_herringbone_wang_tile.h" -#include "stb_rect_pack.h" #define STBTE_DRAW_RECT(x0,y0,x1,y1,color) do ; while(0) #define STBTE_DRAW_TILE(x,y,id,highlight,data) do ; while(0) From 00965512d703a5c068d115c1c96e581a0ec28614 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Wed, 10 Dec 2014 00:29:25 -0800 Subject: [PATCH 34/46] update version number --- README.md | 2 +- stb_truetype.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 31108a9..7696853 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ library | lastest version | category | description --------------------- | ---- | -------- | -------------------------------- **stb_vorbis.c** | 1.04 | audio | decode ogg vorbis files from file/memory to float/16-bit signed output **stb_image.h** | 1.46 | graphics | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC -**stb_truetype.h** | 1.01 | graphics | parse, decode, and rasterize characters from truetype fonts +**stb_truetype.h** | 1.02 | graphics | parse, decode, and rasterize characters from truetype fonts **stb_image_write.h** | 0.95 | graphics | image writing to disk: PNG, TGA, BMP **stb_image_resize.h** | 0.90 | graphics | resize images larger/smaller with good quality **stb_rect_pack.h** | 0.05 | graphics | simple 2D rectangle packer with decent quality diff --git a/stb_truetype.h b/stb_truetype.h index 2cf598f..56ef47b 100644 --- a/stb_truetype.h +++ b/stb_truetype.h @@ -1,4 +1,4 @@ -// stb_truetype.h - v1.01 - public domain +// stb_truetype.h - v1.02 - public domain // authored from 2009-2014 by Sean Barrett / RAD Game Tools // // This library processes TrueType files: @@ -40,6 +40,7 @@ // // VERSION HISTORY // +// 1.02 (2014-12-10) fix various warnings & compile issues w/ stb_rect_pack, C++ // 1.01 (2014-12-08) fix subpixel position when oversampling to exactly match // non-oversampled; STBTT_POINT_SIZE for packed case only // 1.00 (2014-12-06) add new PackBegin etc. API, w/ support for oversampling From 61428d4526bccce3e268ac3b1aebce27397b2f42 Mon Sep 17 00:00:00 2001 From: Fabian Giesen Date: Sat, 13 Dec 2014 17:22:57 -0800 Subject: [PATCH 35/46] stb_image: Trivial optimizations for filter path when img_n==out_n. --- stb_image.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/stb_image.h b/stb_image.h index 90d0d15..c365e4d 100644 --- a/stb_image.h +++ b/stb_image.h @@ -2526,12 +2526,13 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r prior += out_n; // this is a little gross, so that we don't switch per-pixel or per-component if (img_n == out_n) { + int nk = (x - 1)*img_n; #define CASE(f) \ case f: \ - for (i=x-1; i >= 1; --i, raw+=img_n,cur+=img_n,prior+=img_n) \ - for (k=0; k < img_n; ++k) + for (k=0; k < nk; ++k) switch (filter) { - CASE(STBI__F_none) cur[k] = raw[k]; break; + // "none" filter turns into a memcpy here; make that explicit. + case STBI__F_none: memcpy(cur, raw, nk); break; CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(raw[k] + cur[k-img_n]); 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] + cur[k-img_n])>>1)); break; @@ -2540,6 +2541,7 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-img_n],0,0)); break; } #undef CASE + raw += nk; } else { STBI_ASSERT(img_n+1 == out_n); #define CASE(f) \ From 8188e842e26236bbf1f33ff20f5bd8c3d6f6e6be Mon Sep 17 00:00:00 2001 From: Fabian Giesen Date: Sat, 13 Dec 2014 17:31:51 -0800 Subject: [PATCH 36/46] stb_image: Add 'static' for some internal funcs, STBIDEF for external ones. --- stb_image.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/stb_image.h b/stb_image.h index c365e4d..ea3f2ca 100644 --- a/stb_image.h +++ b/stb_image.h @@ -584,7 +584,7 @@ static unsigned char *stbi_load_main(stbi__context *s, int *x, int *y, int *comp #ifndef STBI_NO_STDIO -FILE *stbi__fopen(char const *filename, char const *mode) +static FILE *stbi__fopen(char const *filename, char const *mode) { FILE *f; #if defined(_MSC_VER) && _MSC_VER >= 1400 @@ -628,7 +628,7 @@ STBIDEF unsigned char *stbi_load_from_memory(stbi_uc const *buffer, int len, int return stbi_load_main(&s,x,y,comp,req_comp); } -unsigned char *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +STBIDEF unsigned char *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) { stbi__context s; stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); @@ -637,7 +637,7 @@ unsigned char *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *use #ifndef STBI_NO_HDR -float *stbi_loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) +static float *stbi_loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) { unsigned char *data; #ifndef STBI_NO_HDR @@ -650,14 +650,14 @@ float *stbi_loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); } -float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) { stbi__context s; stbi__start_mem(&s,buffer,len); return stbi_loadf_main(&s,x,y,comp,req_comp); } -float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) { stbi__context s; stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); @@ -665,7 +665,7 @@ float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int } #ifndef STBI_NO_STDIO -float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) +STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) { float *result; FILE *f = stbi__fopen(filename, "rb"); @@ -675,7 +675,7 @@ float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) return result; } -float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) { stbi__context s; stbi__start_file(&s,f); From 92b9e262b79dbc27e04487c57f0dfc6335bc993a Mon Sep 17 00:00:00 2001 From: Fabian Giesen Date: Sat, 13 Dec 2014 17:58:36 -0800 Subject: [PATCH 37/46] stb_image: Keep zout in a local var during stbi__parse_huffman_block. --- stb_image.h | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/stb_image.h b/stb_image.h index ea3f2ca..ba9e065 100644 --- a/stb_image.h +++ b/stb_image.h @@ -2146,10 +2146,11 @@ stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) return z->value[b]; } -static int stbi__zexpand(stbi__zbuf *z, int n) // need to make room for n bytes +static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes { char *q; int cur, limit; + z->zout = zout; if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); cur = (int) (z->zout - z->zout_start); limit = (int) (z->zout_end - z->zout_start); @@ -2179,16 +2180,23 @@ static int stbi__zdist_extra[32] = static int stbi__parse_huffman_block(stbi__zbuf *a) { + char *zout = a->zout; for(;;) { int z = stbi__zhuffman_decode(a, &a->z_length); if (z < 256) { if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes - if (a->zout >= a->zout_end) if (!stbi__zexpand(a, 1)) return 0; - *a->zout++ = (char) z; + if (zout >= a->zout_end) { + if (!stbi__zexpand(a, zout, 1)) return 0; + zout = a->zout; + } + *zout++ = (char) z; } else { stbi_uc *p; int len,dist; - if (z == 256) return 1; + if (z == 256) { + a->zout = zout; + return 1; + } z -= 257; len = stbi__zlength_base[z]; if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); @@ -2196,11 +2204,14 @@ static int stbi__parse_huffman_block(stbi__zbuf *a) if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); dist = stbi__zdist_base[z]; if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); - if (a->zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); - if (a->zout + len > a->zout_end) if (!stbi__zexpand(a, len)) return 0; - p = (stbi_uc *) (a->zout - dist); + if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); + if (zout + len > a->zout_end) { + if (!stbi__zexpand(a, zout, len)) return 0; + zout = a->zout; + } + p = (stbi_uc *) (zout - dist); while (len--) - *a->zout++ = *p++; + *zout++ = *p++; } } } @@ -2273,7 +2284,7 @@ static int stbi__parse_uncomperssed_block(stbi__zbuf *a) if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG"); if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG"); if (a->zout + len > a->zout_end) - if (!stbi__zexpand(a, len)) return 0; + if (!stbi__zexpand(a, a->zout, len)) return 0; memcpy(a->zout, a->zbuffer, len); a->zbuffer += len; a->zout += len; From cdc230598e795cd53c5b976402901efe0de268e9 Mon Sep 17 00:00:00 2001 From: Fabian Giesen Date: Sat, 13 Dec 2014 18:07:00 -0800 Subject: [PATCH 38/46] stb_image: Fast path for matches with dist=1 (runs) in stbi__parse_huffman_block. --- stb_image.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/stb_image.h b/stb_image.h index ba9e065..318ea94 100644 --- a/stb_image.h +++ b/stb_image.h @@ -2210,8 +2210,12 @@ static int stbi__parse_huffman_block(stbi__zbuf *a) zout = a->zout; } p = (stbi_uc *) (zout - dist); - while (len--) - *zout++ = *p++; + if (dist == 1) { // run of one byte; common in images. + stbi_uc v = *p; + do *zout++ = v; while (--len); + } else { + do *zout++ = *p++; while (--len); + } } } } From 007de5eb6e22f9a239d5fa25ed3e5a1cecf88d4a Mon Sep 17 00:00:00 2001 From: Fabian Giesen Date: Sat, 13 Dec 2014 18:18:36 -0800 Subject: [PATCH 39/46] stb_image: Extract zhuffman_decode slow path into own function. --- stb_image.h | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/stb_image.h b/stb_image.h index 318ea94..2d955c7 100644 --- a/stb_image.h +++ b/stb_image.h @@ -2119,18 +2119,9 @@ stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) return k; } -stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) +static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) { int b,s,k; - if (a->num_bits < 16) stbi__fill_bits(a); - b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; - if (b < 0xffff) { - s = z->size[b]; - a->code_buffer >>= s; - a->num_bits -= s; - return z->value[b]; - } - // not resolved by fast table, so compute it the slow way // use jpeg approach, which requires MSbits at top k = stbi__bit_reverse(a->code_buffer, 16); @@ -2146,6 +2137,20 @@ stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) return z->value[b]; } +stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s; + if (a->num_bits < 16) stbi__fill_bits(a); + b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; + if (b < 0xffff) { + s = z->size[b]; + a->code_buffer >>= s; + a->num_bits -= s; + return z->value[b]; + } + return stbi__zhuffman_decode_slowpath(a, z); +} + static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes { char *q; From 3d6dccf0c40d81f9d637f2b81d7f9274454bee44 Mon Sep 17 00:00:00 2001 From: Fabian Giesen Date: Sat, 13 Dec 2014 18:48:37 -0800 Subject: [PATCH 40/46] stb_image: Make 'fast' table contain code size and value directly. --- stb_image.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/stb_image.h b/stb_image.h index 2d955c7..e87f059 100644 --- a/stb_image.h +++ b/stb_image.h @@ -2036,7 +2036,7 @@ static int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, int num) // DEFLATE spec for generating codes memset(sizes, 0, sizeof(sizes)); - memset(z->fast, 255, sizeof(z->fast)); + memset(z->fast, 0, sizeof(z->fast)); for (i=0; i < num; ++i) ++sizes[sizelist[i]]; sizes[0] = 0; @@ -2059,12 +2059,13 @@ static int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, int num) int s = sizelist[i]; if (s) { int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; + stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i); z->size [c] = (stbi_uc ) s; z->value[c] = (stbi__uint16) i; if (s <= STBI__ZFAST_BITS) { int k = stbi__bit_reverse(next_code[s],s); while (k < (1 << STBI__ZFAST_BITS)) { - z->fast[k] = (stbi__uint16) c; + z->fast[k] = fastv; k += (1 << s); } } @@ -2142,11 +2143,11 @@ stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) int b,s; if (a->num_bits < 16) stbi__fill_bits(a); b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; - if (b < 0xffff) { - s = z->size[b]; + if (b) { + s = b >> 9; a->code_buffer >>= s; a->num_bits -= s; - return z->value[b]; + return b & 511; } return stbi__zhuffman_decode_slowpath(a, z); } From 1996a019ac13abe20b1010a23c24502a3547b67d Mon Sep 17 00:00:00 2001 From: Fabian Giesen Date: Sat, 13 Dec 2014 19:15:38 -0800 Subject: [PATCH 41/46] stb_image: Guess decoded image size before zlib decode to avoid unnecessary reallocs. --- stb_image.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/stb_image.h b/stb_image.h index e87f059..01cc73a 100644 --- a/stb_image.h +++ b/stb_image.h @@ -2845,7 +2845,9 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) if (first) return stbi__err("first not IHDR", "Corrupt PNG"); if (scan != SCAN_load) return 1; if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG"); - z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, 16384, (int *) &raw_len, !is_iphone); + // initial guess for decoded data size to avoid unnecessary reallocs + raw_len = s->img_x * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; + z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); if (z->expanded == NULL) return 0; // zlib should set error free(z->idata); z->idata = NULL; if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) From 8679ce08b78c96a74f0e0d7efb54b9abac24dda2 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Sat, 13 Dec 2014 23:35:55 -0800 Subject: [PATCH 42/46] fix incorrect img_n variable for interlaced files, caused files to be totally incorrect if forcing channel count --- stb_image.h | 26 +++++++++++++++----------- tests/image_test.c | 26 +++++++++++++++++--------- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/stb_image.h b/stb_image.h index 5ab9c58..771ba15 100644 --- a/stb_image.h +++ b/stb_image.h @@ -2530,9 +2530,9 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r else { // 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 - in = line8; - stbi_uc* decode_out = line8; + stbi_uc * decode_out = line8; stbi_uc scale = (color == 0) ? 0xFF/((1<= 1; k-=2, raw++) { *decode_out++ = scale * ((*raw >> 4) ); @@ -2617,12 +2617,12 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r return 1; } -static int stbi__create_png_image(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, int depth, int color, int interlaced) +static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) { stbi_uc *final; int p; if (!interlaced) - return stbi__create_png_image_raw(a, raw, raw_len, out_n, a->s->img_x, a->s->img_y, depth, color); + return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); // de-interlacing final = (stbi_uc *) stbi__malloc(a->s->img_x * a->s->img_y * out_n); @@ -2636,18 +2636,22 @@ static int stbi__create_png_image(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_l x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; if (x && y) { - stbi__uint32 img_len = ((((out_n * x * depth) + 7) >> 3) + 1) * y; - if (!stbi__create_png_image_raw(a, raw, raw_len, out_n, x, y, depth, color)) { + stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; + if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { free(final); return 0; } - for (j=0; j < y; ++j) - for (i=0; i < x; ++i) - memcpy(final + (j*yspc[p]+yorig[p])*a->s->img_x*out_n + (i*xspc[p]+xorig[p])*out_n, + for (j=0; j < y; ++j) { + for (i=0; i < x; ++i) { + int out_y = j*yspc[p]+yorig[p]; + int out_x = i*xspc[p]+xorig[p]; + memcpy(final + out_y*a->s->img_x*out_n + out_x*out_n, a->out + (j*x+i)*out_n, out_n); + } + } free(a->out); - raw += img_len; - raw_len -= img_len; + image_data += img_len; + image_data_len -= img_len; } } a->out = final; diff --git a/tests/image_test.c b/tests/image_test.c index c17c766..47c5c68 100644 --- a/tests/image_test.c +++ b/tests/image_test.c @@ -32,24 +32,32 @@ int main(int argc, char **argv) } } else { int i; - char **files = stb_readdir_files("images"); + char **files = stb_readdir_files("pngsuite/part1"); for (i=0; i < stb_arr_len(files); ++i) { int n; + char **failed = NULL; unsigned char *data; - printf("%s\n", files[i]); - data = stbi_load(files[i], &w, &h, &n, 4); if (data) free(data); else printf("Failed &n\n"); - data = stbi_load(files[i], &w, &h, 0, 1); if (data) free(data); else printf("Failed 1\n"); - data = stbi_load(files[i], &w, &h, 0, 2); if (data) free(data); else printf("Failed 2\n"); - data = stbi_load(files[i], &w, &h, 0, 3); if (data) free(data); else printf("Failed 3\n"); - data = stbi_load(files[i], &w, &h, 0, 4); + //printf("%s\n", files[i]); + data = stbi_load(files[i], &w, &h, &n, 0); if (data) free(data); else stb_arr_push(failed, "&n"); + data = stbi_load(files[i], &w, &h, 0, 1); if (data) free(data); else stb_arr_push(failed, "1"); + data = stbi_load(files[i], &w, &h, 0, 2); if (data) free(data); else stb_arr_push(failed, "2"); + data = stbi_load(files[i], &w, &h, 0, 3); if (data) free(data); else stb_arr_push(failed, "3"); + data = stbi_load(files[i], &w, &h, 0, 4); if (data) ; else stb_arr_push(failed, "4"); if (data) { char fname[512]; stb_splitpath(fname, files[i], STB_FILE); stbi_write_png(stb_sprintf("output/%s.png", fname), w, h, 4, data, w*4); free(data); - } else - printf("FAILED\n"); + } + if (failed) { + int j; + printf("FAILED: "); + for (j=0; j < stb_arr_len(failed); ++j) + printf("%s ", failed[j]); + printf(" -- %s\n", files[i]); + } } + printf("Tested %d files\n", i); } return 0; } From 01d2c9d957dbca3ca2899ebc0677cbfe62a73c99 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Sun, 14 Dec 2014 00:01:50 -0800 Subject: [PATCH 43/46] test program now verifies pngsuite tests against refererence versions --- tests/image_test.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/tests/image_test.c b/tests/image_test.c index 47c5c68..c1115f4 100644 --- a/tests/image_test.c +++ b/tests/image_test.c @@ -7,6 +7,8 @@ #define STB_DEFINE #include "stb.h" +#define PART1 + int main(int argc, char **argv) { int w,h; @@ -31,8 +33,12 @@ int main(int argc, char **argv) printf("FAILED 4\n"); } } else { - int i; + int i, nope=0; + #ifdef PART1 char **files = stb_readdir_files("pngsuite/part1"); + #else + char **files = stb_readdir_files("images"); + #endif for (i=0; i < stb_arr_len(files); ++i) { int n; char **failed = NULL; @@ -45,8 +51,24 @@ int main(int argc, char **argv) data = stbi_load(files[i], &w, &h, 0, 4); if (data) ; else stb_arr_push(failed, "4"); if (data) { char fname[512]; + + #ifdef PART1 + int w2,h2; + unsigned char *data2; + stb_splitpath(fname, files[i], STB_FILE_EXT); + data2 = stbi_load(stb_sprintf("pngsuite/part1_check/%s", fname), &w2, &h2, 0, 4); + if (!data2) + printf("FAILED: couldn't load 'pngsuite/part1_check/%s\n", fname); + else { + if (w != w2 || h != w2 || 0 != memcmp(data, data2, w*h*4)) { + printf("FAILED: %s loaded but didn't match part1_check 32-bit version\n", files[i]); + } + free(data2); + } + #else stb_splitpath(fname, files[i], STB_FILE); stbi_write_png(stb_sprintf("output/%s.png", fname), w, h, 4, data, w*4); + #endif free(data); } if (failed) { @@ -57,7 +79,7 @@ int main(int argc, char **argv) printf(" -- %s\n", files[i]); } } - printf("Tested %d files\n", i); + printf("Tested %d files.\n", i); } return 0; } From 8ac015c03fc427eed8e9d5fed0a66620881d9f91 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Sun, 14 Dec 2014 01:43:23 -0800 Subject: [PATCH 44/46] fix 1/2/4-bit png to filter bytes before decoding to pixels; rename pngsuite/part1 to pngsuite/primary; check in pngsuite --- stb_image.h | 211 ++++++++++++++-------- tests/image_test.c | 22 ++- tests/pngsuite/16bit/basi0g16.png | Bin 0 -> 299 bytes tests/pngsuite/16bit/basi2c16.png | Bin 0 -> 595 bytes tests/pngsuite/16bit/basi4a16.png | Bin 0 -> 2855 bytes tests/pngsuite/16bit/basi6a16.png | Bin 0 -> 4180 bytes tests/pngsuite/16bit/basn0g16.png | Bin 0 -> 167 bytes tests/pngsuite/16bit/basn2c16.png | Bin 0 -> 302 bytes tests/pngsuite/16bit/basn4a16.png | Bin 0 -> 2206 bytes tests/pngsuite/16bit/basn6a16.png | Bin 0 -> 3435 bytes tests/pngsuite/16bit/bgai4a16.png | Bin 0 -> 2855 bytes tests/pngsuite/16bit/bgan6a16.png | Bin 0 -> 3435 bytes tests/pngsuite/16bit/bggn4a16.png | Bin 0 -> 2220 bytes tests/pngsuite/16bit/bgyn6a16.png | Bin 0 -> 3453 bytes tests/pngsuite/16bit/oi1n0g16.png | Bin 0 -> 167 bytes tests/pngsuite/16bit/oi1n2c16.png | Bin 0 -> 302 bytes tests/pngsuite/16bit/oi2n0g16.png | Bin 0 -> 179 bytes tests/pngsuite/16bit/oi2n2c16.png | Bin 0 -> 314 bytes tests/pngsuite/16bit/oi4n0g16.png | Bin 0 -> 203 bytes tests/pngsuite/16bit/oi4n2c16.png | Bin 0 -> 338 bytes tests/pngsuite/16bit/oi9n0g16.png | Bin 0 -> 1283 bytes tests/pngsuite/16bit/oi9n2c16.png | Bin 0 -> 3038 bytes tests/pngsuite/16bit/tbbn2c16.png | Bin 0 -> 2041 bytes tests/pngsuite/16bit/tbgn2c16.png | Bin 0 -> 2041 bytes tests/pngsuite/16bit/tbwn0g16.png | Bin 0 -> 1313 bytes tests/pngsuite/PngSuite.LICENSE | 9 + tests/pngsuite/corrupt/xc1n0g08.png | Bin 0 -> 138 bytes tests/pngsuite/corrupt/xc9n2c08.png | Bin 0 -> 145 bytes tests/pngsuite/corrupt/xcrn0g04.png | Bin 0 -> 145 bytes tests/pngsuite/corrupt/xcsn0g01.png | Bin 0 -> 164 bytes tests/pngsuite/corrupt/xd0n2c08.png | Bin 0 -> 145 bytes tests/pngsuite/corrupt/xd3n2c08.png | Bin 0 -> 145 bytes tests/pngsuite/corrupt/xd9n2c08.png | Bin 0 -> 145 bytes tests/pngsuite/corrupt/xdtn0g01.png | Bin 0 -> 61 bytes tests/pngsuite/corrupt/xhdn0g08.png | Bin 0 -> 138 bytes tests/pngsuite/corrupt/xlfn0g04.png | Bin 0 -> 145 bytes tests/pngsuite/corrupt/xs1n0g01.png | Bin 0 -> 164 bytes tests/pngsuite/corrupt/xs2n0g01.png | Bin 0 -> 164 bytes tests/pngsuite/corrupt/xs4n0g01.png | Bin 0 -> 164 bytes tests/pngsuite/corrupt/xs7n0g01.png | Bin 0 -> 164 bytes tests/pngsuite/primary/basi0g01.png | Bin 0 -> 217 bytes tests/pngsuite/primary/basi0g02.png | Bin 0 -> 154 bytes tests/pngsuite/primary/basi0g04.png | Bin 0 -> 247 bytes tests/pngsuite/primary/basi0g08.png | Bin 0 -> 254 bytes tests/pngsuite/primary/basi2c08.png | Bin 0 -> 315 bytes tests/pngsuite/primary/basi3p01.png | Bin 0 -> 132 bytes tests/pngsuite/primary/basi3p02.png | Bin 0 -> 193 bytes tests/pngsuite/primary/basi3p04.png | Bin 0 -> 327 bytes tests/pngsuite/primary/basi3p08.png | Bin 0 -> 1527 bytes tests/pngsuite/primary/basi4a08.png | Bin 0 -> 214 bytes tests/pngsuite/primary/basi6a08.png | Bin 0 -> 361 bytes tests/pngsuite/primary/basn0g01.png | Bin 0 -> 164 bytes tests/pngsuite/primary/basn0g02.png | Bin 0 -> 104 bytes tests/pngsuite/primary/basn0g04.png | Bin 0 -> 145 bytes tests/pngsuite/primary/basn0g08.png | Bin 0 -> 138 bytes tests/pngsuite/primary/basn2c08.png | Bin 0 -> 145 bytes tests/pngsuite/primary/basn3p01.png | Bin 0 -> 112 bytes tests/pngsuite/primary/basn3p02.png | Bin 0 -> 146 bytes tests/pngsuite/primary/basn3p04.png | Bin 0 -> 216 bytes tests/pngsuite/primary/basn3p08.png | Bin 0 -> 1286 bytes tests/pngsuite/primary/basn4a08.png | Bin 0 -> 126 bytes tests/pngsuite/primary/basn6a08.png | Bin 0 -> 184 bytes tests/pngsuite/primary/bgai4a08.png | Bin 0 -> 214 bytes tests/pngsuite/primary/bgan6a08.png | Bin 0 -> 184 bytes tests/pngsuite/primary/bgbn4a08.png | Bin 0 -> 140 bytes tests/pngsuite/primary/bgwn6a08.png | Bin 0 -> 202 bytes tests/pngsuite/primary/s01i3p01.png | Bin 0 -> 113 bytes tests/pngsuite/primary/s01n3p01.png | Bin 0 -> 113 bytes tests/pngsuite/primary/s02i3p01.png | Bin 0 -> 114 bytes tests/pngsuite/primary/s02n3p01.png | Bin 0 -> 115 bytes tests/pngsuite/primary/s03i3p01.png | Bin 0 -> 118 bytes tests/pngsuite/primary/s03n3p01.png | Bin 0 -> 120 bytes tests/pngsuite/primary/s04i3p01.png | Bin 0 -> 126 bytes tests/pngsuite/primary/s04n3p01.png | Bin 0 -> 121 bytes tests/pngsuite/primary/s05i3p02.png | Bin 0 -> 134 bytes tests/pngsuite/primary/s05n3p02.png | Bin 0 -> 129 bytes tests/pngsuite/primary/s06i3p02.png | Bin 0 -> 143 bytes tests/pngsuite/primary/s06n3p02.png | Bin 0 -> 131 bytes tests/pngsuite/primary/s07i3p02.png | Bin 0 -> 149 bytes tests/pngsuite/primary/s07n3p02.png | Bin 0 -> 138 bytes tests/pngsuite/primary/s08i3p02.png | Bin 0 -> 149 bytes tests/pngsuite/primary/s08n3p02.png | Bin 0 -> 139 bytes tests/pngsuite/primary/s09i3p02.png | Bin 0 -> 147 bytes tests/pngsuite/primary/s09n3p02.png | Bin 0 -> 143 bytes tests/pngsuite/primary/s32i3p04.png | Bin 0 -> 355 bytes tests/pngsuite/primary/s32n3p04.png | Bin 0 -> 263 bytes tests/pngsuite/primary/s33i3p04.png | Bin 0 -> 385 bytes tests/pngsuite/primary/s33n3p04.png | Bin 0 -> 329 bytes tests/pngsuite/primary/s34i3p04.png | Bin 0 -> 349 bytes tests/pngsuite/primary/s34n3p04.png | Bin 0 -> 248 bytes tests/pngsuite/primary/s35i3p04.png | Bin 0 -> 399 bytes tests/pngsuite/primary/s35n3p04.png | Bin 0 -> 338 bytes tests/pngsuite/primary/s36i3p04.png | Bin 0 -> 356 bytes tests/pngsuite/primary/s36n3p04.png | Bin 0 -> 258 bytes tests/pngsuite/primary/s37i3p04.png | Bin 0 -> 393 bytes tests/pngsuite/primary/s37n3p04.png | Bin 0 -> 336 bytes tests/pngsuite/primary/s38i3p04.png | Bin 0 -> 357 bytes tests/pngsuite/primary/s38n3p04.png | Bin 0 -> 245 bytes tests/pngsuite/primary/s39i3p04.png | Bin 0 -> 420 bytes tests/pngsuite/primary/s39n3p04.png | Bin 0 -> 352 bytes tests/pngsuite/primary/s40i3p04.png | Bin 0 -> 357 bytes tests/pngsuite/primary/s40n3p04.png | Bin 0 -> 256 bytes tests/pngsuite/primary/tbbn0g04.png | Bin 0 -> 429 bytes tests/pngsuite/primary/tbbn3p08.png | Bin 0 -> 1499 bytes tests/pngsuite/primary/tbgn3p08.png | Bin 0 -> 1499 bytes tests/pngsuite/primary/tbrn2c08.png | Bin 0 -> 1633 bytes tests/pngsuite/primary/tbwn3p08.png | Bin 0 -> 1496 bytes tests/pngsuite/primary/tbyn3p08.png | Bin 0 -> 1499 bytes tests/pngsuite/primary/tm3n3p02.png | Bin 0 -> 116 bytes tests/pngsuite/primary/tp0n0g08.png | Bin 0 -> 719 bytes tests/pngsuite/primary/tp0n2c08.png | Bin 0 -> 1594 bytes tests/pngsuite/primary/tp0n3p08.png | Bin 0 -> 1476 bytes tests/pngsuite/primary/tp1n3p08.png | Bin 0 -> 1483 bytes tests/pngsuite/primary/z00n2c08.png | Bin 0 -> 3172 bytes tests/pngsuite/primary/z03n2c08.png | Bin 0 -> 232 bytes tests/pngsuite/primary/z06n2c08.png | Bin 0 -> 224 bytes tests/pngsuite/primary/z09n2c08.png | Bin 0 -> 224 bytes tests/pngsuite/primary_check/basi0g01.png | Bin 0 -> 391 bytes tests/pngsuite/primary_check/basi0g02.png | Bin 0 -> 283 bytes tests/pngsuite/primary_check/basi0g04.png | Bin 0 -> 252 bytes tests/pngsuite/primary_check/basi0g08.png | Bin 0 -> 293 bytes tests/pngsuite/primary_check/basi2c08.png | Bin 0 -> 274 bytes tests/pngsuite/primary_check/basi3p01.png | Bin 0 -> 273 bytes tests/pngsuite/primary_check/basi3p02.png | Bin 0 -> 286 bytes tests/pngsuite/primary_check/basi3p04.png | Bin 0 -> 331 bytes tests/pngsuite/primary_check/basi3p08.png | Bin 0 -> 387 bytes tests/pngsuite/primary_check/basi4a08.png | Bin 0 -> 263 bytes tests/pngsuite/primary_check/basi6a08.png | Bin 0 -> 298 bytes tests/pngsuite/primary_check/basn0g01.png | Bin 0 -> 391 bytes tests/pngsuite/primary_check/basn0g02.png | Bin 0 -> 283 bytes tests/pngsuite/primary_check/basn0g04.png | Bin 0 -> 252 bytes tests/pngsuite/primary_check/basn0g08.png | Bin 0 -> 293 bytes tests/pngsuite/primary_check/basn2c08.png | Bin 0 -> 274 bytes tests/pngsuite/primary_check/basn3p01.png | Bin 0 -> 273 bytes tests/pngsuite/primary_check/basn3p02.png | Bin 0 -> 286 bytes tests/pngsuite/primary_check/basn3p04.png | Bin 0 -> 331 bytes tests/pngsuite/primary_check/basn3p08.png | Bin 0 -> 387 bytes tests/pngsuite/primary_check/basn4a08.png | Bin 0 -> 263 bytes tests/pngsuite/primary_check/basn6a08.png | Bin 0 -> 298 bytes tests/pngsuite/primary_check/bgai4a08.png | Bin 0 -> 263 bytes tests/pngsuite/primary_check/bgan6a08.png | Bin 0 -> 298 bytes tests/pngsuite/primary_check/bgbn4a08.png | Bin 0 -> 263 bytes tests/pngsuite/primary_check/bgwn6a08.png | Bin 0 -> 298 bytes tests/pngsuite/primary_check/s01i3p01.png | Bin 0 -> 202 bytes tests/pngsuite/primary_check/s01n3p01.png | Bin 0 -> 202 bytes tests/pngsuite/primary_check/s02i3p01.png | Bin 0 -> 210 bytes tests/pngsuite/primary_check/s02n3p01.png | Bin 0 -> 210 bytes tests/pngsuite/primary_check/s03i3p01.png | Bin 0 -> 216 bytes tests/pngsuite/primary_check/s03n3p01.png | Bin 0 -> 216 bytes tests/pngsuite/primary_check/s04i3p01.png | Bin 0 -> 221 bytes tests/pngsuite/primary_check/s04n3p01.png | Bin 0 -> 221 bytes tests/pngsuite/primary_check/s05i3p02.png | Bin 0 -> 232 bytes tests/pngsuite/primary_check/s05n3p02.png | Bin 0 -> 232 bytes tests/pngsuite/primary_check/s06i3p02.png | Bin 0 -> 239 bytes tests/pngsuite/primary_check/s06n3p02.png | Bin 0 -> 239 bytes tests/pngsuite/primary_check/s07i3p02.png | Bin 0 -> 249 bytes tests/pngsuite/primary_check/s07n3p02.png | Bin 0 -> 249 bytes tests/pngsuite/primary_check/s08i3p02.png | Bin 0 -> 255 bytes tests/pngsuite/primary_check/s08n3p02.png | Bin 0 -> 255 bytes tests/pngsuite/primary_check/s09i3p02.png | Bin 0 -> 263 bytes tests/pngsuite/primary_check/s09n3p02.png | Bin 0 -> 263 bytes tests/pngsuite/primary_check/s32i3p04.png | Bin 0 -> 441 bytes tests/pngsuite/primary_check/s32n3p04.png | Bin 0 -> 441 bytes tests/pngsuite/primary_check/s33i3p04.png | Bin 0 -> 470 bytes tests/pngsuite/primary_check/s33n3p04.png | Bin 0 -> 470 bytes tests/pngsuite/primary_check/s34i3p04.png | Bin 0 -> 431 bytes tests/pngsuite/primary_check/s34n3p04.png | Bin 0 -> 431 bytes tests/pngsuite/primary_check/s35i3p04.png | Bin 0 -> 477 bytes tests/pngsuite/primary_check/s35n3p04.png | Bin 0 -> 477 bytes tests/pngsuite/primary_check/s36i3p04.png | Bin 0 -> 448 bytes tests/pngsuite/primary_check/s36n3p04.png | Bin 0 -> 448 bytes tests/pngsuite/primary_check/s37i3p04.png | Bin 0 -> 478 bytes tests/pngsuite/primary_check/s37n3p04.png | Bin 0 -> 478 bytes tests/pngsuite/primary_check/s38i3p04.png | Bin 0 -> 439 bytes tests/pngsuite/primary_check/s38n3p04.png | Bin 0 -> 439 bytes tests/pngsuite/primary_check/s39i3p04.png | Bin 0 -> 499 bytes tests/pngsuite/primary_check/s39n3p04.png | Bin 0 -> 499 bytes tests/pngsuite/primary_check/s40i3p04.png | Bin 0 -> 463 bytes tests/pngsuite/primary_check/s40n3p04.png | Bin 0 -> 463 bytes tests/pngsuite/primary_check/tbbn0g04.png | Bin 0 -> 762 bytes tests/pngsuite/primary_check/tbbn3p08.png | Bin 0 -> 1911 bytes tests/pngsuite/primary_check/tbgn3p08.png | Bin 0 -> 1911 bytes tests/pngsuite/primary_check/tbrn2c08.png | Bin 0 -> 1901 bytes tests/pngsuite/primary_check/tbwn3p08.png | Bin 0 -> 1911 bytes tests/pngsuite/primary_check/tbyn3p08.png | Bin 0 -> 1911 bytes tests/pngsuite/primary_check/tm3n3p02.png | Bin 0 -> 306 bytes tests/pngsuite/primary_check/tp0n0g08.png | Bin 0 -> 1802 bytes tests/pngsuite/primary_check/tp0n2c08.png | Bin 0 -> 1955 bytes tests/pngsuite/primary_check/tp0n3p08.png | Bin 0 -> 1959 bytes tests/pngsuite/primary_check/tp1n3p08.png | Bin 0 -> 1911 bytes tests/pngsuite/primary_check/z00n2c08.png | Bin 0 -> 422 bytes tests/pngsuite/primary_check/z03n2c08.png | Bin 0 -> 422 bytes tests/pngsuite/primary_check/z06n2c08.png | Bin 0 -> 422 bytes tests/pngsuite/primary_check/z09n2c08.png | Bin 0 -> 422 bytes tests/pngsuite/unused/ccwn2c08.png | Bin 0 -> 1514 bytes tests/pngsuite/unused/ccwn3p08.png | Bin 0 -> 1554 bytes tests/pngsuite/unused/cdfn2c08.png | Bin 0 -> 404 bytes tests/pngsuite/unused/cdhn2c08.png | Bin 0 -> 344 bytes tests/pngsuite/unused/cdsn2c08.png | Bin 0 -> 232 bytes tests/pngsuite/unused/cdun2c08.png | Bin 0 -> 724 bytes tests/pngsuite/unused/ch1n3p04.png | Bin 0 -> 258 bytes tests/pngsuite/unused/ch2n3p08.png | Bin 0 -> 1810 bytes tests/pngsuite/unused/cm0n0g04.png | Bin 0 -> 292 bytes tests/pngsuite/unused/cm7n0g04.png | Bin 0 -> 292 bytes tests/pngsuite/unused/cm9n0g04.png | Bin 0 -> 292 bytes tests/pngsuite/unused/cs3n2c16.png | Bin 0 -> 214 bytes tests/pngsuite/unused/cs3n3p08.png | Bin 0 -> 259 bytes tests/pngsuite/unused/cs5n2c08.png | Bin 0 -> 186 bytes tests/pngsuite/unused/cs5n3p08.png | Bin 0 -> 271 bytes tests/pngsuite/unused/cs8n2c08.png | Bin 0 -> 149 bytes tests/pngsuite/unused/cs8n3p08.png | Bin 0 -> 256 bytes tests/pngsuite/unused/ct0n0g04.png | Bin 0 -> 273 bytes tests/pngsuite/unused/ct1n0g04.png | Bin 0 -> 792 bytes tests/pngsuite/unused/cten0g04.png | Bin 0 -> 742 bytes tests/pngsuite/unused/ctfn0g04.png | Bin 0 -> 716 bytes tests/pngsuite/unused/ctgn0g04.png | Bin 0 -> 1182 bytes tests/pngsuite/unused/cthn0g04.png | Bin 0 -> 1269 bytes tests/pngsuite/unused/ctjn0g04.png | Bin 0 -> 941 bytes tests/pngsuite/unused/ctzn0g04.png | Bin 0 -> 753 bytes tests/pngsuite/unused/f00n0g08.png | Bin 0 -> 319 bytes tests/pngsuite/unused/f00n2c08.png | Bin 0 -> 2475 bytes tests/pngsuite/unused/f01n0g08.png | Bin 0 -> 321 bytes tests/pngsuite/unused/f01n2c08.png | Bin 0 -> 1180 bytes tests/pngsuite/unused/f02n0g08.png | Bin 0 -> 355 bytes tests/pngsuite/unused/f02n2c08.png | Bin 0 -> 1729 bytes tests/pngsuite/unused/f03n0g08.png | Bin 0 -> 389 bytes tests/pngsuite/unused/f03n2c08.png | Bin 0 -> 1291 bytes tests/pngsuite/unused/f04n0g08.png | Bin 0 -> 269 bytes tests/pngsuite/unused/f04n2c08.png | Bin 0 -> 985 bytes tests/pngsuite/unused/f99n0g04.png | Bin 0 -> 426 bytes tests/pngsuite/unused/g03n0g16.png | Bin 0 -> 345 bytes tests/pngsuite/unused/g03n2c08.png | Bin 0 -> 370 bytes tests/pngsuite/unused/g03n3p04.png | Bin 0 -> 214 bytes tests/pngsuite/unused/g04n0g16.png | Bin 0 -> 363 bytes tests/pngsuite/unused/g04n2c08.png | Bin 0 -> 377 bytes tests/pngsuite/unused/g04n3p04.png | Bin 0 -> 219 bytes tests/pngsuite/unused/g05n0g16.png | Bin 0 -> 339 bytes tests/pngsuite/unused/g05n2c08.png | Bin 0 -> 350 bytes tests/pngsuite/unused/g05n3p04.png | Bin 0 -> 206 bytes tests/pngsuite/unused/g07n0g16.png | Bin 0 -> 321 bytes tests/pngsuite/unused/g07n2c08.png | Bin 0 -> 340 bytes tests/pngsuite/unused/g07n3p04.png | Bin 0 -> 207 bytes tests/pngsuite/unused/g10n0g16.png | Bin 0 -> 262 bytes tests/pngsuite/unused/g10n2c08.png | Bin 0 -> 285 bytes tests/pngsuite/unused/g10n3p04.png | Bin 0 -> 214 bytes tests/pngsuite/unused/g25n0g16.png | Bin 0 -> 383 bytes tests/pngsuite/unused/g25n2c08.png | Bin 0 -> 405 bytes tests/pngsuite/unused/g25n3p04.png | Bin 0 -> 215 bytes tests/pngsuite/unused/pp0n2c16.png | Bin 0 -> 962 bytes tests/pngsuite/unused/pp0n6a08.png | Bin 0 -> 818 bytes tests/pngsuite/unused/ps1n0g08.png | Bin 0 -> 1456 bytes tests/pngsuite/unused/ps1n2c16.png | Bin 0 -> 1620 bytes tests/pngsuite/unused/ps2n0g08.png | Bin 0 -> 2320 bytes tests/pngsuite/unused/ps2n2c16.png | Bin 0 -> 2484 bytes 254 files changed, 154 insertions(+), 88 deletions(-) create mode 100644 tests/pngsuite/16bit/basi0g16.png create mode 100644 tests/pngsuite/16bit/basi2c16.png create mode 100644 tests/pngsuite/16bit/basi4a16.png create mode 100644 tests/pngsuite/16bit/basi6a16.png create mode 100644 tests/pngsuite/16bit/basn0g16.png create mode 100644 tests/pngsuite/16bit/basn2c16.png create mode 100644 tests/pngsuite/16bit/basn4a16.png create mode 100644 tests/pngsuite/16bit/basn6a16.png create mode 100644 tests/pngsuite/16bit/bgai4a16.png create mode 100644 tests/pngsuite/16bit/bgan6a16.png create mode 100644 tests/pngsuite/16bit/bggn4a16.png create mode 100644 tests/pngsuite/16bit/bgyn6a16.png create mode 100644 tests/pngsuite/16bit/oi1n0g16.png create mode 100644 tests/pngsuite/16bit/oi1n2c16.png create mode 100644 tests/pngsuite/16bit/oi2n0g16.png create mode 100644 tests/pngsuite/16bit/oi2n2c16.png create mode 100644 tests/pngsuite/16bit/oi4n0g16.png create mode 100644 tests/pngsuite/16bit/oi4n2c16.png create mode 100644 tests/pngsuite/16bit/oi9n0g16.png create mode 100644 tests/pngsuite/16bit/oi9n2c16.png create mode 100644 tests/pngsuite/16bit/tbbn2c16.png create mode 100644 tests/pngsuite/16bit/tbgn2c16.png create mode 100644 tests/pngsuite/16bit/tbwn0g16.png create mode 100644 tests/pngsuite/PngSuite.LICENSE create mode 100644 tests/pngsuite/corrupt/xc1n0g08.png create mode 100644 tests/pngsuite/corrupt/xc9n2c08.png create mode 100644 tests/pngsuite/corrupt/xcrn0g04.png create mode 100644 tests/pngsuite/corrupt/xcsn0g01.png create mode 100644 tests/pngsuite/corrupt/xd0n2c08.png create mode 100644 tests/pngsuite/corrupt/xd3n2c08.png create mode 100644 tests/pngsuite/corrupt/xd9n2c08.png create mode 100644 tests/pngsuite/corrupt/xdtn0g01.png create mode 100644 tests/pngsuite/corrupt/xhdn0g08.png create mode 100644 tests/pngsuite/corrupt/xlfn0g04.png create mode 100644 tests/pngsuite/corrupt/xs1n0g01.png create mode 100644 tests/pngsuite/corrupt/xs2n0g01.png create mode 100644 tests/pngsuite/corrupt/xs4n0g01.png create mode 100644 tests/pngsuite/corrupt/xs7n0g01.png create mode 100644 tests/pngsuite/primary/basi0g01.png create mode 100644 tests/pngsuite/primary/basi0g02.png create mode 100644 tests/pngsuite/primary/basi0g04.png create mode 100644 tests/pngsuite/primary/basi0g08.png create mode 100644 tests/pngsuite/primary/basi2c08.png create mode 100644 tests/pngsuite/primary/basi3p01.png create mode 100644 tests/pngsuite/primary/basi3p02.png create mode 100644 tests/pngsuite/primary/basi3p04.png create mode 100644 tests/pngsuite/primary/basi3p08.png create mode 100644 tests/pngsuite/primary/basi4a08.png create mode 100644 tests/pngsuite/primary/basi6a08.png create mode 100644 tests/pngsuite/primary/basn0g01.png create mode 100644 tests/pngsuite/primary/basn0g02.png create mode 100644 tests/pngsuite/primary/basn0g04.png create mode 100644 tests/pngsuite/primary/basn0g08.png create mode 100644 tests/pngsuite/primary/basn2c08.png create mode 100644 tests/pngsuite/primary/basn3p01.png create mode 100644 tests/pngsuite/primary/basn3p02.png create mode 100644 tests/pngsuite/primary/basn3p04.png create mode 100644 tests/pngsuite/primary/basn3p08.png create mode 100644 tests/pngsuite/primary/basn4a08.png create mode 100644 tests/pngsuite/primary/basn6a08.png create mode 100644 tests/pngsuite/primary/bgai4a08.png create mode 100644 tests/pngsuite/primary/bgan6a08.png create mode 100644 tests/pngsuite/primary/bgbn4a08.png create mode 100644 tests/pngsuite/primary/bgwn6a08.png create mode 100644 tests/pngsuite/primary/s01i3p01.png create mode 100644 tests/pngsuite/primary/s01n3p01.png create mode 100644 tests/pngsuite/primary/s02i3p01.png create mode 100644 tests/pngsuite/primary/s02n3p01.png create mode 100644 tests/pngsuite/primary/s03i3p01.png create mode 100644 tests/pngsuite/primary/s03n3p01.png create mode 100644 tests/pngsuite/primary/s04i3p01.png create mode 100644 tests/pngsuite/primary/s04n3p01.png create mode 100644 tests/pngsuite/primary/s05i3p02.png create mode 100644 tests/pngsuite/primary/s05n3p02.png create mode 100644 tests/pngsuite/primary/s06i3p02.png create mode 100644 tests/pngsuite/primary/s06n3p02.png create mode 100644 tests/pngsuite/primary/s07i3p02.png create mode 100644 tests/pngsuite/primary/s07n3p02.png create mode 100644 tests/pngsuite/primary/s08i3p02.png create mode 100644 tests/pngsuite/primary/s08n3p02.png create mode 100644 tests/pngsuite/primary/s09i3p02.png create mode 100644 tests/pngsuite/primary/s09n3p02.png create mode 100644 tests/pngsuite/primary/s32i3p04.png create mode 100644 tests/pngsuite/primary/s32n3p04.png create mode 100644 tests/pngsuite/primary/s33i3p04.png create mode 100644 tests/pngsuite/primary/s33n3p04.png create mode 100644 tests/pngsuite/primary/s34i3p04.png create mode 100644 tests/pngsuite/primary/s34n3p04.png create mode 100644 tests/pngsuite/primary/s35i3p04.png create mode 100644 tests/pngsuite/primary/s35n3p04.png create mode 100644 tests/pngsuite/primary/s36i3p04.png create mode 100644 tests/pngsuite/primary/s36n3p04.png create mode 100644 tests/pngsuite/primary/s37i3p04.png create mode 100644 tests/pngsuite/primary/s37n3p04.png create mode 100644 tests/pngsuite/primary/s38i3p04.png create mode 100644 tests/pngsuite/primary/s38n3p04.png create mode 100644 tests/pngsuite/primary/s39i3p04.png create mode 100644 tests/pngsuite/primary/s39n3p04.png create mode 100644 tests/pngsuite/primary/s40i3p04.png create mode 100644 tests/pngsuite/primary/s40n3p04.png create mode 100644 tests/pngsuite/primary/tbbn0g04.png create mode 100644 tests/pngsuite/primary/tbbn3p08.png create mode 100644 tests/pngsuite/primary/tbgn3p08.png create mode 100644 tests/pngsuite/primary/tbrn2c08.png create mode 100644 tests/pngsuite/primary/tbwn3p08.png create mode 100644 tests/pngsuite/primary/tbyn3p08.png create mode 100644 tests/pngsuite/primary/tm3n3p02.png create mode 100644 tests/pngsuite/primary/tp0n0g08.png create mode 100644 tests/pngsuite/primary/tp0n2c08.png create mode 100644 tests/pngsuite/primary/tp0n3p08.png create mode 100644 tests/pngsuite/primary/tp1n3p08.png create mode 100644 tests/pngsuite/primary/z00n2c08.png create mode 100644 tests/pngsuite/primary/z03n2c08.png create mode 100644 tests/pngsuite/primary/z06n2c08.png create mode 100644 tests/pngsuite/primary/z09n2c08.png create mode 100644 tests/pngsuite/primary_check/basi0g01.png create mode 100644 tests/pngsuite/primary_check/basi0g02.png create mode 100644 tests/pngsuite/primary_check/basi0g04.png create mode 100644 tests/pngsuite/primary_check/basi0g08.png create mode 100644 tests/pngsuite/primary_check/basi2c08.png create mode 100644 tests/pngsuite/primary_check/basi3p01.png create mode 100644 tests/pngsuite/primary_check/basi3p02.png create mode 100644 tests/pngsuite/primary_check/basi3p04.png create mode 100644 tests/pngsuite/primary_check/basi3p08.png create mode 100644 tests/pngsuite/primary_check/basi4a08.png create mode 100644 tests/pngsuite/primary_check/basi6a08.png create mode 100644 tests/pngsuite/primary_check/basn0g01.png create mode 100644 tests/pngsuite/primary_check/basn0g02.png create mode 100644 tests/pngsuite/primary_check/basn0g04.png create mode 100644 tests/pngsuite/primary_check/basn0g08.png create mode 100644 tests/pngsuite/primary_check/basn2c08.png create mode 100644 tests/pngsuite/primary_check/basn3p01.png create mode 100644 tests/pngsuite/primary_check/basn3p02.png create mode 100644 tests/pngsuite/primary_check/basn3p04.png create mode 100644 tests/pngsuite/primary_check/basn3p08.png create mode 100644 tests/pngsuite/primary_check/basn4a08.png create mode 100644 tests/pngsuite/primary_check/basn6a08.png create mode 100644 tests/pngsuite/primary_check/bgai4a08.png create mode 100644 tests/pngsuite/primary_check/bgan6a08.png create mode 100644 tests/pngsuite/primary_check/bgbn4a08.png create mode 100644 tests/pngsuite/primary_check/bgwn6a08.png create mode 100644 tests/pngsuite/primary_check/s01i3p01.png create mode 100644 tests/pngsuite/primary_check/s01n3p01.png create mode 100644 tests/pngsuite/primary_check/s02i3p01.png create mode 100644 tests/pngsuite/primary_check/s02n3p01.png create mode 100644 tests/pngsuite/primary_check/s03i3p01.png create mode 100644 tests/pngsuite/primary_check/s03n3p01.png create mode 100644 tests/pngsuite/primary_check/s04i3p01.png create mode 100644 tests/pngsuite/primary_check/s04n3p01.png create mode 100644 tests/pngsuite/primary_check/s05i3p02.png create mode 100644 tests/pngsuite/primary_check/s05n3p02.png create mode 100644 tests/pngsuite/primary_check/s06i3p02.png create mode 100644 tests/pngsuite/primary_check/s06n3p02.png create mode 100644 tests/pngsuite/primary_check/s07i3p02.png create mode 100644 tests/pngsuite/primary_check/s07n3p02.png create mode 100644 tests/pngsuite/primary_check/s08i3p02.png create mode 100644 tests/pngsuite/primary_check/s08n3p02.png create mode 100644 tests/pngsuite/primary_check/s09i3p02.png create mode 100644 tests/pngsuite/primary_check/s09n3p02.png create mode 100644 tests/pngsuite/primary_check/s32i3p04.png create mode 100644 tests/pngsuite/primary_check/s32n3p04.png create mode 100644 tests/pngsuite/primary_check/s33i3p04.png create mode 100644 tests/pngsuite/primary_check/s33n3p04.png create mode 100644 tests/pngsuite/primary_check/s34i3p04.png create mode 100644 tests/pngsuite/primary_check/s34n3p04.png create mode 100644 tests/pngsuite/primary_check/s35i3p04.png create mode 100644 tests/pngsuite/primary_check/s35n3p04.png create mode 100644 tests/pngsuite/primary_check/s36i3p04.png create mode 100644 tests/pngsuite/primary_check/s36n3p04.png create mode 100644 tests/pngsuite/primary_check/s37i3p04.png create mode 100644 tests/pngsuite/primary_check/s37n3p04.png create mode 100644 tests/pngsuite/primary_check/s38i3p04.png create mode 100644 tests/pngsuite/primary_check/s38n3p04.png create mode 100644 tests/pngsuite/primary_check/s39i3p04.png create mode 100644 tests/pngsuite/primary_check/s39n3p04.png create mode 100644 tests/pngsuite/primary_check/s40i3p04.png create mode 100644 tests/pngsuite/primary_check/s40n3p04.png create mode 100644 tests/pngsuite/primary_check/tbbn0g04.png create mode 100644 tests/pngsuite/primary_check/tbbn3p08.png create mode 100644 tests/pngsuite/primary_check/tbgn3p08.png create mode 100644 tests/pngsuite/primary_check/tbrn2c08.png create mode 100644 tests/pngsuite/primary_check/tbwn3p08.png create mode 100644 tests/pngsuite/primary_check/tbyn3p08.png create mode 100644 tests/pngsuite/primary_check/tm3n3p02.png create mode 100644 tests/pngsuite/primary_check/tp0n0g08.png create mode 100644 tests/pngsuite/primary_check/tp0n2c08.png create mode 100644 tests/pngsuite/primary_check/tp0n3p08.png create mode 100644 tests/pngsuite/primary_check/tp1n3p08.png create mode 100644 tests/pngsuite/primary_check/z00n2c08.png create mode 100644 tests/pngsuite/primary_check/z03n2c08.png create mode 100644 tests/pngsuite/primary_check/z06n2c08.png create mode 100644 tests/pngsuite/primary_check/z09n2c08.png create mode 100644 tests/pngsuite/unused/ccwn2c08.png create mode 100644 tests/pngsuite/unused/ccwn3p08.png create mode 100644 tests/pngsuite/unused/cdfn2c08.png create mode 100644 tests/pngsuite/unused/cdhn2c08.png create mode 100644 tests/pngsuite/unused/cdsn2c08.png create mode 100644 tests/pngsuite/unused/cdun2c08.png create mode 100644 tests/pngsuite/unused/ch1n3p04.png create mode 100644 tests/pngsuite/unused/ch2n3p08.png create mode 100644 tests/pngsuite/unused/cm0n0g04.png create mode 100644 tests/pngsuite/unused/cm7n0g04.png create mode 100644 tests/pngsuite/unused/cm9n0g04.png create mode 100644 tests/pngsuite/unused/cs3n2c16.png create mode 100644 tests/pngsuite/unused/cs3n3p08.png create mode 100644 tests/pngsuite/unused/cs5n2c08.png create mode 100644 tests/pngsuite/unused/cs5n3p08.png create mode 100644 tests/pngsuite/unused/cs8n2c08.png create mode 100644 tests/pngsuite/unused/cs8n3p08.png create mode 100644 tests/pngsuite/unused/ct0n0g04.png create mode 100644 tests/pngsuite/unused/ct1n0g04.png create mode 100644 tests/pngsuite/unused/cten0g04.png create mode 100644 tests/pngsuite/unused/ctfn0g04.png create mode 100644 tests/pngsuite/unused/ctgn0g04.png create mode 100644 tests/pngsuite/unused/cthn0g04.png create mode 100644 tests/pngsuite/unused/ctjn0g04.png create mode 100644 tests/pngsuite/unused/ctzn0g04.png create mode 100644 tests/pngsuite/unused/f00n0g08.png create mode 100644 tests/pngsuite/unused/f00n2c08.png create mode 100644 tests/pngsuite/unused/f01n0g08.png create mode 100644 tests/pngsuite/unused/f01n2c08.png create mode 100644 tests/pngsuite/unused/f02n0g08.png create mode 100644 tests/pngsuite/unused/f02n2c08.png create mode 100644 tests/pngsuite/unused/f03n0g08.png create mode 100644 tests/pngsuite/unused/f03n2c08.png create mode 100644 tests/pngsuite/unused/f04n0g08.png create mode 100644 tests/pngsuite/unused/f04n2c08.png create mode 100644 tests/pngsuite/unused/f99n0g04.png create mode 100644 tests/pngsuite/unused/g03n0g16.png create mode 100644 tests/pngsuite/unused/g03n2c08.png create mode 100644 tests/pngsuite/unused/g03n3p04.png create mode 100644 tests/pngsuite/unused/g04n0g16.png create mode 100644 tests/pngsuite/unused/g04n2c08.png create mode 100644 tests/pngsuite/unused/g04n3p04.png create mode 100644 tests/pngsuite/unused/g05n0g16.png create mode 100644 tests/pngsuite/unused/g05n2c08.png create mode 100644 tests/pngsuite/unused/g05n3p04.png create mode 100644 tests/pngsuite/unused/g07n0g16.png create mode 100644 tests/pngsuite/unused/g07n2c08.png create mode 100644 tests/pngsuite/unused/g07n3p04.png create mode 100644 tests/pngsuite/unused/g10n0g16.png create mode 100644 tests/pngsuite/unused/g10n2c08.png create mode 100644 tests/pngsuite/unused/g10n3p04.png create mode 100644 tests/pngsuite/unused/g25n0g16.png create mode 100644 tests/pngsuite/unused/g25n2c08.png create mode 100644 tests/pngsuite/unused/g25n3p04.png create mode 100644 tests/pngsuite/unused/pp0n2c16.png create mode 100644 tests/pngsuite/unused/pp0n6a08.png create mode 100644 tests/pngsuite/unused/ps1n0g08.png create mode 100644 tests/pngsuite/unused/ps1n2c16.png create mode 100644 tests/pngsuite/unused/ps2n0g08.png create mode 100644 tests/pngsuite/unused/ps2n2c16.png diff --git a/stb_image.h b/stb_image.h index 771ba15..14804d8 100644 --- a/stb_image.h +++ b/stb_image.h @@ -2487,133 +2487,184 @@ static int stbi__paeth(int a, int b, int c) #define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings +static stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; + // 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) { stbi__context *s = a->s; stbi__uint32 i,j,stride = x*out_n; - stbi__uint32 img_len; + stbi__uint32 img_len, img_width_bytes; int k; int img_n = s->img_n; // copy it into a local for later - stbi_uc* line8 = NULL; // point into raw when depth==8 else temporary local buffer STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); - a->out = (stbi_uc *) stbi__malloc(x * y * out_n); + a->out = (stbi_uc *) stbi__malloc(x * y * out_n); // extra bytes to write off the end into if (!a->out) return stbi__err("outofmem", "Out of memory"); - img_len = ((((img_n * x * depth) + 7) >> 3) + 1) * y; + img_width_bytes = (((img_n * x * depth) + 7) >> 3); + img_len = (img_width_bytes + 1) * y; if (s->img_x == x && s->img_y == y) { if (raw_len != img_len) return stbi__err("not enough pixels","Corrupt PNG"); } else { // interlaced: if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); } - if (depth != 8) { - line8 = (stbi_uc *) stbi__malloc((x+7) * out_n); // allocate buffer for one scanline - if (!line8) return stbi__err("outofmem", "Out of memory"); - } - for (j=0; j < y; ++j) { - stbi_uc *in; stbi_uc *cur = a->out + stride*j; stbi_uc *prior = cur - stride; int filter = *raw++; - if (filter > 4) { - if (depth != 8) free(line8); + int filter_bytes = img_n; + int width = x; + if (filter > 4) return stbi__err("invalid filter","Corrupt PNG"); - } - if (depth == 8) { - in = raw; - raw += x*img_n; - } - else { - // 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 - stbi_uc * decode_out = line8; - stbi_uc scale = (color == 0) ? 0xFF/((1<= 1; k-=2, raw++) { - *decode_out++ = scale * ((*raw >> 4) ); - *decode_out++ = scale * ((*raw ) & 0x0f); - } - } else if (depth == 2) { - for (k=x*img_n; k >= 1; k-=4, raw++) { - *decode_out++ = scale * ((*raw >> 6) ); - *decode_out++ = scale * ((*raw >> 4) & 0x03); - *decode_out++ = scale * ((*raw >> 2) & 0x03); - *decode_out++ = scale * ((*raw ) & 0x03); - } - } else if (depth == 1) { - for (k=x*img_n; k >= 1; k-=8, raw++) { - *decode_out++ = scale * ((*raw >> 7) ); - *decode_out++ = scale * ((*raw >> 6) & 0x01); - *decode_out++ = scale * ((*raw >> 5) & 0x01); - *decode_out++ = scale * ((*raw >> 4) & 0x01); - *decode_out++ = scale * ((*raw >> 3) & 0x01); - *decode_out++ = scale * ((*raw >> 2) & 0x01); - *decode_out++ = scale * ((*raw >> 1) & 0x01); - *decode_out++ = scale * ((*raw ) & 0x01); - } - } + if (depth < 8) { + assert(img_width_bytes <= x); + 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; } // if first row, use special filter that doesn't sample previous row if (j == 0) filter = first_row_filter[filter]; - // handle first pixel explicitly - for (k=0; k < img_n; ++k) { + // handle first byte explicitly + for (k=0; k < filter_bytes; ++k) { switch (filter) { - case STBI__F_none : cur[k] = in[k]; break; - case STBI__F_sub : cur[k] = in[k]; break; - case STBI__F_up : cur[k] = STBI__BYTECAST(in[k] + prior[k]); break; - case STBI__F_avg : cur[k] = STBI__BYTECAST(in[k] + (prior[k]>>1)); break; - case STBI__F_paeth : cur[k] = STBI__BYTECAST(in[k] + stbi__paeth(0,prior[k],0)); break; - case STBI__F_avg_first : cur[k] = in[k]; break; - case STBI__F_paeth_first: cur[k] = in[k]; break; + case STBI__F_none : cur[k] = raw[k]; break; + case STBI__F_sub : cur[k] = raw[k]; break; + case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; + case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break; + case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break; + case STBI__F_avg_first : cur[k] = raw[k]; break; + case STBI__F_paeth_first: cur[k] = raw[k]; break; } } - if (img_n != out_n) cur[img_n] = 255; - in += img_n; - cur += out_n; - prior += out_n; + + if (depth == 8) { + if (img_n != out_n) + cur[img_n] = 255; // first pixel + raw += img_n; + cur += out_n; + prior += out_n; + } else { + raw += 1; + cur += 1; + prior += 1; + } + + // @TODO: special case filter_bytes = 1, or just rewrite whole thing to not use a nested loop + // this is a little gross, so that we don't switch per-pixel or per-component - if (img_n == out_n) { + if (depth < 8 || img_n == out_n) { #define CASE(f) \ case f: \ - for (i=x-1; i >= 1; --i, in+=img_n,cur+=img_n,prior+=img_n) \ - for (k=0; k < img_n; ++k) + for (i=width-1; i >= 1; --i, raw+=filter_bytes,cur+=filter_bytes,prior+=filter_bytes) \ + for (k=0; k < filter_bytes; ++k) switch (filter) { - CASE(STBI__F_none) cur[k] = in[k]; break; - CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(in[k] + cur[k-img_n]); break; - CASE(STBI__F_up) cur[k] = STBI__BYTECAST(in[k] + prior[k]); break; - CASE(STBI__F_avg) cur[k] = STBI__BYTECAST(in[k] + ((prior[k] + cur[k-img_n])>>1)); break; - CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(in[k] + stbi__paeth(cur[k-img_n],prior[k],prior[k-img_n])); break; - CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(in[k] + (cur[k-img_n] >> 1)); break; - CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(in[k] + stbi__paeth(cur[k-img_n],0,0)); break; + CASE(STBI__F_none) cur[k] = raw[k]; break; + CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); 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] + cur[k-filter_bytes])>>1)); break; + CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); break; + CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); break; + CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); break; } #undef CASE } else { STBI_ASSERT(img_n+1 == out_n); #define CASE(f) \ case f: \ - for (i=x-1; i >= 1; --i, cur[img_n]=255,in+=img_n,cur+=out_n,prior+=out_n) \ + for (i=x-1; i >= 1; --i, cur[img_n]=255,raw+=img_n,cur+=out_n,prior+=out_n) \ for (k=0; k < img_n; ++k) switch (filter) { - CASE(STBI__F_none) cur[k] = in[k]; break; - CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(in[k] + cur[k-out_n]); break; - CASE(STBI__F_up) cur[k] = STBI__BYTECAST(in[k] + prior[k]); break; - CASE(STBI__F_avg) cur[k] = STBI__BYTECAST(in[k] + ((prior[k] + cur[k-out_n])>>1)); break; - CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(in[k] + stbi__paeth(cur[k-out_n],prior[k],prior[k-out_n])); break; - CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(in[k] + (cur[k-out_n] >> 1)); break; - CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(in[k] + stbi__paeth(cur[k-out_n],0,0)); break; + CASE(STBI__F_none) cur[k] = raw[k]; break; + CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(raw[k] + cur[k-out_n]); 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] + cur[k-out_n])>>1)); break; + CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-out_n],prior[k],prior[k-out_n])); break; + CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(raw[k] + (cur[k-out_n] >> 1)); break; + CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-out_n],0,0)); break; } #undef CASE } } - if (depth != 8) free(line8); + // 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 + stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range + + // 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 + + if (depth == 4) { + for (k=x*img_n; k >= 2; k-=2, ++in) { + *cur++ = scale * ((*in >> 4) ); + *cur++ = scale * ((*in ) & 0x0f); + } + if (k > 0) *cur++ = scale * ((*in >> 4) ); + } else if (depth == 2) { + for (k=x*img_n; k >= 4; k-=4, ++in) { + *cur++ = scale * ((*in >> 6) ); + *cur++ = scale * ((*in >> 4) & 0x03); + *cur++ = scale * ((*in >> 2) & 0x03); + *cur++ = scale * ((*in ) & 0x03); + } + if (k > 0) *cur++ = scale * ((*in >> 6) ); + if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03); + if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03); + } else if (depth == 1) { + for (k=x*img_n; k >= 8; k-=8, ++in) { + *cur++ = scale * ((*in >> 7) ); + *cur++ = scale * ((*in >> 6) & 0x01); + *cur++ = scale * ((*in >> 5) & 0x01); + *cur++ = scale * ((*in >> 4) & 0x01); + *cur++ = scale * ((*in >> 3) & 0x01); + *cur++ = scale * ((*in >> 2) & 0x01); + *cur++ = scale * ((*in >> 1) & 0x01); + *cur++ = scale * ((*in ) & 0x01); + } + if (k > 0) *cur++ = scale * ((*in >> 7) ); + if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01); + if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01); + if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01); + if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01); + if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01); + if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01); + } + if (img_n != out_n) { + // insert alpha = 255 + stbi_uc *cur = a->out + stride*j; + int i; + if (img_n == 1) { + for (i=x-1; i >= 0; --i) { + cur[i*2+1] = 255; + cur[i*2+0] = cur[i]; + } + } else { + assert(img_n == 3); + for (i=x-1; i >= 0; --i) { + cur[i*4+3] = 255; + cur[i*4+2] = cur[i*3+2]; + cur[i*4+1] = cur[i*3+1]; + cur[i*4+0] = cur[i*3+0]; + } + } + } + } + } + return 1; } @@ -2856,7 +2907,7 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); has_trans = 1; for (k=0; k < s->img_n; ++k) - tc[k] = (stbi_uc) (stbi__get16be(s) & 255); // non 8-bit images will be larger + tc[k] = (stbi_uc) (stbi__get16be(s) & 255) * stbi__depth_scale_table[depth]; // non 8-bit images will be larger } break; } diff --git a/tests/image_test.c b/tests/image_test.c index c1115f4..ad0641e 100644 --- a/tests/image_test.c +++ b/tests/image_test.c @@ -7,7 +7,7 @@ #define STB_DEFINE #include "stb.h" -#define PART1 +#define PNGSUITE_PRIMARY int main(int argc, char **argv) { @@ -34,8 +34,8 @@ int main(int argc, char **argv) } } else { int i, nope=0; - #ifdef PART1 - char **files = stb_readdir_files("pngsuite/part1"); + #ifdef PNGSUITE_PRIMARY + char **files = stb_readdir_files("pngsuite/primary"); #else char **files = stb_readdir_files("images"); #endif @@ -43,7 +43,7 @@ int main(int argc, char **argv) int n; char **failed = NULL; unsigned char *data; - //printf("%s\n", files[i]); + printf("%s\n", files[i]); data = stbi_load(files[i], &w, &h, &n, 0); if (data) free(data); else stb_arr_push(failed, "&n"); data = stbi_load(files[i], &w, &h, 0, 1); if (data) free(data); else stb_arr_push(failed, "1"); data = stbi_load(files[i], &w, &h, 0, 2); if (data) free(data); else stb_arr_push(failed, "2"); @@ -52,16 +52,22 @@ int main(int argc, char **argv) if (data) { char fname[512]; - #ifdef PART1 + #ifdef PNGSUITE_PRIMARY int w2,h2; unsigned char *data2; stb_splitpath(fname, files[i], STB_FILE_EXT); - data2 = stbi_load(stb_sprintf("pngsuite/part1_check/%s", fname), &w2, &h2, 0, 4); + data2 = stbi_load(stb_sprintf("pngsuite/primary_check/%s", fname), &w2, &h2, 0, 4); if (!data2) - printf("FAILED: couldn't load 'pngsuite/part1_check/%s\n", fname); + printf("FAILED: couldn't load 'pngsuite/primary_check/%s\n", fname); else { if (w != w2 || h != w2 || 0 != memcmp(data, data2, w*h*4)) { - printf("FAILED: %s loaded but didn't match part1_check 32-bit version\n", files[i]); + int x,y,c; + if (w == w2 && h == h2) + for (y=0; y < h; ++y) + for (x=0; x < w; ++x) + for (c=0; c < 4; ++c) + assert(data[y*w*4+x*4+c] == data2[y*w*4+x*4+c]); + printf("FAILED: %s loaded but didn't match PRIMARY_check 32-bit version\n", files[i]); } free(data2); } diff --git a/tests/pngsuite/16bit/basi0g16.png b/tests/pngsuite/16bit/basi0g16.png new file mode 100644 index 0000000000000000000000000000000000000000..a9f28165efd4a6eaab890f3f46eaab0812614046 GIT binary patch literal 299 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 jpPUeX<8i+F!+uXjVapt`t6N}PA|XNFR{LJ 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 literal 0 HcmV?d00001 diff --git a/tests/pngsuite/16bit/basn0g16.png b/tests/pngsuite/16bit/basn0g16.png new file mode 100644 index 0000000000000000000000000000000000000000..e7c82f78eb954be5be51c35bd287e00018c69d82 GIT binary patch literal 167 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I0R{#J2DZkZ*$fN}Ea{HEjtq=#3k+XOi)Ub9 zi1T!D45^rN^^zgi0RtZAK+EX&^~dfkn0!E^+UTkl%i^2;_7)AxcZ3TICoiySN|5E4 z$#A#no5LxV7h-qVoYWk)FR-0p#JG!fd*cMo3%VKnOMDXS^V#3{f048}U(X$_K`!ug^>bP0l+XkKCtEmz literal 0 HcmV?d00001 diff --git a/tests/pngsuite/16bit/basn2c16.png b/tests/pngsuite/16bit/basn2c16.png new file mode 100644 index 0000000000000000000000000000000000000000..50c1cb91a0171e9f34991b079fe932f5f0bb16d6 GIT binary patch literal 302 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I0VW0phBY0A4;UC2SkfJR9T^zg78t&m7SF)I z@YK`AF{EP7)oBO0nhgY8mOpT;KV7%|@7izEvJU<1&fTQe}4O^Aoe0-!sktm@h{$dVyY}zw&8$% z$+9Ps8qUvSa+pnDyfI?>`of2?arcWeE7KS7&i(8uy}=<}UN52joQy_7uN>=-1$z0ba_Q03+=ZF1yw*OF z40oUSHu8Vm`}vfiWQnr*P;2n=R`dl=)xpZ@$WO<@$ne`YX02{4~=!d+6H5S+ZvvLRmk@zS!IE zkYN6!UTs5m@`Gv-G46?L-t+vhZ+O5Zp~^A8;j5L&eWrX?v-Mt#_d4dR{hj!g<%;)% zJq)Ma6Hm4rW#U;PyW5^|BF~KV4m&t(KXWx6P~@1B`s|lvbCyqaJ#q;cZ_(H?u(Ko4PoBrUX`v0OU&fd64jWR zXz=a^|Mi9SOl!DW>UnK54Y~wog>kgpYrCMASe+4=CKogDoGI_Sn$*<4zYkh)U1Q0y zWa|xl@yCrT<4Izw*eceDGtQR$<#`9bJ)9-m?f9R|SuFeix*b#dQ=0o7<9WB`Fqez$2@Yzo=DO;+Bf7b@|6!P%o0^REKhvDM zTobKk2w%9(?8f#*g(Y3VVx2&S_(IX?w)qu@zJ1`FS((4SM6QPCnflr_fo=bcY_gnx z7i%s^b5`YxuVMOJc*8b!bNjruMs9)LrkzZCGdcb;eo0sO!OtObuwI_gzxi9XlF?fJ z)T`HCJ6W6-y74W44I^_yFA=;dDHW=+gskQ(>A`p$=9l1<-x05ZRz{`_O@EA zHFbRJ_VKd|nO28OCM{Q}5ujVhbn9>g%@Bg#-YR<>ceTwV06-I2i zD=pZXy*1_h-N3}(k4$I&-1+&E<$-SZ2T!Lz_-MrQhWT}i)InKOCgCl6qzRh5x?{uNSHF!uzrDS*dwTq&CO(yfaG9jZ0%z?V4jHg; zcePl$9(ul@y5H$ReYVBYYX_%8iyWQp0!>nBt8 z?^Sj74qm6q3-Qek!D|z})-Fu;?#XHmnek!D(s=^OE5lsl#O=f;-i$7L6WjInmwC{E z19mU(bRLe8xs$o$`vQSphxeKscNt=Xou;t-pWw8hQg+t-RVtsSeEK|T$E{0~GJdb! zqjBe)dg}SLnTggX&LmI1w9}gR^W+P27`|sm#I|}!oMHO1kNKFd>QPVCqkU_cp1cq3 zsfs<+^0_G@YpK#PBcq2moc*;k-gBMY!l`*+#?+blo0oik)*^C8uFZ`(M)=Miqs8V^ zC6_8>XtP{XKghe1r`&ncnNNWqKLFTUjJ+#GUukESx$6W$;m3MDz{`1yeqgrm4VvhOqlxJrf zO72NcJ!WNjYl%rAM9;dUweKHt=bMp`FrlNU~(6<7=w0nA9&*#eM_&XkN^W!qh`SEdmTA!}?(Gxw%?m@4PeOh|Nxm_cW@{n`Ob8c9w|@r?%X_aV)5l>9nsvhnPa7 zUeFbzr~?zCPj*dViYxq^q_dSR>SPy>hC#rAqArGQPn{NCRO^Vjtl6p2DLaeBg}H8m zi^)`3?+H7+^-tb?_~-Ru%kq_>p(g!~a$@(-&9yFnSN?AA^P1;9Q93ka692=F`%7*((_X>z z<7b*530Je`zA9vL+-Nbw*^6f+96qf2A99<|qvUPW?AToOE4$4~avSay?OIX(-&;NE zdS~3l&blSSvjd&~?3PLj<6Zc6TGFbwopHyzCLU~`x+9K#wbzebLVZ)8H9aWm{_*MQ zy2dC@sopSNNa0WBB^Fdz-HPwwfi^`Xp4={d_^ik7kZSI4U`tKfERLo(Bh&Mn6jUS034HeP-wr)={x zr`o%>U*Bu1v9wy=5*Nb!;#8&Ag=@b%tG<3PRs9#<^z}JQ_O17B-9LI|Umsho8ewy> zSRkQt=W6Z+ktanMn_Ty^CzNho%&fp;Bd;*4*qqVDfA@NZBf@^W8FON}l@onb%o)%A zD1ChI%uAEmch~F;h~HoPx9o*(dvO-S*GpUfU)g@=QQ<6K)pdn+4}%Y`elPJT{QTPb zC1FjsJld`x|ztMBLiy54@-v!FxQ-wEugI3Tcp zNB!fIQJm}M?=4n$*sH&t;lhv9Z;lNQBLA~ENSxwX)D_LrVP7D}(6Rqb4bOx*+vQn2 zj=c$NDA`=fs8D(H-u*NN@AG>CU+Z36h1J^jwzf8f_S+&d zHSYFf(h=RI&NwUDcrwGo>`!egUOi)c6p=Qe=Dr=rgf*M<8C2r8*0WCVi#*KmQZ;c( z-lk^^mpE6~vVZV(?fvbxR{CPrme~^x)F#btNc*#^F#p+<*=O^v#jJQ=SM&Yxh3LAP ze#N?HXYcOLQe6@Dxw7HG@qc~|E7X*aG)`vpaC=kO@MXG;3qbhI7e^c_e{bUHaz4eo^EtBrnye-qR;F0(>Y~Kn^YF=XFpp?%4h^Q)1Wp zs8wN#^QXse<#PUha_>w2<@PdCOgAb%J*sQ4E8hA3^rr5uwdZWjtRZSV|^%DUSTc9+rZ z&1m)aA!l{Pc_56s`kbpdl%nzITT~b_xJwVY3t^!tAM%Kc+6=xL~+@7wdt!{cH>| z(Goj;FA8Qjx2%HifZaryobzl~*|&80FJnvg5_IFdH);M%lcOt21=oh3KlsZ%YiX=gZIeCgU9t=d<$pUxaw9`x(exr0~B*X`R}XYF9}?i~Zi z{m=XOvL~4rZ>eNC@P49XSv>ZP|hzVw}LJh7LfH{R)+W8uVmlPB~v*z%Q0PMWl(b-m*@ zzTP=D!S#Gif*+16O0k!--;vm9xanPP!;oo-62tF0|(F zl{~@c_41TGW1#3AnG))&r|QyZ?pk&(>r`)4sqsW-HSRlY?}`*SJe)}x4DEemag zS&ZBkD{6+jw?CP;PTO-w?%_wzyXSxZ!k{9$n`1&v+I?ODYd;(TH@W97KWd!vt)u%(b;4K07Z&^vxgXf-zdBgSFsU@*zQdO%{SA=`0Y<$k-CsKG zC!`+|Uyv*ow*AD6gGw#c2dbGDU4HPc^@;I@_iZHsM}A#;b1CP$SVPHyT|5(fZXISg zdH#(%<0Rj2GIy5A31r0N*9KiUwM%5ibbaUR4r{k;VwhW7q_Bz4q z>hObqPOm)QF&v3!d!DSh@z#E!+DzVt(8ets-)vNvADnTvVR)C?Vb);Hf03c2hGlj9 z#B!Fu0#^^7b$rtx?0kv+8`BczgxI#HKcD_w$II|?N@#|0Lt5)e!`}t7`8l?{$lSN| zgnH{#&lfr&-o2V9#1>d`&P=pas7vGxS6`Scafrc2ev$Wsd)h{)ek!RvKUf#Qvdxso zhmkcwNP;b!>r#`-Lr=yz97*A)3vlOITK)V_L|WNs_G(%pct6KWO-Y-+Rr6 zV~R4&`67!f3(Or$xbD<0Qh$5>X?C+M*GpB;EtkVp?{ArR>3{NszO4J|*Dl;$p4{sg za;dy`&BFSKXF}5tYC3*0-XI@)xP)g-U`CJWu}!KCUz$|@z1(5S6gDeuo90K(&xIz% zj&^Ek&;RA;+iy^`FU(VO{U$vRa=@W1p2 a`_vn64zInv^)mwl1B0ilpUXO@geCw?|A}e< literal 0 HcmV?d00001 diff --git a/tests/pngsuite/16bit/bgai4a16.png b/tests/pngsuite/16bit/bgai4a16.png new file mode 100644 index 0000000000000000000000000000000000000000..51192e731106e77cec52a3acda3d0c3cd54a16d5 GIT binary patch literal 2855 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 a`_vn64zInv^)mwl1B0ilpUXO@geCw?|A}e< literal 0 HcmV?d00001 diff --git a/tests/pngsuite/16bit/bggn4a16.png b/tests/pngsuite/16bit/bggn4a16.png new file mode 100644 index 0000000000000000000000000000000000000000..13fd85ba193369dbd84a0dc07f73d3340485fa6a GIT binary patch literal 2220 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 literal 0 HcmV?d00001 diff --git a/tests/pngsuite/16bit/oi1n0g16.png b/tests/pngsuite/16bit/oi1n0g16.png new file mode 100644 index 0000000000000000000000000000000000000000..e7c82f78eb954be5be51c35bd287e00018c69d82 GIT binary patch literal 167 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I0R{#J2DZkZ*$fN}Ea{HEjtq=#3k+XOi)Ub9 zi1T!D45^rN^^zgi0RtZAK+EX&^~dfkn0!E^+UTkl%i^2;_7)AxcZ3TICoiySN|5E4 z$#A#no5LxV7h-qVoYWk)FR-0p#JG!fd*cMo3%VKnOMDXS^V#3{f048}U(X$_K`!ug^>bP0l+XkKCtEmz literal 0 HcmV?d00001 diff --git a/tests/pngsuite/16bit/oi1n2c16.png b/tests/pngsuite/16bit/oi1n2c16.png new file mode 100644 index 0000000000000000000000000000000000000000..50c1cb91a0171e9f34991b079fe932f5f0bb16d6 GIT binary patch literal 302 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I0VW0phBY0A4;UC2SkfJR9T^zg78t&m7SF)I z@YK`AF{EP7)oBO0nhgY8mOpT;KV7%|@7izEvJU<1&fTQe}4O^Aoe0-!sktm@h{$dVyY}zw&8$% z$+9Ps8qUvSa+pnDyfI?>`of2?arcWeE7KS7&i(8uy}=<}UN52joQy_7uN>=-1J}{ dq{aDq2C*C7H{v%{#n*ydvd$@?2>_2bJ30UW literal 0 HcmV?d00001 diff --git a/tests/pngsuite/16bit/oi2n2c16.png b/tests/pngsuite/16bit/oi2n2c16.png new file mode 100644 index 0000000000000000000000000000000000000000..4c2e3e3352babf7ab7b83c65bbd334a3e14f0632 GIT binary patch literal 314 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I0VW0phBY0A4;UC2SkfJR9T^zg78t&m7SF)I z(BSFf7*a9k>a>Gg%?1K4%O5z_pRU{fckQ=na%{|#+SJk}pQ(~)bA4iaZ9%_)6N8=p zgIVuWii+zbY}Jk9&prAaRlc3+^|=y_f@EIn1Un-WV}`ec{8{xckMKmFWw3=YIB--r$ffKeJ;&F#`ibD#$H*3GL@( zG!lB{SbrRU$1lsUE&Vy~7nk(+Y8T}9&OV^=MI+(6tVH*@-@RrA%yaifCdgH7K9KW8 zBcPtm26BKLh{w2#b$jCk s&I`I3{7ZZi?DN^*_a>Gg%?1K4%O5z_pRU{fckQ=na%{|#+SJk}pQ(~)bA4iaZ9%_)6N8=p zgIVuWii+zbY}Jk9&prAaRlc3+^|=y_f?ys$AzeQ8#nERl zcj+axpOeu@=#^vrar_;>EW@_+=e%EB(%-9Hkl#D|fW{Y%gzvHv-RFMyni(+9-5Z%8 zSGD;-&KHe=zk*q~J<#(0Knd iCxu6kG#MBem_Y9O7gr_DTgAY@z~JfX=d#Wzp$PyF;)s?2 literal 0 HcmV?d00001 diff --git a/tests/pngsuite/16bit/oi9n0g16.png b/tests/pngsuite/16bit/oi9n0g16.png new file mode 100644 index 0000000000000000000000000000000000000000..9248413576d964953c7c15ee5f62c7ea5cfbb5e5 GIT binary patch literal 1283 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I0R{#J2DZkZ*$fN}Ea{HEjtq=#3k+XOi)Ub9 zVDxlx45=u4*76L-nRBsmQ9F!t^D=%$AIsluM3RBqu6J77{+lv{x7cC_0s29rT?sD^CsRUw#6_51f% zV_+Pk2k&(uYH(fZuH#SSLJq93~RBaE{+{dxZ`80Y47bMYB4PJgKV<473CeqLO_ zRT#&D!RlxkjMH$m;ok`uXL&-G_hJ}l$J-{iFc>HNuKCXWFplt=HXAdnoa8^vzMy0Q z4g-_`v3h5+BnqadNxN_U6Bs8UwM%9Lj3eu9Cuj)caHu{0dJD#xx$t!u2aLm@VNv@6 z#<_bT>T)BDgJSfznrB)EVKNSJPi!h+oKwM_VQw%EN{GH_dnvvMCL?y|&54~b4oYmZ z9gMzl7bfGh;Z9pHdqO3Qv*c&9lq8Jf6CP9$4CA20DN5qY|7yyp2vf$sE#`$cjPs_kA54$;NwcRP YU>p>g_{(n$dqJ7o)78&qol`;+0P#L$S^xk5 literal 0 HcmV?d00001 diff --git a/tests/pngsuite/16bit/oi9n2c16.png b/tests/pngsuite/16bit/oi9n2c16.png new file mode 100644 index 0000000000000000000000000000000000000000..f0512e49f2306f1969bc9fcafedcb77f748b54f8 GIT binary patch literal 3038 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I0VW0phBY0A4;UC2SkfJR9T^zg78t&m7SF)I z!074X7*bL8tmPSuGv{LCqIMYP>b=J3%`nb1!w~P8FwVgv(f#LO9Ig{@r+kBPnqxZG z7r{6Nd=GtHU>pI{{@flI$0f4!M^Y^vMXHOVsZA1K`y)e$VnrB)EVH_0C$z3vc=!VI# z9gMzl7sg@UXs81USa7&aGPCS&fXTG!JdXYgZ5V)I}elxRc=0~F7x_ZppOhUqb${zB#-j1zzP zjbSg0b1vk`BzPi!lxFj94@~AWPtQF+7$<6R+fh&!0mo_iv&fm{Fd3AD#B|I|<_JvY zwfqA&2^a^(o|5{26K7#E8nV4tg5135j zruK7jFb+!azG!P6kXFN`QQQ`o6jvCWB&tPk2y4FiZv|=1`(!cS*PS z8<;W_15iqrmF-4pOJK^B z9F)>>8<$mfAWR0u+bBs4C9JO7QNT`(o2g zn9OYdr{*d!4oc2K2}Bgw!;Hm&6bWn-_+@TZT z9IPV)vlOMdg3^pI;q2**g(*XcIm>d}ub_q+*ahqJ0uN7wDZ8^g_OUpO({Qxm-w7B; z=yoH|0vN~Yoyn3Y7^nLE`>Qc9&c-Qm|31MuCoLo(1E~_vrX+3*(>^X}QwY3A`{Flwutvxu8^(DCN$FsjdBAUgTe~DWM4f4?$RT literal 0 HcmV?d00001 diff --git a/tests/pngsuite/16bit/tbbn2c16.png b/tests/pngsuite/16bit/tbbn2c16.png new file mode 100644 index 0000000000000000000000000000000000000000..dd3168e5c864a81f3284856f2b00fd1e52eb312e GIT binary patch literal 2041 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I0VW0phBY0A4;UC2SkfJR9T^zg78t&m7SF)I zz*Z9E7yKU#=I!-10*NGfySp$jFfjc8@1DA{fq{X&$J50zB%<}|4Q?OlR2ha3@29vM z{OHK@>6H>w2^73|<498QjHCl%(-v-BoT|LA%qB)wNx^49$dp67E(Jw#$;ze*Nbs3& zw`5=BXJS>DVwJ{Yn0ChHaWVh4ohv{7tzTdk8L-Q-XMfA-r+xRn|F3^<{qgtzIX~7j z?}*@@bl~|D21{SDMIvVWoHf4RCRqhJczMaOm6nz_tc|{W;KmGY8EZ3Ey?rraMNH}^ zH8xIEN-}!d`07>4hQh~J4?Gl@BoMZmAvCliC*weJ`f`@4YT<(~R!I8z`ZmO$uu(5) z+vB`vNsrCP7S51RTZUP)@|fcE+pga2b={_xHH+@jm?7CmV4*H}^Z!c5CULo+FJXPkJ9npa1Z` zkN@NU^J()FPzZ~}pEB{(sHWP~q`5AM1SdaI|v+n!JCOmJ(fx=7o>$z8~yx918et=il z<40fL zj~^R0{QI|I!;>fb_B~12y?5=|yzdjlKFO@ysc_ZNqU4>5rHVy{=*7wPl1FlsCoZwA zR(Y}X{l4znuV*CZn76fksWN{kxw3i7M71F4Me3e2kAST1k$tr@4&2=AbmW+y@6lu1g!pC&-*Bl|_n_GN;khvJBR)Io z?Y#=_ojia1;)i3>5$6sz+pIn0SoOxxMqlgDOz+iq{hm!>U>6s@d|6o7`7^JL#519T znIU1{zJ-MqxffYjS;_Q$`QpHkotdCud-o*|%Lo2kHJdsM#&;?^S**SC-feyG_xr|{ z;N=@ybfXKNojQL!(sSjJ*KEvw;#GfDW(G6Wro0TApZ_vQk&XSM;rqSc)0w!A{@CGk zaP5+?{QK*|xL!&aB0$n25!OgUn5RzOm=c{n`a>?nYp=guUT}| ztpg5GvnEvhytT!XW9OaMQ%~=Fw^P=lm+R2N#~*aGxY(bcE4-WhV(HSN3G@CbbTXbi z$?35A>DK>$EYf`wdQPPD_8QF;*j=8ixM4k`d|k)!_xpsEv`@c3e=10WiLuqmBRRR^ z?sH+Ml{wkLT9q~h)&){~_7yQnh=q0>DcxV1ZFAvu;qL88tZi}O?d7|7Z&bFN8zE_H ztElq9(9_d!c5u)?p9Ra2J=Gf^TnWS3wdy*>G(Pw98Fq{clu$Wo+L&X%YIQ{0! z4|wIjRqwUqnq$+cIM1rJxbI|%`H8bf&vu?}^>5PUy0doeUYRFP3tQVJFzBaCN{Wg~ zN?xfj%XBKr*y z|6YB+bmGKU1%3YP*rkWk3tVUVR9sKl#keM>a$3s-hWzZ!o8{|ezV{lKEOb~O-f`r} zs#Ql^6z^4WbKl%Ae`gDC==yht5>)*fK zVw@i@x<^d8+gI-H{_)OB5vR3fJFmQYkh*T}hhJS^_m=Dbd-NiZXX6eF(UdebfjPz3 z)*e=Wd-JgF1&%xKxP2DPY-wj_dic=k(AiBsVG$aWb)(a^>P4#^`SHVNe|tfNRBoP_ z)6ycVP^~ys3*LJrYgEFU9wz=ddV=GeO>3(p%k9LoQuk^ePu{hwV9tw@-zQnsJ_r}? zEPGqDGsS3isG70FwKawkJ;%0Y_a5u$m}{-9)Kc-$l`nmnX^Y$Af((;AQN>bwSg%Yv zecR%9pxde*ODG(_r3Wwv%VdoF833dCX0*sA$%#qM{1pWr>|&$HDo+Z5)D^$UqVjO^ZDuHzEP{iE=^%)|FfxWiBV|M&Wf{A`||a=#WON`Y!< MPgg&ebxsLQ0OlFhZU6uP literal 0 HcmV?d00001 diff --git a/tests/pngsuite/16bit/tbgn2c16.png b/tests/pngsuite/16bit/tbgn2c16.png new file mode 100644 index 0000000000000000000000000000000000000000..85cec395c01b305335172fe781aad11e485f45e1 GIT binary patch literal 2041 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 OVDNPHb6Mw<&;$S}uGRbi literal 0 HcmV?d00001 diff --git a/tests/pngsuite/16bit/tbwn0g16.png b/tests/pngsuite/16bit/tbwn0g16.png new file mode 100644 index 0000000000000000000000000000000000000000..99bdeed2b3b8564302d449e6578c4aca0f6261f5 GIT binary patch literal 1313 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I0R{#J2DZkZ*$fN}Ea{HEjtq=#3k+XOi)Ub9 zU@8gn3;zHA#Mb-ALA)eycbEVFMOGW0Wnf_0!(TCB!Aiz{`S~_KKPpGE z?Wx#UnjIUPm376>{BMgqH>*6SK<I*W7F#B-S5q@0cBVP2cQJ4_;cb?)WV zYgLk0=S>ffi3u~S{x(th{k?;{7RAfBfzBH?Lp6dGo$~Li!ro-hO(#4Gn-(oPbp5r>+{xZ4K|&~NqMuBqN`+Hv>o!C93}B-o9gzbl4s{y*Z*r`4Gj$poH((pX%k~odxhxI zq)Jy;uAKk>{`Dpu*p{35=i|$j{JVpGX{n!C6|CRgJ?YeMN$_kWSnmL)ZRD!gLbd=1jSzN%Zf%6qBo(zc0bS*LDJKR?$xKQ1mV zWy#c@oQ4f6w(U7Bq^hS_?znm9uMD<3J0{9ZOnf|XzVO}OYF2wyR;7d;nf=Fob6R7M zhd=-PB{Ixg{%`wPwK3UgR!v{hx8wbbB|p3hef054d)>i}-+F631tsUWURQGB7D+oZ z!!-NcoFgv&;Wrrq#g7(Wn*Vc3Wld$x)V}(kO=$<_+jFK*zJ2JsyNpgu;31iBy9-=T z+?*s9P;zdTsA#ID(&KaU6J=EP_J=oLclr>NU@+~?obMWmUWcXxTt3q^OS*A8_o}An z;^xhhu58JC`0&;6W~nfS*h(sZxpX7#m7&x0Sl zz4WS6Sl$2K8y?=NhGLHd=cE>fnZ&6C{rkOb%m4oyB^a2*^`1OiwrrX0xgB%Xif>pK zvT}d@qa(+TT?lY3t&5$<#>m)sb=BPGmjC}B&phz|fBwBKTbG6|{hXS{)*-I_<=eOK z;i0W9FU&u67F;h@mzq~$@bG{A9=3)@$yZmET>i4OPQN?7y!`vOX;WC(Z{PCL=C=MB zvFEZwc<i$8z*6u*DN%A-5m*tk izpnO=#D1=>>~w|)XQo{>HkT6ym3^MBelF{r5}E)DYm4>( literal 0 HcmV?d00001 diff --git a/tests/pngsuite/PngSuite.LICENSE b/tests/pngsuite/PngSuite.LICENSE new file mode 100644 index 0000000..8d4d1d0 --- /dev/null +++ b/tests/pngsuite/PngSuite.LICENSE @@ -0,0 +1,9 @@ +PngSuite +-------- + +Permission to use, copy, modify and distribute these images for any +purpose and without fee is hereby granted. + + +(c) Willem van Schaik, 1996, 2011 + diff --git a/tests/pngsuite/corrupt/xc1n0g08.png b/tests/pngsuite/corrupt/xc1n0g08.png new file mode 100644 index 0000000000000000000000000000000000000000..940422737011509e21d5c02e879c643a83d360e6 GIT binary patch literal 138 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4n_tBhIeb7d>I%RSkfJR9T^zg78t&m7SF)I z;OOb%7*a7OIVC}bL4@PPW*%179)1qZAK&He6Dkd4L<~*|PDoE#R2jp=#@f^W;nctX q=YO<6D>Rf4F*x;LYHA7#L%`F2g{F^gL^3ciFnGH9xvX{N literal 0 HcmV?d00001 diff --git a/tests/pngsuite/corrupt/xc9n2c08.png b/tests/pngsuite/corrupt/xc9n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..b11c2a7b4049475d967a8cc76b93ef1039684a3a GIT binary patch literal 145 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4o(IJ25rf#MGOoKEa{HEjtq=#3k+XOi)Ub9 z@bGkT45^s&_Ub`S1_K@@ht@X}|86f5wsz6}vhc^bhuT|sS*#nlM1IIDc>AQ*r^2C; xiQlVT{!k0Mh{lHnB^Jsn9U6BRlrKKO*tGFy9KXYPZw3Yi22WQ%mvv4FO#oG-FC_o~ literal 0 HcmV?d00001 diff --git a/tests/pngsuite/corrupt/xcrn0g04.png b/tests/pngsuite/corrupt/xcrn0g04.png new file mode 100644 index 0000000000000000000000000000000000000000..48abba193ab36cb5a404b33a4b8f3d12e4646c4f GIT binary patch literal 145 zcmeAS@N?(omEvV!VBq!ia0y~yU{C;I76t|ehRF|4XfiM`u%tWsIx;Y}EiimBEuMja z!Nb$VF{ENnazcWDNJx;8Sy>?`udlbZe!7A)!_?as9s3xx%AffZu>|Z~9X3(9;ndx| vvt<}V-pw?A!m*&}{XJE8hN-{b$x1RY$cwyVeD&Y)7sxJ8S3j3^P6(j9#r85r9Z7`~Vm&%nUo z;pyTSQZeW4)q|W220Tm-t#2m&-CiVY?V|l<;g53zopr0J(iI0ssI2 literal 0 HcmV?d00001 diff --git a/tests/pngsuite/corrupt/xd3n2c08.png b/tests/pngsuite/corrupt/xd3n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..9e4a3ff7accf4453ddcd58318f7048b326b44ad2 GIT binary patch literal 145 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;IW+ny(hVB!0HZd?Tu%tWsIx;Y}EiimBEuMja z!Nb$VF{EP7+p7mT84P%s99rK@{JXtK*xE(=%fcV$9%^slWwCDH68Rys;O&!Ip9+UY yCVsDW`9m%2A{rkSlvpUQbZFdNP`>y8W7Ec;ar_SFy%`u77(8A5T-G@yGywnu|1hcm literal 0 HcmV?d00001 diff --git a/tests/pngsuite/corrupt/xd9n2c08.png b/tests/pngsuite/corrupt/xd9n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..2c3b91aa4f1220eeb2c32feb5a6be116a2ad4aa1 GIT binary patch literal 145 zcmeAS@N?(olHy`uVBq!ia0y~yU{Cy8W7Ec;ar_SFy%`u77(8A5T-G@yGywn|EHK{y literal 0 HcmV?d00001 diff --git a/tests/pngsuite/corrupt/xdtn0g01.png b/tests/pngsuite/corrupt/xdtn0g01.png new file mode 100644 index 0000000000000000000000000000000000000000..1a81abef826f52b95708677c38c4b8e812e2f462 GIT binary patch literal 61 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;IMg|53hG<6jNCpN5mUKs7M+U~W1%@xC#e>8> MUHx3vIVCg!03C%3d;kCd literal 0 HcmV?d00001 diff --git a/tests/pngsuite/corrupt/xhdn0g08.png b/tests/pngsuite/corrupt/xhdn0g08.png new file mode 100644 index 0000000000000000000000000000000000000000..fcb8737fa2505b43955e995d95c3d6972b85fe32 GIT binary patch literal 138 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4h9AW2It^VUj_ySmUKs7M+U~W1%@xC#WOH4 zIC{D`hE&W+PDxN<5aBqnnTM6Nho3|9$9H-Agh~S$5rb2L6Vg)_RmSkJvG(+TIQ8%U o`5*1i3JoPh3{E|mnwrAG5b*S0q3NR=kswPvUHx3vIVCg!04nS%Z~y=R literal 0 HcmV?d00001 diff --git a/tests/pngsuite/corrupt/xlfn0g04.png b/tests/pngsuite/corrupt/xlfn0g04.png new file mode 100644 index 0000000000000000000000000000000000000000..d9ec53ed94b34f50eeabf3029465e1106725ea2a GIT binary patch literal 145 zcmeAS@N?(llHy`uVBqrfa0y~yU{C;I76t|ehRF|4XfiM`u%tWsIx;Y}EiimBEuMja z!Nb$VF{ENnazcWDNJx;8Sy>?`m#??Be!7A)!_?as9s3xx%AffZu>|Z~9X3(9;ndx| vvt<}V-pw?A!m*&}{XJE8hN-{b$x1RY$cwyVeD&Y)7sxJ8S3j3^P6VBq!ia0y~yU{C;IMg|53hG<6jNCpN5mUKs7M+U~W1%@xC#e;-B zT^vIy=IEZ;$jNNL!+P=cC6-NI3fxsD`4dEKnhy4ICAzW)etgiSzv|VcB`rDUR;mWG zJr6bs7kVVPNpZionys``v8rlZ_pMFy^0Q7EWa`b;Ow4L?x;imgq@V?T~BUsQ!Q_%#uMkd1=Fq2%XfE0;VNzwcil)+70R&CY_wpDy0JnHlqRe`NCgn_BCA=HFC*LS#n{joO__}9PF7+C9=_WT<6}ZZYc@*f*n*U{?tbSGCD#fP@d+Pr(OnDqA Vnf2VrHIj@DxLe z%R@0|4}}y#FOQ((0=r(>OB|MzVB#@wWMN*$b#TEXONKc?4Zf}0Zq_m|Ffe$!`njxg HN@xNA*)K4C literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/basi0g04.png b/tests/pngsuite/primary/basi0g04.png new file mode 100644 index 0000000000000000000000000000000000000000..3853273f93e5960e0642ca62f6d6ce7433654928 GIT binary patch literal 247 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I76t|e#wX8y>}OzLU`coMb!1>{TVVKNT08>- z!#YnF$B>FSseOThhYSQ<#AQTeL}XZGTC6lm1zss!aXjF7(D9(-0mq2~Dk01>J!hOd zTX*Np+ugHoAKr9mn`^1-?<2bo?sG17|9&j1+(!8t@5Z=}uSb)LEtWdw=w(XHc8}^j ztNwPO#?*Dae^)zSlZ#|e`Fg@iDcj*%=Dx%1KaJcA#M+Cj_8b0hUZml@bj!Nzxi?+mt%cD9GZwZ>e!`9N>W!~gUiM`dV_;xl@O1TaS?83{1OTUD BU*`Y- literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/basi0g08.png b/tests/pngsuite/primary/basi0g08.png new file mode 100644 index 0000000000000000000000000000000000000000..faed8bec445f282d68534af38ceb4006a55c3e86 GIT binary patch literal 254 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4h9AWMny5veGCi?Ea{HEjtq=#3k+XOi)Ub9 z*y`!x7*a83>x5XYLk0pZb9bGPaXM1{!}+|bT}Q=+RpNsDir#mY?Ni~8Ra`pd+~p^; z&l>57sR)LOih9mi<>aBXLMu#V;i|4~m81PLXU^mh=ImVH#c(}Ghx2*PC#gG|I4!MG zgTreV7CJ0CI2^lKYp-o`rWjb{X=}sM*D`{>}&O}@i5BRMD)G?_~n81zT@Yb zbx%#Idc_duES(fS%_Nw8gX9U4Zp<>&hiddm**&))gp^@aR=4F(1V22WQ% Jmvv4FO#rj$Wv2iD literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/basi2c08.png b/tests/pngsuite/primary/basi2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..2aab44d42b23d59d48601b109a795d9ba70d6ab8 GIT binary patch literal 315 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4kiW$#%}q$rVI=WEa{HEjtq=#3k+XOi)Ub9 z_~hy07*a9k>SV`NEQ&lXs}EFH2-`+pE;ioVc|9XzYuZJgFX>S~B2x?(iY3*AbxfSp z@K{K-_S%9a=cO1K`W_1{{d{bW`LjQVztp9dEvWCl^>qvXyGxhtnBw%m{L}SHez-7q zq6BwwZugOhkfXU%C6d1^f3Pk0Jm*S=&;J)q>2;X+)MiBvOIL~|f0}lH*UV`N=Wen| zXwPC?v5#SC3d^#$51TeBSv#mc*71Gp%#!R{)^O5l?Xr`zi`$}B>mQghiFbmOf_?1$ zhtqjAT+^G?&i`Kj{?BE$kT1D{v!7JjHx;-4;gy&hedO9K8|5oe^|u=g-NKvA@B4BY VD*mxGW?*1o@O1TaS?83{1OR6gTe~DWM4fH9jNX literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/basi3p02.png b/tests/pngsuite/primary/basi3p02.png new file mode 100644 index 0000000000000000000000000000000000000000..bb16b44b30907b832b678a3b441278df340edb9f GIT binary patch literal 193 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;ICT0c(#!BHu9~l@JSkfJR9T^zg78t&m7SF)I zz+CL)8N$fOSff|o#K6G76W|l#%J84zKLf-6{|pQa|5NR?cQG(91bVtShE&W+t~kD7 zHe*Yy1k1r2XL=MZCB5$LU`+b*ZPDiadOvnGG}?FBcQKy$af%`3!(%aL4}}y#FOQ(_ v_9dbc$`Ui2Rxi+DVb=O6e{jJhONK2`wJ+sMA2KsAFfe$!`njxgN@xNAQSUy6 literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/basi3p04.png b/tests/pngsuite/primary/basi3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..b4e888e2477d4fbaa3c8ed16a8007d40e58cd52c GIT binary patch literal 327 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I7G?$p#&5ylfeZ``Ea{HEjtq=#3k+XOi)Ub9 zU@ms@3}InmDgUu`F#`jGZh%jSs}jS1hX4ON82&5$XJDB5|9=|8U55YV{~7)>Ffja| zc^Aak{eL$DgUf%0|1Os{ci0D)kJsjnY3X*QhNTP+^U(0jT;v*A=|&><0rr^}WmaxEw- de}7DXfnjsms|=o!3!so-@O1TaS?83{1OR>Hf6M>? literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/basi3p08.png b/tests/pngsuite/primary/basi3p08.png new file mode 100644 index 0000000000000000000000000000000000000000..50a6d1cac7a111d53cd3aec0d35dc4d09311baab GIT binary patch literal 1527 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4rT@hM&rf10vH$=SkfJR9T^zg78t&m7SF)I z%n;xc;;Q7r@b&-O^8e+h|Nj@{Vz4S_P*VE;U+}*m1A~$h!~Zp*Y5&vyr=|U8{I4X$ zaOeO3GyiA0xcp}b4OL=bIDPuRiwi^O|IpK?8H}YE{=d2N_W%DU|4;wFbI0YsOIq50 zV+IBnC5E?e|EHxf{9oeo|NpADZ$aAr{r~^>|G)qL8IAuNhiWk}GXC%A_|LFv6(b{q z3j;$(2gCm-r*}m&DE(JTGh+Dvf99%H|3euVR;^+~Lau^Z!ov9ftpRb}<+mGrVPZTg>qPf5%KO2EqUT%NZE{H#7dG<#RU+Mqqt^#7{= z|L@%S9~#QQz>s$54#ORWJI((Y%gg`&`}hC<|I`0NL(9t<{{3S(&2XB5;U6Ot10w^2 zkP^fH|4IxlF0=m||G%<|fgyC}%>OfIGVEg5r4`EX|MclC|I_}@Hva#A*D8ipP8|%v zs~G;TTE)QdmSNYf|NjLU{xL8xxG>C|Ig?@L|1&dpF)(y6bTHgu_&-^Rf#J@-|NmA6 zGn6xwGckg!WMDA<|Mow_E{6Zc#&7?>{ePrm&;N3URSaniX$(qAcNiEziRJ&D|J{NN z45t|w8ABOD89Epk7?c=6u0Q>jf#H8ghYN#C^e%?~d&>XM{Lhfau!N|b)-}wK|zRO7r3`~nWT^vIy=A>T8jNxXGVEbS$xN?HmluN#Ak~K9w zpRN$N^xi%1Y3(OYCWs&HY~+{y+a-TYvs@ zP@AjC>mCO{7)A-(GHaw*51VVSpjKfN-Ya&WVN+x3mrzuO}9eD>X#t^DFP*Ea*-(!7KfU)Gv; z-%$-(7wK_d)^w|)vxum%@$TKLSHFI3ZGH0O$z#V39Js!HtErKZ>e5wROiW(hZ{Kin zX=$H5TU+z#^U9Sc&z`-pW9`|iTUW1Mp`qE?)a2#0X_Ju9nzeiPh=@FT& zf%gvUE`H&M3VRxt7YN%O4qYH_!0UI2r-EVkL&Z5vzc@ZWw2^7Oy@5;bK-_}+AGq=k zM$KRo&;x9Ts2E zTEMS%(BKE(?}tWvm}jvYKV2Gj6DV4L@F}Qp@^tlcS?83{1OP?E&e#9| literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/basi4a08.png b/tests/pngsuite/primary/basi4a08.png new file mode 100644 index 0000000000000000000000000000000000000000..398132be5faadf83e159ac59c212213bcd43a894 GIT binary patch literal 214 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4i*Lm#&so4FBupZSkfJR9T^zg78t&m7SF)I z(Cg{q7*a9kZU0%WW&@t%^^J00uI+XFt?}*Pca38I4R4=pm6H)&B;**@HbX$_(tmd) zNh_g~cV{Nu^x#wB{@ma&XY-#03uiN*-1mWb;)^QZl|~c9D{Ra|mqr_uTw$=O&r{qP zxw}s9`!*dru?Imb(h4IS*)sOsTvdL4iK*-wgM0&4zYPaD{dSoBXy@(Y>UraD%PAWf S8q2`Iz~JfX=d#Wzp$Pz8b5P#^ literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/basi6a08.png b/tests/pngsuite/primary/basi6a08.png new file mode 100644 index 0000000000000000000000000000000000000000..aecb32e0d9e347ccdcab5d7fdad2dde7aef9da8a GIT binary patch literal 361 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`MwVKyBnAcsmUKs7M+U~W1%@xC#WOH4 zDtNj$hE&WsI@Qtduz`T<{H2aNc5g~^+`%@xO|IKl=-@%2gRWYITw19&9Ij58;P}Tw z?qt`antJY-RXpa_5sLud4s^WODKIZyUS^6r#g!w^tX|0Y26 zT*EECa0U(Or^X-70Z(lUMMUOuu3$ Q1_lNOPgg&ebxsLQ0Hr&SF8}}l literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/basn0g01.png b/tests/pngsuite/primary/basn0g01.png new file mode 100644 index 0000000000000000000000000000000000000000..1d722423aa5157fe2b029af4e2bb07f478ebe8bb GIT binary patch literal 164 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;IMg|53hG<6jNCpN5mUKs7M+U~W1%@xC#e;-B zT^vIy=IEZ;$jNNL!+P=cC6-NI3fxsD`4dEKnhy4ICAzW)etgiSzv|VcB`rDUR;mWG zJr6bs7kVVPNpZionys``v8rlZ_pMFy^0Q7EWa`b;Ow4FVdQ&MBb@ E0G9U~9{>OV literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/basn0g04.png b/tests/pngsuite/primary/basn0g04.png new file mode 100644 index 0000000000000000000000000000000000000000..0bf3687863d8a1f53bef0aa24b841b21b0e04d9e GIT binary patch literal 145 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I76t|ehRF|4XfiM`u%tWsIx;Y}EiimBEuMja z!Nb$VF{ENnazcWDNJx;8Sy>?`udlbZe!7A)!_?as9s3xx%AffZu>|Z~9X3(9;ndx| vvt<}V-pw?A!m*&}{XJE8hN-{b$x1RY$cwyVeD&Y)7sxJ8S3j3^P6;M1& literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/basn2c08.png b/tests/pngsuite/primary/basn2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..db5ad15865f56e48e4bae5b43661d2dbc4e847e3 GIT binary patch literal 145 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4kiW$hCdQ-7c($0u%tWsIx;Y}EiimBEuMja z!Nb$VF{EP7+p7mT84P%s99rK@{JXtK*xE(=%fcV$9%^slWwCDH68Rys;O&!Ip9+UY yCVsDW`9m%2A{rkSlvpUQbZFdNP`>y8W7Ec;ar_SFy%`u77(8A5T-G@yGywqXWH537 literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/basn3p01.png b/tests/pngsuite/primary/basn3p01.png new file mode 100644 index 0000000000000000000000000000000000000000..b145c2b8eff1f4298e540bfae5c1351d015a3592 GIT binary patch literal 112 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;IMrH;E2G1=owlgp=u%tWsIx;Y}EiimBEuMja zfi1u%#P!{OC8f0gIZ~I@7#J8tJzX3_D&{0VU}s`8dBiNRK$v+6AH!~W`-794(jpl^ NM!EXAtaD0e0sy9o9ZCQI literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/basn3p02.png b/tests/pngsuite/primary/basn3p02.png new file mode 100644 index 0000000000000000000000000000000000000000..8985b3d818e391502c4d05b93db26b046bc57bd9 GIT binary patch literal 146 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;ICT0c(20oEV=?n}EEa{HEjtq=#3k+XOi)Ub9 zU@ms@3}IwstkElPVqjq43GfMVW%$qVpMl~3e+CAI|Ec!cyBHW4lssJ=Ln`JZ|B&C+ y#n>YG!QjKmgA%J3=+yA6xb**rMDrP2hP|HkjjuZUq!}0(7(8A5T-G@yGywp>N-FyR literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/basn3p04.png b/tests/pngsuite/primary/basn3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..0fbf9e827b467d65dc252db937d6590478bbf88e GIT binary patch literal 216 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I7G?$phQ^Te;|vT8Ea{HEjtq=#3k+XOi)Ub9 zU@ms@3}InmDgUu`F#`jGZh%jSs}jS1hX4ON82&5$XJDB5|9=|8U55YV{~7)>Ffja| zc^Aak{eL$DgUf%0|1Os{c|G)qL8IAuNhiWk}GXC%A_|LFv6(b{q z3j;$(2gCm-r*}m&DE(JTGh+Dvf99%H|3euVR;^+~Lau^Z!ov9ftpRb}<+mGrVPZTg>qPf5%KO2EqUT%NZE{H#7dG<#RU+Mqqt^#7{= z|L@%S9~#QQz>s$54#ORWJI((Y%gg`&`}hC<|I`0NL(9t<{{3S(&2XB5;U6Ot10w^2 zkP^fH|4IxlF0=m||G%<|fgyC}%>OfIGVEg5r4`EX|MclC|I_}@Hva#A*D8ipP8|%v zs~G;TTE)QdmSNYf|NjLU{(({y!_1j88D{=JGjkUMLkB|#!yShIla&}4?)>}zZ&ffu zIYT)UBgjey2IK#4|1<1j_-}0d_W#@eM>_WWFK1ZAkj9Y4prmw%fdQ0Q{@?lEEy%!d znt_oqlp&O%gMooTi4o-b({C9V{&#e^Ft|kTV)(zO{Qu1V3~3Cz{_kQaFE4%za)>d5 zF$2S{|KYP*e7WcHxof>Jh>HEIjGY)+hc^3X_)AVI`ROOy9vK2Sa+jF#X zop7edNoSv@TGkc^Se2w-{_J4eboBvo^Gxz1wK`-XEWCTH0kwa_YOj@?dq zD!WMf_=?l>RhEc9wse+x#=ojyqBYM#1=-G9YZh6o+;OJ;%oB@^9r7nUGtU{d32jkX z_1TDf$I<6o)11ZJ ib5EXT`()5K>kfOP^gn_2X(t|l@~Wq+pUXO@geCy$l4ENC literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/basn4a08.png b/tests/pngsuite/primary/basn4a08.png new file mode 100644 index 0000000000000000000000000000000000000000..3e13052201c9f8b90172ea2491b18d6d121c2786 GIT binary patch literal 126 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4i*LmhMUEk>KPaqSkfJR9T^zg78t&m7SF)I zVCw1O7*a7O`Oobg1q zcNsU!ma@7tpJH3_lQ&`kyPv6?Qf)&_Q^;fK4Nm+qck~!46*?yUf3$$nY(cdH`xF}i lmYWQc0cH;MjM5(%f)u3Yi1F|6VPIfj@O1TaS?83{1OUh>I|2Xz literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/bgai4a08.png b/tests/pngsuite/primary/bgai4a08.png new file mode 100644 index 0000000000000000000000000000000000000000..398132be5faadf83e159ac59c212213bcd43a894 GIT binary patch literal 214 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4i*Lm#&so4FBupZSkfJR9T^zg78t&m7SF)I z(Cg{q7*a9kZU0%WW&@t%^^J00uI+XFt?}*Pca38I4R4=pm6H)&B;**@HbX$_(tmd) zNh_g~cV{Nu^x#wB{@ma&XY-#03uiN*-1mWb;)^QZl|~c9D{Ra|mqr_uTw$=O&r{qP zxw}s9`!*dru?Imb(h4IS*)sOsTvdL4iK*-wgM0&4zYPaD{dSoBXy@(Y>UraD%PAWf S8q2`Iz~JfX=d#Wzp$Pz8b5P#^ literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/bgan6a08.png b/tests/pngsuite/primary/bgan6a08.png new file mode 100644 index 0000000000000000000000000000000000000000..e6087387639b9cefaaafb696e29a8bd910ee0680 GIT binary patch literal 184 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Ea{HEjtq=#3k+XOi)Ub9 z$oF({45^s&_L?DAg8`4*L-mvl|ApV}Ls|M2kK8@#S|Jbg1q zcNsU!ma@7tpJH3_lQ&`kyPv6?Qf)&_Q^;fK4Nm+qck~!46*?yUf3$$nY(cdH`xF}i lmYWQc0cH;MjM5(%f)u3Yi1F|6VPIfj@O1TaS?83{1OUh>I|2Xz literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/bgbn4a08.png b/tests/pngsuite/primary/bgbn4a08.png new file mode 100644 index 0000000000000000000000000000000000000000..7cbefc3bff08a9d91666d6b0f8b5cb1c896b7987 GIT binary patch literal 140 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4i*LmhMUEk>KPaqSkfJR9T^zg78t&m7SF)I zz?9_e?!v&Zs#n>Ffq}u))5S5QVovg(^9K$vw$8~gF;tqPb6-+}S;xL@ALHUg11Yu; r!vqrn_rncZY&~p`G9&^HGcerOQm8%hy7dGD0|SGntDnm{r-UW|POm3( literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/bgwn6a08.png b/tests/pngsuite/primary/bgwn6a08.png new file mode 100644 index 0000000000000000000000000000000000000000..a67ff205bba91cc8f391a0b59110ae6c038539ac GIT binary patch literal 202 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Ea{HEjtq=#3k+XOi)Ub9 zU`z6LcVYMsf(!O8pUl9(knic@7*a9k?KMNL1_K_qhw3RA{tLg`hqCl59=UtewL&)N zMS#X1d0&m2U5o~C)pc|J?=o(dEoF6QKE<};CvU_8c0W@&rP_v=rjW1I!%i8Kplk1Sv?(5#!(C!@$76;OXk;vd$@?2>?IF BLDT>M literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/s01i3p01.png b/tests/pngsuite/primary/s01i3p01.png new file mode 100644 index 0000000000000000000000000000000000000000..6c0fad1fc982e54aea994e12efd3fe3584cabdbc GIT binary patch literal 113 zcmeAS@N?(olHy`uVBq!ia0y~yU|Vh}gLC&ZP3;eS`frEmrY1};w*$B>FS$q5V$3``7+9_yDBGB7YO Nc)I$ztaD0e0st9I8UX+R literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/s02i3p01.png b/tests/pngsuite/primary/s02i3p01.png new file mode 100644 index 0000000000000000000000000000000000000000..2defaed911a29507f745bd7183a9819b29cc53de GIT binary patch literal 114 zcmeAS@N?(olHy`uVBq!ia0y~yU|<4aMrH;EM*I5p9~l@JSkfJR9T^zg78t&m7SF)I zz+CL)8N$NCQvPG>Vh}gLC&ZQE|9{CCeN_eq25wIm$B>FS$q5XM3=C`xjQ@JlPcSer OFnGH9xvXzopr04MMnm;e9( literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/s03i3p01.png b/tests/pngsuite/primary/s03i3p01.png new file mode 100644 index 0000000000000000000000000000000000000000..c23fdc463170faf97e53fccb4799386700b21a15 GIT binary patch literal 118 zcmeAS@N?(olHy`uVBq!ia0y~yU|*t(d3fq^Z+C&ZQEKg0iWhK)~`&Szj?;PG^E45^rtoY26`&cNWq;CSog SGZ_X31_n=8KbLh*2~7aFy&XCL literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/s03n3p01.png b/tests/pngsuite/primary/s03n3p01.png new file mode 100644 index 0000000000000000000000000000000000000000..6d96ee4f873baf1df3652a8d70994eeea799c30b GIT binary patch literal 120 zcmeAS@N?(olHy`uVBq!ia0y~yU|*t(d3fq^Z+C&cwXL;3&z470vF?_^+L5b<%M_9s+ bfkAQ|3**lF=HD0?7#KWV{an^LB{Ts5@*p4# literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/s04n3p01.png b/tests/pngsuite/primary/s04n3p01.png new file mode 100644 index 0000000000000000000000000000000000000000..956396c45b5103d3c38dd8906be14002e5bee48f GIT binary patch literal 121 zcmeAS@N?(olHy`uVBq!ia0y~yU|<1ZMrH;EhROCkwjfTrqpu?aW7`757t`Vy7#Ns~ zojgNWSXjz`Y+cO2z`z#Z6XN=xq5S`UhFRa8cQPc Tv1$7@kR=SBu6{1-oD!M<4yYZo literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/s05i3p02.png b/tests/pngsuite/primary/s05i3p02.png new file mode 100644 index 0000000000000000000000000000000000000000..d14cbd351ac11022eefcfa3bb2af528c3aadae41 GIT binary patch literal 134 zcmeAS@N?(olHy`uVBq!ia0y~yU|Vg?2V&H$efSBC%p%NhRvXJBw#vZ|PYfkD#K#WAE}PI5*zopr05}vQ1^@s6 literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/s05n3p02.png b/tests/pngsuite/primary/s05n3p02.png new file mode 100644 index 0000000000000000000000000000000000000000..bf940f057678363347961bbc920a0603b500d70d GIT binary patch literal 129 zcmeAS@N?(olHy`uVBq!ia0y~yU|Vg?2V&H$efSBC%p%NhRvXJBw#vZ|PYfkDL6#WAE}PIAQ60|r|g g6P0GfTxDR;VrQMOuIGyv0|Nttr>mdKI;Vst0Izu?=l}o! literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/s06i3p02.png b/tests/pngsuite/primary/s06i3p02.png new file mode 100644 index 0000000000000000000000000000000000000000..456ada3200643ae917af3ea3f9fa0df7471c0660 GIT binary patch literal 143 zcmeAS@N?(olHy`uVBq!ia0y~yU|<7bCT0c(##c+teHj=SSkfJR9T^zg78t&m7SF)I zz+CL)8N$NCQvPG>Vg?2V&H$efSBC!#4CVj-GyGrd%9p{wz@X&m;uumfCpjY_BVh)^ u5k4MW9&HI52_=bTY6d0&Mq#=P43_8F;x!BYo?>8NVDNPHb6Mw<&;$UQjv_1o literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/s07i3p02.png b/tests/pngsuite/primary/s07i3p02.png new file mode 100644 index 0000000000000000000000000000000000000000..44b66bab9e4ff6f2af2bd2f8c3c0a95c3b28e45c GIT binary patch literal 149 zcmeAS@N?(olHy`uVBq!ia0y~yU|Vg?2Vo&cW^*Z&OV4FAjj|7T!e_%H3ec@6^ugQ};CV@SoEWQzj@ z4G$R)v$yf`te5;}{3p?a@sK@Fc(O#^8OBKr2Osk^hBp1|WME)m@O1TaS?83{1OO0m BEQSC8 literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/s07n3p02.png b/tests/pngsuite/primary/s07n3p02.png new file mode 100644 index 0000000000000000000000000000000000000000..6a582593d654c8d43aa8c8dfa8f6516e4f24c8c4 GIT binary patch literal 138 zcmeAS@N?(olHy`uVBq!ia0y~yU|Vg?2Vo&cW^*Z&OV4FAjj|7T!e_%H3ec@6^ugOsO>V@SoEK|E5rZ)K|E5rZ)^rXKHESQJCJy$Y2}BYWveiK$wAnfx*+&&t;ucLK6T1jwWaT literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/s09i3p02.png b/tests/pngsuite/primary/s09i3p02.png new file mode 100644 index 0000000000000000000000000000000000000000..0bfae8e45678282b23bed2760c0dbbd736be9df8 GIT binary patch literal 147 zcmeAS@N?(olHy`uVBq!ia0y~yVBiE{CT0c(##cY?i83%Su%tWsIx;Y}EiimBEuMja zfw|bpGlYeOrToX%#S9D#JOMr-t_=Sf7|Q?uXZZiWoZ){MLka@}gR-ZKV@SoE6yQl=W+?s7?k3hVotc4wfx*+&&t;ucLK6U3)F+w% literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/s09n3p02.png b/tests/pngsuite/primary/s09n3p02.png new file mode 100644 index 0000000000000000000000000000000000000000..711ab8245189b4d5118b4dcd49ef9771bf924fb8 GIT binary patch literal 143 zcmeAS@N?(olHy`uVBq!ia0y~yVBiE{CT0c(hPnUWH8U_Uu%tWsIx;Y}EiimBEuMja zfw|bpGlYeOrToX%#S9D#JOMr-t_=Sf7|Q?uXZZiWoZ){MLka@}gS@AUV@SoEt~BdN|9uUYUV`fx*+&&t;ucLK6T3N+;m} literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/s32i3p04.png b/tests/pngsuite/primary/s32i3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..0841910b72779aa7571cce45e56447eeb3de4520 GIT binary patch literal 355 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I7G?$p#&5ylfeZ``Ea{HEjtq=#3k+XOi)Ub9 zU@ms@3}InmDgUu`F#`jGdVo)eD+2?=e}-~~|NkKrL;3%55cB_kkVH91xE#d#x}VLO zfq~(Mr;B4q#hls+d-<9SMBMCM>mCK~khtEqQibn>+b%29!qt2_Z(15>t~Bmc`4F+~ zOPHpi+1crbcYc3n#vs%5_~eHt9&rzTeS6mRvc`SFiyi)EOb^Pk0%m7S+jzBb1@F~w z!J8tME%s3~h??;7_>prj-h4lENJF+mcWS~px6syA3r;mDsJwXK^Rh~-=>(<r~ZW zSP?6`>ePJ>wyw{YDK*KItm`+k<|}@5(THc>io!3fMsNNI%GR?kdh?+C#oEJFEk|6h xA6jbAvvkKlfgIH@t8EoG+}jjo{lC+^CFoMil($Ee85kHCJYD@<);T3K0RUiwmmB~9 literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/s32n3p04.png b/tests/pngsuite/primary/s32n3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..fa58e3e3f69b3ad3cf92d96bc17b030d0fafbcb5 GIT binary patch literal 263 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I7G?$phQ^Te;|vT8Ea{HEjtq=#3k+XOi)Ub9 zU@ms@3}InmDgUu`F#`jGdVo)eD+2?=e}-~~|NkKrL;3%55cB_kkVH91xE#d#x}VLO zfq|jM)5S5QV$RfydwCla1Xv%0GjtYmN>@c~`((DDoKssp(SYB#=ecymIN2m4LGs?0|-jX4ocjrd&+C}*+tDEYX(_&d2 zqpt}(;a1^}3A{TVVKNT08>- z19P#HX9x=mOZktjiy0Ug)B}7%Tp1V`{xg&_{QnQ37|Q>bgP8ySgCxp9!sQ^=*ZpkP z3=9n4JY5_^D(1xY8x|ch5OB3WX`pe0_0ECG!WC}f9tRok>{z~NS+MuYNz=}4)&6B- z*T6S*|7y``m2#&i?F-B2JtFGdC!r1B z)iSePk4UX%@|w!{n)8?O5=~x~zndjuS0+vmyAmlXeabas!5>|l!ku$|>dpDM<8ff| z@dN4BI$taVWqaafI{A(<{&@B^Tl{JMx~RoG+Erh+y16`CWi#7(t>8VIRZ%H$6>t_%ze{~5{|{{M$i4CVjJLCpXEK@#O4;c^h`>wY$C z1_p+Go-U3d6?0k1uK5NLb2{_@K&;Y-Y46f~VFXzY?xV3QY(4e##h>FsvAdcB}Q zX4Ppv-Q9b5v;__@FF7{pIdhFyev3c>*HYHQ7cT34-5?gNon`1hBUP9uHpj)>BFZ}a z)rNK1K99qXG(VcS`?2fC6Sjp*E1pQ1g|0IWoRYope~6yd%Gh0ET}L#9o`=XO#lD@ literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/s34i3p04.png b/tests/pngsuite/primary/s34i3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..bd99039be4a6c3a7a2a6048541436892bc4fd5ae GIT binary patch literal 349 zcmeAS@N?(olHy`uVBq!ia0y~yU{C^K7G?$p#{GF}=?n}EEa{HEjtq=#3k+XOi)Ub9 zU@ms@3}InmDgUu`F#`jGdVo)eD+2?=e}-~~|NkKrL;3%55cB_kkVH91xE#d#x}VLO zfq~(Yr;B4q#hlu{y`UU4~uWfe%P@$U}eQ$K5y5pEgZIj zyh^i{B}RC<%>LXnJ73rLj)0T%XREEL*QRMk&CDz^F*Wd;wJT_HHb-=<=ZT9~a#HdV zPfT?W+8-T1@#UwR)q$HA#0$B~F8XgK%9M1VKrL2h!TSK_>9L+?P4?KA{54*%Y*zsD pt)sD70mcHx`bM(t{}=pc_$c-NUDW*!O$G)A22WQ%mvv4FO#rn^k5>Qy literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/s34n3p04.png b/tests/pngsuite/primary/s34n3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..9cbc68b3b9d5f263eb64bca9ad8bdfeae8205f63 GIT binary patch literal 248 zcmeAS@N?(olHy`uVBq!ia0y~yU{C^K7G?$ph7*}$9~l@JSkfJR9T^zg78t&m7SF)I zz+CL)8N$NCQvPG>Vg?2V^#Gp`R|W=#{|w~}|NlcMhVuXAAm;!7Ac=C2a5;$ebw8Um z0|P^@r;B4q#hj_{TVVKNT08>- z19P#HX9x=mOZktjiy0Ug)B}7%Tp1V`{xg&_{QnQ37|Q>bgP8ySgCxp9!sQ^=*ZpkP z3=E7co-U3d6?0N2*sf~|5NSF7gE_GKdznK-GTe!eS~OtHJ)`)CBXEnK(xR*TrYX-}uD(pqMi)o7^Ow#AK2R!+QR?ffZQJ?=c- z!nDx7ZO8SUqO-l_r_gd?=mN%DchZy`l`{m%{!soV^ zW#5b6>x|p+@z%YxU5}h@9xgqmpUQuozd#|`@kyI%p{9_qM5%A$?1>hK!rXik*v0HU q60K!F@cMK{FFw~PE?fAI{X*Bfg|jn7_!t-%7(8A5T-G@yGywqb9HWK+ literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/s35n3p04.png b/tests/pngsuite/primary/s35n3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..90b892ebafc5b5318b2c4dd257eaca9377692ac5 GIT binary patch literal 338 zcmeAS@N?(olHy`uVBq!ia0y~yU{D5O7G?$phBx2WWic=?u%tWsIx;Y}EiimBEuMja zfw|bpGlYeOrToX%#S9D#>H$6>t_%ze{~5{|{{M$i4CVjJLCpXEK@#O4;c^h`>wY$C z1_p-Xo-U3d6?0NAD)Kcu2(&)DzGcd?8Q<7igeMd2}~OlRG8Z`JfU4_5z5h!l$vzuL3!{g2gFA)B$ zjGwA&S2Y&r-EGTvJ)82z_Ct!%H?})7d-l%$;gsw))%4t+@Qf#cDLh)t5AI92Eq=IB z?ZL*YpZxBJ7G?$p#uUx1whRmmEa{HEjtq=#3k+XOi)Ub9 zU@ms@3}InmDgUu`F#`jGdVo)eD+2?=e}-~~|NkKrL;3%55cB_kkVH91xE#d#x}VLO zfq~(sr;B4q#hl)Wd%2noMBMCe|GK>Wg;MNM&w~s11@126+L6gFUS3#GR>T)_;doY( z?;=m`wkMA(-tBc1>CoV?UVruDy^gTiKAvucUnbtRA6PBe0H#W*f3u>7&C9Dy!zMy0xmxxby4T*MVC$+Us;K;x))v)wW*yh{en1jrn&{H7q{5zE66;Abx+< xjg?vdn7481Bx>af>}D@5{kC#h)IUpmsTOg)-xBqQ7#J8BJYD@<);T3K0RSkyldb>& literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/s36n3p04.png b/tests/pngsuite/primary/s36n3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..b38d179774ce64d3da2a9c3ab1e8c0fc5ce54771 GIT binary patch literal 258 zcmeAS@N?(olHy`uVBq!ia0y~yU{C>J7G?$p24TI{)eH;_Ea{HEjtq=#3k+XOi)Ub9 zU@ms@3}InmDgUu`F#`jGdVo)eD+2?=e}-~~|NkKrL;3%55cB_kkVH91xE#d#x}VLO zfq|ji)5S5QVoq`bL*t=$snb@uFHm6?Q&c#5ph+*~Kmki^N26$L24l0HU zqO}sNoTln1vgtVGNE|a~xZC=UL&wkcQ9w9{$cq(D+zn1WE1Y=dtYVkA(9)nHw$SO2 v6PtvYQNqTFjSVg?2V^#Gp`R|W=#{|w~}|NlcMhVuXAAm;!7Ac=C2a5;$ebw8Um z0|Uc9PZ!6KiaDthtc98k1ls-!%6<%d!7Jl;z(+6PA!EjywJTm`1P5KZwRG90?I#(F zG|Z(x8T^!(bY|1(?a~R8F1R^&hzZZ_Wz4!)%Ttrb+PG_;MuLuj%uJmPv!BeFwm+-S z`<$k7hoI)h6^{>T+__+pCvp7m37!BBPT$EY1`5+eMTN~26BpRum>9FTJE~Yw>tRQj zM6Frgjs?rT;-y^#=G~aEd&<^pUwO+dZOSqXuY_$3k6-PZbL;xGYu+`%b}xR5@72`b zlfLKw%#Tabzx%xWpiseir%<(mGp0efvq*nyPzCpi=nGH1p3N#g>9$qGFI#u7g~&a= jozva!ulu|#sH$F8U1XN>M*GbS3=9mOu6{1-oD!M<%x#|Z literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/s37n3p04.png b/tests/pngsuite/primary/s37n3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..4d3054da516a3fc671bf5d2c4a401abe6886414a GIT binary patch literal 336 zcmeAS@N?(olHy`uVBq!ia0y~yU{D2N7G?$p2J;QJ1`G@gEa{HEjtq=#3k+XOi)Ub9 zU@ms@3}InmDgUu`F#`jGdVo)eD+2?=e}-~~|NkKrL;3%55cB_kkVH91xE#d#x}VLO zfq~(ur;B4q#hlcOx_r$J0&NfV7yABEf5678exrq3p^AY=u65n&wQG(%3R}PGcmV_7 z)tj12HyiWc6r3$kVeIf_(!82h&no4XhTsV{zxFLwE?uFO5_%|6#$XxSlrNn|g|6P` z_f3`3Ic;?OqxoaEikvJPj{dWndzWtuFSh!2J3CmdKI;Vst0FJ?lApigX literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/s38i3p04.png b/tests/pngsuite/primary/s38i3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..a0a8a140ad7ec7f78f5b8cb398f54233e790fe7c GIT binary patch literal 357 zcmeAS@N?(olHy`uVBq!ia0y~yU{C{L7G?$pMqQC3+zbp1Ea{HEjtq=#3k+XOi)Ub9 zU@ms@3}InmDgUu`F#`jGdVo)eD+2?=e}-~~|NkKrL;3%55cB_kkVH91xE#d#x}VLO zfq~(cr;B4q#hj%R?YWyAWZLHci*SrzO1d{{%@5^wkgijA6xSsymV8$=DW@HjY8JTm&YBgY^(h~ yJ^SC2vIn#BlbWROzMeW=v-)_I)7Vg?2V^#Gp`R|W=#{|w~}|NlcMhVuXAAm;!7Ac=C2a5;$ebw8Um z0|P^rr;B4q#hl~>hQ>qhQm3tQPf%etGgLTxph+?9Kmm($Pot=F4r8-co5Te!AH$ro z2(5&|Zmpe3JU5QqFnF86u#5k&?u|P=XQV9*7o5Iul&2x-PDav!9hwOa;>?p$x)Tlg jXYXx3srz696T_!W?dEf9TpltoFfe$!`njxgN@xNAtpHa- literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/s39i3p04.png b/tests/pngsuite/primary/s39i3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..04fee93eae400e745534756b48f5420cbe4a1d91 GIT binary patch literal 420 zcmeAS@N?(olHy`uVBq!ia0y~yU{D8P7G?$pM$WF92@DJjEa{HEjtq=#3k+XOi)Ub9 zU@ms@3}InmDgUu`F-UEIPlzi61H*rYa)$r^ArwRT|8fxX|9_A~IY_u1#QM6Q&6d%@#*r?y&0c}>l`8yLKE`9lV) zkT4-3j;DqPK5X6nUw=V$n(^Y0=4%N&B8z6a%+8$R5SSs@!}?U@=d`TvQCWXhmUVee z-M7K(vc*x;ueOf^`sB1;vF>`e__Kik_p7R4fdot0V~Qdnrr8H=MS7;(c)NvPm)BeQ z)e4)lvlbpY6R)>xjr`*~OYQv{N}IZbla8Irms2}pVf9+y{ZPwdC7%g8NB*64YT!oIY3a zc%GH~xtSkLQqR5JZF+yFz2CK(_wVYT)<65bm0!={Ro>dlzl=Q7OuzB`d-Q;Tfq}u( L)z4*}Q$iB}@Cvlw literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/s39n3p04.png b/tests/pngsuite/primary/s39n3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..c750100d55fbd07d216bcc5af538a83b9f7772a3 GIT binary patch literal 352 zcmeAS@N?(olHy`uVBq!ia0y~yU{D8P7G?$phPqxKHUgYe7^F79C&ZP3f#E+xIm7?|5Q?Gve>sTx|365g93)&0Vtw7uX3fCB zaMjbrF{ENn?j=ROW(R@RhwdJ;r$|*bw+T-uXyoE+IJo$Ng^p0?(S_j;4P_dfOVd1^ z)6?n`j!6A5Vz{Fr^+(d|BG+>nA@!&W+jwmkvAH(xnDBIl`k7Unl6%!B?+v_My4qE= z@9~YwKU)_s`LpBKg5`g9y!x={&knD>w{Oi)x%#bj-{o5`4HC?sven(nP1zpW^*3GL z`I}wJ^miJeZzhV{NqpOOabuFYPx!lM=Sot~Coj|f{UyQ5WOiQ0@1NpQ<}dgzGJoT% sdU`ScZPL?u`fquTuX@AdKTThHnW?Du|M|}t7#J8lUHx3vIVCg!07uM~i2wiq literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/s40i3p04.png b/tests/pngsuite/primary/s40i3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..68f358b822b92784fe065e4656061443a63795e1 GIT binary patch literal 357 zcmeAS@N?(olHy`uVBq!ia0y~yV9)?z7G?$pM$YR~PcSeru%tWsIx;Y}EiimBEuMja zfw|bpGlYeOrToX%#S9D#>H$6>t_%ze{~5{|{{M$i4CVjJLCpXEK@#O4;c^h`>wY$C z1_p*(o-U3d6?4}1ZRBb;5OH09G%EYIVC<6BDM2p+{;yc)$7o(!P$m@ES|EOW0e^PKW7tlvHLh?3y#}+T>k7J%yD2hR!?2 yxOVFtHAY2851A6q=8C)^+p`_nmt^;6#&L;d`4xPwu3%tbVDNPHb6Mw<&;$SlbdhcV literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/s40n3p04.png b/tests/pngsuite/primary/s40n3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..864b6b9673b3b331f2956ad2299b7854210cdb41 GIT binary patch literal 256 zcmeAS@N?(olHy`uVBq!ia0y~yV9)?z7G?$phPn$&;}{qiSkfJR9T^zg78t&m7SF)I zz+CL)8N$NCQvPG>Vg?2V^#Gp`R|W=#{|w~}|NlcMhVuXAAm;!7Ac=C2a5;$ebw8Um z0|P^;r;B4q#hkMjHu5$Y@VH!b?$S}5wji-1$JNYZzUm4icGhOW6$1ZUUwAxxbTZ6u zdC*pwl~;buNV+57?x5(_FL{w6HBc_wJZ?QV_uP7?SD(M%m{nk5zQtT?iB5a2(4%Dx u;ZDAC54rYO;5Fw0^?*2Pz`xgs7F zxBo6He?R|s+{`;x6*F}mi~O~>bAJ%KI4N>Xzp=->Ls>ghl8gVVwVro;F)jCcS$FlC zziSeX%ud}M_SL3*_UB?&VZo}NVksHJdp4mTv{=ro@$`xAan8PR_FkMbvvAO|N6Nd` zKX7gq>zY`&oY5u!!nD{|k9+@wIP$EGV<{4_;1K_kRBR!F0FcYI1HgJ^C0Jn3z%+ z7?Q#|!!$H%g1dt|JNwhq(^FGZV{>DLp9;6BspaeHx=eIQOiZ+%YwgnMVmsNEfnf>5 zX9k9k43UwM;o;$-p`pRS!6vOHfq{W4(^dTa{jIDV1q60&;^${L&cJY#;m@Bx42Kz5 zSf(=^WY8_w{q^e?!+r(^h75+i47aXa5fG^6T+8|6#}9^`3=G>D=FD06?b|n=g**(K z85lM)2uu`USk3V1()5elM~)mh!@zKvi>om^yTZws5TSy@R*Nl{TzK|#R`28O)6ysUz(sqf6mau@c8j#h6aX7Y;25-`6*$M3=AoLe%a^GpTB$e z0Ruzz$&)9=#2ghBBg4ZZU0f>m@8AFW?pwisqy(Q9a z)|w0P(b_8yr0sO5*?MoXsnu!AY@>r*T2rQHXWyUnX8)_|*J`U5Jv!3awRO^?^ev4E zwek@MxqsgLd{weGGXGRYX69An>vL_R!;f;Lth-hB!ZyP3T+Py*#!IG{1|0mPyRO~; zPV4(+NSvtpBYQLQFcvEK0p5T<}4hK)Yb#n}4(&b*r zwanE$XRE-RL#NN4)LpozV&kf7)4c7nj1M1XwOYWnOhxVO9jo^El*M}f<>z~jzAoQ0 z_1^6*tB*7+mRYsnamK5UYfmqGInV$8@pG59mb7nvk-jzdXz*;)#DgcdygxQ|uAh>0 z|NVQ{E}z|W=;zI&dwcIakKxn&AP z<)02mEEl;QeDhoFoHxtzPk%F$;|Qw!xl(GGLi+cqhmJH$&TA}xqyFXVjXl5boc{PL zHBZl-$;a`)zc1E`2mh5fzt4O0^xbX6s)?_YH~vdrnBH+CuKMk*e@B{sCRWb=QK7zb z$~)eCT`RTe*-ZfoWsg6x?tXmp`TOY4pE=)ue0eqB@@(j~kBUlgack{#D|}ge*5;dxu4md=+S1Fp=nlw2*VaGkw`g=LS z{fA@KH=brbSpBootbIm-7xTgHmuaFuo=8dv$vv2UoP~jR-T#Smr`|rmz`(%Z>FVdQ I&MBb@0P|^^UjP6A literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/tbgn3p08.png b/tests/pngsuite/primary/tbgn3p08.png new file mode 100644 index 0000000000000000000000000000000000000000..8cf2e6fb6aabf7c58efda0a953857b318607af30 GIT binary patch literal 1499 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4rT@h2A3sW#~2tGSkfJR9T^zg78t&m7SF)I z^eDh5#P$FG{|#YbTet35;p8-b{``#!3f-cjbLY;LmX4e~do}|@%gmWG`cYI1HgJ^C0Jn3z%+ z7?Q#|!!$H%g1dt|JNwhq(^FGZV{>DLp9;6BspaeHx=eIQOiZ+%YwgnMVmsNEfnf>5 zX9k9k43UwM;o;$-p`pRS!6vOHfq{W4(^dTa{jIDV1q60&;^${L&cJY#;m@Bx42Kz5 zSf(=^WY8_w{q^e?!+r(^h75+i47aXa5fG^6T+8|6#}9^`3=G>D=FD06?b|n=g**(K z85lM)2uu`USk3V1()5elM~)mh!@zKvi>om^yTZws5TSy@R*Nl{TzK|#R`28O)6ysUz(sqf6mau@c8j#h6aX7Y;25-`6*$M3=AoLe%a^GpTB$e z0Ruzz$&)9=#2ghBBg4ZZU0f>m@8AFW?p_!@hljQC0^40Z{^lb(PrY=tx#}JF&{Zxqq*r)<))^%E-*TYJ7dJZFKlij+Aw`>R#AJIG(Fny3=^c6w`o%pLEx? z``>BakvQ?WX|!P7!=JAVHk7P9RyF;w`Z-JISWE4fQyy>1tl1NsGTq_eskd&9flRvG z3%QoLy60>am~-g#*^{~p_f%|Lb#0orU6%3T!>m>dxR$A?y}e`A9-p#U&%gY9&(YWA zd#2vIy=C>0hQ%_g7Cg>)^>OX#WiRLX-#>ot($EvT$Z|OVl1~z zp{V@R;fUoTw}WqftDW;^S^nv7W^x=sl|NTXEmKJUKK0O%X32Stxik4V9{BggTJhk&^5*w>kDk7}tynejb@Il4$qUmvZp2l;z4h-%^UuV}**_}O zcTRc7o3Cr7Ha)v3K%wmMC)VAMZ$5t?{rNNJ`;RZL=371}*tJt?p~95owVNZqOubQ) z>{zFH{nF+6d@Lsm4Hl}be4c&go9aFS`oEt^+?j2QqZ)NzTaY0S=iA6VsviT}SGh34;rzh;VXIg(R zC%FG`top{&%m=G~R+_cXDDYxF*!?n1^v4rP2_d-$(~q+-@UHtmaqiUH2N)O_7(8A5 KT-G@yGywqIZJcZX literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/tbrn2c08.png b/tests/pngsuite/primary/tbrn2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..5cca0d621047cacf1637cf7d77e997d51cc6b15a GIT binary patch literal 1633 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4kiW$hCdQ-7c($0u%tWsIx;Y}EiimBEuMja zfvqISFPPy!2%1Mo*MdZnyxmBFf?%?1Zk71J1fOp5&k*_tzJHfEokCdi#+HaS+xNn`)-J9po|tF}M0FY)kyj)Lds z=H9z^@8rpo|0N3E-`l%w+qNxRwsdrKMAZK`aX)@pPR=&!ZS%y5^{f)|^6y{0I(7DJ zZ&z1POPgG2=~-jr%M4lytS4AjNiI8iaH01~8A+L%Z*Oh}F$M<*hp&&*)zsPK^D6o>@GsEA%e_y_Q`K5Hyy;F1N*sQ+S>j&Ds3F-_#K0R@(X9)Oqm;-6>#DHe*tlEaUr2c@893QdDD`= z;QzncqPY_%E<6<|Dk5^>Zjh7wp1#0u4<9~cWMoX*c;ou@@9*yJ{>)Hf`EusVZKB)W z1m|2&3ol){Ysr!&8#a76(kZ->`*z^oiRG(0ebi(+vRzAG`mPKKI?69&p)m1{x$$qQ7t707@3Ag= z^LFXlwQJcJp7fPZTAn@kwv}5^uu-UI@WPL4zJIZK92pQF5FZ~O9qn!I!m!G-pkRZK z*q*$*-w)(FD0gq2pXlN+W9rnJjEoZu3wG|TbbiXVh2j27hC_CWPoG?V)x5rB^MjDL zA>rZIFI;e7b}dzZAM)btY=5TB2TYY0m+R=k zre{N=r`qe6FAL8V9dm6EdCvZz{KvH)T(4VSFls4kiC**#5IVA8p=yIefuH=p%;@Ny z?d|gY)7eZ6d>nJ%dLC|=ZJxhN^KMB)NW-%Vq3o;Kty`U9<3k-nlomallRV+i$&@1D z$%S0=&xYmP6gu-TgK^T-&-Rk8Ssg6%J?ZJ=WhK^@54(!Q!toXYc;>sYoiyZa=RCE8ouD?*%znV)A$jI*m@8(u(7mFn@l2 zOuo;nH!?5x#BP>b?xR;mTwXwDoTEA`h5CBXC3DX#fu&p+d3VsG^Tn@*Z<#PQ)Kb* z+&RUZGTwrT=kMRX_U-8#@3e$eK0dx9BD3EV5Ayfz9qi%e(8z7`Oi zX5_ERw>w0 zxgz7p0>gXT^X1=){d)ZQ`T6+D8c+S*;`(thJBwPUnHgsEXg2rt^(~c&(MmYy=I*{V xO1D(p)^S?htFLnVjg5`JIMuFI&i_;TSG`W*PgdMqPf(q~;OXk;vd$@?2>{1W1`+@O literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/tbwn3p08.png b/tests/pngsuite/primary/tbwn3p08.png new file mode 100644 index 0000000000000000000000000000000000000000..eacab7a144cb54be28f7a5952a2fc63fd883766e GIT binary patch literal 1496 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4rT@h2A3sW#~2tGSkfJR9T^zg78t&m7SF)I zbU(l+#P$FG{|#YbTet35;p8-b{``#!3f-cjbLY;LmX4e~do}|@%gmWG`cYI1HgJ^C0Jn3z%+ z7?Q#|!!$H%g1dt|JNwhq(^FGZV{>DLp9;6BspaeHx=eIQOiZ+%YwgnMVmsNEfnf>5 zX9k9k43UwM;o;$-p`pRS!6vOHfq{W4(^dTa{jIDV1q60&;^${L&cJY#;m@Bx42Kz5 zSf(=^WY8_w{q^e?!+r(^h75+i47aXa5fG^6T+8|6#}9^`3=G>D=FD06?b|n=g**(K z85lM)2uu`USk3V1()5elM~)mh!@zKvi>om^yTZws5TSy@R*Nl{TzK|#R`28O)6ysUz(sqf6mau@c8j#h6aX7Y;25-`6*$M3=AoLe%a^GpTB$e z0Ruzz$&)9=#2ghBBg4ZZU0f>m@8AFW?p@(X5g zcy=QV#7XjYcVXyYmGxj?VCwR8aSXBOO-@)~RPjNJxBrdpvZHDKIy3jz9MGEmGw#%u zwT-^{%|F_%hQ=!~2c%xk`VlrSbHkcBF`D}htlGP`_VD7;*z?H=n+(_gn)Z52q}{AF z7viI}R~|^)=}@!v-egm&)0Wvr2f4JSOwZ1~Kk3c>SJki8Rxf&Vq_b=5q(|vn8WU>e zBMx%^y!rX6WNl>rsf^6btH#&o+D3;T_?YQf`-S0C4&UiNaH|NZ0VE^RGo-~1wdYwXeB*`|pHPi}dCZ0cM;CF%bA z_pV(&yXnx+n@9Kd-g_R$y{3gVb!&CeJ;CF?+v>KzwY<6eIs_g02a8W+?=pICHLD4VZRG_y5na(cp!d#3gGa)SF0 z$Et5U&3v%>XQf&Di~=v_gWWIFM1MSyln|18F#R|S1Mj;36X#C7eSm?1fx*+&&t;uc GLK6TSKA5Bc literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/tbyn3p08.png b/tests/pngsuite/primary/tbyn3p08.png new file mode 100644 index 0000000000000000000000000000000000000000..656db0989ad8403c040f91caa6d1a79d11713715 GIT binary patch literal 1499 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4rT@h2A3sW#~2tGSkfJR9T^zg78t&m7SF)I z^eDh5#P$FG{|#YbTet35;p8-b{``#!3f-cjbLY;LmX4e~do}|@%gmWG`cYI1HgJ^C0Jn3z%+ z7?Q#|!!$H%g1dt|JNwhq(^FGZV{>DLp9;6BspaeHx=eIQOiZ+%YwgnMVmsNEfnf>5 zX9k9k43UwM;o;$-p`pRS!6vOHfq{W4(^dTa{jIDV1q60&;^${L&cJY#;m@Bx42Kz5 zSf(=^WY8_w{q^e?!+r(^h75+i47aXa5fG^6T+8|6#}9^`3=G>D=FD06?b|n=g**(K z85lM)2uu`USk3V1()5elM~)mh!@zKvi>om^yTZws5TSy@R*Nl{TzK|#R`28O)6ysUz(sqf6mau@c8j#h6aX7Y;25-`6*$M3=AoLe%a^GpTB$e z0Ruzz$&)9=#2ghBBg4ZZU0f>m@8AFW?pDvqpOkJKXjv*Gk$q5ULDn4lO_P?=Rb~MdjXXgHz16s3x z#+}--w$V4g`A6H;(0C>0fYi%bKf>l^ZdfxXMsweRReSf=9$s7;dpDk%$C%xJKs`|Cs>P3%^bari>^eBBx zV?wQb#6j+#H$PvMtc}b+m64fw)%f~c+vxD494YH=)xEHda6DJDbf@u>DW(AjKk2S( z_rKG;BXQz$(`doEhd*B#Y$#cItZMpU^>dcav6k8|r##-2S+gfNWxB(`Q*YfI1DSNW z7ji9gbI?y1e@7KyDa0whgq!_a4l0&dwa*KJw9czo`3oIo};hJ z_e{Nad&}x04U1(~EqI*q>f_qe%U;g&zkmGPrL86Hn_r}FjXfGX+cfdu$t~}XO`Yqf zB;9}i-nGkTHy!$U^XT5*d(Y#z*R-&vZmll5CwSanbI z{z}c$b7%5#Jn-*}wc^2l<<0N&9zA_`Td`{5>*S69k{70T+=#1wd+Xnk=AVg`vwu{m z@0{|EH(%FEZF+W7fI`{hPprEi-+cZ)`txVb_a9$g&9{6|uxqE(LWL>EYd1%JnR=rp z*|ARZ`lZYB`B+XC8Z1;<`8@l~H`Sw}5?tI`JKYLj7N52GCZp?_cGh_RoR9<^wLMq9 zCO-~lUM$Y@LSez<7f+p>IX8;t-8-uK-pcSvSoMvknGaU~tTbz%QQ*aVu={12=#M9o5<+qhrXOcv;9d8B;@qjX4=^w=FnGH9 KxvX(h&YGo63J%Uly)CyTv5L1uhftcuO*)vax(gf2<3S#qEI-=O)UE-NguaMtpLjT=|?&TU=TyL#iUb!8!O zg*V?Qzdyir?#lG3(|*mIJ@a(mtsbSza4JeQ0(*uSi2Nf+nj-?LXIE?Bk7 zNZaPXabuxZ-RsUw+V{^hc)5S(`o^Y18Oeg2vD?*FGb*tvv<@?3QhK1}{w?#moefufX6-}xyHJASVJ9*aU zNuQsciw_VL%~aPurhQa9>AUo*gy^W6tnm9SyEd)ZWBK{nbQd;lkI&JS9+Dyln|@Vz zxfPVghh}D`9DK9$^CzXXDXm*$r?jv0OUYzsx;5fU6Q-?!uo>gtsjy{$C=50GT{H>iF{cEZc+#+4#0vGl4gguf~E>s;8@;%Q~loCIAkCP!RwC literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/tp0n2c08.png b/tests/pngsuite/primary/tp0n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..fc6e42cb420fd08ecd78340256157fa5f8a22934 GIT binary patch literal 1594 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4kiW$hCdQ-7c($0u%tWsIx;Y}EiimBEuMja z^`obYV~9uR*=gK9lfy-h|Cbk$I@2x{Folh$ZKA?f1Le*H<`ohGM*=jLPH|LHdhjCQ z#O2P`g;T;cr+ojd=s1^W`8md7>BFf?%?1Zk71J1fOp5&k*_tzJa+j+{yXkbyRI|?9 zXA)n1{{5Ze^FQZz_n7DWkY~)hzwhq#>*l7WUuQ9vzrUB8pYQMQ-`~^I!_DDQUSjj~ z<;~R>@5syk^>66x?0om`-JU&rUcAVtjJP2fe!a%n*mMC)P@~R*w!~SiO?jf`Spzq4rRo;@~-iVtgd+LS&&H>dRVDamDm8fQ}biP{{8!xEmKofRW&sHm=O`tw>VjI`fY|ejOUnZ4=5CH zW~9wv^7dZZ?A*4qQZ0Z{gt2I&g`QrY*riXmZbflT6f)p9FfefN|797OF6!qupLsr` z?19K>y0>?2by3-sl5L%nP{2KdrH--glHz^_5gzAi-+$AO9yt=Q<}-t`va;7wBXe_e zZEbB`U0+Fw8<}}^$8JTveP3^3Y56t(^pw-l+w{ zA3c8T?Ci|U#I$SIu4jzz?(TM9XKZXdb?2!=hn%dUt9~9_E%DY)NlD4TAV5Xv=g*&a zcNVA1IaFIjN|sG6n=@JFx>$JV%vD>qY+145#gC7VGr4aI&Yf6(sxw4uZt>g4kCi8% z{1OsaS7%o|@nC3z)F!@2PfyOPL8+;!k&%&pe&;T-zPYf_SyA!#o3~SC{4`I?ZQIWO z?b9dQvNtp27%Efj(=M`}IgoZ`*^V7EVuTm$+BJ)-d7jqPu7A_k8Mit)O5WdJzdvHn z`7>{_6Bt@T zLR@@(?C!G2h#jAP3Qc0Lo$GV$_U+em-u7@aXrALg@czT=7r8?Yu07N1*JS3% zlNH7E;b(g3!}*&wPp+)`6&33Y^x(d7t?B*Skx+;}8Hy}EE zYJqm?;%9S`C;ahTY9u_FlWYFriTU?r4n56cm^5|qvSo=PE9w}&&MKd@-OS!=M##(r z77O0nTG2JDLuLAf`d6*eN(xwX=qtVk$2YF}=G0HX@i*6MFZ z($8$KEUGp5sF0D!eMk9j_}rLQc}CF-ydsCfA6s897Znw~vc)FO+JH^w%ZD3hpMQ=t z6Wifoed3&6Bu_vD8$@}-#o9xqD80=c@u818`_{+h?6}55EN z5>Ma0efy+@;nt(o=7yZ_UcQXv`S9ao^4ZGX&6h0yI8?a!w0yKou303_q}6dX=~Zsh z1U@g7NvWspl=@@xS~eGJv&`Q$IqG4n zuO3-orsjKZ$Hn6Z8cwxM65g2TeCh0L``2GLD=0XJhpb(@HtOSo#+kgCeN&F~NnAOW zwDHE-v%SYRo0@+8^3AW}Lqd_FdN<>6xsdMzzU?KY#yj&$;Q; zvu$-d}Th7mY)8y?U$GLy&rFX>4&}wIg`e4T%Lh} Ofx*+&&t;ucLK6Ukyyy-9 literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/tp0n3p08.png b/tests/pngsuite/primary/tp0n3p08.png new file mode 100644 index 0000000000000000000000000000000000000000..69a69e5872234d96cab4cbb017a0933fbfedba81 GIT binary patch literal 1476 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4rT@h2A3sW#~2tGSkfJR9T^zg78t&m7SF)I zbU(l+#8pHjw;?QS>((7BoSf#*pTAK-p<7gR?%cW3(vh=g&t_m~nK^T2|MLFn)2C0J zI(72o$(ovB6DLk&V3^(C-`_p8TTgF!Z*Ok{14DOr_f7_e&dyFAo~sq5rS0wQ3=ErE zTU(bhFx+EcXl!h(udiodm{(g{%fN85y1KfuveMiwR~M&mx(TkiHX*8tz9}@Y$w|?Ff3vC z%)s!GAu=*DJUl!!G&DFk*re4YFfdSMx{ANQzm=7vfWWRz{QL~Z85oW-{Q2{T;V=UW z%XEf=47%mIzkdB<*w4VgkioE*;ntNa0s_^XYdL@X_`$G~fnhttoH+}>ef!34zIOS{nKP3a7#3@39XodH$dMyw7#J>daW!UVSJ>GxGv_ie%;(|? zb93`>bo4EbjSXaHU$J7v+qdr*ELbpa-n=<;<}fhqoHc9KCI*HXGiJPIV3;;-+B^n^ zDO08h3(HKJG-<+w34MKi3=9*yy1F_#I?5K6wRW_&wY9ahv{dl(H#IfYHPzMC)z#G0 zR8>`Z9q=kED=R4}DJm)|C@7f0z>t@hmsOBem6n#3mDR$);IhcYdzyD*N@7w{62lh; ziy0O%F)>k5Q4G%*n3!UnDxAW?!WbAn=uOdc&u}+1OklXd5EK*?5D>s{jzMvT;{X5u z8BQ?x`1t(&`qf6mau@c8j#h6aX7Y;25-`6*$M3=AoLe%a^GpTB$e z0Ruzz$&)9=#2ghBBg4ZZU0f>m@8AFW?paMMNwrg|x z>s1nsXF_lD?`79MF>}31dE1mtY+4cfj(+{nSuJ3$^J!0-_91-;cI_aL9 zR=k&BTME+KmX93bLHvFcQZFu{O#L*sd{$VREdHq&Y~qUzP9^HZ<^fw{POpW z$X(Ok6^Q*^vu$-n*5)*Z5XQ^BQZW{K<2Ja{N*+gp%5WO6GXB2&zJ=xYecpY$JE!l?Z-3#s zuK(z-{?>Vli>lvl&HgRS|E&FK?xV+Zp9JkP-?O#DQSUm-LWeiUo^qER-+cc5_Giz9 z?>)Y}`hL-Yhb6_PPL3M=ztc9q(BAm-Sks@NbxW7q%W_P5oZ#eHbpHB`x87aa1|ni1 zMZJ$MJ)d>*gN&|k+F9fMb3zhy)b?EYn*2DJd9k=er`dwXFP=I%b8ZyPyLVLez12q5 z-=A_7yVJbaSUw3|BHCpeAM<{eeg3wU#~-eneB%=7wI2@DK(Tx?GAUE4W>fq{X+)78&qol`;+0CRJJS^xk5 literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/tp1n3p08.png b/tests/pngsuite/primary/tp1n3p08.png new file mode 100644 index 0000000000000000000000000000000000000000..a6c9f35a86271c056e955f637a8769381eb03827 GIT binary patch literal 1483 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4rT@h2A3sW#~2tGSkfJR9T^zg78t&m7SF)I zbU(l+#P$FG{|#YbTet35;p8-b{``#!3f-cjbLY;LmX4e~do}|@%gmWG`cYI1HgJ^C0Jn3z%+ z7?Q#|!!$H%g1dt|JNwhq(^FGZV{>DLp9;6BspaeHx=eIQOiZ+%YwgnMVmsNEfnf>5 zX9k9k43UwM;o;$-p`pRS!6vOHfq{W4(^dTa{jIDV1q60&;^${L&cJY#;m@Bx42Kz5 zSf(=^WY8_w{q^e?!+r(^h75+i47aXa5fG^6T+8|6#}9^`3=G>D=FD06?b|n=g**(K z85lM)2uu`USk3V1()5elM~)mh!@zKvi>om^yTZws5TSy@R*Nl{TzK|#R`28O)6ysUz(sqf6mau@c8j#h6aX7Y;25-`6*$M3=AoLe%a^GpTB$e z0Ruzz$&)9=#2ghBBg4ZZU0f>m@8AFW?p@(X5g zcy=R=fq|*Z)5S5wqBl8Vfl9OJmO`Cu}lY|7+UoEs=J!)?A2>)?RraZKp%c z)_apptxj8J8y)1*nle2*`~IXi`(IVRR$IO3(UH!st&<+5Z)r@Zm5(^c{qyGMtCF>m z`KK~6Gp`z7pKBW(ev~6+-L1M8wh@l!YL@OaUNXfr;NU0Sb?yFlns+2ld~O;oSoiSf zD}xOsE00x8KdgSv(mB>r`{k6!n=)(m1gA`QIC$!?M^NR@l~T(T(!WnVbfj5wUSs(i^)Fv7?^v7SRd3x?lK8^?eeX&+N z_^-VAecq#|?`|trO?;ia@n7=7^o|>G)o*Y8JJS3!v2ym03iX{+-tp$^TB%LXZVFH+ zd;E!Y_v4$--$#G`%=!M~%d7d84+?helv=1T<#_Gp$S+fG)FeCBXLn2 zlQZW=(Y$*{Ro`0~K51M~6MbUQO`&YQO3}>Lq{-YtTn v?K29zm=AWpOcVX_L{dUX?!olqEDXHs{!g4c_4WY<1_lOCS3j3^P6*avYFgIvH_5n(1I4kPrtXn@*Ai0lqAM=~`{$FzXTrh_d&!~yk9M~(xU jm=5*ig z1Fx75|M*Ye%~9fszCQo5t4q`SCAPs{TY`6P`~0syE$-_6FLtxJB`c;~XlT`7e`4wE zcd_%@0#3cZa~SR)TiOa-OWl9^Y|vb z+QuicYa#R8b+Hqp!dW9qD%ss)Z#2eEUvpw9Kl2_dd4>x!CmB|)PnmHqMlk3rr-xi3^ zsS0r2E+_cm(o5+tR^`o&erqz;Y-Xw}^*Z45y?@VzxytKH{auyr$|zjTmDVUZ%w`oE zJuxbrHKODvn_KLT#@Oj0PcBVojH{J%xS+0F{AK^d%wHRnmi^;Zczu_x=I>6&j=E5h drOZDWLMQv>83rBHVPIfj@O1TaS?83{1OVwOR=WTI literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/z09n2c08.png b/tests/pngsuite/primary/z09n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..5f191a78ee5601a45f1add2a3ad7a77b7b1ae0f1 GIT binary patch literal 224 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4kiW$hCdQ-7c($0EcbMA45_%a^`bXlgMt9_ zg;^U8{FWCh+hJHIkZ30xt}^NRg}k*3nM5@#`0rMJ@-EU{sPyUdLPp6GoT>rr-xi3^ zsS0r2E+_cm(o5+tR^`o&erqz;Y-Xw}^*Z45y?@VzxytKH{auyr$|zjTmDVUZ%w`oE zJuxbrHKODvn_KLT#@Oj0PcBVojH{J%xS+0F{AK^d%wHRnmi^;Zczu_x=I>6&j=E5h drOZDWLMQv>T@&2*m4ShQ!PC{xWt~$(696UISR()c literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/basi0g01.png b/tests/pngsuite/primary_check/basi0g01.png new file mode 100644 index 0000000000000000000000000000000000000000..96ed62dbed7614edfd0d3cb58b1713c0a067eb9c GIT binary patch literal 391 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Ea{HEjtq=#3k+XOi)Ub9 zU`z6LcVYMsf(!O8pUl9(aLUugF(l&f(dmwSEe;$kv(NtffBMbIBcW3ms}9UA^f6U^ zq_Jw1gp~`+d{2vpnGEbTDhDL<*aRltUUcFs$DXSPf?rHy$Uk<6LG-Cy&F;pj4{kH9 zi4x8hsxq%WZ2alO3${gnlh`c6SFGAzEH)=g!FG;B{NYpCQDy;+)0smaE@j}cV5qtI z;YGBN*@0CysR~T{*V#Vn+^zU>l}(BQ^Y$vmtIWH#;*Ad6>1e4=D1W-1P2xide@SSb zRKkJF(v#ku`p@KZkkNsm=kGk`1N{Ee4HqfC+`O8BfkCyzHKHUXu_V0awz{OwQLo@=H!LH@~3VG+5$ z7ZE|PgasGQyHgfkJJn92jncwkKL8ZXJBAZEpd$~Nl7e8wMs5ZO)N=eFfuSS(KR&EH8c(} zGPW|Xv@$f(HL$QUFev1?u8N`|H$Npat&+je($YfLz(m);G{nfr%D~9V#7x(~+{(Zp U@8_Q@3=9kmp00i_>zopr04@Jou>b%7 literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/basi0g04.png b/tests/pngsuite/primary_check/basi0g04.png new file mode 100644 index 0000000000000000000000000000000000000000..2efd4876b56cb502102b73a24c678199e64f646d GIT binary patch literal 252 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Ea{HEjtq=#3k+XOi)Ub9 zU`z6LcVYMsf(!O8pUl9(VDIVT7!q;#?WK*p3<^BVj?EDYzxla!g;~0ar@veB$756R z+Ete-&)diyc=c~5+dk$D1_x#aDTWIS4Qvc13)!ag8WRNi0dV zN-j!GEJPDCD`WilQMmKP5A*lEKi@(n8n3 nMAyJH#K_3Xz{twPLf63D%D}+xSbHY}0|SGntDnm{r-UW|!O2MY literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/basi0g08.png b/tests/pngsuite/primary_check/basi0g08.png new file mode 100644 index 0000000000000000000000000000000000000000..23952137c9a6eff813346fa4db89480e77c87880 GIT binary patch literal 293 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Ea{HEjtq=#3k+XOi)Ub9 zU`z6LcVYMsf(!O8pUl9(km2d#7!q;#?X``(42nF=4$_8fPH*f*llnA%zWXZtKtE>5 zIa5C$23Mg~FSB)T7BTY}G^os&85$bkd%ybhH0gu``V4c5PbGN><*ePwFOksjO?G~< zieXK@qstBucN>3?;kx4=s`=&g6#l0u^G*n1U|>)!ag8WRNi0dVN-j!GEJPDCD`WilQMmKP5A*lEKi@(n8n3MAyJH#K_3Xz{twP bLf63D%D}+xSbHY}0|SGntDnm{r-UW|%->p4 literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/basi2c08.png b/tests/pngsuite/primary_check/basi2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..64ef3f844312534c6c9dc0643ef8df95f07fb676 GIT binary patch literal 274 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Ea{HEjtq=#3k+XOi)Ub9 zU`z6LcVYMsf(!O8pUl9(5bEjT7!q;#?UjwZ2MlKC z_#B*~W~O96Wn$s*IKim#E&UWThk(L^zsyJf`BXA6GO^UuGh90LCU0#_Lqj~nxxL$~ z+W7mQ{fm4Z*K>e@fkCyzHKHUXu_Vr3W%B4PG%Y zM6b%~O!}%C!oa|wTH+c}l9E`GYL#4+npl#`U}RuuqHAcRYiJx|WNc+%X=P}nYhYnz zU{J_&T@^(`ZhlH;S|x*_rKN?gfr+kxX^4@Lm4T6!sfDhAxs`#zr<`_i1_lNOPgg&e IbxsLQ0Pnd_Pyhe` literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/basi3p02.png b/tests/pngsuite/primary_check/basi3p02.png new file mode 100644 index 0000000000000000000000000000000000000000..c911ea9cc2d8793dd5be36477cf563ef6f592650 GIT binary patch literal 286 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Ea{HEjtq=#3k+XOi)Ub9 zU`z6LcVYMsf(!O8pUl9(km%{+7!q;#?KDTO1_J?R^?(1*f6OWtT)ByT^YLj1Cggat zm`yiq`kF9v2kT7PzXv~vI9LSTI`d^^-JM3J6C0WH_kXtjyMvi^g7MM*|NpM^TL&;~ z<^LnMpmqVnTV~b_d5r^{?N4mfFD#c{%D}*&TH+c}l9E`GYL#4+npl#`U}RuuqHAcR zYiJx|WNc+%X=P}nYhYnzU{J_&T@^(`ZhlH;S|x*_rKN?gfr+kxX^4@Lm4T6!sfDhA Yxs`#zr<`_i1_lNOPgg&ebxsLQ0E$Rp6#xJL literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/basi3p04.png b/tests/pngsuite/primary_check/basi3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..750ef69dc5a1f1433a83616453aa1144a11f8ea5 GIT binary patch literal 331 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Ea{HEjtq=#3k+XOi)Ub9 zU`z6LcVYMsf(!O8pUl9((C6vm7!q;#?ev4Z4F){SvR6EegLR#RopF!N|H;Zc_<6OG4c-TLY_N zF`se=hO+88jTdKbPT0lFq_Np}{q^%Q0u7fk7e9byXA%x%nxXX_X9ymX;Q}1}3@&rXfZ~Rt82^rWU#e=2iv-B8~X24;@KH)70%qH5y}{F%$4av z-{~v0j15eA0jm_vc{Vt_Jk5}!?!Z(d_rT_S!tY#$aM2GtZBIGB7;}9cbD+5a_LnB=S3o8SILZ0iYC>nC}Q!>*k84N8gEp!b`bPY^HjEt-djI9ie bbPdd{3=BTn?PX?QU|{fc^>bP0l+XkKp+St{ literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/basi4a08.png b/tests/pngsuite/primary_check/basi4a08.png new file mode 100644 index 0000000000000000000000000000000000000000..1b7b3a5821bc99816cb5508e544986596a951e51 GIT binary patch literal 263 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Ea{HEjtq=#3k+XOi)Ub9 zU`z6LcVYMsf(!O8pUl9(;N|J!7!q;#?WKiW3vm?&aVU3SpJF4>a+5(az|6t_0Nb4)1*tiL+Fq^<3=FCzt`Q|Ei6yC4$wjG&C8-QX z28JfOhDN%E#vw+=RtA<>=o*-Y7#Ud^ c7=tyKTNxPGPT4z`fq{X+)78&qol`;+01$>-vH$=8 literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/basn0g01.png b/tests/pngsuite/primary_check/basn0g01.png new file mode 100644 index 0000000000000000000000000000000000000000..20f6404a201c49da0a7118c9484403cbb606132b GIT binary patch literal 391 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Ea{HEjtq=#3k+XOi)Ub9 zU`z6LcVYMsf(!O8pUl9(aLUugF(l&f(dmwSEe;$kv(NtffBMbIBcW3ms}9UA^f6U^ zq_Jw1gp~`+d{2vpnGEbTDhDL<*aRltUUcFs$DXSPf?rHy$Uk<6LG-Cy&F;pj4{kH9 zi4x8hsxq%WZ2alO3${gnlh`c6SFGAzEH)=g!FG;B{NYpCQDy;+)0smaE@j}cV5qtI z;YGBN*@0CysR~T{*V#Vn+^zU>l}(BQ^Y$vmtIWH#;*Ad6>1e4=D1W-1P2xide@SSb zRKkJF(v#ku`p@KZkkNsm=kGk`1N{Ee4HqfC+`O8BfkCyzHKHUXu_V0awz{OwQLo@=H!LH@~3VG+5$ z7ZE|PgasGQyHgfkJJn92jncwkKL8ZXJBAZEpd$~Nl7e8wMs5ZO)N=eFfuSS(KR&EH8c(} zGPW|Xv@$f(HL$QUFev1?u8N`|H$Npat&+je($YfLz(m);G{nfr%D~9V&_dV1+{(b9 UOs(@R0|Nttr>mdKI;Vst038EaivR!s literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/basn0g04.png b/tests/pngsuite/primary_check/basn0g04.png new file mode 100644 index 0000000000000000000000000000000000000000..166e7db2193ad12dc53cc431d58a9cf93b036ebd GIT binary patch literal 252 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Ea{HEjtq=#3k+XOi)Ub9 zU`z6LcVYMsf(!O8pUl9(VDIVT7!q;#?WK*p3<^BVj?EDYzxla!g;~0ar@veB$756R z+Ete-&)diyc=c~5+dk$D1_x#aDTWIS4Qvc13)!ag8WRNi0dV zN-j!GEJPDCD`WilQMmKP5A*lEKi@(n8n3 nMAyJH#K_3Xz{twbLf63D%D|vZt@AAd0|SGntDnm{r-UW|z|lza literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/basn0g08.png b/tests/pngsuite/primary_check/basn0g08.png new file mode 100644 index 0000000000000000000000000000000000000000..192c79215ae03f39ab41ad54737c2abb06da0c3e GIT binary patch literal 293 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Ea{HEjtq=#3k+XOi)Ub9 zU`z6LcVYMsf(!O8pUl9(km2d#7!q;#?X``(42nF=4$_8fPH*f*llnA%zWXZtKtE>5 zIa5C$23Mg~FSB)T7BTY}G^os&85$bkd%ybhH0gu``V4c5PbGN><*ePwFOksjO?G~< zieXK@qstBucN>3?;kx4=s`=&g6#l0u^G*n1U|>)!ag8WRNi0dVN-j!GEJPDCD`WilQMmKP5A*lEKi@(n8n3MAyJH#K_3Xz{twT bK-a+B%D~{X+ks351_lOCS3j3^P6KC z_#B*~W~O96Wn$s*IKim#E&UWThk(L^zsyJf`BXA6GO^UuGh90LCU0#_Lqj~nxxL$~ z+W7mQ{fm4Z*K>e@fkCyzHKHUXu_V`_*f literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/basn3p01.png b/tests/pngsuite/primary_check/basn3p01.png new file mode 100644 index 0000000000000000000000000000000000000000..77c580b00ae6c173933e5f6f8ae3fd9d50c7cc26 GIT binary patch literal 273 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Ea{HEjtq=#3k+XOi)Ub9 zU`z6LcVYMsf(!O8pUl9(5aQ|L7!q+fx#oNPOM7M^1JC{4XHqSUgJ(8Q`{cvJ%;P3| zV8xVg@~XTStj=A0%5KBrCVRjlim#`Fy=NNpVm=97b~jmrD83%6ge@`>r3W%B4PG%Y zM6b%~O!}%C!oa|wTH+c}l9E`GYL#4+npl#`U}RuuqHAcRYiJx|WNc+%X=P}nYhYnz zU{J_&T@^(`ZhlH;S|x*_rKN?gfr+kxX^4@Lm4T6!v4O6Exs`zd`egLR#RopF!N|H;Zc_<6OG4c-TLY_N zF`se=hO+88jTdKbPT0lFq_Np}{q^%Q0u7fk7e9byXA%x%nxXX_X9ymX;Q}1}3@&rXfZ~Rt82^#s<0u=2iv<>~9WyXJBAp N@O1TaS?83{1OTM3azy|D literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/basn3p08.png b/tests/pngsuite/primary_check/basn3p08.png new file mode 100644 index 0000000000000000000000000000000000000000..0fa8195a519cd76f16124af9ef071f4341235d9d GIT binary patch literal 387 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Ea{HEjtq=#3k+XOi)Ub9 zU`z6LcVYMsf(!O8pUl9(aLm)iF(l&f+vywm4jJ&coYxTAVEO<5#8jsZOV&J5db*)u zmBRgL^XBfeTBSUjQF~sg!}@!z6Yn0_6i`=q&i>-B8~X24;@KH)70%qH5y}{F%$4av z-{~v0j15eA0jm_vc{Vt_Jk5}!?!Z(d_rT_S!tY#$aM2GtZBIGB7;}9cbD+5a_LnB=S3o8SILZ0iYC>nC}Q!>*k84N8gEp!b`bPY^HjEt-djI4}J bbPdd{3=BRme)5EYfq}u()z4*}Q$iB}wKtAb literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/basn4a08.png b/tests/pngsuite/primary_check/basn4a08.png new file mode 100644 index 0000000000000000000000000000000000000000..d4e0a72898577ad612ca2fb9122d23dcc3ccbe82 GIT binary patch literal 263 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Ea{HEjtq=#3k+XOi)Ub9 zU`z6LcVYMsf(!O8pUl9(;N|J!7!q;#?WKiW3vm?&aVU3SpJF4>a+5(az|6t_0Nb4)1*tiL+Fq^<3=FCzt`Q|Ei6yC4$wjG&C8-QX z28JfOhDN%E#vw+=RtA<>=o*-Y7#Ud^ f7+IMZ=^B_@85qpkcH=k$0|SGntDnm{r-UW|93EVF literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/bgai4a08.png b/tests/pngsuite/primary_check/bgai4a08.png new file mode 100644 index 0000000000000000000000000000000000000000..23ec6ae53045bcfd2dd8a13cb735e745398c8119 GIT binary patch literal 263 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Ea{HEjtq=#3k+XOi)Ub9 zU`z6LcVYMsf(!O8pUl9(;N|J!7!q;#?WKiW3vm?&aVU3SpJF4>a+5(az|6t_0Nb4)1*tiL+Fq^<3=FCzt`Q|Ei6yC4$wjG&C8-QX z28JfOhDN%E#vw+=RtA<>=o*-Y7#Ud^ f7+aZ|=^B_@85sCZoL<7fz`)??>gTe~DWM4f4eVQZ literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/bgbn4a08.png b/tests/pngsuite/primary_check/bgbn4a08.png new file mode 100644 index 0000000000000000000000000000000000000000..1086ccc09b46ecd656fecd5d459c657c15d5ae05 GIT binary patch literal 263 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Ea{HEjtq=#3k+XOi)Ub9 zU`z6LcVPg7pU%7M85kJ6JY5_^A`ZX3w2+IzfW!5oxxtzL|08nOtzW|vx3kI7U{1mH zGai@rnaO`&Kfhcn&=uD=^7e`7#Uj`SXvnx=^9vA85k7uTvtWWkei>9nO4bQXlZGo oYha>lU>ag%WMyD%Wn!UgU~Xk#aFONBc8~`=UHx3vIVCg!0M9&3#{d8T literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/bgwn6a08.png b/tests/pngsuite/primary_check/bgwn6a08.png new file mode 100644 index 0000000000000000000000000000000000000000..03a0a303d69431d20dfc9d6c7e4ed346303eb62e GIT binary patch literal 298 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Ea{HEjtq=#3k+XOi)Ub9 zU`z6LcVYMsf(!O8pUl9(kn8E<7!q;#?KMNL1_J??i~2r^eha_bhqCl5uG!n$`$5-i zg3^RXhLVT$j&g0V`&MCDUz*;+TiUvpF_rlXivm?&aVU3SpJF4>a+5(az|6t_0Nb4)1*tiL+Fq^<3=FCzt`Q|Ei6yC4$wjG&C8-QX z28JfOhDN%E#vw+=RtA<>=o*-Y7#Ud^ f7+aZI=o*+?85qc}d!xy~z`)??>gTe~DWM4f4WwIf literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/s01i3p01.png b/tests/pngsuite/primary_check/s01i3p01.png new file mode 100644 index 0000000000000000000000000000000000000000..45f8c619fbaa84ad42c52c0e5a6127e55dac7004 GIT binary patch literal 202 zcmeAS@N?(olHy`uVBq!ia0y~yU|cpt7I^=w6xGQFwr$I k4KXsZGBCC>w9qv$w=yu8`Q*`M1_lNOPgg&ebxsLQ0KwojlmGw# literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/s01n3p01.png b/tests/pngsuite/primary_check/s01n3p01.png new file mode 100644 index 0000000000000000000000000000000000000000..a79ac1b08b251c83b182be308d794df8cfc6f52b GIT binary patch literal 202 zcmeAS@N?(olHy`uVBq!ia0y~yU|cpt7I^=w6xGQFwr$I k4KXsZGBCC>G}AROw=ys|d3$Cb0|Nttr>mdKI;Vst0KBX)! zag8WRNi0dVN-j!GEJPDCD`WilQMmKP5A* vlEKi@(n8n3MAyJH#K_3Xz}U*jK-a+B%D_OSWpy|M0|SGntDnm{r-UW|5BD{q literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/s02n3p01.png b/tests/pngsuite/primary_check/s02n3p01.png new file mode 100644 index 0000000000000000000000000000000000000000..3b813c457e04e56fb7fcb06afbd5f89bd7df6935 GIT binary patch literal 210 zcmeAS@N?(olHy`uVBq!ia0y~yU|<4a4mJh`hN5k}Dhvz^Ea{HEjtq=#3k+XOi)Ub9 zU`z6LcVYMsf(!O8pUl9(AnNJj7{YNqIpxRy|Mtwx%*?{fA`A?=oXm`U4}QO9U|>)! zag8WRNi0dVN-j!GEJPDCD`WilQMmKP5A* vlEKi@(n8n3MAyJH#K_3Xz}U*rOxM8N%D~{{?U{WH3=9mOu6{1-oD!M|eMALcW1&5)3gkoXtwV9|5Jh@q;EwPMO` zW;+H32GtVRh?11Vl2ohYqSVBaR0bmhLla#?BV9w|5F=wN14}DIBV7XvD+7Z|eMALcW1&5)3gkoXtwV9|5Jh@q;EwPMO` zW;+H32GtVRh?11Vl2ohYqSVBaR0bmhLla#?BV9w|5F=wN14}DIBV7XvD+7ZEal|aXtCZ|M?H?nS~OP5KCI*SaY#$|c zvZgXHFsPQeMwFx^mZVxG7o{eaq%s&87@FuB8tEDuhZq@K8CY5w8tEEXSQ!`;@?2L% z(U6;;l9^V?U}$M+p=)5GYhW5;WMpMvY-MDiYhZ3=V4%{nI-G%lfx*+&&t;ucLK6Vr C$2^h% literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/s04n3p01.png b/tests/pngsuite/primary_check/s04n3p01.png new file mode 100644 index 0000000000000000000000000000000000000000..55c63df538fe892122a820840017a89ccfa18ac9 GIT binary patch literal 221 zcmeAS@N?(olHy`uVBq!ia0y~yU|<1Z4mJh`hLs=Z)qyzaj=qizjBN`HUrdWEal|aXtCZ|M?H?nS~OP5KCI*SaY#$|c zvZgXHFsPQeMwFx^mZVxG7o{eaq%s&87@FuB8tEDuhZq@K8CY5w8tEEXSQ!`;@?2L% z(U6;;l9^V?U}$M+p=)5GYhW5;WMpMvY-MPsYhZ3=U~uyG%svJN1_n=8KbLh*2~7a; CaXq*I literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/s05i3p02.png b/tests/pngsuite/primary_check/s05i3p02.png new file mode 100644 index 0000000000000000000000000000000000000000..fd41d1d8115a06d935284c91f40b932178007608 GIT binary patch literal 232 zcmeAS@N?(olHy`uVBq!ia0y~yU|^=`%GkDU{Eb_jVMV;EJ?LWE=o--No6oHFf`FMG}1LR4ly#e zGO)BVG}1M&ure?x^=`%GkDU{Eb_jVMV;EJ?LWE=o--No6oHFf`FMG}1LR4ly#e zGO)BVG}1M&ure?x!C8<`)MX8A;sSHL2h9!C8<`)MX8A;sSHL2h9PQBmMh5NU2pZdzx{xM~3F#`jGYKdz^NlIc#s#S7P zYGO$$gOP!uiLRlMuAy;=k+GG5rIn$Pu7QP>fk7e9byXA%x%nxXX_X9ymX;Q}1}3@& lrXfZ~RtCmaMh3bD=2ivPQBmMh5NU2pZdzx{xM~3F#`jGYKdz^NlIc#s#S7P zYGO$$gOP!uiLRlMuAy;=k+GG5rIn$Pu7QP>fk7e9byXA%x%nxXX_X9ymX;Q}1}3@& jrXfZ~RtCmah8DU8=2iv literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/s08i3p02.png b/tests/pngsuite/primary_check/s08i3p02.png new file mode 100644 index 0000000000000000000000000000000000000000..23d16c71e25c8df5e1f17bad4a7832e89bd4b8df GIT binary patch literal 255 zcmeAS@N?(olHy`uVBq!ia0y~yVBi2@4mJh`h9ms@x)~T4SkfJR9T^zg78t&m7SF)I zz?S6g?!xdN1Q+aGKAC}m!O7FbF+}2WYriKSg8~OL`{VgfIe)#Xx*%byx0iA9C8(ls!*GBDUIy{nFafq}u()z4*}Q$iB}H#JY# literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/s08n3p02.png b/tests/pngsuite/primary_check/s08n3p02.png new file mode 100644 index 0000000000000000000000000000000000000000..4a46016665abd286a25d958ae4b1c5b9a470b46d GIT binary patch literal 255 zcmeAS@N?(olHy`uVBq!ia0y~yVBi2@4mJh`h9ms@x)~T4SkfJR9T^zg78t&m7SF)I zz?S6g?!xdN1Q+aGKAC}m!O7FbF+}2WYriKSg8~OL`{VgfIe)#Xx*%byx0iA9C8x&N4SDfZ=*h11fP@BDv6%4p-{ynkO961MS)e<)^J z%D}*&TH+c}l9E`GYL#4+npl#`U}RuuqHAcRYiJx|WNc+%X=P}nYhYnzU{J_&T@^(` zZhlH;S|x*_rKN?gfr+kxX^4@Lm4UI9k&&)}xs`#zX6apZ3=9kmp00i_>zopr02tO( AZ~y=R literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/s09n3p02.png b/tests/pngsuite/primary_check/s09n3p02.png new file mode 100644 index 0000000000000000000000000000000000000000..7a822537f73bf0cd78f93f717d98e3a658f5ae2b GIT binary patch literal 263 zcmeAS@N?(olHy`uVBq!ia0y~yVBiE{4mJh`h6fYb1Q-|?SkfJR9T^zg78t&m7SF)I zz?S6g?!xdN1Q+aGKAC}m!OPRdF+}2W?*vCK21Oob^+)qx3xBzK_w=UNm5VG}jXW0| zD&$+maPM2gFK$KyvDRf7zkx&N4SDfZ=*h11fP@BDv6%4p-{ynkO961MS)e<)^J z%D}*&TH+c}l9E`GYL#4+npl#`U}RuuqHAcRYiJx|WNc+%X=P}nYhYnzU{J_&T@^(` zZhlH;S|x*_rKN?gfr+kxX^4@Lm4UI9p@pu2xs`#z%qNd7GcYhPc)I$ztaD0e0stxS BRiOX? literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/s32i3p04.png b/tests/pngsuite/primary_check/s32i3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..db4bef7eda1558d27e74bda28c8c0529ba18bce0 GIT binary patch literal 441 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Ea{HEjtq=#3k+XOi)Ub9 zU`z6LcVYMsf(!O8pUl9(@W<1|F(l&f-SB9>76qO;Qt$5=7reSDukut;$Xs`}Z1N(9 z7hArtG88;j^>FfR2${e#^+bQ)vgz04Z}c=XtYF~GxEQ|LmFt(FM4y+DechqsEJs$o z)83;zVNJm=ZuW-F8hU4aBs=Vy&T*zzZeGtZMPmcAw=ZGyiG!Z;k>(#eBisbU}|eLlbnFh9&7oH(u{^TH@`O5 zQ~7wF`LMHz-*$V!pP7CFzjnN<*EMhrk?3okou8`H776qO;Qt$5=7reSDukut;$Xs`}Z1N(9 z7hArtG88;j^>FfR2${e#^+bQ)vgz04Z}c=XtYF~GxEQ|LmFt(FM4y+DechqsEJs$o z)83;zVNJm=ZuW-F8hU4aBs=Vy&T*zzZeGtZMPmcAw=ZGyiG!Z;k>(#eBisbU}|eLlbnFh9&7oH(u{^TH@`O5 zQ~7wF`LMHz-*$V!pP7CFzjnN<*EMhrk?3okou8`H7b z39UFg&GX=!-_BkdX3IWSIp{9 z)I>3{wj)b+erG>^Q8O?5z)WX`30JFkoauZ1?!V#%-C`jF&W`)*U0$7D!jdz|tbUEQ zM&X> zANeO!OxazZkAZ!N|bSMAy(r*U&h`$k@uj(#p_C*TBNc zz@U)lx+;o>-29Zxv`Pj;OG^t~0~1{X(-0#gD+6OIV-sBib1MS_nZ*8E3=9kmp00i_ I>zopr04C70;Q#;t literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/s33n3p04.png b/tests/pngsuite/primary_check/s33n3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..599171c7b1a3569a121ed3c7b751c66c92325751 GIT binary patch literal 470 zcmeAS@N?(olHy`uVBq!ia0y~yU{C~M4mJh`hVUnc@);NySkfJR9T^zg78t&m7SF)I zz?S6g?!xdN1Q+aGKAC}mQPR`JF(l&f(Qrq;!wNi`RsWsYcVP8q=Y^*aEm)J))Ss== zll-WMfrUFlYggx%n3=MkCmwVy2|5_e#&G76cC1L_8y^M+4sR#H0@Eg^Us-0|N)Ixc z;yP~?<}&f-J2QAx%#5GKIm^(aJh`CmszmdW%IB<0g+7*WJYDp1jmnW=&XQ#kiCf>b z39UFg&GX=!-_BkdX3IWSIp{9 z)I>3{wj)b+erG>^Q8O?5z)WX`30JFkoauZ1?!V#%-C`jF&W`)*U0$7D!jdz|tbUEQ zM&X> zANeO!OxazZkAZ!N|bSMAy(r*U&h`$k@uj(#p_C*TBNc zz@U)lx+;o>-29Zxv`Pj;OG^t~0~1{X(-0#gD+6OIBQsqCb1MS__mFwH3=9kmp00i_ I>zopr03;l@|VSvp)*tPMF~R zkU6mNh>TO607JHrl8Eif#A}yAW}BAye-ocD#kBIU*hR)?x7^cmug&}@Gr{3u{AP!5 z-4|~4UsO*{SZ&(={GCv0O5WCGD+*mLq@zM>wUY~(X3G9kP|y73=eq7rLZ4EvNhvd@ z`MnqGPjo8pX!vr)DBN}3pTf8EpShd*S@+#PlGkF`swf(A^HVa@Dj5tdEiH5nOmq!QLyU~942-Re&2$aStqcsh U|IPc%z`(%Z>FVdQ&MBb@0Q&Kw?EnA( literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/s34n3p04.png b/tests/pngsuite/primary_check/s34n3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..b175f59a6b882c4c61168af376bc3a1ef31219ad GIT binary patch literal 431 zcmeAS@N?(olHy`uVBq!ia0y~yU{C^K4mJh`1}k^&LktWIEa{HEjtq=#3k+XOi)Ub9 zU`z6LcVYMsf(!O8pUl9(@X6D~F(l&f)9HbHEebp?^2e;d^USIG=FZ8awL7w_(^QR% zWj^y@|VSvp)*tPMF~R zkU6mNh>TO607JHrl8Eif#A}yAW}BAye-ocD#kBIU*hR)?x7^cmug&}@Gr{3u{AP!5 z-4|~4UsO*{SZ&(={GCv0O5WCGD+*mLq@zM>wUY~(X3G9kP|y73=eq7rLZ4EvNhvd@ z`MnqGPjo8pX!vr)DBN}3pTf8EpShd*S@+#PlGkF`swf(A^HVa@Dj5tdEiH5nOmq!QLyU~942-Re%ybRRtqcs@ UL+0f&FfcH9y85}Sb4q9e0Oi%8cmMzZ literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/s35i3p04.png b/tests/pngsuite/primary_check/s35i3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..ccb1b8aca15f7cf78ad6ef56545869c72a221d9c GIT binary patch literal 477 zcmeAS@N?(olHy`uVBq!ia0y~yU{D5O4mJh`2DzJ?BN-SNSkfJR9T^zg78t&m7SF)I zz?S6g?!xdN1Q+aGKAC}mQNh#2F(l&f*=d1%%?3QqvMbBqt-BChZU2^I!?u|(c>c|D zTRQX2#CApnCQjL1GeqoWvZmhHnY#I{v1l@5!p!IO3w9_)hOjX395-6m!6Gt!OY^}l zZKZ}MHZ#3i+K;%i@-(zue>j`Xlliz0TVHQ}EO&s^WXCB{9*z?VnOd(Jh4`?kXH<30 z+if5jB4J@+uxp=@yt(AL)koLMvYNOx?G?SOR37|NWY=|HbG1w}51rYw*SUvln z-OLk*SrjxoGe7S8to=eVZ&j<@qh&$Xwg-Jhwbss7(|0%D(Rnv}nydcQRHf5AS$DRa zeNesdo5Oy_#=jZN*O&DaF)%QwmbgZgq$HN4S|t~yCYGc!7#SFv=o%X78XAWf8Cw}x zS{WMY8dz8v7!>kcS4Gi~o1c=IR>@#!X=$NrV4`ba8e(K*WngS&Y^G~qZe?K5{cql9 Q1_lNOPgg&ebxsLQ031BAoB#j- literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/s35n3p04.png b/tests/pngsuite/primary_check/s35n3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..2c7219f00d58b9b7382ce956eb05277abe2b2f03 GIT binary patch literal 477 zcmeAS@N?(olHy`uVBq!ia0y~yU{D5O4mJh`2DzJ?BN-SNSkfJR9T^zg78t&m7SF)I zz?S6g?!xdN1Q+aGKAC}mQNh#2F(l&f*=d1%%?3QqvMbBqt-BChZU2^I!?u|(c>c|D zTRQX2#CApnCQjL1GeqoWvZmhHnY#I{v1l@5!p!IO3w9_)hOjX395-6m!6Gt!OY^}l zZKZ}MHZ#3i+K;%i@-(zue>j`Xlliz0TVHQ}EO&s^WXCB{9*z?VnOd(Jh4`?kXH<30 z+if5jB4J@+uxp=@yt(AL)koLMvYNOx?G?SOR37|NWY=|HbG1w}51rYw*SUvln z-OLk*SrjxoGe7S8to=eVZ&j<@qh&$Xwg-Jhwbss7(|0%D(Rnv}nydcQRHf5AS$DRa zeNesdo5Oy_#=jZN*O&DaF)%QwmbgZgq$HN4S|t~yCYGc!7#SFv=o%X78XAWf8Cw}x zS{WMY8dz8v7!>kcS4Gi~o1c=IR>@#!X=$NrV4`ba8e(K*WngS&WT9(dZe?H~p8eE- Qfq{X+)78&qol`;+00wZd8UO$Q literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/s36i3p04.png b/tests/pngsuite/primary_check/s36i3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..d61491fac8816dce998f63673cc1983e193534a6 GIT binary patch literal 448 zcmeAS@N?(olHy`uVBq!ia0y~yU{C>J4mJh`hKCF@W-u@?u%tWsIx;Y}EiimBEuMja zfi20~-G$*l2rk&Wd@=(ABeSQAV@Sl|x6@;n*>T1%WU9l8O1`yvuXs+etGp;G zFb$ACu_DiV&EbYyr~S_7uRkNu_I=a3>19zOJ?n1oPT*oYwMbe+enM&C)~#=+E_B!& zF_}x0t%NJ?yYT%5r<(lDJcOk8WOh}>Z^)Eeu*}pUGG^Q1J+t`AW(I3b_nr2tJn+6l zzG=bCt$)8ATw5oU`D>;KL)}W@c~>^uCxtDyWei?0J@?T2+sq6M45}rr5hW>!C8<`) zMX8A;sSHL2h9J4mJh`hKCF@W-u@?u%tWsIx;Y}EiimBEuMja zfi20~-G$*l2rk&Wd@=(ABeSQAV@Sl|x6@;n*>T1%WU9l8O1`yvuXs+etGp;G zFb$ACu_DiV&EbYyr~S_7uRkNu_I=a3>19zOJ?n1oPT*oYwMbe+enM&C)~#=+E_B!& zF_}x0t%NJ?yYT%5r<(lDJcOk8WOh}>Z^)Eeu*}pUGG^Q1J+t`AW(I3b_nr2tJn+6l zzG=bCt$)8ATw5oU`D>;KL)}W@c~>^uCxtDyWei?0J@?T2+sq6M45}rr5hW>!C8<`) zMX8A;sSHL2h9H*-HDF+1VDNPHb6Mw<&;$UYeWo`6 literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/s37i3p04.png b/tests/pngsuite/primary_check/s37i3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..2906fa311661d670be012c178ea9b6c57798af70 GIT binary patch literal 478 zcmeAS@N?(olHy`uVBq!ia0y~yU{D2N4mJh`hNJTom>C!tSkfJR9T^zg78t&m7SF)I zz?S6g?!xdN1Q+aGKAC}mQPI=IF(l&f+3B%-hYWa{b2ZEFt-BE1K7Cqi*Lq*2#v`K~~7Sc=%i_B7ab~dG`$Zs%^ zbnX)fRWcDyR^0T7jjQ3onthrAq8mKQH(12E@+26kxli0==znO1aK;SZmCu)5aJYK; z)t&cBMmkm!5`X{k@7>*>vH0Y%Y3d;%t>2VZX{`Ajbo_?g-R+G>%p0$jl-_p}I{qV4 z%(;(IxKlllGiKK8vip-C?ONHP@@l5v(JOYAq2DxiADQwt@|9X=+^=xa39?D2zP;;= z-L>9o%hB@tXBX=3`>o>>x$$oJ;gFhRW%vK`9@zSOO%DGxxtQJWA0KS~{Y3oxK6T!k z^)bKyOn5i@u4;Vor&I;*Vm%#D*p|3Pl%yncn&=uD=^7e`7#Uj` zSXvnx=^9vA85k7uTn9%6TtjYtN@iLmgQ2CRg|2~#u7PQYk&%^wv6YE|u7SCgfx)BK Ti!LxQFfe$!`njxgN@xNAPx--9 literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/s37n3p04.png b/tests/pngsuite/primary_check/s37n3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..8931b859daf0a13f2c648a566023d0cb1ecafd61 GIT binary patch literal 478 zcmeAS@N?(olHy`uVBq!ia0y~yU{D2N4mJh`hNJTom>C!tSkfJR9T^zg78t&m7SF)I zz?S6g?!xdN1Q+aGKAC}mQPI=IF(l&f+3B%-hYWa{b2ZEFt-BE1K7Cqi*Lq*2#v`K~~7Sc=%i_B7ab~dG`$Zs%^ zbnX)fRWcDyR^0T7jjQ3onthrAq8mKQH(12E@+26kxli0==znO1aK;SZmCu)5aJYK; z)t&cBMmkm!5`X{k@7>*>vH0Y%Y3d;%t>2VZX{`Ajbo_?g-R+G>%p0$jl-_p}I{qV4 z%(;(IxKlllGiKK8vip-C?ONHP@@l5v(JOYAq2DxiADQwt@|9X=+^=xa39?D2zP;;= z-L>9o%hB@tXBX=3`>o>>x$$oJ;gFhRW%vK`9@zSOO%DGxxtQJWA0KS~{Y3oxK6T!k z^)bKyOn5i@u4;Vor&I;*Vm%#D*p|3Pl%yncn&=uD=^7e`7#Uj` zSXvnx=^9vA85k7uTn9%6TtjYtN@iLmgQ2CRg|2~#u7PQYk&%^wv6Zobu7SCgfx!#C T)h8Jk7#KWV{an^LB{Ts5MNz<= literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/s38i3p04.png b/tests/pngsuite/primary_check/s38i3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..becf5a1df6935d3524bed7d0b279df4e338b1b8a GIT binary patch literal 439 zcmeAS@N?(olHy`uVBq!ia0y~yU{C{L4mJh`h84Ci*D)|Ku%tWsIx;Y}EiimBEuMja zfi20~-G$*l2rk&Wd@=(A!!J)4$B>A_Z>L}6YgXWK^`HK?cz@&iebtU{TXgf>PBUMh zpde5bTG++AVS z5!M}fe!us*-j-R~_btSP*)DB~*?Ib=wJQ6KXQdZewyA8mXmU{P#?`8M_aFJUT0~|w z>smaGc;n3%Q}CWWJB#b#);m3SD($YV)I2h+sjc)M=d~4|&lzp=F0_w$J~z}r=ML9T zn^OxU_4F>WWSbm5>R&Mb^rqI|tbe&?hliUMZe?I#P%UwdC`m~yNwrEYN=+A_Z>L}6YgXWK^`HK?cz@&iebtU{TXgf>PBUMh zpde5bTG++AVS z5!M}fe!us*-j-R~_btSP*)DB~*?Ib=wJQ6KXQdZewyA8mXmU{P#?`8M_aFJUT0~|w z>smaGc;n3%Q}CWWJB#b#);m3SD($YV)I2h+sjc)M=d~4|&lzp=F0_w$J~z}r=ML9T zn^OxU_4F>WWSbm5>R&Mb^rqI|tbe&?hliUMZe?I#P%UwdC`m~yNwrEYN=+>u$)pFR!-Lvm!=w?Z@z= z3Rh=E6f-ahh;7;OGI8nCxi=I1=1!aN{(jLGUWU!<;@6lQ+jLTbK_I=j*U>aGztiJMZv(sO6XWeQ)fm0>HGaNXXCg_}zi3wfg7P9T%otWI)Z_dq` zlbrYMzTCERe4Q69`J>u$)pFR!-Lvm!=w?Z@z= z3Rh=E6f-ahh;7;OGI8nCxi=I1=1!aN{(jLGUWU!<;@6lQ+jLTbK_I=j*U>aGztiJMZv(sO6XWeQ)fm0>HGaNXXCg_}zi3wfg7P9T%otWI)Z_dq` zlbrYMzTCERe4Q69`Jrav2yHSkfJR9T^zg78t&m7SF)I zz?S6g?!xdN1Q+aGKAC}mQOMK9F(l&f+ZhkJ4lD4q=r4UgCwzu~?e9R*wdXc%oS6J& z$%R`%cIQ@fDmYkqH2Ddf5cjmWecicTc<0aa`|c~O<1>gfImenHYC9{N#l-Qu)d4Lx zWnTte*W?%mv7Ixj88+4xK6io5sIrqTtd{9H%Mu+K)TaH=plrav2yHSkfJR9T^zg78t&m7SF)I zz?S6g?!xdN1Q+aGKAC}mQOMK9F(l&f+ZhkJ4lD4q=r4UgCwzu~?e9R*wdXc%oS6J& z$%R`%cIQ@fDmYkqH2Ddf5cjmWecicTc<0aa`|c~O<1>gfImenHYC9{N#l-Qu)d4Lx zWnTte*W?%mv7Ixj88+4xK6io5sIrqTtd{9H%Mu+K)TaH=plj47;1B0ilpUXO@geCxr CgRG?y*^$~gv6^9XYEdU!^u>LX1!ehHt~zkW zw}F#kRp6{drCWb%+!iILmuH`NW+kxr(_Go$Iu)f&w)sf0S&R>F(s5RQvaq{z>XNJM8$TDH+n{sWq$>P{-09}cR_8yT=F5Dqsd~b){#)FI zNu{x?-*&J~D6YGmBhOl4weGV`bBDvZ$`?YP0vQ_KPqHcBCx4%}p7jIgPxdgqZ@xXk{dT^{chTea#+x^re>)Usz_+jA`kL3K7w(?o zZ`)Cs)uOEA>N0WGvqlcpqRNg5O0JJqK5G51RC&UCvR$Yylj}lW-mH|aSeXce!UNrg z8;-o*du4O^`FCgj{MzukHzrw6HK^~)SyYsj}{vvc-jvu=5j80y~{&wvdU!7pp_!aGM&u4GpeM{UlN+<#?1bJ zwQQ@r9z*4Wc3JBTHl`_IVFhB{CCsJ|cHiIEyt|rx)v84rTo*H@MCcqlae|}K!QmEz zfwi^vxw+Qvd*jk;^Uq(8-~9bmXo&;stU7!C#eq_`wl0%A`E+z0rMVXH{8`TXO+Vpl zGyjI&ccqoqg{@W*;#5;tU&`w$!O^nu_S+pXdOU|0#I2v)?eZcz!hwaUM!tWukx9#h z=-$baa?h%k9@2mI{AT%6F6&$~8;7d~C*Iv;{{8*&mkO)C(pdHR=Yv;Y?QmN>d-s9Y zrOGW1*GqHwq!$KsEIWTZN5^gP#f+z`_g>3A`&`-5%&jQr%|=!==4F|a&Og_je%fTV zFVEqGii!&3hV#!CCz}4)^SU_bp2*{07Vg*kgv#0td787fdhLy?&x&5V+@Hg7W5kjG zjRmi*+7c5a*cu%g-o4Aq6mB^DaDt6rzsJ{Q3M|3w%RZd{Rr&T<_Kmk?bNtkoWd`X@ zUm3PKdizwBz|~hzq-~DbyQ@9q6@#4rtm$!43)Zi9(Gj~{PtVr+1OtziA&Y`m=5*}1m@(n>Qw=d)y|@~2-_Ok97q&3X5@Sio$jHcM zh@2Lv#dV`mNaPQz9IM>L@HdN-LU(L<%VgHx%bDFYK}t!0BS35F1(RNIxXDoYg zsMS7TVA*?EkY(J;hNV9r=&ly8PUuk4p-6Yk&DR>quKt zG;_t?+aIOkRxsOd3Hk9TJbr<;Ra;&Idj#wDwO0*aufCX}(6S(k*U0=kTYyX8zY_cOJSK*Ss9&bj zp0b_0e1HD&haU=_p3=DaX7`!%{l-Q@^*O8m&0w0(AAj@uuOPOf2G-!SE6e&XHVQZ; zM20AC`S$&M#xcu`V@bj8^@c`5cUd+pUin3%Iq?faRCMfI7p0FWtW5_MRxNW9 z{&4s}Ir9dlFV3rGGI1LmSpLK6Q}ndfb+1!47pClF`!hRXL+7G33a7O_Ch>Y0SVK8p=QJC9o*+9u{$-~^I|_MFS=t5@8ptOjj5)MCJ#6Gm2YoO zxX>!FpK+bB-M;C^Z!Vjdvmt-O(-X|Bs}CGJb8uRhoR#K<*;VWg*S~HPl1q?^Gz++@ zCZIlFp1EkpUCX%2ryt*U`zqf&Iaz(;f1S@a*PgdXkUcPM)5BY@7wy}8kMV=~pNKN< z1(%yP#W02yTJaX`%*(qc!(8*_%b(7E`?`MTc0SuOqgzWFR;{|!zW;Z?uO}zeEAFl} zuPw2>CB?DkT9D4t#RqQPin3PSe84C>+iYFz?e0Vqj`siOetuqVQIwK&dSlM%l@=2{ zJeK>`0=(vyK3=Wl}$SpSs7|;w+BuU)!|N<`0%03<;(IDJyhmd2-_9v@V7c$ zS{b~&qV`WIn-Q~a$N#_u7c&wf#p3cC*RAWekkO2*-P*l!Wq*fDnSH5K-K&s2dBvZL zlRnL#9P&Q2viSDw9dGkQTpvC>+`i;;rqAUk2b}qBhr=MG}>XmWt^Yc6m3o>U} zRDaWXSt1oVZDQ)o>hJF+o=p>UD){muuus;yP3QFaKldN(WVrVB(o*k7pPrufm~`aO zA*Q2A6Tjd8|5v#CtvV}1M9d!jb8~-dZ_m5?=t!q3@fg`UKF5l;r8v{ z^_KOC4f7BE(N#ta4q2GtVRh?11Vl2ohYqSVBaR0bmhLla#?BV9w|5F=wN z14}DIBV7XvD+7Z_Qsnxn}0hLXTZ0w;rg1_rWfv> z;&0ngnbo4KL&L6lTHUR_mrt5Cfq*3u{VFO>-pRH!jf`s zfg&$=GM;+6X-DB>wv#E7c9*|TdS$h4w)w|Yql));5~TxJxem;_@4t8deD?BpCG+I3 zme!P6&wPAbvg&8*qmLFFBY4^mE9P=8c)iO*ZL-Q_&!Cke%QBtJyfdn#&R-Im=f=$b zfVFI^ydFd4gLYZ#3^t}IVPOSg-6hPX4|d<**Sx!$ebuT(8eA7MrbOr*J8^=e(ZS&s zgMqcR_PM#%?tA0XYxB=vkKg?LRcMI=>#RC^{>6b(wze*lJo$8V9i_Pz@cdcM`%ORL zYcv0b-FKyx)`hKB5#m%+S6|BOD#6jR@%GytF?u|Q7sRcf-0kurI>Ld4sYbqkvyn;5 zgy`PMl5)?gmLAf7_WWk~Q!eXVGaHAi1}EO#Wd8mA@s|p#zS3Cr`R9XIU+r*PJbU+n z*QLrW4%bU__@oyGbSyi6JV(cE@x_d%tM^{ZJ^NhQ(#)+W=gme|HRffRlg>ZaoPOG5 zwlB}&go=s^wL=$^>qUl#7y`-IBc4SAZgwtDT2tIvvFyWF3{abv`i z0F4E&t=bY3B-k1q8s5Fj%M@-n{BVMeU%$uKWeP08?8`o!|5f?+SoV##Wpn)0mt_X& zOIIWtr-cp6GG{D% zaH!QjVC5HvddF$&7p>yI_?2Vnq(l4S-`x&Tm*s9h{AR`b2Ga+Q+4<}0`4m~i4~zfI zx*lG0a(YeF4-rL{u0;YoY=%6{zLy1@4DA22O+Cd?ARYOS-MakTqmN4pc58q6HtR@R zQZ#eL-rFCg;#M%*ZwdMFC_H|FwpCkR1A7GP_O(|HU$4HHq0q7*ir2{eJ6nKD;J*_G zn=>DMtP@c^_3o~L-M!r}v+gknaQxUH{`LX;JI0yUI=wHczB+5QB|mrT$~-29h^Swt z)1I=OyL^BC@rNG@o}SXU`DXW-^Zmv~LiIVT|IJ{U&mVvD`mZ3iq6XIBvn$K`FE$D| zB}9fjf44y=B4S2{yZza3Z~6B9e8w@$jAKc`?)8R7LU&m&W> zTv5}Hb#1$JE1x-HTC2`!SyryryH{Q_KFBXAe_r`TqdD;lLsWF^To^C z68>=bKsoaUrZ3K`W-@Ub99aIt>QnTz)^)E_HW#MsWcxEaVMFJlH43M-Jtpyb7+6Ui zd0OP@&k`WwDpkU_jiF}4>K)wYC$T#<-1A~TD=)f1hx@RBf$!v!TaBrvjV2E__?2&O zPPou2u%B_AvE9Du$8Rp1n6n{&!_yPYtg8~%BLUScl#>eJULl?;(wjbH`kuGNRT}+ZPUYBuNUpxe2?*i`Jad~ z?gf{dHpMW86(!~dE-HNhS-F(0(JKJns?CtJE6OQ)(=YD=(Zc&tybb4dX>6I1} zJv^5C&reH8X!!BALc415U6oBc6hQNZ zU0NBuyrT9`DVq_qZpZ(?1s5|CBE{nJ8`rJtwvf?`tKHhYa%F#qOPPJCQ{AhOJ$c2S zi<3UhpB(Z&w6gg2>>Y3OL|h*}JlwwIa;DGaCkLC^W$bEZ7^k0Gu}0t1_R>=CN1vXa_Ly|! z&>^OyNfW={|NmFG`>i@FLqyCT{d04FYj4lH`{+oga8F;K-S*GoObjcozg`reapCsu z-}RRDi4F4){p04I>aq9LLdFaR1_sp<*NBpo#FA927;}9cb zD+5a_LnB=S3o8SILZ0iYC>nC}Q!>*kK^hEo4NP!ll> zK20?=HC5eo^G)>93)?2QFTS{9#=LpY?(MB!vu@oZFO?5%PBIx;LbB=SF4R8bX*}nb zss4US-1Ei|E!DKNv>CHzB^4G5MlW=5)@UiOlT)3!gd?Rf)?u^CLm7#L_cu3hnQwo7 zUn8T4>%=mi4g2=#)%|$Lo|cwY@$HS|vUQK=%s>A7i{{sf9IFIU8bv02t?(!`{IQIL(Dos+Hk%GIl$x0yt`T|d6Ks4Qn!3T3E^a{veaCIUW~SUO2q?Q#qyl-od=>i#51xZEaba z9e@4){qbi_5buF6U$*S1{H!)>*~ZHC$u)D%&6MQP%DZYK7k0l^eD%(m``r6)Nb^13 zs8h!1njm|Ex$r@s%EZ4X+V&*dXw>4%>d1nN!K6yciUwREn;ZZ)6FDib{>oJ=v` zVLogiAuXN!{oUQIk}KA)U+yzgfA)Tr82M*AEY9uxV#$=naM<9)(;|`Xqu06eY^5WKQ+f;Ae-ptZ`aMtr|wuzTt9*HfPe7Q*B z@ZEj8_iXVf=|BFT9+ znGVx@fBpWQ&5-4`QRnmuR#6iLPH$cBH9x`xoB|dcF#neS%C!Tlv`2A~4`NZ)-BC@VQ#g@%$&HCGMybr!s6=vsYF#KP6XSR(&r$AG* z?{AJUiQ?w{8h0@VWl9*3}i>ao7JtMbVb+ z(_g%Nc~kDd`|pdhvX-t4XW-rU{+FEZ#S5paQtvH07+R*-vLbG25T_!`tg!QskMCzR z(l|BWvd-q*g9P(cx6baXEqHXqF2`*47Tt#P&krx%xqvZ(Da^6_#ht=C3s;C9WMa9| zTFcFF;LxG=DW|nQgj-oJ-f>q?&gKW}#vAWv&X!)bzrLV5b34O|TgRSwyupFPu==)o1+&wSaTtBq~0b35N&Mu$S? z1Kf8XzUvadmAG+F#7QSkn?u2(+jY2OuXnmtYb{HhwQLzv*QPF=^^ATA9f#Y$KPcP1 zG@MDJOKI!1txl2|4DpxT6D%2c6}lENCG7RtpBj0UbGp~h2Ga-kEB3nn`De6h6_a{n zI}d;Pr~OH%y{_%uEnR(*Pfo*wm2DcER_@D%K}_5&Uxgg5m$nEz`E0bIVNry|TsE`Y z20QN*Dzu%R`rz;P{(X`Mo}Qlm^UQzA<7xecC#+nqdx`gnvTq6a+Msns>p&X!w9}Fa zlC#gMOw33s`^IwNz&zXfhp*SyA3t%TVfX7l|f(W`0_Bo^kaQFQdzs*$sM_a&x!;_;x$H=F3I>?Xjn~-R)v$XJ5KHeEp@1 z7Y`nM&aVAPTJna-|3c2FsCUYzS4%(R5$18*QT)7L#?I!)sktAfW>+RBFD`j{O7vXs zoW;tw0?#&_-IS}@cz*igtzYxs+!B3uWhI-M+P@?J{#M8BR@`5v8!qCytKcD1?f+N8 z)7A7Ro`3Q(wAxTrc)={j{rCM>hCF(5GC5{<8Sn19|J+{x%)b6f-rZ`h*!A`C>O!3h zG`KeD2=ldf9!=slXb@s(WMyP%WniLfU~Xk#(EiUR9aKwty85}S Ib4q9e0BFu@SO5S3 literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/tbwn3p08.png b/tests/pngsuite/primary_check/tbwn3p08.png new file mode 100644 index 0000000000000000000000000000000000000000..9ecd40470c4d39cdedd3d6dcb0960f955a731b5c GIT binary patch literal 1911 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Ea{HEjtq=#3k+XOi)Ub9 zU`z6LcVYMsf(!O8pUl9(w#(DSF(l&f(doDIMZSw3w>RFr+5Fp~I0L?Y4cFJaHob87 z6o1=}%B&V;C0Cb;vz|3_s1{XrOi*%twDM8wf2GP3-jnS@b(vfj^73Y-bj8X<7!)4p zHr#OJ_1-I+%g?_%^XJ!w*S#^xda6NvUnZB;|2jMG{LgvCb;V&qP9KVA{n=bqFW69G zrJI(P=CU)UPLVVBe6hvklO6f{eT{5uXFh$J>ax-4$uFIW_u@7d*Ub5QykEG_Wy$lO zzArOPH|*M_HR+^^v9Ym^p5CLCR|DSPS2wZmpL9Bqxu;AeG2!+Jj=lMNUC-an7nYQB z3lw>|lkwEkO*;x7vz<(tw7dL$(krWVv&}!I8dbc%lPDd)%5`AYegD1t=d+i;E14&M zwX~+pdgkNfl2t!bAAPjg7{SwiSTUD#!RuWfYLitadj_o(S(fQ!=ABU`b^emjJU3?c z2drgV<@FdUAGFI_XRt9%2@5L_>n>q7eX#rfzUJN4?5kES(%`z7F(pFh*ohMyjSddC z7!0hfwa?A9cHbM9UYmdZdi>_^uR=>4SZCGQ^DhpRvbA-YnP2&falM0-f#K| zUz_t?(D3eEUZ!xv;fE7!{Q5nmC$W?%N<{IANl$Fgs{Et}(~zAQ6H zZ~Drx)zRChssygSdLnIe%-&t?A+H$Z{AW#%i(0ULy^D_6?Si_)u1`v=3Qc3ydZ^Cm z^D~|}=Y`ACRay@VW+WJRtPEKcv@)k-$Hj~Zr=Mzw>FUMRi2HtK4!^L4X_gpELPkbL zHbdmJKrOBtjY1-SSmjvdE{4BZoD{la!&@e^_Fm5HrU_C?0vrKaQ!kkGIxTEimN{eD zgF~(M0V}^S)H_aFzi1Wz#jhMoCmq@s|L%5(x-575;WsPZH<&(f%+6m|&!@;Depvix z*7fk3lhbRWeuyZtbS)C#VKd}m_Ps3NWMKcFZR#nG0_n(q?AGPy9(`O=uv`1fw^>Kp zlA@U__TK&|6}N)feoM%YN8#}cw5{6m8rUOPx39fw_L`3~E zo%WRN+~xc8k3alS@br|%%{RNxobNX_5~|Nx{ci@-eE#^G*M9}E6*aI1pIuqjf3Z=( zDIqfK`MV7|5fL*o-0jbPd&{@)=QEC3W*kcjcCR-y61vN>VIjx%^3tt#Ga8s}B>AU4 z<%*hqtZUn)Tlvfp(^_>-%d&E{-o5gg@j-q``SZ#z8qJAc7^0$M=ej6;Okr(0sIY38 zlkkVb2g;c@Fnw`eHIs?k;K1@9R-dA$wXS=evbiv2C)=Od2^%^Wtx-6w?JRX+XrzS~#%=E=$G6aVXczPa|iMS|>sX`3G2dcA1h=6j4E%>P7` zaWA;sv?+!$tk8JGb-MmKohz(y(gPrS|>51AaX@psFMt>gEGR+1Y06VsCdRnsBuLKlk(Va*Lvrq|+O7POr3> z=;5*4e|}m*Lc@=@71~vc@2YItsmRJuTf04Qil`2E!o-IUWiDTqpXi}7&qCO)P=~+O z>C(#J;op1Kd!L`@VOWqk z%cA<5&dU<1$Y~Q(XI6iIH}Pzmpi{w@7lD1U)@?ec&;PmqU?;=1x0jZBKl=3aw8x|) zhYm3vO`7=q{{O$i-EY-d86sl#=%1VWTYG!n-A6|{g?sw??6!XvXJS}!{q>>%jSIJL z|E{;JPi&Zf=pQ%tRFA!{7BXfqFfgc=xJHzuB$lLFB^RY8mZUNm85o-A8XD;u8iyDe zTNzkd85-#tSXdbt6!KhGMbVI(pOTqY3DRJwYha>lXb@s(WMyP%WniLfU~Xk#(EiUR Roq>UY!PC{xWt~$(699C^c%J|O literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/tbyn3p08.png b/tests/pngsuite/primary_check/tbyn3p08.png new file mode 100644 index 0000000000000000000000000000000000000000..4fbdb36a33d7f3c3c82addd028dffed7a0d3f0ed GIT binary patch literal 1911 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 E0HtR>djJ3c literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/tp0n2c08.png b/tests/pngsuite/primary_check/tp0n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..364e97e036f23c101785d3bbda2ce0fe1de70a8e GIT binary patch literal 1955 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 L>gTe~DWM4fyeWNg literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/tp1n3p08.png b/tests/pngsuite/primary_check/tp1n3p08.png new file mode 100644 index 0000000000000000000000000000000000000000..9ecd40470c4d39cdedd3d6dcb0960f955a731b5c GIT binary patch literal 1911 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Ea{HEjtq=#3k+XOi)Ub9 zU`z6LcVYMsf(!O8pUl9(w#(DSF(l&f(doDIMZSw3w>RFr+5Fp~I0L?Y4cFJaHob87 z6o1=}%B&V;C0Cb;vz|3_s1{XrOi*%twDM8wf2GP3-jnS@b(vfj^73Y-bj8X<7!)4p zHr#OJ_1-I+%g?_%^XJ!w*S#^xda6NvUnZB;|2jMG{LgvCb;V&qP9KVA{n=bqFW69G zrJI(P=CU)UPLVVBe6hvklO6f{eT{5uXFh$J>ax-4$uFIW_u@7d*Ub5QykEG_Wy$lO zzArOPH|*M_HR+^^v9Ym^p5CLCR|DSPS2wZmpL9Bqxu;AeG2!+Jj=lMNUC-an7nYQB z3lw>|lkwEkO*;x7vz<(tw7dL$(krWVv&}!I8dbc%lPDd)%5`AYegD1t=d+i;E14&M zwX~+pdgkNfl2t!bAAPjg7{SwiSTUD#!RuWfYLitadj_o(S(fQ!=ABU`b^emjJU3?c z2drgV<@FdUAGFI_XRt9%2@5L_>n>q7eX#rfzUJN4?5kES(%`z7F(pFh*ohMyjSddC z7!0hfwa?A9cHbM9UYmdZdi>_^uR=>4SZCGQ^DhpRvbA-YnP2&falM0-f#K| zUz_t?(D3eEUZ!xv;fE7!{Q5nmC$W?%N<{IANl$Fgs{Et}(~zAQ6H zZ~Drx)zRChssygSdLnIe%-&t?A+H$Z{AW#%i(0ULy^D_6?Si_)u1`v=3Qc3ydZ^Cm z^D~|}=Y`ACRay@VW+WJRtPEKcv@)k-$Hj~Zr=Mzw>FUMRi2HtK4!^L4X_gpELPkbL zHbdmJKrOBtjY1-SSmjvdE{4BZoD{la!&@e^_Fm5HrU_C?0vrKaQ!kkGIxTEimN{eD zgF~(M0V}^S)H_aFzi1Wz#jhMoCmq@s|L%5(x-575;WsPZH<&(f%+6m|&!@;Depvix z*7fk3lhbRWeuyZtbS)C#VKd}m_Ps3NWMKcFZR#nG0_n(q?AGPy9(`O=uv`1fw^>Kp zlA@U__TK&|6}N)feoM%YN8#}cw5{6m8rUOPx39fw_L`3~E zo%WRN+~xc8k3alS@br|%%{RNxobNX_5~|Nx{ci@-eE#^G*M9}E6*aI1pIuqjf3Z=( zDIqfK`MV7|5fL*o-0jbPd&{@)=QEC3W*kcjcCR-y61vN>VIjx%^3tt#Ga8s}B>AU4 z<%*hqtZUn)Tlvfp(^_>-%d&E{-o5gg@j-q``SZ#z8qJAc7^0$M=ej6;Okr(0sIY38 zlkkVb2g;c@Fnw`eHIs?k;K1@9R-dA$wXS=evbiv2C)=Od2^%^Wtx-6w?JRX+XrzS~#%=E=$G6aVXczPa|iMS|>sX`3G2dcA1h=6j4E%>P7` zaWA;sv?+!$tk8JGb-MmKohz(y(gPrS|>51AaX@psFMt>gEGR+1Y06VsCdRnsBuLKlk(Va*Lvrq|+O7POr3> z=;5*4e|}m*Lc@=@71~vc@2YItsmRJuTf04Qil`2E!o-IUWiDTqpXi}7&qCO)P=~+O z>C(#J;op1Kd!L`@VOWqk z%cA<5&dU<1$Y~Q(XI6iIH}Pzmpi{w@7lD1U)@?ec&;PmqU?;=1x0jZBKl=3aw8x|) zhYm3vO`7=q{{O$i-EY-d86sl#=%1VWTYG!n-A6|{g?sw??6!XvXJS}!{q>>%jSIJL z|E{;JPi&Zf=pQ%tRFA!{7BXfqFfgc=xJHzuB$lLFB^RY8mZUNm85o-A8XD;u8iyDe zTNzkd85-#tSXdbt6!KhGMbVI(pOTqY3DRJwYha>lXb@s(WMyP%WniLfU~Xk#(EiUR Roq>UY!PC{xWt~$(699C^c%J|O literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/z00n2c08.png b/tests/pngsuite/primary_check/z00n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..ecaa0d8bab72b7e37df0e032d9d28b2479f59ce1 GIT binary patch literal 422 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Ea{HEjtmSN`?>!lvNA9* zFct^7J29*~C-V}dGT9@@mw};5je((|g@NH00|P_D3kHT#0|tgy2@DKYGZ+}e3+C(! zv|(UiU`z6LcVYMsf(!O8pUl9(u))*CF(l&f(MvnI8Vm$jE(q#8`d`21Ws>lRQyX{R zJgmmiW^S>0YSSdf6oz!$>i1Lfca)cq$z5oCK literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/z03n2c08.png b/tests/pngsuite/primary_check/z03n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..ecaa0d8bab72b7e37df0e032d9d28b2479f59ce1 GIT binary patch literal 422 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Ea{HEjtmSN`?>!lvNA9* zFct^7J29*~C-V}dGT9@@mw};5je((|g@NH00|P_D3kHT#0|tgy2@DKYGZ+}e3+C(! zv|(UiU`z6LcVYMsf(!O8pUl9(u))*CF(l&f(MvnI8Vm$jE(q#8`d`21Ws>lRQyX{R zJgmmiW^S>0YSSdf6oz!$>i1Lfca)cq$z5oCK literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/z06n2c08.png b/tests/pngsuite/primary_check/z06n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..ecaa0d8bab72b7e37df0e032d9d28b2479f59ce1 GIT binary patch literal 422 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Ea{HEjtmSN`?>!lvNA9* zFct^7J29*~C-V}dGT9@@mw};5je((|g@NH00|P_D3kHT#0|tgy2@DKYGZ+}e3+C(! zv|(UiU`z6LcVYMsf(!O8pUl9(u))*CF(l&f(MvnI8Vm$jE(q#8`d`21Ws>lRQyX{R zJgmmiW^S>0YSSdf6oz!$>i1Lfca)cq$z5oCK literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/z09n2c08.png b/tests/pngsuite/primary_check/z09n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..d869f992f80e61f073ea0f55a05aef941bfb6842 GIT binary patch literal 422 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}Ea{HEjtmSN`?>!lvNA9* zFct^7J29*~C-V}dGT9@@mw};5je((|g@NH00|P_D3kHT#0|tgy2@DKYGZ+}e3+C(! zv|(UiU`z6LcVYMsf(!O8pUl9(u))*CF(l&f(MvnI8Vm$jE(q#8`d`21Ws>lRQyX{R zJgmmiW^S>0YSSdf6oz!$>i1Lfca)cr& literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/ccwn2c08.png b/tests/pngsuite/unused/ccwn2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..47c24817b79c1e2df8eb3f4fe43798f249a063d6 GIT binary patch literal 1514 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4kiW$hCdQ-7c($0u%tWsIx;Y}EiimBEgmG9 z>=ES4z)+>ez|hdb!0?NKfuZ3A14F3+1H-EX1_rAc3=HB0b9M#VFfg!|db&7dJa{cAI$%WrhoE8al6wM0pP%1(^3U@Bv;Q+I<;B&nXM0UL z<`EZ{X8hr|&H2Np&#ZQ7vEKPb)|Y*b^xhxb|Nrc){jL1>=+~L6f)tCpT&7B->?ttp=+i4P$oAzWO$$+VY3c{!cINq_MC6w60(N(!8nn7aQL; zbo3DrtT`iJclfgC;@gaU8^18t&M$Kixb#k_jI+9=x!$eAXS$ zME0I*w|i@*<%GN1hli>wdS8%kNKb`o0stxxR-rK3+2~#isrJVx|&y ztBCp29Ir01n>%Au`^$yO9fB4c4}IQkQ8jsU9q$Kjzv>@yyL$5$JBP4KU$9s)E6%|@ zO=@BF3P}TYyZS9>zi<8dayfJIvi*-QsU_Ts_BGL4rpW)&)kIM37Rxrr^GncT7UeZ`*yGTOxpp1}tl39ysqO$~-a-zzfpImRxf4&fWo$;UJwyt}Aw_SI? z5WD66a|VO#qUw%?F9qFSNOZ2XXg+%={iSoF4o|Cj+=Tak<7~J5o_t`wXDpNWU8k)V z*6KR5&yYLS+F|3AyR6u>HbXM%*tCtQNs>#?YM=k~xO@(~{C+lzP6;c%Q;s`VNIqWp zclGno_8D@iDTVGavZpT?&2r^_d{(pfh-B*1?ehZN?G3oU=Q7GC&iT)jc7EoQh0G;A z*Qef^dxmQ}kFIl~*$Unp0XZ3Me22x7&(D7H>56&9cU?PcehV?bht)sWo;En1S7Bdg zrlPfF$4Y}MJu=7a9#1IjKPhvwMJdthpxO$S$&XaF7?s*ReSQC-|NgY-^Oo$cZ`l{| zNE{S=%8^!_y*i{*E=p*IgiybVLgOh%o05jx2VYaI=82#jp9VfLNnRIPQ@TEyxRJ2bNZJJ}FeEy{IsX0pd z%QClaP8H*~YM*zF+nO=m)}2>WY~u-?UCT5zuNCM&=nK>|%T>t?xi-P~WcH@6Jxbb| zUR_N_+RGm+N`Jbl-_rftioHxb{dLuY6+$-~*mN#k2=U?mboz}&zr9QP3La1CO>Ji; znTrH>X+8}(Wi*>_{f%zv-K%~awf)@Aw@th(_IdEbDI5B7H<w+4_2$1a zcNx#=>~-+U?%uU#lV|b2MRQ^vy>I^cq*45P-OCI7k6NqqrtD_D^E!Ebz;lu0J9Zz9 zJ~Eg)PhSzVtaRfgo%o55pa1x<#&T=%{lD>bKU>}T-tAy@h2VC?rZ i_v7BFH(GE1$NOW=ZkIK(of-@b3=E#GelF{r5}E+#?9BN9 literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/ccwn3p08.png b/tests/pngsuite/unused/ccwn3p08.png new file mode 100644 index 0000000000000000000000000000000000000000..8bb2c10981594a83b7a8981436225d0b2241d27b GIT binary patch literal 1554 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4rT@h2A3sW#~2tGSkfJR9T^zg78t&m77vn4 z_6YK2V5m}KU}$JzVEDzrz|io5fuYoZf#FpG1B2BJ1_tqhIlBUF7#Nry1^9%xe%o-b z^MC1+|3`WMXTSR2WBPyXf5QVkp3@utU;C$K@_(br1EYU39smFHl?47*KFWOg1Y^$s zbGrZImj1I#^8a6M{6FF!_muy7$twRl>i-`p{(t8G^4{kEowomX|G)T5`v0_P|4;q5 zmW}NEzgOb;fBBdyoBzLm|9SGCPwxMm#{XMA9{qFF`2T;!9o_%U|L4hg3hzt!ze4r@ zMZy2olm2@L{l8hqFjF@F{{zv#-~Y(&c<_Jg|9h`$<{bI|;m@CxKMx)iX8k|daO>{f zufG!B$^Bot?Ej^c|DS08kN?J8u*LMh{Qnon{-2Hg-~2y)t@fRN|AlQ+9{uC{``Y#Y zzW>S2w*R|NoO^rfzsRBg-v8AWNd2Gir|H~(gPu$Ojm6FXFJ?&Y`@i?!|6j8o{Qobh z!~cH+=l^zrX)HW{UjZ=+pgQ zM1J;v{{QnI{QG<5|AqgBK7Yk;_MQCy|A6eg{|yiRdkO!qc0Bn1*Y7_zAOC*aeeZw4 z;f?=w>i)|q{!d)=-*EH)7M}m7B>qQ;eE!S%KQ{IMI`{v*|G4bF-h2DsXT3FJ^sm2b z9RAOp@%~@z|GJR>TTcD&{qoml;{V5D%m1hTKVivy%zx?sHy{4}*G&7%xqa2|*K_`F z`hR-vqW}EgOjhpt{_lV5y2mWf7XMHCKW)PQe91@uBmO_`nfCvk|NnpHf9L-z^#4n@{WpzE{qyzzgd_ibOaD96*ZnX0U(EO4Zq@%j>HPnT z9xuK-`@g-z|MkZIx2b>rEA`)?=KtOQ)ffN!tJ?qnQ1k8I|LS0c|CSRNj{Lvo|37ru z`~P3pAN>DcYOUS>+xp@E8U;A4`J=~g7?=Fxiq!tUW#^8= zxBmBD`v3m_oC~}DYabByTE)P?wBFOjF{ENnvV{|afxy}Wr*G$;x)*bY%VhViprCc@ zzaLtv&^L4EQst+=zHZTa!xb|*J1gqWop-VRw=?E+`yNzTEERjVG;h)CpJsV`_V5Nb zh8DH7Dp6%ouetfakjLNBBip_$L9dTuk+g}$MAXefX7) znR`lJ-m%-crcFQIPd8dkg(XC3-J|Q;d-@YK1L98K|L@zB+M(QhZhG*?`qn{_L#V{D1#G2L>Lmth~QJd?VYgNe_LqvU16bT+a%NfLpfzzf8B;V1ED2jlgK@=Rb?9SNxf*o|N?NCzHb22@PH| zEH`KLO`5c~o!#8Lyz=LtpYK_cwl9CKm~?qlN4xvWnX6W{x9|Mue9PgJmG(9Y=8^^%#kulq3>E^@63=9kmp00i_>zopr0A?|9i2wiq literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/cdfn2c08.png b/tests/pngsuite/unused/cdfn2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..559e5261e705daf7a562a18eee445ccc35990e97 GIT binary patch literal 404 zcmeAS@N?(olHy`uVBq!ia0y~yVBlb2U{K&-VqjocFlk*o0|Ns~x}&cn17q6)!xz)y z85kIti=8|}SXfxfe{5aMz`(#+;1OBOz`(!=Qp#WyWH6b5fl=Ml#WAE}PUxk?!Z!vy zEDzSt6cAty=4cJzXkA<&@=IY)kOc>Ct3!rDh`=5BvN>jxC41M#W`fKc^O|nUqIEIgu?oz&1n&u=MKi)Sa~Hs{_5sm@mE*vTkW&<1*4ze-YZuQ6>gQ_ zEdBcRu2$ZwO<`Yyc_$Z?nYOCx?=Sv*0Aj z{8Y2yPJgAL%(mDEJqI;5Xgj)j^SD`9TAWs`na1URsc-8|&*0!f-QJ>~b8Z>0WjVe6 zNc7RkO2@C&7MRE%w{^Vbv?a1vHgmhB(9OVlhtfZ*cilNIFK%4AtXSd0b_NCp22WQ% Jmvv4FO#sF#r7i#f literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/cdhn2c08.png b/tests/pngsuite/unused/cdhn2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..3e07e8ecbd08b38031432052c4f8a4b02f866b8d GIT binary patch literal 344 zcmeAS@N?(olHy`uVBq!ia0y~yU{GLSVBp|jVqjnpf1dS&fq{V~-O<;Pfw66Y;frbU z3=9m+#ZI0fEG#VLKejGrU|`@Z@Q5r1DPv$@U}TVg5t_=t!0_7B#WAE}PVJ=ZjfWLP zTK1p0avOYBwQE4~WcT6~a^bB(@2gu;}2u`V4SbT;SgC`i03QuKsH;h^Rp z{gx3U?us0e^ zoUlryZI0g(Yl{OVUqy6(d~&l6j@RNcoSEep{nKie~F-3mu$25Un vrTrRq2iPVq*Ef4R_hWPWy_I#@m+Lvs#;nTN_j?Hg0|SGntDnm{r-UW|G~0<` literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/cdsn2c08.png b/tests/pngsuite/unused/cdsn2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..076c32cc082066dc870e1282b97c15ec22192407 GIT binary patch literal 232 zcmeAS@N?(olHy`uVBq!ia0y~yVBi2@4kiW$2Jc+WI}8jAEa{HEjtq=#3k+XOi)Ub9 zU@ms@3}InmDgUu`F#`hwXMsm#F#`hwBN+Ru9=XQAz)QHSDdsNxg!`j6&k$`913I7UZ}lr>V_JV)}J$djCSsfbvBrAW5t;Qv6?drlk9!& zWQteb)sDVb+ijYC(lf{){__j7Z@0}tRMg$GTzUnL+XXZ~O|AVC5X-$u=v1P(u>alo f@^%rf8b+-R`WM9GuB~HWU|{fc^>bP0l+XkKErd(n literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/cdun2c08.png b/tests/pngsuite/unused/cdun2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..846033be6b4fdec08cc010aa0abb35428b6659d0 GIT binary patch literal 724 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4kiW$hCdQ-7c($0u%tWsIx;Y}EiimBEuMja zfw|bpGlYeOrToWMkThq3M`SSr1M>?IX53mGl+D1vla>Rw?MuqvTxi=+ws{AhrKYFWw{!H@= z{pcnR!AqA9@8M;XIn#T2Vy?hHafbx9?{i`|vM@gCX5gDPJ$Abp$5Ey;A1do?K6|$p zeUa$rW?+vun0?;#*Sa};Hb2fqHuc-}t^DKtUMeEdI(3y2*M^d#pC+8y82xj5ljjH9 zZ~szemzs+H3N!Avn<+O(&A$9#*yU}9-Y3hNC)3}jXR5iftG_G#W{%-cIC}MtQuNOc+-X4>RR-#3uIHwnWyo;$y}RP`vYFQp8Sh?w=sssF z*Mr?6Zy9*6`=s1le~HCDfpKG<_V){IDLE_+eOkTB_kX@Ch|pnXDOmt&E)aXESCVKQ+_xZrT~X_Out=HD51YbG-0rz3@Yq>F@t?Y&|bl z@0DpkZ{7W5#%pzNKYW;^-J{L@e0|Ho+a-2gML8EwJTqnZ)>$d)t9S9~=QN&xwPpuC e{`}YUms!B!`Z>Lv-9iiu3=E#GelF{r5}E+XgGo66 literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/ch1n3p04.png b/tests/pngsuite/unused/ch1n3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..17cd12dfc9169036898b84dfcd8d7c547c8dfde0 GIT binary patch literal 258 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I7G?$phQ^Te;|vT8Ea{HEjtq=#3k+XOi)Ub9 zU@ms@3}InmDgUu`F#`jGZh%jSs}jS1hX4ON82&5$XJDB5|9=|8U55YV{~7)>Ffja| zc^Aak{eL$DgUf%0|1Os{c|G)qL8IAuNhiWk}GXC%A_|LFv6(b{q z3j;$(2gCm-r*}m&DE(JTGh+Dvf99%H|3euVR;^+~Lau^Z!ov9ftpRb}<+mGrVPZTg>qPf5%KO2EqUT%NZE{H#7dG<#RU+Mqqt^#7{= z|L@%S9~#QQz>s$54#ORWJI((Y%gg`&`}hC<|I`0NL(9t<{{3S(&2XB5;U6Ot10w^2 zkP^fH|4IxlF0=m||G%<|fgyC}%>OfIGVEg5r4`EX|MclC|I_}@Hva#A*D8ipP8|%v zs~G;TTE)QdmSNYf|NjLU{(({y!_1j88D{=JGjkUMLkB|#!yShIla&}4?)>}zZ&ffu zIYT)UBgjey2IK#4|1<1j_-}0d_W#@eM>_WWFK1ZAkj9Y4prmw%fdQ0Q{@?lEEy%!d znt_oqlp&O%gMooTi4o-b({C9V{&#e^Ft|kTV)(zO{Qu1V3~3Cz{_kQaFE4%za)>d5 zF$2S{|KC5h@$~|FZD{h{*=V;|R;Y^Q{&OT4ItSt_(DoMZm*}=BQ+tsYNt74YAhxZ5j z%aP{=xM^J>h5kZ=reornwbUjeOJ$*IFD5s8fu4%-Z!q`1eZp z@@oRVD^BU$x->&{OSo&2^{Kp(^m!fqatv-7kyPfh>c9Hb)6{qK`ED?Wf=`8b%e^tRmYo3J)vYofqEV5X+ z<4pURCl(t!qx-`c=%aaOMNh0tnvuaQ@tbFr zdzRW6cGP`QWZXY_qWVpzIg7dHo;=O=$)Iu89ri})e**2(PCNjW+n%m|F6*2UngDNe BYqkIY literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/cm0n0g04.png b/tests/pngsuite/unused/cm0n0g04.png new file mode 100644 index 0000000000000000000000000000000000000000..9fba5db3b82ca7725816efca47adfb44d61292f0 GIT binary patch literal 292 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I76t|ehRF|4XfiM`u%tWsIx;Y}EiimBEuMja zfxX1j*OmPOBO{NJ#oamo8yFZEPI$UFhE&Xny?BuKkO2>CfV`Fi#|IACg~}ValtUh! zU^QfvHekvLa7$pmvB1rCD%1QUo`H{Kw4NU=eLE#VOtmn(k=JA1$5|aKKW=HrW%^!! zmgCRX2lwZ5UhK8i5!sRU#^0OkIs1YOC4C1pPP}J*GU>Y9vbS#B)-M8fHLTxPT~Y8n zmf5mhpS_@8OGV?2*2~H_SDP1H|0j3rnikk@kH_`o5%P%0- ztcHxz2242tZVAjc7P#3?WtxA)Gw_j&*7KvKZ>J=PsTO88@_NksIICmj$1M%HOyBFz za{Sr);QoBhi@mlwB0JLF_+ zGF!ImvlsMhsc5{>dRh7AYV(5Y|Kx7HeE!1WyYn6eA;He-%d#oQ!UJH&c5J6N#6mD6Yp7{Ou8<&?5!KO^^1UA4eR$+R}?&t zWwvbBXD{g2Qqg#$^|JEK)#e4)|H<8Y`TT{$cjr9{LY&E03dQDi``r#zZqYO}+^*N# uC|V@&_!EN-jZe}uG?q4&{AG~4dC2w0|ITcX_dQ+xT-G@yGywpT)^bz; literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/cs3n2c16.png b/tests/pngsuite/unused/cs3n2c16.png new file mode 100644 index 0000000000000000000000000000000000000000..bf5fd20a20445fb7c9cf5d38a6ac4cd0fb28de29 GIT binary patch literal 214 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I0VW0phBY0A4;UC2SkfJR9T^zg78t&m7SF)I zz+CL)8N$oUd%?W-AOizKou`XqNX4AD(+~0#=y1;A$b7)@LgT|f4yir%O>FOzm7E;rCc3&XyE~j@HwaeCjHxe6 RXJBAp@O1TaS?83{1OU;1N@f56 literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/cs3n3p08.png b/tests/pngsuite/unused/cs3n3p08.png new file mode 100644 index 0000000000000000000000000000000000000000..f4a66237bfb3a113b7874d569367932762cd0ba8 GIT binary patch literal 259 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4rT@h2A3sW#~2tGSkfJR9T^zg78t&m7SF)I zz+CL)8N$rWym-FVdQ&MBb@06uR!@c;k- literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/cs5n3p08.png b/tests/pngsuite/unused/cs5n3p08.png new file mode 100644 index 0000000000000000000000000000000000000000..dfd6e6e6ecfcf1d0be69730fb34292c8b6561376 GIT binary patch literal 271 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4rT@h2A3sW#~2tGSkfJR9T^zg78t&m7SF)I zz+CL)8N$lSDxr4InSp^JA;2fZ^}i&8(|?Ae{}~wmS2O(I%kcj{!+!=4f9e1K_ZXJ` zXJAPF|9=hxgW~`HQ49?Kt^QjvB>!i423E!JKS~j#aSp@(dkoM1|Nqax(DMKPUIqrI z|NpBQT0l~g?)t4?85kJ6JzX3_D(18vWMw?Sz|dgu?%lh;(RNJIlO4V`g?-@2I;g6_ z(w-pF(iHT8i_K9Xf@S3c;gY6E0nRW-of|Bj3F0YDF$G*&2X!-!@E_bw~Nq_Zy`;1fugk+p+k-<#T> zEF1>Do$neSIBs|lFZh6Y0SkWz~JfX=d#Wzp$P!y Cx-zB! literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/cs8n3p08.png b/tests/pngsuite/unused/cs8n3p08.png new file mode 100644 index 0000000000000000000000000000000000000000..a44066eb6edf7e7c45720aed393b64efa2381847 GIT binary patch literal 256 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4rT@h2A3sW#~2tGSkfJR9T^zg78t&m7SF)I zkPzS#;;QhU;lDfs2>-vo;6DSye|v`i{~7)>G=SLg4FBsBKs<&AAntsI2mc-ZgX9?w z{QrNSfnmY_|N9vj8vY*u$?pF@pMfFa|NnXh28aLu;~5wf{{OdU*xa}|nSp`9+tbA{ zq+(9%K~}~C3=9nh@7}%p8*RrVy;VV=rpdj4lkcF?43_2vf;mkQ6S%b;^#f)qh^RC< v1#m?j)azhbxj?w5DRKjs-$C7qqx_nW>==K14!+62z`)??>gTe~DWM4f$ar9+ literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/ct0n0g04.png b/tests/pngsuite/unused/ct0n0g04.png new file mode 100644 index 0000000000000000000000000000000000000000..40d1e062f8cd792950cbc4307c8eebde62ab5ada GIT binary patch literal 273 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I76t|ehRF|4XfiM`u%tWsIx;Y}EiimBEuMja z;e@A)V@SoE*oy~w4;k>V2FPnUaD3p9U8uZ)OF87x306Z!X#=L50Jj9@8w=cQr!vhy z;u-izM(g>}(zjC*#8eBj8+kqEeVo;?^5d3!)fENLW0@`6_1O#hwNy0TXuYg_bG3QF z^?!1=UOs=}@ZEWjf)Ho&l|r$3-F~-2m0L6o4Y%v{Hi{MrJo%8uEdIn`L*tY542`9Y aC4U*@ZXR;|@xL=0qZ};mPz>hkCFkdA_MLH;XJBBk0BLs4FQ_caOwTA`fU^{!CLs*bQ3%e= zOHVAwFG^J~w6rwUwKQu9V6k9eVE7F(!zHyixhS)sBr`vc!BHVOKer$=ClSO`$WK#9 zR47g@0WmUj6Vp?R6_Sfm6H8K46iV_HN>YnU6iPBuxyllYGV@D|6_WFF@{4p!DhpDJ zK{`q@QWXOH+!fODi*gf7^b|bvl5WpF6v{J8G87VX3NjKEk~0$X@=|jkVq7IfiFw5ZiAAY-$(2xpi}e&7b8-}tGD~z* zQVU8liWL%ba`MYT_9Q3g7o}w8rE`H?n~|zeT#%X!vR$E|D782>uSCz6lQ)}zfx!|K z48i$nCFO}lsSM6gFXrbdBr5o&MuZfXK!OA8KZVlb%)E33rGmWNlKg_abS1qkp_EDn z1_lw3AugH4$vKIcxv51AZbhl7AoKL%8+5!F7#L1?x;TbZ%!$2tkoS-Q4{LzDmIKEJ z4%vmu8@QB19-Uw{WRx~w$_a2wV7{@y&2}o&{3D)$k7Tr-A1!@5B|%KJFuRf0W8TME z9VX~<>zUVoP3&(;U`=W|}{wbc>Xk@m*lo9j9If(s>m2Q*H+XMHm1y4plk-(D=Y0TnJ3^p`ANzc$&+F0_JLGI=u*B}2oK>^3$>FVdQ&MBb@ E02hEDfB*mh literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/cten0g04.png b/tests/pngsuite/unused/cten0g04.png new file mode 100644 index 0000000000000000000000000000000000000000..a6a56faf2b3e8655f88c028070ac174823ccefd1 GIT binary patch literal 742 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I76t|ehRF|4XfiM`u%tWsIx;Y}EiimBEuMja zK{7KWq9i1@9_n4Vg!kX)3SSdyBeP?E1ul3HA%P?C|VP?lJfnO|D0ker{BU!+@7 zS&&)`(gBhR@N-v4%P-1JEYVZ&%uCKGO-W5rNGwWKNXkh}&Q>eW$Sg_KfoRlGC`imn zEh$M&(NQSREXhzv%qhr7R7lQ9%*#v7fr^zBCFT_uBo?LSC09ZXF4j|U%*jzm$}G`M zNi8VJC{{?!$;mGV*^``{UzC!WmkxGqMyf(_L25GC_JX3+;?%qny*g7~7X}6fcTl(l z=ckpFCl)~?6wY&odN@B%AyL6EH6o!KS$A@ f;b3c3UkM|_-OZl^L$8@k2PI%nS3j3^P6 z)a=Zx!%G;#GjnoMa}~-G^Av)UGZHhi6*S7hLJq}Xu3mC}uBPv%8CMw?7(76RIOi8s z7G@-id3cFJfSesOW4o`P>_c4A(lLVlh?ZfS8zVp(EN zc7A4FYMu^6qmDvBVoqvFNotCYLSjxqMxriAd0C>4LSk8dW^QR|N-9Vv%rx)B%gnp| Jvd$@?2>^p10G9v& literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/ctgn0g04.png b/tests/pngsuite/unused/ctgn0g04.png new file mode 100644 index 0000000000000000000000000000000000000000..453f2b0a49ee544fcc6b297a59dd685a06285005 GIT binary patch literal 1182 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I76t|ehRF|4XfiM`u%tWsIx;Y}EiimBEgmG9 z84^(vl39|I%D}*on!|8z$+`9CTh8r1xBq+-LqJ}7aA{^qszSTNP6h@BH;`J#(vpn) zBB^$xAA-vLwIIRPHL_~Sz?|-aB@asX10PxIatV{7|hj6 z&d=4nre&7Kz`)Q6GSNA|pt2}4J);C_=z?>5&uu;5dT!6Tjptj=?L4>Z+!}>*TfmHs z=XRd&gGy{+jR`*=A7GkZll8a=JT!Rc7uZK+~#xZ6wYlt-*CQ1 z;oMq~=^)A8b9>M22T3cO+Y0i<`JQuo&v%~Nt8l*I-2U^eAir%tx98kW5a)a&$c%G4 z&TT)p3*%zu5&xj?K!tj;d~3&3~<0~Jl}S{=X@hr;CwrnvFF?x zhzi~FE$4gBH$dcCKz1mc+jDOJ`Ns2Y=hi6%__^yToLg`X;EN_ z-*Rr_xt$8<_JfFx=bO(roNqke0}lSy^Nr`Wo^R4o09yx+5*>wt#GKTUlGGF(kPTZE z&aFAO`+VEEjS3L2fVk&&!sK91SbM%n;e5-v?dO|7-rEUIM1ByfiaL{c&w-e!PJ)L>$a~K#HVm)0PLo_DNJ?ALMpvdEVG2Rq9i1hkCFkdA zp7*VN4%QnIQR19mP+63jo>2l8V0f@(>Vu`750#q7 z%a&|-uw=!9rR`vYz|N| zX#!gbmg#@6WU9i0B|E@zF&~RK$nL2RmTY>kWQCprD4s#at^+%96I3}!7VOn250-%3 zwBx~&)nN0M=^&gBVy=3yv;(5}!IJr46$=#}EZGSbZ2~E11aKZU$CFO}l@I1ByoW@s!9Wfsi zqoDk={=t$B3=fuorTcKsS5rICSU&7Z-}sy73JgU9EaJZFC&1eIr=u6{1-oD!M<8ZpS? literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/ctjn0g04.png b/tests/pngsuite/unused/ctjn0g04.png new file mode 100644 index 0000000000000000000000000000000000000000..a77b8d2fee4c377c20b8e751317d094cc2be3cf4 GIT binary patch literal 941 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I76t|ehRF|4XfiM`u%tWsIx;Y}EiimBEgmG9 z84^(vl39|I%D}*omB{e8Y5(JEy>6) zf+&75ar%pfR)+A*oSf8Lg|fsvh2Z3j#LR33jdHM%Lot}EmzP2$o-Lp8xS{oN zC&>SeGaol~KW?1=xT*1R<7$wzIwm}Bocg$_2Q0Ycar45*&3hgjn8N9eYtxQSn=w| z&0s?s8Xq@L1P33)Rm&eY&V1a^1R@)EK5m5AI2mHmv+WzfZs>WscE-~=D;_sa2P*)% z^U3b1pnz&z{dC{t$Bm0Y9&eodxN*hf#-7KG%O5xPg8T(iKmTz<(_vQLEes3{$)G3* z&QB{TPb`8bs=Xi|GdATL|1$pU8kDDev*}MPw6sX01sSzQ?C5fQO zd(pY+$&N0Jz~2Y*MMKk}<{t(O3=Bpf>s&I6lXDU?b5o%S^J#1Ei%n~u?CO5Gpp^k^ z^(s)%f)W+T_QwrPWgncMF)%Qsdb&7X=(ob z&;PirWPbS{pK1JrCD t=JRuQR!^5qZ};mPz>hkCFkdA_MLH;XJBA(tO|)Jan3KOEXqvJC}Cizm{WXCe}&E| zpYs}l9OuuR^gJ7?;e95U!|$BOnKRb{InJH&_SZR~?-gpWWsAwxttQM2-HH55f}*Af zF)%Rf1{vm(TAW;zSx}Ohp9eBdw{IigAp;(l?{!CgeU|<|&=MiAKOx3h>5hdLPw0QS z@C}jss>{onZU=3il&-yjog=o!{*#mc%Li&tj1Kea-F@iU#=kY^{RN-3vbC!pax1Ca zS(k3JM)!%ZUh7v|c5mOd-9r2MvQOzf=9dZdJgQuCWR`8?7BwbyE!QvKrS}BBG-cw- z|Np@5;gYWEZ;y4Z2J;8x-mRXo_UulZ_S)PvFGDNx-E%K3{qcoW{!1Pm?|uf9e+T>Nfs-NpuR= zry}o9+@CH@{lc*9jiA%Kz!mEl7#L(hX1Qb*C+8$)=B5^bP1E-B)%Dl$y2{KT7|NV* zW!={I3=9k>JY5_^D(1vqJji>oM=+td5l*w>0E3eXl>u@n`FU`|~+3_S))* z>_~g#@6Gj`eZhs2z5^O3-m^ZLbX{)QTQ_d&7XiB(*6*vXD0m*rY}u~QUeK?lqVY!S zW#yZz%?qyole_iu`3r~d&U+MuIFqjwip}fxyB(_BqG@QjU9Y!Mv`FB|hcssKCk7iD ipQLAKENv|L%OH32kn4~Co!JZw3=E#GelF{r5}E*#0y6vn literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/f00n0g08.png b/tests/pngsuite/unused/f00n0g08.png new file mode 100644 index 0000000000000000000000000000000000000000..45a007596753f6627224931755c073a3362be88c GIT binary patch literal 319 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4h9AWhA=@@4F(2AHcuDFkcv62m-Ky{0!5C0 zT>n6#IGN4doT)KsL4?QpJzr*Zrfn9?3{md&*nBZZO{gyrZyJ~3QXE191>KebU^*9 z;+0qn;l}!%6N2teTgUOivLJnh-HQ$ebJqIks}i|_55E|=mY!P4v0wgoz}jM^LvPh< zSq^UG@c7lyG>v1C!ncp=7GACqzrJRMxqh>OauV(MIwz@gKqy5Wfa Xk=j!c0n5&91BHyItDnm{r-UW|MPY`} literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/f00n2c08.png b/tests/pngsuite/unused/f00n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..d6a1ffff62eb0f1f1dcdb4ba2b1d30473d3adacd GIT binary patch literal 2475 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 E00okh?EnA( literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/f01n0g08.png b/tests/pngsuite/unused/f01n0g08.png new file mode 100644 index 0000000000000000000000000000000000000000..4a1107b4637642335b8ec7b8e1856dc0ba7dab70 GIT binary patch literal 321 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4h9AWhA=@@4F(2A4o?@ykcv62mlVB^I0~?S z_+D04_Kn4mqv>FRVT6ua_sKLN9+@jx!I5a0T8g(UfqG4!9x4lfykJ*Rh1_RqgoOYA literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/f01n2c08.png b/tests/pngsuite/unused/f01n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..26fee958ce7e62a59843205ad34f86a525718595 GIT binary patch literal 1180 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4kiW$hCdQ-7c(%hBzw9zhE&X1JI(%$YN%w} z{O^DMo||L*{0)Z*i;_r0=S`>N#)&LK+8ZxSm=UmH?lCtmUk#lM4-E~S9>a}`48kTg zY&5+PG-2t|n}?hhbMmU{Tu*v;XYS3vZ`&43US4tD{ABIy{CCAAhc@)woS78_irM;0CYmUDix~>Pb=dU3aMAbt zBNHW;O^oc~*rqJZb+BW1&HYNX8)o|_f4v^x7H7hhd`UwmwBq)}k54BYu6>rxQKnvf zSp4rx^M(FjJQo|ya!Z}rx>;5-TyDzWx_O1$&i^|6Ix+8y*L+i{#o1?coKKXcgzPIh zcS0{Rf8WdKqdlW{bh|`0%l%pybI^Z>R{TfN`yY7iwM%N$d0HFg zkGQ^nY5d^$^5eqWCT%acx+v34}CeXI-8 z+?cVXXikSZo8|vS0!CwUVqHM?OM zUvBMGVAYwVET$Q#YN(pEOl{RgqqBbY_1p#T_n*?}=?vTwV$GHE^byy`6Q+yQU4s-{ zbtYX`JvZgdl$FQc-+#Euefz&NE27e@xsH@w61Z+~l3 z*C&@8Ta$VtP(fU=qw-jFl8Rf9RkB;${@G5NKEhjrR%b0WHEZ0!*07qocp2#s5gjzUDdKcTZ3cda5B{)@ZKiYM_)k09)y>SC4i}aI)n_|u=gz3rNvJ&~oIlUmW z{=A~dp_cVBtcTPDE-CPR+BD1Y^}e~*H>{onx(H6c5S6U)_`0Y)cgtdsGt~sVpEs>- xUfbMY<02B+)N<+Lxncnh_r?Ojj`)AvPVcI9o2sWjXJBAp@O1TaS?83{1OVloId1>} literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/f02n0g08.png b/tests/pngsuite/unused/f02n0g08.png new file mode 100644 index 0000000000000000000000000000000000000000..bfe410c5e7caaa19aa9f3294da29847720362d16 GIT binary patch literal 355 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4h9AWhA=@@4F(2AEl(H6kcv627xlfH10`5L z9R6t`)~(Q?z|rK$!`$q9gIz)=qTSPgCyeDVH#hU)gonOO2|@>xHcIF;ISQ~ieyM#I ze|XvVo$n9r{dxT9oX-UXRyOO^F8_M+{f+bg|cEK#4 z*D)7V7vK*c+@MW5z&KeSQOQq`gXT643PRoxh;$Cp;l3u6Yf^Q45yX^v29(@t@ zDCOc){|nEPSa>#FeQ9jSR`oOX#g-Y2?rTpQY83L8+}gg>{}JDTH$^puR>4h*oPX@U zvO5cDug;c^wyvJ*Jh$1g^XXMr3GSwi3Sgq6NrCH;_{%5L_wPUR`Y$N-JYD@<);T3K F0RXgSmFfTh literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/f02n2c08.png b/tests/pngsuite/unused/f02n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..e590f1234816946731c677d0b353e2db5a08d71b GIT binary patch literal 1729 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4kiW$hCdQ-7c(%hb$GfshE&YSz3SPaQYm`; zW4?=Sq<45~>f5WYc{&~)e7mUP!m-H;9Sist6~8!m+CjPE!m;Ld$qx$*n3XvC6gryU zGBrKW&{De8vExCL?UyNcx0b#Qy%{R{wZEr+pSa-6k2WrD;nzxzf2{veU-ACv|G!Sj zN8DbSZB6LD{$^(R&E5CY<$p}5{jsa|&Es#K{x_G~r^oL|jIX(vS9f#YC)3}*yubD4 z-_pLn?S0+(x)093Kl;BF-@hgP|FwTV)PJ9je;faQWA*86`x2{vmkC8ipV8@AC&8`x z`P3Yv)jryny_{zTsZI4vb=tY0M|<(96-JA$Oi@hrkPKm)65!})xHQ1Z%l+h3pFrNb zu8U3|3p%xE(}FYFn@{x^E%wn4_S)+&6@E->Y9OW;+HC#B`e7nb%lo+4L zOUsRWyJoK7l6t**S=qi>pM74WojEI(cW_Z_llLjtx5-QTCvM*7>#;ub@u?YKW+Wzh zXt{ALNjbD5Z(ZYTGjn&7^q6aQYN?K^vM$ZL7_cnp)u9y2*;5P?LnJ*{YMLfSNcw2I z9j<7qxD+F6o|@N|acsw;TAx#kzRWV4ZlrxxKR{CWl*=jB#286$$(20|r#PlM9J;3Q z(c&X(@#Gzz#k`B!3PXR-n4-FJ)-IqDBS)qAY(^*Q*H2bQK+}4US zcUX&sTUSSi=`u9kb@k~&^G&`b+;`oYA29mYIDYsgSk)u9Sg@+g>dHc0 z6G!1Ii<{cm@0AH}6W$h;b7Y&`=0`u~Z%#cvdt&Z_@aDA2$M@gN{lDS+zsq(%@_%Pk z8j0_@=hA;6$jZ@Q`=z0jg ziLy`3zfJt~hr!Zi)(Pb&9F}f!;lhh`O>91vJ;|)%6Z$4x7PU=wv*hN7IafD6s^X1w zH^0#S;_<$z&#Pb9RdtwMbl;n`WX-ZEhc25<+@5@X;_{gV6E_Xi#mQz_}7w&dx_NoPmiBu^HJ~G?5Jvd+eUZ1d>s!8-V`P*?h*5|g($+e2^?qWZ| zwW;fmPK0J-yT|{WbK%PU69TS=_#COZEtIdDe@*@doyu zLF$#*#FnOX)rlMwut4Y?Tr_ zA7PW8x9|6xyvpAVvEpK_tch_mMAKR%S2DTGm~wBk9REqS3yzl*OC(m#ypqxX$lbdw zrD=&@_Nhm1g@5-yef#iOx=vKp?KJ)HbvA+uijfXx4SW;$7BrujaMIwdRNa!}Dvwo! zzx|nCz5RYAqj`7qh78B~90G51R~$bR!pV}tC>3^W!AXI)i8cKj*Z*6%y*_WhN6c~4 zg3CKByPtijX_#|nh&FG_FrgvpL`*=!JkITDu^GxA1=TA*{PW12?{pt~rTwwd-iJa~Coo%kXw(<(M z#1#}{mGw_>Z)!Sog2yx{Kwv_{^LdYt@#fuoa&7H{r_-Cm<9Xw%b$8TSS3K^0a8C9P z%euV4*qz_Z+#-U+oImkZPB(EcR#`mvp>dSgoJUhUECl;*nb@-5`?lw;%C@;T(oSDX zj_!TCZ*yvT{?12vCGULSEA2jEr#M${E??zz9rd#lc}{+i?7ZYvcq%j1=95enpG_^J zlc<7@b+xh8_M-9$vQAx1dDH#c{if@vpT5YW>m4|0N<`tIl?8X6-MIWkrs|t;neevg zoMSmh)>z6}ytCdd{_^Kpxg=Is$3V$SziE@xmPk&z7*^xu-N~x%lIwTsY@L`w2;-qu z$wzM%UDrCXfjtV?0P wm|8ARddbT1+pyZux=;7`vSi&$?0@8)?L?M`r`p;wFfcH9y85}Sb4q9e0Bmzg%K!iX literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/f03n0g08.png b/tests/pngsuite/unused/f03n0g08.png new file mode 100644 index 0000000000000000000000000000000000000000..ed01e2923c92fd8b8786524c6d6841365a44b9de GIT binary patch literal 389 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4h9AWhA=@@4F(2AA5Ry@kcv6Amo|Dk1&SR1 z`2J;!OQ3)tucB*HfQSi;9-rfBX7+`O99>ERipUcrH!epxjhp7n* zuj2#x2m3!tU3p%4s=9oq%#VWiJHMA-DK)xzckkcBizmnY`?98@uCTJSHdt$VzP9M~ zwYx%nI~5u(+-~!_`)N^Yp4XNOyo*}b3F(@6Zn?m6(P{b-@m9CLU!VSbxv*@$JV)>2 zZneKtrROZ{{;}xy^3op$+g~*Cv?$0N*!|Y|IcEpc73R6GWWuIAF#I7l_h^UpgS8X4 zI;Efa{PS4pES46(+x%WjZ6$@QT17k5{U-NxR!V*U9^|7#Rz4o;x4kkW{Ip=fS?83{1OU1@rkDT# literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/f03n2c08.png b/tests/pngsuite/unused/f03n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..758115059d78260f7485521b83a864d4a930be84 GIT binary patch literal 1291 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4kiW$hCdQ-7c(%hT=H~r45^q?J1w>&Bvs;g z{rNrV>Cewxm)sxqdxFj;{*9ZiX!PE4+CG8xu#=IKmTxQ9UI8AiD*lS(x`6Uaq2-r+ z!>cdmDjZabizrJJNP6npwD#Sbns;+*cUe52YiYcB_u<4D4`uG%|NY>gfkkHF z8;*9ZU9)ZV^;^H?H@&`g+g)z6^t>(7<~Ns{-+sRBR<8c7>2cfE_uRf-eyh{`?K{ui z&vkcym)-q7_V>Nt-wv>Ud!ShTWX0bn!PRee*cKj|_vcRC$EANy-3nfQW@G6weOH!% zHlryESX?!n7`Z02+x(bNe1GwT()-E=OmYfhE{0aaWHM z*JSU+B)4tz6RUVWKm6S0U~(XSV$u}Z1>G-SomgH{vQ%g7;Wzi^EnE|F!Qt;zW}c-Q z=k%5;oP4!!lJIiplU$J!fo=zcZ9a%FODZ;3{=Ukix{ycoB13)YEX65PCIz%K1q6I@ zV*J#!{)ZEv+fhT6k6A7sj=U5w-l^?8(eBtRRSDPQCz|y&We=?|dL_}>*OI7q?}Uol zl-5bfJ-Vkm_C~q6cO@Px_r9c3=y}?!f$i1$w?}w5|8brFFFkL+=)B#M^L`uKRNLD8 zuC92NRq@R0$JZ^kdzW61TKspdDU)2<<8MC9uL7DamvC)1=)My=tImY`ev9t3e>G|I za~-rx&mOkfk|?KS@Orx^^GavgXA7n!ozW<@|8+u)@799}v0pdJTIa~yB+38N+atQZ z&iDJ(g^auzPL~aD@fq_!+jsU-3IA0gSqnDfRi^uk&;MO}$nU3a++X#(q0JTPnQqdV z%O%uqcyu$iS+t!w)D!e|@r=TVe|_Qm7uhWuG}tnm78l#c>bAZ?^|*oWK~qR##&C_;&xs8<@LswHV!PZ*Q0YY z7V2*4G`nCG<(!@I%wp!`Gp`Qy+&_0a#`+C|`Jvm3%~mWd-O^{apwaB2+AXK(3r@Vr zkst2-JiY6q1b^e6*;iN>vZQic@Om=+Q`s8XdyJ>Pbv|U67}6jS_Dp~|uI7h|WuN7A z{a7~{!BmbAZCU#ZAJiV)Ui*?^;z9<)keVwB^Q`Y0DqEis=*sJ3&sea0J!9nWTMi8# z^$ikUmLCEpUlQd15z)22Y}U&9lt+@sJ4!>o+|E=;{?5}H5*Sn_`KfM_L$lSSq=KJp z2d>B)eRP_>al_A;JDa$_F*G~gcs^BeIOSFea#RY{_|s3+?;Fg^^dMT z-P^s&@p$}Z4Q0LEinB`@rHuDX>C;Q*o?b6IWAUfY`~gi|QZD~)7%1}z9QF{KTIcp= z>hwuQr}|`j`cEHe@$ox#Z||mh`@K~x83I4E#Zx7W*hIyquujr$@_6Y{^oNbFYO%S` zrRMPWS<7F3UzS&Mb&@zwfTL)u#?g+J$`=+6w|oD*3+P$ylC{IVbpDru^+}V&4Om-P zU8i5WSk#lstg`B>q0joPS0y|ZSFdhd5#DXI%C@cW_WSfDdtYfx{KD9_S1PF_O}Oo4 z_TCv+QgzlZp1EoDyCq8`%WL29GO$S;j?=vrem3MRd&!v}|CyKeP2W5H+_ZlT3=9mO Lu6{1-oD!M<89Q^B literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/f04n0g08.png b/tests/pngsuite/unused/f04n0g08.png new file mode 100644 index 0000000000000000000000000000000000000000..663fdae3e7d906df7379d92621a7a951313705cc GIT binary patch literal 269 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4h9AWhA=@@4F(2=E1oWnAr*64FCNT2WFXS; z@cy^WXMN@_Ok!KYcYs%Od0xX6Z}k;ZbR)Q(6rUYnyv={x(xvL+^8YuxYVsec9g}e8 zxL2)zue11EWOlD1n{s+oKdaBArJVDe^l}?mt5`QEH^?%siTUjyx^0fu0YPr&_EQ3nGXqs{)jaEP^75kFZxEh6F3_MJ_4Sr@E0VLN}?o4;ab7<^=+ zwNG6VUZel|VE)J; Wrsl)0I5VLUcAJH-YmzJ|{A= zT5L%0nC`?Med7=t4@cfdo;g+9mpx&)ntIsd@uk<_OssD-9n`f8^I8}XzxML3qAB9% zdv;qcDePAFT6)E4=|0X(OU_wMO5OhFvb%I8Tumj-dumbHjUW8Kep+8T zv)CeN=I*$xMv>o2SGiVptO;^%HM6VH-ahd`_#wxYJzopB>gx|I6x00XuYQV2ccM^N z;?MZkSECR8++{bbeEVvRR8x;_rdvChyRDuqKfi6_1Mx$Z$Ez$JPg||R(9GA^<2F4aKKU=NGa#nT5mwCLu#5F7S-(Y<7ep?ZH%_{%wZKk_XWHCDi>z2K6oZZCE{a< zrg6wDReQdvmkRT5?mw*+Hc7S5tGn~pPmO->pM{+MUsiv9d#F&qJ@54tr%5{=%b$yF zOz&S=A1^U6VZwPv_n^5opH*|uZb^!|eAQ_6Z}I!g&)$}wne9-$%|7C|+O4>{6CZhw z`Gy2|Zt8cNsj^bnu4(0^bv4UpC>yZ!`SPoMzA^D|ih7{NQk97&FApB&S!NKt>%sHo zQccO?w~Jfkq^v4mwe1Q0^hz}LxNnw%LHM(SzuoyyZoIi{`un#0Uf!Gp-fWHyP5c{L z*m~uxO$3%PALV%)adt0PH3Qr6GWUJ$A2+|0d#C6iq4Vs-1$BYjZ&fB{dcXKn=)dfJ zqK7}fSlNTNT8oJEU+dU53G=#0JH0NJwcN6toso6&(^H4cehX>dIGwd-g3)8?w`-M5 z>U22UwQemp?w@Voye?NP<)bp+9t3W18S@YeQiYGMBHm@pT z*XC$l?i2R8q4|wDf8QxX{!dGJxVf(VXTEtWYhT}|#eWzW7#KWV{an^LB{Ts5t5eU! literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/f99n0g04.png b/tests/pngsuite/unused/f99n0g04.png new file mode 100644 index 0000000000000000000000000000000000000000..0b521c1d56ac6ba14d82547eea5c87dae391cfba GIT binary patch literal 426 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I76t|ehRF|4XfiM`7J9lkhE&Wc4czF*xr!~Pn)pNMZCzU zV56uzkB<@U(i z2W~FjnsF;kTeZ^I_^JPX*$p4A9j&gEfKamHREL`#*WJ)?VY7 zqWJvbn}<^;B>MC?mZjWFJuk1VerI83g~*wl-)kloJvdc)YuAcDs_|N@w_GawB-v0C zeM0b;C(jnyu4wbielD89ecu<@tL~2V)qDN*^^&lk`GJr7COGjNN!dAXwdB4@6DR5S g+uxSIfA&f}V?OKV=$7XtOF)s}>FVdQ&MBb@0NIVb^8f$< literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/g03n0g16.png b/tests/pngsuite/unused/g03n0g16.png new file mode 100644 index 0000000000000000000000000000000000000000..41083ca80f964707b6b89e1cc1266e381710175e GIT binary patch literal 345 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I0R{#J2DZkZ*$fN}Ea{HEjtmSPJN6#++`z!V zDB$Vh7*a83>s4Q_Lk0q@55m_(xdvz)jXfA_GX2ArIHm0ZF&s)wOCQDOmMS_L3ky4! zh&4*Scx}FP%f-KZYZrOEUwY;Dq6@!wWPUkV!Zi#+o*2RGf5-fN` zc-ZDO-S(CL^1HD~g;V59RU^}NEq@n(w)FXJ)9}7qwDYz{#uBsIjv3>#x0& zFDY5f_hn+3;b$(rwZYXPJm9>7Z@INZ7pI^4pGJMM#&L3q-eJOr`<#z6ZgpC}+HVmbrJ#E@9cejJW%+uA+Wt~$(696#3hJXM7 literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/g03n2c08.png b/tests/pngsuite/unused/g03n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..a9354dbee6f36cf88f7b6277d3fd43b6cabfd84a GIT binary patch literal 370 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4kiW$hCdQ-7c($0u%tWsIx;YH?AUwMa{~hd zqo${eV@SoEr_+494mk+8tv3AU!XhYAuD9n%1xNpD#a|+NEaFB@5-D!!ZjTRjoK)$5 za(Kt4u&G{4XE2fS+!S~G=c1pd*jRp;H-Eg5Yqrui%-n+M!N$nV4=?0yFLB<@E?G03 zk&U@LdB)8=arNkP@`92zQyCX&{9bupb-O|{Geg#I{%;rN&vRU=(0qOuLyE)pr@MI8 ZMa_#;W{|xMk?H^d literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/g03n3p04.png b/tests/pngsuite/unused/g03n3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..60396c95af19fc5f14aff9f83d391331a32b3dab GIT binary patch literal 214 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I7G?$phQ^Te;|vT8Ea{HEjtmSPJN6#++`z!V zAQ#{h;>y6l!0`Y7e}?}ICr+$g%W(HDhzH`|{r`XMf5Tl09SjT%$(}BbAr*6yHQ1R{ z6%5#z92F8A#1a@7f34tPZJO!85ZbjZZG^Cd2f^Y@Fe=W=JTGS1t2>~miG^9}0?H{3n+U=h24gA70Oiozdtj}x|jGKtWW z<<&^oSYT4Ix4>Y2wUo=m#f+?H(&n*UUb&d@tpk$*b9lpzgDHs z(ZJKiF{EP7)oHeQha3dl_D?-CzsH4{l~tFO{Q=v@g|#g*4NXmLO-&veK}vO#PKZcs zXpW!bUpQHF&DV{Qw%O;IXK-UE1*}-Pkz+;zCzdf5NhFSW-xdoRE8B-j>ujI{UC};bB{{Y(# zwzbnZ6`Fn`ebnKUIXKDJro zl=$V$2))gZl-AFiCZ6J8yqhs>^&7*={6AtT4h{LnGkgwJ{k@P9q%iTI9K-jtr5`PF z%bP0l+XkKf@A9?;?rjO%{Ww~_u6kh4*PmLrA~sN$tI*-S{Kl2R zzJl%YN0)ZZQsTSM!nK-p<20Am{nDLloWIY@hy!t$S-7 UZ|QQusUTN*y85}Sb4q9e0F9nj9{>OV literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/g05n0g16.png b/tests/pngsuite/unused/g05n0g16.png new file mode 100644 index 0000000000000000000000000000000000000000..70b37f01e2b9e13a30a6e9d3c51a114a2f0953ca GIT binary patch literal 339 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I0R{#J2DZkZ*$fN}Ea{HEjtmUfZd~z?Fk)a} z{XuATC4kC5Z_wcL5zcZP8}#CIlWFVI*Q9?KlT zvg7n=wO6;a4ltfpTW30jV-}n4iI;VD+!L3bUmnD8T3LXR@51hBPfO;@&8{zS3AldS sJwn>$L)Ay7js>eOG^KFK@!KEde;ePD#^kv90VuRQUHx3vIVCg!0LhhvF#rGn literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/g05n2c08.png b/tests/pngsuite/unused/g05n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..932c1365364fead1166e4772f29dcb7657f73f39 GIT binary patch literal 350 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4kiW$hCdQ-7c($0u%tWsIx;X^yK%)o!ia%^ zQPk7LF{EP7(`lA`hYSQI;sC zocnQH|NO>9JMOGHEqNwo-7foedG6^9JZxA0T0Y_3!SSLjQ&mHtPjABe5|@Uo2`Wkr zJRBGDx*4u2^tm=Rg6-@w4uxjnC(^uvAL`kR986bScV&=dxxFZXE&Rpg zgMyzp8NXfNPjg_nx*)8XQ_D!fVMB09!=HA?S-W0t*>UX1nKPT7KhG=Hz-VQrYBs^z)@paD3ufOv)o{;a4xu;}wql#hL z>Fv8WUwROivf(2`g{b5jMR`}H2A;49{AmvLrx)&XHP5p2ojFHTC!B$Sfx*+&&t;uc GLK6TIIg{c5 literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/g05n3p04.png b/tests/pngsuite/unused/g05n3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..9619930585eb3798db54058d41c09f6cd195c723 GIT binary patch literal 206 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I7G?$phQ^Te;|vT8Ea{HEjtmUfZd~z?Fk)a} zkPGk$ab;j&VEF(4%o&FNXZ|y+Tlb&ge|I;-e-L2!-~GS%k;)_n28L))7srr_Ims^= zngSFG7?~Uu5*)-57#M%82w-ZO>A(=)sN>)+n(2_h!%`r6f@#W11B0@{1jn$032zQP zYH()dm@-{_%HdE2ZiSTz3F(YkjzNKOeC6z$7-niQT;Zs&_IkS@6yy+3S3j3^P6@uB6%h@dCt_xH8VcxkEN|Jt^wcFsL44`X{hmG_ ze;#JKX~`Gx$RbO(CF=UtsOsCx>`oX}@a8!%Wd7niaExVw$~3mZoJ;}NX>3*v*A#ek zc}p19ItoZgtywMkfS=cgF^c*Ac9RQ?J-pxUUSRlt?s7_I1LKi|$a{>+k+UT4UN_d zPY6D4a?Qf{Gu`6Ju|Gvw4~|S$*a~3%mV?Vo&h29prJ~`E~Eog4b_& Y?3j)&ymCROSO*j~p00i_>zopr0B@gv`Tzg` literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/g07n2c08.png b/tests/pngsuite/unused/g07n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..597346460f1999fb225a46c941751a063ce744f4 GIT binary patch literal 340 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4kiW$hCdQ-7c($0u%tWsIx;W{7Ia!igfTEM za(lWshE&YCI?a)**+9TmU8!@?j;|~`8?^Nwc)r?Lq_$r1?liGn%^R-Tp;q$7CJEMO zlzJ4;KMxP^Ju+RX;HYL@-Gk#Fc^OVknlFE_jwyyigG-Tt!`Wfp;>ix4yqkPDCP;NK z1~r?AGA&_CVldj##`Gqwfx%OWMS=NC$B~Bl#s+R26ZX0O&u3sPH<&IZ62xF6aj-6< zfbsKPBL}u9ZpH%&Qk^%<(ysb0p4T0|bq?e8IJVNY+vWzaHM1{xy=+yGG{Y1|rkb`h zNA3yjto+-{XrFnVCqaPMB`5oDUbd)UCL<@`O96M_uJo#|LglgsxQF8R^$h;7b}TjfzJUdIdD$lW>Eyq?p`_m4Y& z-{J`iGB5FV+1}XZ)MS0PIdR4^0cqiR*K_!P*&REUA$u*Ssq)>f&GN^7%oX0FGx-n4 zhwKyvhT~IA43B-Re#o*YH&an!xd?+!chJ8-3q8M`-?Hxc&Fd`ZSM%&)e8n+i|IJ=(JjAQ#qaFmV&reiJFD%l zhjIQ}wpr^l@890_jG=6^#B0eP=Ss?^FRbsXalaPq+q@}7X_b~7+i&|FISSblJ&%*N p=CDmZ_fPK4>k{6ezoCB^uB`P9xp%*R9s>gdgQu&X%Q~loCIEp+b2|V4 literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/g10n3p04.png b/tests/pngsuite/unused/g10n3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..1b6a6be2ca571956ce45bae5470c03cd2266fd89 GIT binary patch literal 214 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I7G?$phQ^Te;|vT8Ea{HEjtq=#3k+XOi)Ub9 zkPGk$ab;j&ShNvQI>NzCvuoQ@%V4AYhz`)Nt!8z<;!klB% z8kRNnGA?3bIdz)*)MbeUS`U~UbUm~rZrp5WQ(CE^-@cnUvcX4`!R=A&$(dGyd<+Z> N44$rjF6*2UngEwaM=}5a literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/g25n0g16.png b/tests/pngsuite/unused/g25n0g16.png new file mode 100644 index 0000000000000000000000000000000000000000..a9f6787c7ab50968e37514529f53a6249762ca17 GIT binary patch literal 383 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I0R{#J2DZkZ*$fN}Ea{HEjttBfCj1EL@MmCP zH1l+E45^s2bjoSoLk2t!cZD2kl#ZnL<{fEdv|^8Ccqg-qse6Jc7stnTF$vmIfsjEfequXr2Aw%}OS_RsSLOm4hSWk^$CHE2Hk z(4U#BBYEM$j~&vzZ5JH464;hsp3nB&I8$Tc!KY2qXO~@gP&Jit1|#d1D5vJzyymxZ z7asikj(tk%fd(cv=9tUZ&+y3c-+58;hav4l%`Zli8H}tYyXzQ?7dXHAniIE{A6q-#z`U7{e=ub$6FCHEg)MoN2*?!xLK{94bgZzrgjEr&d51QgwC2Jh(moH|Sa4?j6fkJcsi}z(y8H|4L zC+sv)GMde5Y^GHCmwBz@`sb53nS9>KJ-K2614|NjF2|1 zIk7HT(rL5#taN;3=A_F7|t*-{AVy`U@$gjFivAIp2=W*hQathNHWcsAuWv|Z6-t7 z8HTj~Ahk1%8D^$2%$&(E^9;kx{~)brj2X_PF`SvnaOModng0y`85sT>GyG3u_&<~3 z{~3n=|3LN)qoiR2(lV*Hortz6G#%KN;|7S4%Z*2TO&G`RJEK^{soP6L6NX=!KD(*A?|H`6$6W?I_J znQ1f6q|N*f^6nX9kmQ+}X=l!)o%x^kpCRqPaoYd1wEr{H{+~(v|9>VZ?2KoELTBbo zkpKUK!Up7}w3#4BpP6a=9~4v|i_>O;j6O3n?LR2wK+Kwg@82IT1fpg5Un4D!LunP)&o{|80U8Do%#K>Raj&ip^~pW)1Z<1_!$&itQw z=Kq;9|Nny`5FGs=SAb&_6rbQo0yzpC?x5%e2PMdj;LriZHrT@;CxiU}iu^OiprAT4 z6J#*h=>PvgvGo5x$WQ)(y ef0jK9jrTuu`WMH(`^Xzm-t%Im=&ab*AjV+Mva28Njo3}+Y^{xcXeFc=#%7^g89&txz@!(jX$B$;N+ke0@fHj^Rk z3`5#~klLBX3^UUhX3k`od4^%;e~{KQ#tdiD7|zUOICF;K%zuXe3=IE`8UCj+{GZA2 z{|v+b{~&`wMyDAw%rs^=W6ba$WRJ12v2mKQ@l0dmGsedMLDr@j8>giir_D4@J7b*o zALNRe#>O+#jAza?o_WT2=6{f*&KMh?Ni#k()A-C8<1_z_|1%i>H#YvCX8eDq@&7Z% z|Np0fykwjPa`enJkhA`Sd;qd3Ee&MWnKa}7AP=P(r-8uCw6rs6Y5zg~n`xXjGc9fA z%(R(j(q{e#dH0MlNb=0gv@>VY&iqgN&ye=tIPHI0+W(np|IeiT|34EHcE&S7p)+$P z$p8OAVFU6~+Dwq6&&)Lb4+<)f#c4A^MxU9P_8$~-AnCN3AaG{p%>ST(JYx*9_RP$g zXU@z#^MB@lhME73XZ}x{`G4lj|7T|Y|9=J)NycYD(J=E2D4_p?LLC%#X&|kj;P?-U zgf!zbATP~419J3#P@K#(2Kiv-%rhXP|AV6Fj4{YVApV&%Xa1l0&v53y@tOZ=Xa3JT z^Z(45|NlV|2#$V`E5I=dicfGPfgA-6cTn_#gA(LMaOi+y8|-0_lfixfMgAFMP*9zj z2{IUL^#A{$So;4TYjW(^>5+-ubaKIJo{J~7#NsOd|iErnSp^Jf#G0XXay)u$27=# fmzpy$Ff3|dmOlI~R9KWBq=3QG)z4*}Q$iB}HdA)w literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/ps1n0g08.png b/tests/pngsuite/unused/ps1n0g08.png new file mode 100644 index 0000000000000000000000000000000000000000..99625fa4ba1c6964446797075c47ee05dcae22f5 GIT binary patch literal 1456 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4h9AWhA=@@4F(1VmUKs7M+U~W1%@xC#WOIl zN)-qAgcN61=q8sYr80n2{s*Zx29s%EaweEO11A52NMi;t307kaR$~lSV+>Yf3|5l{ zR+9!+lLl6k23C^>R+9!+GZU<4CRoi(u$q}*H8a6#W`fn60joI!R&xfd<_uWP8L*l& zU^V~2YW{=O{0FP~4_5OZtmZ#RjWGjAjWGjAjWGjAjWGjAjWGjAjWGjQ4cK4C#$YvI ze;I@QWeoP0G1y?^vCfHvy!Ty>F_Sa0Xzh;8{H52TwnP7j-1p8|y z*k3cj{+bE)*G#a#W`g~72JEjhV1Jzf`|AwYUuVGnIs^9C8L+?3fckQamXTbhC1NPS$u)ofL{dETHuQOnOodNsn4A@_1!2UV|_SYG(zs`XDbq4IOGhlz6 z0sHF=*k5PB{yGEp*BP+C&Vc=O2JEjhV1Jzf`|AwYU;n}W`VaQkf3Uy)gZ=d%?63b| zfBgsh>p$3E|H1zH5BAr8u)qF;{q-O0um50w{RjK&KiFUY!T$OW_Sb)~zy5>$^&jl7 z|6qUp2m9+k*kAv_{`wF0*MG3T{)7GXAMCIHV1NAw`|Cg0U;n}W`VaQkf3Uy)gZ-uS zKSPg!fx*$!#WAE}PI5|u3WEs8iOoE$tUdf3nm@kF+b2{S$cPx65}c5pvZykKhmEzT t|HG+&|Ihzue^zKHA!2aq!PL|g7KVVQ{|ZeX-G~GguAZ)bF6*2Ung9T8N>2a) literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/ps1n2c16.png b/tests/pngsuite/unused/ps1n2c16.png new file mode 100644 index 0000000000000000000000000000000000000000..0c7a6b380e9a2e60c887a260d43a41553260fc74 GIT binary patch literal 1620 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I0VW0phBY0A4;UC2SkfJR9T^zg78t&m7SF)I zDpefd6H=U6p_^Qql*+)tz`*dIfq{X+7)+*t$(dmC44C{6B8|anjKOM*!D@`bYK*~Z zjKONsz-rRKYSO@J(!grcz-rRKYG#7f%mk~M305-`tY#)y%}lVGGhj7mz-rEb)tmvV zIRjR62CU{kSj~U1n*U%m|G{ehgVp>8sWAro%NXo0V+N2KV+N2KV+N2KV+ODqu)mDK z{xSyp%NXo0W3a!B!TvG^`^y;YFJrL3jKTgg2K&nx>@Q=mzl_2DG6wt080;@&u)mDK z{xSyp%NXo0W3a!B!TvG^`^y;YFJrL3jKTgg2K&nx>@Q=mzl_2DN(1{V4eYNpu)os4 z{z?P;D-G?^vCfHvy!Ty>F_Sa0Xzh;8{H52TwnP7j-1p8|y z*k3cj{+bE)*G#a#W`g}S6YQ@uV1Jzf`|AwYUuVGnIs^9C8L+?3fckQamXTbhC1NPS$u)ofL{dETHuQOnOodNsn4A@_1!2UV|_SYG(zs`XDbq4IOGhlz6 z0sHF=*k5PB{yGEp*BP+C&Vc=O2JEjhV1Jzf`|AwYUuVGn`VaQkf3Uy)gZ=d%?63b| zfBgsh>p$3E|H1zH5BAr8u)qF;{q-O0um50w{RjK&KiFUY!T$OW_Sb)~zy5>$^&jl7 z|6qUp2m9+k*kAv_{`wF0*MG3T{)7GXAMCIHV1NAw`|Cg0U;n}W`VaQkf3Uy)gZ=d% z>@TJN8F~y13{O2>978JRT%C51tJy%nW%&cg`qOpW|E~QuO^%IuQkz=ZOp0gsr-9{JBS;qsq54y*^i>QLxB(`scTw3SuuZCVbx182{qU zC#K4hWg8CImn?fCsp0%QCWqPd#Tz50uP=NU8+X4rvod`F@7&Lx(iF?Dp$nTwfK;w%>!gpDT?sLC;%?z05?u|^4tJ-`Z=Zi)_ zJ)6k|%k_5}gsiGJHpo?NY|yF_IWeCxx8$6$^oNFX^EiGu`m^j=XuSWK)4w?O-ACSl ODgaMcKbLh*2~7YESD6OrNQ;4!S$xW^`^n~ror`s%!TNk3D-Llu6HI}?@YMfnQ*-zmq7HMf$Kd3 z*Lw!8_Y7R`8Mt1M+aY>EBnX2-4CE6~u>FVY{SVjsAFdY^QXn0mkOJvqU;wcodO<9Z zpCDo&7eZJd`yeckZV(Hk5@HH0oIx~9FD#rvVlcfR8z4Gh;S7owkSNGJSU7{kVD`eo z86*a?7Z%PS8(?~2;S3Uk>4k+eNDQVI7S5o!hv|idGe``k7Z%PSF_>PE%Rv~V4}?K( zhJ`bT57P?^XOI{~FUYr$a0anJ;tUKR79^}dEQnqZ3ldf!7ECWJoIxoPrWX<(AX6Z| zgRo$FL8?G51%)WgUXX5>7|dQ+dIqV3=>^F_)WO0TqzYsr$PQRIgT!ENhJ`ao4CZE7 zID_I3rWY2@ATgL;SU7{kV0uBegD}V?FukyF28qG+!onFO2GI+0F~q+h7DO+I1yaGl z0AfM(f>;p$f>fHvlkZ5kdg!<3kzqE9LO~wQ()l?5`*c5g)>MDW-rJD5C*A% z>4k+eNDPEQ=E1@l#E0kw*$VM5hy~FLVnO^1Vu92$Fo0N)a0anpdST%VD(PT)Vc`rC zgXx8ZGe``k7m_bPCd0xRMDBo8tV5~>guOfSeK z5WNuhgJdDDfv{kDLFT~J!SsS?h!}_jVUP&Szp!uyiGgeZnFkAJkQl_jAYBkQgIEx~ zAQr@45DTIg!~*GpsRi->gUfUn3#Jzq&LCNsURXGT#9;Qq!WraFm|jpR0Wl92&LCNs zy&yM1WMSzURP(^}!qPKH3}!DRErQ$(5`pN2g)=BDV0uBZ36lk>1nGdKXOKFWn;~jI zvJjs@SRi*nSTMa1JrFUl-f0)Q+ZY%a96eneLn`JZrzEH_h;W?P%)`ps!_T4lh`}kr3F#?|Dr0!qSbO?Eocj0w{Ezl$g@zI$2B#iOO-*582zdIh(Dc!bNKg&z M>FVdQ&MBb@0FJmzdH?_b literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/ps2n2c16.png b/tests/pngsuite/unused/ps2n2c16.png new file mode 100644 index 0000000000000000000000000000000000000000..a4a181e4ecfc378abcba1a2af79c0aa96eae57e1 GIT binary patch literal 2484 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I0VW0phBY0A4;UC2SkfJR9T^zg78t&m7SF)I zQB@q^6H=U6p_^Qql*%B$00I9Y6oWAXjFkpw&4jbgz*+yHEMo=+I18rNm;t8Om;t8O zm;t62qzYn38eDH0+}<>}-ZZ%0G`L=nxe&cG;d*Dn_0ELroe9@F6RsEJ5{TY2aJ^^X zde6Z1o`LH<1J?_3J47#t1YwY`K|TQm+kd#;|8Twk;d((K1=0ZuDUdD(1`rFP7sLYj z2_gn^A%q3855fZJ2C+aYA*L8Z-3+2(dST%V5`*al*#OZ23ujQgfJ8y&!NM6N2D29y z&LAdO^O0gfoZ*5@%olu^?duVnOtRSdg#+v0!>(;S5TVFujoQ0GR^u z9fSqb3sMDgDJVo?_JVZ7#9;Qq(lbaMOfN_dq7D|$AXOj}L3Y5x86*aCGc24zVlX$u z!Wk5QFukyF28qG+!onFO2Ga|&9fUzHf$4>XGe``k7Z%PSF^FD}iy{66u^@UuERYHY z1`rFP7sP`27sP_;g@rRH_rmnT!Wkq6(+f!xAoD<~KrRJ^3d~+uID^Ds_Ci7iqyyql z2n%K}#0?-ZkS!4NK)PWpn7y!YhLj`_Sy(uO;o}AQng$Of882A6%xxSTMb?a0bc3^uod!BnGn=7S14d!t{bl35a>Ha0bc3 z>;<_AA`45;pqdA!7nYtuVlaClX%XaRkO)LCESy1M0n-bLO_(f5B}fM>J%iN2+ze3z zl7;vL!UDMq!h-3A=z)lV^-jCc-NwMc@YK`AF{EP7)oBO0nhgY8mOpT;KV7%|@7izE zvJU<1&fTQ ze}4O^Aoe0-!sktm@h{$dVyY}zw&8$%$+9Ps8qUvSa+pnDyfI?>`of2?arcWeE7KS7 z&i(8uy}=<}UN52joQy_7uN>=-1< eKg*tl#`~W+{flGYedG=d#Wzp$P!SsG*+# literal 0 HcmV?d00001 From 91255cb1cdfe6a11d411d9ae09d46aa2a3462d04 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Sun, 14 Dec 2014 02:06:33 -0800 Subject: [PATCH 45/46] update stb_image version & changelog --- README.md | 2 +- stb_image.h | 47 ++++++++++++++++++++++++++++------------------- 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 7696853..486a2f7 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ single-file public domain libraries for C/C++ library | lastest version | category | description --------------------- | ---- | -------- | -------------------------------- **stb_vorbis.c** | 1.04 | audio | decode ogg vorbis files from file/memory to float/16-bit signed output -**stb_image.h** | 1.46 | graphics | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC +**stb_image.h** | 1.47 | graphics | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC **stb_truetype.h** | 1.02 | graphics | parse, decode, and rasterize characters from truetype fonts **stb_image_write.h** | 0.95 | graphics | image writing to disk: PNG, TGA, BMP **stb_image_resize.h** | 0.90 | graphics | resize images larger/smaller with good quality diff --git a/stb_image.h b/stb_image.h index 0f0f28c..d0c8f86 100644 --- a/stb_image.h +++ b/stb_image.h @@ -1,4 +1,4 @@ -/* stb_image - v1.46 - public domain JPEG/PNG reader - http://nothings.org/stb_image.c +/* stb_image - v1.47 - public domain JPEG/PNG reader - http://nothings.org/stb_image.c when you control the images you're loading no warranty implied; use at your own risk @@ -28,19 +28,15 @@ - overridable dequantizing-IDCT, YCbCr-to-RGB conversion (define STBI_SIMD) Latest revisions: - 1.xx (2014-09-26) 1/2/4-bit PNG support (both grayscale and paletted) + 1.47 (2014-12-14) 1/2/4-bit PNG support (both grayscale and paletted) + optimize PNG + fix bug in interlaced PNG with user-specified channel count 1.46 (2014-08-26) fix broken tRNS chunk in non-paletted PNG 1.45 (2014-08-16) workaround MSVC-ARM internal compiler error by wrapping malloc 1.44 (2014-08-07) warnings 1.43 (2014-07-15) fix MSVC-only bug in 1.42 1.42 (2014-07-09) no _CRT_SECURE_NO_WARNINGS; error-path fixes; STBI_ASSERT 1.41 (2014-06-25) fix search&replace that messed up comments/error messages - 1.40 (2014-06-22) gcc warning - 1.39 (2014-06-15) TGA optimization bugfix, multiple BMP fixes - 1.38 (2014-06-06) suppress MSVC run-time warnings, fix accidental rename of 'skip' - 1.37 (2014-06-04) remove duplicate typedef - 1.36 (2014-06-03) converted to header file, allow reading incorrect iphoned-images without iphone flag - 1.35 (2014-05-27) warnings, bugfixes, TGA optimization, etc See end of file for full revision history. @@ -2459,8 +2455,6 @@ typedef struct stbi__uint32 type; } stbi__pngchunk; -#define PNG_TYPE(a,b,c,d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) - static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) { stbi__pngchunk c; @@ -2486,13 +2480,23 @@ typedef struct enum { - STBI__F_none=0, STBI__F_sub=1, STBI__F_up=2, STBI__F_avg=3, STBI__F_paeth=4, - STBI__F_avg_first, STBI__F_paeth_first + STBI__F_none=0, + STBI__F_sub=1, + 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 }; static stbi_uc first_row_filter[5] = { - STBI__F_none, STBI__F_sub, STBI__F_none, STBI__F_avg_first, STBI__F_paeth_first + STBI__F_none, + STBI__F_sub, + STBI__F_none, + STBI__F_avg_first, + STBI__F_paeth_first }; static int stbi__paeth(int a, int b, int c) @@ -2848,6 +2852,8 @@ static void stbi__de_iphone(stbi__png *z) } } +#define STBI__PNG_TYPE(a,b,c,d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) + static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) { stbi_uc palette[1024], pal_img_n=0; @@ -2867,11 +2873,11 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) for (;;) { stbi__pngchunk c = stbi__get_chunk_header(s); switch (c.type) { - case PNG_TYPE('C','g','B','I'): + case STBI__PNG_TYPE('C','g','B','I'): is_iphone = 1; stbi__skip(s, c.length); break; - case PNG_TYPE('I','H','D','R'): { + case STBI__PNG_TYPE('I','H','D','R'): { int comp,filter; if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); first = 0; @@ -2899,7 +2905,7 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) break; } - case PNG_TYPE('P','L','T','E'): { + case STBI__PNG_TYPE('P','L','T','E'): { if (first) return stbi__err("first not IHDR", "Corrupt PNG"); if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG"); pal_len = c.length / 3; @@ -2913,7 +2919,7 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) break; } - case PNG_TYPE('t','R','N','S'): { + case STBI__PNG_TYPE('t','R','N','S'): { if (first) return stbi__err("first not IHDR", "Corrupt PNG"); if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG"); if (pal_img_n) { @@ -2933,7 +2939,7 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) break; } - case PNG_TYPE('I','D','A','T'): { + case STBI__PNG_TYPE('I','D','A','T'): { if (first) return stbi__err("first not IHDR", "Corrupt PNG"); if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); if (scan == SCAN_header) { s->img_n = pal_img_n; return 1; } @@ -2950,7 +2956,7 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) break; } - case PNG_TYPE('I','E','N','D'): { + case STBI__PNG_TYPE('I','E','N','D'): { stbi__uint32 raw_len; if (first) return stbi__err("first not IHDR", "Corrupt PNG"); if (scan != SCAN_load) return 1; @@ -4700,6 +4706,9 @@ STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int /* revision history: + 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) + optimize PNG (ryg) + fix bug in interlaced PNG with user-specified channel count (stb) 1.46 (2014-08-26) fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG 1.45 (2014-08-16) From f547761c1581d757b5151319c6b718de6d4f30e1 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Sun, 14 Dec 2014 18:14:14 -0800 Subject: [PATCH 46/46] Fix assert() that should be STBI_ASSERT() --- README.md | 2 +- stb_image.h | 6 ++++-- tests/test_cpp_compilation.cpp | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 486a2f7..ddcdb9b 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ single-file public domain libraries for C/C++ library | lastest version | category | description --------------------- | ---- | -------- | -------------------------------- **stb_vorbis.c** | 1.04 | audio | decode ogg vorbis files from file/memory to float/16-bit signed output -**stb_image.h** | 1.47 | graphics | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC +**stb_image.h** | 1.48 | graphics | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC **stb_truetype.h** | 1.02 | graphics | parse, decode, and rasterize characters from truetype fonts **stb_image_write.h** | 0.95 | graphics | image writing to disk: PNG, TGA, BMP **stb_image_resize.h** | 0.90 | graphics | resize images larger/smaller with good quality diff --git a/stb_image.h b/stb_image.h index d0c8f86..a930bea 100644 --- a/stb_image.h +++ b/stb_image.h @@ -1,4 +1,4 @@ -/* stb_image - v1.47 - public domain JPEG/PNG reader - http://nothings.org/stb_image.c +/* stb_image - v1.48 - public domain JPEG/PNG reader - http://nothings.org/stb_image.c when you control the images you're loading no warranty implied; use at your own risk @@ -28,6 +28,7 @@ - overridable dequantizing-IDCT, YCbCr-to-RGB conversion (define STBI_SIMD) Latest revisions: + 1.48 (2014-12-14) fix incorrectly-named assert() 1.47 (2014-12-14) 1/2/4-bit PNG support (both grayscale and paletted) optimize PNG fix bug in interlaced PNG with user-specified channel count @@ -2545,7 +2546,7 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r return stbi__err("invalid filter","Corrupt PNG"); if (depth < 8) { - assert(img_width_bytes <= x); + STBI_ASSERT(img_width_bytes <= x); 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; @@ -4706,6 +4707,7 @@ STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int /* revision history: + 1.48 (2014-12-14) fix incorrectly-named assert() 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) optimize PNG (ryg) fix bug in interlaced PNG with user-specified channel count (stb) diff --git a/tests/test_cpp_compilation.cpp b/tests/test_cpp_compilation.cpp index bc31a76..44262fb 100644 --- a/tests/test_cpp_compilation.cpp +++ b/tests/test_cpp_compilation.cpp @@ -8,6 +8,7 @@ #define STB_HERRINGBONE_WANG_TILE_IMPLEMENTATION #define STB_RECT_PACK_IMPLEMENTATION +#include "stb_image.h" #include "stb_rect_pack.h" #include "stb_truetype.h" #include "stb_image_write.h" @@ -15,7 +16,6 @@ #include "stb_dxt.h" #include "stb_c_lexer.h" #include "stb_divide.h" -#include "stb_image.h" #include "stb_herringbone_wang_tile.h" #define STBTE_DRAW_RECT(x0,y0,x1,y1,color) do ; while(0)