moreupdates
[synfig.git] / synfig-core / trunk / src / modules / mod_png / trgt_png.cpp
1 /*! ========================================================================
2 ** Synfig
3 ** png_trgt Target Module
4 ** $Id: trgt_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 /* === H E A D E R S ======================================================= */
22
23 #define SYNFIG_TARGET
24
25 #ifdef USING_PCH
26 #       include "pch.h"
27 #else
28 #ifdef HAVE_CONFIG_H
29 #       include <config.h>
30 #endif
31
32 #include "trgt_png.h"
33 #include <png.h>
34 #include <ETL/stringf>
35 #include <cstdio>
36 #include <algorithm>
37 #include <functional>
38 #include <ETL/misc>
39
40 #endif
41
42 /* === M A C R O S ========================================================= */
43
44 using namespace synfig;
45 using namespace std;
46 using namespace etl;
47
48 /* === G L O B A L S ======================================================= */
49
50 SYNFIG_TARGET_INIT(png_trgt);
51 SYNFIG_TARGET_SET_NAME(png_trgt,"png");
52 SYNFIG_TARGET_SET_EXT(png_trgt,"png");
53 SYNFIG_TARGET_SET_VERSION(png_trgt,"0.1");
54 SYNFIG_TARGET_SET_CVS_ID(png_trgt,"$Id: trgt_png.cpp,v 1.1.1.1 2005/01/04 01:23:14 darco Exp $");
55
56 /* === M E T H O D S ======================================================= */
57
58 void
59 png_trgt::png_out_error(png_struct *png_data,const char *msg)
60 {
61         png_trgt *me=(png_trgt*)png_data->error_ptr;
62         synfig::error(strprintf("png_trgt: error: %s",msg));
63         me->ready=false;
64 }
65
66 void
67 png_trgt::png_out_warning(png_struct *png_data,const char *msg)
68 {
69         png_trgt *me=(png_trgt*)png_data->error_ptr;
70         synfig::warning(strprintf("png_trgt: warning: %s",msg));
71         me->ready=false;
72 }
73
74
75 //Target *png_trgt::New(const char *filename){  return new png_trgt(filename);}
76
77 png_trgt::png_trgt(const char *Filename)
78 {
79         file=NULL;
80         filename=Filename;
81         buffer=NULL;
82         ready=false;
83         color_buffer=0; 
84 }
85
86 png_trgt::~png_trgt()
87 {
88         if(file)
89                 fclose(file);
90         file=NULL;
91         delete [] buffer;
92         delete [] color_buffer;
93 }
94
95 bool
96 png_trgt::set_rend_desc(RendDesc *given_desc)
97 {
98         //given_desc->set_pixel_format(PixelFormat((int)PF_RGB|(int)PF_A));
99         desc=*given_desc;
100         imagecount=desc.get_frame_start();
101         if(desc.get_frame_end()-desc.get_frame_start()>0)
102                 multi_image=true;
103         else
104                 multi_image=false;
105         return true;
106 }
107
108 void
109 png_trgt::end_frame()
110 {
111         if(ready && file)
112         {
113                 png_write_end(png_ptr,info_ptr);
114                 png_destroy_write_struct(&png_ptr, &info_ptr);
115         }
116
117         if(file && file!=stdout)
118                 fclose(file);
119         file=NULL;
120         imagecount++;
121         ready=false;
122 }
123
124 bool
125 png_trgt::start_frame(synfig::ProgressCallback *callback)
126 {
127         int w=desc.get_w(),h=desc.get_h();
128         
129         if(file && file!=stdout)
130                 fclose(file);
131         if(filename=="-")
132         {
133                 if(callback)callback->task(strprintf("(stdout) %d",imagecount).c_str());
134                 file=stdout;
135         }
136         else if(multi_image)
137         {
138                 String
139                         newfilename(filename),
140                         ext(find(filename.begin(),filename.end(),'.'),filename.end());
141                 newfilename.erase(find(newfilename.begin(),newfilename.end(),'.'),newfilename.end());
142                 
143                 newfilename+=etl::strprintf("%04d",imagecount)+ext;
144                 file=fopen(newfilename.c_str(),"wb");
145                 if(callback)callback->task(newfilename);
146         }
147         else
148         {
149                 file=fopen(filename.c_str(),"wb");
150                 if(callback)callback->task(filename);
151         }
152         
153         if(!file)
154                 return false;
155                 
156         delete [] buffer;
157         buffer=new unsigned char[4*w];
158
159         delete [] color_buffer;
160         color_buffer=new Color[w];
161
162         png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)this,png_out_error, png_out_warning);
163         if (!png_ptr)
164         {
165                 synfig::error("Unable to setup PNG struct");
166                 fclose(file);
167                 return false;
168         }
169         
170         info_ptr= png_create_info_struct(png_ptr);
171         if (!info_ptr)
172         {
173                 synfig::error("Unable to setup PNG info struct");
174                 fclose(file);
175                 png_destroy_write_struct(&png_ptr,(png_infopp)NULL);
176                 return false;
177         }
178         
179         if (setjmp(png_jmpbuf(png_ptr)))
180         {
181                 synfig::error("Unable to setup longjump");
182                 png_destroy_write_struct(&png_ptr, &info_ptr);
183                 fclose(file);
184                 return false;
185         }
186         png_init_io(png_ptr,file);
187         png_set_filter(png_ptr,0,PNG_FILTER_NONE);
188
189         setjmp(png_jmpbuf(png_ptr));
190         png_set_IHDR(png_ptr,info_ptr,w,h,8,PNG_COLOR_TYPE_RGBA,PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT);
191
192         // Write the gamma
193         //png_set_gAMA(png_ptr, info_ptr,1.0/gamma().get_gamma());
194         png_set_gAMA(png_ptr, info_ptr,gamma().get_gamma());
195         
196         // Write the physical size
197         png_set_pHYs(png_ptr,info_ptr,round_to_int(desc.get_x_res()),round_to_int(desc.get_y_res()),PNG_RESOLUTION_METER);
198         
199         // Output any text info along with the file
200         png_text comments[]=
201         {
202                 { PNG_TEXT_COMPRESSION_NONE, "Title", const_cast<char *>(get_canvas()->get_name().c_str()) },
203                 { PNG_TEXT_COMPRESSION_NONE, "Description", const_cast<char *>(get_canvas()->get_description().c_str()) },
204                 { PNG_TEXT_COMPRESSION_NONE, "Copyright", "(c) 2004 Voria Studios, LLC" },
205                 { PNG_TEXT_COMPRESSION_NONE, "Software", "SYNFIG" },
206         };
207         png_set_text(png_ptr,info_ptr,comments,sizeof(comments)/sizeof(png_text));
208         
209         png_write_info_before_PLTE(png_ptr, info_ptr);
210         png_write_info(png_ptr, info_ptr);
211         ready=true;
212         return true;
213 }
214
215 Color *
216 png_trgt::start_scanline(int scanline)
217 {
218         return color_buffer;
219 }
220
221 bool
222 png_trgt::end_scanline()
223 {
224         if(!file || !ready)
225                 return false;
226
227         convert_color_format(buffer, color_buffer, desc.get_w(), PF_RGB|PF_A, gamma());
228
229         setjmp(png_jmpbuf(png_ptr));
230         png_write_row(png_ptr,buffer);
231
232         return true;
233 }