From 1bdcf470b3416f24aefcb99bb4bba2fb0df9704d Mon Sep 17 00:00:00 2001 From: Lode Date: Sat, 9 Apr 2016 16:21:25 +0200 Subject: color key and file handling --- lodepng.cpp | 120 +++++++++++++++++++++++++++++++++------------------ lodepng.h | 4 +- lodepng_unittest.cpp | 42 +++++++++++++++++- 3 files changed, 121 insertions(+), 45 deletions(-) diff --git a/lodepng.cpp b/lodepng.cpp index 0fca1a9..6132ae5 100644 --- a/lodepng.cpp +++ b/lodepng.cpp @@ -1,5 +1,5 @@ /* -LodePNG version 20160124 +LodePNG version 20160409 Copyright (c) 2005-2016 Lode Vandevenne @@ -30,19 +30,16 @@ Rename this file to lodepng.cpp to use it for C++, or to lodepng.c to use it for #include "lodepng.h" +#include #include #include -#ifdef LODEPNG_COMPILE_CPP -#include -#endif /*LODEPNG_COMPILE_CPP*/ - #if defined(_MSC_VER) && (_MSC_VER >= 1310) /*Visual Studio: A few warning types are not desired here.*/ #pragma warning( disable : 4244 ) /*implicit conversions: not warned by gcc -Wall -Wextra and requires too much casts*/ #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 = "20160124"; +const char* LODEPNG_VERSION_STRING = "20160409"; /* This source file is built up in the following large parts. The code sections @@ -350,31 +347,53 @@ static void lodepng_add32bitInt(ucvector* buffer, unsigned value) #ifdef LODEPNG_COMPILE_DISK -unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename) +/* returns negative value on error. This should be pure C compatible, so no fstat. */ +static long lodepng_filesize(const char* filename) { FILE* file; long size; + file = fopen(filename, "rb"); + if(!file) return -1; - /*provide some proper output values if error will happen*/ - *out = 0; - *outsize = 0; + if(fseek(file, 0, SEEK_END) != 0) + { + fclose(file); + return -1; + } + + size = ftell(file); + /* It may give LONG_MAX as directory size, this is invalid for us. */ + if(size == LONG_MAX) size = -1; + + fclose(file); + return size; +} +/* load file into buffer that already has the correct allocated size. Returns error code.*/ +static unsigned lodepng_buffer_file(unsigned char* out, size_t size, const char* filename) +{ + FILE* file; + size_t readsize; file = fopen(filename, "rb"); if(!file) return 78; - /*get filesize:*/ - fseek(file , 0 , SEEK_END); - size = ftell(file); - rewind(file); + readsize = fread(out, 1, size, file); + fclose(file); + + if (readsize != size) return 78; + return 0; +} + +unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename) +{ + long size = lodepng_filesize(filename); + if (size < 0) return 78; + *outsize = (size_t)size; - /*read contents of the file into the vector*/ - *outsize = 0; *out = (unsigned char*)lodepng_malloc((size_t)size); - if(size && (*out)) (*outsize) = fread(*out, 1, (size_t)size, file); + if(!(*out) && size > 0) return 83; /*the above malloc failed*/ - fclose(file); - if(!(*out) && size) return 83; /*the above malloc failed*/ - return 0; + return lodepng_buffer_file(*out, (size_t)size, filename); } /*write given buffer to the file, overwriting the file, it doesn't append to it.*/ @@ -2671,7 +2690,7 @@ unsigned lodepng_can_have_alpha(const LodePNGColorMode* info) size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color) { /*will not overflow for any color type if roughly w * h < 268435455*/ - int bpp = lodepng_get_bpp(color); + size_t bpp = lodepng_get_bpp(color); size_t n = w * h; return ((n / 8) * bpp) + ((n & 7) * bpp + 7) / 8; } @@ -2679,7 +2698,7 @@ size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* colo size_t lodepng_get_raw_size_lct(unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth) { /*will not overflow for any color type if roughly w * h < 268435455*/ - int bpp = lodepng_get_bpp_lct(colortype, bitdepth); + size_t bpp = lodepng_get_bpp_lct(colortype, bitdepth); size_t n = w * h; return ((n / 8) * bpp) + ((n & 7) * bpp + 7) / 8; } @@ -2691,7 +2710,7 @@ size_t lodepng_get_raw_size_lct(unsigned w, unsigned h, LodePNGColorType colorty static size_t lodepng_get_raw_size_idat(unsigned w, unsigned h, const LodePNGColorMode* color) { /*will not overflow for any color type if roughly w * h < 268435455*/ - int bpp = lodepng_get_bpp(color); + size_t bpp = lodepng_get_bpp(color); size_t line = ((w / 8) * bpp) + ((w & 7) * bpp + 7) / 8; return h * line; } @@ -3602,15 +3621,28 @@ unsigned lodepng_get_color_profile(LodePNGColorProfile* profile, alpha_done = 1; } } - if(alpha_done && numcolors_done && colored_done && bits_done) break; } + + if(profile->key && !profile->alpha) + { + for(i = 0; i != numpixels; ++i) + { + getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode); + if(a != 0 && r == profile->key_r && g == profile->key_g && b == profile->key_b) + { + /* Color key cannot be used if an opaque pixel also has that RGB color. */ + profile->alpha = 1; + alpha_done = 1; + } + } + } } else /* < 16-bit */ { + unsigned char r = 0, g = 0, b = 0, a = 0; for(i = 0; i != numpixels; ++i) { - unsigned char r = 0, g = 0, b = 0, a = 0; getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode); if(!bits_done && profile->bits < 8) @@ -3675,6 +3707,20 @@ unsigned lodepng_get_color_profile(LodePNGColorProfile* profile, if(alpha_done && numcolors_done && colored_done && bits_done) break; } + if(profile->key && !profile->alpha) + { + for(i = 0; i != numpixels; ++i) + { + getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode); + if(a != 0 && r == profile->key_r && g == profile->key_g && b == profile->key_b) + { + /* Color key cannot be used if an opaque pixel also has that RGB color. */ + profile->alpha = 1; + alpha_done = 1; + } + } + } + /*make the profile's key always 16-bit for consistency - repeat each byte twice*/ profile->key_r += (profile->key_r << 8); profile->key_g += (profile->key_g << 8); @@ -4718,7 +4764,7 @@ unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h, const u unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename, LodePNGColorType colortype, unsigned bitdepth) { - unsigned char* buffer; + unsigned char* buffer = 0; size_t buffersize; unsigned error; error = lodepng_load_file(&buffer, &buffersize, filename); @@ -5942,28 +5988,16 @@ namespace lodepng #ifdef LODEPNG_COMPILE_DISK unsigned load_file(std::vector& buffer, const std::string& filename) { - std::ifstream file(filename.c_str(), std::ios::in|std::ios::binary|std::ios::ate); - if(!file) return 78; - - /*get filesize*/ - std::streamsize size = 0; - if(file.seekg(0, std::ios::end).good()) size = file.tellg(); - if(file.seekg(0, std::ios::beg).good()) size -= file.tellg(); - - /*read contents of the file into the vector*/ - buffer.resize(size_t(size)); - if(size > 0) file.read((char*)(&buffer[0]), size); - - return 0; /* OK */ + long size = lodepng_filesize(filename.c_str()); + if(size < 0) return 78; + buffer.resize((size_t)size); + return size == 0 ? 0 : lodepng_buffer_file(&buffer[0], (size_t)size, filename.c_str()); } /*write given buffer to the file, overwriting the file, it doesn't append to it.*/ unsigned save_file(const std::vector& buffer, const std::string& filename) { - std::ofstream file(filename.c_str(), std::ios::out|std::ios::binary); - if(!file) return 79; - file.write(buffer.empty() ? 0 : (char*)&buffer[0], std::streamsize(buffer.size())); - return 0; + return lodepng_save_file(buffer.empty() ? 0 : &buffer[0], buffer.size(), filename.c_str()); } #endif /* LODEPNG_COMPILE_DISK */ diff --git a/lodepng.h b/lodepng.h index 9ecedd1..33f1051 100644 --- a/lodepng.h +++ b/lodepng.h @@ -1,5 +1,5 @@ /* -LodePNG version 20160124 +LodePNG version 20160409 Copyright (c) 2005-2016 Lode Vandevenne @@ -1607,6 +1607,8 @@ yyyymmdd. Some changes aren't backwards compatible. Those are indicated with a (!) symbol. +*) 09 apr 2016: Fixed colorkey usage detection, and better file loading (within + the limits of pure C90). *) 08 dec 2015: Made load_file function return error if file can't be opened. *) 24 okt 2015: Bugfix with decoding to palette output. *) 18 apr 2015: Boundary PM instead of just package-merge for faster encoding. diff --git a/lodepng_unittest.cpp b/lodepng_unittest.cpp index 8259db5..fcfea54 100644 --- a/lodepng_unittest.cpp +++ b/lodepng_unittest.cpp @@ -1,7 +1,7 @@ /* LodePNG Unit Test -Copyright (c) 2005-2015 Lode Vandevenne +Copyright (c) 2005-2016 Lode Vandevenne This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -608,6 +608,45 @@ void testColor(int r, int g, int b, int a) testSinglePixel(r, g, b, a); } +// Tests combinations of various colors in different orders +void testFewColors() +{ + std::cout << "codec test colors " << std::endl; + Image image; + image.width = 20; + image.height = 20; + image.colorType = LCT_RGBA; + image.bitDepth = 8; + image.data.resize(image.width * image.height * 4); + std::vector colors; + colors.push_back(0); colors.push_back(0); colors.push_back(0); colors.push_back(255); + colors.push_back(255); colors.push_back(255); colors.push_back(255); colors.push_back(255); + colors.push_back(128); colors.push_back(128); colors.push_back(128); colors.push_back(255); + colors.push_back(0); colors.push_back(0); colors.push_back(255); colors.push_back(255); + colors.push_back(255); colors.push_back(255); colors.push_back(255); colors.push_back(0); + colors.push_back(255); colors.push_back(255); colors.push_back(255); colors.push_back(1); + for(size_t i = 0; i < colors.size(); i += 4) + for(size_t j = 0; j < colors.size(); j += 4) + for(size_t k = 0; k < colors.size(); k += 4) + for(size_t l = 0; l < colors.size(); l += 4) + { + for(size_t c = 0; c < 4; c++) + { + /*image.data[0 + c] = colors[i + c]; + image.data[4 + c] = colors[j + c]; + image.data[8 + c] = colors[k + c];*/ + for(unsigned y = 0; y < image.height; y++) + for(unsigned x = 0; x < image.width; x++) + { + image.data[y * image.width * 4 + x * 4 + c] = (x ^ y) ? colors[i + c] : colors[j + c]; + } + image.data[c] = colors[k + c]; + image.data[image.data.size() - 4 + c] = colors[l + c]; + } + doCodecTest(image); + } +} + void testSize(unsigned w, unsigned h) { std::cout << "codec test size " << w << " " << h << std::endl; @@ -1921,6 +1960,7 @@ void doMain() testPaletteToPaletteDecode2(); //Colors + testFewColors(); testColorKeyConvert(); testColorConvert(); testColorConvert2(); -- cgit v1.2.3