1 /* 2 LodePNG Utils 3 4 Copyright (c) 2005-2020 Lode Vandevenne 5 6 This software is provided 'as-is', without any express or implied 7 warranty. In no event will the authors be held liable for any damages 8 arising from the use of this software. 9 10 Permission is granted to anyone to use this software for any purpose, 11 including commercial applications, and to alter it and redistribute it 12 freely, subject to the following restrictions: 13 14 1. The origin of this software must not be misrepresented; you must not 15 claim that you wrote the original software. If you use this software 16 in a product, an acknowledgment in the product documentation would be 17 appreciated but is not required. 18 19 2. Altered source versions must be plainly marked as such, and must not be 20 misrepresented as being the original software. 21 22 3. This notice may not be removed or altered from any source 23 distribution. 24 */ 25 26 /* 27 Extra C++ utilities for LodePNG, for convenience. 28 Not part of the stable API of lodepng, more loose separate utils. 29 */ 30 31 #ifndef LODEPNG_UTIL_H 32 #define LODEPNG_UTIL_H 33 34 #include <string> 35 #include <vector> 36 #include "lodepng.h" 37 38 namespace lodepng { 39 40 /* 41 Returns info from the header of the PNG by value, purely for convenience. 42 Does NOT check for errors. Returns bogus info if the PNG has an error. 43 Does not require cleanup of allocated memory because no palette or text chunk 44 info is in the LodePNGInfo object after checking only the header of the PNG. 45 */ 46 LodePNGInfo getPNGHeaderInfo(const std::vector<unsigned char>& png); 47 48 /* 49 Get the names and sizes of all chunks in the PNG file. 50 Returns 0 if ok, non-0 if error happened. 51 */ 52 unsigned getChunkInfo(std::vector<std::string>& names, std::vector<size_t>& sizes, 53 const std::vector<unsigned char>& png); 54 55 /* 56 Returns the names and full chunks (including the name and everything else that 57 makes up the chunk) for all chunks except IHDR, PLTE, IDAT and IEND. 58 It separates the chunks into 3 separate lists, representing the chunks between 59 certain critical chunks: 0: IHDR-PLTE, 1: PLTE-IDAT, 2: IDAT-IEND 60 Returns 0 if ok, non-0 if error happened. 61 */ 62 unsigned getChunks(std::vector<std::string> names[3], 63 std::vector<std::vector<unsigned char> > chunks[3], 64 const std::vector<unsigned char>& png); 65 66 /* 67 Inserts chunks into the given png file. The chunks must be fully encoded, 68 including length, type, content and CRC. 69 The array index determines where it goes: 70 0: between IHDR and PLTE, 1: between PLTE and IDAT, 2: between IDAT and IEND. 71 They're appended at the end of those locations within the PNG. 72 Returns 0 if ok, non-0 if error happened. 73 */ 74 unsigned insertChunks(std::vector<unsigned char>& png, 75 const std::vector<std::vector<unsigned char> > chunks[3]); 76 77 /* 78 Get the filtertypes of each scanline in this PNG file. 79 Returns 0 if ok, 1 if PNG decoding error happened. 80 81 For a non-interlaced PNG, it returns one filtertype per scanline, in order. 82 83 For interlaced PNGs, it returns a result as if it's not interlaced. It returns 84 one filtertype per scanline, in order. The values match pass 6 and 7 of the 85 Adam7 interlacing, alternating between the two, so that the values correspond 86 the most to their scanlines. 87 */ 88 unsigned getFilterTypes(std::vector<unsigned char>& filterTypes, const std::vector<unsigned char>& png); 89 90 /* 91 Get the filtertypes of each scanline in every interlace pass this PNG file. 92 Returns 0 if ok, 1 if PNG decoding error happened. 93 94 For a non-interlaced PNG, it returns one filtertype per scanline, in order, in 95 a single std::vector in filterTypes. 96 97 For an interlaced PNG, it returns 7 std::vectors in filterTypes, one for each 98 Adam7 pass. The amount of values per pass can be calculated as follows, where 99 w and h are the size of the image and all divisions are integer divisions: 100 pass 1: (h + 7) / 8 101 pass 2: w <= 4 ? 0 : (h + 7) / 8 102 pass 3: h <= 4 ? 0 : (h + 7) / 8 103 pass 4: w <= 2 ? 0 : (h + 3) / 4 104 pass 5: h <= 2 ? 0 : (h + 3) / 4 105 pass 6: w <= 1 ? 0 : (h + 1) / 2 106 pass 7: h <= 1 ? 0 : (h + 1) / 2 107 */ 108 unsigned getFilterTypesInterlaced(std::vector<std::vector<unsigned char> >& filterTypes, 109 const std::vector<unsigned char>& png); 110 111 /* 112 Returns the value of the i-th pixel in an image with 1, 2, 4 or 8-bit color. 113 E.g. if bits is 4 and i is 5, it returns the 5th nibble (4-bit group), which 114 is the second half of the 3th byte, in big endian (PNG's endian order). 115 */ 116 int getPaletteValue(const unsigned char* data, size_t i, int bits); 117 118 #ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS 119 120 /* Similar to convertRGBModel, but the 'to' model is sRGB. The pixel format 121 of in and out must be the same and is given by state_in->info_raw. An 122 error may occur if the pixel format cannot contain the new colors (e.g. palette) */ 123 unsigned convertToSrgb(unsigned char* out, const unsigned char* in, 124 unsigned w, unsigned h, 125 const LodePNGState* state_in); 126 127 /* Similar to convertRGBModel, but the 'from' model is sRGB. The pixel format 128 of in and out must be the same and is given by state_out->info_raw. An 129 error may occur if the pixel format cannot contain the new colors (e.g. palette) */ 130 unsigned convertFromSrgb(unsigned char* out, const unsigned char* in, 131 unsigned w, unsigned h, 132 const LodePNGState* state_out); 133 134 /* 135 Converts from one RGB model to another RGB model. 136 Similar to calling convertToXYZ followed by convertFromXYZ, but may be 137 more efficient and more precise (e.g. no computation needed when both models 138 are the same). See their documentation for more info. 139 140 Parameters: 141 142 *) out: output pixel data 143 *) in: input pixel data 144 *) w, h: image size 145 *) state_out: output RGB color model in state_out->info_png and byte format in state_out->info_raw. 146 *) state_in: output RGB color model in state_in->info_png and byte format in state_in->info_raw 147 *) return value: 0 if ok, positive value if error 148 *) rendering_intent: 1 for relative, 3 for absolute, should be relative for standard behavior. 149 See description at convertFromXYZ. 150 */ 151 unsigned convertRGBModel(unsigned char* out, const unsigned char* in, 152 unsigned w, unsigned h, 153 const LodePNGState* state_out, 154 const LodePNGState* state_in, 155 unsigned rendering_intent); 156 157 /* 158 Converts the RGB color to the absolute XYZ color space given the RGB color profile 159 chunks in the PNG info. 160 161 Color space here refers to the different possible RGB spaces with different 162 possible chromaticities or whitepoint and XYZ color from colorimetry, not the 163 LodePNGColorType that describes the byte based encoding. 164 165 You need this function only if the PNG could contain data in an arbitrary RGB 166 color space and you wish to output to a display or format that does not provide 167 color management for you (so you need to convert rather than pass on the profile 168 to it) but expects a certain RGB format (e.g. sRGB). See the background info below. 169 170 Supports the gAMA, cHRM, sRGB and iCCP colorimetry chunks. If no colometry chunks are present 171 (that is, in state->info_png, the fields gama_defined, chrm_defined, srgb_defined and 172 iccp_defined are all 0), it assumes the format is sRGB. 173 For more information, see the chunk specifications in the PNG specification. 174 175 Some background: 176 177 A PNG image contains RGB data inside, but this data may use a specific RGB model (by default sRGB but 178 different if colorimetry chunks are given). 179 The computer display and/or operating system can have another RGB model (typically sRGB, or wider gamut 180 or HDR formats). 181 182 The PNG chunks describe what format the data inside has, not the format of the display. To correctly 183 display a PNG image on a display, a conversion is needed from the PNG model to the display model if their 184 models differ. Some options to achieve that are: 185 *) If your use case already supports color management on its own, you can give it the RGB values straight from 186 the PNG image and give it the information from the cHRM, gAMA, sRGB and iCCP chunks (which you can find 187 in the LodePNGInfo), and the color management should then handle it correctly for you. You don't need 188 this function here in that case. 189 *) If your use case does not support color management, you may instead want to give it the RGB values in a 190 consistent color model, such as sRGB, but the PNG does not necessarily have it in this desired model. 191 In that case, use the function below (or a similar one from a CMS library if you prefer) to convert it to 192 the absolute color space XYZ, and then you can convert it to the target RGB with the counterpart convertFromXYZ 193 further below. 194 195 Parameters: 196 197 *) out: 4 floats per pixel, X,Y,Z,alpha color format, in range 0-1 (normally, not clipped if beyond), must 198 be allocated to have 4 * w * h floats available. 199 *) whitepoint: output argument, the whitepoint the original RGB data used, given in absolute XYZ. Needed for 200 relative rendering intents: give these values to counterpart function convertFromXYZ. 201 *) in: input RGB color, in byte format given by state->info_raw and RGB color profile given by info->info_png 202 *) w, h: image size 203 *) state (when using a LodePNG decode function that takes a LodePNGState parameter, can directly use that one): 204 state->info_png: PNG info with possibly an RGB color model in cHRM,gAMA and/or sRGB chunks 205 state->info_raw: byte format of in (amount of channels, bit depth) 206 *) return value: 0 if ok, positive value if error 207 */ 208 unsigned convertToXYZ(float* out, float whitepoint[3], 209 const unsigned char* in, unsigned w, unsigned h, 210 const LodePNGState* state); 211 212 /* 213 Same as convertToXYZ but takes floating point input. Slower. 214 The main black..white range in 0..1. Does not clip values that are outside that range. 215 */ 216 unsigned convertToXYZFloat(float* out, float whitepoint[3], const float* in, 217 unsigned w, unsigned h, const LodePNGState* state); 218 219 /* 220 Converts XYZ to RGB in the RGB color model given by info and byte format by mode_out. 221 If info has no coloremtry chunks, converts to sRGB. 222 Parameters: 223 *) out: output color in byte format given by state->info_raw and RGB color profile given 224 by info->info_png. Must have enough bytes allocated to contain pixels in the given byte format. 225 *) in: 4 floats per pixel, X,Y,Z,alpha color format, in range 0-1 (normally). 226 *) whitepoint: input argument, the original whitepoint in absolute XYZ that the pixel data 227 in "in" had back when it was in a previous RGB space. Needed to preserve the whitepoint 228 in the new target RGB space for relative rendering intent. 229 *) rendering_intent: the desired rendering intent, with numeric meaning matching the 230 values used by ICC: 0=perceptual, 1=relative, 2=saturation, 3=absolute. 231 Should be 1 for normal use cases, it adapts white to match that of different RGB 232 models which is the best practice. Using 3 may change the color of white and may 233 turn grayscale into colors of a certain tone. Using 0 and 2 will have the same 234 effect as 1 because using those requires more data than the matrix-based RGB profiles 235 supporetd here have. 236 *) w, h: image size 237 *) state: 238 state->info_png: PNG info with possibly an RGB color profile in cHRM,gAMA and/or sRGB chunks 239 state->info_raw: byte format of out (amount of channels, bit depth) 240 *) return value: 0 if ok, positive value if error 241 */ 242 unsigned convertFromXYZ(unsigned char* out, const float* in, unsigned w, unsigned h, 243 const LodePNGState* state, 244 const float whitepoint[3], unsigned rendering_intent); 245 246 /* 247 Same as convertFromXYZ but outputs the RGB colors in floating point. 248 The main black..white range in 0..1. Does not clip values that are outside that range. 249 */ 250 unsigned convertFromXYZFloat(float* out, const float* in, unsigned w, unsigned h, 251 const LodePNGState* state, 252 const float whitepoint[3], unsigned rendering_intent); 253 #endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ 254 255 /* 256 The information for extractZlibInfo. 257 */ 258 struct ZlibBlockInfo { 259 int btype; //block type (0-2) 260 size_t compressedbits; //size of compressed block in bits 261 size_t uncompressedbytes; //size of uncompressed block in bytes 262 263 // only filled in for block type 2 264 size_t treebits; //encoded tree size in bits 265 int hlit; //the HLIT value that was filled in for this tree 266 int hdist; //the HDIST value that was filled in for this tree 267 int hclen; //the HCLEN value that was filled in for this tree 268 std::vector<int> clcl; //19 code length code lengths (compressed tree's tree) 269 std::vector<int> treecodes; //N tree codes, with values 0-18. Values 17 or 18 are followed by the repetition value. 270 std::vector<int> litlenlengths; //288 code lengths for lit/len symbols 271 std::vector<int> distlengths; //32 code lengths for dist symbols 272 273 // only filled in for block types 1 or 2 274 std::vector<int> lz77_lcode; //LZ77 codes. 0-255: literals. 256: end symbol. 257-285: length code of length/dist pairs 275 // the next vectors have the same size as lz77_lcode, but an element only has meaningful value if lz77_lcode contains a length code. 276 std::vector<int> lz77_dcode; 277 std::vector<int> lz77_lbits; 278 std::vector<int> lz77_dbits; 279 std::vector<int> lz77_lvalue; 280 std::vector<int> lz77_dvalue; 281 size_t numlit; //number of lit codes in this block 282 size_t numlen; //number of len codes in this block 283 }; 284 285 //Extracts all info needed from a PNG file to reconstruct the zlib compression exactly. 286 void extractZlibInfo(std::vector<ZlibBlockInfo>& zlibinfo, const std::vector<unsigned char>& in); 287 288 } // namespace lodepng 289 290 #endif /*LODEPNG_UTIL_H inclusion guard*/ 291