Fix g++ 4.3 issues; add missing <cstring> includes, remove storage class on explicit...
[synfig.git] / synfig-core / trunk / src / tool / main.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file tool/main.cpp
3 **      \brief SYNFIG Tool
4 **
5 **      $Id$
6 **
7 **      \legal
8 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **      Copyright (c) 2007 Chris Moore
10 **
11 **      This package is free software; you can redistribute it and/or
12 **      modify it under the terms of the GNU General Public License as
13 **      published by the Free Software Foundation; either version 2 of
14 **      the License, or (at your option) any later version.
15 **
16 **      This package is distributed in the hope that it will be useful,
17 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
18 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 **      General Public License for more details.
20 **      \endlegal
21 */
22 /* ========================================================================= */
23
24 /* === H E A D E R S ======================================================= */
25
26 #ifdef USING_PCH
27 #       include "pch.h"
28 #else
29 #ifdef HAVE_CONFIG_H
30 #       include <config.h>
31 #endif
32
33 #include <iostream>
34 #include <ETL/stringf>
35 #include <list>
36 #include <ETL/clock>
37 #include <algorithm>
38 #include <cstring>
39
40 #include <synfig/loadcanvas.h>
41 #include <synfig/savecanvas.h>
42 #include <synfig/target_scanline.h>
43 #include <synfig/module.h>
44 #include <synfig/importer.h>
45 #include <synfig/layer.h>
46 #include <synfig/canvas.h>
47 #include <synfig/target.h>
48 #include <synfig/time.h>
49 #include <synfig/string.h>
50 #include <synfig/paramdesc.h>
51 #include <synfig/main.h>
52 #include <synfig/guid.h>
53 #endif
54
55 using namespace std;
56 using namespace etl;
57 using namespace synfig;
58
59 /* === M A C R O S ========================================================= */
60
61 #undef _
62 #define _(x) gettext(x)
63
64 enum exit_code
65 {
66         SYNFIGTOOL_OK                           = 0,
67         SYNFIGTOOL_FILENOTFOUND         = 1,
68         SYNFIGTOOL_BORED                        = 2,
69         SYNFIGTOOL_HELP                         = 3,
70         SYNFIGTOOL_UNKNOWNARGUMENT      = 4,
71         SYNFIGTOOL_UNKNOWNERROR         = 5,
72         SYNFIGTOOL_INVALIDTARGET        = 6,
73         SYNFIGTOOL_RENDERFAILURE        = 7,
74         SYNFIGTOOL_BLANK                        = 8,
75         SYNFIGTOOL_BADVERSION           = 9,
76         SYNFIGTOOL_MISSINGARGUMENT      =10
77 };
78
79 #ifndef VERSION
80 #define VERSION "unknown"
81 #define PACKAGE "synfig-tool"
82 #endif
83
84 #ifdef DEFAULT_QUALITY
85 #undef DEFAULT_QUALITY
86 #endif
87
88 #define DEFAULT_QUALITY         2
89 #define VERBOSE_OUT(x) if(verbosity>=(x))std::cerr
90
91 /* === G L O B A L S ======================================================= */
92
93 const char *progname;
94 int verbosity=0;
95 bool be_quiet=false;
96 bool print_benchmarks=false;
97
98 /* === M E T H O D S ======================================================= */
99
100 class Progress : public synfig::ProgressCallback
101 {
102         const char *program;
103
104 public:
105
106         Progress(const char *name):program(name) { }
107
108         virtual bool
109         task(const String &task)
110         {
111                 VERBOSE_OUT(1)<<program<<": "<<task<<std::endl;
112                 return true;
113         }
114
115         virtual bool
116         error(const String &task)
117         {
118                 std::cerr<<program<<": "<<_("error")<<": "<<task<<std::endl;
119                 return true;
120         }
121
122         virtual bool
123         warning(const String &task)
124         {
125                 std::cerr<<program<<": "<<_("warning")<<": "<<task<<std::endl;
126                 return true;
127         }
128
129         virtual bool
130         amount_complete(int /*current*/, int /*total*/)
131         {
132                 return true;
133         }
134 };
135
136 class RenderProgress : public synfig::ProgressCallback
137 {
138         string taskname;
139
140         etl::clock clk;
141         int clk_scanline; // The scanline at which the clock was reset
142         etl::clock clk2;
143
144         float last_time;
145 public:
146
147         RenderProgress():clk_scanline(0), last_time(0) { }
148
149         virtual bool
150         task(const String &thetask)
151         {
152                 taskname=thetask;
153                 return true;
154         }
155
156         virtual bool
157         error(const String &task)
158         {
159                 std::cout<<_("error")<<": "<<task<<std::endl;
160                 return true;
161         }
162
163         virtual bool
164         warning(const String &task)
165         {
166                 std::cout<<_("warning")<<": "<<task<<std::endl;
167                 return true;
168         }
169
170         virtual bool
171         amount_complete(int scanline, int h)
172         {
173                 if(be_quiet)return true;
174                 if(scanline!=h)
175                 {
176                         const float time(clk()*(float)(h-scanline)/(float)(scanline-clk_scanline));
177                         const float delta(time-last_time);
178
179                         int weeks=0,days=0,hours=0,minutes=0,seconds=0;
180
181                         last_time=time;
182
183                         if(clk2()<0.2)
184                                 return true;
185                         clk2.reset();
186
187                         if(scanline)
188                                 seconds=(int)time+1;
189                         else
190                         {
191                                 //cerr<<"reset"<<endl;
192                                 clk.reset();
193                                 clk_scanline=scanline;
194                         }
195
196                         if(seconds<0)
197                         {
198                                 clk.reset();
199                                 clk_scanline=scanline;
200                                 seconds=0;
201                         }
202                         while(seconds>=60)
203                                 minutes++,seconds-=60;
204                         while(minutes>=60)
205                                 hours++,minutes-=60;
206                         while(hours>=24)
207                                 days++,hours-=24;
208                         while(days>=7)
209                                 weeks++,days-=7;
210
211                         cerr<<taskname<<": "<<_("Line")<<" "<<scanline<<_(" of ")<<h<<" -- ";
212                         //cerr<<time/(h-clk_scanline)<<" ";
213                         /*
214                         if(delta>=-time/(h-clk_scanline)  )
215                                 cerr<<">";
216                         */
217                         if(delta>=0 && clk()>4.0 && scanline>clk_scanline+200)
218                         {
219                                 //cerr<<"reset"<<endl;
220                                 clk.reset();
221                                 clk_scanline=scanline;
222                         }
223
224                         if(weeks)
225                                 cerr<<weeks<<"w ";
226                         if(days)
227                                 cerr<<days<<"d ";
228                         if(hours)
229                                 cerr<<hours<<"h ";
230                         if(minutes)
231                                 cerr<<minutes<<"m ";
232                         if(seconds)
233                                 cerr<<seconds<<"s ";
234
235                         cerr<<"           \r";
236                 }
237                 else
238                         cerr<<taskname<<": "<<_("DONE")<<"                        "<<endl;;
239                 return true;
240         }
241 };
242
243 struct Job
244 {
245         String filename;
246         String outfilename;
247
248         RendDesc desc;
249
250         Canvas::Handle root;
251         Canvas::Handle canvas;
252         Target::Handle target;
253
254         int quality;
255         bool sifout;
256 };
257
258 typedef list<String> arg_list_t;
259 typedef list<Job> job_list_t;
260
261 void guid_test()
262 {
263         cout<<"GUID Test"<<endl;
264         for(int i=20;i;i--)
265         {
266                 cout<<synfig::GUID().get_string()<<' '<<synfig::GUID().get_string()<<endl;
267         }
268 }
269
270 void signal_test_func()
271 {
272         cout<<"**SIGNAL CALLED**"<<endl;
273 }
274
275 void signal_test()
276 {
277         sigc::signal<void> sig;
278         sigc::connection conn;
279         cout<<"Signal Test"<<endl;
280         conn=sig.connect(sigc::ptr_fun(signal_test_func));
281         cout<<"Next line should exclaim signal called."<<endl;
282         sig();
283         conn.disconnect();
284         cout<<"Next line should NOT exclaim signal called."<<endl;
285         sig();
286         cout<<"done."<<endl;
287 }
288
289 /* === P R O C E D U R E S ================================================= */
290
291 void display_help(int amount)
292 {
293         class Argument
294         {
295         public:
296                 Argument(const char *flag,const char *arg, string description)
297                 {
298                         const char spaces[]="                      ";
299                         if(arg)
300                                 cerr<<strprintf(" %s %s %s",flag, arg, spaces+strlen(arg)+strlen(flag)+1)+description<<endl;
301                         else
302                                 cerr<<strprintf(" %s %s",flag,spaces+strlen(flag))+description<<endl;
303
304                 }
305         };
306         cerr<<_("syntax: ")<<progname<<" [DEFAULT OPTIONS] ([SIF FILE] [SPECIFIC OPTIONS])..."<<endl;
307         cerr<<endl;
308         if(amount>=1)
309         {
310                 Argument("-t","<output type>",_("Specify output target (Default:unknown)"));
311                 Argument("-w","<pixel width>",_("Set the image width (Use zero for file default)"));
312                 Argument("-h","<pixel height>",_("Set the image height (Use zero for file default)"));
313                 Argument("-s","<image dist>",_("Set the diagonal size of image window (Span)"));
314                 Argument("-a","<1...30>",_("Set antialias amount for parametric renderer."));
315                 Argument("-Q","<0...10>",strprintf(_("Specify image quality for accelerated renderer (default=%d)"),DEFAULT_QUALITY).c_str());
316                 Argument("-g","<amount>",_("Gamma (default=2.2)"));
317                 Argument("-v",NULL,_("Verbose Output (add more for more verbosity)"));
318                 Argument("-q",NULL,_("Quiet mode (No progress/time-remaining display)"));
319                 Argument("-c","<canvas id>",_("Render the canvas with the given id instead of the root."));
320                 Argument("-o","<output file>",_("Specify output filename"));
321                 Argument("-T","<# of threads>",_("Enable multithreaded renderer using specified # of threads"));
322
323                 Argument("-b",NULL,_("Print Benchmarks"));
324
325                 Argument("--fps","<framerate>",_("Set the frame rate"));
326                 Argument("--time","<time>",_("Render a single frame at <seconds>"));
327                 Argument("--begin-time","<time>",_("Set the starting time"));
328                 Argument("--end-time","<time>",_("Set the ending time"));
329                 Argument("--dpi","<res>",_("Set the dots-per-inch"));
330                 Argument("--append","<filename>",_("Append layers in <filename> to composition"));
331
332                 Argument("--layer-info","<layer>",_("Print out layer's description, parameter info, etc."));
333                 Argument("--layers",NULL,_("Print out the list of available layers"));
334                 Argument("--targets",NULL,_("Print out the list of available targets"));
335                 Argument("--importers",NULL,_("Print out the list of available importers"));
336                 Argument("--valuenodes",NULL,_("Print out the list of available ValueNodes"));
337                 Argument("--modules",NULL,_("Print out the list of loaded modules"));
338                 Argument("--version",NULL,_("Print out version information"));
339                 Argument("--info",NULL,_("Print out misc build information"));
340                 Argument("--license",NULL,_("Print out license information"));
341
342 #ifdef _DEBUG
343                 Argument("--guid-test",NULL,_("Test GUID generation"));
344                 Argument("--signal-test",NULL,_("Test signal implementation"));
345 #endif
346         }
347         else
348
349         Argument("--help",NULL,_("Print out usage and syntax info"));
350         cerr<<endl;
351 }
352
353 int process_global_flags(arg_list_t &arg_list)
354 {
355         arg_list_t::iterator iter, next;
356
357         for(next=arg_list.begin(),iter=next++;iter!=arg_list.end();iter=next++)
358         {
359                 if(*iter == "--")
360                         return SYNFIGTOOL_OK;
361
362                 if(*iter == "--signal-test")
363                 {
364                         signal_test();
365                         return SYNFIGTOOL_HELP;
366                 }
367
368                 if(*iter == "--guid-test")
369                 {
370                         guid_test();
371                         return SYNFIGTOOL_HELP;
372                 }
373
374
375                 if(*iter == "--help")
376                 {
377                         display_help(1);
378
379                         return SYNFIGTOOL_HELP;
380                 }
381
382                 if(*iter == "--info")
383                 {
384                         cout<<PACKAGE"-"VERSION<<endl;
385                         cout<<"Compiled on "__DATE__ " at "__TIME__;
386 #ifdef __GNUC__
387                         cout<<" with GCC "<<__VERSION__;
388 #endif
389 #ifdef _MSC_VER
390                         cout<<" with Microsoft Visual C++ "<<(_MSC_VER>>8)<<'.'<<(_MSC_VER&255);
391 #endif
392 #ifdef __TCPLUSPLUS__
393                         cout<<" with Borland Turbo C++ "<<(__TCPLUSPLUS__>>8)<<'.'<<((__TCPLUSPLUS__&255)>>4)<<'.'<<(__TCPLUSPLUS__&15);
394 #endif
395
396                         cout<<endl<<SYNFIG_COPYRIGHT<<endl;
397                         cout<<endl;
398                         return SYNFIGTOOL_HELP;
399                 }
400
401                 if(*iter == "--layers")
402                 {
403                         Progress p(PACKAGE);
404                         synfig::Main synfig_main(dirname(progname),&p);
405                         synfig::Layer::Book::iterator iter=synfig::Layer::book().begin();
406                         for(;iter!=synfig::Layer::book().end();iter++)
407                                 cout<<iter->first<<endl;
408
409                         return SYNFIGTOOL_HELP;
410                 }
411
412                 if(*iter == "--layer-info")
413                 {
414                         Progress p(PACKAGE);
415                         synfig::Main synfig_main(dirname(progname),&p);
416                         iter=next++;
417                         Layer::Handle layer=synfig::Layer::create(*iter);
418                         cout<<"Layer Name: "<<layer->get_name()<<endl;
419                         cout<<"Localized Layer Name: "<<layer->get_local_name()<<endl;
420                         cout<<"Version: "<<layer->get_version()<<endl;
421                         Layer::Vocab vocab=layer->get_param_vocab();
422                         for(;!vocab.empty();vocab.pop_front())
423                         {
424                                 cout<<"param - "<<vocab.front().get_name();
425                                 if(!vocab.front().get_critical())
426                                         cout<<" (not critical)";
427                                 cout<<endl<<"\tLocalized Name: "<<vocab.front().get_local_name()<<endl;
428                                 if(!vocab.front().get_description().empty())
429                                         cout<<"\tDescription: "<<vocab.front().get_description()<<endl;
430                                 if(!vocab.front().get_hint().empty())
431                                         cout<<"\tHint: "<<vocab.front().get_hint()<<endl;
432                         }
433
434                         return SYNFIGTOOL_HELP;
435                 }
436
437                 if(*iter == "--modules")
438                 {
439                         Progress p(PACKAGE);
440                         synfig::Main synfig_main(dirname(progname),&p);
441                         synfig::Module::Book::iterator iter=synfig::Module::book().begin();
442                         for(;iter!=synfig::Module::book().end();iter++)
443                                 cout<<iter->first<<endl;
444                         return SYNFIGTOOL_HELP;
445                 }
446
447                 if(*iter == "--targets")
448                 {
449                         Progress p(PACKAGE);
450                         synfig::Main synfig_main(dirname(progname),&p);
451                         synfig::Target::Book::iterator iter=synfig::Target::book().begin();
452                         for(;iter!=synfig::Target::book().end();iter++)
453                                 cout<<iter->first<<endl;
454
455                         return SYNFIGTOOL_HELP;
456                 }
457
458                 if(*iter == "--valuenodes")
459                 {
460                         Progress p(PACKAGE);
461                         synfig::Main synfig_main(dirname(progname),&p);
462                         synfig::LinkableValueNode::Book::iterator iter=synfig::LinkableValueNode::book().begin();
463                         for(;iter!=synfig::LinkableValueNode::book().end();iter++)
464                                 cout<<iter->first<<endl;
465
466                         return SYNFIGTOOL_HELP;
467                 }
468
469                 if(*iter == "--importers")
470                 {
471                         Progress p(PACKAGE);
472                         synfig::Main synfig_main(dirname(progname),&p);
473                         synfig::Importer::Book::iterator iter=synfig::Importer::book().begin();
474                         for(;iter!=synfig::Importer::book().end();iter++)
475                                 cout<<iter->first<<endl;
476
477                         return SYNFIGTOOL_HELP;
478                 }
479
480                 if(*iter == "--version")
481                 {
482                         cerr<<PACKAGE<<" "<<VERSION<<endl;
483
484                         arg_list.erase(iter);
485
486                         return SYNFIGTOOL_HELP;
487                 }
488
489                 if(*iter == "--license")
490                 {
491                         cerr<<PACKAGE<<" "<<VERSION<<endl;
492                         cout<<SYNFIG_COPYRIGHT<<endl<<endl;
493                         cerr<<"\
494 **      This package is free software; you can redistribute it and/or\n\
495 **      modify it under the terms of the GNU General Public License as\n\
496 **      published by the Free Software Foundation; either version 2 of\n\
497 **      the License, or (at your option) any later version.\n\
498 **\n\
499 **      " << endl << endl;
500                         arg_list.erase(iter);
501
502                         return SYNFIGTOOL_HELP;
503                 }
504
505                 if(*iter == "-v")
506                 {
507                         verbosity++;
508
509                         arg_list.erase(iter);
510
511                         continue;
512                 }
513
514                 if(*iter == "-q")
515                 {
516                         be_quiet=true;
517
518                         arg_list.erase(iter);
519
520                         continue;
521                 }
522                 if(*iter == "-b")
523                 {
524                         print_benchmarks=true;
525
526                         arg_list.erase(iter);
527
528                         continue;
529                 }
530         }
531
532         return SYNFIGTOOL_OK;
533 }
534
535 int extract_arg_cluster(arg_list_t &arg_list,arg_list_t &cluster)
536 {
537         arg_list_t::iterator iter, next;
538
539         for(next=arg_list.begin(),iter=next++;iter!=arg_list.end();iter=next++)
540         {
541                 if(*iter->begin() != '-')
542                 {
543                         //cerr<<*iter->begin()<<"-----------"<<endl;
544                         return SYNFIGTOOL_OK;
545                 }
546
547                 if(
548                         *iter=="-t" ||
549                         *iter=="-w" ||
550                         *iter=="-h" ||
551                         *iter=="-a" ||
552                         *iter=="-g" ||
553                         *iter=="-o" ||
554                         *iter=="-s" ||
555                         *iter=="-Q" ||
556                         *iter=="-c" ||
557                         *iter=="--fps" ||
558                         *iter=="--start-time" ||
559                         *iter=="--begin-time" ||
560                         *iter=="--end-time" ||
561                         *iter=="--start-frame" ||
562                         *iter=="--end-frame" ||
563                         *iter=="--time" ||
564                         *iter=="--frame" ||
565                         *iter=="--dpi" ||
566                         *iter=="--dpi-x" ||
567                         *iter=="--dpi-y" ||
568                         *iter=="--append" ||
569                         *iter=="-T" )
570                 {
571                         cluster.push_back(*iter);
572                         arg_list.erase(iter);
573                         iter=next++;
574                         if (iter==arg_list.end()) {
575                                 error("The `%s' flag requires a value.  Use --help for a list of options.", cluster.back().c_str());
576                                 return SYNFIGTOOL_MISSINGARGUMENT;
577                         }
578                 }
579
580                 cluster.push_back(*iter);
581                 arg_list.erase(iter);
582         }
583
584         return SYNFIGTOOL_OK;
585 }
586
587 int extract_RendDesc(arg_list_t &arg_list,RendDesc &desc)
588 {
589         arg_list_t::iterator iter, next;
590         int w=0,h=0;
591         float span=0;
592         for(next=arg_list.begin(),iter=next++;iter!=arg_list.end();iter=next++)
593         {
594                 if(*iter=="-w")
595                 {
596                         arg_list.erase(iter);
597                         iter=next++;
598                         w=atoi(iter->c_str());
599                         arg_list.erase(iter);
600                 }
601                 else if(*iter=="-h")
602                 {
603                         arg_list.erase(iter);
604                         iter=next++;
605                         h=atoi(iter->c_str());
606                         arg_list.erase(iter);
607                 }
608                 else if(*iter=="-a")
609                 {
610             int a;
611                         arg_list.erase(iter);
612                         iter=next++;
613                         a=atoi(iter->c_str());
614                         desc.set_antialias(a);
615                         VERBOSE_OUT(1)<<strprintf(_("Antialiasing set to %d, (%d samples per pixel)"),a,a*a)<<endl;
616                         arg_list.erase(iter);
617                 }
618                 else if(*iter=="-s")
619                 {
620                         arg_list.erase(iter);
621                         iter=next++;
622                         span=atof(iter->c_str());
623                         VERBOSE_OUT(1)<<strprintf(_("Span set to %d units"),span)<<endl;
624                         arg_list.erase(iter);
625                 }
626                 else if(*iter=="--fps")
627                 {
628                         arg_list.erase(iter);
629                         iter=next++;
630                         float fps=atof(iter->c_str());
631                         desc.set_frame_rate(fps);
632                         arg_list.erase(iter);
633                         VERBOSE_OUT(1)<<strprintf(_("Frame rate set to %d frames per second"),fps)<<endl;
634                 }
635                 else if(*iter=="--dpi")
636                 {
637                         arg_list.erase(iter);
638                         iter=next++;
639                         float dpi=atof(iter->c_str());
640                         float dots_per_meter=dpi*39.3700787402;
641                         desc.set_x_res(dots_per_meter).set_y_res(dots_per_meter);
642                         arg_list.erase(iter);
643                         VERBOSE_OUT(1)<<strprintf(_("Physical resolution set to %f dpi"),dpi)<<endl;
644                 }
645                 else if(*iter=="--dpi-x")
646                 {
647                         arg_list.erase(iter);
648                         iter=next++;
649                         float dpi=atof(iter->c_str());
650                         float dots_per_meter=dpi*39.3700787402;
651                         desc.set_x_res(dots_per_meter);
652                         arg_list.erase(iter);
653                         VERBOSE_OUT(1)<<strprintf(_("Physical X resolution set to %f dpi"),dpi)<<endl;
654                 }
655                 else if(*iter=="--dpi-y")
656                 {
657                         arg_list.erase(iter);
658                         iter=next++;
659                         float dpi=atof(iter->c_str());
660                         float dots_per_meter=dpi*39.3700787402;
661                         desc.set_y_res(dots_per_meter);
662                         arg_list.erase(iter);
663                         VERBOSE_OUT(1)<<strprintf(_("Physical Y resolution set to %f dpi"),dpi)<<endl;
664                 }
665                 else if(*iter=="--start-time" || *iter=="--begin-time")
666                 {
667                         arg_list.erase(iter);
668                         iter=next++;
669                         desc.set_time_start(Time(*iter,desc.get_frame_rate()));
670                         arg_list.erase(iter);
671                 }
672                 else if(*iter=="--end-time")
673                 {
674                         arg_list.erase(iter);
675                         iter=next++;
676                         desc.set_time_end(Time(*iter,desc.get_frame_rate()));
677                         arg_list.erase(iter);
678                 }
679                 else if(*iter=="--time")
680                 {
681                         arg_list.erase(iter);
682                         iter=next++;
683                         desc.set_time(Time(*iter,desc.get_frame_rate()));
684                         VERBOSE_OUT(1)<<_("Rendering frame at ")<<desc.get_time_start().get_string(desc.get_frame_rate())<<endl;
685                         arg_list.erase(iter);
686                 }
687                 else if(*iter=="-g")
688                 {
689                         synfig::warning("Gamma argument is currently ignored");
690                         arg_list.erase(iter);
691                         iter=next++;
692                         //desc.set_gamma(Gamma(atof(iter->c_str())));
693                         arg_list.erase(iter);
694                 }
695         }
696         if(w&&h)
697         {
698                 desc.set_wh(w,h);
699                 VERBOSE_OUT(1)<<strprintf(_("Resolution set to %dx%d"),w,h)<<endl;
700         }
701         else
702         {
703                 if(w)
704                 {
705                         VERBOSE_OUT(1)<<strprintf(_("Width set to %d pixels"),w)<<endl;
706                         desc.set_w(w);
707                 }
708                 if(h)
709                 {
710                         VERBOSE_OUT(1)<<strprintf(_("Height set to %d pixels"),h)<<endl;
711                         desc.set_h(h);
712                 }
713         }
714         if(span)
715                 desc.set_span(span);
716         return SYNFIGTOOL_OK;
717 }
718
719 int extract_quality(arg_list_t &arg_list,int &quality)
720 {
721         arg_list_t::iterator iter, next;
722         for(next=arg_list.begin(),iter=next++;iter!=arg_list.end();iter=next++)
723         {
724                 if(*iter=="-Q")
725                 {
726                         arg_list.erase(iter);
727                         iter=next++;
728                         quality=atoi(iter->c_str());
729                         VERBOSE_OUT(1)<<strprintf(_("Quality set to %d"),quality)<<endl;
730                         arg_list.erase(iter);
731                 }
732         }
733
734         return SYNFIGTOOL_OK;
735 }
736
737 int extract_threads(arg_list_t &arg_list,int &threads)
738 {
739         arg_list_t::iterator iter, next;
740         for(next=arg_list.begin(),iter=next++;iter!=arg_list.end();iter=next++)
741         {
742                 if(*iter=="-T")
743                 {
744                         arg_list.erase(iter);
745                         iter=next++;
746                         threads=atoi(iter->c_str());
747                         VERBOSE_OUT(1)<<strprintf(_("Threads set to %d"),threads)<<endl;
748                         arg_list.erase(iter);
749                 }
750         }
751
752         return SYNFIGTOOL_OK;
753 }
754
755 int extract_target(arg_list_t &arg_list,string &type)
756 {
757         arg_list_t::iterator iter, next;
758         type.clear();
759
760         for(next=arg_list.begin(),iter=next++;iter!=arg_list.end();iter=next++)
761         {
762                 if(*iter=="-t")
763                 {
764                         arg_list.erase(iter);
765                         iter=next++;
766                         type=*iter;
767                         arg_list.erase(iter);
768                 }
769         }
770
771         return SYNFIGTOOL_OK;
772 }
773
774 int extract_append(arg_list_t &arg_list,string &filename)
775 {
776         arg_list_t::iterator iter, next;
777         filename.clear();
778
779         for(next=arg_list.begin(),iter=next++;iter!=arg_list.end();iter=next++)
780         {
781                 if(*iter=="--append")
782                 {
783                         arg_list.erase(iter);
784                         iter=next++;
785                         filename=*iter;
786                         arg_list.erase(iter);
787                 }
788         }
789
790         return SYNFIGTOOL_OK;
791 }
792
793 int extract_outfile(arg_list_t &arg_list,string &outfile)
794 {
795         arg_list_t::iterator iter, next;
796         int ret=SYNFIGTOOL_FILENOTFOUND;
797         outfile.clear();
798
799         for(next=arg_list.begin(),iter=next++;iter!=arg_list.end();iter=next++)
800         {
801                 if(*iter=="-o")
802                 {
803                         arg_list.erase(iter);
804                         iter=next++;
805                         outfile=*iter;
806                         arg_list.erase(iter);
807                         ret=SYNFIGTOOL_OK;
808                 }
809         }
810
811         return ret;
812 }
813
814 int extract_canvasid(arg_list_t &arg_list,string &canvasid)
815 {
816         arg_list_t::iterator iter, next;
817         //canvasid.clear();
818
819         for(next=arg_list.begin(),iter=next++;iter!=arg_list.end();iter=next++)
820         {
821                 if(*iter=="-c")
822                 {
823                         arg_list.erase(iter);
824                         iter=next++;
825                         canvasid=*iter;
826                         arg_list.erase(iter);
827                 }
828         }
829
830         return SYNFIGTOOL_OK;
831 }
832
833 /* === M E T H O D S ======================================================= */
834
835 /* === E N T R Y P O I N T ================================================= */
836
837 int main(int argc, char *argv[])
838 {
839         int i;
840         arg_list_t arg_list;
841         job_list_t job_list;
842
843         setlocale(LC_ALL, "");
844         bindtextdomain("synfig", LOCALEDIR);
845         textdomain("synfig");
846
847         progname=argv[0];
848         Progress p(argv[0]);
849
850         if(!SYNFIG_CHECK_VERSION())
851         {
852                 cerr<<_("FATAL: Synfig Version Mismatch")<<endl;
853                 return SYNFIGTOOL_BADVERSION;
854         }
855         if(argc==1)
856         {
857                 display_help(0);
858                 return SYNFIGTOOL_BLANK;
859         }
860
861         for(i=1;i<argc;i++)
862                 arg_list.push_back(argv[i]);
863
864         if((i=process_global_flags(arg_list)))
865                 return i;
866
867         VERBOSE_OUT(1)<<_("verbosity set to ")<<verbosity<<endl;
868         synfig::Main synfig_main(dirname(progname),&p);
869
870         {
871                 arg_list_t defaults, imageargs;
872                 int ret;
873
874                 // Grab the defaults before the first file
875                 if ((ret = extract_arg_cluster(arg_list,defaults)) != SYNFIGTOOL_OK)
876                   return ret;
877
878                 while(arg_list.size())
879                 {
880                         string target_name;
881                         job_list.push_front(Job());
882                         int threads=0;
883
884                         imageargs=defaults;
885                         job_list.front().filename=arg_list.front();
886                         arg_list.pop_front();
887
888                         if ((ret = extract_arg_cluster(arg_list,imageargs)) != SYNFIGTOOL_OK)
889                           return ret;
890
891                         // Open the composition
892                         {
893                                 job_list.front().root=open_canvas(job_list.front().filename);
894                         }
895                         if(!job_list.front().root)
896                         {
897                                 cerr<<_("Unable to open ")<<job_list.front().filename<<"."<<endl;
898                                 cerr<<_("Throwing out job...")<<endl;
899                                 job_list.pop_front();
900                                 continue;
901                         }
902
903                         job_list.front().root->set_time(0);
904
905                         string canvasid;
906                         extract_canvasid(imageargs,canvasid);
907                         if(!canvasid.empty())
908                         {
909                                 try
910                                 {
911                                         job_list.front().canvas=job_list.front().root->find_canvas(canvasid);
912                                 }
913                                 catch(Exception::IDNotFound)
914                                 {
915                                         cerr<<_("Unable to find canvas with ID \"")<<canvasid<<_("\" in ")<<job_list.front().filename<<"."<<endl;
916                                         cerr<<_("Throwing out job...")<<endl;
917                                         job_list.pop_front();
918                                         continue;
919
920                                 }
921                                 catch(Exception::BadLinkName)
922                                 {
923                                         cerr<<_("Invalid canvas name \"")<<canvasid<<_("\" in ")<<job_list.front().filename<<"."<<endl;
924                                         cerr<<_("Throwing out job...")<<endl;
925                                         job_list.pop_front();
926                                         continue;
927
928                                 }
929                         }
930                         else
931                                 job_list.front().canvas=job_list.front().root;
932
933                         extract_RendDesc(imageargs,job_list.front().canvas->rend_desc());
934                         extract_target(imageargs,target_name);
935                         extract_threads(imageargs,threads);
936                         job_list.front().quality=DEFAULT_QUALITY;
937                         extract_quality(imageargs,job_list.front().quality);
938                         VERBOSE_OUT(2)<<_("Quality set to ")<<job_list.front().quality<<endl;
939                         job_list.front().desc=job_list.front().canvas->rend_desc();
940                         extract_outfile(imageargs,job_list.front().outfilename);
941
942                         // Extract composite
943                         do{
944                                 string composite_file;
945                                 extract_append(imageargs,composite_file);
946                                 if(!composite_file.empty())
947                                 {
948                                         Canvas::Handle composite(open_canvas(composite_file));
949                                         if(!composite)
950                                                 break;
951                                         Canvas::reverse_iterator iter;
952                                         for(iter=composite->rbegin();iter!=composite->rend();++iter)
953                                         {
954                                                 Layer::Handle layer(*iter);
955                                                 if(layer->active())
956                                                         job_list.front().canvas->push_front(layer->clone());
957                                         }
958                                         VERBOSE_OUT(2)<<_("Appended contents of ")<<composite_file<<endl;
959                                 }
960                         }while(false);
961
962                         VERBOSE_OUT(4)<<_("Attempting to determine target/outfile...")<<endl;
963
964                         // If the target type is not yet defined,
965                         // try to figure it out from the outfile.
966                         if(target_name.empty() && !job_list.front().outfilename.empty())
967                         {
968                                 VERBOSE_OUT(3)<<_("Target name undefined, attempting to figure it out")<<endl;
969                                 string ext = filename_extension(job_list.front().outfilename);
970                                 if (ext.length()) ext = ext.substr(1);
971                                 if(Target::ext_book().count(ext))
972                                         target_name=Target::ext_book()[ext];
973                                 else
974                                         target_name=ext;
975                         }
976
977                         // If the target type is STILL not yet defined, then
978                         // set it to a some sort of default
979                         if(target_name.empty())
980                         {
981                                 VERBOSE_OUT(2)<<_("Defaulting to PNG target...")<<endl;
982                                 target_name="png";
983                         }
984
985                         // If no output filename was provided, then
986                         // create a output filename based on the
987                         // given input filename. (ie: change the extension)
988                         if(job_list.front().outfilename.empty())
989                         {
990                                 job_list.front().outfilename = filename_sans_extension(job_list.front().filename) + '.';
991                                 if(Target::book().count(target_name))
992                                         job_list.front().outfilename+=Target::book()[target_name].second;
993                                 else
994                                         job_list.front().outfilename+=target_name;
995                         }
996
997                         VERBOSE_OUT(4)<<"target_name="<<target_name<<endl;
998                         VERBOSE_OUT(4)<<"outfile_name="<<job_list.front().outfilename<<endl;
999
1000                         VERBOSE_OUT(4)<<_("Creating the target...")<<endl;
1001                         job_list.front().target=synfig::Target::create(target_name,job_list.front().outfilename);
1002
1003                         if(target_name=="sif")
1004                         {
1005                                 job_list.front().sifout=true;
1006                         }
1007                         else
1008                         {
1009                                 if(!job_list.front().target)
1010                                 {
1011                                         cerr<<_("Unknown target for ")<<job_list.front().filename<<": "<<target_name<<endl;
1012                                         cerr<<_("Throwing out job...")<<endl;
1013                                         job_list.pop_front();
1014                                         continue;
1015                                 }
1016                                 job_list.front().sifout=false;
1017                         }
1018
1019                         // Set the Canvas on the Target
1020                         if(job_list.front().target)
1021                         {
1022                                 VERBOSE_OUT(4)<<_("Setting the canvas on the target...")<<endl;
1023                                 job_list.front().target->set_canvas(job_list.front().canvas);
1024                                 VERBOSE_OUT(4)<<_("Setting the quality of the target...")<<endl;
1025                                 job_list.front().target->set_quality(job_list.front().quality);
1026                         }
1027
1028                         // Set the threads for the target
1029                         if(job_list.front().target && Target_Scanline::Handle::cast_dynamic(job_list.front().target))
1030                         {
1031                                 Target_Scanline::Handle::cast_dynamic(job_list.front().target)->set_threads(threads);
1032                         }
1033
1034                         if(imageargs.size())
1035                         {
1036                                 cerr<<_("Unidentified arguments for ")<<job_list.front().filename<<": ";
1037                                 for(;imageargs.size();imageargs.pop_front())
1038                                         cerr<<' '<<imageargs.front();
1039                                 cerr<<endl;
1040                                 cerr<<_("Throwing out job...")<<endl;
1041                                 job_list.pop_front();
1042                                 continue;
1043                         }
1044                         //string bleh;
1045                         //getline(cin,bleh);
1046                 }
1047         }
1048
1049         if(arg_list.size())
1050         {
1051                 cerr<<_("Unidentified arguments:");
1052                 for(;arg_list.size();arg_list.pop_front())
1053                         cerr<<' '<<arg_list.front();
1054                 cerr<<endl;
1055                 return SYNFIGTOOL_UNKNOWNARGUMENT;
1056         }
1057
1058         if(!job_list.size())
1059         {
1060                 cerr<<_("Nothing to do!")<<endl;
1061                 return SYNFIGTOOL_BORED;
1062         }
1063
1064         for(;job_list.size();job_list.pop_front())
1065         {
1066                 VERBOSE_OUT(3)<<job_list.front().filename<<" -- "<<endl<<'\t'<<
1067                 strprintf("w:%d, h:%d, a:%d, pxaspect:%f, imaspect:%f, span:%f",
1068                         job_list.front().desc.get_w(),
1069                         job_list.front().desc.get_h(),
1070                         job_list.front().desc.get_antialias(),
1071                         job_list.front().desc.get_pixel_aspect(),
1072                         job_list.front().desc.get_image_aspect(),
1073                         job_list.front().desc.get_span()
1074                         )<<endl<<'\t'<<
1075                 strprintf("tl:[%f,%f], br:[%f,%f], focus:[%f,%f]",
1076                         job_list.front().desc.get_tl()[0],job_list.front().desc.get_tl()[1],
1077                         job_list.front().desc.get_br()[0],job_list.front().desc.get_br()[1],
1078                         job_list.front().desc.get_focus()[0],job_list.front().desc.get_focus()[1]
1079                         )<<endl;
1080
1081                 RenderProgress p;
1082                 p.task(job_list.front().filename+" ==> "+job_list.front().outfilename);
1083                 if(!job_list.front().sifout)
1084                 {
1085                         VERBOSE_OUT(1)<<_("Rendering...")<<endl;
1086                         etl::clock timer;
1087                         timer.reset();
1088                         // Call the render member of the target
1089                         if(!job_list.front().target->render(&p))
1090                         {
1091                                 cerr<<"Render Failure."<<endl;
1092                                 return SYNFIGTOOL_RENDERFAILURE;
1093                         }
1094                         if(print_benchmarks)
1095                         {
1096                                 cout<<job_list.front().filename+": Rendered in "<<timer()<<" seconds."<<endl;
1097                         }
1098                 }
1099                 else
1100                 {
1101                         if(!save_canvas(job_list.front().outfilename,job_list.front().canvas))
1102                         {
1103                                 cerr<<"Render Failure."<<endl;
1104                                 return SYNFIGTOOL_RENDERFAILURE;
1105                         }
1106                 }
1107         }
1108
1109         job_list.clear();
1110
1111         VERBOSE_OUT(1)<<_("Done.")<<endl;
1112
1113         return SYNFIGTOOL_OK;
1114 }