namespace gfx::bitmaps; #define _Noreturn import "Display" #define uint _uint #include "png.h" #undef uint #ifdef __BIG_ENDIAN__ static void swap16pair(uint16 n[2]) { char *p = (char*)n; char tmp; tmp = p[0]; p[0] = p[1]; p[1] = tmp; p += 2; tmp = p[0]; p[0] = p[1]; p[1] = tmp; } //this function only swaps on big endian static void swap32s(uint32 n[], uint count) { unsigned char *i = (unsigned char*)n; uint *o = n; uint32 tmp; while (count--) { unsigned char *p = (i+=4); tmp = 0; tmp |= (*--p) & 0xFF; tmp <<= 8; tmp |= (*--p) & 0xFF; tmp <<= 8; tmp |= (*--p) & 0xFF; tmp <<= 8; tmp |= (*--p) & 0xFF; *o++ = tmp; } } #endif static void ReadData(png_structp png, png_bytep bytes, png_size_t size) { File f = png_get_io_ptr(png); f.Read(bytes, 1, (uint)size); } static void WriteData(png_structp png, png_bytep bytes, png_size_t size) { File f = png_get_io_ptr(png); f.Write(bytes, 1, (uint)size); } static const char * extensions[] = { "png", null }; class PNGFormat : BitmapFormat { class_property(extensions) = extensions; bool Load(Bitmap bitmap, File f) { bool result = false; png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, null, null, null); if(png_ptr) { png_infop info_ptr = png_create_info_struct(png_ptr); if (info_ptr) { if(!setjmp(png_jmpbuf(png_ptr))) { png_uint_32 width, height; int bit_depth, color_type, interlace_type; unsigned int sig_read = 0; int numPasses; int channels; png_set_read_fn(png_ptr, f, ReadData); png_set_sig_bytes(png_ptr, sig_read); png_read_info(png_ptr, info_ptr); channels = png_get_channels(png_ptr, info_ptr); if(channels == 3 || channels == 4 || channels == 1 || channels == 2) { png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, null, null); numPasses = png_set_interlace_handling(png_ptr); if(color_type == PNG_COLOR_TYPE_PALETTE) { if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { channels = 4; png_set_tRNS_to_alpha(png_ptr); } else channels = 3; png_set_palette_to_rgb(png_ptr); } else if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); if((result = bitmap.Allocate(null, (uint)width, (uint)height, 0, pixelFormatRGBA, false))) { int pass; result = false; if(channels == 1) { byte * rowPtr = new byte[width * ((bit_depth == 16) ? 2 : 1)]; for (pass = 0; pass < numPasses; pass++) { uint y; for (y = 0; y < height; y++) { uint x; ColorRGBA * destPtr = ((ColorRGBA *)bitmap.picture) + y * bitmap.stride; png_read_rows(png_ptr, &rowPtr, null, 1); if(bit_depth == 16) { for(x = 0; x> 3; uint mask = 1 << (7 - (x & 0x07)); byte b = (rowPtr[offset] & mask) ? 255 : 0; destPtr[x] = ColorRGBA { b, b, b, 255 }; } } } } delete rowPtr; result = true; } else if(channels == 2) { byte * rowPtr = new byte[width * 2 * ((bit_depth == 16) ? 2 : 1)]; for (pass = 0; pass < numPasses; pass++) { uint y; for (y = 0; y < height; y++) { uint x; ColorRGBA * destPtr = ((ColorRGBA *)bitmap.picture) + y * bitmap.stride; png_read_rows(png_ptr, &rowPtr, null, 1); if(bit_depth == 16) { for(x = 0; x