Fix bugs in previous commit that caused FTBFS in synfig and ETL FTBFS with older...
[synfig.git] / synfig-core / tags / stable / 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, 2008 Chris Moore
10 **
11 **      This package is free software; you can redistribute it and/or
12 **      modify it under the terms of the GNU General Public License as
13 **      published by the Free Software Foundation; either version 2 of
14 **      the License, or (at your option) any later version.
15 **
16 **      This package is distributed in the hope that it will be useful,
17 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
18 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 **      General Public License for more details.
20 **      \endlegal
21 */
22 /* ========================================================================= */
23
24 /* === H E A D E R S ======================================================= */
25
26 #ifdef USING_PCH
27 #       include "pch.h"
28 #else
29 #ifdef HAVE_CONFIG_H
30 #       include <config.h>
31 #endif
32
33 #include <iostream>
34 #include <ETL/stringf>
35 #include <list>
36 #include <ETL/clock>
37 #include <algorithm>
38 #include <cstring>
39
40 #include <synfig/loadcanvas.h>
41 #include <synfig/savecanvas.h>
42 #include <synfig/target_scanline.h>
43 #include <synfig/module.h>
44 #include <synfig/importer.h>
45 #include <synfig/layer.h>
46 #include <synfig/canvas.h>
47 #include <synfig/target.h>
48 #include <synfig/time.h>
49 #include <synfig/string.h>
50 #include <synfig/paramdesc.h>
51 #include <synfig/main.h>
52 #include <synfig/guid.h>
53 #endif
54
55 using namespace std;
56 using namespace etl;
57 using namespace synfig;
58
59 /* === M A C R O S ========================================================= */
60
61 #ifdef ENABLE_NLS
62 #undef _
63 #define _(x) gettext(x)
64 #else
65 #undef _
66 #define _(x) (x)
67 #endif
68
69 enum exit_code
70 {
71         SYNFIGTOOL_OK                           = 0,
72         SYNFIGTOOL_FILENOTFOUND         = 1,
73         SYNFIGTOOL_BORED                        = 2,
74         SYNFIGTOOL_HELP                         = 3,
75         SYNFIGTOOL_UNKNOWNARGUMENT      = 4,
76         SYNFIGTOOL_UNKNOWNERROR         = 5,
77         SYNFIGTOOL_INVALIDTARGET        = 6,
78         SYNFIGTOOL_RENDERFAILURE        = 7,
79         SYNFIGTOOL_BLANK                        = 8,
80         SYNFIGTOOL_BADVERSION           = 9,
81         SYNFIGTOOL_MISSINGARGUMENT      =10
82 };
83
84 #ifndef VERSION
85 #define VERSION "unknown"
86 #define PACKAGE "synfig-tool"
87 #endif
88
89 #ifdef DEFAULT_QUALITY
90 #undef DEFAULT_QUALITY
91 #endif
92
93 #define DEFAULT_QUALITY         2
94 #define VERBOSE_OUT(x) if(verbosity>=(x))std::cerr
95
96 /* === G L O B A L S ======================================================= */
97
98 const char *progname;
99 int verbosity=0;
100 bool be_quiet=false;
101 bool print_benchmarks=false;
102
103 /* === M E T H O D S ======================================================= */
104
105 class Progress : public synfig::ProgressCallback
106 {
107         const char *program;
108
109 public:
110
111         Progress(const char *name):program(name) { }
112
113         virtual bool
114         task(const String &task)
115         {
116                 VERBOSE_OUT(1)<<program<<": "<<task<<std::endl;
117                 return true;
118         }
119
120         virtual bool
121         error(const String &task)
122         {
123                 std::cerr<<program<<": "<<_("error")<<": "<<task<<std::endl;
124                 return true;
125         }
126
127         virtual bool
128         warning(const String &task)
129         {
130                 std::cerr<<program<<": "<<_("warning")<<": "<<task<<std::endl;
131                 return true;
132         }
133
134         virtual bool
135         amount_complete(int /*current*/, int /*total*/)
136         {
137                 return true;
138         }
139 };
140
141 class RenderProgress : public synfig::ProgressCallback
142 {
143         string taskname;
144
145         etl::clock clk;
146         int clk_scanline; // The scanline at which the clock was reset
147         etl::clock clk2;
148
149         float last_time;
150 public:
151
152         RenderProgress():clk_scanline(0), last_time(0) { }
153
154         virtual bool
155         task(const String &thetask)
156         {
157                 taskname=thetask;
158                 return true;
159         }
160
161         virtual bool
162         error(const String &task)
163         {
164                 std::cout<<_("error")<<": "<<task<<std::endl;
165                 return true;
166         }
167
168         virtual bool
169         warning(const String &task)
170         {
171                 std::cout<<_("warning")<<": "<<task<<std::endl;
172                 return true;
173         }
174
175         virtual bool
176         amount_complete(int scanline, int h)
177         {
178                 if(be_quiet)return true;
179                 if(scanline!=h)
180                 {
181                         const float time(clk()*(float)(h-scanline)/(float)(scanline-clk_scanline));
182                         const float delta(time-last_time);
183
184                         int weeks=0,days=0,hours=0,minutes=0,seconds=0;
185
186                         last_time=time;
187
188                         if(clk2()<0.2)
189                                 return true;
190                         clk2.reset();
191
192                         if(scanline)
193                                 seconds=(int)time+1;
194                         else
195                         {
196                                 //cerr<<"reset"<<endl;
197                                 clk.reset();
198                                 clk_scanline=scanline;
199                         }
200
201                         if(seconds<0)
202                         {
203                                 clk.reset();
204                                 clk_scanline=scanline;
205                                 seconds=0;
206                         }
207                         while(seconds>=60)
208                                 minutes++,seconds-=60;
209                         while(minutes>=60)
210                                 hours++,minutes-=60;
211                         while(hours>=24)
212                                 days++,hours-=24;
213                         while(days>=7)
214                                 weeks++,days-=7;
215
216                         cerr<<taskname<<": "<<_("Line")<<" "<<scanline<<_(" of ")<<h<<" -- ";
217                         //cerr<<time/(h-clk_scanline)<<" ";
218                         /*
219                         if(delta>=-time/(h-clk_scanline)  )
220                                 cerr<<">";
221                         */
222                         if(delta>=0 && clk()>4.0 && scanline>clk_scanline+200)
223                         {
224                                 //cerr<<"reset"<<endl;
225                                 clk.reset();
226                                 clk_scanline=scanline;
227                         }
228
229                         if(weeks)
230                                 cerr<<weeks<<"w ";
231                         if(days)
232                                 cerr<<days<<"d ";
233                         if(hours)
234                                 cerr<<hours<<"h ";
235                         if(minutes)
236                                 cerr<<minutes<<"m ";
237                         if(seconds)
238                                 cerr<<seconds<<"s ";
239
240                         cerr<<"           \r";
241                 }
242                 else
243                         cerr<<taskname<<": "<<_("DONE")<<"                        "<<endl;;
244                 return true;
245         }
246 };
247
248 struct Job
249 {
250         String filename;
251         String outfilename;
252
253         RendDesc desc;
254
255         Canvas::Handle root;
256         Canvas::Handle canvas;
257         Target::Handle target;
258
259         int quality;
260         bool sifout;
261         bool list_canvases;
262
263         bool canvas_info, canvas_info_all, canvas_info_time_start, canvas_info_time_end, canvas_info_frame_rate,
264                  canvas_info_frame_start, canvas_info_frame_end, canvas_info_w, canvas_info_h, canvas_info_image_aspect,
265                  canvas_info_pw, canvas_info_ph, canvas_info_pixel_aspect, canvas_info_tl, canvas_info_br,
266                  canvas_info_physical_w, canvas_info_physical_h, canvas_info_x_res, canvas_info_y_res, canvas_info_span,
267                  canvas_info_interlaced, canvas_info_antialias, canvas_info_clamp, canvas_info_flags, canvas_info_focus,
268                  canvas_info_bg_color, canvas_info_metadata;
269
270         Job()
271         {
272                 canvas_info = canvas_info_all = canvas_info_time_start = canvas_info_time_end = canvas_info_frame_rate = canvas_info_frame_start = canvas_info_frame_end = canvas_info_w = canvas_info_h = canvas_info_image_aspect = canvas_info_pw = canvas_info_ph = canvas_info_pixel_aspect = canvas_info_tl = canvas_info_br = canvas_info_physical_w = canvas_info_physical_h = canvas_info_x_res = canvas_info_y_res = canvas_info_span = canvas_info_interlaced = canvas_info_antialias = canvas_info_clamp = canvas_info_flags = canvas_info_focus = canvas_info_bg_color = canvas_info_metadata = false;
273         };
274 };
275
276 typedef list<String> arg_list_t;
277 typedef list<Job> job_list_t;
278
279 void guid_test()
280 {
281         cout<<"GUID Test"<<endl;
282         for(int i=20;i;i--)
283                 cout<<synfig::GUID().get_string()<<' '<<synfig::GUID().get_string()<<endl;
284 }
285
286 void signal_test_func()
287 {
288         cout<<"**SIGNAL CALLED**"<<endl;
289 }
290
291 void signal_test()
292 {
293         sigc::signal<void> sig;
294         sigc::connection conn;
295         cout<<"Signal Test"<<endl;
296         conn=sig.connect(sigc::ptr_fun(signal_test_func));
297         cout<<"Next line should exclaim signal called."<<endl;
298         sig();
299         conn.disconnect();
300         cout<<"Next line should NOT exclaim signal called."<<endl;
301         sig();
302         cout<<"done."<<endl;
303 }
304
305 /* === P R O C E D U R E S ================================================= */
306
307 void display_help(int amount)
308 {
309         class Argument
310         {
311         public:
312                 Argument(const char *flag,const char *arg, string description)
313                 {
314                         const char spaces[]="                      ";
315                         if(arg)
316                                 cerr<<strprintf(" %s %s %s",flag, arg, spaces+strlen(arg)+strlen(flag)+1)+description<<endl;
317                         else
318                                 cerr<<strprintf(" %s %s",flag,spaces+strlen(flag))+description<<endl;
319                 }
320         };
321
322         cerr << endl << _("syntax: ") << progname << " [DEFAULT OPTIONS] ([SIF FILE] [SPECIFIC OPTIONS])..." << endl << endl;
323
324         if(amount == 0)
325                 Argument("--help",NULL,_("Print out usage and syntax info"));
326         else
327         {
328                 Argument("-t","<output type>",_("Specify output target (Default:unknown)"));
329                 Argument("-w","<pixel width>",_("Set the image width (Use zero for file default)"));
330                 Argument("-h","<pixel height>",_("Set the image height (Use zero for file default)"));
331                 Argument("-s","<image dist>",_("Set the diagonal size of image window (Span)"));
332                 Argument("-a","<1...30>",_("Set antialias amount for parametric renderer."));
333                 Argument("-Q","<0...10>",strprintf(_("Specify image quality for accelerated renderer (default=%d)"),DEFAULT_QUALITY).c_str());
334                 Argument("-g","<amount>",_("Gamma (default=2.2)"));
335                 Argument("-v",NULL,_("Verbose Output (add more for more verbosity)"));
336                 Argument("-q",NULL,_("Quiet mode (No progress/time-remaining display)"));
337                 Argument("-c","<canvas id>",_("Render the canvas with the given id instead of the root."));
338                 Argument("-o","<output file>",_("Specify output filename"));
339                 Argument("-T","<# of threads>",_("Enable multithreaded renderer using specified # of threads"));
340                 Argument("-b",NULL,_("Print Benchmarks"));
341                 Argument("--fps","<framerate>",_("Set the frame rate"));
342                 Argument("--time","<time>",_("Render a single frame at <seconds>"));
343                 Argument("--begin-time","<time>",_("Set the starting time"));
344                 Argument("--start-time","<time>",_("Set the starting time"));
345                 Argument("--end-time","<time>",_("Set the ending time"));
346                 Argument("--dpi","<res>",_("Set the physical resolution (dots-per-inch)"));
347                 Argument("--dpi-x","<res>",_("Set the physical X resolution (dots-per-inch)"));
348                 Argument("--dpi-y","<res>",_("Set the physical Y resolution (dots-per-inch)"));
349
350                 Argument("--list-canvases",NULL,_("List the exported canvases in the composition"));
351                 Argument("--canvas-info","<fields>",_("Print out specified details of the root canvas"));
352                 Argument("--append","<filename>",_("Append layers in <filename> to composition"));
353
354                 Argument("--layer-info","<layer>",_("Print out layer's description, parameter info, etc."));
355                 Argument("--layers",NULL,_("Print out the list of available layers"));
356                 Argument("--targets",NULL,_("Print out the list of available targets"));
357                 Argument("--importers",NULL,_("Print out the list of available importers"));
358                 Argument("--valuenodes",NULL,_("Print out the list of available ValueNodes"));
359                 Argument("--modules",NULL,_("Print out the list of loaded modules"));
360                 Argument("--version",NULL,_("Print out version information"));
361                 Argument("--info",NULL,_("Print out misc build information"));
362                 Argument("--license",NULL,_("Print out license information"));
363
364 #ifdef _DEBUG
365                 Argument("--guid-test",NULL,_("Test GUID generation"));
366                 Argument("--signal-test",NULL,_("Test signal implementation"));
367 #endif
368         }
369
370         cerr<<endl;
371 }
372
373 int process_global_flags(arg_list_t &arg_list)
374 {
375         arg_list_t::iterator iter, next;
376
377         for(next=arg_list.begin(),iter=next++;iter!=arg_list.end();iter=next++)
378         {
379                 if(*iter == "--")
380                         return SYNFIGTOOL_OK;
381
382                 if(*iter == "--signal-test")
383                 {
384                         signal_test();
385                         return SYNFIGTOOL_HELP;
386                 }
387
388                 if(*iter == "--guid-test")
389                 {
390                         guid_test();
391                         return SYNFIGTOOL_HELP;
392                 }
393
394                 if(*iter == "--help")
395                 {
396                         display_help(1);
397                         return SYNFIGTOOL_HELP;
398                 }
399
400                 if(*iter == "--info")
401                 {
402                         cout<<PACKAGE"-"VERSION<<endl;
403                         cout<<"Compiled on "__DATE__ /* " at "__TIME__ */;
404 #ifdef __GNUC__
405                         cout<<" with GCC "<<__VERSION__;
406 #endif
407 #ifdef _MSC_VER
408                         cout<<" with Microsoft Visual C++ "<<(_MSC_VER>>8)<<'.'<<(_MSC_VER&255);
409 #endif
410 #ifdef __TCPLUSPLUS__
411                         cout<<" with Borland Turbo C++ "<<(__TCPLUSPLUS__>>8)<<'.'<<((__TCPLUSPLUS__&255)>>4)<<'.'<<(__TCPLUSPLUS__&15);
412 #endif
413
414                         cout<<endl<<SYNFIG_COPYRIGHT<<endl;
415                         cout<<endl;
416                         return SYNFIGTOOL_HELP;
417                 }
418
419                 if(*iter == "--layers")
420                 {
421                         Progress p(PACKAGE);
422                         synfig::Main synfig_main(dirname(progname),&p);
423                         synfig::Layer::Book::iterator iter=synfig::Layer::book().begin();
424                         for(;iter!=synfig::Layer::book().end();iter++)
425                                 if (iter->second.category != CATEGORY_DO_NOT_USE)
426                                         cout<<iter->first<<endl;
427
428                         return SYNFIGTOOL_HELP;
429                 }
430
431                 if(*iter == "--layer-info")
432                 {
433                         Progress p(PACKAGE);
434                         synfig::Main synfig_main(dirname(progname),&p);
435                         iter=next++;
436                         if (iter==arg_list.end())
437                         {
438                                 error("The `%s' flag requires a value.  Use --help for a list of options.", "--layer-info");
439                                 return SYNFIGTOOL_MISSINGARGUMENT;
440                         }
441                         Layer::Handle layer=synfig::Layer::create(*iter);
442                         cout<<"Layer Name: "<<layer->get_name()<<endl;
443                         cout<<"Localized Layer Name: "<<layer->get_local_name()<<endl;
444                         cout<<"Version: "<<layer->get_version()<<endl;
445                         Layer::Vocab vocab=layer->get_param_vocab();
446                         for(;!vocab.empty();vocab.pop_front())
447                         {
448                                 cout<<"param - "<<vocab.front().get_name();
449                                 if(!vocab.front().get_critical())
450                                         cout<<" (not critical)";
451                                 cout<<endl<<"\tLocalized Name: "<<vocab.front().get_local_name()<<endl;
452                                 if(!vocab.front().get_description().empty())
453                                         cout<<"\tDescription: "<<vocab.front().get_description()<<endl;
454                                 if(!vocab.front().get_hint().empty())
455                                         cout<<"\tHint: "<<vocab.front().get_hint()<<endl;
456                         }
457
458                         return SYNFIGTOOL_HELP;
459                 }
460
461                 if(*iter == "--modules")
462                 {
463                         Progress p(PACKAGE);
464                         synfig::Main synfig_main(dirname(progname),&p);
465                         synfig::Module::Book::iterator iter=synfig::Module::book().begin();
466                         for(;iter!=synfig::Module::book().end();iter++)
467                                 cout<<iter->first<<endl;
468                         return SYNFIGTOOL_HELP;
469                 }
470
471                 if(*iter == "--targets")
472                 {
473                         Progress p(PACKAGE);
474                         synfig::Main synfig_main(dirname(progname),&p);
475                         synfig::Target::Book::iterator iter=synfig::Target::book().begin();
476                         for(;iter!=synfig::Target::book().end();iter++)
477                                 cout<<iter->first<<endl;
478                         return SYNFIGTOOL_HELP;
479                 }
480
481                 if(*iter == "--valuenodes")
482                 {
483                         Progress p(PACKAGE);
484                         synfig::Main synfig_main(dirname(progname),&p);
485                         synfig::LinkableValueNode::Book::iterator iter=synfig::LinkableValueNode::book().begin();
486                         for(;iter!=synfig::LinkableValueNode::book().end();iter++)
487                                 cout<<iter->first<<endl;
488                         return SYNFIGTOOL_HELP;
489                 }
490
491                 if(*iter == "--importers")
492                 {
493                         Progress p(PACKAGE);
494                         synfig::Main synfig_main(dirname(progname),&p);
495                         synfig::Importer::Book::iterator iter=synfig::Importer::book().begin();
496                         for(;iter!=synfig::Importer::book().end();iter++)
497                                 cout<<iter->first<<endl;
498                         return SYNFIGTOOL_HELP;
499                 }
500
501                 if(*iter == "--version")
502                 {
503                         cerr<<PACKAGE<<" "<<VERSION<<endl;
504                         arg_list.erase(iter);
505                         return SYNFIGTOOL_HELP;
506                 }
507
508                 if(*iter == "--license")
509                 {
510                         cerr<<PACKAGE<<" "<<VERSION<<endl;
511                         cout<<SYNFIG_COPYRIGHT<<endl<<endl;
512                         cerr<<"\
513 **      This package is free software; you can redistribute it and/or\n\
514 **      modify it under the terms of the GNU General Public License as\n\
515 **      published by the Free Software Foundation; either version 2 of\n\
516 **      the License, or (at your option) any later version.\n\
517 **\n\
518 **      " << endl << endl;
519                         arg_list.erase(iter);
520                         return SYNFIGTOOL_HELP;
521                 }
522
523                 if(*iter == "-v")
524                 {
525                         verbosity++;
526                         arg_list.erase(iter);
527                         continue;
528                 }
529
530                 if(*iter == "-q")
531                 {
532                         be_quiet=true;
533                         arg_list.erase(iter);
534                         continue;
535                 }
536                 if(*iter == "-b")
537                 {
538                         print_benchmarks=true;
539                         arg_list.erase(iter);
540                         continue;
541                 }
542         }
543
544         return SYNFIGTOOL_OK;
545 }
546
547 /* true if the given flag takes an extra parameter */
548 bool flag_requires_value(String flag)
549 {
550         return (flag=="-a"                      || flag=="-c"                   || flag=="-g"                   || flag=="-h"                   || flag=="-o"                   ||
551                         flag=="-Q"                      || flag=="-s"                   || flag=="-t"                   || flag=="-T"                   || flag=="-w"                   ||
552                         flag=="--append"        || flag=="--begin-time" || flag=="--canvas-info"|| flag=="--dpi"                || flag=="--dpi-x"              ||
553                         flag=="--dpi-y"         || flag=="--end-time"   || flag=="--fps"                || flag=="--layer-info" || flag=="--start-time" ||
554                         flag=="--time"          );
555 }
556
557 int extract_arg_cluster(arg_list_t &arg_list,arg_list_t &cluster)
558 {
559         arg_list_t::iterator iter, next;
560
561         for(next=arg_list.begin(),iter=next++;iter!=arg_list.end();iter=next++)
562         {
563                 if(*iter->begin() != '-')
564                 {
565                         //cerr<<*iter->begin()<<"-----------"<<endl;
566                         return SYNFIGTOOL_OK;
567                 }
568
569                 if (flag_requires_value(*iter))
570                 {
571                         cluster.push_back(*iter);
572                         arg_list.erase(iter);
573                         iter=next++;
574                         if (iter==arg_list.end())
575                         {
576                                 error("The `%s' flag requires a value.  Use --help for a list of options.", cluster.back().c_str());
577                                 return SYNFIGTOOL_MISSINGARGUMENT;
578                         }
579                 }
580
581                 cluster.push_back(*iter);
582                 arg_list.erase(iter);
583         }
584
585         return SYNFIGTOOL_OK;
586 }
587
588 int extract_RendDesc(arg_list_t &arg_list,RendDesc &desc)
589 {
590         arg_list_t::iterator iter, next;
591         int w=0,h=0;
592         float span=0;
593         for(next=arg_list.begin(),iter=next++;iter!=arg_list.end();iter=next++)
594         {
595                 if(*iter=="-w")
596                 {
597                         arg_list.erase(iter);
598                         iter=next++;
599                         w=atoi(iter->c_str());
600                         arg_list.erase(iter);
601                 }
602                 else if(*iter=="-h")
603                 {
604                         arg_list.erase(iter);
605                         iter=next++;
606                         h=atoi(iter->c_str());
607                         arg_list.erase(iter);
608                 }
609                 else if(*iter=="-a")
610                 {
611             int a;
612                         arg_list.erase(iter);
613                         iter=next++;
614                         a=atoi(iter->c_str());
615                         desc.set_antialias(a);
616                         VERBOSE_OUT(1)<<strprintf(_("Antialiasing set to %d, (%d samples per pixel)"),a,a*a)<<endl;
617                         arg_list.erase(iter);
618                 }
619                 else if(*iter=="-s")
620                 {
621                         arg_list.erase(iter);
622                         iter=next++;
623                         span=atof(iter->c_str());
624                         VERBOSE_OUT(1)<<strprintf(_("Span set to %d units"),span)<<endl;
625                         arg_list.erase(iter);
626                 }
627                 else if(*iter=="--fps")
628                 {
629                         arg_list.erase(iter);
630                         iter=next++;
631                         float fps=atof(iter->c_str());
632                         desc.set_frame_rate(fps);
633                         arg_list.erase(iter);
634                         VERBOSE_OUT(1)<<strprintf(_("Frame rate set to %d frames per second"),fps)<<endl;
635                 }
636                 else if(*iter=="--dpi")
637                 {
638                         arg_list.erase(iter);
639                         iter=next++;
640                         float dpi=atof(iter->c_str());
641                         float dots_per_meter=dpi*39.3700787402;
642                         desc.set_x_res(dots_per_meter).set_y_res(dots_per_meter);
643                         arg_list.erase(iter);
644                         VERBOSE_OUT(1)<<strprintf(_("Physical resolution set to %f dpi"),dpi)<<endl;
645                 }
646                 else if(*iter=="--dpi-x")
647                 {
648                         arg_list.erase(iter);
649                         iter=next++;
650                         float dpi=atof(iter->c_str());
651                         float dots_per_meter=dpi*39.3700787402;
652                         desc.set_x_res(dots_per_meter);
653                         arg_list.erase(iter);
654                         VERBOSE_OUT(1)<<strprintf(_("Physical X resolution set to %f dpi"),dpi)<<endl;
655                 }
656                 else if(*iter=="--dpi-y")
657                 {
658                         arg_list.erase(iter);
659                         iter=next++;
660                         float dpi=atof(iter->c_str());
661                         float dots_per_meter=dpi*39.3700787402;
662                         desc.set_y_res(dots_per_meter);
663                         arg_list.erase(iter);
664                         VERBOSE_OUT(1)<<strprintf(_("Physical Y resolution set to %f dpi"),dpi)<<endl;
665                 }
666                 else if(*iter=="--start-time" || *iter=="--begin-time")
667                 {
668                         arg_list.erase(iter);
669                         iter=next++;
670                         desc.set_time_start(Time(*iter,desc.get_frame_rate()));
671                         arg_list.erase(iter);
672                 }
673                 else if(*iter=="--end-time")
674                 {
675                         arg_list.erase(iter);
676                         iter=next++;
677                         desc.set_time_end(Time(*iter,desc.get_frame_rate()));
678                         arg_list.erase(iter);
679                 }
680                 else if(*iter=="--time")
681                 {
682                         arg_list.erase(iter);
683                         iter=next++;
684                         desc.set_time(Time(*iter,desc.get_frame_rate()));
685                         VERBOSE_OUT(1)<<_("Rendering frame at ")<<desc.get_time_start().get_string(desc.get_frame_rate())<<endl;
686                         arg_list.erase(iter);
687                 }
688                 else if(*iter=="-g")
689                 {
690                         synfig::warning("Gamma argument is currently ignored");
691                         arg_list.erase(iter);
692                         iter=next++;
693                         //desc.set_gamma(Gamma(atof(iter->c_str())));
694                         arg_list.erase(iter);
695                 }
696                 else if (flag_requires_value(*iter))
697                         iter=next++;
698         }
699         if (w||h)
700         {
701                 if (!w)
702                         w = desc.get_w() * h / desc.get_h();
703                 else if (!h)
704                         h = desc.get_h() * w / desc.get_w();
705
706                 desc.set_wh(w,h);
707                 VERBOSE_OUT(1)<<strprintf(_("Resolution set to %dx%d"),w,h)<<endl;
708         }
709         if(span)
710                 desc.set_span(span);
711         return SYNFIGTOOL_OK;
712 }
713
714 int extract_quality(arg_list_t &arg_list,int &quality)
715 {
716         arg_list_t::iterator iter, next;
717         for(next=arg_list.begin(),iter=next++;iter!=arg_list.end();iter=next++)
718         {
719                 if(*iter=="-Q")
720                 {
721                         arg_list.erase(iter);
722                         iter=next++;
723                         quality=atoi(iter->c_str());
724                         VERBOSE_OUT(1)<<strprintf(_("Quality set to %d"),quality)<<endl;
725                         arg_list.erase(iter);
726                 }
727                 else if (flag_requires_value(*iter))
728                         iter=next++;
729         }
730
731         return SYNFIGTOOL_OK;
732 }
733
734 int extract_threads(arg_list_t &arg_list,int &threads)
735 {
736         arg_list_t::iterator iter, next;
737         for(next=arg_list.begin(),iter=next++;iter!=arg_list.end();iter=next++)
738         {
739                 if(*iter=="-T")
740                 {
741                         arg_list.erase(iter);
742                         iter=next++;
743                         threads=atoi(iter->c_str());
744                         VERBOSE_OUT(1)<<strprintf(_("Threads set to %d"),threads)<<endl;
745                         arg_list.erase(iter);
746                 }
747                 else if (flag_requires_value(*iter))
748                         iter=next++;
749         }
750
751         return SYNFIGTOOL_OK;
752 }
753
754 int extract_target(arg_list_t &arg_list,string &type)
755 {
756         arg_list_t::iterator iter, next;
757         type.clear();
758
759         for(next=arg_list.begin(),iter=next++;iter!=arg_list.end();iter=next++)
760         {
761                 if(*iter=="-t")
762                 {
763                         arg_list.erase(iter);
764                         iter=next++;
765                         type=*iter;
766                         arg_list.erase(iter);
767                 }
768                 else if (flag_requires_value(*iter))
769                         iter=next++;
770         }
771
772         return SYNFIGTOOL_OK;
773 }
774
775 int extract_append(arg_list_t &arg_list,string &filename)
776 {
777         arg_list_t::iterator iter, next;
778         filename.clear();
779
780         for(next=arg_list.begin(),iter=next++;iter!=arg_list.end();iter=next++)
781         {
782                 if(*iter=="--append")
783                 {
784                         arg_list.erase(iter);
785                         iter=next++;
786                         filename=*iter;
787                         arg_list.erase(iter);
788                 }
789                 else if (flag_requires_value(*iter))
790                         iter=next++;
791         }
792
793         return SYNFIGTOOL_OK;
794 }
795
796 int extract_outfile(arg_list_t &arg_list,string &outfile)
797 {
798         arg_list_t::iterator iter, next;
799         int ret=SYNFIGTOOL_FILENOTFOUND;
800         outfile.clear();
801
802         for(next=arg_list.begin(),iter=next++;iter!=arg_list.end();iter=next++)
803         {
804                 if(*iter=="-o")
805                 {
806                         arg_list.erase(iter);
807                         iter=next++;
808                         outfile=*iter;
809                         arg_list.erase(iter);
810                         ret=SYNFIGTOOL_OK;
811                 }
812                 else if (flag_requires_value(*iter))
813                         iter=next++;
814         }
815
816         return ret;
817 }
818
819 int extract_canvasid(arg_list_t &arg_list,string &canvasid)
820 {
821         arg_list_t::iterator iter, next;
822         //canvasid.clear();
823
824         for(next=arg_list.begin(),iter=next++;iter!=arg_list.end();iter=next++)
825         {
826                 if(*iter=="-c")
827                 {
828                         arg_list.erase(iter);
829                         iter=next++;
830                         canvasid=*iter;
831                         arg_list.erase(iter);
832                 }
833                 else if (flag_requires_value(*iter))
834                         iter=next++;
835         }
836
837         return SYNFIGTOOL_OK;
838 }
839
840 int extract_list_canvases(arg_list_t &arg_list,bool &list_canvases)
841 {
842         arg_list_t::iterator iter, next;
843
844         for(next=arg_list.begin(),iter=next++;iter!=arg_list.end();iter=next++)
845                 if(*iter=="--list-canvases")
846                 {
847                         list_canvases = true;
848                         arg_list.erase(iter);
849                 }
850
851         return SYNFIGTOOL_OK;
852 }
853
854 void extract_canvas_info(arg_list_t &arg_list, Job &job)
855 {
856         arg_list_t::iterator iter, next;
857
858         for(next=arg_list.begin(),iter=next++;iter!=arg_list.end();iter=next++)
859                 if(*iter=="--canvas-info")
860                 {
861                         job.canvas_info = true;
862                         arg_list.erase(iter);
863                         iter=next++;
864                         String values(*iter), value;
865                         arg_list.erase(iter);
866
867                         std::string::size_type pos;
868                         while (!values.empty())
869                         {
870                                 pos = values.find_first_of(',');
871                                 if (pos == std::string::npos)
872                                 {
873                                         value = values;
874                                         values = "";
875                                 }
876                                 else
877                                 {
878                                         value = values.substr(0, pos);
879                                         values = values.substr(pos+1);
880                                 }
881                                 if (value == "all")
882                                 {
883                                         job.canvas_info_all = true;
884                                         return;
885                                 }
886
887                                 if (value == "time_start")                      job.canvas_info_time_start              = true;
888                                 else if (value == "time_end")           job.canvas_info_time_end                = true;
889                                 else if (value == "frame_rate")         job.canvas_info_frame_rate              = true;
890                                 else if (value == "frame_start")        job.canvas_info_frame_start             = true;
891                                 else if (value == "frame_end")          job.canvas_info_frame_end               = true;
892                                 else if (value == "w")                          job.canvas_info_w                               = true;
893                                 else if (value == "h")                          job.canvas_info_h                               = true;
894                                 else if (value == "image_aspect")       job.canvas_info_image_aspect    = true;
895                                 else if (value == "pw")                         job.canvas_info_pw                              = true;
896                                 else if (value == "ph")                         job.canvas_info_ph                              = true;
897                                 else if (value == "pixel_aspect")       job.canvas_info_pixel_aspect    = true;
898                                 else if (value == "tl")                         job.canvas_info_tl                              = true;
899                                 else if (value == "br")                         job.canvas_info_br                              = true;
900                                 else if (value == "physical_w")         job.canvas_info_physical_w              = true;
901                                 else if (value == "physical_h")         job.canvas_info_physical_h              = true;
902                                 else if (value == "x_res")                      job.canvas_info_x_res                   = true;
903                                 else if (value == "y_res")                      job.canvas_info_y_res                   = true;
904                                 else if (value == "span")                       job.canvas_info_span                    = true;
905                                 else if (value == "interlaced")         job.canvas_info_interlaced              = true;
906                                 else if (value == "antialias")          job.canvas_info_antialias               = true;
907                                 else if (value == "clamp")                      job.canvas_info_clamp                   = true;
908                                 else if (value == "flags")                      job.canvas_info_flags                   = true;
909                                 else if (value == "focus")                      job.canvas_info_focus                   = true;
910                                 else if (value == "bg_color")           job.canvas_info_bg_color                = true;
911                                 else if (value == "metadata")           job.canvas_info_metadata                = true;
912                                 else
913                                 {
914                                         cerr<<_("Unrecognised canvas variable: ") << "'" << value << "'" << endl;
915                                         cerr<<_("Recognized variables are:") << endl <<
916                                                 "  all, time_start, time_end, frame_rate, frame_start, frame_end, w, h," << endl <<
917                                                 "  image_aspect, pw, ph, pixel_aspect, tl, br, physical_w, physical_h," << endl <<
918                                                 "  x_res, y_res, span, interlaced, antialias, clamp, flags," << endl <<
919                                                 "  focus, bg_color, metadata" << endl;
920                                 }
921
922                                 if (pos == std::string::npos)
923                                         break;
924                         };
925                 }
926 }
927
928 void list_child_canvases(string prefix, Canvas::Handle canvas)
929 {
930         Canvas::Children children(canvas->children());
931         for (Canvas::Children::iterator iter = children.begin(); iter != children.end(); iter++)
932         {
933                 cout << prefix << ":" << (*iter)->get_id() << endl;
934                 list_child_canvases(prefix + ":" + (*iter)->get_id(), *iter);
935         }
936 }
937
938 void list_canvas_info(Job job)
939 {
940         Canvas::Handle canvas(job.canvas);
941         const RendDesc &rend_desc(canvas->rend_desc());
942
943         if (job.canvas_info_all || job.canvas_info_time_start)
944         {
945                 cout << endl << "# " << _("Start Time") << endl;
946                 cout << "time_start"    << "=" << rend_desc.get_time_start().get_string().c_str() << endl;
947         }
948
949         if (job.canvas_info_all || job.canvas_info_time_end)
950         {
951                 cout << endl << "# " << _("End Time") << endl;
952                 cout << "time_end"              << "=" << rend_desc.get_time_end().get_string().c_str() << endl;
953         }
954
955         if (job.canvas_info_all || job.canvas_info_frame_rate)
956         {
957                 cout << endl << "# " << _("Frame Rate") << endl;
958                 cout << "frame_rate"    << "=" << rend_desc.get_frame_rate() << endl;
959         }
960
961         if (job.canvas_info_all || job.canvas_info_frame_start)
962         {
963                 cout << endl << "# " << _("Start Frame") << endl;
964                 cout << "frame_start"   << "=" << rend_desc.get_frame_start() << endl;
965         }
966
967         if (job.canvas_info_all || job.canvas_info_frame_end)
968         {
969                 cout << endl << "# " << _("End Frame") << endl;
970                 cout << "frame_end"             << "=" << rend_desc.get_frame_end() << endl;
971         }
972
973         if (job.canvas_info_all)
974                 cout << endl;
975
976         if (job.canvas_info_all || job.canvas_info_w)
977         {
978                 cout << endl << "# " << _("Width") << endl;
979                 cout << "w"                             << "=" << rend_desc.get_w() << endl;
980         }
981
982         if (job.canvas_info_all || job.canvas_info_h)
983         {
984                 cout << endl << "# " << _("Height") << endl;
985                 cout << "h"                             << "=" << rend_desc.get_h() << endl;
986         }
987
988         if (job.canvas_info_all || job.canvas_info_image_aspect)
989         {
990                 cout << endl << "# " << _("Image Aspect Ratio") << endl;
991                 cout << "image_aspect"  << "=" << rend_desc.get_image_aspect() << endl;
992         }
993
994         if (job.canvas_info_all)
995                 cout << endl;
996
997         if (job.canvas_info_all || job.canvas_info_pw)
998         {
999                 cout << endl << "# " << _("Pixel Width") << endl;
1000                 cout << "pw"                    << "=" << rend_desc.get_pw() << endl;
1001         }
1002
1003         if (job.canvas_info_all || job.canvas_info_ph)
1004         {
1005                 cout << endl << "# " << _("Pixel Height") << endl;
1006                 cout << "ph"                    << "=" << rend_desc.get_ph() << endl;
1007         }
1008
1009         if (job.canvas_info_all || job.canvas_info_pixel_aspect)
1010         {
1011                 cout << endl << "# " << _("Pixel Aspect Ratio") << endl;
1012                 cout << "pixel_aspect"  << "=" << rend_desc.get_pixel_aspect() << endl;
1013         }
1014
1015         if (job.canvas_info_all)
1016                 cout << endl;
1017
1018         if (job.canvas_info_all || job.canvas_info_tl)
1019         {
1020                 cout << endl << "# " << _("Top Left") << endl;
1021                 cout << "tl"                    << "=" << rend_desc.get_tl()[0]
1022                          << " " << rend_desc.get_tl()[1] << endl;
1023         }
1024
1025         if (job.canvas_info_all || job.canvas_info_br)
1026         {
1027                 cout << endl << "# " << _("Bottom Right") << endl;
1028                 cout << "br"                    << "=" << rend_desc.get_br()[0]
1029                          << " " << rend_desc.get_br()[1] << endl;
1030         }
1031
1032         if (job.canvas_info_all || job.canvas_info_physical_w)
1033         {
1034                 cout << endl << "# " << _("Physical Width") << endl;
1035                 cout << "physical_w"    << "=" << rend_desc.get_physical_w() << endl;
1036         }
1037
1038         if (job.canvas_info_all || job.canvas_info_physical_h)
1039         {
1040                 cout << endl << "# " << _("Physical Height") << endl;
1041                 cout << "physical_h"    << "=" << rend_desc.get_physical_h() << endl;
1042         }
1043
1044         if (job.canvas_info_all || job.canvas_info_x_res)
1045         {
1046                 cout << endl << "# " << _("X Resolution") << endl;
1047                 cout << "x_res"                 << "=" << rend_desc.get_x_res() << endl;
1048         }
1049
1050         if (job.canvas_info_all || job.canvas_info_y_res)
1051         {
1052                 cout << endl << "# " << _("Y Resolution") << endl;
1053                 cout << "y_res"                 << "=" << rend_desc.get_y_res() << endl;
1054         }
1055
1056         if (job.canvas_info_all || job.canvas_info_span)
1057         {
1058                 cout << endl << "# " << _("Diagonal Image Span") << endl;
1059                 cout << "span"                  << "=" << rend_desc.get_span() << endl;
1060         }
1061
1062         if (job.canvas_info_all)
1063                 cout << endl;
1064
1065         if (job.canvas_info_all || job.canvas_info_interlaced)
1066         {
1067                 cout << endl << "# " << _("Interlaced") << endl;
1068                 cout << "interlaced"    << "=" << rend_desc.get_interlaced() << endl;
1069         }
1070
1071         if (job.canvas_info_all || job.canvas_info_antialias)
1072         {
1073                 cout << endl << "# " << _("Antialias") << endl;
1074                 cout << "antialias"             << "=" << rend_desc.get_antialias() << endl;
1075         }
1076
1077         if (job.canvas_info_all || job.canvas_info_clamp)
1078         {
1079                 cout << endl << "# " << _("Clamp") << endl;
1080                 cout << "clamp"                 << "=" << rend_desc.get_clamp() << endl;
1081         }
1082
1083         if (job.canvas_info_all || job.canvas_info_flags)
1084         {
1085                 cout << endl << "# " << _("Flags") << endl;
1086                 cout << "flags"                 << "=" << rend_desc.get_flags() << endl;
1087         }
1088
1089         if (job.canvas_info_all || job.canvas_info_focus)
1090         {
1091                 cout << endl << "# " << _("Focus") << endl;
1092                 cout << "focus"                 << "=" << rend_desc.get_focus()[0]
1093                          << " " << rend_desc.get_focus()[1] << endl;
1094         }
1095
1096         if (job.canvas_info_all || job.canvas_info_bg_color)
1097         {
1098                 cout << endl << "# " << _("Background Color") << endl;
1099                 cout << "bg_color"              << "=" << rend_desc.get_bg_color().get_string().c_str() << endl;
1100         }
1101
1102         if (job.canvas_info_all)
1103                 cout << endl;
1104
1105         if (job.canvas_info_all || job.canvas_info_metadata)
1106         {
1107                 std::list<String> keys(canvas->get_meta_data_keys());
1108                 cout << endl << "# " << _("Metadata") << endl;
1109                 for (std::list<String>::iterator iter = keys.begin(); iter != keys.end(); iter++)
1110                         cout << *iter << "=" << canvas->get_meta_data(*iter) << endl;
1111         }
1112 }
1113
1114 /* === M E T H O D S ======================================================= */
1115
1116 /* === E N T R Y P O I N T ================================================= */
1117
1118 int main(int argc, char *argv[])
1119 {
1120         int i;
1121         arg_list_t arg_list;
1122         job_list_t job_list;
1123
1124         setlocale(LC_ALL, "");
1125
1126 #ifdef ENABLE_NLS
1127         bindtextdomain("synfig", LOCALEDIR);
1128         textdomain("synfig");
1129 #endif
1130
1131         progname=argv[0];
1132         Progress p(argv[0]);
1133
1134         if(!SYNFIG_CHECK_VERSION())
1135         {
1136                 cerr<<_("FATAL: Synfig Version Mismatch")<<endl;
1137                 return SYNFIGTOOL_BADVERSION;
1138         }
1139
1140         if(argc==1)
1141         {
1142                 display_help(0);
1143                 return SYNFIGTOOL_BLANK;
1144         }
1145
1146         for(i=1;i<argc;i++)
1147                 arg_list.push_back(argv[i]);
1148
1149         if((i=process_global_flags(arg_list)))
1150                 return i;
1151
1152         VERBOSE_OUT(1)<<_("verbosity set to ")<<verbosity<<endl;
1153         synfig::Main synfig_main(dirname(progname),&p);
1154
1155         {
1156                 arg_list_t defaults, imageargs;
1157                 int ret;
1158
1159                 // Grab the defaults before the first file
1160                 if ((ret = extract_arg_cluster(arg_list,defaults)) != SYNFIGTOOL_OK)
1161                   return ret;
1162
1163                 while(arg_list.size())
1164                 {
1165                         string target_name;
1166                         job_list.push_front(Job());
1167                         int threads=0;
1168
1169                         imageargs=defaults;
1170                         job_list.front().filename=arg_list.front();
1171                         arg_list.pop_front();
1172
1173                         if ((ret = extract_arg_cluster(arg_list,imageargs)) != SYNFIGTOOL_OK)
1174                           return ret;
1175
1176                         // Open the composition
1177                         job_list.front().root=open_canvas(job_list.front().filename);
1178
1179                         if(!job_list.front().root)
1180                         {
1181                                 cerr<<_("Unable to open ")<<job_list.front().filename<<"."<<endl;
1182                                 cerr<<_("Throwing out job...")<<endl;
1183                                 job_list.pop_front();
1184                                 continue;
1185                         }
1186
1187                         bool list_canvases = false;
1188                         extract_list_canvases(imageargs, list_canvases);
1189                         job_list.front().list_canvases = list_canvases;
1190
1191                         extract_canvas_info(imageargs, job_list.front());
1192
1193                         job_list.front().root->set_time(0);
1194
1195                         string canvasid;
1196                         extract_canvasid(imageargs,canvasid);
1197                         if(!canvasid.empty())
1198                         {
1199                                 try
1200                                 {
1201                                         job_list.front().canvas=job_list.front().root->find_canvas(canvasid);
1202                                 }
1203                                 catch(Exception::IDNotFound)
1204                                 {
1205                                         cerr<<_("Unable to find canvas with ID \"")<<canvasid<<_("\" in ")<<job_list.front().filename<<"."<<endl;
1206                                         cerr<<_("Throwing out job...")<<endl;
1207                                         job_list.pop_front();
1208                                         continue;
1209
1210                                 }
1211                                 catch(Exception::BadLinkName)
1212                                 {
1213                                         cerr<<_("Invalid canvas name \"")<<canvasid<<_("\" in ")<<job_list.front().filename<<"."<<endl;
1214                                         cerr<<_("Throwing out job...")<<endl;
1215                                         job_list.pop_front();
1216                                         continue;
1217                                 }
1218                         }
1219                         else
1220                                 job_list.front().canvas=job_list.front().root;
1221
1222                         extract_RendDesc(imageargs,job_list.front().canvas->rend_desc());
1223                         extract_target(imageargs,target_name);
1224                         extract_threads(imageargs,threads);
1225                         job_list.front().quality=DEFAULT_QUALITY;
1226                         extract_quality(imageargs,job_list.front().quality);
1227                         VERBOSE_OUT(2)<<_("Quality set to ")<<job_list.front().quality<<endl;
1228                         job_list.front().desc=job_list.front().canvas->rend_desc();
1229                         extract_outfile(imageargs,job_list.front().outfilename);
1230
1231                         // Extract composite
1232                         do{
1233                                 string composite_file;
1234                                 extract_append(imageargs,composite_file);
1235                                 if(!composite_file.empty())
1236                                 {
1237                                         Canvas::Handle composite(open_canvas(composite_file));
1238                                         if(!composite)
1239                                                 break;
1240                                         Canvas::reverse_iterator iter;
1241                                         for(iter=composite->rbegin();iter!=composite->rend();++iter)
1242                                         {
1243                                                 Layer::Handle layer(*iter);
1244                                                 if(layer->active())
1245                                                         job_list.front().canvas->push_front(layer->clone());
1246                                         }
1247                                         VERBOSE_OUT(2)<<_("Appended contents of ")<<composite_file<<endl;
1248                                 }
1249                         } while(false);
1250
1251                         VERBOSE_OUT(4)<<_("Attempting to determine target/outfile...")<<endl;
1252
1253                         // If the target type is not yet defined,
1254                         // try to figure it out from the outfile.
1255                         if(target_name.empty() && !job_list.front().outfilename.empty())
1256                         {
1257                                 VERBOSE_OUT(3)<<_("Target name undefined, attempting to figure it out")<<endl;
1258                                 string ext = filename_extension(job_list.front().outfilename);
1259                                 if (ext.length()) ext = ext.substr(1);
1260                                 if(Target::ext_book().count(ext))
1261                                 {
1262                                         target_name=Target::ext_book()[ext];
1263                                         info("target name not specified - using %s", target_name.c_str());
1264                                 }
1265                                 else
1266                                 {
1267                                         string lower_ext(ext);
1268
1269                                         for(unsigned int i=0;i<ext.length();i++)
1270                                                 lower_ext[i] = tolower(ext[i]);
1271
1272                                         if(Target::ext_book().count(lower_ext))
1273                                         {
1274                                                 target_name=Target::ext_book()[lower_ext];
1275                                                 info("target name not specified - using %s", target_name.c_str());
1276                                         }
1277                                         else
1278                                                 target_name=ext;
1279                                 }
1280                         }
1281
1282                         // If the target type is STILL not yet defined, then
1283                         // set it to a some sort of default
1284                         if(target_name.empty())
1285                         {
1286                                 VERBOSE_OUT(2)<<_("Defaulting to PNG target...")<<endl;
1287                                 target_name="png";
1288                         }
1289
1290                         // If no output filename was provided, then
1291                         // create a output filename based on the
1292                         // given input filename. (ie: change the extension)
1293                         if(job_list.front().outfilename.empty())
1294                         {
1295                                 job_list.front().outfilename = filename_sans_extension(job_list.front().filename) + '.';
1296                                 if(Target::book().count(target_name))
1297                                         job_list.front().outfilename+=Target::book()[target_name].second;
1298                                 else
1299                                         job_list.front().outfilename+=target_name;
1300                         }
1301
1302                         VERBOSE_OUT(4)<<"target_name="<<target_name<<endl;
1303                         VERBOSE_OUT(4)<<"outfile_name="<<job_list.front().outfilename<<endl;
1304
1305                         VERBOSE_OUT(4)<<_("Creating the target...")<<endl;
1306                         job_list.front().target=synfig::Target::create(target_name,job_list.front().outfilename);
1307
1308                         if(target_name=="sif")
1309                                 job_list.front().sifout=true;
1310                         else
1311                         {
1312                                 if(!job_list.front().target)
1313                                 {
1314                                         cerr<<_("Unknown target for ")<<job_list.front().filename<<": "<<target_name<<endl;
1315                                         cerr<<_("Throwing out job...")<<endl;
1316                                         job_list.pop_front();
1317                                         continue;
1318                                 }
1319                                 job_list.front().sifout=false;
1320                         }
1321
1322                         // Set the Canvas on the Target
1323                         if(job_list.front().target)
1324                         {
1325                                 VERBOSE_OUT(4)<<_("Setting the canvas on the target...")<<endl;
1326                                 job_list.front().target->set_canvas(job_list.front().canvas);
1327                                 VERBOSE_OUT(4)<<_("Setting the quality of the target...")<<endl;
1328                                 job_list.front().target->set_quality(job_list.front().quality);
1329                         }
1330
1331                         // Set the threads for the target
1332                         if(job_list.front().target && Target_Scanline::Handle::cast_dynamic(job_list.front().target))
1333                                 Target_Scanline::Handle::cast_dynamic(job_list.front().target)->set_threads(threads);
1334
1335                         if(imageargs.size())
1336                         {
1337                                 cerr<<_("Unidentified arguments for ")<<job_list.front().filename<<": ";
1338                                 for(;imageargs.size();imageargs.pop_front())
1339                                         cerr<<' '<<imageargs.front();
1340                                 cerr<<endl;
1341                                 cerr<<_("Throwing out job...")<<endl;
1342                                 job_list.pop_front();
1343                                 continue;
1344                         }
1345                 }
1346         }
1347
1348         if(arg_list.size())
1349         {
1350                 cerr<<_("Unidentified arguments:");
1351                 for(;arg_list.size();arg_list.pop_front())
1352                         cerr<<' '<<arg_list.front();
1353                 cerr<<endl;
1354                 return SYNFIGTOOL_UNKNOWNARGUMENT;
1355         }
1356
1357         if(!job_list.size())
1358         {
1359                 cerr<<_("Nothing to do!")<<endl;
1360                 return SYNFIGTOOL_BORED;
1361         }
1362
1363         for(;job_list.size();job_list.pop_front())
1364         {
1365                 VERBOSE_OUT(3)<<job_list.front().filename<<" -- "<<endl<<'\t'<<
1366                 strprintf("w:%d, h:%d, a:%d, pxaspect:%f, imaspect:%f, span:%f",
1367                         job_list.front().desc.get_w(),
1368                         job_list.front().desc.get_h(),
1369                         job_list.front().desc.get_antialias(),
1370                         job_list.front().desc.get_pixel_aspect(),
1371                         job_list.front().desc.get_image_aspect(),
1372                         job_list.front().desc.get_span()
1373                         )<<endl<<'\t'<<
1374                 strprintf("tl:[%f,%f], br:[%f,%f], focus:[%f,%f]",
1375                         job_list.front().desc.get_tl()[0],job_list.front().desc.get_tl()[1],
1376                         job_list.front().desc.get_br()[0],job_list.front().desc.get_br()[1],
1377                         job_list.front().desc.get_focus()[0],job_list.front().desc.get_focus()[1]
1378                         )<<endl;
1379
1380                 RenderProgress p;
1381                 p.task(job_list.front().filename+" ==> "+job_list.front().outfilename);
1382                 if(job_list.front().sifout)
1383                 {
1384                         if(!save_canvas(job_list.front().outfilename,job_list.front().canvas))
1385                         {
1386                                 cerr<<"Render Failure."<<endl;
1387                                 return SYNFIGTOOL_RENDERFAILURE;
1388                         }
1389                 }
1390                 else if (job_list.front().list_canvases)
1391                 {
1392                         list_child_canvases(job_list.front().filename + "#", job_list.front().canvas);
1393                         cerr << endl;
1394                 }
1395                 else if (job_list.front().canvas_info)
1396                 {
1397                         list_canvas_info(job_list.front());
1398                         cerr << endl;
1399                 }
1400                 else
1401                 {
1402                         VERBOSE_OUT(1)<<_("Rendering...")<<endl;
1403                         etl::clock timer;
1404                         timer.reset();
1405                         // Call the render member of the target
1406                         if(!job_list.front().target->render(&p))
1407                         {
1408                                 cerr<<"Render Failure."<<endl;
1409                                 return SYNFIGTOOL_RENDERFAILURE;
1410                         }
1411                         if(print_benchmarks)
1412                                 cout<<job_list.front().filename+": Rendered in "<<timer()<<" seconds."<<endl;
1413                 }
1414         }
1415
1416         job_list.clear();
1417
1418         VERBOSE_OUT(1)<<_("Done.")<<endl;
1419
1420         return SYNFIGTOOL_OK;
1421 }