223 lines
6.7 KiB
C++
223 lines
6.7 KiB
C++
/*! \file
|
|
* \brief \ref PNG library
|
|
*
|
|
* The PNG library 'uPNG' was written by Sean Middleditch and Lode Vandevenne
|
|
* and modified for StuBS by Bernhard Heinloth.
|
|
*
|
|
* \see https://github.com/elanthis/upng
|
|
*
|
|
* uPNG -- derived from LodePNG version 20100808
|
|
*
|
|
* Copyright (c) 2005-2010 Lode Vandevenne
|
|
* Copyright (c) 2010 Sean Middleditch
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
/**! \brief Portable Network Graphics file format
|
|
*/
|
|
class PNG {
|
|
public:
|
|
enum error {
|
|
PNG_EOK = 0, ///< success (no error)
|
|
PNG_ENOMEM = 1, ///< memory allocation failed
|
|
PNG_ENOTFOUND = 2, ///< resource not found (file missing)
|
|
PNG_ENOTPNG = 3, ///< image data does not have a PNG header
|
|
PNG_EMALFORMED = 4, ///< image data is not a valid PNG image
|
|
PNG_EUNSUPPORTED = 5, ///< critical PNG chunk type is not supported
|
|
PNG_EUNINTERLACED = 6, ///< image interlacing is not supported
|
|
PNG_EUNFORMAT = 7, ///< image color format is not supported
|
|
PNG_EPARAM = 8, ///< invalid parameter to method call
|
|
PNG_EIOERROR = 9 ///< Filesystem issues
|
|
};
|
|
|
|
enum format {
|
|
BADFORMAT, ///< Invalid format
|
|
RGB8, ///< 24bit RGB (8bit per color)
|
|
RGB16, ///< 48bit RGB (16bit per color)
|
|
RGBA8, ///< 32bit RGB (including alpha channel)
|
|
RGBA16, ///< 64bit RGB (including alpha channel)
|
|
LUMINANCE1, ///< Monochrome (black-white)
|
|
LUMINANCE2, ///< four shades of gray (2bit gray scale)
|
|
LUMINANCE4, ///< 16 shades of gray (4bit gray scale)
|
|
LUMINANCE8, ///< 8bit gray scale
|
|
LUMINANCE_ALPHA1, ///< Monochrome (black-white) with alpha channel
|
|
LUMINANCE_ALPHA2, ///< 2bit gray scale with alpha channel
|
|
LUMINANCE_ALPHA4, ///< 4bit gray scale with alpha channel
|
|
LUMINANCE_ALPHA8 ///< 8bit gray scale with alpha channel
|
|
};
|
|
|
|
private:
|
|
enum color { COLOR_LUM = 0, COLOR_RGB = 2, COLOR_LUMA = 4, COLOR_RGBA = 6 };
|
|
|
|
unsigned width = 0;
|
|
unsigned height = 0;
|
|
|
|
enum color color_type;
|
|
unsigned color_depth;
|
|
enum format format = BADFORMAT;
|
|
|
|
unsigned char* buffer = nullptr;
|
|
unsigned long size = 0;
|
|
|
|
enum {
|
|
STATE_ERROR = -1,
|
|
STATE_DECODED = 0,
|
|
STATE_HEADER = 1,
|
|
STATE_NEW = 2
|
|
} state;
|
|
|
|
struct {
|
|
const unsigned char* buffer;
|
|
unsigned long size;
|
|
char owning;
|
|
} source;
|
|
|
|
struct huffman_tree {
|
|
unsigned* tree2d;
|
|
unsigned maxbitlen; ///< maximum number of bits a single code can get
|
|
unsigned
|
|
numcodes; ///< number of symbols in the alphabet = number of codes
|
|
};
|
|
|
|
void free_source();
|
|
static void huffman_tree_init(struct huffman_tree* tree, unsigned* buffer,
|
|
unsigned numcodes, unsigned maxbitlen);
|
|
void huffman_tree_create_lengths(struct huffman_tree* tree,
|
|
const unsigned* bitlen);
|
|
unsigned huffman_decode_symbol(const unsigned char* in, unsigned long* bp,
|
|
const struct huffman_tree* codetree,
|
|
unsigned long inlength);
|
|
void get_tree_inflate_dynamic(struct huffman_tree* codetree,
|
|
struct huffman_tree* codetreeD,
|
|
struct huffman_tree* codelengthcodetree,
|
|
const unsigned char* in, unsigned long* bp,
|
|
unsigned long inlength);
|
|
void inflate_huffman(unsigned char* out, unsigned long outsize,
|
|
const unsigned char* in, unsigned long* bp,
|
|
unsigned long* pos, unsigned long inlength,
|
|
unsigned btype);
|
|
void inflate_uncompressed(unsigned char* out, unsigned long outsize,
|
|
const unsigned char* in, unsigned long* bp,
|
|
unsigned long* pos, unsigned long inlength);
|
|
enum error uz_inflate_data(unsigned char* out, unsigned long outsize,
|
|
const unsigned char* in, unsigned long insize,
|
|
unsigned long inpos);
|
|
enum error uz_inflate(unsigned char* out, unsigned long outsize,
|
|
const unsigned char* in, unsigned long insize);
|
|
void unfilter_scanline(unsigned char* recon, const unsigned char* scanline,
|
|
const unsigned char* precon, unsigned long bytewidth,
|
|
unsigned char filterType, unsigned long length);
|
|
void unfilter(unsigned char* out, const unsigned char* in, unsigned w,
|
|
unsigned h, unsigned bpp);
|
|
static void remove_padding_bits(unsigned char* out, const unsigned char* in,
|
|
unsigned long olinebits,
|
|
unsigned long ilinebits, unsigned h);
|
|
void post_process_scanlines(unsigned char* out, unsigned char* in,
|
|
const PNG* info_png);
|
|
enum format determine_format();
|
|
|
|
protected:
|
|
enum error error;
|
|
unsigned error_line;
|
|
|
|
/*! \brief Extract header (image attributes)
|
|
*/
|
|
enum error header();
|
|
|
|
/*! \brief Decode whole image
|
|
*/
|
|
enum error decode();
|
|
|
|
public:
|
|
/*! \brief Load PNG image from memory
|
|
* \param buffer pointer to memory buffer
|
|
* \param size size of memory buffer
|
|
*/
|
|
PNG(const unsigned char* buffer, unsigned long size);
|
|
|
|
/*! \brief Free memory reserved for PNG image
|
|
*/
|
|
~PNG();
|
|
|
|
/*! \brief Width of image (pixels)
|
|
*/
|
|
unsigned get_width() const { return width; }
|
|
|
|
/*! \brief Height of image (pixels)
|
|
*/
|
|
unsigned get_height() const { return height; }
|
|
|
|
/*! \brief Bits per pixel
|
|
*/
|
|
unsigned get_bpp() const { return get_bitdepth() * get_components(); }
|
|
|
|
/*! \brief Depth of color (bits pro color channel)
|
|
*/
|
|
unsigned get_bitdepth() const { return color_depth; }
|
|
|
|
/*! \brief Number of components per pixel
|
|
*/
|
|
unsigned get_components() const {
|
|
switch (color_type) {
|
|
case COLOR_LUM:
|
|
return 1;
|
|
case COLOR_RGB:
|
|
return 3;
|
|
case COLOR_LUMA:
|
|
return 2;
|
|
case COLOR_RGBA:
|
|
return 4;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*! \brief Number of bytes per pixel
|
|
*/
|
|
unsigned get_pixelsize() const {
|
|
unsigned bits = get_bitdepth() * get_components();
|
|
bits += bits % 8;
|
|
return bits;
|
|
}
|
|
|
|
/*! \brief Retrieve the format
|
|
*/
|
|
enum format get_format() const { return format; }
|
|
|
|
/*! \brief Image buffer address
|
|
* \return Pointer to image buffer
|
|
*/
|
|
const unsigned char* get_buffer() {
|
|
decode();
|
|
return buffer;
|
|
}
|
|
|
|
/*! \brief Size of image buffer
|
|
* \return Total size of image buffer in bytes
|
|
*/
|
|
unsigned get_size() {
|
|
decode();
|
|
return size;
|
|
}
|
|
};
|