r870: Merge 2.1:
[cinelerra_cv.git] / plugins / svg / svg.C
blobc8fb48434ed689c0cf791412446a8a0fe9d8f77c
1 #include "clip.h"
2 #include "filexml.h"
3 #include "picon_png.h"
4 #include "svg.h"
5 #include "svgwin.h"
6 #include <unistd.h>
7 #include <fcntl.h>
8 #include <string.h>
9 #include <errno.h>
10 #include <sys/mman.h>
13 #include <libintl.h>
14 #define _(String) gettext(String)
15 #define gettext_noop(String) String
16 #define N_(String) gettext_noop (String)
18 #include "empty_svg.h"
20 struct raw_struct {
21         char rawc[5];        // Null terminated "RAWC" string
22         int32_t struct_version;  // currently 1 (bumped at each destructive change) 
23         int32_t struct_size;     // size of this struct in bytes
24         int32_t width;               // logical width of image
25         int32_t height;
26         int32_t pitch;           // physical width of image in memory
27         int32_t color_model;      // as BC_ constant, currently only BC_RGBA8888 is supported
28         int64_t time_of_creation; // in milliseconds - calculated as (tv_sec * 1000 + tv_usec / 1000);
29                                 // we can't trust date on the file, due to different reasons
30 };      
33 REGISTER_PLUGIN(SvgMain)
35 SvgConfig::SvgConfig()
37         in_x = 0;
38         in_y = 0;
39         in_w = 720;
40         in_h = 480;
41         out_x = 0;
42         out_y = 0;
43         out_w = 720;
44         out_h = 480;
45         last_load = 0;
46         strcpy(svg_file, "");
49 int SvgConfig::equivalent(SvgConfig &that)
51         return EQUIV(in_x, that.in_x) && 
52                 EQUIV(in_y, that.in_y) && 
53                 EQUIV(in_w, that.in_w) && 
54                 EQUIV(in_h, that.in_h) &&
55                 EQUIV(out_x, that.out_x) && 
56                 EQUIV(out_y, that.out_y) && 
57                 EQUIV(out_w, that.out_w) &&
58                 EQUIV(out_h, that.out_h) &&
59                 !strcmp(svg_file, that.svg_file);
62 void SvgConfig::copy_from(SvgConfig &that)
64         in_x = that.in_x;
65         in_y = that.in_y;
66         in_w = that.in_w;
67         in_h = that.in_h;
68         out_x = that.out_x;
69         out_y = that.out_y;
70         out_w = that.out_w;
71         out_h = that.out_h;
72         last_load = that.last_load;
73         strcpy(svg_file, that.svg_file);
76 void SvgConfig::interpolate(SvgConfig &prev, 
77         SvgConfig &next, 
78         long prev_frame, 
79         long next_frame, 
80         long current_frame)
82         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
83         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
85         this->in_x = prev.in_x * prev_scale + next.in_x * next_scale;
86         this->in_y = prev.in_y * prev_scale + next.in_y * next_scale;
87         this->in_w = prev.in_w * prev_scale + next.in_w * next_scale;
88         this->in_h = prev.in_h * prev_scale + next.in_h * next_scale;
89         this->out_x = prev.out_x * prev_scale + next.out_x * next_scale;
90         this->out_y = prev.out_y * prev_scale + next.out_y * next_scale;
91         this->out_w = prev.out_w * prev_scale + next.out_w * next_scale;
92         this->out_h = prev.out_h * prev_scale + next.out_h * next_scale;
93         strcpy(this->svg_file, prev.svg_file);
103 SvgMain::SvgMain(PluginServer *server)
104  : PluginVClient(server)
106         temp_frame = 0;
107         overlayer = 0;
108         need_reconfigure = 0;
109         force_raw_render = 0;
110         PLUGIN_CONSTRUCTOR_MACRO
113 SvgMain::~SvgMain()
115         PLUGIN_DESTRUCTOR_MACRO
117         if(temp_frame) delete temp_frame;
118         temp_frame = 0;
119         if(overlayer) delete overlayer;
120         overlayer = 0;
123 char* SvgMain::plugin_title() { return N_("SVG via Inkscape"); }
124 int SvgMain::is_realtime() { return 1; }
125 int SvgMain::is_synthesis() { return 1; }
127 NEW_PICON_MACRO(SvgMain)
129 int SvgMain::load_defaults()
131         char directory[1024], string[1024];
132 // set the default directory
133         sprintf(directory, "%ssvg.rc", BCASTDIR);
135 // load the defaults
136         defaults = new BC_Hash(directory);
137         defaults->load();
140         config.in_x = defaults->get("IN_X", config.in_x);
141         config.in_y = defaults->get("IN_Y", config.in_y);
142         config.in_w = defaults->get("IN_W", config.in_w);
143         config.in_h = defaults->get("IN_H", config.in_h);
144         config.out_x = defaults->get("OUT_X", config.out_x);
145         config.out_y = defaults->get("OUT_Y", config.out_y);
146         config.out_w = defaults->get("OUT_W", config.out_w);
147         config.out_h = defaults->get("OUT_H", config.out_h);
148         strcpy(config.svg_file, "");
149 //      defaults->get("SVG_FILE", config.svg_file);
152 int SvgMain::save_defaults()
154         defaults->update("IN_X", config.in_x);
155         defaults->update("IN_Y", config.in_y);
156         defaults->update("IN_W", config.in_w);
157         defaults->update("IN_H", config.in_h);
158         defaults->update("OUT_X", config.out_x);
159         defaults->update("OUT_Y", config.out_y);
160         defaults->update("OUT_W", config.out_w);
161         defaults->update("OUT_H", config.out_h);
162         defaults->update("SVG_FILE", config.svg_file);
163         defaults->save();
166 LOAD_CONFIGURATION_MACRO(SvgMain, SvgConfig)
168 void SvgMain::save_data(KeyFrame *keyframe)
170         FileXML output;
172 // cause data to be stored directly in text
173         output.set_shared_string(keyframe->data, MESSAGESIZE);
175 // Store data
176         output.tag.set_title("SVG");
177         output.tag.set_property("IN_X", config.in_x);
178         output.tag.set_property("IN_Y", config.in_y);
179         output.tag.set_property("IN_W", config.in_w);
180         output.tag.set_property("IN_H", config.in_h);
181         output.tag.set_property("OUT_X", config.out_x);
182         output.tag.set_property("OUT_Y", config.out_y);
183         output.tag.set_property("OUT_W", config.out_w);
184         output.tag.set_property("OUT_H", config.out_h);
185         output.tag.set_property("SVG_FILE", config.svg_file);
186         output.append_tag();
188         output.terminate_string();
189 // data is now in *text
192 void SvgMain::read_data(KeyFrame *keyframe)
194         FileXML input;
196         input.set_shared_string(keyframe->data, strlen(keyframe->data));
198         int result = 0;
200         while(!result)
201         {
202                 result = input.read_tag();
204                 if(!result)
205                 {
206                         if(input.tag.title_is("SVG"))
207                         {
208                                 config.in_x = input.tag.get_property("IN_X", config.in_x);
209                                 config.in_y = input.tag.get_property("IN_Y", config.in_y);
210                                 config.in_w = input.tag.get_property("IN_W", config.in_w);
211                                 config.in_h = input.tag.get_property("IN_H", config.in_h);
212                                 config.out_x =  input.tag.get_property("OUT_X", config.out_x);
213                                 config.out_y =  input.tag.get_property("OUT_Y", config.out_y);
214                                 config.out_w =  input.tag.get_property("OUT_W", config.out_w);
215                                 config.out_h =  input.tag.get_property("OUT_H", config.out_h);
216                                 input.tag.get_property("SVG_FILE", config.svg_file);
217                         }
218                 }
219         }
229 int SvgMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
231         char filename_raw[1024];
232         int fh_raw;
233         struct stat st_raw;
234         VFrame *input, *output;
235         input = input_ptr;
236         output = output_ptr;
237         unsigned char * raw_buffer;
238         struct raw_struct *raw_data;
240         need_reconfigure |= load_configuration();
242         if (config.svg_file[0] == 0) {
243                 output->copy_from(input);
244                 return(0);
245         }
247         strcpy(filename_raw, config.svg_file);
248         strcat(filename_raw, ".raw");
249         fh_raw = open(filename_raw, O_RDWR); // in order for lockf to work it has to be open for writing
251         if (fh_raw == -1 || force_raw_render) // file does not exist, export it
252         {
253                 need_reconfigure = 1;
254                 char command[1024];
255                 sprintf(command,
256                         "inkscape --without-gui --cinelerra-export-file=%s %s",
257                         filename_raw, config.svg_file);
258                 printf(_("Running command %s\n"), command);
259                 system(command);
260                 stat(filename_raw, &st_raw);
261                 force_raw_render = 0;
262                 fh_raw = open(filename_raw, O_RDWR); // in order for lockf to work it has to be open for writing
263                 if (!fh_raw) {
264                         printf(_("Export of %s to %s failed\n"), config.svg_file, filename_raw);
265                         return 0;
266                 }
267         }
270         // file exists, ... lock it, mmap it and check time_of_creation
271         lockf(fh_raw, F_LOCK, 0);    // Blocking call - will wait for inkscape to finish!
272         fstat (fh_raw, &st_raw);
273         raw_buffer = (unsigned char *)mmap (NULL, st_raw.st_size, PROT_READ, MAP_SHARED, fh_raw, 0); 
274         raw_data = (struct raw_struct *) raw_buffer;
276         if (strcmp(raw_data->rawc, "RAWC")) 
277         {
278                 printf (_("The file %s that was generated from %s is not in RAWC format. Try to delete all *.raw files.\n"), filename_raw, config.svg_file);    
279                 lockf(fh_raw, F_ULOCK, 0);
280                 close(fh_raw);
281                 return (0);
282         }
283         if (raw_data->struct_version > 1) 
284         {
285                 printf (_("Unsupported version of RAWC file %s. This means your Inkscape uses newer RAWC format than Cinelerra. Please upgrade Cinelerra.\n"), filename_raw);
286                 lockf(fh_raw, F_ULOCK, 0);
287                 close(fh_raw);
288                 return (0);
289         }
290         // Ok, we can now be sure we have valid RAWC file on our hands
291         if (need_reconfigure || config.last_load < raw_data->time_of_creation) {    // the file was updated or is new (then last_load is zero)
293                 if (temp_frame && 
294                   !temp_frame->params_match(raw_data->width, raw_data->height, output_ptr->get_color_model()))
295                 {
296                         // parameters don't match
297                         delete temp_frame;
298                         temp_frame = 0;
299                 }
300                 if (!temp_frame)                        
301                         temp_frame = new VFrame(0, 
302                                         raw_data->width,
303                                         raw_data->height,
304                                         output_ptr->get_color_model());
306                 // temp_frame is ready by now, we can do the loading
307                 unsigned char ** raw_rows;
308                 raw_rows = new unsigned char*[raw_data->height]; // this could be optimized, so new isn't used every time
309                 for (int i = 0; i < raw_data->height; i++) {
310                         raw_rows[i] = raw_buffer + raw_data->struct_size + raw_data->pitch * i * 4;
311                 }
312                 cmodel_transfer(temp_frame->get_rows(),
313                         raw_rows,
314                         0,
315                         0,
316                         0,
317                         0,
318                         0,
319                         0,
320                         0,
321                         0,
322                         raw_data->width,
323                         raw_data->height,
324                         0,
325                         0,
326                         temp_frame->get_w(),
327                         temp_frame->get_h(),
328                         BC_RGBA8888,
329                         temp_frame->get_color_model(),
330                         0,
331                         raw_data->pitch,
332                         temp_frame->get_w());
333                 delete [] raw_rows;
334                 munmap(raw_buffer, st_raw.st_size);
335                 lockf(fh_raw, F_ULOCK, 0);
336                 close(fh_raw);
339         }       
340         // by now we have temp_frame ready, we just need to overylay it
342         if(!overlayer)
343         {
344                 overlayer = new OverlayFrame(smp + 1);
345         }
349 // printf("SvgMain::process_realtime 3 output=%p input=%p config.w=%f config.h=%f"
350 //      "%f %f %f %f -> %f %f %f %f\n", 
351 //      output,
352 //      input,
353 //      config.w, 
354 //      config.h,
355 //      in_x1, 
356 //      in_y1, 
357 //      in_x2, 
358 //      in_y2,
359 //      out_x1, 
360 //      out_y1, 
361 //      out_x2, 
362 //      out_y2);
363                 output->copy_from(input);
364                 overlayer->overlay(output, 
365                         temp_frame,
366                         0, 
367                         0, 
368                         temp_frame->get_w(),
369                         temp_frame->get_h(),
370                         config.out_x, 
371                         config.out_y, 
372                         config.out_x + temp_frame->get_w(),
373                         config.out_y + temp_frame->get_h(),
374                         1,
375                         TRANSFER_NORMAL,
376                         get_interpolation_type());
378         return(0);
384 SHOW_GUI_MACRO(SvgMain, SvgThread)
385                                                               
386 RAISE_WINDOW_MACRO(SvgMain)
388 SET_STRING_MACRO(SvgMain)
390 void SvgMain::update_gui()
392         if(thread)
393         {
394                 load_configuration();
395                 thread->window->lock_window();
396 //              thread->window->in_x->update(config.in_x);
397 //              thread->window->in_y->update(config.in_y);
398 //              thread->window->in_w->update(config.in_w);
399 //              thread->window->in_h->update(config.in_h);
400                 thread->window->out_x->update(config.out_x);
401                 thread->window->out_y->update(config.out_y);
402 //              thread->window->out_w->update(config.out_w);
403 //              thread->window->out_h->update(config.out_h);
404                 thread->window->svg_file_title->update(config.svg_file);
405                 thread->window->unlock_window();
406         }