Permalink
Cannot retrieve contributors at this time
290 lines (245 sloc)
13.4 KB
/* | |
LodePNG Utils | |
Copyright (c) 2005-2020 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 | |
arising from the use of this software. | |
Permission is granted to anyone to use this software for any purpose, | |
including commercial applications, and to alter it and redistribute it | |
freely, subject to the following restrictions: | |
1. The origin of this software must not be misrepresented; you must not | |
claim that you wrote the original software. If you use this software | |
in a product, an acknowledgment in the product documentation would be | |
appreciated but is not required. | |
2. Altered source versions must be plainly marked as such, and must not be | |
misrepresented as being the original software. | |
3. This notice may not be removed or altered from any source | |
distribution. | |
*/ | |
/* | |
Extra C++ utilities for LodePNG, for convenience. | |
Not part of the stable API of lodepng, more loose separate utils. | |
*/ | |
#ifndef LODEPNG_UTIL_H | |
#define LODEPNG_UTIL_H | |
#include <string> | |
#include <vector> | |
#include "lodepng.h" | |
namespace lodepng { | |
/* | |
Returns info from the header of the PNG by value, purely for convenience. | |
Does NOT check for errors. Returns bogus info if the PNG has an error. | |
Does not require cleanup of allocated memory because no palette or text chunk | |
info is in the LodePNGInfo object after checking only the header of the PNG. | |
*/ | |
LodePNGInfo getPNGHeaderInfo(const std::vector<unsigned char>& png); | |
/* | |
Get the names and sizes of all chunks in the PNG file. | |
Returns 0 if ok, non-0 if error happened. | |
*/ | |
unsigned getChunkInfo(std::vector<std::string>& names, std::vector<size_t>& sizes, | |
const std::vector<unsigned char>& png); | |
/* | |
Returns the names and full chunks (including the name and everything else that | |
makes up the chunk) for all chunks except IHDR, PLTE, IDAT and IEND. | |
It separates the chunks into 3 separate lists, representing the chunks between | |
certain critical chunks: 0: IHDR-PLTE, 1: PLTE-IDAT, 2: IDAT-IEND | |
Returns 0 if ok, non-0 if error happened. | |
*/ | |
unsigned getChunks(std::vector<std::string> names[3], | |
std::vector<std::vector<unsigned char> > chunks[3], | |
const std::vector<unsigned char>& png); | |
/* | |
Inserts chunks into the given png file. The chunks must be fully encoded, | |
including length, type, content and CRC. | |
The array index determines where it goes: | |
0: between IHDR and PLTE, 1: between PLTE and IDAT, 2: between IDAT and IEND. | |
They're appended at the end of those locations within the PNG. | |
Returns 0 if ok, non-0 if error happened. | |
*/ | |
unsigned insertChunks(std::vector<unsigned char>& png, | |
const std::vector<std::vector<unsigned char> > chunks[3]); | |
/* | |
Get the filtertypes of each scanline in this PNG file. | |
Returns 0 if ok, 1 if PNG decoding error happened. | |
For a non-interlaced PNG, it returns one filtertype per scanline, in order. | |
For interlaced PNGs, it returns a result as if it's not interlaced. It returns | |
one filtertype per scanline, in order. The values match pass 6 and 7 of the | |
Adam7 interlacing, alternating between the two, so that the values correspond | |
the most to their scanlines. | |
*/ | |
unsigned getFilterTypes(std::vector<unsigned char>& filterTypes, const std::vector<unsigned char>& png); | |
/* | |
Get the filtertypes of each scanline in every interlace pass this PNG file. | |
Returns 0 if ok, 1 if PNG decoding error happened. | |
For a non-interlaced PNG, it returns one filtertype per scanline, in order, in | |
a single std::vector in filterTypes. | |
For an interlaced PNG, it returns 7 std::vectors in filterTypes, one for each | |
Adam7 pass. The amount of values per pass can be calculated as follows, where | |
w and h are the size of the image and all divisions are integer divisions: | |
pass 1: (h + 7) / 8 | |
pass 2: w <= 4 ? 0 : (h + 7) / 8 | |
pass 3: h <= 4 ? 0 : (h + 7) / 8 | |
pass 4: w <= 2 ? 0 : (h + 3) / 4 | |
pass 5: h <= 2 ? 0 : (h + 3) / 4 | |
pass 6: w <= 1 ? 0 : (h + 1) / 2 | |
pass 7: h <= 1 ? 0 : (h + 1) / 2 | |
*/ | |
unsigned getFilterTypesInterlaced(std::vector<std::vector<unsigned char> >& filterTypes, | |
const std::vector<unsigned char>& png); | |
/* | |
Returns the value of the i-th pixel in an image with 1, 2, 4 or 8-bit color. | |
E.g. if bits is 4 and i is 5, it returns the 5th nibble (4-bit group), which | |
is the second half of the 3th byte, in big endian (PNG's endian order). | |
*/ | |
int getPaletteValue(const unsigned char* data, size_t i, int bits); | |
#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS | |
/* Similar to convertRGBModel, but the 'to' model is sRGB. The pixel format | |
of in and out must be the same and is given by state_in->info_raw. An | |
error may occur if the pixel format cannot contain the new colors (e.g. palette) */ | |
unsigned convertToSrgb(unsigned char* out, const unsigned char* in, | |
unsigned w, unsigned h, | |
const LodePNGState* state_in); | |
/* Similar to convertRGBModel, but the 'from' model is sRGB. The pixel format | |
of in and out must be the same and is given by state_out->info_raw. An | |
error may occur if the pixel format cannot contain the new colors (e.g. palette) */ | |
unsigned convertFromSrgb(unsigned char* out, const unsigned char* in, | |
unsigned w, unsigned h, | |
const LodePNGState* state_out); | |
/* | |
Converts from one RGB model to another RGB model. | |
Similar to calling convertToXYZ followed by convertFromXYZ, but may be | |
more efficient and more precise (e.g. no computation needed when both models | |
are the same). See their documentation for more info. | |
Parameters: | |
*) out: output pixel data | |
*) in: input pixel data | |
*) w, h: image size | |
*) state_out: output RGB color model in state_out->info_png and byte format in state_out->info_raw. | |
*) state_in: output RGB color model in state_in->info_png and byte format in state_in->info_raw | |
*) return value: 0 if ok, positive value if error | |
*) rendering_intent: 1 for relative, 3 for absolute, should be relative for standard behavior. | |
See description at convertFromXYZ. | |
*/ | |
unsigned convertRGBModel(unsigned char* out, const unsigned char* in, | |
unsigned w, unsigned h, | |
const LodePNGState* state_out, | |
const LodePNGState* state_in, | |
unsigned rendering_intent); | |
/* | |
Converts the RGB color to the absolute XYZ color space given the RGB color profile | |
chunks in the PNG info. | |
Color space here refers to the different possible RGB spaces with different | |
possible chromaticities or whitepoint and XYZ color from colorimetry, not the | |
LodePNGColorType that describes the byte based encoding. | |
You need this function only if the PNG could contain data in an arbitrary RGB | |
color space and you wish to output to a display or format that does not provide | |
color management for you (so you need to convert rather than pass on the profile | |
to it) but expects a certain RGB format (e.g. sRGB). See the background info below. | |
Supports the gAMA, cHRM, sRGB and iCCP colorimetry chunks. If no colometry chunks are present | |
(that is, in state->info_png, the fields gama_defined, chrm_defined, srgb_defined and | |
iccp_defined are all 0), it assumes the format is sRGB. | |
For more information, see the chunk specifications in the PNG specification. | |
Some background: | |
A PNG image contains RGB data inside, but this data may use a specific RGB model (by default sRGB but | |
different if colorimetry chunks are given). | |
The computer display and/or operating system can have another RGB model (typically sRGB, or wider gamut | |
or HDR formats). | |
The PNG chunks describe what format the data inside has, not the format of the display. To correctly | |
display a PNG image on a display, a conversion is needed from the PNG model to the display model if their | |
models differ. Some options to achieve that are: | |
*) If your use case already supports color management on its own, you can give it the RGB values straight from | |
the PNG image and give it the information from the cHRM, gAMA, sRGB and iCCP chunks (which you can find | |
in the LodePNGInfo), and the color management should then handle it correctly for you. You don't need | |
this function here in that case. | |
*) If your use case does not support color management, you may instead want to give it the RGB values in a | |
consistent color model, such as sRGB, but the PNG does not necessarily have it in this desired model. | |
In that case, use the function below (or a similar one from a CMS library if you prefer) to convert it to | |
the absolute color space XYZ, and then you can convert it to the target RGB with the counterpart convertFromXYZ | |
further below. | |
Parameters: | |
*) out: 4 floats per pixel, X,Y,Z,alpha color format, in range 0-1 (normally, not clipped if beyond), must | |
be allocated to have 4 * w * h floats available. | |
*) whitepoint: output argument, the whitepoint the original RGB data used, given in absolute XYZ. Needed for | |
relative rendering intents: give these values to counterpart function convertFromXYZ. | |
*) in: input RGB color, in byte format given by state->info_raw and RGB color profile given by info->info_png | |
*) w, h: image size | |
*) state (when using a LodePNG decode function that takes a LodePNGState parameter, can directly use that one): | |
state->info_png: PNG info with possibly an RGB color model in cHRM,gAMA and/or sRGB chunks | |
state->info_raw: byte format of in (amount of channels, bit depth) | |
*) return value: 0 if ok, positive value if error | |
*/ | |
unsigned convertToXYZ(float* out, float whitepoint[3], | |
const unsigned char* in, unsigned w, unsigned h, | |
const LodePNGState* state); | |
/* | |
Same as convertToXYZ but takes floating point input. Slower. | |
The main black..white range in 0..1. Does not clip values that are outside that range. | |
*/ | |
unsigned convertToXYZFloat(float* out, float whitepoint[3], const float* in, | |
unsigned w, unsigned h, const LodePNGState* state); | |
/* | |
Converts XYZ to RGB in the RGB color model given by info and byte format by mode_out. | |
If info has no coloremtry chunks, converts to sRGB. | |
Parameters: | |
*) out: output color in byte format given by state->info_raw and RGB color profile given | |
by info->info_png. Must have enough bytes allocated to contain pixels in the given byte format. | |
*) in: 4 floats per pixel, X,Y,Z,alpha color format, in range 0-1 (normally). | |
*) whitepoint: input argument, the original whitepoint in absolute XYZ that the pixel data | |
in "in" had back when it was in a previous RGB space. Needed to preserve the whitepoint | |
in the new target RGB space for relative rendering intent. | |
*) rendering_intent: the desired rendering intent, with numeric meaning matching the | |
values used by ICC: 0=perceptual, 1=relative, 2=saturation, 3=absolute. | |
Should be 1 for normal use cases, it adapts white to match that of different RGB | |
models which is the best practice. Using 3 may change the color of white and may | |
turn grayscale into colors of a certain tone. Using 0 and 2 will have the same | |
effect as 1 because using those requires more data than the matrix-based RGB profiles | |
supporetd here have. | |
*) w, h: image size | |
*) state: | |
state->info_png: PNG info with possibly an RGB color profile in cHRM,gAMA and/or sRGB chunks | |
state->info_raw: byte format of out (amount of channels, bit depth) | |
*) return value: 0 if ok, positive value if error | |
*/ | |
unsigned convertFromXYZ(unsigned char* out, const float* in, unsigned w, unsigned h, | |
const LodePNGState* state, | |
const float whitepoint[3], unsigned rendering_intent); | |
/* | |
Same as convertFromXYZ but outputs the RGB colors in floating point. | |
The main black..white range in 0..1. Does not clip values that are outside that range. | |
*/ | |
unsigned convertFromXYZFloat(float* out, const float* in, unsigned w, unsigned h, | |
const LodePNGState* state, | |
const float whitepoint[3], unsigned rendering_intent); | |
#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/ | |
/* | |
The information for extractZlibInfo. | |
*/ | |
struct ZlibBlockInfo { | |
int btype; //block type (0-2) | |
size_t compressedbits; //size of compressed block in bits | |
size_t uncompressedbytes; //size of uncompressed block in bytes | |
// only filled in for block type 2 | |
size_t treebits; //encoded tree size in bits | |
int hlit; //the HLIT value that was filled in for this tree | |
int hdist; //the HDIST value that was filled in for this tree | |
int hclen; //the HCLEN value that was filled in for this tree | |
std::vector<int> clcl; //19 code length code lengths (compressed tree's tree) | |
std::vector<int> treecodes; //N tree codes, with values 0-18. Values 17 or 18 are followed by the repetition value. | |
std::vector<int> litlenlengths; //288 code lengths for lit/len symbols | |
std::vector<int> distlengths; //32 code lengths for dist symbols | |
// only filled in for block types 1 or 2 | |
std::vector<int> lz77_lcode; //LZ77 codes. 0-255: literals. 256: end symbol. 257-285: length code of length/dist pairs | |
// the next vectors have the same size as lz77_lcode, but an element only has meaningful value if lz77_lcode contains a length code. | |
std::vector<int> lz77_dcode; | |
std::vector<int> lz77_lbits; | |
std::vector<int> lz77_dbits; | |
std::vector<int> lz77_lvalue; | |
std::vector<int> lz77_dvalue; | |
size_t numlit; //number of lit codes in this block | |
size_t numlen; //number of len codes in this block | |
}; | |
//Extracts all info needed from a PNG file to reconstruct the zlib compression exactly. | |
void extractZlibInfo(std::vector<ZlibBlockInfo>& zlibinfo, const std::vector<unsigned char>& in); | |
} // namespace lodepng | |
#endif /*LODEPNG_UTIL_H inclusion guard*/ |