compiler: Added (u)intsize to map to size_t; Updated C prototypes to use it; Fixed...
[sdk] / ecere / src / gfx / bitmaps / PNGFormat.ec
1 namespace gfx::bitmaps;
2
3 import "Display"
4
5 #define uint _uint
6 #include "png.h"
7 #undef uint
8
9 #ifdef __BIG_ENDIAN__
10 static void swap16pair(uint16 n[2]) {
11    char *p = (char*)n;
12    char tmp;
13    tmp = p[0];
14    p[0] = p[1];
15    p[1] = tmp;
16    p += 2;
17    tmp = p[0];
18    p[0] = p[1];
19    p[1] = tmp;
20 }
21 //this function only swaps on big endian
22 static void swap32s(uint32 n[], uint count) {
23    unsigned char *i = (unsigned char*)n;
24    uint *o = n;
25    uint32 tmp;
26    while (count--) {
27       unsigned char *p = (i+=4);
28       tmp = 0;
29       tmp |= (*--p) & 0xFF;
30       tmp <<= 8;
31       tmp |= (*--p) & 0xFF;
32       tmp <<= 8;
33       tmp |= (*--p) & 0xFF;
34       tmp <<= 8;
35       tmp |= (*--p) & 0xFF;
36       *o++ = tmp;
37    }
38 }
39 #endif
40
41 static void ReadData(png_structp png, png_bytep bytes, png_size_t size)
42 {
43    File f = png_get_io_ptr(png);
44    f.Read(bytes, 1, (uint)size);
45 }
46
47 static void WriteData(png_structp png, png_bytep bytes, png_size_t size)
48 {
49    File f = png_get_io_ptr(png);
50    f.Write(bytes, 1, (uint)size);
51 }
52
53 static char * extensions[] = { "png", null };
54
55 class PNGFormat : BitmapFormat
56 {
57    class_property(extensions) = extensions;
58
59    bool Load(Bitmap bitmap, File f)
60    {
61       bool result = false;
62
63       png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, null, null, null);
64
65       if(png_ptr)
66       {
67          png_infop info_ptr = png_create_info_struct(png_ptr);
68          if (info_ptr)
69          {
70             if(!setjmp(png_jmpbuf(png_ptr)))
71             {
72                png_uint_32 width, height;
73                int bit_depth, color_type, interlace_type;
74                unsigned int sig_read = 0;
75                int numPasses;
76                int channels;
77
78                png_set_read_fn(png_ptr, f, ReadData);
79
80                png_set_sig_bytes(png_ptr, sig_read);
81
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)
85                {            
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
92                   if((result = bitmap.Allocate(null, width, height, 0, pixelFormatRGBA, false)))
93                   {
94                      int pass;
95
96                      result = false;
97
98                      if(channels == 1)
99                      {
100                         byte * rowPtr = new byte[width * ((bit_depth == 16) ? 2 : 1)];
101                         for (pass = 0; pass < numPasses; pass++)
102                         {
103                            uint y;
104                            for (y = 0; y < height; y++)
105                            {
106                               uint x;
107                               ColorRGBA * destPtr = ((ColorRGBA *)bitmap.picture) + y * bitmap.stride;
108                               png_read_rows(png_ptr, &rowPtr, null, 1);
109                               if(bit_depth == 16)
110                               {
111                                  for(x = 0; x<width; x++)
112                                     destPtr[x] = ColorRGBA { rowPtr[x*2+0], rowPtr[x*2+0], rowPtr[x*2+0], 255 };
113                               }
114                               else if(bit_depth == 8)
115                               {
116                                  for(x = 0; x<width; x++)
117                                     destPtr[x] = ColorRGBA { rowPtr[x], rowPtr[x], rowPtr[x], 255 };
118                               }
119                               else if(bit_depth == 1)
120                               {
121                                  for(x = 0; x<width; x++)
122                                  {
123                                     int offset = x >> 3;
124                                     uint mask = 1 << (7 - (x & 0x07));
125                                     byte b = (rowPtr[offset] & mask) ? 255 : 0;
126                                     destPtr[x] = ColorRGBA { b, b, b, 255 };
127                                  }
128                               }
129                            }
130                         }
131                         delete rowPtr;
132                         result = true;
133                      }
134                      else if(channels == 2)
135                      {
136                         byte * rowPtr = new byte[width * 2 * ((bit_depth == 16) ? 2 : 1)];
137                         for (pass = 0; pass < numPasses; pass++)
138                         {
139                            uint y;
140                            for (y = 0; y < height; y++)
141                            {
142                               uint x;
143                               ColorRGBA * destPtr = ((ColorRGBA *)bitmap.picture) + y * bitmap.stride;
144                               png_read_rows(png_ptr, &rowPtr, null, 1);
145                               if(bit_depth == 16)
146                               {
147                                  for(x = 0; x<width; x++)
148                                     destPtr[x] = ColorRGBA { rowPtr[x*4], rowPtr[x*4], rowPtr[x*4], rowPtr[x*4+2] };
149                               }
150                               else if(bit_depth == 8)
151                               {
152                                  for(x = 0; x<width; x++)
153                                     destPtr[x] = ColorRGBA { rowPtr[x*2], rowPtr[x*2], rowPtr[x*2], rowPtr[x*2+1] };
154                               }
155                            }
156                         }
157                         delete rowPtr;
158                         result = true;
159                      }
160                      else if(channels == 3)
161                      {
162                         byte * rowPtr = new byte[width * 3 * ((bit_depth == 16) ? 2 : 1)];
163                         for (pass = 0; pass < numPasses; pass++)
164                         {
165                            uint y;
166                            for (y = 0; y < height; y++)
167                            {
168                               uint x;
169                               ColorRGBA * destPtr = ((ColorRGBA *)bitmap.picture) + y * bitmap.stride;
170                               png_read_rows(png_ptr, &rowPtr, null, 1);
171                               if(bit_depth == 16)
172                               {
173                                  for(x = 0; x<width; x++)
174                                     destPtr[x] = ColorRGBA { rowPtr[x*6+0], rowPtr[x*6+2], rowPtr[x*6+4], 255 };
175                               }
176                               else
177                               {
178                                  for(x = 0; x<width; x++)
179                                     destPtr[x] = ColorRGBA { rowPtr[x*3+0], rowPtr[x*3+1], rowPtr[x*3+2], 255 };
180                               }
181                            }
182                         }
183                         delete rowPtr;
184                         result = true;
185                      }
186                      else if(channels == 4)
187                      {
188                         if(bit_depth == 16)
189                         {
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++)
193                            {
194                               uint y;
195                               for (y = 0; y < height; y++)
196                               {
197                                  uint x;
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] };
202                               }
203                            }
204                            delete rowPtr;
205                            result = true;
206                         }
207                         else
208                         {
209                            for (pass = 0; pass < numPasses; pass++)
210                            {
211                               uint y;
212                               for (y = 0; y < height; y++)
213                               {
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);
218                                  #endif
219                               }
220                            }
221                            result = true;
222                         }
223                      }
224                   }
225                }
226
227                png_read_end(png_ptr, info_ptr);
228             }
229          }
230          png_destroy_read_struct(&png_ptr, &info_ptr, null);
231       }
232       if(!result)
233          bitmap.Free();
234       return result;
235    }
236
237    bool Save(Bitmap bitmap, char *filename, void * options)
238    {
239       bool result = false;
240       Bitmap tempBitmap = null;
241       if(bitmap && bitmap.pixelFormat != pixelFormatRGBA)
242       {
243          tempBitmap = Bitmap { };
244          if(tempBitmap.Copy(bitmap) && tempBitmap.Convert(null, pixelFormatRGBA, null))
245             bitmap = tempBitmap;
246          else
247             bitmap = null;
248       }
249
250       if(bitmap)
251       {
252          File f = FileOpen(filename, write);
253          if(f) 
254          {
255             png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, null, null, null);
256             if(png_ptr)
257             {
258                png_infop info_ptr = png_create_info_struct(png_ptr);
259                if(info_ptr)
260                {
261                   if(!setjmp(png_jmpbuf(png_ptr)))
262                   {
263                      uint y;
264
265                      png_set_write_fn(png_ptr, f, WriteData, null);
266
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);
269
270                      png_write_info(png_ptr, info_ptr);
271
272                      for (y = 0; y < bitmap.height; y++)
273                      {
274                         byte * rowPtr = (byte *)(((uint *)bitmap.picture) + y * bitmap.stride);
275                         png_write_rows(png_ptr, &rowPtr, 1);
276                      }
277
278                      png_write_end(png_ptr, info_ptr);
279
280                      result = true;
281                   }
282                }
283                png_destroy_write_struct(&png_ptr, &info_ptr);
284             }
285             delete f;
286          }
287       }
288       if(tempBitmap)
289          delete tempBitmap;
290       return result;   
291    }
292
293    ColorAlpha * LoadPalette(char * fileName, char * type)
294    {
295       ColorAlpha * result = null;
296       return result;
297    }
298 }