1 namespace gfx::bitmaps;
10 static void swap16pair(uint16 n[2]) {
21 //this function only swaps on big endian
22 static void swap32s(uint32 n[], uint count) {
23 unsigned char *i = (unsigned char*)n;
27 unsigned char *p = (i+=4);
41 static void ReadData(png_structp png, png_bytep bytes, png_size_t size)
43 File f = png_get_io_ptr(png);
44 f.Read(bytes, 1, (uint)size);
47 static void WriteData(png_structp png, png_bytep bytes, png_size_t size)
49 File f = png_get_io_ptr(png);
50 f.Write(bytes, 1, (uint)size);
53 static char * extensions[] = { "png", null };
55 class PNGFormat : BitmapFormat
57 class_property(extensions) = extensions;
59 bool Load(Bitmap bitmap, File f)
63 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, null, null, null);
67 png_infop info_ptr = png_create_info_struct(png_ptr);
70 if(!setjmp(png_jmpbuf(png_ptr)))
72 png_uint_32 width, height;
73 int bit_depth, color_type, interlace_type;
74 unsigned int sig_read = 0;
78 png_set_read_fn(png_ptr, f, ReadData);
80 png_set_sig_bytes(png_ptr, sig_read);
82 png_read_info(png_ptr, info_ptr);
83 channels = png_get_channels(png_ptr, info_ptr);
84 if(channels == 3 || channels == 4 || channels == 1 || channels == 2)
86 png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
87 &interlace_type, null, null);
88 numPasses = png_set_interlace_handling(png_ptr);
89 if(color_type == PNG_COLOR_TYPE_PALETTE)
91 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
94 png_set_tRNS_to_alpha(png_ptr);
98 png_set_palette_to_rgb(png_ptr);
100 else if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
101 png_set_tRNS_to_alpha(png_ptr);
103 if((result = bitmap.Allocate(null, (uint)width, (uint)height, 0, pixelFormatRGBA, false)))
111 byte * rowPtr = new byte[width * ((bit_depth == 16) ? 2 : 1)];
112 for (pass = 0; pass < numPasses; pass++)
115 for (y = 0; y < height; y++)
118 ColorRGBA * destPtr = ((ColorRGBA *)bitmap.picture) + y * bitmap.stride;
119 png_read_rows(png_ptr, &rowPtr, null, 1);
122 for(x = 0; x<width; x++)
123 destPtr[x] = ColorRGBA { rowPtr[x*2+0], rowPtr[x*2+0], rowPtr[x*2+0], 255 };
125 else if(bit_depth == 8)
127 for(x = 0; x<width; x++)
128 destPtr[x] = ColorRGBA { rowPtr[x], rowPtr[x], rowPtr[x], 255 };
130 else if(bit_depth == 1)
132 for(x = 0; x<width; x++)
135 uint mask = 1 << (7 - (x & 0x07));
136 byte b = (rowPtr[offset] & mask) ? 255 : 0;
137 destPtr[x] = ColorRGBA { b, b, b, 255 };
145 else if(channels == 2)
147 byte * rowPtr = new byte[width * 2 * ((bit_depth == 16) ? 2 : 1)];
148 for (pass = 0; pass < numPasses; pass++)
151 for (y = 0; y < height; y++)
154 ColorRGBA * destPtr = ((ColorRGBA *)bitmap.picture) + y * bitmap.stride;
155 png_read_rows(png_ptr, &rowPtr, null, 1);
158 for(x = 0; x<width; x++)
159 destPtr[x] = ColorRGBA { rowPtr[x*4], rowPtr[x*4], rowPtr[x*4], rowPtr[x*4+2] };
161 else if(bit_depth == 8)
163 for(x = 0; x<width; x++)
164 destPtr[x] = ColorRGBA { rowPtr[x*2], rowPtr[x*2], rowPtr[x*2], rowPtr[x*2+1] };
171 else if(channels == 3)
173 byte * rowPtr = new byte[width * 4 /*3*/ * ((bit_depth == 16) ? 2 : 1)];
174 for (pass = 0; pass < numPasses; pass++)
177 for (y = 0; y < height; y++)
180 ColorRGBA * destPtr = ((ColorRGBA *)bitmap.picture) + y * bitmap.stride;
181 png_read_rows(png_ptr, &rowPtr, null, 1);
184 for(x = 0; x<width; x++)
185 destPtr[x] = ColorRGBA { rowPtr[x*6+0], rowPtr[x*6+2], rowPtr[x*6+4], 255 };
189 for(x = 0; x<width; x++)
190 destPtr[x] = ColorRGBA { rowPtr[x*3+0], rowPtr[x*3+1], rowPtr[x*3+2], 255 };
197 else if(channels == 4)
201 // 16 bit per pixel not supported... Convert to 8 bit
202 byte * rowPtr = new byte[width * 4 * 2];
203 for (pass = 0; pass < numPasses; pass++)
206 for (y = 0; y < height; y++)
209 ColorRGBA * destPtr = ((ColorRGBA *)bitmap.picture) + y * bitmap.stride;
210 png_read_rows(png_ptr, &rowPtr, null, 1);
211 for(x = 0; x<width; x++)
212 destPtr[x] = ColorRGBA { rowPtr[x*8+0], rowPtr[x*8+2], rowPtr[x*8+4], rowPtr[x*8+6] };
220 for (pass = 0; pass < numPasses; pass++)
223 for (y = 0; y < height; y++)
225 byte * rowPtr = (byte *)(((ColorRGBA *)bitmap.picture) + y * bitmap.stride);
226 png_read_rows(png_ptr, &rowPtr, null, 1);
227 #ifdef __BIG_ENDIAN__
228 swap32s((uint32*)rowPtr, width);
238 png_read_end(png_ptr, info_ptr);
241 png_destroy_read_struct(&png_ptr, &info_ptr, null);
248 bool Save(Bitmap bitmap, char *filename, void * options)
251 Bitmap tempBitmap = null;
252 if(bitmap && bitmap.pixelFormat != pixelFormatRGBA)
254 tempBitmap = Bitmap { };
255 if(tempBitmap.Copy(bitmap) && tempBitmap.Convert(null, pixelFormatRGBA, null))
263 File f = FileOpen(filename, write);
266 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, null, null, null);
269 png_infop info_ptr = png_create_info_struct(png_ptr);
272 if(!setjmp(png_jmpbuf(png_ptr)))
276 png_set_write_fn(png_ptr, f, WriteData, null);
278 png_set_IHDR(png_ptr, info_ptr, bitmap.width, bitmap.height, 8, PNG_COLOR_TYPE_RGBA,
279 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
281 png_write_info(png_ptr, info_ptr);
283 for (y = 0; y < bitmap.height; y++)
285 byte * rowPtr = (byte *)(((uint *)bitmap.picture) + y * bitmap.stride);
286 png_write_rows(png_ptr, &rowPtr, 1);
289 png_write_end(png_ptr, info_ptr);
294 png_destroy_write_struct(&png_ptr, &info_ptr);
304 ColorAlpha * LoadPalette(char * fileName, char * type)
306 ColorAlpha * result = null;