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 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
89 png_set_tRNS_to_alpha(png_ptr);
90 numPasses = png_set_interlace_handling(png_ptr);
92 if((result = bitmap.Allocate(null, width, height, 0, pixelFormatRGBA, false)))
100 byte * rowPtr = new byte[width * ((bit_depth == 16) ? 2 : 1)];
101 for (pass = 0; pass < numPasses; pass++)
104 for (y = 0; y < height; y++)
107 ColorRGBA * destPtr = ((ColorRGBA *)bitmap.picture) + y * bitmap.stride;
108 png_read_rows(png_ptr, &rowPtr, null, 1);
111 for(x = 0; x<width; x++)
112 destPtr[x] = ColorRGBA { rowPtr[x*2+0], rowPtr[x*2+0], rowPtr[x*2+0], 255 };
114 else if(bit_depth == 8)
116 for(x = 0; x<width; x++)
117 destPtr[x] = ColorRGBA { rowPtr[x], rowPtr[x], rowPtr[x], 255 };
119 else if(bit_depth == 1)
121 for(x = 0; x<width; x++)
124 uint mask = 1 << (7 - (x & 0x07));
125 byte b = (rowPtr[offset] & mask) ? 255 : 0;
126 destPtr[x] = ColorRGBA { b, b, b, 255 };
134 else if(channels == 2)
136 byte * rowPtr = new byte[width * 2 * ((bit_depth == 16) ? 2 : 1)];
137 for (pass = 0; pass < numPasses; pass++)
140 for (y = 0; y < height; y++)
143 ColorRGBA * destPtr = ((ColorRGBA *)bitmap.picture) + y * bitmap.stride;
144 png_read_rows(png_ptr, &rowPtr, null, 1);
147 for(x = 0; x<width; x++)
148 destPtr[x] = ColorRGBA { rowPtr[x*4], rowPtr[x*4], rowPtr[x*4], rowPtr[x*4+2] };
150 else if(bit_depth == 8)
152 for(x = 0; x<width; x++)
153 destPtr[x] = ColorRGBA { rowPtr[x*2], rowPtr[x*2], rowPtr[x*2], rowPtr[x*2+1] };
160 else if(channels == 3)
162 byte * rowPtr = new byte[width * 3 * ((bit_depth == 16) ? 2 : 1)];
163 for (pass = 0; pass < numPasses; pass++)
166 for (y = 0; y < height; y++)
169 ColorRGBA * destPtr = ((ColorRGBA *)bitmap.picture) + y * bitmap.stride;
170 png_read_rows(png_ptr, &rowPtr, null, 1);
173 for(x = 0; x<width; x++)
174 destPtr[x] = ColorRGBA { rowPtr[x*6+0], rowPtr[x*6+2], rowPtr[x*6+4], 255 };
178 for(x = 0; x<width; x++)
179 destPtr[x] = ColorRGBA { rowPtr[x*3+0], rowPtr[x*3+1], rowPtr[x*3+2], 255 };
186 else if(channels == 4)
190 // 16 bit per pixel not supported... Convert to 8 bit
191 byte * rowPtr = new byte[width * 4 * 2];
192 for (pass = 0; pass < numPasses; pass++)
195 for (y = 0; y < height; y++)
198 ColorRGBA * destPtr = ((ColorRGBA *)bitmap.picture) + y * bitmap.stride;
199 png_read_rows(png_ptr, &rowPtr, null, 1);
200 for(x = 0; x<width; x++)
201 destPtr[x] = ColorRGBA { rowPtr[x*8+0], rowPtr[x*8+2], rowPtr[x*8+4], rowPtr[x*8+6] };
209 for (pass = 0; pass < numPasses; pass++)
212 for (y = 0; y < height; y++)
214 byte * rowPtr = (byte *)(((ColorRGBA *)bitmap.picture) + y * bitmap.stride);
215 png_read_rows(png_ptr, &rowPtr, null, 1);
216 #ifdef __BIG_ENDIAN__
217 swap32s((uint32*)rowPtr, width);
227 png_read_end(png_ptr, info_ptr);
230 png_destroy_read_struct(&png_ptr, &info_ptr, null);
237 bool Save(Bitmap bitmap, char *filename, void * options)
240 Bitmap tempBitmap = null;
241 if(bitmap && bitmap.pixelFormat != pixelFormatRGBA)
243 tempBitmap = Bitmap { };
244 if(tempBitmap.Copy(bitmap) && tempBitmap.Convert(null, pixelFormatRGBA, null))
252 File f = FileOpen(filename, write);
255 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, null, null, null);
258 png_infop info_ptr = png_create_info_struct(png_ptr);
261 if(!setjmp(png_jmpbuf(png_ptr)))
265 png_set_write_fn(png_ptr, f, WriteData, null);
267 png_set_IHDR(png_ptr, info_ptr, bitmap.width, bitmap.height, 8, PNG_COLOR_TYPE_RGBA,
268 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
270 png_write_info(png_ptr, info_ptr);
272 for (y = 0; y < bitmap.height; y++)
274 byte * rowPtr = (byte *)(((uint *)bitmap.picture) + y * bitmap.stride);
275 png_write_rows(png_ptr, &rowPtr, 1);
278 png_write_end(png_ptr, info_ptr);
283 png_destroy_write_struct(&png_ptr, &info_ptr);
293 ColorAlpha * LoadPalette(char * fileName, char * type)
295 ColorAlpha * result = null;