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);
91 if(color_type == PNG_COLOR_TYPE_PALETTE)
93 png_set_palette_to_rgb(png_ptr);
97 if((result = bitmap.Allocate(null, (uint)width, (uint)height, 0, pixelFormatRGBA, false)))
105 byte * rowPtr = new byte[width * ((bit_depth == 16) ? 2 : 1)];
106 for (pass = 0; pass < numPasses; pass++)
109 for (y = 0; y < height; y++)
112 ColorRGBA * destPtr = ((ColorRGBA *)bitmap.picture) + y * bitmap.stride;
113 png_read_rows(png_ptr, &rowPtr, null, 1);
116 for(x = 0; x<width; x++)
117 destPtr[x] = ColorRGBA { rowPtr[x*2+0], rowPtr[x*2+0], rowPtr[x*2+0], 255 };
119 else if(bit_depth == 8)
121 for(x = 0; x<width; x++)
122 destPtr[x] = ColorRGBA { rowPtr[x], rowPtr[x], rowPtr[x], 255 };
124 else if(bit_depth == 1)
126 for(x = 0; x<width; x++)
129 uint mask = 1 << (7 - (x & 0x07));
130 byte b = (rowPtr[offset] & mask) ? 255 : 0;
131 destPtr[x] = ColorRGBA { b, b, b, 255 };
139 else if(channels == 2)
141 byte * rowPtr = new byte[width * 2 * ((bit_depth == 16) ? 2 : 1)];
142 for (pass = 0; pass < numPasses; pass++)
145 for (y = 0; y < height; y++)
148 ColorRGBA * destPtr = ((ColorRGBA *)bitmap.picture) + y * bitmap.stride;
149 png_read_rows(png_ptr, &rowPtr, null, 1);
152 for(x = 0; x<width; x++)
153 destPtr[x] = ColorRGBA { rowPtr[x*4], rowPtr[x*4], rowPtr[x*4], rowPtr[x*4+2] };
155 else if(bit_depth == 8)
157 for(x = 0; x<width; x++)
158 destPtr[x] = ColorRGBA { rowPtr[x*2], rowPtr[x*2], rowPtr[x*2], rowPtr[x*2+1] };
165 else if(channels == 3)
167 byte * rowPtr = new byte[width * 3 * ((bit_depth == 16) ? 2 : 1)];
168 for (pass = 0; pass < numPasses; pass++)
171 for (y = 0; y < height; y++)
174 ColorRGBA * destPtr = ((ColorRGBA *)bitmap.picture) + y * bitmap.stride;
175 png_read_rows(png_ptr, &rowPtr, null, 1);
178 for(x = 0; x<width; x++)
179 destPtr[x] = ColorRGBA { rowPtr[x*6+0], rowPtr[x*6+2], rowPtr[x*6+4], 255 };
183 for(x = 0; x<width; x++)
184 destPtr[x] = ColorRGBA { rowPtr[x*3+0], rowPtr[x*3+1], rowPtr[x*3+2], 255 };
191 else if(channels == 4)
195 // 16 bit per pixel not supported... Convert to 8 bit
196 byte * rowPtr = new byte[width * 4 * 2];
197 for (pass = 0; pass < numPasses; pass++)
200 for (y = 0; y < height; y++)
203 ColorRGBA * destPtr = ((ColorRGBA *)bitmap.picture) + y * bitmap.stride;
204 png_read_rows(png_ptr, &rowPtr, null, 1);
205 for(x = 0; x<width; x++)
206 destPtr[x] = ColorRGBA { rowPtr[x*8+0], rowPtr[x*8+2], rowPtr[x*8+4], rowPtr[x*8+6] };
214 for (pass = 0; pass < numPasses; pass++)
217 for (y = 0; y < height; y++)
219 byte * rowPtr = (byte *)(((ColorRGBA *)bitmap.picture) + y * bitmap.stride);
220 png_read_rows(png_ptr, &rowPtr, null, 1);
221 #ifdef __BIG_ENDIAN__
222 swap32s((uint32*)rowPtr, width);
232 png_read_end(png_ptr, info_ptr);
235 png_destroy_read_struct(&png_ptr, &info_ptr, null);
242 bool Save(Bitmap bitmap, char *filename, void * options)
245 Bitmap tempBitmap = null;
246 if(bitmap && bitmap.pixelFormat != pixelFormatRGBA)
248 tempBitmap = Bitmap { };
249 if(tempBitmap.Copy(bitmap) && tempBitmap.Convert(null, pixelFormatRGBA, null))
257 File f = FileOpen(filename, write);
260 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, null, null, null);
263 png_infop info_ptr = png_create_info_struct(png_ptr);
266 if(!setjmp(png_jmpbuf(png_ptr)))
270 png_set_write_fn(png_ptr, f, WriteData, null);
272 png_set_IHDR(png_ptr, info_ptr, bitmap.width, bitmap.height, 8, PNG_COLOR_TYPE_RGBA,
273 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
275 png_write_info(png_ptr, info_ptr);
277 for (y = 0; y < bitmap.height; y++)
279 byte * rowPtr = (byte *)(((uint *)bitmap.picture) + y * bitmap.stride);
280 png_write_rows(png_ptr, &rowPtr, 1);
283 png_write_end(png_ptr, info_ptr);
288 png_destroy_write_struct(&png_ptr, &info_ptr);
298 ColorAlpha * LoadPalette(char * fileName, char * type)
300 ColorAlpha * result = null;