wip II
[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                   numPasses = png_set_interlace_handling(png_ptr);
89                   if(color_type == PNG_COLOR_TYPE_PALETTE)
90                   {
91                      if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
92                      {
93                         channels = 4;
94                         png_set_tRNS_to_alpha(png_ptr);
95                      }
96                      else
97                         channels = 3;
98                      png_set_palette_to_rgb(png_ptr);                     
99                   }
100                   else if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
101                       png_set_tRNS_to_alpha(png_ptr);
102
103                   if((result = bitmap.Allocate(null, (uint)width, (uint)height, 0, pixelFormatRGBA, false)))
104                   {
105                      int pass;
106
107                      result = false;
108
109                      if(channels == 1)
110                      {
111                         byte * rowPtr = new byte[width * ((bit_depth == 16) ? 2 : 1)];
112                         for (pass = 0; pass < numPasses; pass++)
113                         {
114                            uint y;
115                            for (y = 0; y < height; y++)
116                            {
117                               uint x;
118                               ColorRGBA * destPtr = ((ColorRGBA *)bitmap.picture) + y * bitmap.stride;
119                               png_read_rows(png_ptr, &rowPtr, null, 1);
120                               if(bit_depth == 16)
121                               {
122                                  for(x = 0; x<width; x++)
123                                     destPtr[x] = ColorRGBA { rowPtr[x*2+0], rowPtr[x*2+0], rowPtr[x*2+0], 255 };
124                               }
125                               else if(bit_depth == 8)
126                               {
127                                  for(x = 0; x<width; x++)
128                                     destPtr[x] = ColorRGBA { rowPtr[x], rowPtr[x], rowPtr[x], 255 };
129                               }
130                               else if(bit_depth == 1)
131                               {
132                                  for(x = 0; x<width; x++)
133                                  {
134                                     int offset = x >> 3;
135                                     uint mask = 1 << (7 - (x & 0x07));
136                                     byte b = (rowPtr[offset] & mask) ? 255 : 0;
137                                     destPtr[x] = ColorRGBA { b, b, b, 255 };
138                                  }
139                               }
140                            }
141                         }
142                         delete rowPtr;
143                         result = true;
144                      }
145                      else if(channels == 2)
146                      {
147                         byte * rowPtr = new byte[width * 2 * ((bit_depth == 16) ? 2 : 1)];
148                         for (pass = 0; pass < numPasses; pass++)
149                         {
150                            uint y;
151                            for (y = 0; y < height; y++)
152                            {
153                               uint x;
154                               ColorRGBA * destPtr = ((ColorRGBA *)bitmap.picture) + y * bitmap.stride;
155                               png_read_rows(png_ptr, &rowPtr, null, 1);
156                               if(bit_depth == 16)
157                               {
158                                  for(x = 0; x<width; x++)
159                                     destPtr[x] = ColorRGBA { rowPtr[x*4], rowPtr[x*4], rowPtr[x*4], rowPtr[x*4+2] };
160                               }
161                               else if(bit_depth == 8)
162                               {
163                                  for(x = 0; x<width; x++)
164                                     destPtr[x] = ColorRGBA { rowPtr[x*2], rowPtr[x*2], rowPtr[x*2], rowPtr[x*2+1] };
165                               }
166                            }
167                         }
168                         delete rowPtr;
169                         result = true;
170                      }
171                      else if(channels == 3)
172                      {
173                         byte * rowPtr = new byte[width * 4 /*3*/ * ((bit_depth == 16) ? 2 : 1)];
174                         for (pass = 0; pass < numPasses; pass++)
175                         {
176                            uint y;
177                            for (y = 0; y < height; y++)
178                            {
179                               uint x;
180                               ColorRGBA * destPtr = ((ColorRGBA *)bitmap.picture) + y * bitmap.stride;
181                               png_read_rows(png_ptr, &rowPtr, null, 1);
182                               if(bit_depth == 16)
183                               {
184                                  for(x = 0; x<width; x++)
185                                     destPtr[x] = ColorRGBA { rowPtr[x*6+0], rowPtr[x*6+2], rowPtr[x*6+4], 255 };
186                               }
187                               else
188                               {
189                                  for(x = 0; x<width; x++)
190                                     destPtr[x] = ColorRGBA { rowPtr[x*3+0], rowPtr[x*3+1], rowPtr[x*3+2], 255 };
191                               }
192                            }
193                         }
194                         delete rowPtr;
195                         result = true;
196                      }
197                      else if(channels == 4)
198                      {
199                         if(bit_depth == 16)
200                         {
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++)
204                            {
205                               uint y;
206                               for (y = 0; y < height; y++)
207                               {
208                                  uint x;
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] };
213                               }
214                            }
215                            delete rowPtr;
216                            result = true;
217                         }
218                         else
219                         {
220                            for (pass = 0; pass < numPasses; pass++)
221                            {
222                               uint y;
223                               for (y = 0; y < height; y++)
224                               {
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);
229                                  #endif
230                               }
231                            }
232                            result = true;
233                         }
234                      }
235                   }
236                }
237
238                png_read_end(png_ptr, info_ptr);
239             }
240          }
241          png_destroy_read_struct(&png_ptr, &info_ptr, null);
242       }
243       if(!result)
244          bitmap.Free();
245       return result;
246    }
247
248    bool Save(Bitmap bitmap, char *filename, void * options)
249    {
250       bool result = false;
251       Bitmap tempBitmap = null;
252       if(bitmap && bitmap.pixelFormat != pixelFormatRGBA)
253       {
254          tempBitmap = Bitmap { };
255          if(tempBitmap.Copy(bitmap) && tempBitmap.Convert(null, pixelFormatRGBA, null))
256             bitmap = tempBitmap;
257          else
258             bitmap = null;
259       }
260
261       if(bitmap)
262       {
263          File f = FileOpen(filename, write);
264          if(f) 
265          {
266             png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, null, null, null);
267             if(png_ptr)
268             {
269                png_infop info_ptr = png_create_info_struct(png_ptr);
270                if(info_ptr)
271                {
272                   if(!setjmp(png_jmpbuf(png_ptr)))
273                   {
274                      uint y;
275
276                      png_set_write_fn(png_ptr, f, WriteData, null);
277
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);
280
281                      png_write_info(png_ptr, info_ptr);
282
283                      for (y = 0; y < bitmap.height; y++)
284                      {
285                         byte * rowPtr = (byte *)(((uint *)bitmap.picture) + y * bitmap.stride);
286                         png_write_rows(png_ptr, &rowPtr, 1);
287                      }
288
289                      png_write_end(png_ptr, info_ptr);
290
291                      result = true;
292                   }
293                }
294                png_destroy_write_struct(&png_ptr, &info_ptr);
295             }
296             delete f;
297          }
298       }
299       if(tempBitmap)
300          delete tempBitmap;
301       return result;   
302    }
303
304    ColorAlpha * LoadPalette(char * fileName, char * type)
305    {
306       ColorAlpha * result = null;
307       return result;
308    }
309 }