moreupdates
[synfig.git] / synfig-core / trunk / src / modules / mod_png / mptr_png.cpp
1 /*! ========================================================================
2 ** Synfig
3 ** ppm Target Module
4 ** $Id: mptr_png.cpp,v 1.1.1.1 2005/01/04 01:23:14 darco Exp $
5 **
6 ** Copyright (c) 2002 Robert B. Quattlebaum Jr.
7 **
8 ** This software and associated documentation
9 ** are CONFIDENTIAL and PROPRIETARY property of
10 ** the above-mentioned copyright holder.
11 **
12 ** You may not copy, print, publish, or in any
13 ** other way distribute this software without
14 ** a prior written agreement with
15 ** the copyright holder.
16 **
17 ** === N O T E S ===========================================================
18 **
19 ** ========================================================================= */
20
21 /*!
22 **  \todo Support 16 bit PNG files
23 **      \todo Support GAMMA correction
24 **      \todo Fix memory leaks
25 */
26
27 /* === H E A D E R S ======================================================= */
28
29 #ifdef USING_PCH
30 #       include "pch.h"
31 #else
32 #ifdef HAVE_CONFIG_H
33 #       include <config.h>
34 #endif
35
36 #include "mptr_png.h"
37 #include <synfig/importer.h>
38 #include <synfig/time.h>
39 #include <synfig/general.h>
40
41
42 #include <cstdio>
43 #include <algorithm>
44 #include <functional>
45 #endif
46
47 /* === M A C R O S ========================================================= */
48
49 using namespace synfig;
50 using namespace std;
51 using namespace etl;
52
53 #define PNG_CHECK_BYTES         8
54
55 /* === G L O B A L S ======================================================= */
56
57 SYNFIG_IMPORTER_INIT(png_mptr);
58 SYNFIG_IMPORTER_SET_NAME(png_mptr,"png_mptr");
59 SYNFIG_IMPORTER_SET_EXT(png_mptr,"png");
60 SYNFIG_IMPORTER_SET_VERSION(png_mptr,"0.1");
61 SYNFIG_IMPORTER_SET_CVS_ID(png_mptr,"$Id: mptr_png.cpp,v 1.1.1.1 2005/01/04 01:23:14 darco Exp $");
62
63 /* === M E T H O D S ======================================================= */
64
65 void
66 png_mptr::png_out_error(png_struct *png_data,const char *msg)
67 {
68         //png_mptr *me=(png_mptr*)png_data->error_ptr;
69         synfig::error(strprintf("png_mptr: error: %s",msg));
70         //me->ready=false;
71 }
72
73 void
74 png_mptr::png_out_warning(png_struct *png_data,const char *msg)
75 {
76         //png_mptr *me=(png_mptr*)png_data->error_ptr;
77         synfig::warning(strprintf("png_mptr: warning: %s",msg));
78         //me->ready=false;
79 }
80
81 int
82 png_mptr::read_chunk_callback(png_struct *png_data, png_unknown_chunkp chunk)
83 {
84         /* The unknown chunk structure contains your
85           chunk data: */
86         //png_byte name[5];
87         //png_byte *data;
88         //png_size_t size;
89         /* Note that libpng has already taken care of
90           the CRC handling */
91         
92         /* put your code here.  Return one of the
93           following: */
94         
95         //return (-n); /* chunk had an error */
96         return (0); /* did not recognize */
97         //return (n); /* success */
98 }
99
100 png_mptr::png_mptr(const char *file_name)
101 {
102         filename=file_name;
103         
104         /* Open the file pointer */
105     FILE *file = fopen(file_name, "rb");
106     if (!file)
107     {
108         //! \todo THROW SOMETHING
109                 throw strprintf("Unable to physically open %s",file_name);
110                 return;
111     }
112     
113         
114         /* Make sure we are dealing with a PNG format file */
115         png_byte header[PNG_CHECK_BYTES];
116         fread(header, 1, PNG_CHECK_BYTES, file);
117     bool is_png = !png_sig_cmp(header, 0, PNG_CHECK_BYTES);
118     if (!is_png)
119     {
120         //! \todo THROW SOMETHING
121                 throw strprintf("This (\"%s\") doesn't appear to be a PNG file",file_name);
122                 return;
123     }
124         
125         
126         png_structp png_ptr = png_create_read_struct
127        (PNG_LIBPNG_VER_STRING, (png_voidp)this,
128         &png_mptr::png_out_error, &png_mptr::png_out_warning);
129         if (!png_ptr)
130     {
131         //! \todo THROW SOMETHING
132                 throw String("error on importer construction, *WRITEME*3");
133                 return;
134     }
135
136     png_infop info_ptr = png_create_info_struct(png_ptr);
137     if (!info_ptr)
138     {
139         png_destroy_read_struct(&png_ptr,
140            (png_infopp)NULL, (png_infopp)NULL);
141         //! \todo THROW SOMETHING
142                 throw String("error on importer construction, *WRITEME*4");
143                 return;
144     }
145
146     png_infop end_info = png_create_info_struct(png_ptr);
147     if (!end_info)
148     {
149         png_destroy_read_struct(&png_ptr, &info_ptr,
150           (png_infopp)NULL);
151         //! \todo THROW SOMETHING
152                 throw String("error on importer construction, *WRITEME*4");
153                 return;
154     }
155
156         
157         
158         png_init_io(png_ptr, file);
159         png_set_sig_bytes(png_ptr,PNG_CHECK_BYTES);
160
161         double fgamma;
162         if (png_get_gAMA(png_ptr, info_ptr, &fgamma))
163         {
164                 synfig::info("PNG: Image gamma is %f",fgamma);
165                 png_set_gamma(png_ptr, gamma().get_gamma(), fgamma);
166         }
167         
168         
169         /*
170         if (setjmp(png_jmpbuf(png_ptr)))
171         {
172                 synfig::error("Unable to setup longjump");
173                 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
174                 fclose(file);
175         //! \todo THROW SOMETHING
176                 throw String("error on importer construction, *WRITEME*5");
177                 return;
178         }
179         */
180         
181         png_set_read_user_chunk_fn(png_ptr, this, &png_mptr::read_chunk_callback);
182         
183         
184         png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_PACKING|PNG_TRANSFORM_STRIP_16, NULL);
185
186         int bit_depth,color_type,interlace_type, compression_type,filter_method;
187         png_uint_32 width,height;
188         
189     png_get_IHDR(png_ptr, info_ptr, &width, &height,
190        &bit_depth, &color_type, &interlace_type,
191        &compression_type, &filter_method);
192         
193         png_bytep *row_pointers=new png_bytep[height];
194         row_pointers = png_get_rows(png_ptr, info_ptr);
195         int x;
196         int y;
197         surface_buffer.set_wh(width,height);
198
199         switch(color_type)
200         {
201         case PNG_COLOR_TYPE_RGB:
202                 DEBUGPOINT();
203                 for(y=0;y<surface_buffer.get_h();y++)
204                         for(x=0;x<surface_buffer.get_w();x++)
205                         {
206                                 float r=gamma().r_U8_to_F32((unsigned char)row_pointers[y][x*3+0]);
207                                 float g=gamma().g_U8_to_F32((unsigned char)row_pointers[y][x*3+1]);
208                                 float b=gamma().b_U8_to_F32((unsigned char)row_pointers[y][x*3+2]);
209                                 surface_buffer[y][x]=Color(
210                                         r,
211                                         g,
212                                         b,
213                                         1.0
214                                 );
215 /*
216                                 surface_buffer[y][x]=Color(
217                                         (float)(unsigned char)row_pointers[y][x*3+0]*(1.0/255.0),
218                                         (float)(unsigned char)row_pointers[y][x*3+1]*(1.0/255.0),
219                                         (float)(unsigned char)row_pointers[y][x*3+2]*(1.0/255.0),
220                                         1.0
221                                 );
222 */
223                         }
224                 break;
225                         
226         case PNG_COLOR_TYPE_RGB_ALPHA:
227                 DEBUGPOINT();
228                 for(y=0;y<surface_buffer.get_h();y++)
229                         for(x=0;x<surface_buffer.get_w();x++)
230                         {
231                                 float r=gamma().r_U8_to_F32((unsigned char)row_pointers[y][x*4+0]);
232                                 float g=gamma().g_U8_to_F32((unsigned char)row_pointers[y][x*4+1]);
233                                 float b=gamma().b_U8_to_F32((unsigned char)row_pointers[y][x*4+2]);
234                                 surface_buffer[y][x]=Color(
235                                         r,
236                                         g,
237                                         b,
238                                         (float)(unsigned char)row_pointers[y][x*4+3]*(1.0/255.0)
239                                 );
240                                 /*
241                                 surface_buffer[y][x]=Color(
242                                         (float)(unsigned char)row_pointers[y][x*4+0]*(1.0/255.0),
243                                         (float)(unsigned char)row_pointers[y][x*4+1]*(1.0/255.0),
244                                         (float)(unsigned char)row_pointers[y][x*4+2]*(1.0/255.0),
245                                         (float)(unsigned char)row_pointers[y][x*4+3]*(1.0/255.0)
246                                 );
247                                 */
248                         }
249                 break;
250                         
251         case PNG_COLOR_TYPE_GRAY:
252                 for(y=0;y<surface_buffer.get_h();y++)
253                         for(x=0;x<surface_buffer.get_w();x++)
254                         {
255                                 float gray=gamma().g_U8_to_F32((unsigned char)row_pointers[y][x]);
256                                 //float gray=(float)(unsigned char)row_pointers[y][x]*(1.0/255.0);
257                                 surface_buffer[y][x]=Color(
258                                         gray,
259                                         gray,
260                                         gray,
261                                         1.0
262                                 );
263                         }
264                 break;
265
266         case PNG_COLOR_TYPE_GRAY_ALPHA:
267                 for(y=0;y<surface_buffer.get_h();y++)
268                         for(x=0;x<surface_buffer.get_w();x++)
269                         {
270                                 float gray=gamma().g_U8_to_F32((unsigned char)row_pointers[y][x*2]);
271 //                              float gray=(float)(unsigned char)row_pointers[y][x*2]*(1.0/255.0);
272                                 surface_buffer[y][x]=Color(
273                                         gray,
274                                         gray,
275                                         gray,
276                                         (float)(unsigned char)row_pointers[y][x*2+1]*(1.0/255.0)
277                                 );
278                         }
279                 break;
280
281         case PNG_COLOR_TYPE_PALETTE:
282                 synfig::warning("png_mptr: Paletted PNGs aren't yet fully supported.");
283                 for(y=0;y<surface_buffer.get_h();y++)
284                         for(x=0;x<surface_buffer.get_w();x++)
285                         {
286                                 float r=gamma().r_U8_to_F32((unsigned char)png_ptr->palette[row_pointers[y][x]].red);
287                                 float g=gamma().g_U8_to_F32((unsigned char)png_ptr->palette[row_pointers[y][x]].green);
288                                 float b=gamma().b_U8_to_F32((unsigned char)png_ptr->palette[row_pointers[y][x]].blue);
289                                 surface_buffer[y][x]=Color(
290                                         r,
291                                         g,
292                                         b,
293                                         1.0
294                                 );
295                         }
296                 break;
297         default:
298                 synfig::error("png_mptr: error: Unsupported color type");
299         //! \todo THROW SOMETHING
300                 throw String("error on importer construction, *WRITEME*6");
301                 return;
302         }
303
304         DEBUGPOINT();
305         
306         // \fixme These shouldn't be uncommented, but for some
307         // reason, they crash the program. I will have to look into this
308         // later. This is a memory leak, but it shouldn't be too bad.
309         
310         /*
311         png_read_end(png_ptr, end_info);
312         png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
313         fclose(file);
314         */
315
316         delete [] row_pointers;
317 }
318
319 png_mptr::~png_mptr()
320 {
321         DEBUGPOINT();
322 }
323
324 bool
325 png_mptr::get_frame(synfig::Surface &surface,Time, synfig::ProgressCallback *cb)
326 {
327         surface.mirror(surface_buffer);
328 //      surface=surface_buffer;
329         return true;
330 }