r726: Implementing ability to add textural info to the labels
[cinelerra_cv/mob.git] / plugins / svg / svg.C
blobc0eb90b530babfa1fe9bd6e5d9ac31dd6b598073
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 Sodipodi"); }
124 int SvgMain::is_realtime() { return 1; }
126 NEW_PICON_MACRO(SvgMain)
128 int SvgMain::load_defaults()
130         char directory[1024], string[1024];
131 // set the default directory
132         sprintf(directory, "%ssvg.rc", BCASTDIR);
134 // load the defaults
135         defaults = new Defaults(directory);
136         defaults->load();
139         config.in_x = defaults->get("IN_X", config.in_x);
140         config.in_y = defaults->get("IN_Y", config.in_y);
141         config.in_w = defaults->get("IN_W", config.in_w);
142         config.in_h = defaults->get("IN_H", config.in_h);
143         config.out_x = defaults->get("OUT_X", config.out_x);
144         config.out_y = defaults->get("OUT_Y", config.out_y);
145         config.out_w = defaults->get("OUT_W", config.out_w);
146         config.out_h = defaults->get("OUT_H", config.out_h);
147         strcpy(config.svg_file, "");
148 //      defaults->get("SVG_FILE", config.svg_file);
151 int SvgMain::save_defaults()
153         defaults->update("IN_X", config.in_x);
154         defaults->update("IN_Y", config.in_y);
155         defaults->update("IN_W", config.in_w);
156         defaults->update("IN_H", config.in_h);
157         defaults->update("OUT_X", config.out_x);
158         defaults->update("OUT_Y", config.out_y);
159         defaults->update("OUT_W", config.out_w);
160         defaults->update("OUT_H", config.out_h);
161         defaults->update("SVG_FILE", config.svg_file);
162         defaults->save();
165 LOAD_CONFIGURATION_MACRO(SvgMain, SvgConfig)
167 void SvgMain::save_data(KeyFrame *keyframe)
169         FileXML output;
171 // cause data to be stored directly in text
172         output.set_shared_string(keyframe->data, MESSAGESIZE);
174 // Store data
175         output.tag.set_title("SVG");
176         output.tag.set_property("IN_X", config.in_x);
177         output.tag.set_property("IN_Y", config.in_y);
178         output.tag.set_property("IN_W", config.in_w);
179         output.tag.set_property("IN_H", config.in_h);
180         output.tag.set_property("OUT_X", config.out_x);
181         output.tag.set_property("OUT_Y", config.out_y);
182         output.tag.set_property("OUT_W", config.out_w);
183         output.tag.set_property("OUT_H", config.out_h);
184         output.tag.set_property("SVG_FILE", config.svg_file);
185         output.append_tag();
187         output.terminate_string();
188 // data is now in *text
191 void SvgMain::read_data(KeyFrame *keyframe)
193         FileXML input;
195         input.set_shared_string(keyframe->data, strlen(keyframe->data));
197         int result = 0;
199         while(!result)
200         {
201                 result = input.read_tag();
203                 if(!result)
204                 {
205                         if(input.tag.title_is("SVG"))
206                         {
207                                 config.in_x = input.tag.get_property("IN_X", config.in_x);
208                                 config.in_y = input.tag.get_property("IN_Y", config.in_y);
209                                 config.in_w = input.tag.get_property("IN_W", config.in_w);
210                                 config.in_h = input.tag.get_property("IN_H", config.in_h);
211                                 config.out_x =  input.tag.get_property("OUT_X", config.out_x);
212                                 config.out_y =  input.tag.get_property("OUT_Y", config.out_y);
213                                 config.out_w =  input.tag.get_property("OUT_W", config.out_w);
214                                 config.out_h =  input.tag.get_property("OUT_H", config.out_h);
215                                 input.tag.get_property("SVG_FILE", config.svg_file);
216                         }
217                 }
218         }
228 int SvgMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
230         char filename_raw[1024];
231         int fh_raw;
232         struct stat st_raw;
233         VFrame *input, *output;
234         input = input_ptr;
235         output = output_ptr;
236         unsigned char * raw_buffer;
237         struct raw_struct *raw_data;
239         need_reconfigure |= load_configuration();
241         if (config.svg_file[0] == 0) {
242                 output->copy_from(input);
243                 return(0);
244         }
246         strcpy(filename_raw, config.svg_file);
247         strcat(filename_raw, ".raw");
248         fh_raw = open(filename_raw, O_RDWR); // in order for lockf to work it has to be open for writing
250         if (fh_raw == -1 || force_raw_render) // file does not exist, export it
251         {
252                 need_reconfigure = 1;
253                 char command[1024];
254                 sprintf(command,
255                         "sodipodi --without-gui --cinelerra-export-file=%s %s",
256                         filename_raw, config.svg_file);
257                 printf(_("Running command %s\n"), command);
258                 system(command);
259                 stat(filename_raw, &st_raw);
260                 force_raw_render = 0;
261                 fh_raw = open(filename_raw, O_RDWR); // in order for lockf to work it has to be open for writing
262                 if (!fh_raw) {
263                         printf(_("Export of %s to %s failed\n"), config.svg_file, filename_raw);
264                         return 0;
265                 }
266         }
269         // file exists, ... lock it, mmap it and check time_of_creation
270         lockf(fh_raw, F_LOCK, 0);    // Blocking call - will wait for sodipodi to finish!
271         fstat (fh_raw, &st_raw);
272         raw_buffer = (unsigned char *)mmap (NULL, st_raw.st_size, PROT_READ, MAP_SHARED, fh_raw, 0); 
273         raw_data = (struct raw_struct *) raw_buffer;
275         if (strcmp(raw_data->rawc, "RAWC")) 
276         {
277                 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);    
278                 lockf(fh_raw, F_ULOCK, 0);
279                 close(fh_raw);
280                 return (0);
281         }
282         if (raw_data->struct_version > 1) 
283         {
284                 printf (_("Unsupported version of RAWC file %s. This means your Sodipodi uses newer RAWC format than Cinelerra. Please upgrade Cinelerra.\n"), filename_raw);
285                 lockf(fh_raw, F_ULOCK, 0);
286                 close(fh_raw);
287                 return (0);
288         }
289         // Ok, we can now be sure we have valid RAWC file on our hands
290         if (need_reconfigure || config.last_load < raw_data->time_of_creation) {    // the file was updated or is new (then last_load is zero)
292                 if (temp_frame && 
293                   !temp_frame->params_match(raw_data->width, raw_data->height, output_ptr->get_color_model()))
294                 {
295                         // parameters don't match
296                         delete temp_frame;
297                         temp_frame = 0;
298                 }
299                 if (!temp_frame)                        
300                         temp_frame = new VFrame(0, 
301                                         raw_data->width,
302                                         raw_data->height,
303                                         output_ptr->get_color_model());
305                 // temp_frame is ready by now, we can do the loading
306                 unsigned char ** raw_rows;
307                 raw_rows = new unsigned char*[raw_data->height]; // this could be optimized, so new isn't used every time
308                 for (int i = 0; i < raw_data->height; i++) {
309                         raw_rows[i] = raw_buffer + raw_data->struct_size + raw_data->pitch * i * 4;
310                 }
311                 cmodel_transfer(temp_frame->get_rows(),
312                         raw_rows,
313                         0,
314                         0,
315                         0,
316                         0,
317                         0,
318                         0,
319                         0,
320                         0,
321                         raw_data->width,
322                         raw_data->height,
323                         0,
324                         0,
325                         temp_frame->get_w(),
326                         temp_frame->get_h(),
327                         BC_RGBA8888,
328                         temp_frame->get_color_model(),
329                         0,
330                         raw_data->pitch,
331                         temp_frame->get_w());
332                 delete [] raw_rows;
333                 munmap(raw_buffer, st_raw.st_size);
334                 lockf(fh_raw, F_ULOCK, 0);
335                 close(fh_raw);
338         }       
339         // by now we have temp_frame ready, we just need to overylay it
341         if(!overlayer)
342         {
343                 overlayer = new OverlayFrame(smp + 1);
344         }
348 // printf("SvgMain::process_realtime 3 output=%p input=%p config.w=%f config.h=%f"
349 //      "%f %f %f %f -> %f %f %f %f\n", 
350 //      output,
351 //      input,
352 //      config.w, 
353 //      config.h,
354 //      in_x1, 
355 //      in_y1, 
356 //      in_x2, 
357 //      in_y2,
358 //      out_x1, 
359 //      out_y1, 
360 //      out_x2, 
361 //      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         }