1 namespace gfx::bitmaps;
5 #if !defined(__EMSCRIPTEN__) && !defined(__pnacl__)
12 static void swap16pair(uint16 n[2]) {
23 //this function only swaps on big endian
24 static void swap32s(uint32 n[], uint count) {
25 unsigned char *i = (unsigned char*)n;
29 unsigned char *p = (i+=4);
43 static void ReadData(png_structp png, png_bytep bytes, png_size_t size)
45 File f = png_get_io_ptr(png);
46 f.Read(bytes, 1, (uint)size);
49 static void WriteData(png_structp png, png_bytep bytes, png_size_t size)
51 File f = png_get_io_ptr(png);
52 f.Write(bytes, 1, (uint)size);
55 static const char * extensions[] = { "png", null };
57 class PNGFormat : BitmapFormat
59 class_property(extensions) = extensions;
61 bool Load(Bitmap bitmap, File f)
65 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, null, null, null);
69 png_infop info_ptr = png_create_info_struct(png_ptr);
72 if(!setjmp(png_jmpbuf(png_ptr)))
74 png_uint_32 width, height;
75 int bit_depth, color_type, interlace_type;
76 unsigned int sig_read = 0;
80 png_set_read_fn(png_ptr, f, ReadData);
82 png_set_sig_bytes(png_ptr, sig_read);
84 png_read_info(png_ptr, info_ptr);
85 channels = png_get_channels(png_ptr, info_ptr);
86 if(channels == 3 || channels == 4 || channels == 1 || channels == 2)
88 png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
89 &interlace_type, null, null);
90 numPasses = png_set_interlace_handling(png_ptr);
91 if(color_type == PNG_COLOR_TYPE_PALETTE)
93 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
96 png_set_tRNS_to_alpha(png_ptr);
100 png_set_palette_to_rgb(png_ptr);
102 else if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
103 png_set_tRNS_to_alpha(png_ptr);
105 if((result = bitmap.Allocate(null, (uint)width, (uint)height, 0, pixelFormatRGBA, false)))
113 byte * rowPtr = new byte[width * ((bit_depth == 16) ? 2 : 1)];
114 for (pass = 0; pass < numPasses; pass++)
117 for (y = 0; y < height; y++)
120 ColorRGBA * destPtr = ((ColorRGBA *)bitmap.picture) + y * bitmap.stride;
121 png_read_rows(png_ptr, &rowPtr, null, 1);
124 for(x = 0; x<width; x++)
125 destPtr[x] = ColorRGBA { rowPtr[x*2+0], rowPtr[x*2+0], rowPtr[x*2+0], 255 };
127 else if(bit_depth == 8)
129 for(x = 0; x<width; x++)
130 destPtr[x] = ColorRGBA { rowPtr[x], rowPtr[x], rowPtr[x], 255 };
132 else if(bit_depth == 1)
134 for(x = 0; x<width; x++)
137 uint mask = 1 << (7 - (x & 0x07));
138 byte b = (rowPtr[offset] & mask) ? 255 : 0;
139 destPtr[x] = ColorRGBA { b, b, b, 255 };
147 else if(channels == 2)
149 byte * rowPtr = new byte[width * 2 * ((bit_depth == 16) ? 2 : 1)];
150 for (pass = 0; pass < numPasses; pass++)
153 for (y = 0; y < height; y++)
156 ColorRGBA * destPtr = ((ColorRGBA *)bitmap.picture) + y * bitmap.stride;
157 png_read_rows(png_ptr, &rowPtr, null, 1);
160 for(x = 0; x<width; x++)
161 destPtr[x] = ColorRGBA { rowPtr[x*4], rowPtr[x*4], rowPtr[x*4], rowPtr[x*4+2] };
163 else if(bit_depth == 8)
165 for(x = 0; x<width; x++)
166 destPtr[x] = ColorRGBA { rowPtr[x*2], rowPtr[x*2], rowPtr[x*2], rowPtr[x*2+1] };
173 else if(channels == 3)
175 byte * rowPtr = new byte[width * 4 /*3*/ * ((bit_depth == 16) ? 2 : 1)];
176 for (pass = 0; pass < numPasses; pass++)
179 for (y = 0; y < height; y++)
182 ColorRGBA * destPtr = ((ColorRGBA *)bitmap.picture) + y * bitmap.stride;
183 png_read_rows(png_ptr, &rowPtr, null, 1);
186 for(x = 0; x<width; x++)
187 destPtr[x] = ColorRGBA { rowPtr[x*6+0], rowPtr[x*6+2], rowPtr[x*6+4], 255 };
191 for(x = 0; x<width; x++)
192 destPtr[x] = ColorRGBA { rowPtr[x*3+0], rowPtr[x*3+1], rowPtr[x*3+2], 255 };
199 else if(channels == 4)
203 // 16 bit per pixel not supported... Convert to 8 bit
204 byte * rowPtr = new byte[width * 4 * 2];
205 for (pass = 0; pass < numPasses; pass++)
208 for (y = 0; y < height; y++)
211 ColorRGBA * destPtr = ((ColorRGBA *)bitmap.picture) + y * bitmap.stride;
212 png_read_rows(png_ptr, &rowPtr, null, 1);
213 for(x = 0; x<width; x++)
214 destPtr[x] = ColorRGBA { rowPtr[x*8+0], rowPtr[x*8+2], rowPtr[x*8+4], rowPtr[x*8+6] };
222 for (pass = 0; pass < numPasses; pass++)
225 for (y = 0; y < height; y++)
227 byte * rowPtr = (byte *)(((ColorRGBA *)bitmap.picture) + y * bitmap.stride);
228 png_read_rows(png_ptr, &rowPtr, null, 1);
229 #ifdef __BIG_ENDIAN__
230 swap32s((uint32*)rowPtr, width);
240 png_read_end(png_ptr, info_ptr);
243 png_destroy_read_struct(&png_ptr, &info_ptr, null);
250 bool Save(Bitmap bitmap, const char *filename, void * options)
253 Bitmap tempBitmap = null;
254 if(bitmap && bitmap.pixelFormat != pixelFormatRGBA)
256 tempBitmap = Bitmap { };
257 if(tempBitmap.Copy(bitmap) && tempBitmap.Convert(null, pixelFormatRGBA, null))
265 File f = FileOpen(filename, write);
268 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, null, null, null);
271 png_infop info_ptr = png_create_info_struct(png_ptr);
274 if(!setjmp(png_jmpbuf(png_ptr)))
278 png_set_write_fn(png_ptr, f, WriteData, null);
280 png_set_IHDR(png_ptr, info_ptr, bitmap.width, bitmap.height, 8, PNG_COLOR_TYPE_RGBA,
281 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
283 png_write_info(png_ptr, info_ptr);
285 for (y = 0; y < bitmap.height; y++)
287 byte * rowPtr = (byte *)(((uint *)bitmap.picture) + y * bitmap.stride);
288 png_write_rows(png_ptr, &rowPtr, 1);
291 png_write_end(png_ptr, info_ptr);
296 png_destroy_write_struct(&png_ptr, &info_ptr);
306 ColorAlpha * LoadPalette(const char * fileName, const char * type)
308 ColorAlpha * result = null;
313 #endif // !defined(__EMSCRIPTEN__)