1 /* === S Y N F I G ========================================================= */
3 ** \brief MNG Target Module
8 ** Copyright 2007 Paul Wise
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.
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.
21 ** === N O T E S ===========================================================
23 ** You will need to read the PNG and MNG specs to understand this code
25 ** ========================================================================= */
27 /* === H E A D E R S ======================================================= */
40 #include <ETL/stringf>
48 /* === M A C R O S ========================================================= */
50 using namespace synfig;
54 /* === G L O B A L S ======================================================= */
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$");
62 /* === M E T H O D S ======================================================= */
64 static mng_ptr MNG_DECL
65 mng_alloc_proc(mng_size_t size)
67 return (mng_ptr)calloc(1,size);
71 mng_free_proc(mng_ptr ptr, mng_size_t size)
76 static mng_bool MNG_DECL
77 mng_null_proc(mng_handle mng)
79 // synfig::info("%s:%d mng_trgt::mng_null_proc was called", __FILE__, __LINE__);
83 static mng_bool MNG_DECL
84 mng_write_proc(mng_handle mng, mng_ptr buf, mng_uint32 size, mng_uint32* written)
86 FILE* file = (FILE*)mng_get_userdata (mng);
87 *written = fwrite(buf, 1, size, file);
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)
95 synfig::error("%s:%d mng_trgt: error: %s", __FILE__, __LINE__, errortext);
99 mng_trgt::mng_trgt(const char *Filename) : filename(Filename)
109 mng_trgt::~mng_trgt()
111 synfig::info("mng_trgt: ~mng_trgt");
114 mng_putchunk_mend(mng);
115 if (mng_write(mng) != 0)
118 mng_chunkid chunkname;
123 mng_getlasterror(mng, &severity, &chunkname, &chunkseq, &extra1,&extra2, &errortext);
124 synfig::error("mng_trgt: error: couldn't write mng: %s",errortext);
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; }
135 mng_trgt::set_rend_desc(RendDesc *given_desc)
138 imagecount=desc.get_frame_start();
139 if (desc.get_frame_end()-desc.get_frame_start()>0)
150 // synfig::info("%s:%d mng_trgt::init()", __FILE__, __LINE__);
152 int frame_rate, num_frames, play_time;
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;
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 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;
184 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;
185 if (mng_putchunk_text(mng, sizeof(MNG_TEXT_SOFTWARE), MNG_TEXT_SOFTWARE, sizeof("SYNFIG"), "SYNFIG") != 0) goto cleanup_on_error;
186 if (mng_putchunk_gama(mng, MNG_FALSE, (int)(1.0/gamma().get_gamma()*100000)) != 0) goto cleanup_on_error;
187 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;
188 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;
189 buffer=new unsigned char[(4*w)+1];
190 if (buffer == NULL) goto cleanup_on_error;
191 color_buffer=new Color[w];
192 if (color_buffer == NULL) goto cleanup_on_error;
200 mng_chunkid chunkname;
205 mng_getlasterror (mng, &severity, &chunkname, &chunkseq, &extra1,&extra2, &errortext);
206 synfig::error("mng_trgt: libmng: %s",errortext);
210 if (file && file!=stdout)
220 if (color_buffer != NULL)
222 delete [] color_buffer;
230 mng_trgt::end_frame()
232 // synfig::info("%s:%d mng_trgt::end_frame()", __FILE__, __LINE__);
234 if (deflate(&zstream,Z_FINISH) != Z_STREAM_END)
236 synfig::error("%s:%d deflate()", __FILE__, __LINE__);
239 if (deflateEnd(&zstream) != Z_OK)
241 synfig::error("%s:%d deflateEnd()", __FILE__, __LINE__);
246 mng_putchunk_idat(mng, zstream.next_out-zbuffer, zbuffer);
247 mng_putchunk_iend(mng);
254 mng_trgt::start_frame(synfig::ProgressCallback *callback)
256 // synfig::info("%s:%d mng_trgt::start_frame()", __FILE__, __LINE__);
260 synfig::error("%s:%d mng == MNG_NULL", __FILE__, __LINE__);
264 if (mng_putchunk_ihdr(mng, w, h, MNG_BITDEPTH_8, MNG_COLORTYPE_RGBA, MNG_COMPRESSION_DEFLATE, MNG_FILTER_ADAPTIVE, MNG_INTERLACE_NONE) != 0)
266 synfig::error("%s:%d mng_putchunk_ihdr()", __FILE__, __LINE__);
270 zstream.zalloc = Z_NULL;
271 zstream.zfree = Z_NULL;
272 zstream.opaque = Z_NULL;
274 if (deflateInit(&zstream, /* Z_BEST_COMPRESSION */ Z_DEFAULT_COMPRESSION) != Z_OK)
276 synfig::error("%s:%d deflateInit()", __FILE__, __LINE__);
282 zbuffer_len = deflateBound(&zstream,((4*w)+1)*h); // don't forget the 'filter' byte - one per scanline
283 zbuffer = (unsigned char*)realloc(zbuffer, zbuffer_len);
286 zstream.avail_out = zbuffer_len;
287 zstream.next_out = zbuffer;
295 mng_trgt::start_scanline(int scanline)
301 mng_trgt::end_scanline()
305 synfig::error("%s:%d !file or !ready", __FILE__, __LINE__);
309 *buffer = MNG_FILTER_NONE;
310 convert_color_format(buffer+1, color_buffer, desc.get_w(), PF_RGB|PF_A, gamma());
312 zstream.next_in = buffer;
313 zstream.avail_in = (4*w)+1;
315 if (deflate(&zstream,Z_NO_FLUSH) != Z_OK) {
316 synfig::error("%s:%d deflate()", __FILE__, __LINE__);