Fix warnings from g++ 4.2.
[synfig.git] / synfig-core / trunk / src / modules / mod_mng / trgt_mng.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file trgt_mng.cpp
3 **      \brief MNG Target Module
4 **
5 **      $Id$
6 **
7 **      \legal
8 **      Copyright 2007 Paul Wise
9 **
10 **      This package is free software; you can redistribute it and/or
11 **      modify it under the terms of the GNU General Public License as
12 **      published by the Free Software Foundation; either version 2 of
13 **      the License, or (at your option) any later version.
14 **
15 **      This package is distributed in the hope that it will be useful,
16 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
17 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 **      General Public License for more details.
19 **      \endlegal
20 **
21 ** === N O T E S ===========================================================
22 **
23 ** You will need to read the PNG and MNG specs to understand this code
24 **
25 ** ========================================================================= */
26
27 /* === H E A D E R S ======================================================= */
28
29 #define SYNFIG_TARGET
30
31 #ifdef USING_PCH
32 #       include "pch.h"
33 #else
34 #ifdef HAVE_CONFIG_H
35 #       include <config.h>
36 #endif
37
38 #include "trgt_mng.h"
39 #include <libmng.h>
40 #include <ETL/stringf>
41 #include <cstdio>
42 #include <algorithm>
43 #include <functional>
44 #include <ETL/misc>
45
46 #endif
47
48 /* === M A C R O S ========================================================= */
49
50 using namespace synfig;
51 using namespace std;
52 using namespace etl;
53
54 /* === G L O B A L S ======================================================= */
55
56 SYNFIG_TARGET_INIT(mng_trgt);
57 SYNFIG_TARGET_SET_NAME(mng_trgt,"mng");
58 SYNFIG_TARGET_SET_EXT(mng_trgt,"mng");
59 SYNFIG_TARGET_SET_VERSION(mng_trgt,"0.1");
60 SYNFIG_TARGET_SET_CVS_ID(mng_trgt,"$Id$");
61
62 /* === M E T H O D S ======================================================= */
63
64 static mng_ptr MNG_DECL
65 mng_alloc_proc(mng_size_t size)
66 {
67         return (mng_ptr)calloc(1,size);
68 }
69
70 static void MNG_DECL
71 mng_free_proc(mng_ptr ptr, mng_size_t size)
72 {
73         free(ptr); return;
74 }
75
76 static mng_bool MNG_DECL
77 mng_null_proc(mng_handle mng)
78 {
79         // synfig::info("%s:%d mng_trgt::mng_null_proc was called", __FILE__, __LINE__);
80         return MNG_TRUE;
81 }
82
83 static mng_bool MNG_DECL
84 mng_write_proc(mng_handle mng, mng_ptr buf, mng_uint32 size, mng_uint32* written)
85 {
86         FILE* file = (FILE*)mng_get_userdata (mng);
87         *written = fwrite(buf, 1, size, file);
88         return MNG_TRUE;
89 }
90
91 static mng_bool MNG_DECL
92 mng_error_proc(mng_handle mng, mng_int32 error, mng_int8 severity, mng_chunkid chunkname,
93                            mng_uint32 chunkseq, mng_int32 extra1, mng_int32 extra2, mng_pchar errortext)
94 {
95         synfig::error("%s:%d mng_trgt: error: %s", __FILE__, __LINE__, errortext);
96         return MNG_TRUE;
97 }
98
99 mng_trgt::mng_trgt(const char *Filename) : filename(Filename)
100 {
101         file=NULL;
102         buffer=NULL;
103         color_buffer=NULL;      
104         zbuffer=NULL;   
105         zbuffer_len=0;
106         ready=false;
107 }
108
109 mng_trgt::~mng_trgt()
110 {
111         synfig::info("mng_trgt: ~mng_trgt");
112         if (mng != MNG_NULL)
113         {
114                 mng_putchunk_mend(mng);
115                 if (mng_write(mng) != 0)
116                 {
117                         mng_int8 severity;
118                         mng_chunkid chunkname;
119                         mng_uint32 chunkseq;
120                         mng_int32 extra1;
121                         mng_int32 extra2;
122                         mng_pchar errortext;
123                         mng_getlasterror(mng, &severity, &chunkname, &chunkseq, &extra1,&extra2, &errortext);
124                         synfig::error("mng_trgt: error: couldn't write mng: %s",errortext);
125                 }
126                 mng_cleanup (&mng);
127         }
128         if (file != NULL) fclose(file); file=NULL;
129         if (buffer != NULL) { delete [] buffer; buffer = NULL; }
130         if (color_buffer != NULL) { delete [] color_buffer; color_buffer = NULL; }
131         if (zbuffer != NULL) { free(zbuffer); zbuffer = NULL; zbuffer_len = 0; }
132 }
133
134 bool
135 mng_trgt::set_rend_desc(RendDesc *given_desc)
136 {
137         desc=*given_desc;
138         imagecount=desc.get_frame_start();
139         if (desc.get_frame_end()-desc.get_frame_start()>0)
140                 multi_image=true;
141         else
142                 multi_image=false;
143         return true;
144 }
145
146
147 bool
148 mng_trgt::init()
149 {
150         // synfig::info("%s:%d mng_trgt::init()", __FILE__, __LINE__); 
151
152         int frame_rate, num_frames, play_time;
153         int num_layers = 1;
154
155         if (multi_image)
156         {
157                 frame_rate = int(desc.get_frame_rate());
158                 printf("frame rt %d\n", frame_rate);
159                 num_frames = desc.get_frame_end()-desc.get_frame_start();
160                 play_time = num_frames;// / frame_rate;
161         }
162         else
163         {
164                 frame_rate = 0;
165                 num_frames = 1;
166                 play_time = 0;
167         }
168
169         time_t t = time (NULL);
170         struct tm* gmt = gmtime(&t);
171         w=desc.get_w(); h=desc.get_h();
172         file = fopen(filename.c_str(), POPEN_BINARY_WRITE_TYPE);
173         if (file == NULL) goto cleanup_on_error;
174         mng = mng_initialize((mng_ptr)file, mng_alloc_proc, mng_free_proc, MNG_NULL);
175         if (mng == MNG_NULL) goto cleanup_on_error;
176         if (mng_setcb_errorproc(mng, mng_error_proc) != 0) goto cleanup_on_error;
177         if (mng_setcb_writedata(mng, mng_write_proc) != 0) goto cleanup_on_error;
178         if (mng_setcb_openstream(mng, mng_null_proc) != 0) goto cleanup_on_error;
179         if (mng_setcb_closestream(mng, mng_null_proc) != 0) goto cleanup_on_error;
180         if (mng_create(mng) != 0) goto cleanup_on_error;
181         if (mng_putchunk_mhdr(mng, w, h, frame_rate, num_layers, num_frames, play_time, MNG_SIMPLICITY_VALID|MNG_SIMPLICITY_SIMPLEFEATURES) != 0) goto cleanup_on_error;
182         if (mng_putchunk_term(mng, MNG_TERMACTION_REPEAT, MNG_ITERACTION_LASTFRAME, 0, 0x7fffffff) != 0) goto cleanup_on_error;
183         {
184                 char title[] = MNG_TEXT_TITLE;
185                 if (mng_putchunk_text(mng, sizeof(title), title,
186                                                           get_canvas()->get_name().length(), const_cast<char *>(get_canvas()->get_name().c_str())) != 0)
187                         goto cleanup_on_error;
188
189                 char description[] = MNG_TEXT_DESCRIPTION;
190                 if (mng_putchunk_text(mng, sizeof(description), description,
191                                                           get_canvas()->get_description().length(), const_cast<char *>(get_canvas()->get_description().c_str())) != 0)
192                         goto cleanup_on_error;
193
194                 char software[] = MNG_TEXT_SOFTWARE; char synfig[] = "SYNFIG";
195                 if (mng_putchunk_text(mng, sizeof(software), software,
196                                                           sizeof(synfig), synfig) != 0)
197                         goto cleanup_on_error;
198         }
199         if (mng_putchunk_gama(mng, MNG_FALSE, (int)(gamma().get_gamma()*100000)) != 0) goto cleanup_on_error;
200         if (mng_putchunk_phys(mng, MNG_FALSE, round_to_int(desc.get_x_res()),round_to_int(desc.get_y_res()), MNG_UNIT_METER) != 0) goto cleanup_on_error;
201         if (mng_putchunk_time(mng, gmt->tm_year + 1900, gmt->tm_mon + 1, gmt->tm_mday, gmt->tm_hour, gmt->tm_min, gmt->tm_sec) != 0) goto cleanup_on_error;
202         buffer=new unsigned char[(4*w)+1];
203         if (buffer == NULL) goto cleanup_on_error;
204         color_buffer=new Color[w];
205         if (color_buffer == NULL) goto cleanup_on_error;
206         return true;
207         
208 cleanup_on_error:
209         ready=false;
210         if (mng != MNG_NULL)
211         {
212                 mng_int8 severity;
213                 mng_chunkid chunkname;
214                 mng_uint32 chunkseq;
215                 mng_int32 extra1;
216                 mng_int32 extra2;
217                 mng_pchar errortext;
218                 mng_getlasterror (mng, &severity, &chunkname, &chunkseq, &extra1,&extra2, &errortext);
219                 synfig::error("mng_trgt: libmng: %s",errortext); 
220                 mng_cleanup (&mng);
221         }
222
223         if (file && file!=stdout)
224                 fclose(file);
225         file=NULL;
226
227         if (buffer != NULL)
228         {
229                 delete [] buffer;
230                 buffer = NULL;
231         }
232
233         if (color_buffer != NULL)
234         {
235                 delete [] color_buffer;
236                 color_buffer = NULL;
237         }
238
239         return false;   
240 }
241
242 void
243 mng_trgt::end_frame()
244 {
245         // synfig::info("%s:%d mng_trgt::end_frame()", __FILE__, __LINE__); 
246
247         if (deflate(&zstream,Z_FINISH) != Z_STREAM_END)
248         {
249                 synfig::error("%s:%d deflate()", __FILE__, __LINE__);
250                 return;
251         }
252         if (deflateEnd(&zstream) != Z_OK)
253         {
254                 synfig::error("%s:%d deflateEnd()", __FILE__, __LINE__);
255                 return;
256         }
257         if (mng != MNG_NULL)
258         {
259                 mng_putchunk_idat(mng, zstream.next_out-zbuffer, zbuffer);
260                 mng_putchunk_iend(mng);
261         }
262         imagecount++;
263         ready=false;
264 }
265
266 bool
267 mng_trgt::start_frame(synfig::ProgressCallback *callback)
268 {
269         // synfig::info("%s:%d mng_trgt::start_frame()", __FILE__, __LINE__); 
270
271         if (mng == MNG_NULL)
272         {
273                 synfig::error("%s:%d mng == MNG_NULL", __FILE__, __LINE__);
274                 return false;
275         }
276
277         if (mng_putchunk_ihdr(mng, w, h, MNG_BITDEPTH_8, MNG_COLORTYPE_RGBA, MNG_COMPRESSION_DEFLATE, MNG_FILTER_ADAPTIVE, MNG_INTERLACE_NONE) != 0)
278         {
279                 synfig::error("%s:%d mng_putchunk_ihdr()", __FILE__, __LINE__);
280                 return false;
281         }
282         
283         zstream.zalloc = Z_NULL;
284         zstream.zfree = Z_NULL;
285         zstream.opaque = Z_NULL;
286
287         if (deflateInit(&zstream, /* Z_BEST_COMPRESSION */ Z_DEFAULT_COMPRESSION) != Z_OK)
288         {
289                 synfig::error("%s:%d deflateInit()", __FILE__, __LINE__);
290                 return false;
291         }
292
293         if (zbuffer == NULL)
294         {
295                 zbuffer_len = deflateBound(&zstream,((4*w)+1)*h); // don't forget the 'filter' byte - one per scanline
296                 zbuffer = (unsigned char*)realloc(zbuffer, zbuffer_len);
297         }
298
299         zstream.avail_out = zbuffer_len;
300         zstream.next_out = zbuffer;
301
302         ready=true;
303
304         return true;
305 }
306
307 Color*
308 mng_trgt::start_scanline(int scanline)
309 {
310         return color_buffer;
311 }
312
313 bool
314 mng_trgt::end_scanline()
315 {
316         if (!file || !ready)
317         {
318                 synfig::error("%s:%d !file or !ready", __FILE__, __LINE__);
319                 return false;
320         }
321
322         *buffer = MNG_FILTER_NONE;
323         convert_color_format(buffer+1, color_buffer, desc.get_w(), PF_RGB|PF_A, gamma());
324
325         zstream.next_in = buffer;
326         zstream.avail_in = (4*w)+1;
327
328         if (deflate(&zstream,Z_NO_FLUSH) != Z_OK) {
329                 synfig::error("%s:%d deflate()", __FILE__, __LINE__);
330                 return false;
331         }
332
333         return true;
334 }