14 #include <ext/libpng/png.h>
19 using std::unique_ptr;
29 void PNGTextureReader::readDataFromMemory(png_structp png_ptr, png_bytep outBytes, png_size_t outBytesToRead) {
30 auto io_ptr = png_get_io_ptr(png_ptr);
31 if (io_ptr ==
nullptr)
return;
34 pngInputStream->
readBytes((int8_t*)outBytes, outBytesToRead);
43 pngInputStream.
readBytes((int8_t*)sig,
sizeof(sig));
44 if (png_sig_cmp(sig, 0, 8)) {
49 auto png = png_create_read_struct(PNG_LIBPNG_VER_STRING,
nullptr,
nullptr,
nullptr);
53 auto info = png_create_info_struct(png);
54 if (info ==
nullptr) {
55 png_destroy_read_struct(&png,
nullptr,
nullptr);
63 if (setjmp(png_jmpbuf(png))) {
64 png_destroy_read_struct(&png, &info,
nullptr);
69 png_set_sig_bytes(png,
sizeof(sig));
72 png_read_info(png, info);
75 width = png_get_image_width(png, info);
76 height = png_get_image_height(png, info);
80 switch(png_get_color_type(png, info)) {
81 case PNG_COLOR_TYPE_GRAY:
86 case PNG_COLOR_TYPE_GRAY_ALPHA:
91 case PNG_COLOR_TYPE_PALETTE:
95 if (png_get_valid(png, info, PNG_INFO_tRNS)) {
98 bytesPerPixel = alpha?4:3;
101 case PNG_COLOR_TYPE_RGB:
106 case PNG_COLOR_TYPE_RGBA:
113 png_destroy_read_struct(&png, &info,
nullptr);
119 png_destroy_read_struct(&png, &info,
nullptr);
132 unsigned char sig[8];
133 pngInputStream.
readBytes((int8_t*)sig,
sizeof(sig));
134 if (png_sig_cmp(sig, 0, 8)) {
139 auto png = png_create_read_struct(PNG_LIBPNG_VER_STRING,
nullptr,
nullptr,
nullptr);
140 if (png ==
nullptr) {
143 auto info = png_create_info_struct(png);
144 if (info ==
nullptr) {
145 png_destroy_read_struct(&png,
nullptr,
nullptr);
153 if (setjmp(png_jmpbuf(png))) {
154 png_destroy_read_struct(&png, &info,
nullptr);
159 png_set_sig_bytes(png,
sizeof(sig));
162 png_read_info(png, info);
165 auto width = png_get_image_width(png, info);
166 auto height = png_get_image_height(png, info);
169 if (png_get_bit_depth(png, info) < 8) png_set_packing(png);
170 if (png_get_bit_depth(png, info) == 16) png_set_strip_16(png);
173 auto bytesPerPixel = -1;
174 switch(png_get_color_type(png, info)) {
175 case PNG_COLOR_TYPE_GRAY:
178 png_set_gray_to_rgb(png);
181 case PNG_COLOR_TYPE_GRAY_ALPHA:
184 png_set_gray_to_rgb(png);
187 case PNG_COLOR_TYPE_PALETTE:
191 if (png_get_valid(png, info, PNG_INFO_tRNS)) {
193 png_set_tRNS_to_alpha(png);
195 bytesPerPixel = alpha?4:3;
199 case PNG_COLOR_TYPE_RGB:
204 case PNG_COLOR_TYPE_RGBA:
211 png_destroy_read_struct(&png, &info,
nullptr);
217 png_set_interlace_handling(png);
218 png_read_update_info(png, info);
221 auto success =
false;
222 auto rowPtrs =
new(nothrow)png_bytep[height];
223 if (rowPtrs !=
nullptr) {
227 auto bufferPtr = (uint8_t*)textureByteBuffer.
getBuffer();
228 for(
auto i = 0; i < height; i++) {
229 rowPtrs[i] = bufferPtr;
230 bufferPtr += width * bytesPerPixel;
236 png_read_image(png, rowPtrs);
237 png_read_end(png,
nullptr);
244 png_destroy_read_struct(&png, &info,
nullptr);
253 uint8_t bytesPerPixel;
254 if (
readHeader(pngData, width, height, bytesPerPixel) ==
false) {
255 Console::println(
"PNGTextureReader::read(): " + idPrefix + textureId +
": Could not read PNG header");
259 auto textureWidth = width;
260 auto textureHeight = height;
261 if (powerOfTwo ==
true) {
263 while (textureWidth < width) textureWidth*= 2;
265 while (textureHeight < height) textureHeight*= 2;
266 if (textureWidth != width || textureHeight != height) {
267 auto textureByteBuffer =
ByteBuffer(width * height * bytesPerPixel);
268 if (
read(pngData, textureByteBuffer) ==
false) {
269 Console::println(
"PNGTextureReader::read(): " + idPrefix + textureId +
": Could not read PNG bitmap data");
272 Console::println(
"PNGTextureReader::read(): " + idPrefix + textureId +
": scaling to fit power of 2: " + to_string(width) +
"x" + to_string(height) +
" --> " + to_string(textureWidth) +
"x" + to_string(textureHeight));
273 auto textureByteBufferScaled =
ByteBuffer(textureWidth * textureHeight * bytesPerPixel);
274 auto textureYIncrement = (float)textureHeight / (
float)height;
275 auto textureYPixelRest = 0.0f;
277 for (
auto y = 0; y < height; y++) {
278 for (
auto i = 0; i < (int)textureYIncrement + (
int)textureYPixelRest; i++) {
282 textureYPixelRest-= (int)textureYPixelRest;
283 textureYPixelRest+= textureYIncrement - (int)textureYIncrement;
286 while (textureY < textureHeight) {
297 idPrefix + textureId,
305 textureByteBufferScaled
309 return texture.release();
320 idPrefix + textureId,
332 return texture.release();
static TextureFormat getRGBFormatByPixelBitsPerPixel(int bpp)
Return RGB/A texture format by bits per pixel.
static TextureFormat getPNGFormatByPixelBitsPerPixel(int bpp)
Return PNG RGB/A texture format by bits per pixel.
static TextureDepth getRGBDepthByPixelBitsPerPixel(int bpp)
Return RGB/A texture depth by bits per pixel.
void readBytes(int8_t *outBytes, int32_t outBytesToRead)
Read bytes.
PNG texture reader class.
static bool read(const vector< uint8_t > &pngData, ByteBuffer &textureByteBuffer)
Read PNG from memory into texture byte buffer.
static void readDataFromMemory(png_structp png_ptr, png_bytep outBytes, png_size_t outBytesToRead)
Read PNG data from memory.
static bool readHeader(const vector< uint8_t > &pngData, int &width, int &height, uint8_t &bytesPerPixel)
Read PNG header from memory.
static void scaleTextureLine(const ByteBuffer &pixelByteBuffer, ByteBuffer &pixelByteBufferScaled, int width, int textureWidth, int bytesPerPixel, int y)
Scales a texture line.
const uint8_t * getBuffer() const
virtual void releaseReference()
Releases a reference, thus decrementing the counter and delete it if reference counter is zero.
virtual void acquireReference()
Acquires a reference, incrementing the counter.