Fix bugs in previous commit that caused FTBFS in synfig and ETL FTBFS with older...
[synfig.git] / synfig-core / tags / synfig_0_61_06 / 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 ** FIXME: THIS DOES NOT ACTUALLY WORK YET
24 **
25 ** You will need to read the PNG and MNG specs to understand this code
26 **
27 ** ========================================================================= */
28
29 /* === H E A D E R S ======================================================= */
30
31 #define SYNFIG_TARGET
32
33 #ifdef USING_PCH
34 #       include "pch.h"
35 #else
36 #ifdef HAVE_CONFIG_H
37 #       include <config.h>
38 #endif
39
40 #include "trgt_mng.h"
41 #include <libmng.h>
42 #include <ETL/stringf>
43 #include <cstdio>
44 #include <algorithm>
45 #include <functional>
46 #include <ETL/misc>
47
48 #endif
49
50 /* === M A C R O S ========================================================= */
51
52 using namespace synfig;
53 using namespace std;
54 using namespace etl;
55
56 /* === G L O B A L S ======================================================= */
57
58 SYNFIG_TARGET_INIT(mng_trgt);
59 SYNFIG_TARGET_SET_NAME(mng_trgt,"mng");
60 SYNFIG_TARGET_SET_EXT(mng_trgt,"mng");
61 SYNFIG_TARGET_SET_VERSION(mng_trgt,"0.1");
62 SYNFIG_TARGET_SET_CVS_ID(mng_trgt,"$Id$");
63
64 /* === M E T H O D S ======================================================= */
65
66 static mng_ptr MNG_DECL mng_alloc_proc(mng_size_t size){
67         return (mng_ptr)calloc(1,size);
68 }
69
70 static void MNG_DECL mng_free_proc(mng_ptr ptr, mng_size_t size)
71 {
72   free(ptr); return;
73 }
74
75 static mng_bool MNG_DECL mng_null_proc(mng_handle mng)
76 {
77         synfig::error("mng_trgt: error: mng_null_proc");
78         return MNG_TRUE;
79 }
80
81 static mng_bool MNG_DECL mng_write_proc(mng_handle mng, mng_ptr buf, mng_uint32 size, mng_uint32* written)
82 {
83         synfig::error("mng_trgt: error: mng_write_proc");
84         FILE* file = (FILE*)mng_get_userdata (mng);
85         *written = fwrite(buf, 1, size, file);
86         return MNG_TRUE;
87 }
88
89 static mng_bool MNG_DECL mng_error_proc(
90         mng_handle mng, mng_int32 error, mng_int8 severity, mng_chunkid chunkname,
91         mng_uint32 chunkseq, mng_int32 extra1, mng_int32 extra2, mng_pchar errortext){
92         mng_trgt* me = (mng_trgt*)mng_get_userdata (mng);
93         fprintf(stderr,"mng_trgt: error: %s",errortext);
94         // me->ready=false;
95         return MNG_TRUE;
96 }
97
98 mng_trgt::mng_trgt(const char *Filename):
99         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::error("mng_trgt: error: ~mng_trgt");
112         if( mng != MNG_NULL){
113                 mng_putchunk_mend(mng);
114                 if( mng_write(mng) != 0 ){
115                         mng_int8 severity;
116                         mng_chunkid chunkname;
117                         mng_uint32 chunkseq;
118                         mng_int32 extra1;
119                         mng_int32 extra2;
120                         mng_pchar errortext;
121                         mng_getlasterror(mng, &severity, &chunkname, &chunkseq, &extra1,&extra2, &errortext);
122                         synfig::error("mng_trgt: error: couldn't write mng: %s",errortext);
123                 }
124                 mng_cleanup (&mng);
125         }
126         if( file != NULL ) fclose(file); file=NULL;
127         if( buffer != NULL ){ delete [] buffer; buffer = NULL; }
128         if( color_buffer != NULL ){ delete [] color_buffer; color_buffer = NULL; }
129         if( zbuffer != NULL ){ free(zbuffer); zbuffer = NULL; zbuffer_len = 0; }
130 }
131
132 bool
133 mng_trgt::set_rend_desc(RendDesc *given_desc)
134 {
135         desc=*given_desc;
136         imagecount=desc.get_frame_start();
137         if(desc.get_frame_end()-desc.get_frame_start()>0)
138                 multi_image=true;
139         else
140                 multi_image=false;
141         return true;
142 }
143
144
145 bool
146 mng_trgt::init(){
147         time_t t = time (NULL);
148         struct tm* gmt = gmtime(&t);
149         w=desc.get_w(); h=desc.get_h();
150         //synfig::error("mng_trgt: init %d %d",w,h); 
151         file = fopen(filename.c_str(), "wb");
152         if( file == NULL ) goto cleanup_on_error;
153         mng = mng_initialize((mng_ptr)file, mng_alloc_proc, mng_free_proc, MNG_NULL);
154         if(mng == MNG_NULL) goto cleanup_on_error;
155         if( mng_setcb_errorproc(mng, mng_error_proc) != 0 ) goto cleanup_on_error;
156         if( mng_setcb_writedata(mng, mng_write_proc) != 0 ) goto cleanup_on_error;
157         if( mng_setcb_openstream(mng, mng_null_proc) != 0 ) goto cleanup_on_error;
158         if( mng_setcb_closestream(mng, mng_null_proc) != 0 ) goto cleanup_on_error;
159         if( mng_create(mng) != 0 ) goto cleanup_on_error;
160         if( mng_putchunk_mhdr(mng, w, h, multi_image?1000:0, 1, desc.get_frame_end()-desc.get_frame_start(), 0, 0) != 0 ) goto cleanup_on_error;
161         if( mng_putchunk_term(mng, MNG_TERMACTION_REPEAT, MNG_ITERACTION_LASTFRAME, 0, 0x7fffffff) != 0 ) goto cleanup_on_error;
162         if( mng_putchunk_text(mng, sizeof(MNG_TEXT_TITLE), MNG_TEXT_TITLE, get_canvas()->get_name().length(), const_cast<char *>(get_canvas()->get_name().c_str()) ) != 0 ) goto cleanup_on_error;
163         if( mng_putchunk_text(mng, sizeof(MNG_TEXT_DESCRIPTION), MNG_TEXT_DESCRIPTION, get_canvas()->get_description().length(), const_cast<char *>(get_canvas()->get_description().c_str()) ) != 0 ) goto cleanup_on_error;
164         if( mng_putchunk_text(mng, sizeof(MNG_TEXT_SOFTWARE), MNG_TEXT_SOFTWARE, sizeof("SYNFIG"), "SYNFIG" ) != 0 ) goto cleanup_on_error;
165         /* FIXME: not sure if this is correct */
166         if( mng_putchunk_gama(mng, MNG_FALSE, (int)(1.0/gamma().get_gamma()*100000)) != 0 ) goto cleanup_on_error;
167         if( mng_putchunk_phyg(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;
168         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;
169         buffer=new unsigned char[4*w];
170         if( buffer == NULL ) goto cleanup_on_error;
171         color_buffer=new Color[w];
172         if( color_buffer == NULL ) goto cleanup_on_error;
173         return true;
174         
175 cleanup_on_error:
176         ready=false;
177         if( mng != MNG_NULL){
178                 mng_int8 severity;
179                 mng_chunkid chunkname;
180                 mng_uint32 chunkseq;
181                 mng_int32 extra1;
182                 mng_int32 extra2;
183                 mng_pchar errortext;
184                 mng_getlasterror (mng, &severity, &chunkname, &chunkseq, &extra1,&extra2, &errortext);
185                 synfig::error("mng_trgt: libmng: %s",errortext); 
186                 mng_cleanup (&mng);
187         }
188         if( file && file!=stdout ) fclose(file); file=NULL;
189         if( buffer != NULL ){ delete [] buffer; buffer = NULL; }
190         if( color_buffer != NULL ){ delete [] color_buffer; color_buffer = NULL; }
191         return false;   
192 }
193
194 void
195 mng_trgt::end_frame()
196 {
197         //synfig::error("mng_trgt: endf %d %d",w,h); 
198         //synfig::error("mng_trgt: error: endframe");
199         deflate(&zstream,Z_FINISH);
200         deflateEnd(&zstream);
201         if( mng != MNG_NULL ){
202                 mng_int8 severity;
203                 mng_chunkid chunkname;
204                 mng_uint32 chunkseq;
205                 mng_int32 extra1;
206                 mng_int32 extra2;
207                 mng_pchar errortext;
208                 mng_putchunk_idat(mng, zbuffer_len, zbuffer);
209                 //mng_getlasterror (mng, &severity, &chunkname, &chunkseq, &extra1,&extra2, &errortext);
210                 //synfig::error("mng_trgt: libmng: %s %d",errortext,zbuffer_len); 
211                 mng_putchunk_iend(mng);
212                 //mng_getlasterror (mng, &severity, &chunkname, &chunkseq, &extra1,&extra2, &errortext);
213                 //synfig::error("mng_trgt: libmng: %s %d",errortext); 
214         }
215         imagecount++;
216         ready=false;
217 }
218
219 bool
220 mng_trgt::start_frame(synfig::ProgressCallback *callback)
221 {
222         //synfig::error("mng_trgt: startf %d %d",w,h); 
223         //synfig::error("mng_trgt: error: startframe");
224         /*
225         FIXME: figure out if we need this
226         mng_putchunk_fram(mng,
227                 MNG_FALSE,
228                 MNG_FRAMINGMODE_NOCHANGE,
229                 0,
230                 NULL,
231                 MNG_CHANGEDELAY_NO,
232                 MNG_CHANGETIMOUT_NO,
233                 MNG_CHANGECLIPPING_NO,
234                 MNG_CHANGESYNCID_NO,
235                 0,
236                 0,
237                 0,
238                 layer_offset_x,
239                 layer_offset_x + layer_cols,
240                 layer_offset_y,
241                 layer_offset_y + layer_rows,
242                 0,
243                 0)
244         mng_getchunk_fram(mng_handle       hHandle,
245                 mng_handle       hChunk,
246                 mng_bool         *bEmpty,
247                 mng_uint8        *iMode,
248                 mng_uint32       *iNamesize,
249                 mng_pchar        *zName,
250                 mng_uint8        *iChangedelay,
251                 mng_uint8        *iChangetimeout,
252                 mng_uint8        *iChangeclipping,
253                 mng_uint8        *iChangesyncid,
254                 mng_uint32       *iDelay,
255                 mng_uint32       *iTimeout,
256                 mng_uint8        *iBoundarytype,
257                 mng_int32        *iBoundaryl,
258                 mng_int32        *iBoundaryr,
259                 mng_int32        *iBoundaryt,
260                 mng_int32        *iBoundaryb,
261                 mng_uint32       *iCount,
262                 mng_uint32p      *pSyncids);
263         */
264         if( mng == MNG_NULL ) return false;
265         if( mng_putchunk_defi(mng,0,MNG_DONOTSHOW_VISIBLE,MNG_ABSTRACT,MNG_FALSE,0,0,MNG_FALSE,0,0,0,0) != 0) return false;
266         if( mng_putchunk_ihdr(mng,w,h,MNG_BITDEPTH_8,MNG_COLORTYPE_RGBA,MNG_COMPRESSION_DEFLATE, 0/*MNG_FILTER_NO_DIFFERING*/,MNG_INTERLACE_NONE) != 0) return false;
267         zstream.zalloc = Z_NULL;
268         zstream.zfree = Z_NULL;
269         zstream.opaque = Z_NULL;
270         zstream.data_type = Z_BINARY; 
271         if( deflateInit(&zstream, Z_DEFAULT_COMPRESSION) != Z_OK ) return false;
272         //zbuffer_len = deflateBound(&zstream,4*w*h);
273         if(zbuffer == NULL){
274                 zbuffer_len = 4*w*h;
275                 zbuffer = (unsigned char*)realloc(zbuffer, zbuffer_len);
276                 zstream.next_out = zbuffer;
277                 zstream.avail_out = zbuffer_len;
278         }
279         ready=true;
280         return true;
281 }
282
283 Color *
284 mng_trgt::start_scanline(int scanline)
285 {
286         //synfig::error("mng_trgt: starts %d %d",w,h); 
287         //synfig::error("mng_trgt: error: startscanline");
288         return color_buffer;
289 }
290
291 bool
292 mng_trgt::end_scanline()
293 {
294         //synfig::error("mng_trgt: ends %d %d",w,h); 
295         //synfig::error("mng_trgt: error: endscanline");
296         if(!file || !ready)
297                 return false;
298         convert_color_format(buffer, color_buffer, desc.get_w(), PF_RGB|PF_A, gamma());
299         /* FIXME: Implement buffer management */
300         zstream.next_in = buffer;
301         zstream.avail_in = 4*w;
302         deflate(&zstream,Z_NO_FLUSH);
303         return true;
304 }