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