From 942c151c7b92dc727fc2d0a00211e9fa83ef6e83 Mon Sep 17 00:00:00 2001 From: Lode Date: Sat, 24 Oct 2015 23:49:28 +0200 Subject: output palette fix --- lodepng.cpp | 40 ++++++++++++++++++---------- lodepng.h | 5 ++-- lodepng_unittest.cpp | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 103 insertions(+), 15 deletions(-) diff --git a/lodepng.cpp b/lodepng.cpp index 643bfd5..a5a5b78 100644 --- a/lodepng.cpp +++ b/lodepng.cpp @@ -1,5 +1,5 @@ /* -LodePNG version 20150912 +LodePNG version 20151024 Copyright (c) 2005-2015 Lode Vandevenne @@ -42,7 +42,7 @@ Rename this file to lodepng.cpp to use it for C++, or to lodepng.c to use it for #pragma warning( disable : 4996 ) /*VS does not like fopen, but fopen_s is not standard C so unusable here*/ #endif /*_MSC_VER */ -const char* LODEPNG_VERSION_STRING = "20150912"; +const char* LODEPNG_VERSION_STRING = "20151024"; /* This source file is built up in the following large parts. The code sections @@ -779,7 +779,7 @@ unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequen { if(frequencies[i] > 0) { - leaves[numpresent].weight = frequencies[i]; + leaves[numpresent].weight = (int)frequencies[i]; leaves[numpresent].index = i; ++numpresent; } @@ -832,7 +832,7 @@ unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequen } /*each boundaryPM call adds one chain to the last list, and we need 2 * numpresent - 2 chains.*/ - for(i = 2; i != 2 * numpresent - 2; ++i) boundaryPM(&lists, leaves, numpresent, maxbitlen - 1, i); + for(i = 2; i != 2 * numpresent - 2; ++i) boundaryPM(&lists, leaves, numpresent, (int)maxbitlen - 1, (int)i); for(node = lists.chains1[maxbitlen - 1]; node; node = node->tail) { @@ -2598,10 +2598,15 @@ static int lodepng_color_mode_equal(const LodePNGColorMode* a, const LodePNGColo if(a->key_g != b->key_g) return 0; if(a->key_b != b->key_b) return 0; } - if(a->palettesize != b->palettesize) return 0; - for(i = 0; i != a->palettesize * 4; ++i) - { - if(a->palette[i] != b->palette[i]) return 0; + /*if one of the palette sizes is 0, then we consider it to be the same as the + other: it means that e.g. the palette was not given by the user and should be + considered the same as the palette inside the PNG.*/ + if(1/*a->palettesize != 0 && b->palettesize != 0*/) { + if(a->palettesize != b->palettesize) return 0; + for(i = 0; i != a->palettesize * 4; ++i) + { + if(a->palette[i] != b->palette[i]) return 0; + } } return 1; } @@ -3419,7 +3424,7 @@ static void getPixelColorRGBA16(unsigned short* r, unsigned short* g, unsigned s } unsigned lodepng_convert(unsigned char* out, const unsigned char* in, - LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in, + const LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in, unsigned w, unsigned h) { size_t i; @@ -3435,12 +3440,21 @@ unsigned lodepng_convert(unsigned char* out, const unsigned char* in, if(mode_out->colortype == LCT_PALETTE) { + size_t palettesize = mode_out->palettesize; + const unsigned char* palette = mode_out->palette; size_t palsize = 1u << mode_out->bitdepth; - if(mode_out->palettesize < palsize) palsize = mode_out->palettesize; + /*if the user specified output palette but did not give the values, assume + they want the values of the input color type (assuming that one is palette). + Note that we never create a new palette ourselves.*/ + if(palettesize == 0) { + palettesize = mode_in->palettesize; + palette = mode_in->palette; + } + if(palettesize < palsize) palsize = palettesize; color_tree_init(&tree); for(i = 0; i != palsize; ++i) { - unsigned char* p = &mode_out->palette[i * 4]; + const unsigned char* p = &palette[i * 4]; color_tree_add(&tree, p[0], p[1], p[2], p[3], i); } } @@ -3468,7 +3482,7 @@ unsigned lodepng_convert(unsigned char* out, const unsigned char* in, for(i = 0; i != numpixels; ++i) { getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode_in); - rgba8ToPixel(out, i, mode_out, &tree, r, g, b, a); + CERROR_TRY_RETURN(rgba8ToPixel(out, i, mode_out, &tree, r, g, b, a)); } } @@ -3477,7 +3491,7 @@ unsigned lodepng_convert(unsigned char* out, const unsigned char* in, color_tree_cleanup(&tree); } - return 0; /*no error (this function currently never has one, but maybe OOM detection added later.)*/ + return 0; /*no error*/ } #ifdef LODEPNG_COMPILE_ENCODER diff --git a/lodepng.h b/lodepng.h index 86e56a3..86c24f9 100644 --- a/lodepng.h +++ b/lodepng.h @@ -1,5 +1,5 @@ /* -LodePNG version 20150912 +LodePNG version 20151024 Copyright (c) 2005-2015 Lode Vandevenne @@ -508,7 +508,7 @@ For 16-bit per channel colors, uses big endian format like PNG does. Return value is LodePNG error code */ unsigned lodepng_convert(unsigned char* out, const unsigned char* in, - LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in, + const LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in, unsigned w, unsigned h); #ifdef LODEPNG_COMPILE_DECODER @@ -1564,6 +1564,7 @@ yyyymmdd. Some changes aren't backwards compatible. Those are indicated with a (!) symbol. +*) 24 okt 2015: Bugfix with decoding to palette output. *) 18 apr 2015: Boundary PM instead of just package-merge for faster encoding. *) 23 aug 2014: Reduced needless memory usage of decoder. *) 28 jun 2014: Removed fix_png setting, always support palette OOB for diff --git a/lodepng_unittest.cpp b/lodepng_unittest.cpp index 92fc370..6d9cbab 100644 --- a/lodepng_unittest.cpp +++ b/lodepng_unittest.cpp @@ -1799,6 +1799,77 @@ void testAutoColorModels() testAutoColorModel(alpha16, 16, LCT_RGBA, 16, false); } +void testPaletteToPaletteDecode() { + std::cout << "testPaletteToPaletteDecode" << std::endl; + // It's a bit big for a 2x2 image... but this tests needs one with 256 palette entries in it. + std::string base64 = "iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAMAAABFaP0WAAAAA3NCSVQICAjb4U/gAAADAFBMVEUA" + "AAAAADMAAGYAAJkAAMwAAP8AMwAAMzMAM2YAM5kAM8wAM/8AZgAAZjMAZmYAZpkAZswAZv8AmQAA" + "mTMAmWYAmZkAmcwAmf8AzAAAzDMAzGYAzJkAzMwAzP8A/wAA/zMA/2YA/5kA/8wA//8zAAAzADMz" + "AGYzAJkzAMwzAP8zMwAzMzMzM2YzM5kzM8wzM/8zZgAzZjMzZmYzZpkzZswzZv8zmQAzmTMzmWYz" + "mZkzmcwzmf8zzAAzzDMzzGYzzJkzzMwzzP8z/wAz/zMz/2Yz/5kz/8wz//9mAABmADNmAGZmAJlm" + "AMxmAP9mMwBmMzNmM2ZmM5lmM8xmM/9mZgBmZjNmZmZmZplmZsxmZv9mmQBmmTNmmWZmmZlmmcxm" + "mf9mzABmzDNmzGZmzJlmzMxmzP9m/wBm/zNm/2Zm/5lm/8xm//+ZAACZADOZAGaZAJmZAMyZAP+Z" + "MwCZMzOZM2aZM5mZM8yZM/+ZZgCZZjOZZmaZZpmZZsyZZv+ZmQCZmTOZmWaZmZmZmcyZmf+ZzACZ" + "zDOZzGaZzJmZzMyZzP+Z/wCZ/zOZ/2aZ/5mZ/8yZ///MAADMADPMAGbMAJnMAMzMAP/MMwDMMzPM" + "M2bMM5nMM8zMM//MZgDMZjPMZmbMZpnMZszMZv/MmQDMmTPMmWbMmZnMmczMmf/MzADMzDPMzGbM" + "zJnMzMzMzP/M/wDM/zPM/2bM/5nM/8zM////AAD/ADP/AGb/AJn/AMz/AP//MwD/MzP/M2b/M5n/" + "M8z/M///ZgD/ZjP/Zmb/Zpn/Zsz/Zv//mQD/mTP/mWb/mZn/mcz/mf//zAD/zDP/zGb/zJn/zMz/" + "zP///wD//zP//2b//5n//8z///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABlenwdAAABAHRSTlP/////////////////////////" + "////////////////////////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////////////////////" + "////////////////////////////////////////////////////////////////////////////" + "//////////////////////////////////8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + "AAAAAAAAAAAAG8mZagAAAAlwSFlzAAAOTQAADpwB3vacVwAAAA5JREFUCJlj2CLHwHodAATjAa+k" + "lTE5AAAAAElFTkSuQmCC"; + std::vector png; + fromBase64(png, base64); + + std::vector image; + unsigned width, height; + unsigned error = lodepng::decode(image, width, height, png, LCT_PALETTE, 8); + ASSERT_EQUALS(0, error); + ASSERT_EQUALS(2, width); + ASSERT_EQUALS(2, height); + ASSERT_EQUALS(180, image[0]); + ASSERT_EQUALS(30, image[1]); + ASSERT_EQUALS(5, image[2]); + ASSERT_EQUALS(215, image[3]); +} + +//2-bit palette +void testPaletteToPaletteDecode2() { + std::cout << "testPaletteToPaletteDecode2" << std::endl; + std::string base64 = "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgAgMAAAAOFJJnAAAADFBMVEX/AAAA/wAAAP/////7AGD2AAAAE0lEQVR4AWMQhAKG3VCALDIqAgDl2WYBCQHY9gAAAABJRU5ErkJggg=="; + std::vector png; + fromBase64(png, base64); + + std::vector image; + unsigned width, height; + unsigned error = lodepng::decode(image, width, height, png, LCT_PALETTE, 8); + ASSERT_EQUALS(0, error); + ASSERT_EQUALS(32, width); + ASSERT_EQUALS(32, height); + ASSERT_EQUALS(0, image[0]); + ASSERT_EQUALS(1, image[1]); + + //Now add a user-specified output palette, that differs from the input palette. That should give error 82. + LodePNGState state; + lodepng_state_init(&state); + state.info_raw.colortype = LCT_PALETTE; + state.info_raw.bitdepth = 8; + lodepng_palette_add(&state.info_raw, 0, 0, 0, 255); + lodepng_palette_add(&state.info_raw, 1, 1, 1, 255); + lodepng_palette_add(&state.info_raw, 2, 2, 2, 255); + lodepng_palette_add(&state.info_raw, 3, 3, 3, 255); + unsigned char* image2 = 0; + unsigned error2 = lodepng_decode(&image2, &width, &height, &state, &png[0], png.size()); + ASSERT_EQUALS(82, error2); + lodepng_state_cleanup(&state); + free(image2); +} + void doMain() { //PNG @@ -1809,6 +1880,8 @@ void doMain() testPredefinedFilters(); testFuzzing(); testWrongWindowSizeGivesError(); + testPaletteToPaletteDecode(); + testPaletteToPaletteDecode2(); //Colors testColorKeyConvert(); -- cgit v1.2.3