x265 update 2.7, findobj upgrade, fix svg init, fix for dragchkbox buttonpress, add...
[goodguy/history.git] / cinelerra-5.1 / plugins / svg / svg.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "clip.h"
22 #include "filexml.h"
23 #include "language.h"
24 #include "mainerror.h"
25 #include "svg.h"
26 #include "svgwin.h"
27 #include "overlayframe.inc"
28
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <unistd.h>
32 #include <fcntl.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <sys/mman.h>
36 #include <sys/types.h>
37 #include <sys/wait.h>
38
39
40 REGISTER_PLUGIN(SvgMain)
41
42 SvgConfig::SvgConfig()
43 {
44         out_x = 0;   out_y = 0;
45         out_w = 640; out_h = 480;
46         dpi = 90;
47         strcpy(svg_file, "");
48         ms_time = 0;
49 }
50
51 int SvgConfig::equivalent(SvgConfig &that)
52 {
53         return EQUIV(dpi, that.dpi) &&
54                 EQUIV(out_x, that.out_x) &&
55                 EQUIV(out_y, that.out_y) &&
56                 EQUIV(out_w, that.out_w) &&
57                 EQUIV(out_h, that.out_h) &&
58                 !strcmp(svg_file, that.svg_file) &&
59                 ms_time != 0 && that.ms_time != 0 &&
60                 ms_time == that.ms_time;
61 }
62
63 void SvgConfig::copy_from(SvgConfig &that)
64 {
65         out_x = that.out_x;
66         out_y = that.out_y;
67         out_w = that.out_w;
68         out_h = that.out_h;
69         dpi = that.dpi;
70         strcpy(svg_file, that.svg_file);
71         ms_time = that.ms_time;
72 }
73
74 void SvgConfig::interpolate(SvgConfig &prev, SvgConfig &next,
75         long prev_frame, long next_frame, long current_frame)
76 {
77         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
78         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
79
80         this->out_x = prev.out_x * prev_scale + next.out_x * next_scale;
81         this->out_y = prev.out_y * prev_scale + next.out_y * next_scale;
82         this->out_w = prev.out_w * prev_scale + next.out_w * next_scale;
83         this->out_h = prev.out_h * prev_scale + next.out_h * next_scale;
84         this->dpi = prev.dpi;
85         strcpy(this->svg_file, prev.svg_file);
86         this->ms_time = prev.ms_time;
87 }
88
89
90 SvgMain::SvgMain(PluginServer *server)
91  : PluginVClient(server)
92 {
93         ofrm = 0;
94         overlayer = 0;
95         need_reconfigure = 1;
96 }
97
98 SvgMain::~SvgMain()
99 {
100         delete ofrm;
101         delete overlayer;
102 }
103
104 const char* SvgMain::plugin_title() { return N_("SVG via Inkscape"); }
105 int SvgMain::is_realtime() { return 1; }
106 int SvgMain::is_synthesis() { return 1; }
107
108
109 LOAD_CONFIGURATION_MACRO(SvgMain, SvgConfig)
110
111 void SvgMain::save_data(KeyFrame *keyframe)
112 {
113         FileXML output;
114
115 // cause data to be stored directly in text
116         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
117
118         output.tag.set_title("SVG");
119         output.tag.set_property("OUT_X", config.out_x);
120         output.tag.set_property("OUT_Y", config.out_y);
121         output.tag.set_property("OUT_W", config.out_w);
122         output.tag.set_property("OUT_H", config.out_h);
123         output.tag.set_property("DPI", config.dpi);
124         output.tag.set_property("SVG_FILE", config.svg_file);
125         output.tag.set_property("MS_TIME", config.ms_time);
126         output.append_tag();
127         output.tag.set_title("/SVG");
128         output.append_tag();
129
130         output.terminate_string();
131 }
132
133 void SvgMain::read_data(KeyFrame *keyframe)
134 {
135         FileXML input;
136
137         const char *data = keyframe->get_data();
138         input.set_shared_input((char*)data, strlen(data));
139         int result = 0;
140
141         while( !(result = input.read_tag()) ) {
142                 if(input.tag.title_is("SVG")) {
143                         config.out_x = input.tag.get_property("OUT_X", config.out_x);
144                         config.out_y = input.tag.get_property("OUT_Y", config.out_y);
145                         config.out_w = input.tag.get_property("OUT_W", config.out_w);
146                         config.out_h = input.tag.get_property("OUT_H", config.out_h);
147                         config.dpi = input.tag.get_property("DPI", config.dpi);
148                         input.tag.get_property("SVG_FILE", config.svg_file);
149                         config.ms_time = input.tag.get_property("MS_TIME", config.ms_time);
150                 }
151         }
152 }
153
154 static int exec_command(char* const*argv)
155 {
156         pid_t pid = vfork();
157         if( pid < 0 ) return -1;
158         if( pid > 0 ) {
159                 int stat = 0;
160                 waitpid(pid, &stat, 0);
161                 if( stat ) {
162                         char msg[BCTEXTLEN];
163                         sprintf(msg, "%s: error exit status %d", argv[0], stat);
164                         MainError::show_error(msg);
165                 }
166                 return 0;
167         }
168         execvp(argv[0], &argv[0]);
169         return -1;
170 }
171
172
173 int SvgMain::process_realtime(VFrame *input, VFrame *output)
174 {
175         if( input != output )
176                 output->copy_from(input);
177
178         int need_export = 0;
179         float last_dpi = config.dpi;
180         char last_svg_file[BCTEXTLEN];
181         strcpy(last_svg_file, config.svg_file);
182         int64_t last_ms_time = config.ms_time;
183         need_reconfigure = load_configuration();
184         if( !ofrm || last_dpi != config.dpi )
185                 need_export = 1;
186         if( strcmp(last_svg_file, config.svg_file) ||
187             last_ms_time != config.ms_time )
188                 need_reconfigure = 1;
189
190         if( need_reconfigure || need_export ) {
191                 need_reconfigure = 0;
192                 if( config.svg_file[0] == 0 ) return 0;
193                 delete ofrm;  ofrm = 0;
194                 char filename_png[BCTEXTLEN];
195                 strcpy(filename_png, config.svg_file);
196                 strncat(filename_png, ".png", sizeof(filename_png));
197                 struct stat st_png;
198                 int64_t ms_time = need_export || stat(filename_png, &st_png) ? 0 :
199                         st_png.st_mtim.tv_sec*1000 + st_png.st_mtim.tv_nsec/1000000;
200                 int fd = ms_time < config.ms_time ? -1 : open(filename_png, O_RDWR);
201                 if( fd < 0 ) { // file does not exist, export it
202                         char command[BCTEXTLEN], dpi[BCSTRLEN];
203                         snprintf(command, sizeof(command),
204                                 "inkscape --without-gui --export-background=0x000000 "
205                                 "--export-background-opacity=0 -d %f %s --export-png=%s",
206                                 config.dpi, config.svg_file, filename_png);
207                         printf(_("Running command %s\n"), command);
208                         snprintf(dpi, sizeof(dpi), "%f", config.dpi);
209                         snprintf(command, sizeof(command), "--export-png=%s",filename_png);
210                         char *const argv[] = {
211                                 (char*)"inkscape",
212                                 (char*)"--without-gui",
213                                 (char*)"--export-background=0x000000",
214                                 (char*)"--export-background-opacity=0",
215                                 (char*)"-d", dpi, config.svg_file, command,
216                                 0, };
217                         exec_command(argv);
218                         // in order for lockf to work it has to be open for writing
219                         fd = open(filename_png, O_RDWR);
220                         if( fd < 0 )
221                                 printf(_("Export of %s to %s failed\n"), config.svg_file, filename_png);
222                 }
223                 if( fd >= 0 ) {
224                         ofrm = VFramePng::vframe_png(fd);
225                         close(fd);
226                         if( ofrm && ofrm->get_color_model() != output->get_color_model() ) {
227                                 VFrame *vfrm = new VFrame(ofrm->get_w(), ofrm->get_h(),
228                                         output->get_color_model(), 0);
229                                 vfrm->transfer_from(ofrm);
230                                 delete ofrm;  ofrm = vfrm;
231                         }
232                         if( !ofrm )
233                                 printf (_("The file %s that was generated from %s is not in PNG format."
234                                           " Try to delete all *.png files.\n"), filename_png, config.svg_file);
235                 }
236         }
237         if( ofrm ) {
238                 if(!overlayer) overlayer = new OverlayFrame(smp + 1);
239                 overlayer->overlay(output, ofrm,
240                          0, 0, ofrm->get_w(), ofrm->get_h(),
241                         config.out_x, config.out_y,
242                         config.out_x + config.out_w,
243                         config.out_y + config.out_h,
244                         1, TRANSFER_NORMAL, LINEAR_LINEAR);
245         }
246         return 0;
247 }
248
249
250 NEW_WINDOW_MACRO(SvgMain, SvgWin)
251
252 void SvgMain::update_gui()
253 {
254         if(thread) {
255                 load_configuration();
256                 SvgWin *window = (SvgWin*)thread->window;
257                 window->update_gui(config);
258         }
259 }
260