From 4baa1b1384da4ae9ddbe42a90e5f6300afb44fe7 Mon Sep 17 00:00:00 2001 From: Randy Date: Wed, 9 Feb 2022 23:56:04 +0100 Subject: [PATCH] decode: expose zlib FLEVEL for images (#204) --- spng/spng.c | 23 ++++++++++++++++++++++- tests/testsuite.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/spng/spng.c b/spng/spng.c index 9598e31..68b7925 100644 --- a/spng/spng.c +++ b/spng/spng.c @@ -3623,10 +3623,31 @@ int spng_decode_image(spng_ctx *ctx, void *out, size_t len, int fmt, int flags) if(len < ctx->image_size) return SPNG_EBUFSIZ; } + uint32_t bytes_read = 0; + + ret = read_idat_bytes(ctx, &bytes_read); + if(ret) return decode_err(ctx, ret); + + if(bytes_read > 1) + { + int valid = read_u16(ctx->data) % 31 ? 0 : 1; + + unsigned flg = ctx->data[1]; + unsigned flevel = flg >> 6; + int compression_level = Z_DEFAULT_COMPRESSION; + + if(flevel == 0) compression_level = 0; /* fastest */ + else if(flevel == 1) compression_level = 1; /* fast */ + else if(flevel == 2) compression_level = 6; /* default */ + else if(flevel == 3) compression_level = 9; /* slowest, max compression */ + + if(valid) ctx->image_options.compression_level = compression_level; + } + ret = spng__inflate_init(ctx, ctx->image_options.window_bits); if(ret) return decode_err(ctx, ret); - ctx->zstream.avail_in = 0; + ctx->zstream.avail_in = bytes_read; ctx->zstream.next_in = ctx->data; size_t scanline_buf_size = ctx->subimage[ctx->widest_pass].scanline_width; diff --git a/tests/testsuite.c b/tests/testsuite.c index 8df44d1..fc0c87e 100644 --- a/tests/testsuite.c +++ b/tests/testsuite.c @@ -1422,6 +1422,10 @@ static int extended_tests(FILE *file, int fmt) struct spng_plte plte = {0}; static unsigned char chunk_data[9000]; + /* NOTE: This value is compressed to 2 bits by zlib, it's not a 1:1 mapping */ + int compression_level = 0; + int expected_compression_level = 0; + spng_set_png_file(dec, file); spng_get_ihdr(dec, &ihdr); @@ -1435,6 +1439,7 @@ static int extended_tests(FILE *file, int fmt) enc = spng_ctx_new(SPNG_CTX_ENCODER); spng_set_option(enc, SPNG_ENCODE_TO_BUFFER, 1); + spng_set_option(enc, SPNG_IMG_COMPRESSION_LEVEL, compression_level); spng_set_ihdr(enc, &ihdr); @@ -1475,6 +1480,31 @@ static int extended_tests(FILE *file, int fmt) } spng_ctx_free(enc); + enc = NULL; + + /* Verify the image's zlib FLEVEL */ + spng_ctx_free(dec); + dec = spng_ctx_new(0); + + spng_set_png_buffer(dec, encoded, bytes_encoded); + + spng_decode_image(dec, NULL, 0, SPNG_FMT_PNG, SPNG_DECODE_PROGRESSIVE); + + ret = spng_get_option(dec, SPNG_IMG_COMPRESSION_LEVEL, &compression_level); + + if(ret || (compression_level != expected_compression_level) ) + { + if(ret) printf("error getting image compression level: %s\n", spng_strerror(ret)); + else + { + printf("unexpected compression level (expected %d, got %d)\n", + expected_compression_level, + compression_level); + ret = 1; + } + + goto cleanup; + } /* Reencode the same image but to a stream this time */ enc = spng_ctx_new(SPNG_CTX_ENCODER); @@ -1483,6 +1513,8 @@ static int extended_tests(FILE *file, int fmt) spng_set_png_stream(enc, stream_write_checked, &state); + spng_set_option(enc, SPNG_IMG_COMPRESSION_LEVEL, compression_level); + spng_set_ihdr(enc, &ihdr); if(plte.n_entries) spng_set_plte(enc, &plte);