interp bilinear fix
[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 "svg.h"
25 #include "svgwin.h"
26 #include "overlayframe.inc"
27
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <unistd.h>
31 #include <fcntl.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <sys/mman.h>
35
36
37 REGISTER_PLUGIN(SvgMain)
38
39 SvgConfig::SvgConfig()
40 {
41         out_x = 0;   out_y = 0;
42         out_w = 640; out_h = 480;
43         dpi = 90;
44         strcpy(svg_file, "");
45         ms_time = 0;
46 }
47
48 int SvgConfig::equivalent(SvgConfig &that)
49 {
50         return EQUIV(dpi, that.dpi) &&
51                 EQUIV(out_x, that.out_x) &&
52                 EQUIV(out_y, that.out_y) &&
53                 EQUIV(out_w, that.out_w) &&
54                 EQUIV(out_h, that.out_h) &&
55                 !strcmp(svg_file, that.svg_file) &&
56                 ms_time == that.ms_time;
57 }
58
59 void SvgConfig::copy_from(SvgConfig &that)
60 {
61         out_x = that.out_x;
62         out_y = that.out_y;
63         out_w = that.out_w;
64         out_h = that.out_h;
65         dpi = that.dpi;
66         strcpy(svg_file, that.svg_file);
67         ms_time = that.ms_time;
68 }
69
70 void SvgConfig::interpolate(SvgConfig &prev, SvgConfig &next,
71         long prev_frame, long next_frame, long current_frame)
72 {
73         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
74         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
75
76         this->out_x = prev.out_x * prev_scale + next.out_x * next_scale;
77         this->out_y = prev.out_y * prev_scale + next.out_y * next_scale;
78         this->out_w = prev.out_w * prev_scale + next.out_w * next_scale;
79         this->out_h = prev.out_h * prev_scale + next.out_h * next_scale;
80         this->dpi = prev.dpi;
81         strcpy(this->svg_file, prev.svg_file);
82         this->ms_time = prev.ms_time;
83 }
84
85
86 SvgMain::SvgMain(PluginServer *server)
87  : PluginVClient(server)
88 {
89         ofrm = 0;
90         overlayer = 0;
91         need_reconfigure = 1;
92 }
93
94 SvgMain::~SvgMain()
95 {
96         delete ofrm;
97         delete overlayer;
98 }
99
100 const char* SvgMain::plugin_title() { return _("SVG via Inkscape"); }
101 int SvgMain::is_realtime() { return 1; }
102 int SvgMain::is_synthesis() { return 1; }
103
104
105 LOAD_CONFIGURATION_MACRO(SvgMain, SvgConfig)
106
107 void SvgMain::save_data(KeyFrame *keyframe)
108 {
109         FileXML output;
110
111 // cause data to be stored directly in text
112         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
113
114         output.tag.set_title("SVG");
115         output.tag.set_property("OUT_X", config.out_x);
116         output.tag.set_property("OUT_Y", config.out_y);
117         output.tag.set_property("OUT_W", config.out_w);
118         output.tag.set_property("OUT_H", config.out_h);
119         output.tag.set_property("DPI", config.dpi);
120         output.tag.set_property("SVG_FILE", config.svg_file);
121         output.tag.set_property("MS_TIME", config.ms_time);
122         output.append_tag();
123         output.tag.set_title("/SVG");
124         output.append_tag();
125
126         output.terminate_string();
127 }
128
129 void SvgMain::read_data(KeyFrame *keyframe)
130 {
131         FileXML input;
132
133         const char *data = keyframe->get_data();
134         input.set_shared_input((char*)data, strlen(data));
135         int result = 0;
136
137         while( !(result = input.read_tag()) ) {
138                 if(input.tag.title_is("SVG")) {
139                         config.out_x = input.tag.get_property("OUT_X", config.out_x);
140                         config.out_y = input.tag.get_property("OUT_Y", config.out_y);
141                         config.out_w = input.tag.get_property("OUT_W", config.out_w);
142                         config.out_h = input.tag.get_property("OUT_H", config.out_h);
143                         config.dpi = input.tag.get_property("DPI", config.dpi);
144                         input.tag.get_property("SVG_FILE", config.svg_file);
145                         config.ms_time = input.tag.get_property("MS_TIME", config.ms_time);
146                 }
147         }
148 }
149
150
151 int SvgMain::process_realtime(VFrame *input, VFrame *output)
152 {
153         if( input != output )
154                 output->copy_from(input);
155
156         int need_export = 0;
157         float last_dpi = config.dpi;
158         char last_svg_file[BCTEXTLEN];
159         strcpy(last_svg_file, config.svg_file);
160         int64_t last_ms_time = config.ms_time;
161         load_configuration();
162         if( last_dpi != config.dpi )
163                 need_export = 1;
164         if( strcmp(last_svg_file, config.svg_file) ||
165             last_ms_time != config.ms_time )
166                 need_reconfigure = 1;
167
168         if( need_reconfigure || need_export ) {
169                 need_reconfigure = 0;
170                 if( config.svg_file[0] == 0 ) return 0;
171                 delete ofrm;  ofrm = 0;
172                 char filename_png[BCTEXTLEN];
173                 strcpy(filename_png, config.svg_file);
174                 strncat(filename_png, ".png", sizeof(filename_png));
175                 struct stat st_png;
176                 int64_t ms_time = need_export || stat(filename_png, &st_png) ? 0 :
177                         st_png.st_mtim.tv_sec*1000 + st_png.st_mtim.tv_nsec/1000000;
178                 int fd = ms_time < config.ms_time ? -1 : open(filename_png, O_RDWR);
179                 if( fd < 0 ) { // file does not exist, export it
180                         char command[BCTEXTLEN];
181                         snprintf(command, sizeof(command),
182                                 "inkscape --without-gui --export-background=0x000000 "
183                                 "--export-background-opacity=0 -d %f %s --export-png=%s",
184                                 config.dpi, config.svg_file, filename_png);
185                         printf(_("Running command %s\n"), command);
186                         system(command);
187                         // in order for lockf to work it has to be open for writing
188                         fd = open(filename_png, O_RDWR);
189                         if( fd < 0 )
190                                 printf(_("Export of %s to %s failed\n"), config.svg_file, filename_png);
191                 }
192                 if( fd >= 0 ) {
193                         ofrm = VFramePng::vframe_png(fd);
194                         close(fd);
195                         if( ofrm && ofrm->get_color_model() != output->get_color_model() ) {
196                                 VFrame *vfrm = new VFrame(ofrm->get_w(), ofrm->get_h(),
197                                         output->get_color_model());
198                                 vfrm->transfer_from(ofrm);
199                                 delete ofrm;  ofrm = vfrm;
200                         }
201                         if( !ofrm )
202                                 printf (_("The file %s that was generated from %s is not in PNG format."
203                                           " Try to delete all *.png files.\n"), filename_png, config.svg_file);
204                 }
205         }
206         if( ofrm ) {
207                 if(!overlayer) overlayer = new OverlayFrame(smp + 1);
208                 overlayer->overlay(output, ofrm,
209                          0, 0, ofrm->get_w(), ofrm->get_h(),
210                         config.out_x, config.out_y,
211                         config.out_x + config.out_w,
212                         config.out_y + config.out_h,
213                         1, TRANSFER_NORMAL, LINEAR_LINEAR);
214         }
215         return 0;
216 }
217
218
219 NEW_WINDOW_MACRO(SvgMain, SvgWin)
220
221 void SvgMain::update_gui()
222 {
223         if(thread) {
224                 load_configuration();
225                 SvgWin *window = (SvgWin*)thread->window;
226                 window->update_gui(config);
227         }
228 }
229