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