627f1dd3b500c4ae795dcec8e53ff195c2d16753
[synfig.git] / synfig-core / trunk / src / modules / mod_imagemagick / trgt_imagemagick.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file trgt_imagemagick.cpp
3 **      \brief ppm Target Module
4 **
5 **      \legal
6 ** $Id$
7 **
8 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
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 ** ========================================================================= */
24
25 /* === H E A D E R S ======================================================= */
26
27 #define SYNFIG_TARGET
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 <ETL/stringf>
37 #include "trgt_imagemagick.h"
38 #include <stdio.h>
39 #include <sys/types.h>
40 #if HAVE_SYS_WAIT_H
41  #include <sys/wait.h>
42 #endif
43 #if HAVE_IO_H
44  #include <io.h>
45 #endif
46 #if HAVE_PROCESS_H
47  #include <process.h>
48 #endif
49 #if HAVE_FCNTL_H
50  #include <fcntl.h>
51 #endif
52 #include <unistd.h>
53 #include <algorithm>
54 #include <functional>
55 #include <ETL/clock>
56 #include <ETL/misc>
57
58 #endif
59
60 /* === M A C R O S ========================================================= */
61
62 using namespace synfig;
63 using namespace std;
64 using namespace etl;
65
66 #if defined(HAVE_FORK) && defined(HAVE_PIPE) && defined(HAVE_WAITPID)
67  #define UNIX_PIPE_TO_PROCESSES
68 #else
69  #define WIN32_PIPE_TO_PROCESSES
70 #endif
71
72 /* === G L O B A L S ======================================================= */
73
74 SYNFIG_TARGET_INIT(imagemagick_trgt);
75 SYNFIG_TARGET_SET_NAME(imagemagick_trgt,"imagemagick");
76 SYNFIG_TARGET_SET_EXT(imagemagick_trgt,"miff");
77 SYNFIG_TARGET_SET_VERSION(imagemagick_trgt,"0.1");
78 SYNFIG_TARGET_SET_CVS_ID(imagemagick_trgt,"$Id$");
79
80 /* === M E T H O D S ======================================================= */
81
82 imagemagick_trgt::imagemagick_trgt(const char *Filename)
83 {
84         pid=-1;
85         file=NULL;
86         filename=Filename;
87         multi_image=false;
88         buffer=NULL;
89         color_buffer=0;
90 }
91
92 imagemagick_trgt::~imagemagick_trgt()
93 {
94         if(file){
95 #if defined(WIN32_PIPE_TO_PROCESSES)
96                 pclose(file);
97 #elif defined(UNIX_PIPE_TO_PROCESSES)
98                 fclose(file);
99                 int status;
100                 waitpid(pid,&status,0);
101 #endif
102         }
103         file=NULL;
104         delete [] buffer;
105         delete [] color_buffer;
106 }
107
108 bool
109 imagemagick_trgt::set_rend_desc(RendDesc *given_desc)
110 {
111         if(filename_extension(filename) == ".xpm")
112                 pf=PF_RGB;
113         else
114                 pf=PF_RGB|PF_A;
115
116         desc=*given_desc;
117         return true;
118 }
119
120 bool
121 imagemagick_trgt::init()
122 {
123         imagecount=desc.get_frame_start();
124         if(desc.get_frame_end()-desc.get_frame_start()>0)
125                 multi_image=true;
126
127         delete [] buffer;
128         buffer=new unsigned char[channels(pf)*desc.get_w()];
129         delete [] color_buffer;
130         color_buffer=new Color[desc.get_w()];
131         return true;
132 }
133
134 void
135 imagemagick_trgt::end_frame()
136 {
137         if(file)
138         {
139                 fputc(0,file);
140                 fflush(file);
141 #if defined(WIN32_PIPE_TO_PROCESSES)
142                 pclose(file);
143 #elif defined(UNIX_PIPE_TO_PROCESSES)
144                 fclose(file);
145                 int status;
146                 waitpid(pid,&status,0);
147 #endif
148         }
149         file=NULL;
150         imagecount++;
151 }
152
153 bool
154 imagemagick_trgt::start_frame(synfig::ProgressCallback *cb)
155 {
156         const char *msg=_("Unable to open pipe to imagemagick's convert utility");
157
158         string newfilename;
159
160         if (multi_image)
161                 newfilename = (filename_sans_extension(filename) +
162                                            etl::strprintf(".%04d",imagecount) +
163                                            filename_extension(filename));
164         else
165                 newfilename = filename;
166
167 #if defined(WIN32_PIPE_TO_PROCESSES)
168
169         string command;
170
171         command=strprintf("convert -depth 8 -size %dx%d rgb%s:-[0] -density %dx%d \"%s\"\n",
172                           desc.get_w(), desc.get_h(),                                   // size
173                           ((channels(pf) == 4) ? "a" : ""),                             // rgba or rgb?
174                           round_to_int(desc.get_x_res()/39.3700787402), // density
175                           round_to_int(desc.get_y_res()/39.3700787402),
176                           newfilename.c_str());
177
178         file=popen(command.c_str(),POPEN_BINARY_WRITE_TYPE);
179
180 #elif defined(UNIX_PIPE_TO_PROCESSES)
181
182         int p[2];
183   
184         if (pipe(p)) {
185                 if(cb) cb->error(N_(msg));
186                 else synfig::error(N_(msg));
187                 return false;
188         };
189   
190         pid = fork();
191   
192         if (pid == -1) {
193                 if(cb) cb->error(N_(msg));
194                 else synfig::error(N_(msg));
195                 return false;
196         }
197         
198         if (pid == 0){
199                 // Child process
200                 // Close pipeout, not needed
201                 close(p[1]);
202                 // Dup pipeout to stdin
203                 if( dup2( p[0], STDIN_FILENO ) == -1 ){
204                         if(cb) cb->error(N_(msg));
205                         else synfig::error(N_(msg));
206                         return false;
207                 }
208                 // Close the unneeded pipeout
209                 close(p[0]);
210                 execlp("convert", "convert",
211                         "-depth", "8",
212                         "-size", strprintf("%dx%d", desc.get_w(), desc.get_h()).c_str(),
213                         ((channels(pf) == 4) ? "rgba:-[0]" : "rgb:-[0]"),
214                         "-density", strprintf("%dx%d", round_to_int(desc.get_x_res()/39.3700787402), round_to_int(desc.get_y_res()/39.3700787402)).c_str(),
215                         newfilename.c_str(),
216                         (const char *)NULL);
217                 // We should never reach here unless the exec failed
218                 if(cb) cb->error(N_(msg));
219                 else synfig::error(N_(msg));
220                 return false;
221         } else {
222                 // Parent process
223                 // Close pipein, not needed
224                 close(p[0]);
225                 // Save pipeout to file handle, will write to it later
226                 file = fdopen(p[1], "wb");
227         }
228
229 #else
230         #error There are no known APIs for creating child processes
231 #endif
232
233         if(!file)
234         {
235                 if(cb)cb->error(N_(msg));
236                 else synfig::error(N_(msg));
237                 return false;
238         }
239
240         //etl::yield();
241
242         return true;
243 }
244
245 Color *
246 imagemagick_trgt::start_scanline(int /*scanline*/)
247 {
248         return color_buffer;
249 }
250
251 bool
252 imagemagick_trgt::end_scanline(void)
253 {
254         if(!file)
255                 return false;
256
257         convert_color_format(buffer, color_buffer, desc.get_w(), pf, gamma());
258
259         if(!fwrite(buffer,channels(pf),desc.get_w(),file))
260                 return false;
261
262         return true;
263 }