From 40eb865b3bd713ea5ece4b87f97ab1b469b894a4 Mon Sep 17 00:00:00 2001 From: Fabian Giesen Date: Mon, 23 Jan 2023 00:46:33 -0800 Subject: [PATCH] stb_image: header scan mode always needs to check for tRNS For paletted images, header-scanning mode (used by stbi_info) kept going after the image header to see if a tRNS (transparency) chunk shows up to correctly determine the channel count, but we would immediately return after IHDR for non-paletted images. This is incorrect. We also change our reported channel count on RGB images with a tRNS chunk, therefore non-paletted images also have to resume scanning further chunks. Update the logic to keep scanning regardless and report the correct channel count from stbi_info for RGB images with tRNS (constant alpha channel). Fixes issue #1419. --- stb_image.h | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/stb_image.h b/stb_image.h index 0844662..9128cab 100644 --- a/stb_image.h +++ b/stb_image.h @@ -5115,14 +5115,13 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) if (!pal_img_n) { s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); - if (scan == STBI__SCAN_header) return 1; } else { // if paletted, then pal_n is our final components, and // img_n is # components to decompress/filter. s->img_n = 1; if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); - // if SCAN_header, have to scan to see if we have a tRNS } + // even with SCAN_header, have to scan to see if we have a tRNS break; } @@ -5154,6 +5153,8 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); has_trans = 1; + // non-paletted with tRNS = constant alpha. if header-scanning, we can stop now. + if (scan == STBI__SCAN_header) { ++s->img_n; return 1; } if (z->depth == 16) { for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is } else { @@ -5166,7 +5167,12 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) case STBI__PNG_TYPE('I','D','A','T'): { if (first) return stbi__err("first not IHDR", "Corrupt PNG"); if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); - if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } + if (scan == STBI__SCAN_header) { + // header scan definitely stops at first IDAT + if (pal_img_n) + s->img_n = pal_img_n; + return 1; + } if (c.length > (1u << 30)) return stbi__err("IDAT size limit", "IDAT section larger than 2^30 bytes"); if ((int)(ioff + c.length) < (int)ioff) return 0; if (ioff + c.length > idata_limit) {