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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 fYY$1 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 zcmV+`0o4A9P)kMw|y20kXn4P1fk&um!5HR4i(o|AwZ6~LzrfePT$2C@a*GO>pzD`W+JMY+o{~OMQc&lm=3iqj(vZoAg56v)&@pF xpiv;U26q|-VrxJe1@ZNXf_(7)M8WX7;00Eg?uiut|NZ~~002ovPDHLkV1i{YdSUv}5QRU_7&y#fp@D&gr9M`8f1y92FoiBVSa`IsurPtS ze{e7d3sdH>SD>hoE4z_nx$z0??7UgMea|aJNhAr@Zvg8Z*gUmKePu;z>y8jWkvlsq z1W-(qZPlsA;>PQ-xbb>e=+HyjR`72RpJL@9duyYiw{L8ondoV1Dstk)`yNe2E|Tn) zQn&|5Z4$O-o8S$zjgb_v!ImC3RAHrGc4#Vv!)L8;XfO3ToGLXjk#F*79m4!RxgIe_tfnTuJcqEWy)4g2yKb%DDu0za_YxN$~Sgf+CmT>X!ubOoF_W z03=B5#`sg62L3e6{2RJyFI>13c>MtF{pl)#xkJ@t(o7&`wRIOmYhI*_#{U5rtXn@HNfb7oz6Bu5!i$}Tx-z(a!?=gYPiFWah6BvhR7Y~@g_(Z#S%LK+P h+Qpp-{6C^y{2ine-m~8mME3vy002ovPDHLkV1lO|5~BbB literal 0 HcmV?d00001 diff --git a/tests/pngsuite/16bit/basi4a16.png b/tests/pngsuite/16bit/basi4a16.png new file mode 100644 index 0000000000000000000000000000000000000000..51192e731106e77cec52a3acda3d0c3cd54a16d5 GIT binary patch literal 2855 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 FV1na*GhqM# literal 0 HcmV?d00001 diff --git a/tests/pngsuite/16bit/basi6a16.png b/tests/pngsuite/16bit/basi6a16.png new file mode 100644 index 0000000000000000000000000000000000000000..4181533ad81b739fb7b4f3b024f632cd7baa85c5 GIT binary patch literal 4180 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 N1)i>cF6*2UngAzTID!BG 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 zcmV+}0nz@6P)NTxus~-YE?|ew94KIo9tHTv?hhRR zwrA%J^h9UxCeRmyPjW#d?oxNFL9(uFDZ1gBle+D$rIj`J+5;}Xa zfF63WfGT3xy1iYa$zve>zUI)9x>;M1&07*qoM6N<$g8PGj A5dZ)H literal 0 HcmV?d00001 diff --git a/tests/pngsuite/16bit/basn4a16.png b/tests/pngsuite/16bit/basn4a16.png new file mode 100644 index 0000000000000000000000000000000000000000..8243644d0743ebd1fdacb7923069fefbb01dab0e GIT binary patch literal 2206 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 AY5)KL 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 zcmV+?3)u9DP)g!L)UG2f4l6J=4p4#(2+)EA zvXHcTS1ax6t#q~OA5Tm&Z9J1dzH`ppKkj_bx#xV(x!C~bO!&>~VAnvFITMTviN3hTRvvh5o9_Li#WZ{Cau%@5fj4SqfkHXeXW_kl8PG~_?ADWrA$ zH!S0goyyC9fY0`aGL_B#ZB3zaMcUqyN1D1DLhN@e}=^4=3 z34M)_RrMTn4OBh9u@5%(!^-c#e@=DqtErHss}R!u2+M$o_#+hMmhS%WC0(uX!iWbF z{{dH%(3XVCx6jrq541zuHeEfwO;^`G1Dyr%>+i$8*=Os&bQqyL&<;y_pydy`dg>`% zediiHlykOz>5mY_`#`zB3#1Fy9)S}=SASGt88e?ogreD)z#MoT#Z_WQ5&;M zzG>OMZg4k3ZXYOzL9q-N?F2gl!|Pz618#l~B2UAP$1J0w0uH_m-a1&+1k)Bk!C`Q} z4|y6W5dmT@^t}T&zYG_?205!OBkZzRzZWrcI~@8~XwJa?-B7&(X77RNQz5t&vNj%o z?y&Ce*ruzla?PxY!jdRdoq(z+6mN&~E8*Oq;Cv0tOUCT7S7Wvk5s=kp8MEHDsN8^< zwF_pAL-9WFghAN~+Ic8zhOuT)zXe52aQzW@uNks56Lj_SAq^Jk` zFeMKDI3)X>#7@LP{w<6IArXXl5PE{p6@*wJ=xS`lH7g7*Q!_iZ>FO<8SNndVtAq1( z)jpxCnMZVWEMHfX-_zBB>$=)gtE)F(*VU_qx;nexVW?DY0QUm8TCSOw7x+!zvoP(p z^Q4($koJM~5_FfswRX684=ieo+2wI4RzaB+2H$y@5`|9|YUTySZx+=;Wi7~WL9zor zYk@02gEOtL>{iUKoCC$HA$a$K!c!28g8vEly<0O+&+(hH(=hrm4AjFXcc7&gYS+Z< zxwoNYF9hP?Q^8fa0p_QicdxF7a2t3wYi8tWT^;(hu3j$H)g!&Sy0r*uYvI1z@P$UF zQ}w$HWE4iDF!C5Iei)WUpk=jYo?GcRzkL8+SQoSB-G)FdcuzxKBjm(EQ9%hDgUpMN z$%pYWkdH$7DyY~2OP6WpYp)8UDhm0#Ah!aP_rSFoT)%)U6O?OjLR!GcN*Fu_cdFsy z{jh%-e0(NmA3TV0_&7%BJ}7U2Kq*XV0JR2kZOC3*uCBSg(67WU`;|{d{YqP{UwLJP zU)gm^$iF%%WbP6nk3VJC{Qg5bGI~bHwMO;!TXyD==(>a=jU@Z+H4zPr>vu@P8fLNpKB8ZaesH zL(y9>V>JwW;nH%9_8>;uhHUGKx@J~bNL>n9HebklHVIjrE#%ZCLI$@Anf@Cghd&ZB zbx6qcppddn$jpmE4m8^}R-YZo(o7JB*62S9fn#vj{-r*^z-9;5mcQJ$wt!}e21QpP z5e6&lH?MEe%t8}}8(`!Dq%$yn9wv@}Yd7RHfO--j~&R3_VTIa~wXq1U-Y$#pKz9>&NOt^KuJOvOX@5mkP8JV$d7|J44z+25=d`=k$;Ai2FXT9EC*{U^sj*K zZok=fQZwhyh2aMwvmNsO4z%TtZh#Z{op<5JA-LQGSDN6;NvP0;QN6-43U7ly3cl0e z{WtK$!TnE=_Yac<#=3&y%2KjMfM zKz9T#u7nRBfzvZ!@jhX!Z?lZzS0E5@+Gt7?+|PoVg1mmn4MWb|8W<15_-{cbK|T*- zQAlqFyBbm{7&-|9)1mtmTwd)r_g~Y@kQIfj0?4`rS#ikP0Q?jbVL)ax zWIT{*gz<-9`~t|iFxCm9qhL2dD&*`4J->yElM%o6sxSZ^-UK@ygGF6Xyb`o}@I*lE zfZSZj@qy9=*^43jb#SenoGAt#sAlU|q1PmO8&jeik3Y^~L zr22(*f~u(V1TU# zJ_oi3QVlR%1Bp(sehIz3&{geJ_Tpp0*jgl5{6mj#6p#Oci(*~VgPCM1E5mdB8 z#V#n%gFurrqQUXYJ79blxZ9y<4RjpGXo*4D44AghnMhhUR3W`33X(1<~qBSrz1pX~BWewzo zoI(P~YlSKAg1;3;TVWysN-MZq9lZ!NLT@X^#lujz2mC=OcoTdjlfOlASZlPl_{~7d z`4t66KF9uQ69q@qvsAXt%q9I#IP^;|7^ix6>=L_yx>`2dh@V`j`6FF=a$IAc!002ovPDHLk FV1na*GhqM# literal 0 HcmV?d00001 diff --git a/tests/pngsuite/16bit/bgan6a16.png b/tests/pngsuite/16bit/bgan6a16.png new file mode 100644 index 0000000000000000000000000000000000000000..984a99525f5246cbc5d7083dd79006c7efa0ab0b GIT binary patch literal 3435 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 AY5)KL 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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 TFaLS`e*&EE@`;w61 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!ia0vp^3Lq>1BpBEle`W(ImUKs7M+U~W1%@xC#RK_qo-U3d z6?3j$GUPg7z~dZf8U4Qg*qsHF4`@^yUDaY)e6!!)qG9=taAD!(1y)T7vK%uR?lygM zIK}cp><*ign#1-5wiApPcd>47oWOZOH-mqPPlA0u`y2l+k{0Ld8N_aQ--utQJ^wn$ N1)i>cF6*2UngAzTID!BG 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 zcmV+}0nz@6P)NTxus~-YE?|ew94KIo9tHTv?hhRR zwrA%J^h9UxCeRmyPjW#d?oxNFL9(uFDZ1gBle+D$rIj`J+5;}Xa zfF63WfGT3xy1iYa$zve>zUI)9x>;M1&07*qoM6N<$g8PGj A5dZ)H literal 0 HcmV?d00001 diff --git a/tests/pngsuite/16bit/oi2n0g16.png b/tests/pngsuite/16bit/oi2n0g16.png new file mode 100644 index 0000000000000000000000000000000000000000..14d64c583db347908d4e107b49bdaf88e3857b8d GIT binary patch literal 179 zcmeAS@N?(olHy`uVBq!ia0vp^3Lq>1BpBEle`W(ImUKs7M+U~W1%@xC#RK^co-U3d z6?3j$GUPg7z~dZf8U4Qg*qsHF4`@^yUDaY)e6!!)qG9=taAD!(1y)T7vK%uR?lygM zIK}cp><*ign#1-5wiAr3HXJYpnk5G^i*Xn0_QnaE7j!fDm-r;u=d-`@{~~E|zMets XhWCy5O;z!=K$Q%hu6{1-oD!MJY5_^ zD&}0Bc95&tK)_}B1IPN)b=&{0{WeXGjd@a=TH53@RT6EkPi(I(=ofHeu+x7q>wQX5 zah-&%x^euuN1vn0w==yySE5m{$awnax1S1PFES>4-qaZX;>{9*dzc{lpeF5*>&z{m79Ma`yb}T3cx+N9l7QKY_b21tUy>hHS zj=$rVW!RSfocD`M`g^qt@_T0=(DrKPRwV_Ejec_{h{I9JdPiZ{w#YI8t;GR^e@i0d|ndJLIzJ) KKbLh*2~7a%CxW>E literal 0 HcmV?d00001 diff --git a/tests/pngsuite/16bit/oi4n0g16.png b/tests/pngsuite/16bit/oi4n0g16.png new file mode 100644 index 0000000000000000000000000000000000000000..69e73ede311c4a846a8f818330708658a1e0fe77 GIT binary patch literal 203 zcmeAS@N?(olHy`uVBq!ia0vp^3Lq>1BpBEle`W(ImUKs7M+U~W1%@xC#RK{Bo-U3d z6?3j$GUPg7z~dZf8U4Qg*qsHF4`@^yUDaY)e6!!)qCI!=eVEdQwQX5 zah-&%x^euuN1vn0w==yySE5m{$awnax1S1PFES>4-qaZX;>{Y_l!4PL3!@ULbQoiNtWY z=b;I!`Z?mk+pi~%T4uHFkQ%qs0PKuo=U#gjgXq@dQ#YX;uR zyDEzTqN3i8Ri+t9;=Io`4iKjuJ*jdoASoRATB86`e`o#L4-kt!*XOIIkPy|$Z!G18 zk=$_R1cm^jDHwGE*;OPH+pecw0=8F|cWD7)9r{V(>YZh7s}#xX@Y-V@a8$R# zz7Nzll=T^a-D91a7GNOU#!3RDRppIxfH+g4`7VUA7;JpD{z%Gl^hz`rR!C-7WjBz2w=IKp0oL zbO>k?lt*0#RAuh<9{?e*sV()uX|32M9JssnY{osHpuWUu5cv8Oo7WFKnf5e90$&!U zD|&#%lN#4PfLz=wKl=n%AbF;bH~a_iR2$1}rLn7htMc}f7XqbjYTgrI+dp1QF98{q zx~>x7qmaPfO~8-eOc`>46CZ0QegN!tCr*3|kka8h&MF@x8JDN?qySsUVf_vKy0476 z9%wM?M@--UJ8OATkeUmSDcRFHm6nLa%*FSV76{aF1);#sVqI_>Kql)G-?4S=NapNh zVg_*djmhC=Ag9J7dkM%L^-MbokZB}6AQ$H>b5|DQ7>`=5gAqs{oMFj;fyD8u{}=gK zMu71K5`$&sNDOfBa_Q}rTV!=k^EBM^c>q~R=6AduZXuc8qS|W*kl#6Wnxp&)iHoCb zXd@uZXIuUPD6CbzZUDK2+Pw*)4M@m|&Mp?KwVGjB$JzxnI1su>k|SW z;K-2xP8~qD0I!0IuDeLqZiu^T&h0G>BMn)Ym=lSRkOKQt;)MxF$jp%`={{CrJA+}Q z0NGudCGHuG7?!!Lm%ady&A}>J%1A4M0{%q_gjthe+%dX`L1TnYm#8ctAc9 z@}pa>>=HU6*)gvdIs;@`N_gX0SxCrj<`CfL)P#i0DJdZ9W{Ka!FtV*beIQ<%iDapc zzwQpuzunh$8PLB|-d+oAxGoVK2OOgUZCC)=Ex%&=XT>2Qmra%!>Ggb-Hfk2fkY^() zKsHtKl(~0px+MSwNPBxOXxkqksf(TP*$R+5i!_m(4oOIRA3ry`IR({7L&)Y`5g+dy zjA3LNm(5d>Pa+|cbrc|HP1XT<>~@^s)UP}#S04qW zJ7f!3yE~lF1UCm1Ag?RrHNta!r8Eu0$jtfWu@_WGT8_ru{1AB9l%}=?3U3!0mB7Z| zi!2)ef4yhpK|nM&HhOB*ztD(3v5YRNcL0EJE 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 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 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!ia0vp^3LwnE2_&^8vlamc;6;z7cmE{-7; zb9B#amdK II;Vst0B-g)L;wH) literal 0 HcmV?d00001 diff --git a/tests/pngsuite/corrupt/xd0n2c08.png b/tests/pngsuite/corrupt/xd0n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..2f001610a85a662d8baa0c1f02c06adc02cfa20f GIT binary patch literal 145 zcmeAS@N?(olHy`uVBq!ia0vp^3Si6xB+q0lO9E0X>5jgR42*3H3|~x(2l72UT^vIy z=DfXnkdwiHhsmM!&BVXki-fIRw7)F;aqgk^7G4(X1}>2wG7H{5sr9LFXk_B|YL`FM q!Y-omVL^$7@=Axs-38@~4=^@u{29mZaNZkeCWEJ|pUXO@geCyFeJ}z5 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!ia0vp^3LwnP1SGpp+}Q-ASkfJR9T^zg78t&m77yfmc)B=- zRLpsM^&lsM0S}Wy>zj#xw-*UpyJ&w|_~YC|?Jc}4)(u=DKV%lXeNyXF;n2v$@6|4U rsD)ibzj#xw-*UpyJ&w|_~YC|?Jc}4)(u=DKV%lXeNyXF;n2v$@6|4U rsD)ibc;6;z8n`u6{1- HoD!M<9fb>g 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!ia0vp^3Lwk@Bp957Lw$i1OS+@4BLidG0>c;6;(>fePZ!6K ziaE(C2`UUC949vOu(I~>b7=nfE^nVuX&@tFa7u7Oddi~87#=p(p8gM~{{27yqy1T- hp#)Io!PL|g7KVVQ{|ZeX-G~HP;_2$=vd$@?2>>eWDsTV* 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`uVBqrfa0vp^3Lwk^Bp4c;6;z7cmE{-7; zb9B#azopr048WOXaE2J literal 0 HcmV?d00001 diff --git a/tests/pngsuite/corrupt/xs2n0g01.png b/tests/pngsuite/corrupt/xs2n0g01.png new file mode 100644 index 0000000000000000000000000000000000000000..b8147f2a84b861b559fd52fc0ded6971debdc6f1 GIT binary patch literal 164 zcmeAS^mFIslHy`uVBq!ia0vp^3Lwk~Bp9L@-6Me%OS+@4BLidG0>c;6;z7cmE{-7; zb9B#azopr0C@{E=>Px# literal 0 HcmV?d00001 diff --git a/tests/pngsuite/corrupt/xs4n0g01.png b/tests/pngsuite/corrupt/xs4n0g01.png new file mode 100644 index 0000000000000000000000000000000000000000..45237a1d294f7432c06ae45769727d9745250221 GIT binary patch literal 164 zcmeAS@Jr|AlHy`uVBq!ia0vp^3Lwk~Bp9L@-6Me%OS+@4BLidG0>c;6;z7cmE{-7; zb9B#azopr0E~z=2mk;8 literal 0 HcmV?d00001 diff --git a/tests/pngsuite/corrupt/xs7n0g01.png b/tests/pngsuite/corrupt/xs7n0g01.png new file mode 100644 index 0000000000000000000000000000000000000000..3f307f14ea5ed37b9f74b896a98ee4a5d2c9e111 GIT binary patch literal 164 zcmeAS@N?(oQs81>VBq!ia0vp^3Lwk~Bp9L@-6Me%OS+@4BLidG0>c;6;z7cmE{-7; zb9B#azopr0DK%Y?f?J) literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/basi0g01.png b/tests/pngsuite/primary/basi0g01.png new file mode 100644 index 0000000000000000000000000000000000000000..556fa72704084920c07066054bb57adc5a250b27 GIT binary patch literal 217 zcmeAS@N?(olHy`uVBq!ia0vp^3Lwk~Bp7wr%FhF7mUKs7M+U~W1%@xC#RK^hJY5_^ zD(2|+8uA@7;Bmcwtm%lTL>0plJ;|yaa?KmnAMk`(G6*LxZMYGklX_CXw8pz)!~XsE z{R_l;B%iO@S+Mxi#d|k1W1jAhOum0pYrW6>o9eGz=B2dXkDg=peCAH+`yAT7-d7m? zpD=neuC5Ya_iW0gUZXDEgTe~DWM4fgQ!vM literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/basi0g02.png b/tests/pngsuite/primary/basi0g02.png new file mode 100644 index 0000000000000000000000000000000000000000..ce09821ef101b65b2aa653931416c72923ccab09 GIT binary patch literal 154 zcmeAS@N?(olHy`uVBq!ia0vp^3Lwk`Bp9=o@yY{fmUKs7M+U~W1%@xC#RK_)o-U3d z6?2jUl3pY*JS=M4oiJze;et03Q>IK~Gc?O{N#DFKJ@&l7SH)M%%o7ftVn}g$DCX>; zkRs^i5p-N&*DHI8!;%tAJO+*|%*(hAE|_G=Fej+Nw{_diTA<+!p00i_>zopr0NF1v AeE`KLv!pxvIx;Y}EiimBEgr~U=jq}Y zQZXmBFHrE1fq;v+j0h02$h25#lnT63xZ-%g@gNW$aGWTh62d&wbH=%|b$8yp-97vE z;Z29Oxt6;AKCTefnOkLOe zceV31xk&buuP3aOvK_8v?mNu>)5yI*ti8x;zv2JpMH=2qx2(%fUX!Y@wwPzh+iJE; se9X+5d(#!(S{O|*V`01GC)_Bn-uQauWnXqNpvxINUHx3vIVCg!0H8fu|I&j2dyvG3;`TGSdQ=U^x!+b$IgQ- z%948O0A52IVpo?-TFZBK`N@L-n zZIKuYb8U;nSX9Mrl^A36r{K12&k3mj^Z%lhjX;s*Jg960iexztW-CxinU-MA*#;OZ zngOW30HtIErtRT^u_8M_CF3kj<3j{vMRtJ6I<2P3n{$R*t1rNmk`0g=AU|E-;g=04 zMQ4L1&-<_M{L=>-dBi{f3 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!ia0vp^3LwnH%)r1{DZJ<-ki(Mh=EaktF(C3l8oA>Me*wxTz-(}y$c;d$?hLjJF#hg79QUtv`g1+0Ah)O6+%y3%0 kK!=4{>!bX^1(PfpwnWvwlrMbmdKI;Vst08#Hgh5!Hn 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!ia0vp^3LwnF%)r3-EjT<7$YDu$^mSxlY+GRXVp=?q&s^-} z8N$NCQvPG>Vjx#Hz$e62iQzxP|Nk8f|CRnTFwFe_KaJro!~b%i7*N6gnRh{q-T!wp zFt`9&E|)fV?gff(^K@|xshE@eVr8<$zX=QdragS9+NR;%b~IQ*M^<9l2E!vd+h?C( zII@q&;mi?+BR6^0F7JwWQfc53?9iD|$he5*L_qV3*BrK+SKaw>*N06*_XNYzScwH+ zV%a3lGAx}cv7khXdCI+B1NO@fK9ddC9@xTtImqX>;oQaofA@?RGmTe=O`R?+y}#PL zSZx`DR(OCwFvHZ>kD4?aPVKE04`%2+-2h~U1|1S{c)Dz9BG-bV^7qFC7#KE}y~^Mz Rxc~|Y22WQ%mvv4FO#pr5f6M>? 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 zcmWkt4Nw$y6n}dd;vwQ8DFIG$3@GI2c^hLQV*{=V2t>jrDk_FvDg&7$%b-@G;h|=k zpdN>Gek8Jdh#y$4REHQNu9O-n$@*~yld0Q~CgKPCdUtQ`_P_uC|GnSGdsmv8GRH?B zs0RR_gm`WqJ;%AfULF7pdq_&9mmwd-CdUF(;+S%8&r$#nNKHzgW#r%qssai!qCpSQ z0vL_7LIcnOu#UGNg#{Tj`hkLY32hvQ!1G1`Sw@Zn9(h>?HW2Wkq9XR7jEce`M@cLI zX9QKH0)U4(L{U}UX&T}n(htKT%SQskpw)^XiVOoBfYl1vBTI|Gh(?PU5N)D}JkUAF z*+A4fQ52$qu$3IJkUnIraqtk890gF3fMr1iHJ=i#wnVy*0swAiP?EIuK(HVK+H9oK zO8az3*a`*`R}fi5uu;&5F%xGAi8P7`R6^54fJ7UmSdgp%+jcbYbn0eLh5#4{O2a|z zFlncK3j#}*c@!wwN`=4x0@Wv9Pz46?iR#Xv1EQkRnl2%Lup5n_C@hN_Xp)3BL=u!O zgCs#6RU@v*uGicWd7h||*~k+*SQG^)HX|blsFAzW2%aZ!O(VrJ31D;t3x3pAg5Wqi zve-$Qc$9#ED~5p_E`A&DTySs_gXBPgvEi4GHiIsCXqG@a(*{? zqG+gzY2=omW89DcEUHMQNrOtO^VViET%@j9XuK5ipN55EJB^!6bHJ02)DH{^ z28HH;T8~zS28YEnJAZp0KzA^Ki%l=ATyc3-rZ)t5_Dwa^e3e*sHMuT3A|j#p=*X*F z#y0Vd=-McX6_VY&k>*>Z%e|vX1^&KXtnjHm_kp z{Oz$(O(8S=UuD^|XKQO8JeWScy}iAy&FQ@UT~n0V9QLiaO{Ytot3K50Bj4!g*tp@* zcGj*hPH>pOmLs;xabA)>UnI5F|W2|vHO`X8G8{qNq5UvQ>+yva2AorH*qN%N=1 zRO-F+*Y4O692_0}_3qrW zV_8*GU40<7^H$aV#hJ=gqrL3swI3}rKihD;tJ~gc@LGOoZ}}hHIjh6Ni;61tbzVDC zEf)+M(cfo^N={x^khe0+l%Bp^o)#S#*w$83a{u1Ivl?+Wcj0ty-sn>0W|&`1nH z58GA$jXh^Y`JN;7H@hZGKGv`#E%e2gv6o*jI5)Y=Gw4px%OQatp)Q!Xsl()5;fH&w40HKUbx zj4}D7oEu&UXI&wcy60YxT`|F*cQ@)MIhQzY_v!Om7VgvKXAK=bq{#ES%PVuszm5L= z&bJ*WO#!E!Apy*TI{`1@hW^84hM29NG>%Pa9pm_Xjc<61X<)<)m$})aVkqnKe7Wgq z-l@|1T-)pTTjSfo?;6Ga8{R(IDkmelNXRj)ZH9oA|PM{kg$m&gMT07S3iqx$gt>#1~b*D~%?ISJ;?`E{!%Qxx!#mpQpGpa(A8H z_iZ|MVh@5=q!mUuvSsYMxvKp95>weV2Kff8ej5&Q`t30L(azh))$_*RmQyw|G#2PE N22WQ%mvv4FO#oeUP~QLm 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 zcmV-v0ha!WP)!N7@Xl>n0JWRT0P1ZZ0~F7IAF8qd>UAgssMo0sP&xyjf=W~LX-;!O00000NkvXX Hu0mjfr8|%> 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!ia0vp^3Lwk~Bp9L@-6Me%OS+@4BLidG0>c;6;z7cmE{-7; zb9B#azopr0C;FL=l}o! literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/basn0g02.png b/tests/pngsuite/primary/basn0g02.png new file mode 100644 index 0000000000000000000000000000000000000000..508332418fa86637d39e95268ec1d3658d120cae GIT binary patch literal 104 zcmeAS@N?(olHy`uVBq!ia0vp^3Lwk`Bp75C+I9jdmUKs7M+U~W1%@xC#RK{Bo-U3d z6?2jkIAXub_k1+y2sp$L+}6)%%qgEdVJADoUeEf*ZqCk?AR|0o{an^LB{Ts5miHSU 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!ia0vp^3Lwk^Bp4c;6;(>fePZ!6K ziaE(C2`UUC949vOu(I~>b7=nfE^nVuX&@tFa7u7Oddi~87#=p(p8gM~{{27yqy1T- hp#)Io!PL|g7KVVQ{|ZeX-G~HP;_2$=vd$@?2>|oDDeM3M 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!ia0vp^3LwnE1SJ1Ryj={WSkfJR9T^zg78t&m77yfmc)B=- zRLpsM^&lsM0S}Wy>zj#xw-*UpyJ&w|_~YC|?Jc}4)(u=DKV%lXeNyXF;n2v$@6|4U rsD)ibtrx; 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!ia0vp^3LwnL3?x0byx0z;SkfJR9T^zg78t&m77ygJ1^9%x zzWcAFl=eSI>XI5zMAXy8F{ENn@&k4zHj_up0tD0@h%3W?AY}Lt#0>va?X`CSX(dk=$B>FS$v@Vz>816FsF9(VN75txh7sS~8e>Vez z3y|e3}y1F=z>r=LEEca@LnZf*~BA0ROZ5~$d#4)lIa>n+tGAx#s~NCh;!h=Q?&7t5~~Lk>mL*|1x+L`Ivp6mn?kJ^kK$c6a~%|NrOteLPR)ru^*4 zh?oc>ipx)wHw!xP<||VqG2mh2yNQ1IZKr30Xr(I7PBXU z(o_;ftk^?X5O*qmM)+A^aUR*s!>r3PlcI=3mc_D63M-aHQVj83+hHDKi)~wG8A%eb zMRFVzAa0kL4aW(lxy(-(A3@r7{KRdCcI^9^ zBwSWlMY4uMp(p@%T`0C7K$rnonuoRmLY9xP#5bTx(RKJi zCYfG^*s^*-{Ro^e4Kgw{Dlmv)JpjQ5bKwF@CLI|%59=nhA>e#HJh5GNjRLr(&Jco- zL=roU($L^w70~)&xPh+uFV&-K!K0w3W-9Hy@g@HWXL3ML4|%5ULen8 zlT@|D2@;VI*iada4446_ptp_#Sul*Cx7Y6>PlSiq8TyN-q=y}cXZX&@20)p=ihIP{CfA$Z*4W@ zEr$zzJ<~t_(0G1&!T9U{_Iz>DPFy@Dgq4(i*+1}U*ZiG1m)32#<4sRFJ5!AP>yZ}L zzdq~5lB&|C6*=qgy?nj!is#SN$*Gwo6M?qJgKJtd1_tvb_xS3qJuRh&eH)f1f0J@< z)4uq(Z_li{H~+s=+3L-xjU7X)ZvEUC-CLA+t^7d7$jI)tsK~;c&XdnBOC5Txp}1)@ zusm-vWl2G`{dnN}K>pDE=;yi{rVB@Y3B-HrtGOePxNz#}j}FD`z3|nlwikX+ZZ56= zAY&lKTUG9w&2^VN89D}o5=^>%~&6ID5>`0fk%7K&zZcY&F#znJTW|E zB5&cFwM~ly35&;HdZq5*>W9rM<&V4Wr%mNt{B`@CxYpR8I;^7!?Tc=wu6t&Du2Ec< zKIiz-xXN3dttqGahAW20Qo6MzgSk7e_{!(?CKyw`*?j|NY=7wG%F`JaWZ(VOm8CUr z$$no_)1uMK%W6)nN!IrL6EB>puUj#i+1xg}<&qUPnY6#j4&NW^MpZNn{t+Cq+^l@L JEAySt{s-!kV`~5a 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!ia0vp^3LwnE0wix1Z>k4UEa{HEjtq=#3k+XOiwE*eJzX3_ zD&{2rIe*{)W9ys@6GNprI`<_tn04&i_AxF_G>~EoF-$NKa6jCj#n!|2C_^IPFayJV XErr@6uUk(54Pfwe^>bP0l+XkK+-D@M literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/basn6a08.png b/tests/pngsuite/primary/basn6a08.png new file mode 100644 index 0000000000000000000000000000000000000000..e6087387639b9cefaaafb696e29a8bd910ee0680 GIT binary patch literal 184 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzmUKs7M+U~W1%@xC#RK{Io-U3d z6?5KRGvsP8;BkAXo|56e@Vk8|OTXfgyGLCsWP@G=X#A1))wtQkXb@LjH|PH@<7U}X zR(Ix8Y%6~9Ml4|WGnG@SZHQ?Kc`Uubi9hC!9z&%<$E5#{7BHGEsCHnVVk5wElR+}T f%%Pr9`U69dg47%_{vAF*s~J39{an^LB{Ts5$SFGl 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!ia0vp^3LwnE!oa||uB7QDki(Mh=l@|1T-)pTTjSfo?;6Ga8{R(IDkmelNXRj)ZH9oA|PM{kg$m&gMT07S3iqx$gt>#1~b*D~%?ISJ;?`E{!%Qxx!#mpQpGpa(A8H z_iZ|MVh@5=q!mUuvSsYMxvKp95>weV2Kff8ej5&Q`t30L(azh))$_*RmQyw|G#2PE N22WQ%mvv4FO#oeUP~QLm 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!ia0vp^3LwnE1|*BCs=fdzmUKs7M+U~W1%@xC#RK{Io-U3d z6?5KRGvsP8;BkAXo|56e@Vk8|OTXfgyGLCsWP@G=X#A1))wtQkXb@LjH|PH@<7U}X zR(Ix8Y%6~9Ml4|WGnG@SZHQ?Kc`Uubi9hC!9z&%<$E5#{7BHGEsCHnVVk5wElR+}T f%%Pr9`U69dg47%_{vAF*s~J39{an^LB{Ts5$SFGl 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!ia0vp^3LwnE0wix1Z>k4UEa{HEjtq=#3k+XOiwE+VlDyqr z7#LRdDjNZLrk*a2Ar*6y|C~Q?fU$K>hKZrl9G&};8q7NOZTlD(CmKkxg%~E72)G|^ k&|>Rhdz2v&aF~JNzLrAmk=Ly!fCeyly85}Sb4q9e08Xzba{vGU 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!ia0vp^3LwnE1|*BCs=fdzmUKs7M+U~W1%@xC#RK_lN#5=* z4F5rJ!QSPQfg<^yE{-7;bKYJvrKjw}eL#0B;r2mf= uFq$o>c3_`kBfxT#K{CM1p`KCt14EF4)EqJX9X>#-89ZJ6T-G@yGywoV#zE8o 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!ia0vp^j3CU&3?zc?q{RR^Ea{HEjtq=#3k+XOiwE+Vi=8|} zSXfxfe{5Y0;s*GHxH2&O@2a>I4&-uqx;TbZ%t=lFvY8kdJ=QNN1hN=BUHx3vIVCg! E01FBk(f|Me literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/s01n3p01.png b/tests/pngsuite/primary/s01n3p01.png new file mode 100644 index 0000000000000000000000000000000000000000..cb2c8c78261e509e7ef2c352306618963954a84a GIT binary patch literal 113 zcmeAS@N?(olHy`uVBq!ia0vp^j3CU&3?x-=hn)gaEa{HEjtq=#3k+XOiwE+Vi=8|} zSXfxfe{5Y0;s*GHxH2&O@2a>I4&-uqx;TbZ%t=lFvY8kdJ=QNN1hN=BUHx3vIVCg! E02xdg0RR91 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!ia0vp^Od!n2%)r2CU%&n%ki(Mh=)Kx2KC^NX4Aw1O`S11~vx9e?93ZfWi!(u6{1- HoD!M4t literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/s02n3p01.png b/tests/pngsuite/primary/s02n3p01.png new file mode 100644 index 0000000000000000000000000000000000000000..2b1b669643540f182c425fb67869b7f97fe75f10 GIT binary patch literal 115 zcmeAS@N?(olHy`uVBq!ia0vp^Od!n23?w}&=BEQGmUKs7M+U~W1%@xC#RK`w#ZI0f zEG#VLKejFgaRYopTp9lVmyFR@1#)>jT^vIy<|HR1Bmj9V42<8zEkc1T22WQ%mvv4F FO#mnG8JGY7 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!ia0vp^%plANBpIb2ie~{iEa{HEjtq=#3k+XOiw8*-J9&n% zu&|W>*t!_VWee~Lab@_=@V}g49;WoqQ$(6ld^s L^>bP0l+XkKxV;@Z 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!ia0vp^%plANB6FUp{{d1g>5jgR42*3H3|~x(2T2w?d4{mC zu$2GUx){i13-AeXW%$qVzno#?)1~u)B7B}Mjv*Cuk`odN5)y#?V+@X#hCJRt7K5j& KpUXO@geCw&86D36 literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/s04i3p01.png b/tests/pngsuite/primary/s04i3p01.png new file mode 100644 index 0000000000000000000000000000000000000000..0e710c2c397e371e4feab66add6a9f9763ce0c27 GIT binary patch literal 126 zcmeAS@N?(olHy`uVBq!ia0vp^EFjFt%)r3-#KLAZh?DN<>&U>^w!rYkw0Iz&x!B1w zgoTBr{KwYCKrUN=Pl)S(hVuXa8D@QV-U$>D@pN$vshE?Tk-%_}nTL-@Si+8hL2?}n Uzopr0P-Lp3;+NC 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!ia0vp^EFjFt3?wJp^Voto>5jgR42*3H3|~x(2lAPVojgNW zSXjz`Y+VfGvIY2rxc+A-|Noz1)_3QfKoNdV7srr_Imtf`7%+0!GcfRQFf%r7-v+XT N!PC{xWt~$(695jV9kT!c 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!ia0vp^tRT$9%)r3d&i3yCki(Mh=b^8f!C{x5dr%K!>0dAc};RLn`vNXST-!El6+N0&!i n!bU<#VwswOk4HkpRtAR1>$j<%)r2S&bt2^ki(Mh==jv*Cuk}VDtG(2QH%-+V! svtII_@t;Hw#zXcz;mHztXBa0j9DK~v7~1r+6R3f~)78&qol`;+01$C3h5!Hn 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!ia0vp^>>$j<3?z5j>~{cCEa{HEjtq=#3k+XOiwE+Vi=8|} zSXfxfe{5Y08<>}%WQZXm_$N%<+Sv-f=TJo4b eYw%F`{a>D;u##)1Tx>4LCI(MeKbLh*2~7YjwJ1CQ literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/s08i3p02.png b/tests/pngsuite/primary/s08i3p02.png new file mode 100644 index 0000000000000000000000000000000000000000..acf74f3fc4132609443b0555d56e5b314644bf23 GIT binary patch literal 149 zcmeAS@N?(olHy`uVBq!ia0vp^93afZ%)r2SE-kGO$YDu$^mSxlY+GRXVp=?q&s^-} z8N$NCQvPG>Vj!0%z$e6&;s5_~hX3XN8U8actlAYR0~A;Fba4!+n3J5qz{IFfcOc>T u0@fwp4bCJ+99*!q$#Hv=FS$q5Mw7orX>_}}cf hovEdPM`3y+BZF-itL;x80b!sr22WQ%mvv4FO#lIoCTIWv 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!ia0vp^oFL4^%)r3->c>4%AcrO0(btiIv2B6ji)rydK69~? zX9x=mOZktji-BC80G|+7hW`u<<^TUP{QqCh@IQEaktF()~}fr+~zg1bjT rBF;F5J&BF&_kSLqX%_`}QkWS^|FgS^^-Kp^#=zj|>gTe~DWM4fSkxz) 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!ia0vp^oFL4^3?%3Nf7cA8SkfJR9T^zg78t&m77yez7dv@| zu&}U{|Jb@1$mI#}32|lk&%jXr|3Ab3|K$w-!x&P4;_{v@jv*Cuk`ox1e*fp;30o~G lp|iL#LdvQ6heDwO14Cvi>)|ZtdS#$e22WQ%mvv4FO#lN*C*c49 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!ia0vp^3LwnF%)r3-EjT<7$YDu$^mSxlY+GRXVp=?q&s^-} z8N$NCQvPG>Vjx#Nz$e5NNdIRjXZZggLNS#8F9$J!e4s=*NVput`nsRZ8c5&pba4!+ zm{U7pFJF^^h?~7@-J{?g64%>Ss_=bq+ht{1xSCJrO-tjMmhSi` nkfZu#wXNcYdz+%H|96_V1YK&G^7e=_(2oqBu6{1-oD!M>$PW;WtqGsLq6}$jpDV7@>y0l)ibBXvN}dz6L`X{!W|QK qt4`9uP~=9WliB7OneY3z7cem=9`<-$rKSgT2ZN`ppUXO@geCyfYFs4% literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/s33i3p04.png b/tests/pngsuite/primary/s33i3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..ab0dc14aba444d3f59f0bf77808ee7ee78ab5a48 GIT binary patch literal 385 zcmeAS@N?(olHy`uVBq!ia0vp^iXhCw%)r2S>FoPcKn_c~qpu?aW7`757t`W_eCA>& z&kz9yJIm7?|5Q?Gve>sQ=2z#A&*U>UfA#bB(&kXT4uKE5vkQo zUQ-!gbN(`3qRGqhce6z7%EakmS0Y8FPq}6+_@ir6xO2`=y*VFuJPs^Aejwdi=Zl4) zY)`yQC*Lu~AJ4vKi$Bd@7qys2yXwnUHmtVq{n7=4!I#bZtC8xk9FB%)(-P6#}_whaYKv zG;#N1*N-P`3zt?rkunQiXB;>sd*S~OJ*$Vjx#Nz$e5NNdIRjXZZggLNS#8F9$J!e4s=*NVput`nsRZ8c1LAba4!+ zm{Z%gm#f)8#BG1p-0Bz*xXo g-$=Io|APMvAEo}ki@M*T3G^LmdKI;Vst0JTexR{#J2 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!ia0vp^N+8U_3?xrvihTr9Ea{HEjtq=#3k+XOiwE+Vi=8|} zSXfxfe{5Y00D12$B>FS zQ_pYYZBP(ky%4X^8GYlzZKG+@7dEqqPBxHOE~fV1{h+qq6V*Svna^1j^)9?Ct99+6 zN12I`jtXnzk)}u!%RD37KjJGY{QS1{OXvRBqt2SFsin;wQV|yPQK!t*<5f${SKY|E by&mjqj=t@%(q8BXw3xxu)z4*}Q$iB}CDT{I literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/s35i3p04.png b/tests/pngsuite/primary/s35i3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..e2a5e0a6595f100edc1f79a3e0864ad6ea0d0121 GIT binary patch literal 399 zcmeAS@N?(olHy`uVBq!ia0vp^${@_b%)r1n`@_6HKn_c~qpu?aW7`757t`W_eCA>& z&kz9yJIm7?|5Q?Gve>sQ= z+doX6Y5h};;jD1&3&kR*!|w$e_FSCK!TZ;uv#nAtd0y%gzGN#yUNMtr9o7cw{d`v} znPPXp_t6M&TexoXtroF))1FRQrM1j3tI<%mZHpV5tekks+WAwqdfa)ug=wLE+m7oy zMQ7hT>LK{?oy%sWdO^0lW9vk3*7N!L?zPr!EpIN@4l($9_RGP?h0kp-%f1)C*BQ6t zSkfJR9T^zg78t&m77yez7dv@| zu&}U{|Jb@1$W;&U32_C|{~5{|{{M$i4CVjJK};YYC{Yd)E(fu`?q{2n^e{*@3Z79)POXW#oDtF1yr`=+itVv=OktFdG6g{K)mRoAX+EY7>z zmhXBt<&Eu!6r*o!cV_nNo&Ccp*=?%nxjo?-PXbeTw3r{SnJ?StNM`T3!o6nKZi}v&Xt(4rKl7t^ V?&lUg^#FQ_!PC{xWt~$(696v@lAZtn literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/s36i3p04.png b/tests/pngsuite/primary/s36i3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..eb61b6f9a325db7d967bd796d3a65494bf6b7754 GIT binary patch literal 356 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|l%)r2yqPf);$YDu$^mSxlY+GRXVp=?q&s^-} z8N$NCQvPG>Vjx#Nz$e5NNdIRjXZZggLNS#8F9$J!e4s=*NVput`nsRZ8c5&tba4!+ znA1CPFITgHh@1WGUzfMPP>Mb3d2r#rz};nBJ2KhD%L@z2iugh<9M4MfUF6B#_T+KJ zyS#u&i*AX_`$J4FwOGR3+lYu(xyz9^Us?I$Nzg8@_uT%B&fwPAv<_h$1 zKV4X~uHW!2nO zw^mgdcYZzlI&jNId!5cjyapMo+SY3yv3S|MG5=1ghQ&wM_et*;#P6@Vu`=r)^ENJ> nM6Fzb-Rz~M-&QV*`e$h`)grF|l3?zm1T2})pmUKs7M+U~W1%@xC#RK`w#ZI0f zEG#VLKejFga@7NTLR^9Le}-~~|NkKrL;3%55EIA;N|b|y%R#KK``N64bh)RCV@SoE zeX02TU7fN^(b&f@AC0IF4)lp>A zamtZ6X3lW8^&N+fpX;N5a1N0dE1b9+oO)I`@yuDpE^(oyK}Bq#(;+7|2{WUFjT0Lq lq)!ST`XV5f-^|R;z~ISp;_}2b`+!bh@O1TaS?83{1OP(LROkQz literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/s37i3p04.png b/tests/pngsuite/primary/s37i3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..6e2b1e9b79ba8ded32f713506b543f95c8720615 GIT binary patch literal 393 zcmeAS@N?(olHy`uVBq!ia0vp^svyk5%)r3tu$^}qki(Mh=sg+HIV-2>Eakt zF(-9`wNR6RK-+&o*^hxQcxC(!_~<1(WXyQ8cE!t#;Gj#lmM+`0{Ul?NhPm`7gP#(U z&TKlpT{>aX1vlpoG2ywrj9K?;d1~@l8+XmqNYD|GnW?j3_LDi&_Gk5ZpVL(C5Y*hb z;_)GkI~OeSB#!?*!4ts2={s4)Kw+AwsIZx0;sW~{6Jr*4M-?k-J?sdRs5Q&mv0%AZ zytIqJyc-jCPuY6yD{r}_O<9KFm9UNB@vD7vZe722&ATSp?!|BMy_))a()awI`Eg15 zcb}IZ6e>9H6slHm#xw|b7U^#ds^C5mec`FsvsuL_-L{JOW$W&>5V^;FS zsTXzmnjHk%9_laj{iXhZjaU6f3%5cQ1CLzmy47pf9C;MBe%0{;2EMB|HJ5HS=D#U8 zTcE<&;mf3XHLadi$}J7S6KsC%TdZ8VLMtWoP@;^%GPWsSI*kflz0dEPDy4JU==ewT z$8HrlSvDN~XJuI*Zalg3>X&(%0bi?r*mu~p# z*kbkGd%RM6vU;~}yPmpD-2FE9?b`>wofE(7z53qT-=ZIGukYz~KPva4hT&JMP+%DE SUKyZ=7(8A5T-G@yGywpP!HFRN 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!ia0vp^Y9P$Q%)r2?D{_Pz$YDu$^mSxlY+GRXVp=?q&s^-} z8N$NCQvPG>Vjx#Nz$e5NNdIRjXZZggLNS#8F9$J!e4s=*NVput`nsRZ8c5&rba4!+ zn6q@EJ$I9XOxyf_5svYTT%(q*Y;ODGw$)5_M`m;PZW9x8Q*O>*8?9X5^PP9_c=!F& zj}P}&avWz``7H13GiA$f!58}0_y?X%x||YHuGu}U@%Fz$#r)47t&6p-nF}}c@lTBs z^1PZ{v*FFH8(9sEQqM(?B}LEJyE$O3_FS z$q5XNhu)=5Tjidh!fa-!aP~lxV%mWM7U!NuQRf`SX00}f3tT>iIb{)A35DHSJCk^B z9JyieHiKao|6$!5cY4l9TNo}lec>oiL(-j$qysxN6CA{uC#7^J8uHKH+k8^@!3HLV YPnp`y=hnD91lr2r>FVdQ&MBb@0IdL5LI3~& 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!ia0vp^>LAR*%)r3N*;O+E$YDu$^mSxlY+GRXVp=?q&s^-} z8N$NCQvPG>VvyPZpAc6d{hy(n;s1XK#Zdmg9K;0jffD5);c^h`>wY$Cpuv)!E{-7; zb8;sb7Bw3PxXwR5nPsxbIbI3B13h{Zl-LU%&pWl%I?8Km-rd09oy#9GScQZM32{6% zJn&)b?*IA=s?&@YhcsVH;1O9g(`9z%6oU2EhY-&tz!*HGHjC7g8ZRKA?r5euu=`tFBX7AyHo&^hw&tWyi;3*RQj<5NC7 zD$9QAmr-d~@vfp^>g%_&3Lb_R^iP%F$ND|O^6>H9g zXp(yF?QYZiJMI0h)x3XK|Fr(u@2&iL4zKdoR{mw=nP&Qp=ij3Tz`$bgboFyt=akR{ E0PqU5-v9sr 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!ia0vp^>LAR*3?%D%eb|5$OS+@4BLidG0>c;6;(>hTVkgfK z78aKBA6plL)CTy3xB}__4CM^}|3fH-^8e)^CXf%5Crf5MCykT z!yOH&Kayq_xt_}isYhMd#%sHX&9!mIgr_sq&#dB<+^ar$Z{X$9)vls_k8f1|*}8bi zpB=vzEdR6P)rUoYc6jZ*eQSQo)o-o)F5h}-kYN6lt?pKC%J$H%zv=qU-|SMRztaeP zGf~`5;@h^18+60tYao5g)5S5Q zV$RyWja;A|lo{eZ(@L`p} zS{LWU6$LrdObg}*USsKY346=g=`j6{lFBTGU2~>go4o6%r;zgB(0Rug*KVDo#;EA% pAydNHT#*-Kd$uF{lI;G>I4-d)zk<)z6+mAyc)I$ztaD0e0ssYck!}D0 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!ia0vp^8X(NV3?%C=ER6$FEa{HEjtq=#3k+XOiwE+Vi=8|} zSXfxfe{5Y0FS zXD@8zZ7|?*x#--bqd09rVn>dvna6z96-Ml=&4Mcg{<*&Jc=+gKnBVfCtuiaG{Fsq+ zN5I`d(XC(dB13ART()`KdT#Ey^-ixof4?!Sz`}fsxz-Y$_FSPy%NW9)eC5gyx=V3r k20fUweGf1AoYPn=%bN?oV&q3&xZP#{- zd#wGeV8okcyH@o)cboHb1rrf^jB^?sG2T2?@G1n)CJc@hyhCf)&E8%^0~1oF;v>7S z;6sBJiji@r0Yq=mmR;)Ojr>$W46R-Sau7HO7xZFtI1{|4z%-nLbW=B z3o0EAC)h$;8WIR1rohQ#w444G0#1m$Dj66xet|L#R>4C36e7xMM0T)(aSAa2XfV)D zcEU#my$(kCaRx~QL^LgQ_;=)3gHxFOXBZJd{maEJLqY3H<>rDuET^1Yth7z0>+1gi X*waT#qxC!3? zz50+^bb0-!+_LIFVlkOn3uCR$oXN=hfy)oYZM=LTO5_V)JX0F)aUb#`{Px3~8K z45Cm8G#cZ?2?d2q03|3C!N$f8gK>%=kzAFOs;a7HXJsOhsJOUTC=>!T78DfJ0p#W7 zO#|fS<`x6+csvb_-PzgMH*VaxejVY*&B(||Pfw37i%v;TNli^nPEKZQ-I|z~7@ruA z92Sce8ykD3^-OehbYx^?czAeNSXdrFNJvO(?(>_pT_EMw{BQ#m>$Sn!qg3OkVyw9#4k*05u5X^#Wxw8I%DBhvS=>0kTjoKsJnz zkHa;PN~LfWvNvv&lMD4H5CQz1ooNFD1Ml8_0AO}^ckkGN(bYw&Ct|UTmX?<3ckj?> zcNB^Yu-39J8}w6t>_9>;(#;tUCqEAdt`EKrw%G5dUucga(q-6VG498*{K%rij4wv2 zoEfW%jzHYO{1#TLQQ`9W=k@mzoI;b9QinWz_A0mp3_C3m`>c%tC$KR#Xus#^maPqG>$Ip&r<7PP}+lo3xrqrK0bX_;b9>)$CG zYiDOPWRFqn6UcGDpA~Oj9{Dz;6-NwxejzAm$n^KEA< zw~yjS7UP676`?(gNA_%Ti&?JTRiQ)ukN>niNvk-4K4Y-(eYokz+n%p00U^e=@{X9+ z)rI4_;#GQ*EM)A{+^B9WciOLZ)vuJAK75`z`)0L0X_*pJxWq7Myp(uq&jr<7|o zLnIyhWR@l$6GSYpXJsSmv@J23K`FjDRPrN<`4!1UJg1FhP}`#*W-iAZNy`g6qaeJ622^AeZriDs|F)fz44lCrgvCaK9(i)p7!%%LO z6LCs$SZ>MfJV}wPPOIFlR1QvYe%|MK-}ia{df)f+{c@b0>@`sOC;-qn<$!ZVI(j`f zDj^kjGph?}%2e!GEGVRlO(*lc0TkamJGz}*TU$#c5*r&IR@vH?l$6w=(b>AXMMXv1 zx04DB3jtEEU%$?+^=WBow*aI7Nl8fw2?+qjY&IL9hsk8d#>O5wLZs8_(b3V7k&zD74p)(r z6#W5wi5%j-eJnyYfy3casnmdg0P-cW&PSbeL&Go(2FJts`1l+vI)>xmtn;h^Zo*f9 zFF+!ZJUl$y-Q5WUf_a*`i;K%{;ch%0Z)Jtm(t1?CX%ln~ww zvI4CLn;>X`*DqdZX)#srsxB=p0rJcP5Q$0`7Z=q_)!{xs9cb~i;5IBQEI>6tCCtyy z&(6+*5T>W60ceneP(Tm>WPquush*y(ii(Z4cCD)F{LssxzP`RZfO2EwuCA_*j*dQn zArvZ!Mq?a5uB3Dcpag{?+Sxf^v1cR6WET~cs;a8FIk{LYE-o$>i9`TRH*Vah2Ph~g zm;uPo&o2hx^Z7bDJ92Y#uU)%#^(w-Tmz9;3nVA_=7L%5lmY$xTnwrYkv?)0`IX*ca z2^NbL7Z-QB?Q~2`OjJ}7l7z-JS_iG7g0sVN0Uz}3~&+1VKez@Wfj%a%*<6dWBL zfByUl>%J=rqtT`{H60urpc%{q%@q~D69^Qz2T+SJUKdaPBUi= zZ?YsBS+ans&A`7&dFaENu<+a*|IhOD!Fy5FU2($py#tmf$d>!3__F$7Rx`n0Xd`(x zXNPrB#Hf{`Do)y8Y}67x>Fw{qlr}T!YF_4_IUZux-oC*~jH=jeIQPaX!`r{y1WzBl z(m6wK7D&e$Zg(V>@2C;Wf~LRR?X8$9#=q?zc-|P5aetE9NbV#QTKGtM8suGqBBx#3 zxo@Q}hx+TEERS}!iYl~OZDE->d_uXdy?`@|M5G4?j`=QYAGR)#`a zvNJkHwy@!`Y;;2I`Sq)+{L9pEnB}|hM@{;rXnr^QKIxlagyn~gH+uDas6JD-A_hPD*sh|5-pZZezZNI zTBjQ-?c5``GX0PwW_dm>8`Y+1#_9&A`Q}k652Y3f(u)LcJ9%$iuabnh9D6vUApEqF nBzr1Qcj<%PHtn77gx$)ZQM<+~5{$JW7KKwMop80bl;r;b+-;m} 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 zcmV-n2A=teP))6_}Akuqmh*5X4X^rIbM;BH-v?$kU01p_ErCl=u4~ zL7fbz&H-~9!(}3aFu`RZW&unzb50QkgK2!RYsr=o3t~2tT^d3tzx&+X@9uj)%)Vj6 z{|IpB&Yj-g-pR?y{}^!Z-o3WAwzRagh=_<-fB!T`$I~7jJzDL9k&%A|7#|<+>gvkP z&5eqRQiO&cb#=`%Gt&SnAO*+-su`xq!J$j392p#Z_UzeG0aH^`SFc_zD=UkSkAGjG zNZGY3d;R({hG_tbfDeIqE;r1MUWVZftDkNW!h zs;jG$lamt?5{`w2W;;5Ta5(kAS>OWD3k(34fhLB@x3Eyz+ozkGX8`3uA)t^*Vq;_J zARVu%si6?50P_I-{r&0b>GXAy-pZYvJ_kMn+JSRiZt1pd#bWVg8=D~(>oza}`~v)> zM}7e)8HRFA`iDhFM^mix0K>z>DwQfHCnqyAGc`3;6%f#2ZhqFvO5^8uBq=H7FUwFU zT6XLhvbG*uwdz+cchJo2l$~8_P|)B15EmC05)$I?@88+kIS+9E{(W+tk&&UwQ56&v z(A`o(AH0rH_Tk~-0RaJGvDnww_wL=h^8j=?>6z)a6}IeCY}aO2b*Z|fq@=L0@WhD| zsSDdty^(jSiA*M&bM5WzEtks;bWvVj9&?GoHDC(zc6o7eG4)bKMMY_8X?Aw@u?6h# z;lshf`|a#hY<3Bkd&JHz$kWs3`0?Wg0OXPTF&CY{G^|Igi;9ZKH36!ss;DvOr&_J1 zx~1t&sZ>(M4;(lkk?c1!`x@w{b_L!AqU`OZt*xyF0OXE$lBa8(+d4*aQ!-UaQ=##! z_w+pDSx{e4UteEaTT3@Y0IErFaIj1kyl&n1z;8e!i?yF&L_nC8m3(Mu$N-?Zxp_n7 z2DAX*=>Wn$A?4)L>VvOzv*1+iR99Em(9l2wMRh0dROro{PXe>RH6x>UEG*vQa@TOV zQlU`t^yyOrfcExwL7@Om)cL>za2|4U%W^%=c<5%V3NB?X6h0+EjKsu5@-7xf85_?~ z_(n!?E-s$Cckkx$Tm=FtNq~V#ChO_xan5qaMSv9N2jF-3*7yqRh3Ek)Au1KoO;8fV zprIvzKyXeU{%KoVxrc`zkCz5CFib&h?McIcn>TN|Dcy8{RDkAq5^L3Kg|$LmUsXU< zBBJ4(W03sGWO5UeaSET!R&3c4%;9JOl9gkorlAz5VF1mVSE84$J}Q`0nqU|>1Di@4 ze5+F&_hR?T%1UBTp~Aw#cJ55qhku#R59RT^^+74-!fSSE~<7VgEJh?uUa0qm; z8Ez47t52=QkANEJ0t(=x^_iQy^73*TT0XxG7zGZwyYCSQ1YB+maEUU=$|_zAke{D# zTyIS3>>TO5U9}y3y6WrNG#}mt-ZU1(ApHmo3|zUggX&{s6zS#V<>Yh_y5_4hF$wDK z?p_S=`P`~WeyGw#>B+X26iZPz^D41kPE3=O0g4z6qf*N)=*PsGE4-+(Dp2{ zw2Zxeeeh*hh5=+_V`EuaSwV3@IIpj54kWn}jYdNZ8e`JrO`E(~ENUAnPWZ-+iMMY3 zY|zhwfLVQ0wY0S8#Df-Q7G&8n5<6nh7)vA)kx0bn+nAbqczMM?d^oX?lf?jYc4O#< zON|S4tujMN`;Hh?Jz7|PetuiGZY4pbYg^pItKUTv6B8tGw0Wp##Go?l 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 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 literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/tm3n3p02.png b/tests/pngsuite/primary/tm3n3p02.png new file mode 100644 index 0000000000000000000000000000000000000000..fb3ef1d0c5aa4658cf1c1383dc6e74fcf09116d3 GIT binary patch literal 116 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@o&cW^R|bavaI|&4^Ese6b4ie2 zFhl4n?w#tEK(2_Vi(^PdTyhFSQ-Fe;PETlaHzR|#xM-r7v7RGPp25@A&t;ucLK6T+ CZ5hr0 literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/tp0n0g08.png b/tests/pngsuite/primary/tp0n0g08.png new file mode 100644 index 0000000000000000000000000000000000000000..333465fcdc9f10f7f25b2d999b558f5421983ecc GIT binary patch literal 719 zcmV;=0xe{x-64Dw5ISbDJfGPNXYF1fsnx~?7~M3eMD*m6rOMo0;2$rUW>-c(^**S*Ycd0zuX+u!1|S9WB+#F78QX<>lo? ziQz$h-hRnIWoQ!H=elq>2fX`s$g4Md}>$Ugu1e*ygBpcmqZ3DNb_5HNEsBtg8Fz$MsRgsRcUEt!R)#7 z@*=Hdg|%Ijgaqfp6x>M8@W|(*DezA>78ATBV zGiJ?6^pq7`pj8TmNNXtGQ7M(fr#kNOGpUKtO+a# zE}lAlTDXoRkAt?j2v0jgK~H>oU`AO)UQprWsr_L}qI~YALPA1E5ej}SPEJnGOv?!@ zojAEOR7Ob9QdC4?8%mP9keiy8ksVOlKd~`Xk)KCEK=mA2ntaoimYx|<+}mFjqR+?8 zZTJ8q(f(PLp6*}V-CGiDD=qBv7F)8vQWR0&(VZLQZ(jZjd%k$Tpt-FhJuqOwUu^jT z1pXapZA%Q=jx2U BP!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 zcmV-A2F3Y_P)u542F>)wJ;-zU<0Ta5X4X^rIbM; zBH-v?$kU01p_ErCl=u4~L7fbz&H-~9!(}3aFu`RZW&unzb50QkgK2zirzKlPEQpyV zJ88Z&UwhB*+;h+QpNot)Z1^7mZr{G$*Vi{SHT9YSckkY9Z*NaePmhd@j0*@zcXT}E z>DjB%+#enNPk@PuiSF+1yu7^V=xBLZ*b!IPd^0mOpafEZETD#AngxPxg<^DQ=;_m^ zO9f0%PhYumrM$d6AtB*?xjc2}&YX4Y${D5+CG4W_vSdOD(DVN&-oB_@QeZU}a320`R0!vG! zgF}Y7c_vT+6ajLvI4&-Z7Si(C+FA;c5-<-iFfc$*`Z-x=6;4i{1D^pMz*&|p+q$(x zB)Vj4J8WQZ3z!6c0e;dUzW@{rLwimBm&L@yP^|L+BO@b9r7|}+H!CYEEiFwM7}#lU ze#Y8b?eBj$IXU%j%aqGow{IV|u^C^v@>iA}GBZ1AZ=V(%{LdfavLmWItxn1d>CixU>w z(z&H&q%@~cmeiGMuLdu#(_V!Qg$)f2b#--gLIj|kgoK1hr6FtAeh>TxG#MD|V;DCe z+}c_;JUpxi(9+VfzG^*Mf$y{cVZV^}t ze*#wx4d1b}e2ZmQv#dlY6hC?LL=T{&qk~_>M>ADEa39m2fL{qvo7rko-xdG82;t3ZKJ~Z{8fjKg!o$ON?8wlCe~HHnv#{{d1tq7Cl~vHp z%#3~jNv`NUkyhKvAxIVA8=wbFDWm}$)k06v92)E2}b{Rj#QTCt*&@?&Ti zD zl4Z+2B9B~dgtK!fhf@n&;PLjfw||-Og6SEVLqkKcv9UCP1w{gUs+$RUkfbMoF`VR)x@ASCQaVB z(Z|4m%7&5?v0+2f&6_{#^|K%#LswL-t*u(|pn;hUX^xb{ju_O&VzJoG&5g&iH8u70 z_D*>4U~(ZRivi~B`tWs^S{JHXMW%x09Wf|-G_d^r{kLq{LV`-iwz!9v--{+ECrRLF z@=(%OV07*qoM6N<$f`h#14gdfE 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 zcmWlXc~H^`6vv-Om}J3dn5OOMOgg5aIm=3#R_~R8*9gm+#ueDlIJqsFg@0;tH{|b8}HqQ5Jw$Ebasl zi9{wQqx{s={QP`?_T1du%K+m5+1c6W&Yc6O&&;#KYi za0xyG{0*U@p&=n5OeT{~rxS7s!NI{ht9Awk26}jqu-LA432IQH$P*->1%a<=E7fhf7KmpiNEL?|$g$1|@ z&=;ZU0fm$KWEP7BFz+mN_CD$D>KXyBfJUPQ1qHz$U@Noz`t>V3 z0Y5*#_4Rf5=AAr|%l))v3zbTRZXmD;`udA>dIa18XhRr(3s9%iK@&&<11kswKn|(| zCKfuzi4TRu*jp4GWDgcp#{666_U|?<$;@lL6fyrT=v@~MF43;U zZ$6b_)kkb?TQRlFx@L1DFHuvCdiGRV@qSb5o3SyX=dqWIo~SD}lgtU8-0hinIc|l^ zwZpyIy{+Kp3qku~jyuQS{wOJTffqk}ylg!rGf@@8WYp~qRTEe@i_6M#f}U2WR@4MfM)1HJRjPCMx~ z7uM(-p3*y>&A)fhi1A3;cS(L+J1;&pqWL&it>CX0-+eBqO{=g-lKzNGvG(`sNqtRF zeg3%mDzvL|F3Eho_0DyETn8H%dc!?dA!#0>Q=Vr9#{-Ga&|1#6CAW+Q0sfY$`N-&; z^0c=#@%4)8jy6X3lL6u3JAW=?c#tm>K2a$#(Q?|Uz}T^+pWADD@MB|q8>&Xr948aj zsY1|Z7&ad@u4wr4W%TE{WS7U&Rh^yI#(OsCtq$vQ3|A*M_uLm%-A~M)I@BiVUyS#YR$&g!`CNx58tIE z|3D@=NLJY$Q%;J12ZU?1w#&^2c5EzDN05DZLoa2szJ*SEwwg0|Mem<$Yn1cWcz^cq z-}lxrB6iz%k1R&3=>`|KS%};k)l(YskH!jI!g#-(&O>3hx)5(GX8X3fe_&q16?&Zr z)72bEymR&OySDOI3mZ0C3tSEiO=8X3u^BG}uBukDWrMyZ$LQ%Y4sr7@il=hRi%!IK N0G~qvls0mN@PBi2fm#3n 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 zcmWlXdpOez7{_0ijw~Xj6ZLfH5mEEBP|@KrEtkTuS}m>SI;>1?8{6D(v$V!$$}kk^ z;zXQM92O%H=ShmnbXw(ZQ8_r3^Xq+{_x=9)zVGMz<@$KL>7tBL0HEvPj`Ks*k)Uu?Q@xn6z>Z3lMM-Q#6tfUZ$jg9xOySS8oYSdsZ?58S}Ku90Gh5`xl#{MR8%wt zP*_-43Lq2;*RS7_pPzr}(xrd%E)}>Vg+~H{0|EmB;S209 z+JEZQsgoy9!bij)vJ2CNNF)M$vKCsqg}Grc6c_?OKR+KIALs+qBGU~U&cS2w^z{7x z{X6{3T?w5=n_Ror-Q69U!8X)ZUHvP8K!G~|wFu*%2C7slr~p15FS4}-9)W zgA1TkDj@~(fB8jCjUG%S0R(${)B5}SM@HTPu)4duH*Un5nj+Sda5!dbYwOg=2pWA9 zg`xngv~oCl+wa{*R;b1Lc@x0-<4`CPvRn@w_UQh+Ac}Mk^OKb>f7-E19*W;}xs}~! zRlIciNyF__FM9f7*5I)-+cbPa1|k-TrQvsONlsb*)pnz$h0|UcNA3@z)MNfwE}Uv0 zIbFH+_Zk14HEp3y&g@1-ft^E-J#CK+WhE5TXruYlt&^-N^P3g#I=H!w`R}L=sT9s{ zCuD1uhCdG)aY*zhVd3F}HZMyY{g2C62iLwz8h1Q_?PFhSvbid>^O4P?YqRlh((eZd z#_aspCH=EBx%*CRO=qIG-J;L_AlZKBgiu)@&Tb|Ii=AapW?Zqp>gYA)sH#J5XB+h; zk9wYVqsyC_bvIrV9&w7WX>VWUAVpP~na{j&$UYNXX^m&}Uyx5RnnjA&4L3VdD!1H_ zD#Iq{ZueA8l;TIb`kpn$X5SsBHj?FpV!HrYcY~@^RN}pDGk;X^V&G~0qorYaOP*rv z^qN~4t3n!C(Ta6lUVkRto3S5$_!4xZm;=Uxwl-UlXk<^TD! zwrXx-kZ%7r>OqrnxrwlgbC>i*G{g?VCRx6GHc+-!v-|w+aMq(Z)3<$!sgDrNgW zt{66;txYft&kQV}Qtm74k`-qO{C2WMU5|#0wUn?oyC~|ghKx56YPk5`Xp_O#x8g2M X(5+n&l!#upArS?SL*BSr7fRay;V71Q literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary/z00n2c08.png b/tests/pngsuite/primary/z00n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..7669eb8385172325c399f3229cfe834f886fecb2 GIT binary patch literal 3172 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1SJ1Ryj{$|z@zQy;uunKi&25+{%6Mj{~3NT zfY5g^iOI$zg{%daG8T~8Gz1(pwSa?x0cZixpELm=(-{~zY2*W_>0lpFKMoM4)4~E2 z)2SW@=%!OQ4zQR`#UR3NI<+joX*yLbz-Kz;kxamJ3L}}Y>68Q!QKpk^0kNi&7Y8Jm zPDUJ%W;&@sM6&55SwN2I#K!@drV|+lP)Gd0N=r*M+Cfdcn4n{+d)GIuBfe}0=haRfYbdY4|HeAW8JeNk!}u< z>b4FPx}gJ|u3eE@R|Qyfc?U*a*nwS_tjMJg1H3vP0MMC|F?z3LnBH6wQvU~l^-l+Q iz3w1HzgHBc=YRuMlTL2m+d~-u0000811+tMcYXzcm?aHZ#?gdL8ij-oNLTu@go{<42!=C2J(%l`2yyuQm;^LM9XM_s7MQs$ow Yp_Bdc41*5p0G-U>>FVdQ&MBb@0O=}Ly8r+H 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!ia0vp^3LwnE1SJ1Ryj={WmV3H5hE&|zdeNJ&K|z4|!mJGk ze#?uM?J%qpNVJm;SDAGELf+biOrjbV{C6uqc^By}RQhy!A*198PSpVRZwtidR0X(h zmlOPO>811+tMcYXzcm?aHZ#?gdL8ij-oNLTu@go{<42!=C2J(%l`2yyuQm;^LM9XM_s7MQs$ow Yp_Bdct_kk@3Uo4qr>mdKI;Vst043R2BLDyZ 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!ia0vp^3LwnE1|*BCs=fdzmUKs7M+U~W1%@xC#RK_lN#5=* z4F5rJ!QSPQfg-0oT^vIq4j-NF$k*b)!7}^ozyGJ-oIDabg|X_u>_Q(?)khkuR!La7 zu*~chsLPP|}S^f!skB7DWF?ZskqvJ`CRNW>pLl^tak&^VnrV)#A>)9kel<=2?=1C*pefxc2Lag8WRNi0dVN-jzTQVd20h9bP0l+XkKm%fiA literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/basi0g02.png b/tests/pngsuite/primary_check/basi0g02.png new file mode 100644 index 0000000000000000000000000000000000000000..bb5309885175369e7a44a82b3d71c503ee0e6230 GIT binary patch literal 283 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzmUKs7M+U~W1%@xC#RK_lN#5=* z4F5rJ!QSPQfg*99E{-7)hu==~<~m@&;gasP?#18!r0uz8iWB6Y>=YJ}>w6Iq^h#K8 z;k-L#;k9$^Z^>}_zukc`I~jKX*zo!^M()1+nFD*GaTS& zXpm=kzseGVKswJ)wB`Jv|saDBFsX&Us$iUD<*U(7U&^W}%*vi1t3dlCF zure?xzopr04@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!ia0vp^3LwnE1|*BCs=fdzmUKs7M+U~W1%@xC#RK_lN#5=* z4F5rJ!QSPQfg<*vE{-7)hu>b>$jhL>!|d1`q41lZTUVH+t9bgmC4W3N6|Y@&sq(yy z+<{mBcCzhb&R}q0W{_gIz|g?PV8T$qppwOVi}ypuVxUo~C9V-ADTyViR>?)FK#IZ0 zz|ch3&`8(NIK;@<%D~bJ$TqOBGB7CQxvq+$AvZrIGp&-r(9+UE*T6*Az%<0j$jZRT a$^^(Y2Wqf8*4_!!z~JfX=d#Wzp$P!N$w>GB 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!ia0vp^3LwnE1|*BCs=fdzmUKs7M+U~W1%@xC#RK_lN#5=* z4F5rJ!QSPQfg%~6E{-7)hu>b?$jhL}!|Wh!$maCMUNossom zTJ?)FK#IZ0z|ch3&`8(NIK;@< z%D~bJ$TqOBGB7CQxvq+$AvZrIGp&-r(9+UE*T6*Az%<0j$jZRT$^^(Y2Wqf8*4_!! Oz~JfX=d#Wzp$P!Y-&#@t 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!ia0vp^3LwnE1|*BCs=fdzmUKs7M+U~W1%@xC#RK_lN#5=* z4F5rJ!QSPQfg+)vE{-7)hu>b=$a}zmhuKl;g514&?c7hAlVoQ+;=X1hFoDm(DQad) z_ERPn4v!Oz8sE}SF>?qgJow9e^q)^910xelO+CY x-29Zxv`Pj;OG^t~0~1{X(-0#gD+41dQy|+MsKNBi+hm{y22WQ%mvv4FO#tY{R$u@C literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/basi3p01.png b/tests/pngsuite/primary_check/basi3p01.png new file mode 100644 index 0000000000000000000000000000000000000000..a8599e9a5504cf33f6de68849961c0eb59e77883 GIT binary patch literal 273 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzmUKs7M+U~W1%@xC#RK_lN#5=* z4F5rJ!QSPQfg&NEE{-7)hm&i*$G@~^7BcYM-+d<4!Z>(l 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!ia0vp^3LwnE1|*BCs=fdzmUKs7M+U~W1%@xC#RK_lN#5=* z4F5rJ!QSPQfg*{XE{-7)hu=K|~gNTDg(5*9HR@U8VWIC~tIe-6W>%TjgStl4D?f?JpO22gg!&d%3atmq~ zFuY}E&5+kPz}f!9M*YHa>7_u+R7+eVN>UO_QmvAUQh^kMk%6I!uAz~xp>c?jv6X?P z6_9OUVP#-Y$a7s4MMG|WN@iLmgQ2CRg|2~#u7PQYk&%^wk(DWsYYx=#DW_c=sDZ)L L)z4*}Q$iB}ib!A; 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!ia0vp^3LwnE1|*BCs=fdzmUKs7M+U~W1%@xC#RK_lN#5=* z4F5rJ!QSPQfg*jLE{-7)hu=;=$lGAR!z_En)5<$Mfwe7()vY1)h1NswKM$_AwSVru z5~Xh46;*uT<2v4r*KT|h`#rZ${z~~4|AVY2RU3?~i{&7%6Eugk`*|>Tz=5t zT+U{T-$0kCmbgZgq$HN4S|t~y0x1R~149#CLnB>7;}9cbD+5a_Altyg%D|wI=ejD2 yhTQy=%(O}dLrY5wT>}$c1Je*ABP#Y~u z*B$5i8g-Kbl@=^GmZjsDF@@uXVnashqQHO7tU?NmX6z^Yeq=M;;pBB_u%jNt$P 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!ia0vp^3LwnE1|*BCs=fdzmUKs7M+U~W1%@xC#RK_lN#5=* z4F5rJ!QSPQfg)a>E{-7)hu>aW$i-m5;d;^B;LQL35xMKuui=T?+2m+2r{MY-k4yW^ zp4a+XIofu^dKxJHzuB$lLFB^RXv zDF!10Lla#?BV9w|5F=wN14}C)+rYxgz@U)lx+;o>-29Zxv`Pj;OG^t~0~1{X(-0#g cD+8b&Aln?MVbZ$}OP~e@Pgg&ebxsLQ07Pz2rT_o{ literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/basi6a08.png b/tests/pngsuite/primary_check/basi6a08.png new file mode 100644 index 0000000000000000000000000000000000000000..c12484fc58fd2ea0ff4709c6c5093af224580faa GIT binary patch literal 298 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzmUKs7M+U~W1%@xC#RK_lN#5=* z4F5rJ!QSPQfg-t{E{-7)hu>Z^MG{133*2~v=nBdG1=3ba_Y#5JNMC9x#cD!C{XNHG{07@FuB8tEDu zhZq@K8CY5Y*#;I?1_p&Z*Huw8-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!ia0vp^3LwnE1|*BCs=fdzmUKs7M+U~W1%@xC#RK_lN#5=* z4F5rJ!QSPQfg-0oT^vIq4j-NF$k*b)!7}^ozyGJ-oIDabg|X_u>_Q(?)khkuR!La7 zu*~chsLPP|}S^f!skB7DWF?ZskqvJ`CRNW>pLl^tak&^VnrV)#A>)9kel<=2?=1C*pefxc2Lag8WRNi0dVN-jzTQVd20h9=YJ}>w6Iq^h#K8 z;k-L#;k9$^Z^>}_zukc`I~jKX*zo!^M()1+nFD*GaTS& zXpm=kzseGVKswJ)wB`Jv|saDBFsX&Us$iUD<*U(7U&^W}%*vi1t3dlCF zure?xgTe~ HDWM4f9Rpd5 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!ia0vp^3LwnE1|*BCs=fdzmUKs7M+U~W1%@xC#RK_lN#5=* z4F5rJ!QSPQfg<*vE{-7)hu>b>$jhL>!|d1`q41lZTUVH+t9bgmC4W3N6|Y@&sq(yy z+<{mBcCzhb&R}q0W{_gIz|g?PV8T$qppwOVi}ypuVxUo~C9V-ADTyViR>?)FK#IZ0 zz|ch3&`8(NIK;@<%D~bJ$TqOBGB7CQxvq+$AvZrIGp&-r(9+UE*T6*Az%<0j$jZRT a$`Hsk2Wlu&>wF8;z~JfX=d#Wzp$P!M(Mab?$jhL}!|Wh!$maCMUNossom zTJ?)FK#IZ0z|ch3&`8(NIK;@< z%D~bJ$TqOBGB7CQxvq+$AvZrIGp&-r(9+UE*T6*Az%<0j$jZRT%E&<1z#ORIwA+D9 Ppaup{S3j3^P6b=$a}zmhuKl;g514&?c7hAlVoQ+;=X1hFoDm(DQad) z_ERPn4v!Oz8sE}SF>?qgJow9e^q)^910xelO+CY z-29Zxv`Pj;OG^t~0~1{X(-0#gD+41dBQsqCbD)M5)4m1+H86O(`njxgN@xNA>`_*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!ia0vp^3LwnE1|*BCs=fdzmUKs7M+U~W1%@xC#RK_lN#5=* z4F5rJ!QSPQfg&NEE{-7)hm&i*$G@~^7BcYM-+d<4!Z>(lK|~gNTDg(5*9HR@U8VWIC~tIe-6W>%TjgStl4D?f?JpO22gg!&d%3atmq~ zFuY}E&5+kPz}f!9M*YHa>7_u+R7+eVN>UO_QmvAUQh^kMk%6I!uAz~xp>c?jv6X?P z6_9OUVP#-Y$a7s4MMG|WN@iLmgQ2CRg|2~#u7PQYk&%^wk(IH5u7NpF1N)l;-+>w! NJYD@<);T3K0RWJ$V7UMQ literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/basn3p04.png b/tests/pngsuite/primary_check/basn3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..f08c6e99d4b477e8ec7defd7f7cbb58cb815d2b9 GIT binary patch literal 331 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzmUKs7M+U~W1%@xC#RK_lN#5=* z4F5rJ!QSPQfg*jLE{-7)hu=;=$lGAR!z_En)5<$Mfwe7()vY1)h1NswKM$_AwSVru z5~Xh46;*uT<2v4r*KT|h`#rZ${z~~4|AVY2RU3?~i{&7%6Eugk`*|>Tz=5t zT+U{T-$0kCmbgZgq$HN4S|t~y0x1R~149#CLnB>7;}9cbD+5a_Altyg%D|wI=ejD2 zhTQy=%(O}dLrY5wT>}$c1Je*ABP#Y~u z*B$5i8g-Kbl@=^GmZjsDF@@uXVnashqQHO7tU?NmX6z^Yeq=M;;pBBE{-7)hu>aW$i-m5;d;^B;LQL35xMKuui=T?+2m+2r{MY-k4yW^ zp4a+XIofu^dKxJHzuB$lLFB^RXv zDF!10Lla#?BV9w|5F=wN14}C)+rYxgz@U)lx+;o>-29Zxv`Pj;OG^t~0~1{X(-0#g fD+41dV>4X?bD)M4o3Ceq8W=oX{an^LB{Ts5MD|b1 literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/basn6a08.png b/tests/pngsuite/primary_check/basn6a08.png new file mode 100644 index 0000000000000000000000000000000000000000..1f54e565df630fc54cf973677e9b7344d639cf25 GIT binary patch literal 298 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzmUKs7M+U~W1%@xC#RK_lN#5=* z4F5rJ!QSPQfg-t{E{-7)hu>Z^MG{133*2~v=nBdG1=3ba_Y#5JNMC9x#cD!C{XNHG{07@FuB8tEDu zhZq@K8CY5Y*#;I?1_p&Z*Huw8E{-7)hu>aW$i-m5;d;^B;LQL35xMKuui=T?+2m+2r{MY-k4yW^ zp4a+XIofu^dKxJHzuB$lLFB^RXv zDF!10Lla#?BV9w|5F=wN14}C)+rYxgz@U)lx+;o>-29Zxv`Pj;OG^t~0~1{X(-0#g dD+6OI6Cl?dsNo{Zo9#di44$rjF6*2UngB;aPvrmr literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/bgan6a08.png b/tests/pngsuite/primary_check/bgan6a08.png new file mode 100644 index 0000000000000000000000000000000000000000..6cb76f2b43ccd41aeca1eb05eb9863ba4b4129db GIT binary patch literal 298 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzmUKs7M+U~W1%@xC#RK_lN#5=* z4F5rJ!QSPQfg-t{E{-7)hu>Z^MG{133*2~v=nBdG1=3ba_Y#5JNMC9x#cD!C{XNHG{07@FuB8tEDu zhZq@K8CY5Y*#;I?1_p&Z*Huw8)WG2B>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!ia0vp^3LwnE1|*BCs=fdzmUKs7M+U~W1%@xC#RK_lN#5=* zKpF^sI`6IrQeK`ejv*0;-(FhC#bChUdePkA%>Vxpx$D-i;fdSX%rmB{>MwFx^mZVxG7o`Fz z1|tJQ6J0|iT|?s#BV#KAODiDTz{1MFppfUfDvE~O{FKbJN(MtqOAB2C6I}z-5F;Zi c17j-_AlDqI;UdeM?LZ9-p00i_>zopr0M9&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!ia0vp^3LwnE1|*BCs=fdzmUKs7M+U~W1%@xC#RK_lN#5=* z4F5rJ!QSPQfg-t{E{-7)hu>Z^MG{133*2~v=nBdG1=3ba_Y#5JNMC9x#cD!C{XNHG{07@FuB8tEDu zhZq@K8CY5Y*#;I?1_p&Z*Huw8|fFnGH9xvXzm0Xkxq!^40 z3{7+mjdTr-LyU~A3@ojHYy%4`1A{`I>#8Uka`RI%(<&JZEiEl{4NPzm0Xkxq!^40 z3{7+mjdTr-LyU~A3@ojHYy%4`1A{`I>#8Uka`RI%(<&JZEiEl{4NP6%z+wC-k#Y9)WG2B>gTe~DWM4fysR}V literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/s02i3p01.png b/tests/pngsuite/primary_check/s02i3p01.png new file mode 100644 index 0000000000000000000000000000000000000000..d84f40613e6b2aed5b1c3c0a638ea8599b57327c GIT binary patch literal 210 zcmeAS@N?(olHy`uVBq!ia0vp^Od!m`1|*BN@u~nRmUKs7M+U~W1%@xC#RK_lN#5=* z4F5rJ!QSPQfg+-wE{-7_*OOCz{Qqyy3p*F|> literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/s03i3p01.png b/tests/pngsuite/primary_check/s03i3p01.png new file mode 100644 index 0000000000000000000000000000000000000000..51367f7f8e0bf32bbf096160b69349bf1ddf2c2c GIT binary patch literal 216 zcmeAS@N?(olHy`uVBq!ia0vp^%plCc1|-8Yw(bW~Ea{HEjtq=#3k+XOiwE-AlDyqr z82*Fcg1yTp14X1gT^vI=t|zDbIR9ZjBi9TGAov&VV9|5Jh@q;EwPMO`W;>uV)e_f; zl9a@fRIB8oR3OD*WMF8bYiOivXdGf>Y-M0+1!NmoSQ!`;@?2L%(U6;;l9^V?U}$M+ op=)5GYhW5;WMpMvY-MDiYhVu4pwhBB9H@c8)78&qol`;+0Pxj18vpuV)e_f; zl9a@fRIB8oR3OD*WMF8bYiOivXdGf>Y-M0+1!NmoSQ!`;@?2L%(U6;;l9^V?U}$M+ op=)5GYhW5;WMpMvY-MPsYhVu4aPs!dKA;8$Pgg&ebxsLQ00NFXK>z>% literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/s04i3p01.png b/tests/pngsuite/primary_check/s04i3p01.png new file mode 100644 index 0000000000000000000000000000000000000000..ae326c1c4bbdb9c7e51e1054ac3d79df26bbeb00 GIT binary patch literal 221 zcmeAS@N?(olHy`uVBq!ia0vp^EFjFm1|(O0oL2|pq&xaLGBCC+FnlpB9>`})@^*J& z_z!{$_AZ|c6jAVWaSY+Op8V(k{D=0;LJ3I;AfVHpu!BJ;!R0y=gT!IBkCHlBQ-Nw# zOI#yLQW8s2t&)pUffR$0fuV`6p^>hkafp$zm4T%dkZoXLWnfUqb6pihLvDUbW?ChK rp{1pTu7QcJfoX`5k(Gh5m63t2fjLlvO3UhSpaup{S3j3^P6`})@^*J& z_z!{$_AZ|c6jAVWaSY+Op8V(k{D=0;LJ3I;AfVHpu!BJ;!R0y=gT!IBkCHlBQ-Nw# zOI#yLQW8s2t&)pUffR$0fuV`6p^>hkafp$zm4T%dkZoXLWnfUqb6pihLvDUbW?ChK sp{1pTu7QcJfoX`5k(Gh5m7$rgfjLma$=fsgfEpM)UHx3vIVCg!0P%4>xBvhE 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!ia0vp^tRT$61|)m))t&+=mUKs7M+U~W1%@xC#RK_lN#5=* z4F5rJ!QSPQfg;+TE{-7_*OUL8Kk#8bBku+SAP7^=`%DCCQ!R0gC`m~yNwrEYN(E93Mh1o^x`sx&hQ=XA##RQFRzS9ag_VIp zA^=`%DCCQ!R0gC`m~yNwrEYN(E93Mh1o^x`sx&hQ=XA##RQFRzS9ag_VIp zA;r0G@O1TaS?83{ F1OP&2LP-Ds literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/s06i3p02.png b/tests/pngsuite/primary_check/s06i3p02.png new file mode 100644 index 0000000000000000000000000000000000000000..73a7b0c64ffebe6b62296460854bb97e53e878f0 GIT binary patch literal 239 zcmeAS@N?(olHy`uVBq!ia0vp^Y#_`5A|IT2?*XJ((j9#r85r9Z7`~Vm50Xssc6VX; z4}uH!E}sk(G4gbA4B@z*{OA0K|Mtvc2M!$of`~q?ANwaaHgcYOozRk?k&twNG2+1* zu8`Fdg^_#=dDplmi8BXw0d=dExJHzuB$lLFB^RXvDF!10Lla#?BV9w|5F=wN14}C) z+rYxgz@U)lx+;o>-29Zxv`Pj;OG^t~0~1{X(-0#gD+6OIBLiInbD##5met`v4Gf;H KelF{r5}E)-K1fFZ literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/s06n3p02.png b/tests/pngsuite/primary_check/s06n3p02.png new file mode 100644 index 0000000000000000000000000000000000000000..e85eac8e8f8618ac6f320da65e51072f6de12003 GIT binary patch literal 239 zcmeAS@N?(olHy`uVBq!ia0vp^Y#_`5A|IT2?*XJ((j9#r85r9Z7`~Vm50Xssc6VX; z4}uH!E}sk(G4gbA4B@z*{OA0K|Mtvc2M!$of`~q?ANwaaHgcYOozRk?k&twNG2+1* zu8`Fdg^_#=dDplmi8BXw0d=dExJHzuB$lLFB^RXvDF!10Lla#?BV9w|5F=wN14}C) z+rYxgz@U)lx+;o>-29Zxv`Pj;OG^t~0~1{X(-0#gD+6OILm<~2sA1-lN0)&b7(8A5 KT-G@yGywoy97)yy literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/s07i3p02.png b/tests/pngsuite/primary_check/s07i3p02.png new file mode 100644 index 0000000000000000000000000000000000000000..08f61804f4ba73b862d9bf31e5aada044dae1ee9 GIT binary patch literal 249 zcmeAS@N?(olHy`uVBq!ia0vp^>>$j+1|*LJg>$j+1|*LJgbP0l+XkKiN;L> 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!ia0vp^93afW1|*O0@9PFqEa{HEjtq=#3k+XOiwE-AlDyqr z82*Fcg1yTp14W!XT^vIsF1Pl3@-ZlIFtb0N|CICBtEvkUrh0oBCts49RH4D7@}@#( z1tUXc@}A#qshtJa`WyQn**tNc#`t4t_us6rWy|>f*Z%rB4QQHbiEBhjN@7W>RdP`( zkYX@0Ff`FMG}1LR4ly#eGO)A)vJEV(3=9f+uB)PG$jwj5Osixtw6wI)H89aNFby#> evNABXG6HHa2Wr?Xy{itWfx*+&&t;ucLK6TtHBZ<8 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!ia0vp^93afW1|*O0@9PFqEa{HEjtq=#3k+XOiwE-AlDyqr z82*Fcg1yTp14W!XT^vIsF1Pl3@-ZlIFtb0N|CICBtEvkUrh0oBCts49RH4D7@}@#( z1tUXc@}A#qshtJa`WyQn**tNc#`t4t_us6rWy|>f*Z%rB4QQHbiEBhjN@7W>RdP`( zkYX@0Ff`FMG}1LR4ly#eGO)A)vJEV(3=9f+uB)PG$jwj5Osixtw6wI)H89aNFby#> evNABXG6ZtXff{B$d2|`5fx*+&&t;ucLK6T;Pf-Z~ literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/s09i3p02.png b/tests/pngsuite/primary_check/s09i3p02.png new file mode 100644 index 0000000000000000000000000000000000000000..ea14f9be0e000d9079a2305b26259234b6f9e810 GIT binary patch literal 263 zcmeAS@N?(olHy`uVBq!ia0vp^oFL4>1|%O$WD@{VEa{HEjtq=#3k+XOiwE-AlDyqr z82*Fcg1yTp14X<%T^vIsF85AwdcG!ScDmhme{?4J9NNta?@PFXlDefiG+N2H84PR{%Hg&|=ZpZJGjrlmkrRZCnW zN>UO_QmvAUQh^kMk%6I!uAz~xp>c?jv6X?P6_9OUVP#-Y$a7s4MMG|WN@iLmgQ2CR ng|2~#u7PQYk&%^wv6T@}gE>&cX6apZKn)C@u6{1-oD!M<7}iv9 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!ia0vp^oFL4>1|%O$WD@{VEa{HEjtq=#3k+XOiwE-AlDyqr z82*Fcg1yTp14X<%T^vIsF85AwdcG!ScDmhme{?4J9NNta?@PFXlDefiG+N2H84PR{%Hg&|=ZpZJGjrlmkrRZCnW zN>UO_QmvAUQh^kMk%6I!uAz~xp>c?jv6X?P6_9OUVP#-Y$a7s4MMG|WN@iLmgQ2CR ng|2~#u7PQYk&%^wv6Uf^YYx;f^U0&jKn)C@u6{1-oD!Mb3K)h=a~;X zoA_yLw#%*AR)m*4g=~I*oznCEXTim0e7<*qydRxMEjY%hjgc*~fP7 zxX%5s)HvAOMsvUYgbq88b3K)h=a~;X zoA_yLw#%*AR)m*4g=~I*oznCEXTim0e7<*qydRxMEjY%hjgc*~fP7 zxX%5s)HvAOMsvUYgbq88zopr0B;tb)Bpeg literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/s33i3p04.png b/tests/pngsuite/primary_check/s33i3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..0faaa74108eebe50057ae9499393d39730e86096 GIT binary patch literal 470 zcmeAS@N?(olHy`uVBq!ia0vp^iXhCv1|-9u9Lfh$Ea{HEjtq=#3k+XOiwE-AlDyqr z82*Fcg1yTpGcYhpdb&7xXE?#OpofoHSozcc#|tlsRr@bsYtYqFa9vsHSMAN4S> za7SqE>f91DQ`YmugRUh(2ZPxd&Ro)t6={6q!@$7d?Ic)W+T`>r%dA`JK}J(t=dHqA zCfdz>$^6g6=$b; z9(?oL*-OK0*~hA!idjuc6E1dSaGdTlQrM(!ZKm+kZ1C7HKHUXu_V$ 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!ia0vp^iXhCv1|-9u9Lfh$Ea{HEjtq=#3k+XOiwE-AlDyqr z82*Fcg1yTpGcYhpdb&7xXE?#OpofoHSozcc#|tlsRr@bsYtYqFa9vsHSMAN4S> za7SqE>f91DQ`YmugRUh(2ZPxd&Ro)t6={6q!@$7d?Ic)W+T`>r%dA`JK}J(t=dHqA zCfdz>$^6g6=$b; z9(?oL*-OK0*~hA!idjuc6E1dSaGdTlQrM(!ZKm+kZ1C7HKHUXu_Vh&(&(E z@>ArT>|ms#D119{?Ys5I^lenc7>y3iT^k82~$if4~t!7e0Iw{E%(~Yk1`V+9>#BW_||>lR{ury z6x?a$u{rKaRh&(&(E z@>ArT>|ms#D119{?Ys5I^lenc7>y3iT^k82~$if4~t!7e0Iw{E%(~Yk1`V+9>#BW_||>lR{ury z6x?a$u{rKaRxXlEs(F-fX7*OW%;{x7lNzp-*Rl&HuD9~zgcceXTF)( z&Zxk|DZ6Wih}}%q)EhffH@`I&O=e7(`MiF?4yDKt76zWzL)bPY+ zrdLb*5qDOehL-COXR~=SANOJF>&=hl4v?DcI3>!%aY7+e>s6x=A2#)js?K@44J1P( zEG!Im?K6@$mpr%n=z3XJ6Stb>-}9XH=hUm%p<`>G6Fdt}Vh}qbIGI$vbQB`?`BVP)t{QGbebpY&X%(esuzB9 z*w5JbH-q{5vYsMf=&6>tMwFx^mZVxG7o`Fz1|tJQ6J0|iT|?s#BV#KAODiDTz{1MF zppfUfDvE~O{FKbJN(MtqOAB2C6I}z-5F;Zi17j;=GhG97poZ>$^F9MLFnGH9xvXxXlEs(F-fX7*OW%;{x7lNzp-*Rl&HuD9~zgcceXTF)( z&Zxk|DZ6Wih}}%q)EhffH@`I&O=e7(`MiF?4yDKt76zWzL)bPY+ zrdLb*5qDOehL-COXR~=SANOJF>&=hl4v?DcI3>!%aY7+e>s6x=A2#)js?K@44J1P( zEG!Im?K6@$mpr%n=z3XJ6Stb>-}9XH=hUm%p<`>G6Fdt}Vh}qbIGI$vbQB`?`BVP)t{QGbebpY&X%(esuzB9 z*w5JbH-q{5vYsMf=&6>tMwFx^mZVxG7o`Fz1|tJQ6J0|iT|?s#BV#KAODiDTz{1MF zppfUfDvE~O{FKbJN(MtqOAB2C6I}z-5F;Zi17j;AAlDqIK|K4Z0Z;>jr>mdKI;Vst E00wZd8UO$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!ia0vp^Dj>|k1|%Oc%$NbBSkfJR9T^zg78t&m77ygJC3(BM zF#HF>1$&oIW?*1s_H=O!i8%ardMsbF0Z;SXPV479wp+hDbUR%xedC@fXW*p8dQiPX zmWyG}CSjF@Dh^s6O*2O++{-vy2@$}Q#e_SOy&iI8)by!i!w^r{J&nb457exi80n#T{ zx43Y%@kp%TPZy6%4Ykdu;sRl!3(D69(sS985lsSC9V-ADTyViR>?)FK#IZ0 zz|ch3&`8(NIK;@<%D~bJ$TqOBGB7CQxvq+$AvZrIGp&-r(9+UE*T6*Az%<0j$jZRj a${5Hs2Wq%|@aa0B1_n=8KbLh*2~7aHMW@gJ literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/s36n3p04.png b/tests/pngsuite/primary_check/s36n3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..1f50479e48ebcbf5c106e1baa714a47fcbee2448 GIT binary patch literal 448 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbBSkfJR9T^zg78t&m77ygJC3(BM zF#HF>1$&oIW?*1s_H=O!i8%ardMsbF0Z;SXPV479wp+hDbUR%xedC@fXW*p8dQiPX zmWyG}CSjF@Dh^s6O*2O++{-vy2@$}Q#e_SOy&iI8)by!i!w^r{J&nb457exi80n#T{ zx43Y%@kp%TPZy6%4Ykdu;sRl!3(D69(sS985lsSC9V-ADTyViR>?)FK#IZ0 zz|ch3&`8(NIK;@<%D~bJ$TqOBGB7CQxvq+$AvZrIGp&-r(9+UE*T6*Az%<0j$jZRj a$_U6c2Wk+{erf>Jz~JfX=d#Wzp$Pz@eWo`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!ia0vp^svyk41|*NpQ(y*CEa{HEjtq=#3k+XOiwE-AlDyqr z82*Fcg1yTpGcYhJdb&7xXlJ(ll~0Z((TX8FB!7lPZTPirmv>)5lT&PgCM>|5e? zmIVzn?A8|H9T0ePg6j2gGc!Wi#S)F1S2)~iJJ`l53LZ+nBlwf`LYWRS1-T1^IpkF z$4Wxt??3*%yZbX1pFB2AJtU;{o6;(cHNS(7-;lezz43^7~~k zT7LiRLfw78b$lW>-VHw-Qgf{A{$Jh$TYs;~;lCyqv-|zygU!F6h=1Rw&U>>y=J%fo z?`GdsjW7O`s=!^WrvnPx64!{5l*E!$tK_0oAjM#0U}&OiXryas9Aac_WngIqWE)sm z85k7uTn9%6TtjYtN@iLmgQ2CRg|2~#u7PQYk&%^wv6YE|u7NpF!=u-WE&y#{@O1Ta JS?83{1OQL@!BYSL 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!ia0vp^svyk41|*NpQ(y*CEa{HEjtq=#3k+XOiwE-AlDyqr z82*Fcg1yTpGcYhJdb&7xXlJ(ll~0Z((TX8FB!7lPZTPirmv>)5lT&PgCM>|5e? zmIVzn?A8|H9T0ePg6j2gGc!Wi#S)F1S2)~iJJ`l53LZ+nBlwf`LYWRS1-T1^IpkF z$4Wxt??3*%yZbX1pFB2AJtU;{o6;(cHNS(7-;lezz43^7~~k zT7LiRLfw78b$lW>-VHw-Qgf{A{$Jh$TYs;~;lCyqv-|zygU!F6h=1Rw&U>>y=J%fo z?`GdsjW7O`s=!^WrvnPx64!{5l*E!$tK_0oAjM#0U}&OiXryas9Aac_WngIqWE)sm z85k7uTn9%6TtjYtN@iLmgQ2CRg|2~#u7PQYk&%^wv6Zobu7NpF!wbFDCxJFFc)I$z JtaD0e0suu(z?}d9 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!ia0vp^Y9P$P1|(P5zFY^SSkfJR9T^zg78t&m77ygJC3(BM zF#HF>1$&oI28#Uhba4!cIQ(|{MZRVQ9#{YAe~b4wuHRSf__jqi&+Rnx^$7|BML}NP zj3rArJ$JB7Qs&&bV*dAK{%h+ER>(0uQD|KM?c;XWzIW`e`=U7QzdL_DsPn~^eHEj& zpjTx8!}+Dj+h#|yyIGz(_VewBwCN3Nw;S<=Ol8^ezA#7RxxDA&Cdu6uRvls8k>~e& zpX+UzrG4K*OqlJ`mYAKVZ(6Ie-*{Gfk!738hKnW#)oxs^ns@(^f2&1gR1ipoT}U S7hM2qVDNPHb6Mw<&;$Vcd#phK literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/s38n3p04.png b/tests/pngsuite/primary_check/s38n3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..43f8c983f111c2e7d7812f99aedfc787b68680f8 GIT binary patch literal 439 zcmeAS@N?(olHy`uVBq!ia0vp^Y9P$P1|(P5zFY^SSkfJR9T^zg78t&m77ygJC3(BM zF#HF>1$&oI28#Uhba4!cIQ(|{MZRVQ9#{YAe~b4wuHRSf__jqi&+Rnx^$7|BML}NP zj3rArJ$JB7Qs&&bV*dAK{%h+ER>(0uQD|KM?c;XWzIW`e`=U7QzdL_DsPn~^eHEj& zpjTx8!}+Dj+h#|yyIGz(_VewBwCN3Nw;S<=Ol8^ezA#7RxxDA&Cdu6uRvls8k>~e& zpX+UzrG4K*OqlJ`mYAKVZ(6Ie-*{Gfk!738hKnW#)oxs^ns@(^f2&1gR1ipoSNE St4{(oFnGH9xvXLAR)1|)kH2buyYmUKs7M+U~W1%@xC#RK_lN#5=* z4F5rJ!QSPQ85kJNJY5_^A`YLO5xwrPf`D^wr|o6k4O#c))s}iz#AvSl7=BdY>a2)j z1||WqEn8kDE`2)pW`f_`X%pVxFWSP(uz6kl8k1w2PD(Hcq!;%ZdS8%Q+HbJY4;?wdEGtk}LMy>|1O$GL5pd9-b^4bpV=o?Z# zS5tx_Zdg?{W@d+&HSX_ueM)Vc9Gkj-Q~jpJg_F#W@{|C>RJFu4q9i4;B-JXpC>2OC z7#SFv=o%X78XAWf8Cw}xS^?Px7FGrZg*?|)Q8eV{r(~v8G8kG~TId>>=o*-Y7#Ud^ c7+aYDHJAf6l$LD%3Dm&g>FVdQ&MBb@0C};)`v3p{ literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/s39n3p04.png b/tests/pngsuite/primary_check/s39n3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..d37d66d44129066477311007b621745cee75fd73 GIT binary patch literal 499 zcmeAS@N?(olHy`uVBq!ia0vp^>LAR)1|)kH2buyYmUKs7M+U~W1%@xC#RK_lN#5=* z4F5rJ!QSPQ85kJNJY5_^A`YLO5xwrPf`D^wr|o6k4O#c))s}iz#AvSl7=BdY>a2)j z1||WqEn8kDE`2)pW`f_`X%pVxFWSP(uz6kl8k1w2PD(Hcq!;%ZdS8%Q+HbJY4;?wdEGtk}LMy>|1O$GL5pd9-b^4bpV=o?Z# zS5tx_Zdg?{W@d+&HSX_ueM)Vc9Gkj-Q~jpJg_F#W@{|C>RJFu4q9i4;B-JXpC>2OC z7#SFv=o%X78XAWf8Cw}xS^?Px7FGrZg*?|)Q8eV{r(~v8G8kG~TId>>=o*-Y7#Ud^ c7+VzuQ<002!1)diDrSIp2&+xDP9Voi?+@_5alfNvva4X2} z+=@;G2P=;zKYJvJs->WRWJaZS5oNMZu=I%|~=4`WNbdjGPwtIhkafp$zm4T%dkZoXLWnfUqb6pihLvDUbW?ChK qp{1pTu7QcJfoX`5k(Gh5l?hOTIZ#7s$>yIx4Gf;HelF{r5}E*qORR7J literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/s40n3p04.png b/tests/pngsuite/primary_check/s40n3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..6f8596ca14510022eb45b8a6e05fca280b354e32 GIT binary patch literal 463 zcmeAS@N?(olHy`uVBq!ia0vp^8X(NU1|)m_?Z^dEEa{HEjtq=#3k+XOiwE-AlDyqr z82*Fcg1yTpGcYg;dAc};L>zuQ<002!1)diDrSIp2&+xDP9Voi?+@_5alfNvva4X2} z+=@;G2P=;zKYJvJs->WRWJaZS5oNMZu=I%|~=4`WNbdjGPwtIhkafp$zm4T%dkZoXLWnfUqb6pihLvDUbW?ChK rp{1pTu7QcJfoX`5k(Gh5l`&9*IZ#9W#$6A98W=oX{an^LB{Ts5ii51A literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/tbbn0g04.png b/tests/pngsuite/primary_check/tbbn0g04.png new file mode 100644 index 0000000000000000000000000000000000000000..8d9f7d52b0446496c9db04c1ab90dd967dbdbf71 GIT binary patch literal 762 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 literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/tbgn3p08.png b/tests/pngsuite/primary_check/tbgn3p08.png new file mode 100644 index 0000000000000000000000000000000000000000..fa5cdbc95a44cf76abbf44527dbbd7e12d72c268 GIT binary patch literal 1911 zcmV--2Z;EIP)%G*ochBz3{Q9u#ja*|cB~p&`lXidl&7RNso^yV4RuV$+bDI3KdVdjs zbUH0&W@bdWTz(-5ZO?N!lgWs0zfCedeVOIuWkj(;1j2vy1FWo$s{u~Gb}DH;;Ge8@82ghKaY~jQ3H&2Bw=9N$Oye}y+zO4Zxb0FMo|>$ zxdF=Mvbb^M2FYZSyLazm>N>8QH}PdMc<u>Q!_=1)6?852H~UJv~H{Ne(P6K^qF74E(1J_Ag-dgAcH~-5VmVR;wfu z2_`2er42J=v!Do1Oj{?kFzo~gpgZ}lNlc7dZofI=I7aW zvK}x z6yy3hN7s%Lc84(xgKD)(ypF&EU>F90K!EP2qgXpqb0 zC>AX)UVIl#^8;7Vv;vwI1Yl@rXlnpjmQgAS*ntuh`~@Bb9?@6qqheLKu_5C~8zmC!VeLZN`BX_%(q!i7Ijsq_GUL6)zgst?ii2&Iz3zF+R!R3{w^hr{fs z?|?PnL2GZWe-0r87sD6%YS&kM$(MXu_!J=oilPt<1~Ci+P16uUFhBnWmC6Wk8(IDb zJ9p0F@uYCOEA;l7#D-#919-jL@fu#J13$D>_~KVzpes6tZh!|^1-Gr$G3%?*Xdr~3 zS`9Kc_XbczQU1umgK6UNeiS9j?%gmx-n;2)-T)8?_^=o4;0NvjnbwI*(k1H6I<#+X zwW)3b09ac3HJ0TD&ePwY$KmjB<;p18?7Pg*k25k7e{8G%m;#>1yjwb zc8}445JF&CR_E@pELd2WXh%QI_U#V7`Q`|kHVC9}yRR`a65Rx_p$NBkb+ta2fCD@k z50&K#T9?L(w$j>f16Y=YEXy4Q3WeR&>jB_zba&@@^eBU2^Z;60U7bWC@ni*p!62%p zLKE=Az;^?%0`x`aLuIps8ab&p${F`8~iK46^%PUBd4M;FL8pP#t zNlye&6h#_z4z>V%u&cNW&yoj1fZj?6%^wx8EDOUhFin$m+JR*?fi&T;PItG1V9zO&u|@HhNeb_<}>g0frzR&hEF za=C79-W&sb^z{6Rk3W8oLx&DMb~4(efU2s}hrjz!`sBzbc-^fxeRMh68VIb`QY@vT zz}nhcJ0-KgGHYu#u3g)UVKfMb|IYdIr#NzCV#~2?%c(e#NJytopJrfSfcWirD|(~d zB(k|71ps}0w^5W8EDKS=+{B;I011*UEQJ~Ri zU|AMkZ-K6^i#Qx9UVXKTsi}{MM0P)QLVoI0yl!*zb7JzJlT`0jd2`#Fxb1EfMd9JY zhosYKOw;7Sg9jWwe3&z5&Y-I5GmYoZ3;>{MnmBv*Ea`L_S(cGynS1x{k3v)jE;^zxAPYQ0I1jNqEIN%+uQqpIe%e*pThnN3zbN{>Y)K>0000bbVXQnWMOn= zI%9HWVRU5xGB7bTEip1JF*8&$GdeIiIx#XWFgQ9eFmVjmB>(^bC3HntbYx+4Wjbwd xWNBu305UK!F)c7OEio`uF)}(bF*-0bEigAaFffPyJZAs^002ovPDHLkV1hJDb{GHv literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/tbrn2c08.png b/tests/pngsuite/primary_check/tbrn2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..bbe748fd32d611cece365935600b1cbc400ae247 GIT binary patch literal 1901 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 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 zcmV--2Z;EIP)%G*ochBz3{Q9u#ja*|cB~p&`lXidl&7RNso^yV4RuV$+bDI3KdVdjs zbUH0&W@bdWTz(-5ZO?N!lgWs0zfCedeVOIuWkj(;1j2vy1FWo$s{u~Gb}DH;;Ge8@82ghKaY~jQ3H&2Bw=9N$Oye}y+zO4Zxb0FMo|>$ zxdF=Mvbb^M2FYZSyLazm>N>8QH}PdMc<u>Q!_=1)6?852H~UJv~H{Ne(P6K^qF74E(1J_Ag-dgAcH~-5VmVR;wfu z2_`2er42J=v!Do1Oj{?kFzo~gpgZ}lNlc7dZofI=I7aW zvK}x z6yy3hN7s%Lc84(xgKD)(ypF&EU>F90K!EP2qgXpqb0 zC>AX)UVIl#^8;7Vv;vwI1Yl@rXlnpjmQgAS*ntuh`~@Bb9?@6qqheLKu_5C~8zmC!VeLZN`BX_%(q!i7Ijsq_GUL6)zgst?ii2&Iz3zF+R!R3{w^hr{fs z?|?PnL2GZWe-0r87sD6%YS&kM$(MXu_!J=oilPt<1~Ci+P16uUFhBnWmC6Wk8(IDb zJ9p0F@uYCOEA;l7#D-#919-jL@fu#J13$D>_~KVzpes6tZh!|^1-Gr$G3%?*Xdr~3 zS`9Kc_XbczQU1umgK6UNeiS9j?%gmx-n;2)-T)8?_^=o4;0NvjnbwI*(k1H6I<#+X zwW)3b09ac3HJ0TD&ePwY$KmjB<;p18?7Pg*k25k7e{8G%m;#>1yjwb zc8}445JF&CR_E@pELd2WXh%QI_U#V7`Q`|kHVC9}yRR`a65Rx_p$NBkb+ta2fCD@k z50&K#T9?L(w$j>f16Y=YEXy4Q3WeR&>jB_zba&@@^eBU2^Z;60U7bWC@ni*p!62%p zLKE=Az;^?%0`x`aLuIps8ab&p${F`8~iK46^%PUBd4M;FL8pP#t zNlye&6h#_z4z>V%u&cNW&yoj1fZj?6%^wx8EDOUhFin$m+JR*?fi&T;PItG1V9zO&u|@HhNeb_<}>g0frzR&hEF za=C79-W&sb^z{6Rk3W8oLx&DMb~4(efU2s}hrjz!`sBzbc-^fxeRMh68VIb`QY@vT zz}nhcJ0-KgGHYu#u3g)UVKfMb|IYdIr#NzCV#~2?%c(e#NJytopJrfSfcWirD|(~d zB(k|71ps}0w^5W8EDKS=+{B;I011*UEQJ~Ri zU|AMkZ-K6^i#Qx9UVXKTsi}{MM0P)QLVoI0yl!*zb7JzJlT`0jd2`#Fxb1EfMd9JY zhosYKOw;7Sg9jWwe3&z5&Y-I5GmYoZ3;>{MnmBv*Ea`L_S(cGynS1x{k3v)jE;^zxAPYQ0I1jNqEIN%+uQqpIe%e*pThnN3zbN{>Y)K>0000bbVXQnWMOn= zI%9HWVRU5xGB7bTEip1JF*8&$GdeIiIx#XWFgQ9eFmVjmB>(^bC3HntbYx+4Wjbwd xWNBu305UK!F)c7OEio`uF)}(bF*-0bEigAaFffPyJZAs^002ovPDHLkV1myucDn!o literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/tm3n3p02.png b/tests/pngsuite/primary_check/tm3n3p02.png new file mode 100644 index 0000000000000000000000000000000000000000..babdebefb5f83c6d969414485fe31d9a3b8486b3 GIT binary patch literal 306 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 literal 0 HcmV?d00001 diff --git a/tests/pngsuite/primary_check/tp0n3p08.png b/tests/pngsuite/primary_check/tp0n3p08.png new file mode 100644 index 0000000000000000000000000000000000000000..e5a29d6d627bee342ee10dfc9140169e96a05163 GIT binary patch literal 1959 zcmV;Y2Uz%tP)r| z0M6{t%uG}ytJi7LDy?d@s!}gnX#%Q=N?Z&D2@M1nfD%x|1rn59pn`;i)=pE46e^T9 zTA3oDsDwdNldOhdAT%F1{%9Q%+d0R_=iP;kS(XqQF4jjnvR}*Zd4A{re4OVs96EGJ z@DrN!Q#uDQKJUgIJ9aQJF+ngG+qNYG7@m~_ZEbBtA`z}#yT-kH_ps-3m>xW!CK^RfCdmO>SxPUktf`6BZ@UF>BHX=um!hIjH8_Yf9>*~}%rYPgq=8wNi+p`O-wh8} z_HR}coMtoe_uixN<(CPCLIi_BIy*b(0aS8e|Ni|%A`v2y2uF?_p;#nQ3Oe{+hwTL1bCR@Anf725D+) z;^fJba{-2ihUo6@CZEqEgg}xc)<&aj7#>CeOhCcqV$|>F?y6O+i$rK18Nm-Yl1WG= znFhWugM9@oTkgSZu>c^1V0d_#fq?-wZQ3+n0k_+W*=(k&stQfh$mjDU*R8{M=MKW{ z=2j@gWMd;jD&=iF5a64c8GaUxvhnIwRv3-gfvl#HSi2Tpd=abNUU8%-3aM0zTrP*- z?`M2`d@g{)VM7Rkq9_#@x`okUt%h_tjUm|zl6EEY+n zQcO=zQz#VBG>t$YKyPpFTmYxjiK?r7T>CLGM~tu%=B?Sc@Y=j+nnpI8C7;hfv#f*= zmCvcEDbndQilU%t8k(lzcDp%!`tJu(FFOYNQsHv&J=krlr zU0o{4behr8QL@=QJw1OWli31%izHpgVz~vVJbEOv@#h<#4&e2AS)N}Gv%q)d@~j_1 z2*G9VWxibbC13Cb=hEj8LLkdB9*+l2)5v5p2qB0@-(+T{3Al|U{gV|dZeX{^u-Rr< zy}C%SG5B-&}(gDGQz0^ov%ZyR6|sE1e~ z20EaDQ+8II>$;AjC?pagBq;~{3y-IOEKedylNby}U=y1+dpLIN*x~>k9UZK?3xl0hCfWC_GU>*L5^aqgX65HfBNB3&0p&uR>j&1&^l+A$|*dLpZ#Fg>2qL zwBEPA5_H1qQLCzY&j%1fQQV^8W|Ya zfTpQ0;;N_>pBicn%dgSSS&GKeYKXp zzCD~je~xF_Gsp6djt-*HD4+fMGg{-VG-sL#C;^JaVg*15!Sdx!>gp`)-rYiXcRL?^ zaN?QHVF?G5PyhZYpYQ&hix)34Ha3P{(z;Rw27`gNwl=nI-Aa3V`;Wct(hepkPMl!- z_U(kj;Yt%yRTYE5!29p-(^bC3HntbYx+4WjbwdWNBu3 t05UK!F)c7OEio`uF)}(bF*-0bEigAaFffPyJZAs^002ovPDHLkV1m3UeQ^K) 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 zcmV--2Z;EIP)%G*ochBz3{Q9u#ja*|cB~p&`lXidl&7RNso^yV4RuV$+bDI3KdVdjs zbUH0&W@bdWTz(-5ZO?N!lgWs0zfCedeVOIuWkj(;1j2vy1FWo$s{u~Gb}DH;;Ge8@82ghKaY~jQ3H&2Bw=9N$Oye}y+zO4Zxb0FMo|>$ zxdF=Mvbb^M2FYZSyLazm>N>8QH}PdMc<u>Q!_=1)6?852H~UJv~H{Ne(P6K^qF74E(1J_Ag-dgAcH~-5VmVR;wfu z2_`2er42J=v!Do1Oj{?kFzo~gpgZ}lNlc7dZofI=I7aW zvK}x z6yy3hN7s%Lc84(xgKD)(ypF&EU>F90K!EP2qgXpqb0 zC>AX)UVIl#^8;7Vv;vwI1Yl@rXlnpjmQgAS*ntuh`~@Bb9?@6qqheLKu_5C~8zmC!VeLZN`BX_%(q!i7Ijsq_GUL6)zgst?ii2&Iz3zF+R!R3{w^hr{fs z?|?PnL2GZWe-0r87sD6%YS&kM$(MXu_!J=oilPt<1~Ci+P16uUFhBnWmC6Wk8(IDb zJ9p0F@uYCOEA;l7#D-#919-jL@fu#J13$D>_~KVzpes6tZh!|^1-Gr$G3%?*Xdr~3 zS`9Kc_XbczQU1umgK6UNeiS9j?%gmx-n;2)-T)8?_^=o4;0NvjnbwI*(k1H6I<#+X zwW)3b09ac3HJ0TD&ePwY$KmjB<;p18?7Pg*k25k7e{8G%m;#>1yjwb zc8}445JF&CR_E@pELd2WXh%QI_U#V7`Q`|kHVC9}yRR`a65Rx_p$NBkb+ta2fCD@k z50&K#T9?L(w$j>f16Y=YEXy4Q3WeR&>jB_zba&@@^eBU2^Z;60U7bWC@ni*p!62%p zLKE=Az;^?%0`x`aLuIps8ab&p${F`8~iK46^%PUBd4M;FL8pP#t zNlye&6h#_z4z>V%u&cNW&yoj1fZj?6%^wx8EDOUhFin$m+JR*?fi&T;PItG1V9zO&u|@HhNeb_<}>g0frzR&hEF za=C79-W&sb^z{6Rk3W8oLx&DMb~4(efU2s}hrjz!`sBzbc-^fxeRMh68VIb`QY@vT zz}nhcJ0-KgGHYu#u3g)UVKfMb|IYdIr#NzCV#~2?%c(e#NJytopJrfSfcWirD|(~d zB(k|71ps}0w^5W8EDKS=+{B;I011*UEQJ~Ri zU|AMkZ-K6^i#Qx9UVXKTsi}{MM0P)QLVoI0yl!*zb7JzJlT`0jd2`#Fxb1EfMd9JY zhosYKOw;7Sg9jWwe3&z5&Y-I5GmYoZ3;>{MnmBv*Ea`L_S(cGynS1x{k3v)jE;^zxAPYQ0I1jNqEIN%+uQqpIe%e*pThnN3zbN{>Y)K>0000bbVXQnWMOn= zI%9HWVRU5xGB7bTEip1JF*8&$GdeIiIx#XWFgQ9eFmVjmB>(^bC3HntbYx+4Wjbwd xWNBu305UK!F)c7OEio`uF)}(bF*-0bEigAaFffPyJZAs^002ovPDHLkV1jhUc%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!ia0vp^3LwnE1|*BCs=fdzmUKs7M+SzC{oH>NS%G}U;vjb? zhIQv;UV>C6dj$D1FjT2AFf_CjA5L~c#`DCET22U5qkch)aFYV-NFc4t5AgJ@`fBl-5Nx~maZQOnHuo_33xy9zG zO_LZ?7}9O4-%rWkQC^n9Vy9{3u!`}Vg^Y#LzXQGOAs>#-W&TrmoOes%a^5e6?Oexp z6gF7qNi?)c_fF`O?wQc89e&`rDD#PerMxE!TY1+!>=s?~n47Vr;33!629nO4bQ qXlZGoYha>lU>ag%WMyD#WeU__4%D#az+nZT1_n=8KbLh*2~7Z8tc<<@ 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!ia0vp^3LwnE1|*BCs=fdzmUKs7M+SzC{oH>NS%G}U;vjb? zhIQv;UV>C6dj$D1FjT2AFf_CjA5L~c#`DCET22U5qkch)aFYV-NFc4t5AgJ@`fBl-5Nx~maZQOnHuo_33xy9zG zO_LZ?7}9O4-%rWkQC^n9Vy9{3u!`}Vg^Y#LzXQGOAs>#-W&TrmoOes%a^5e6?Oexp z6gF7qNi?)c_fF`O?wQc89e&`rDD#PerMxE!TY1+!>=s?~n47Vr;33!629nO4bQ qXlZGoYha>lU>ag%WMyD#WeU__4%D#az+nZT1_n=8KbLh*2~7Z8tc<<@ 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!ia0vp^3LwnE1|*BCs=fdzmUKs7M+SzC{oH>NS%G}U;vjb? zhIQv;UV>C6dj$D1FjT2AFf_CjA5L~c#`DCET22U5qkch)aFYV-NFc4t5AgJ@`fBl-5Nx~maZQOnHuo_33xy9zG zO_LZ?7}9O4-%rWkQC^n9Vy9{3u!`}Vg^Y#LzXQGOAs>#-W&TrmoOes%a^5e6?Oexp z6gF7qNi?)c_fF`O?wQc89e&`rDD#PerMxE!TY1+!>=s?~n47Vr;33!629nO4bQ qXlZGoYha>lU>ag%WMyD#WeU__4%D#az+nZT1_n=8KbLh*2~7Z8tc<<@ 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!ia0vp^3LwnE1|*BCs=fdzmUKs7M+SzC{oH>NS%G}U;vjb? zhIQv;UV>C6dj$D1FjT2AFf_CjA5L~c#`DCET22U5qkch)aFYV-NFc4t5AgJ@`fBl-5Nx~maZQOnHuo_33xy9zG zO_LZ?7}9O4-%rWkQC^n9Vy9{3u!`}Vg^Y#LzXQGOAs>#-W&TrmoOes%a^5e6?Oexp z6gF7qNi?)c_fF`O?wQc89e&`rDD#PerMxE!TY1+!>=s?~n47Vr;33!629nO4bQ qXlZGoYha>lU>ag%WMyD#WeQ}Q12tS1_$CF^z~JfX=d#Wzp$Pz2HjH2Z 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 zcmV004R>004l5008;`004mK004C`008P>0026e000+ooVrmw000Gb zNkl1!`#jIX%gn1pggd$P9Zd(E8@>1o|NOaq`y>7F!|ZsTJzwK126G#Ly6%XM z@b-^5>QWhU%dqD1!_57RBTumVe+8~Hq9eTb8gGRJAwh?*OV}a2z_~^C|CZMU`+s$C zf=f^GMjIPqJ*EzYFsfNGT)Lap?PPm7_!7VJ=-g%pukx;sAJU$c-=j0zF+ofa5q!)a ze#6rhquT+FvGf6bpLReH((V#=343&VbR#+uVMHe)7;@qr4%Ccq1-RxEz0QX|?KUbv zg-D3?a5PfW@#w_lF{X>|p$bm?jc2~d`wI6~f#a;6WITuOqXKjXI#{2ULDi%_otUzR z>7gTt5je5J^Sd~Dle2ye@C#0R_#V2AZlgm~2OH2hsG43tH)a~4d#D*O2R?ta&G)tW z>8Ar@roZFTCSclIO*Ag1ArI+AG!Z7+1hzr17QOyU)Mwc7+NS`==$DuP*T?vqO>|IQ ztcPnUI`m>BLib<}*@i@om~~+l){c| zVM7=SBVi=G`3mjN^Uzb*0scX@ir!A!MZ4%0+DG}A03D)xh@t5bN9Y)dtvG|t!e{A2 zVJr-VH(rqM{a!t^`;)+*NnHXL-9oj{tt~?bm>$Z7h&)1VrgJrYXc=0@ma%1G8KuoD z&+_AUoChDj1~`crIu6P~xu_ZAq5Z4pRfm`!Wn^(jTpi2MGMYsT(bw1_m z-{DWcW?RoW2Sx1%q6`?p5#3d|Bp`vxK|FMT+rjJ7PN`Fx6q_I^ zHsSO@o_kdt`-!tWMURz18H)xjXp0u5EYvg!dKD%@(vVc71xZelk*1^>Sw>ormt<42 zhFmB#g+t{FiXi4}-?><#$4U#@DlI4r4PvoVssT2+X;jvbP04Gr zio7B#DN2fhGApO!Ash15FNBNxItO+uXX|?4s1n(L1}xIhR7?x<%j`IhKSXD!3`rZZ zhRl*T6jO>R>MU|4RaMv=y0F$9} zR4$TPn>VItC~Z@fNxj~;XU>`>Z{Pj*Eq?Q{1ADY{!yAorm%^@LYwChBA?vgK9NhuV zEWJQVYm2(9vPpCPqMTgf?}Pc|ffx6F>Cg}2g?nz4y9M0qW3N!>6l2^z@iOrMH$#`G zQl@pW(kx$*<@%1VVyS645OM(au{s2+Lb!Cm*v-(Kz~fjhVU4fw3PM64Z& QC;$Ke07*qoM6N<$g6Hha`2YX_ 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 zcmWkudo+{@9Q~wiYbxpxyQH*PvQk+jg_3M0kMUetMjk0^ibC6FT8+ng>|mu<;>-?$ zm5gBE76za z`V2rL-V2)_s6XvdI|05qg3CyUFdEKU;xM`LGPZ>qA>#tN;_w)^vQv<0j}{EP(no$i z`mo0!AQSgK>Bh#O1Uo1c%9qgC08SDbT*Rc~7NA^cjuaHHr)sr@p!{AFnbKlF+h0Dke2lZ=BJFa3_1Pd-&6R(7q2>7?e`@` z2+zSi67nJu@aa}f)U3dTH8`j}NbZC|_wRhnwqpDkdIZnq^Mw#AAXh1rk|hC1a$`e# zV-YlQO+>2x#2+~ArqX?p(+hMM6oVzgAuTW+d5|lVcJnG(%P3BD)?#ZSHf%!Zby(CP zbrt$P!C~!psuiF|p!y)PNs5DXbQ*5lJ!*k+RpmZhEtn@Gs0a|;pZ zu~mOaE5qA45~jygEACV%-f(amkFH*arp)TM<_{!(td=Z&Rf=QC&qd6qVjPAfD<3nC zh_J^_V+ezxPwstYijw1t$B&EU&4{COWt zVR8e2Z{dXU?a)tyb#R1Iirg-^pTWKhiHJp<1{^AoqaTColG2eP?A-^hB^piMsr0bp zJVwAA0PXX=m^&{c!SpeNZ7$J;AsYN{&O*xN0eV#q7~bv=)=g+*8hLJE5TG$3=Ore@ zlDBF%NJ@Yi>YMI%3XnaBS#bVnhFOQ!p^C+C=TZ+i`hL#|-?g9Ev8Jly(eTN>(I6qk zs-@Z6yPEsqewkrTVN==Wzva^UFWypuE-|9M5ejGMwBbk&+nr}rsz)C=6Mg;7!p`W{ z*3~{qezB>k(KS802c-H%MJtOML$`!vXDrv4dA&B^?EA>Laq)wJ`AA9-`)?bXpnYtZ z**8#nC9r6}lYe*V7X^NmwdatS!q&aTv2GK}t$pbuI?lXOqlte1o8O&f1YZsfs{L&1 zZoz%=oa51tY^i+zB#M=_j$sXzMB?(7N*Xj(?)<=@b}om6+jNTRdt1f!@iLHfQk z`Im$Q_8Q769>r)~P>^hRDA_iy_5h*$Kk5ptj>x+)kf| zUCti|wcqQxc@1b(iexLF45xdH9&YI{Rtz*|(b+mwZY$GfOU5Nji;Hn)EvInIyw&H6VI7pV{6m$_g05>{kkUx-_69w3hFaYQorBj zDX_=;D|R(DV{iZR3fwcX5XUT6UNQ*_n^{<5*q_TfRA5^dnUj}yFa2X1o3rN@lnb*< z!|vRg*cA5kc1HTa*M$`o>FG@i|HPJ@sFVg?HagxLeoW@3zx4@sz5b)(>a_fdH;*5O z)i?OfjnGg^KQwW7n2!*3?6#5{%QaA_=g+OQ^R1n-BcAPeo8I7%7X;;=;1%j1i zZ)bCl8v&97rVft|P_iC!Ccs>)Nfzav-)4vs=ljCt>^(xPQBFB!f~}2 z33c`L-70SCvR3s|4U=$oHH9TFzjO1%!~RfY+0z-VM(^3 zbZpsM^d4*^09(kX9^w*ZmI5XJmB^)Ql!H<7e6ZY) zc`+QeUEqwtD6lI*MoSDvI5{}WC480&PtuOH*-2AVaV?E<`JCD_tpv-j#9PIaBFEN! ya5NvsJwe(+v{{WEX}38N*-?K$b^NQk+{YgmGj*nOAn>;U0000d_tM6?Z=$-SxY}-ICRK&4y|1 zVwc#f!dHA1xV88oBj*}@g$RWy_hMZ-KIm-D*-?;qSET3(i^4(8Km2Jkn4dfq@Se&3 zTKj@moXkY~bFu#0PPnZ(e1e0$_)enlnWhXC=IqbUUkI-WEMadnm^fjTNZTC0CDs-P zO1_Hd{`ll}k%^K0x`I<0XS2iy+u$b!SFTK5^fGI1n`4Un+K*`hy-NEv><+L^T&{2S kcJ9aK_IoSqvM<+joQ+wPvG4a1ptl)3UHx3vIVCg!05sc)VE_OC 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!ia0vp^93afW1SGw4HSYi^mUKs7M+U~W1%@xC#RK`w#ZI0f zEG#VLKejFgaybh;B8!1EBN+Ru9=Qf&RC~HOhE&XPJr~G($U(&AVsKMqdZO+XCv8UV z2nJ4tMy~^h!kDxdYA>9+p~j^3=S&}?ojYTl4JO=Jai&15=FGw*d!IX*;+1!`qwm#r zn`WQ%3^IuS{KD+pZL<&+b@wcnUV-Cw0nJZSYySkqa&Hnkl_)Oke>c9oU4*NKQEP+# V1@X9R>wwN+@O1TaS?83{1OP3BOWptg 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 zcmV;_0xSKAP)9p$>iIc zM9BG}R?-GyZPG$D`^%XGf`^qAr06IYS+9p{fK&k*ZoATR1wD8|WCM=~607$j`vY7L zV8zwkB3t?J3uaPidN3!<*KK9Z0BA!^-Kg`Xnb*QIyQ{+A355#ayA z0cpp|nK|8N%npZU=nH)H(bhrG@~;!&M3?XV2(`}^e@baTp03|x0oH!)@bHo=j4KQ0 zuY|$dbUuo5Y|+T(H30UBc@<4A(dF}I3{b5$!14M1g8c&!K-bPLY`YQw0000Vz>816FsF9(VN75txh7sS~8e>Vez z3y|esg8)MVP)qc0!95k9*}y}5sLX|@B3D-GMbkBlwnNjonHwIy z9EcJJF%{78L==oIJhA+`7;;cFolQHd7RYGxEQK6edY*pw@2LCip7ZW~-{<*#JkP!5 zYYTEB!lT29C?YRceiiRU!SD1?JmuDki+F_~O=B_)K_Hn((}+hbb3KVH`hCQ#8wM+c zbFwxPsNG;gO(S62+sIEOu%KnpUADK`#I{M2L=HJ6NYwOv+-H@D_X=#9?oI+MS;V>y zl^XVO2yC09!Icb&nREm`f)AWc25B~!P{MT$qI?}Geug!qSF%UJX^=e(A@Tsq&y_e(IV5N zc2ombmUg;9iHZVhFq;*ili#)pv6lr^Wf$(E5sCtE*M(vW0)!C2(rmO95VCxjCB6Yo zimt;CGRgER#Fo_!>WATkX^@enQK3N$>j4Nhm?Bc~Cc@4FTut;EC7;Rd?q$9UQBAH#yE#JE|Q0|h>!DU_)gvGGGRzl1C&lfZjR|WWg|k-fq8#JmDTaBI#^STUG9+W$DsWo438O zx%khhimTsDdcDtYX^8l8`@k~2aals#tw5h$TvR^EzC~aJtyXxM{*Nd)reoq~rm{KwpXnEYf zqB*0lzd&-2CvWIFQhLa@dP&k(Dd*Pij(dA}O2xf7|D4KEZ$_?Z8(4n($A+lx;)H8u z)fq!W+gl8UebBY<#K*_xetq?5tDJr_srucF zRWSz=YaUiV+I4>B_%&@-PtL)FX`y5J^WLm!j19!cj=uCt?f&G4P0QquI_{@U+1wXV|N8?-P52vntW^|UZqc(l!@kKG^x7(XjPW24#8yrdL)E4&VZN1_vo8296 zO!#K>^qsN&VVBEKXIzkd_mj&@tKO3RzQo4)w=OTPI2+x=IZaHg(y>8-4$mKjGb gSyRUo_cYqm_AGEC_tp3R7W~7>%Px>RvflahUvG13wg3PC 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!ia0vp^3Lwk^Bp4a_!xt_BxxKPq}K;y)F)+dv$%Po8B#%=u~U{}NXebp5O&tsV_+x6KC z`n6Ov-e|q7d~>yV!S#P~w_ZMf;qcvgkAe_q@|8lddEI`uLzP=J4Gp*J^)`wY2|W3b o#w`BCU_;}R^bC!qjU|5>nikk@kH_`o5%P%0-tcHxz2242t zZVAjc7P#3?WtxA)Gw_j&*7KvKZ>J=PsTO88@_NksIICmj$1M%HOyBFza{Sr);QoBh zi@mlwB0JLF_+GF!ImvlsMh zsc5{>dRh7AYV(5Y|Kx7HeE!1WyYn6eA`4jdmiWEU!L;8G5Gbb{58QQCkh zC%`R%`Nje_+o??Rk9Y_%RXc^_wWto*p8A(!cU{aKDbTOZt? z&v~)eR!3w<+8cjwuIKCvE|l~g&^Ym)^~t2`a?9Sjaa+F#*wwIpUv)*n^H^rfc767O zek~P^H(D<%-&}28aQ&a$t(VVVIDB{BqaehYe5FuqUbo-vP~{d)L&NQQy^W$p0#81q oF^fMj*wFYSJwsz@W656zxtoVvfBf&v2KtG?)78&qol`;+0Fu^nQ~&?~ 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!ia0vp^3Lq@N1SHpV7(M_}Ea{HEjtq=#3k+XOiwE+Vi=8|} zczJm*nD-t8a_c-@978JRyq$iK_lN@rGdt(YQy#z8YiT}?Tf!kXZS7nxn;(ocNRJS_ct9{9$oSsu1^4G$9qOxF^ITqWf!_v|1&zuJmL90#Z}{$h z;X$oW3rB}@4oBt#ju#pq{&7g{v2S8~pRDBMFgMZFh1uQVB)dVdT4qdrSvt@q44$rj JF6*2UngG#&N@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!ia0vp^3LwnE3?yBabR7dyEa{HEjtq=#3k+XOiwE+Vi=8|} zn3vvNsN)kh^hn zQh3OQxBHhXtGq91lkmGBUgcb!!F~1uvkcz_zD4pSt$G)@WaeGq$X&o%(w=ugNaorF hmc0uYt(@e4Fe^D2KP>;UP7P=dgQu&X%Q~loCIF6>U!?#5 literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/cs5n2c08.png b/tests/pngsuite/unused/cs5n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..40f947c33e477af3d4c13e3a56efcf32e6871be2 GIT binary patch literal 186 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1SJ1Ryj={WSkfJR9T^zg78t&m77yez7dv@| zu(GmBsNHi0a+5q=978JRyq&sHu)%@n@Dyu(NA}wKUA0-b10Ep zFS_6slkGtcsjSnkCm!EZ->w_6&B5QGsqfG`#!m_?Kf_rn1^#&$H05(u3N+bpIQ|n& cya`qx_w<}dzJS2a44`ccp00i_>zopr06uR!@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!ia0vp^3LwnE3?yBabR7dyEa{HEjtq=#3k+XOiwE+Vi=8|} zSXo&m)b2S0xd{P2A+G-=8Jzwz9R1J0@V}bj|6Ydw{~3U6Ab;uq|M!3d14Huv|8p1^ z6#xH^0;;k4Zv_-!cm`I*@IOisq;U=dQ0cS(K&=cd|AA%zO#~X&0+Nz+*Khp_w9DJm z#WAE}PU}Hd#sdrt4F>Ptz55$&$0R-3;cHXa2ac?Rsv0cq2_h{`K_9r-92Fv1Rz46e wX^Ir!40F`E!P1!^p3)Rkz@>FiH{%HZu|hk>x7R-I1{%xY>FVdQ&MBb@0QH?@PXGV_ literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/cs8n2c08.png b/tests/pngsuite/unused/cs8n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..8e01d3294ff71ea83918aa7f99589c7f88da81c4 GIT binary patch literal 149 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1SJ1Ryj={WSkfJR9T^zg78t&m77yh6c)B=- zRLpsM)sdIMfX69t)`R5F>$8F{b!Pm_R9NudWu=&O_QeBy0tqv+c5v)_Q~Q&J!@#%m wUE>4C4G-c4A22Uq;csH)Zz^SCk$A@V`i@Ax+rlTSfaWrIy85}Sb4q9e0Oq;wP*-)CT0@c;jQ z2B6XdAldyud4`1l|LYkT9R35fGAR598n(G{b288_Z%-G;kcv622U!^p0CgC=d-v{d zv>lW5Rt15YCienPzJp3LSeh3I<}^i2;MQ`~516SSqSE9Pz!h~+uY+af0^y#f$PHY6 d2X!ls@@qb_WBltft&4Aruj!a10Ts~ zJwICdc1nVnYGHOGugAQPvpQCO+|rQC^u7Kp$Dgea?$77E*lVjJvLo${zc<%&_5~M8 z`VMHEc+dJ|(sj9IZ{4`9Uj*!GSii5jqTqQfvt_$JdqKaJipCqQmz8g>HZQpTPwv*s z=Pw+-JMU2t;!M6$C^oO#?{=tii>9IBcD>$4(ISB-AJUk`pBQXte3G7_v9z(|FN568 VL#{vmcV>h9>gnp|vd$@?2>`oyZOi}w literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/ct1n0g04.png b/tests/pngsuite/unused/ct1n0g04.png new file mode 100644 index 0000000000000000000000000000000000000000..3ba110aa764ff4e5ee642b7c0788229a4924d383 GIT binary patch literal 792 zcmYL_OH30%7{`}afYlm95ECCT0X3y5D?Mmv3<;G|C`zfeL@oq|?R0nSc4yh0QW_6Z zB`Pss;_F}x)Pp8ol!HcNj8URV4;m%W;Nzf@CWQndoG|e@TZkTZXTJH*|M$)JANBiM zE&Mi~<2Z}A&3%-u!2Al?kGu3WUCWk2$<^WF^3J3j^H+OWy@|GT(;%h_;{2)(`~)QFCN!|B{t=iEQyFKl3pA11?%3{l4##YE*?fOXKY0?i7L zFo3{7)ZE}Gl#l^L9YKmhfD%BFK>?K!KL~Y9VoW0n(d%eJWA~VYNr1%#!bFckDgdu4 zDzOmrLLKq_3KS!I;xY@vzGk!o4JwE-xE;hXl>t;V83H!9sv>3WjHfzO4UGX*F|iId z1mIE>(2r?d2x(L{m{B2dvyUheJ;X-m&DXNm7#b4I?m*L#fmAAVlv*Mz2B#TAfP`tB ziCpvgh%5jIe5gBU(6u;n^MRPbh@e_iqm*c>R4p7Y3ndt&JeMUlL>pcHB)>|a4ucs$lG3@ulPNE1@BXy#w+=g z&%HGh>bR@`vHY&O>~* zIQ52(KeeX66=g2YR^D3jY&bCQe>8me$%!E?+f(2?ySG@oVB2L~v@IkS-pGsyV*?Kcce{q!`rdz)M R88w6Bye&TWor8U+{sI?(Ab 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 zcmZXRO=uHA6vrnJKT;a(wL;~!h$N6MrYd;wkTqLtKw~wL_E6C2W|AE`J2UJ|4DsMW zRM3MWg?cGs!J~Lk1VIoBT0AKzdTK$zg5c4M2SMLvLo0aLnfLj7^Zt8tx;m8|*gHT7 z$yQE!=kSL3OXEQnzrM}mm2SDGU6Q)-p!j|10{X+eK5OgT3Wg4oBr&IDtJdb0eR}j} zAI6WyMQ+;$DoU#Q_6!$-g>Z>VsQCfq3y|ydLM7949bbj{$r*TvU2e=ME8UHFE3gS> z+ugF@KV|{SRMG~8iG#)BhaZPl2}upcFpn8O;@Wa06WqT67jU-bg2ri3O`u?yjSU{s z7Bk>Sj9S(JtH3g2!3GQ$iMVQGP6-u_+pfks?1)n+Ei_dWQtLoP`l8*yUK%l&7t~)k z&zCi*cOQE4;+q~Gm>jRUR_FwgCHgJ~NWY!s>! z&+&Z~HMnf`UW>0Wn)$uyI%0-N>s&dK^-zSVSeKe=+76NvQMSBte_@n^LY2+djZMVq zZ3}G^^T)Idtu?rFVds1`b3(7;*|Nq{$ee}L~xhLtN m^^F(rmq*W#)$5mU+Z5S&`t$7h&xh|JmsBRJ-s9sJul@x+i~KYI literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/ctfn0g04.png b/tests/pngsuite/unused/ctfn0g04.png new file mode 100644 index 0000000000000000000000000000000000000000..353873ebbd0ca66c57ec7f6488e8f18a1c3517ac GIT binary patch literal 716 zcmZXRL1+^}6ow}dghq?tNtEi?QzFS~JO~9rW1}X-)@p**gXox@CNDF)v+m4n$W41t z#Dj>S9;8}`R}Y>7A|4{OAV@F0t5^`c)r&$!-zHWNVP}W8^WOLG|Ih82=~JVrT`5Ay zXt`88hdYf|5?|#0$K?!e$wpzSKoU2f=D$3+jP-7)&6*k*$+4INa>i&7LXjE2QMF+B zx4p|{Jei2w3f44LIP9x&0j++QTmUJ#M6jjrPF;DKsTYq{ajXKnB>NAH%plenk*N$M+~b-foIWHJh@4$U`PV!RWLc-i8>vZ zYmJf~ieQMENeRYSMs>jJvF4}ickq$@uJ-#~=k4KZ7t!O<*mhOTnKlbIZ?4%wub_=G zpi=KsN5hy&~?ec@1Ie>$uaZM$zGZ32aTXT=*4DPUBk9b(-q_gZk&Rz>KfHfjULdK5 zH;yEd?bZG3$(5cvLVGXUPbMZ8$oxB!=x!zCN4Q?tvGV2>GD-Qwbn*G|EAzhrgC78w 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 zcma)5T}V@57(R*-XciSoc=e?OF6PLfpo_retRxc2LEc1;b=(f_kL{>MM01;(Fe5Xf zEW;>*KsS#z?6{55l|t}-Nl;fsffq#=K@ibZJ>R!Yx(T}2`Tn23_uY6`=gHdY`f5c{ zYCBFj&SGTZSA~x<^=Zw5p~_=FV^=ChXInnsxgZWTXOHgGbf1ca>Qm?mrFnv~RNyhC zE8yuK&~%lJwVF6SA@14-bZ;Su$l0PA*pU0OeD z8j@SB5xKOvgMQ1~14sIRF)k3>f}zV{&EwTeptF>x41jZhOOQz`G{@+It7 zq5r*E79uniV^~U#1TBk;1#FwRoMJp7F=Q|ZpC|cn5p+yWa&RSYG-H^6B1xDi66P=rqhKk9 zjX zV6q@FSka1Dl36}0OPELY;915{wj$|8Qs^d#OUh)SAWLbaQD~L|kr3iUf+qY8(>!LG zl3p2k4w1mJU>90&RA7;i>J~Lfi+y;)8$&u0PT|J(^txqlxhuPaefp3qT>e|!m(?|S z9B{IR3f=xk*}xVT_Dc=084&AKdz=y7C3;Hc2G?;}%>tAlWaKC_M-~mCfL{-W0-gq2 z+oe}uA*xMwr517fT$*1k{{bh(OZhr2(Uu{LkBj1n6h&sDDgTmfvp!7w0C&E_VRtr7 z&X9elvTs}4y7y&e-9mJWwf9loLRU>sYfatao0<1tj;;RQeotYipJg&1R`2evblkc& zt=)|G^=q%|e_c&vDuCong?_VK6m>q(xv*Kj1}5zZ0E5m^qKHu!ynhmu$Vm7IxEZTxmWRJtOe)8nzKoFYPwIw!K*RB7e%yF z@Pvro5`0PUQPvpnINCH_b^NYfLeNRNVQtgB!EokEQbcBf)_^0b>7mDF0+E zS1ONHR48xVEehSw6nHuI1 zi1Qsu5>)3!^d{h7A_y#l*kM_gy_ooqopK`X8Q03EeQC7humk5Lwq3+zxN zH!h@?2)YxXDI?9PD2VK17?dF4c6$^4GEKO z3p|9D^*}JNT7@ZQc;-ZOK=8YA0%9oy zs*K(bI-FqXKGv&E&WP@!2~|o$0lyv$1w6`;Y_sJHNzVYy6H1~P${jFi_z33btHz1 zF3grRu&4GtmL4{+t8(L6@usQu?YouYqOb1{)iP$O`Sxb_^IwmVi`h@t+vciUyZ!(g CG05To 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 zcmZWn$xB;77$27w5yewMq=%qTvTX0TTOEITtVlMs?! zQ(g4}zdG@xg~SC8ec3O_n1t!KbW{qL<7NeP=JUpscJ>oaWV0xVW3II$>gcJ z_fgZ}RzA!so>ibTT7l3RJ(vP#dLKsmEMuq_C|DnIPUEw8uhw1t1EWw?)+7$Vz;TLs-nJd z+}PZFnUj8UQe5owNs^*uwPa*u-Yxo*$bn9ItiZd}V*Z_YZ^iJn%Q4lWAD-c literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/ctzn0g04.png b/tests/pngsuite/unused/ctzn0g04.png new file mode 100644 index 0000000000000000000000000000000000000000..b4401c9cfca842537838cec131e416ce9d7b0c26 GIT binary patch literal 753 zcmeAS@N?(olHy`uVBq!ia0vp^3Lwk^Bp4&$Z`J6 zNzb#P8s2AuIsDFfoH=tXkmKALZ-1Q=`d*<1Teg^7-D<+j(4EM?Bq(Z%5YVvQAj4cz zi<65o3raHc^FYSw_HE=lWWeL{z3!;5&(i+~S|SAYC&V}_-LdfE3H>h@z9Dj7b$L0{ z?V!z*(zQ3RbHvuze{%AF`9ST7(P3V_yAM6v__yY~zu>c0ws!SHZY7mF>(Xu3=spqF zYyE1=?(N&QTWCLD_9?x`{4#-_N0n=i%(89VqQ<1I<@)8j^q#<%rc7M<{~y>rT+&tj z?Xk|)VE%yIyVWz+p51BFUYon-WoSjdd+w#BKfbWae+pyylvLFL^o9e-8^QT$CFO}l zso)^d^YYd4^bI_5KG-AVgLf~7rkwsp-f`cTpI5{UVGdHyeY?`*0udct2*HvZ)!BFOeE9Eakt zF(>xoL0({Ru?EO%IdFX7kX@*}flE2$(Fs;VMri}4oB+23<{Jy#Y^O5KKjInqNJi`V z(bBh562w#svm1Fm=6#&ivGU`VhFqra^=CQ$Y<+NlKIg?=TOE-dX>a_!xt_BxxKPq} zK;y)F)+dv$%Po8B#%=u~U{}NXebp5O&tsV_+x6KC`n6Ov-e|q7d~>yV!S#P~w_ZMf z;qcvgkAe_q@|8lddEI`uLzP=J4Gp*J^)`wY2|W3b#w`BCU_;}R^bC!qjU|5>N8=ISR z4CLwk<95#Vg>&ou?4IBK-OKf4I=h+Q-Yu4^`-jJ;=a<*F_w~o;*Jiu>-k0SMV?!`9 z1Vck`We6?}!N3q)7=l6z!b$|W5>ORnBHWgrk_!4FAm#v-gL4rOlDZRAQhFl5C-ouJ zT{shgf4PuS-IlHh@Hud2s6Ob305=7HTh$nC5#jVOMRm%l2)`fuP_1(!!tE!01i`Tg zNcxC^mI$IC_VFh;N<~=u^=Vc`@;_)KBFl?^KZrv^P&WiMLvUaSEP*Ak#4p5s%2-gQ R&b9ym002ovPDHLkV1h+qhR^^2 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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 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 zcmV-H0lxl;P)}T4b;N0E z3!a!0=lJ%5$Eg%oz?c7nM_Pz6fDfO-!!(E~0KEA*c%UmW2WDfu_({31E3v>N-{Hyc z!o4_%Y@;b2{kGgyCmt~K_ux)+Vvc)%F>XgE7N{D;Epg%*RfD)GPQ0RO5I3R|@2DEY z_29%Oss?dQ2JwUcSEewBLHsU3nZgtbQQmYZ7(-i7*cJ?I3zBU?bOg~6L`VDql~F8% T6Mw4;00000NkvXXu0mjfmy?8r 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 zcmV;N1Y`S&P)Qj4`pI zFjkU)u{F?Akfo*B!a}174J9nsV(#3X+5PQ?pp&O~&o{|^n{V!Obi%NV*_mQj=dbpv zm_B(tFHYo4wlii|=dbiix4xT4UZ{eGTtw$J**>tSy6N}n|vqif78L&$byRK9f1$SzrLzUf{!*^r3k$774rXm_7!8f1Q2+ z=C=8j8BA;b>93ttmB!R4Gqr2#)Il4ngL#p|9QHl^o9+4V^!;`CWzciKaJiBz*2s-A z%Q~e~hNeLo)I~S+8N27*(|0^}KLTZc)b*DYt70WpQX@6;tlY_+JY<94KKc3jyKkHx zc~$=bes_90V0+^67$}#lCtg&T@Kv!ADxnb@aaQcaP8xdm`scunQ;gUj^(pYH(^C;! zNn5y!L|KC#`k`FGPq->y@fF|j4L>V%d?yTrfgi+0@98t($EU{=wvxAS)ubd$_PkV3 z!A+>5imOt?H8kTouFDPFK!bmL?KbeO)596d+rNC?VU*+1#52gCK!FJ=R8*lsgBd#N zFko=|Nq}~GkP6E2D88M@l8GXUm_!xTsfy-kVs>rq&*Z3{>ZqRPX`b1u2fF{_*^dDC$unBQ(Ew)&lzW^YzR^hz^JI^CidP9to*K@y zNDItSJ$~`R-vM{)Cyb~i-{XO3q;i~yCk82yJm$&k5=WK56seJ#sF9XvnK_+adK+*z zf5tFI)>7;!5IcJyUb1-f+PNSFERrJ@DN!XcC2FQ7s?jpdPCtJOaPPm$D2$0wv{X9^ zWaZ)t@yIozCq+^qMJ$rnCC-%0l&Qw=-{Go9xBkqiT4p;6#CFmU*E%r}BWWdJiJY-a zF^Vx6Z~f)!f}4M1bjGY@*ij%CA&7a#dtxL;QaWQsUcZ|{DNGZ!QmbmEH8z2;34}4U zEce==fUtrOcu$DLNKC}F#?F@|D_EgSluD^gm7PG?1j0Nt7TXI1ibI5i_qeUYM`9wZ zHAc+m{muoO$dyvD%1$6`0-+Ag%UwbcF5n#U_<-~Hh>wJXPsDV-gPixfkS9{*C=fP* zFb&F3UG{zuavL5Oa2^-&5ueTk!)M~U--S34D@TE_2?QJDp|V`eAXY9N+By{R372qb zf6pNl!i29J1;Qo}(jX4E_qp%Fz4^!GobzySIy|o?)B5V>_Wt4V>G|dL?fv8P>$@@5`4A$18fipC zj4{?)>#TR)dmloGF-Am6L9i(ZNIDP1wql`V1IXeb3GF@N^}7L$OLT?eW035 z>s-(z0SrY%YCz?nO#+xF1yoYnBznj5E`aJnr^KQQpxV+di7ue_plgdhP^rb}TH<8U z-_)#002ovPDHLkV1l$} BmFfTh 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 zcmV;y20r-x*}n2M`}#}vjc?j3 z-?s05&wlVj`|(fh7r(S$|JMHaC;Q7^?O*?~d&{=IVSD>_5?Nc!ER3!g3n}x;oHDCS zE7M9tnNlW|No7L0po}Y{%BV7;)RZA*NEuWHlu$uIF{MyCN=M0+Oi>NpMWV~bQp%#T zpv)_?%8W9jOe<4Ly-ylf#ww|%3|Gvc5-LF-)9o>#n>V*ev}9aNS<tNOUgyIH` zG-q7aJ|<;Bs%p}n(NLyR>cV6>o0KtOR2fOBDK%kO8B8li!+3&t(p()kWp0LO#<-$= zOvf4WkAB#DDgP)1#^?QNplUNhH+K4K#)MH}M8lng?S#!1>#?oI+;=QHd&_Y* zvQ2ag-A04p0Z)8E@cI#Yj2@#AdWt&Kp)E8)6V#)Eh6mnu6Sfn!T5QC&9<$>3pR;Ah zn~`mxSA%AGv*B#jvEq6SSw}a}hv?(JmFIitK6;2Y(MP>%q^zct!qYa9w`0$dr1uwhW0Zhu#4`YC3A2lof%qhmB?1mex?MvA0uiC*F<|9wjtewjbMGY&*`j zoNYQ=i;4%x3bKm)ELbUlhe-cy&Q~LkkWkfBOvHTK5^pVU&KE8zqNF%!6-RN=jJt=f zyYIStuDcy|)=2IKN9FDBuxB>$Tlj7K4t|&RE`A?>fIq}HX*X$yq{F5)WCR(dJ%%60 zUobyOQYUH9nkJsLcn-IKTf$xH1ii7(+IyZFAaXuHLUf39$aL7GW-`)eOjt5$$&|Gk z7SC8bXKudx>~4AcfL#|Bg#}?=m=$J(8L0w9n3UeL9uLU|&_U86bQr0b)M$_5M@xoe zf}~Ds%Hl?G{lDey;l^hyT6)`NFITQS5g;L1KsJC5kPe`O$dJh}?HYch$0Xw<6ZZU{ zd$-?t0XK_VuxLS_2oUXUsK?Ay2?S&T8dk=j$q?;fe2=lO{-L*jZof!e$2D-%xH*gF z^n8Gvsp5t2h@l@X8zXow7$3|f20{E)r!yT=R8p8tOF$?p``zg4{drQ+FJ#q^ho zXy)BBQMAcvVzRW z3^h_v5Ric9p5w+1ZrERCgI8Y-UVAOLeLHyLjo{85+yt&}QC+$AHbz)d7DMt5 zd6zUtb0njk;WJuFoZ^&7I1!H8G(892_Pp&Rww>5!%hqFCjqSd(WoK`>;%;>AP46PR z$UY&RE}af}mn)!IyrepUKyIwR{8>j(~{{02>UU6F*}Ye$EIT~(g*w> XLp~IzS7kjt00000NkvXXu0mjfY;#J> 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 zcmV;00eb$4P)4Zd45D^U_MS@TiGz2aVLCXUNp&Fi;&<&!6t`aRYNwm-e(L$HR7llUs_2v2Lp?04i2#w>5 zCjFHgoS}>OqWhKs;-;4%0XoyCYd;H{ChLTAkL z`Nnmc1cXl84@#vy84@~$6^JKJlZ=Ubk`d9uF>y~YB0kwMamU0Lt#&uLFSbqGG0ztr z+6kZrX%qLj_#)n+{rCF=MU%cN0ReDq=R?P^VtFOGwjP)u6|4v*CxG_LFwq4OLVH6N jD*7N)_#jLSK#2GUV`p4Ky#5P000000NkvXXu0mjfx;dtp 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 zcmV+m1@!ufP)=&S9{TIAi*MDSax9$V&z4Gt?ul6?wozPIOm-?GqbzHVVL0@-rxKGKhOL8k5O_q zSFpv3t*o}I*V_9Zvg_8{M;@~qp0pb`*{3(#=eF8yFWQ%0wy%ua*LT{9H|_38yXP&t z_Z_?MUHjhq_P_`B;30eDsQu(qd+fM9al)Sb+AZ}0v>o^z(58vARqwd=u@6n@Pmke1XD_3x{N{!lS^S@Mz)_} zdJOa7^M*h)z+aJKlpUap>FUU*babUGt;6i!o}sK%&_Ml_0}Q1o&Mu`O$?Cq66Q@JT z3RxIYM!*w1@Du|XA%l7Q)eI$}3>DD;e|4H6l$4TCgo02|@B=KrQ z@Wkm5Gr226kv_(nB^X7=$b&B_9m1$G>KKWRgkdJ$$Rs9|g_2{8Ez5|#T1H2TVa9h$ z(j;+7%SwO->aXp@3<>@U&;J{qzZIUl8J_zyJbOJn`+IoiYIx>K`1Q0sy`|S$qy4Ql z0v=}L_DlonP=h(73bQba+*O)>Gz;H^EtdX#W}j_9D|OAoJhWjRA~5T>Ndu`v9p<2x zV$3LYKl;cP4%*<5UG=dYJ8U03Vjuo4ycMs0P50HI0S#zE(=pl(GY{sz&C+xa)e;>z z1~aNPzjM$1t-?9LR-*64P#mG-1*D8@fZ(*yqnYop#)_J&`RW&@^-8p-T}(?iQxc|RDc*( z<`4s3eE1|ejyabvT}B)cWe8L&9Y4_UCg9tx=>U_B7``SQ&NPmDBN;&XQlhP3n_*jascABYwWa1geh;>x-+i4(U_Y8$pQBrmp@_v#) zgF2F8aQOzn)E_eOLYJ|y`CQzx3-$nmLD=V&A(sP5g05dja_!i}_ zgIDirr|I{mZhX~}7YtBA6@@6ph=h6QI6&Kt{O(YUr$lPFM|Gd{aIa#L7cd2c1x1(E z(Q=Gs10<^TF-)&&>U0cv)zz`6SBo;LJ%(}H?`NdF>L`))0fxOAVsvH`hUsg)nABw~ zucMi=tL~(v8Fzi|4FCoh!(J`gSItz-2XxH%{{y9tm%W$Hmi_<$002ovPDHLkV1gMt BbC>`C 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 zcmV+o0rLKdP){e2x4DAd1)!+NJ)f5B{T9psOdMM) z%F+|8FY)0+3~^>3vs1_&)hG|SqQp{zQhWvt^p*^yfsjOBNTM$!(HFu%2m|o|7A8yw TA(>!-00000NkvXXu0mjf-K%M) literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/f04n2c08.png b/tests/pngsuite/unused/f04n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..3c8b5116e72a63a3de8e0c1892c147071d0269e7 GIT binary patch literal 985 zcmV;~119{5P)hvyJ!8utT1VEc>UN*1Tj!qJPN}IY>N=sRACLdrt)_N=Jy&nmRP0foi1T3q z1vs!^NS8tnTiC(|3Cm|k`D(`N4+4W;;{3xH5HR3=UuuoS4K!$rOa`(R z?R*&X`GvfR1n&u#ACUWVNrjF@+CUA>kh2DD{mP;k>FRtL8*-Oa0-8az@Zi?_D?6u0xgjeiedR*>(yJr`MN%ucekr3 zWi?2)HMNKXi#p_|&$f}^7s7eRdN|{jt0Vw}4uOnAlX>OyYx{;(h32S_hezhCE(Fab znDm|v`WGp9zt{od@3wLWe5y}twl%v9eNEpS4jt=K5jm_s#Yobzz%^iBf5O6mQ4IVB z1gSS#SEq}Q@Y^iry7D|7u$1$9vV7%>V~{k^6C{`$4zP=FjwZm`$rGS zvDv1V?}l%U4QyZyYY4D{53qy=jUGER5T*mg4DDFWy$X8(2FG?szK8L%=^pMOKo~6M z$j~Pc+wCNgX-nw*aZjf2VMtF87IxrAsgQ{`|D+q<6)@}&$53fBJv+1hHpj`E}Y00000NkvXX Hu0mjft5eU! 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 zcmV;b0agBqP)R*H$WiHScT#vd?>UqJiKVd^cv0p+pyQ zGH|gKM+__s5&6}tHkZ;`DS5Y9+rZhQ zwP@N_D-FoTR{3vHO$x#=5Cz~@tXf4-D8*gDQ#65;*9uNSx9chJUE%)%R{#^#^^XN{toLo}DWI?N<>C;~ z04ksXP5}*|#RS)@U%=Ob*$h}N)l>-ed1V5+W2XZEdA?ey6A(g5buxi@h4uQqlhPtM zpG^V)m`*nvwSYxHS5VI&O?NvOiV039lVCCd(iGV5g^==n1tvHiO#xM<`sZb@9~=`L r4yJ(5#RO&P7r+GDZJ=PW2opR2brp<;D@5J500000NkvXXu0mjfFu#U? 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 zcmV-&0ge8NP)yO^U)m5Jsyp{zL>36n8GX#CQmg>mm9SE(8}cf*52*XGY_~ zh{+_6px=OtfYFFnf&gIz^!p-! z4E~_M*AoG%LANUc)ER`K2v7|=9TA|;pxqV$s(}np4O%S`KnAq|RD)(y1iYU?5QqRW z_=SEnxIkSs2+80F>Z$=A5dp}6`d>Z+8Ssq3bn47(xy-IHGcz-PeHq)$ 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!ia0vp^3LwnF3?v&v(vJfvmUKs7M+SzD9ea;@ZUFM-0(?ST zfi%Pa|Nj~OGn_cFb}hr*yC5EjfA|0Ywf_xwDRcl8Bzw9zhE&W+)?jB+RWM*uY zOI4Q~40T|+ae#?Kl#?gtjDxO+)}>1i-Z_XV1hX;(T`t)BOm^#Pkb^v3{an^LB{Ts5 DR8dIo literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/g04n0g16.png b/tests/pngsuite/unused/g04n0g16.png new file mode 100644 index 0000000000000000000000000000000000000000..32395b76c9c0e1cb962743e8a9c8c41f319a26bd GIT binary patch literal 363 zcmV-x0hIoUP)k zMP!AUF&SCLg{ApYo}a%I2W<;z1p%J5#`A86=diAEu-(Goq6aWQ91jDiarl1YV72lz zSS}q6C}6R0GJYI*6ZWZ>;Ot> zZFbS1yTa-8J$*mz%z(DscaWy%bDwwTTMVko4oH&Ag@0}_C`%l49mFv}k^p3xQd%q3 z*T@Wt!e(&2nptb1gFLri;n!jYw;K*dqhSCu$TClZ{oV~g4L&I}i72HGV}Jkv002ov JPDHLkV1oB;ijV*R literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/g04n2c08.png b/tests/pngsuite/unused/g04n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..a652b0ce87ed2824e2320154aeeb92915dab7be4 GIT binary patch literal 377 zcmV-<0fzpGP)=$qmFdR}P2oOfV zU|<4VgMQxxxCU`-0$hV$&jh#zHh>I1V1Ku30$c+d;Lf1aF#%*iSJZBs0Cxue-@pdA z2CbF}AcGU^M}sfOy9O~C5WqFSD>^`)3~T@e862Ae{Ka543z8O#a*afilwMz5gDA=u z(`i^Pv*IGJo|YG6Kr_1mR;%nWd2jp{WI%v#Gnh=mdi~I3QXrAR9su`drSUjyHa}Ju z8`J_uqi|tJ+HSMFZgOR)ZU*mlfZeWqG%Y-fK?ZMifZqlgyfy_OgO{cNWI%t*O&Od4 Xkxf^INQ0u+00000NkvXXu0mjffu*e-u`Y1b?z zzWXd(t64Wrb6MRl-MPm3%bnSi&5lTH;%2!xfw$vO?LWcx>5tgDx7P8NE*G2%a+Rm6 KpUXO@geCxuo>m_K 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 zcmV-Z0j&OsP)?t@NnF8DcSAbJ+I4}jD4==ze*zcJFZU7PBBkXpb0$0HQ1>69qAc{N%IA9o<0{k+y ztwZpB+XXm)2wVYpI0a#74`2wgEYEeVl>WRDLD#JdZnwEs3P4|pU@M>~u2)?HSOmDs z%O>jDD!>8DCayJ<2$}{h$mxDQ3z4SJr&0jRBM<=&(7Tr9be|rZe{e)l*V{)}8$|GW l@dAjTs?dUD3LXzX!4K_Ugk}Okv)}*#002ovPDHLkV1mh&gfRdB 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 zcmV-k0iphhP)yIS#@w5JksQ*g`}>M?;BdsB#iGXl_D}xBv~JKVfNIcci2&6=2B-$jrU)Q|6XY8W5%7NoGC(z`*F^vs1lyuu23P2l z!4dKa0rt=jWC9bvghS52BVSt=-A}B^lR{o z!EBZfhpyn1c^lB7D8J-F$KT*fK)J|Z=K<*ToSF6eZn4N8k6hj>3?mmdm%hv(n&R wWU%o7coi9}As&7nsP&a50$ri)KG u9IC*rureVboiWQXC@_w%oP86+Of7~h92M4HZx@7u9OCKf=d#Wzp$PyhYDC`v literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/g07n0g16.png b/tests/pngsuite/unused/g07n0g16.png new file mode 100644 index 0000000000000000000000000000000000000000..d6a47c2d5746fc93d252900c0b2286878b14a71b GIT binary patch literal 321 zcmV-H0lxl;P)ic&7(nC-rHzraP|afnxc^RYsd`d`5u7poSz$l82kp{Tq3Z6JE6!C z<~cx~GsZc95JJcub)b0oLy=wE_B`cklP8(MI6l9^UC0cE!3;nQ`rgu@>+B3Z0>z=! T&@6K-00000NkvXXu0mjfZ=Zkq 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 zcmV-a0jvIrP)Ec1Z7JAAD^)rl zGc;g3%p!~-&*xWAO~jWXaK$Npe&EOP4FJlLpC7?~0$d0v3LyXpLqMLRlR!xgvP=k& z8i)Z>gESQaqy}ODGPs5U>}G%fNg@Ow1N4Z*fS)rkMhK9;MgMOA0e3K$8Wd6hG8n;r zXmA1Z-7-K1S_=WdAR39-HfGgLqn?XbwVVOhUIuloww+K0g9o7Nrm9jK0F(g&e1^=# z-V(Wa{fz-XY1a&35Di3ZYyEC(6%kphw4Tp(^SMg{u4DAwEbq7P7ygd;HOjyT;8iGt mb0`2ZIE4Zr1N1W+%HRPOfLawl;h_ou0000jY(XgVYP$Ug2i0{3Ntua3PevZO<6g^Ah?s$m6bVyVK1BpBEle`W(ImUKs7M+U~W1%@xC#RK_!JzX3_ zD(1YMYRK23AmC~*&8=hG7IXO0C1yqTPaJWFFL_6JBpnoMIXcsY>1ImurhiOn%Vt#m z5fC`n=)o~7+xK(flFC$FU60NsKN=pf&Dn9QJZi=3cwrm4I|rNBb9(vyap&(_JYhlR zCEhOE8{3?ktnW4_&R8ZOEj;gf4*xH^W5+UNujMpVzT34~{@9PX!h3Wk|Ka$Mox;Fy ze2R(Tv5(acSr+AHDoQLDVbJLg`uAs{=eP4));+&@o#p&$o;{4OIA-jB`e#}P$b+7) KelF{r5}E)9`D>*B literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/g10n2c08.png b/tests/pngsuite/unused/g10n2c08.png new file mode 100644 index 0000000000000000000000000000000000000000..b3039970c10e786659f9752913c41b8a26b1179a GIT binary patch literal 285 zcmV+&0pk9NP)@();|)eY}Flu=NxRyTwAba19zW zNcaI2oGKYjCc{&aErrDdt_X+yXV}i(ARy1f{s-JoAU8t`q60wT=m4lx4WLj1#Goi5 z0}g9&GjO^Y?CP)v$sk{c!58?k4IU`q1^i?TP{4Hwg$wQL5H j&i)?k>vRoL{Z;$`)U8ca-rtX&00000NkvXXu0mjffk|^a 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!ia0vp^3LwnF3?v&v(vJfvmUKs7M+U~W1%@xC#RK_r0X`wF zKzij$28RFt|F8NV62kBw2K)ELwKW(gS)7nLjn&=f#?aQDJu;O{JayK!wx3QIX10fSyM0LA|{qo zr@2pEmRO+mfXPAELrdbu&4xCml^Xi(yO|>!d_)=C9<`pFX(h-9w2r~k)z4*}Q$iB} Dmq$l3 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 zcmV-_0f7FAP)$PJx&n)kH3|svhZZ(r0ivJ>sO?q;pvG#q^Pdnj*zaWkW*`MH zgTvuZ0}6;^p~3Np8;yq0Knh?6r_-MX=QC+2p~2;X8_lNB;Cht-m;nW}T0(={4L90t zp~3y`2b5*NfC2^sT+`Rg3?2{M=yd!5X7GIa0W_Ea1$4W905hON>h)}1tpH{-dv8qr zYh?yig&X}o0Kj6ArtTUrpa891&a%3ygBrvY39Yr(8X(K&^KXDL&H#scy)e;z2g~Jm zWsI8yn*n_$yCu)3Q-D0T+mfUnB%1+k42L$a*EYNPyBsudfL{?b7>)b@WOU@^z{4wh)7YG#lngB zpO4to4PwXAUtl<^EZyItpI$A4c0ho^z$dGfn@-I=c}&df(}j0HTdM#fvR(&W;o}K& zG9bWk2p1G&K>eeU5^p%h%I3sGP!q+00000NkvXXu0mjf+0UW; literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/g25n3p04.png b/tests/pngsuite/unused/g25n3p04.png new file mode 100644 index 0000000000000000000000000000000000000000..4f943c6175f31c3609bf4458fff9d3c591f112f7 GIT binary patch literal 215 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvmUKs7M+W8#6Mlqr_yhTJ0X`wF zK$<~Um*M|^0Re{pF+l47e;^$L6aWH-pup=-feKPQT^vIy=IlMUk+;Es$0ab@YvMKS z4NTlSPH?R`z_n#cTw`u=ph~f+$IqufMW?aPJ#nF}g2zjg8cRnT4C8a-ev#F_0RlCh$*z86iP| zaVyJO7(suuAQvVX1O;6NThywBgyle%p;kiF?Y!^7%*UPg-nqYX?l%`38+JvCR~8dd zB)L1WAJ5hPQxeAagYN1HJPOnCJ#h+k^;hS6n~B2RjrC1+_??J}9FY(yk@yB>bT*DpgTKuCNOVY>KHEazxSy09-hZpy3u#A`f8V zHsSyi48tL)AqHsN1Qs~Z7}}6FKO%n`+o-V&6GM>jhqkEH%nvXazo!T$>gO2@$wLLX z`|$=*dd46fKkdM#M|Gt4gY=kt2bIyaHXr#UDa%9SKVaIhyKeYwX|*h#PykDCr-AN)~w;?+^4yN zr-s8{bD3D{UA{K=ZMOCByHINGNoR9@dNzC}GcY)|Ju@)5BDQntP)ot4{Pc$K&wPET zb0n|#)BTaYxn$Ykj&#Mk)P>xtSgI$wXyNturRDT2Jr$Wxq-QF}D@JdO#pYwF-{qy3 za({X@R~7V)9!N#APsdv3V~y=a8^^ai{@Af>>)D}>Xm+S$ZFc#a+o9u`9GCs*$lY49 f5Z_z){0_hPQv2`7;*nR={=b*3Ye+n*O`ZD>%pJzM literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/pp0n6a08.png b/tests/pngsuite/unused/pp0n6a08.png new file mode 100644 index 0000000000000000000000000000000000000000..4ed7a30e4d16e0527c2695bf0493ec1ba156d8c4 GIT binary patch literal 818 zcmW-fy=zoa5XDDVMV1W~5)ehSNEfm%xBU z2&4*#Vrk)5qd16#e?&m+j8-!K=3aRF?(EE*Ip@rKwzzO@s(ZRCB2&ZbgJs_5>p6am z-v^V)Z(c|4^l$d%(39=C{jFOfho3IqSefU45fw2J7YUK9NLAECT{J|qlBQxN=3*h1 zRqHBl;w~QIS*@WGCgBnxkswK`q)EDDND_bzG*~oKoi(S9sk&;YW{o8>Q**UY%VI&& zP2JT)J&P2zVH&Ox8VN^QHBHksLzAhn1`N`$gcdmlgAFuTG-nB_nB!()mZgueMDFHc zo+TF+B*QJjB2f=1YAxL|ERlyF(4-qX&<_a|!WuA0!;(^XFc@s0!OC*3(!`u_&oUBy zj3tWjNPI;uEJ%8WCqCjd2EdDQj7BY1;s-S8#tt|k7=^F~4AOK$3myyx8|bVRRW)g1 zPO>qKL?2^`BC{6Q)?X~zMr)sKNkyvpUh8dE7RTmJZMz9B%1uKpztJiMZ4%IY4r~eY z(8Q?Quih^4C60%K{>u7`U*G4t?=SSOE=^ya`TK7B-cIk^kKIxK>$!`kdXxRvvtNF0 z{=1(CZ$@{A&yUj9`FybVvBPCeK0F$)bCK1Jv!jQXxa@3n&V2eaJ~@4&3S>CHFnD=o G?eTv$Q+DJ4 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 zcmXxkK}(cj5Ww*#aAOfA1P>uWA_;XUl%aEMY}7)@A`%EeORi%bMFPEcC<37_1p^(# z58$OQAu`alqXdS>Zh3N=`9rY#yvw`)eV+Lp_Wd|qc|1KiH`!X79z5x<=5@Z_-CWx9 znZ?_Anb_(*>$NNI50=lrzHF^Cw=;aYw)1B9?#A0!o2|;IT3D6USe-R$6&j%t8le#y zp-~#8Q5vOD8l^EBqcIwzF&d+B8mDm@r*Rsm37Vh@nxF}qs77!JE@{yjc z!KJtqm*P@fc~mxr%WxSk!)3T~kZN!lF2iNG3|Ed>4KBlFxD1!!N<=ld442_DT!t$@ zR)foM87{+RxH7B;m*Fy8hRbl}HrY5X$K|*jm*dJqs=?*B9GByATscBDxEz<`a$Jrp z2doB{<8oY%%W>uS)!=emj>~a5u3W0Y<+vP|<8oY?Wb^-3|G~f&xB^#hQ1@{KuD}(z z0#|Nd4X(fyxB^$;%EPO{6}SRd;0jzhS~a)=SKtaFjV?4UmX1mAVr#hYeYu!5+e{Vh*?JeDyT{@Zhyfr@Ddogvjv;XPO$z}Yw k`0#ss`FehH`ek!G(S~Q2+xLI{T(5`g;L%F|=;7$yKLBk?PXGV_ 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 zcmXxlUue~37{Kx0Hvcggjqqa5wnZ0q2=d=kL4nm-M{-~`!ka?f!Rk2%2GSHdS8n`@?ayH~ad{hwEnjwy0Kqsa!OTO|EN93>3xU&cXi8TL<6T z_xS63cfMIH^CJ6I2&=LtR%6Yv3XRYRjnD{<&?t@4D2>u6jnX8VM3ZO|O`=IOMq@Na zV>Cu%G?^yTWSUHqX>v4zOK?dMjTF&H5sial#U;1|m*5gy{x}+3f=h4-F2Us=iUyb9 z5?q2yaQT+e;1XPdOK=G;KQJ0xf=h4-F2UvFc%!%!m*P@fipz(M2AASeT#8F^IVBog zic4`RF2&^!qQRxO6qn*sT%JdROK~YK#ih7>vuJQBF2$v|6qg_6O~RFMC0q$t!sUZR zgDc@mxDu{}%g2lcSHhKWC0q%YBcj2Ta3x#`SHk6QqrsJMC0q$t!sTH!xDu{}E8$AG zd>d~Jm*Fy8hRbmIA<^J6T!zbV87?0o8eE3Ua2YPc%WxSkPrUj672m;(E91(ze1mw7E91(zGOmovw~q!_#+7kpTp5=i9u2OH zE91(zGAr)-96iXX{yejIXKXmyW6~f=;W#C=Y~#RUr~DD=C<7}Pd4V( zH~-n#+;niNVPDrK+m6lmtvvO7t!H)hgZe|I>Uj6!dzWuN&{h0UyVC!@}`gd2y$Mt{4pIX~;?82+n?%}i3yBA9R2bMfB^Yr&uM<0CVz0;%J!>30d8(#j? tiKe%Q>ay~W(faXa_sTCXI{$_Ic%%2f9ZRP!&BY%;-^MMK?|Q3;?gI^1pmYEL literal 0 HcmV?d00001 diff --git a/tests/pngsuite/unused/ps2n0g08.png b/tests/pngsuite/unused/ps2n0g08.png new file mode 100644 index 0000000000000000000000000000000000000000..90b2979685772423e875e3504fcfee1d406d6a37 GIT binary patch literal 2320 zcmYk4K}%Fo7=}-vF^E!vi-@2W1+@s2p><45)If=Z1VNCbj)cC8aMZEGd0S>5Cs( zJyVm_Gd0qcmznjVR@Ql^~~0? zdZrdvOdOUJmK0Z{u%x&m$?BPHW%W!=R?o4*q*$@9zh`Rp)iX8wW@^~XkYryy^VYt4 zP9=Ty%sW{>) zq|8hTOUle7Sv}KLR?pOA^_=N)gPxgFR?pOA^_+de>Y2@C^-N7x&oK~I&$y7)Gc{Q~ z$Jzf|XMb5e<3v`^vD~r;U-oueZ@odkx4iv!b#3Khnd^M|I6XPJf2wok=+F7zj<`#D 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 zcmYk4Z)ntY9LInAqm9Avh#oBGwjSvrRL)-t1*>k|sDbH-Jt?dmsdoql;x5t)bSqee zNKkNb>TLSJ5KOlMePH5(prGSe59(15hG-tNTI`k%!mfMs?)AmNe&6?fe)sx*KA#u& z(eTa}JKEQ`M^V%<^iukj#`&236U~k1#Si-y8b@m`^>Qj|nw;*d7DuC~tuQvcV`Oaq z;m7y9{pP+X(fEe`>OP`4q-;o~kjf#||4(sXlMo>hazvubuF(laZWRr1VAW|cg%5-gt86&BB` z!Q$D|`35{|PFOsv28(C!V;0Za3>MF-!Q$Bl%;H%tVDYRPES~M`!L7YNES}{A7SFca zV2ks|CmY^w52aHhhfn`p{I>o5Es69O3#ns29=&@1%e%#%wJo1aZp?mKE_6-~-s=Bl z`s2hv^z4%hCztjf8avwAzbPKA+^oI!&ei7MEBWNXbMa@jKb8-^{!>$?_SM8_b#b}* zNdElH+;jQ!w;oNtaA)^{mTlF=t<8T|cQj30tClb1raPu;LtQh^=X#&Wd{Eht%$(?1 zv-$;;WxjP*z>Dy^=4^c9w}F4(c<9=9i;ab& Np~0Q$O9Pqr{sYFSp`QQ% 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)