rewrote manpage/--help
[swftools.git] / src / pdf2swf.c
1 /* pdf2swf.c
2    main routine for pdf2swf(1)
3
4    Part of the swftools package.
5    
6    Copyright (c) 2001,2002,2003 Matthias Kramm <kramm@quiss.org> 
7  
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <stdarg.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include "../config.h"
28 #ifdef HAVE_SIGNAL_H
29 #include <signal.h>
30 #endif
31 #ifdef HAVE_DIRENT_H
32 #include <dirent.h>
33 #endif
34 #ifdef HAVE_MALLOC_H
35 #include <malloc.h>
36 #endif
37
38 #include "../lib/args.h"
39 #include "../lib/os.h"
40 #include "../lib/rfxswf.h"
41 #include "../lib/devices/swf.h"
42 #include "../lib/devices/polyops.h"
43 #include "../lib/devices/record.h"
44 #include "../lib/pdf/pdf.h"
45 #include "../lib/log.h"
46
47 #define SWFDIR concatPaths(getInstallationPath(), "swfs")
48
49 static gfxsource_t*driver = 0;
50 static gfxdevice_t*out = 0;
51
52 static char * outputname = 0;
53 static int loglevel = 3;
54 static char * pagerange = 0;
55 static char * filename = 0;
56 static char * password = 0;
57 static int zlib = 0;
58
59 static char * preloader = 0;
60 static char * viewer = 0;
61 static int xnup = 1;
62 static int ynup = 1;
63
64 static int info_only = 0;
65
66 static int max_time = 0;
67
68 static int flatten = 0;
69
70 char* fontpaths[256];
71 int fontpathpos = 0;
72
73 int move_x=0;
74 int move_y=0;
75 int custom_move = 0;
76 int clip_x1=0,clip_y1=0,clip_x2=0,clip_y2=0;
77 int custom_clip = 0;
78
79 static int system_quiet=0;
80
81 int systemf(const char* format, ...)
82 {
83     char buf[1024];
84     int ret;
85     va_list arglist;
86     va_start(arglist, format);
87     vsprintf(buf, format, arglist);
88     va_end(arglist);
89
90     if(!system_quiet) {
91         printf("%s\n", buf);
92         fflush(stdout);
93     }
94     ret = system(buf);
95     if(ret) {
96         fprintf(stderr, "system() returned %d\n", ret);
97         exit(ret);
98     }
99     return ret;
100 }
101
102 #ifdef HAVE_SIGNAL_H
103 void sigalarm(int signal)
104 {
105     msg("<fatal> Aborting rendering after %d seconds", max_time);
106 #if 0 && defined(HAVE_SYS_TIME_H) && defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRUSAGE)
107     struct rusage usage;
108     getrusage(RUSAGE_CHILDREN, &usage);
109     msg("<fatal> Memory used: %d,%d,%d", usage.ru_maxrss, usage.ru_idrss, usage.ru_isrss);
110 #endif 
111 #if defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_H)
112     struct mallinfo info = mallinfo();
113     msg("<fatal> Memory used: %d Mb (%d bytes)", info.uordblks/1048576, info.uordblks);
114 #endif
115     exit(1);
116 }
117 #endif
118
119 int args_callback_option(char*name,char*val) {
120     if (!strcmp(name, "o"))
121     {
122         outputname = val;
123         return 1;
124     }
125     else if (!strcmp(name, "v"))
126     {
127         loglevel ++;
128         setConsoleLogging(loglevel);
129         return 0;
130     }
131     else if (!strcmp(name, "2"))
132     {
133         xnup = 2;
134         ynup = 1;
135         return 0;
136     }
137     else if (!strcmp(name, "4"))
138     {
139         xnup = 2;
140         ynup = 2;
141         return 0;
142     }
143     else if (!strcmp(name, "9"))
144     {
145         xnup = 3;
146         ynup = 3;
147         return 0;
148     }
149     else if (!strcmp(name, "q"))
150     {
151         loglevel --;
152         setConsoleLogging(loglevel);
153         system_quiet = 1;
154         return 0;
155     }
156     else if (name[0]=='p')
157     {
158         /* check whether the page range follows the p directly, like 
159            in -p1,2 */
160         do {
161             name++;
162         } while(*name == 32 || *name == 13 || *name == 10 || *name == '\t');
163
164         if(*name) {
165             pagerange = name;
166             return 0;
167         } 
168         pagerange = val;        
169         return 1;
170     }
171     else if (!strcmp(name, "P"))
172     {
173         password = val;
174         return 1;
175     }
176     else if (!strcmp(name, "c"))
177     {
178         char*s = strdup(val);
179         char*x1 = strtok(s, ":");
180         char*y1 = strtok(0, ":");
181         char*x2 = strtok(0, ":");
182         char*y2 = strtok(0, ":");
183         if(!(x1 && y1 && x2 && y2)) {
184             fprintf(stderr, "-c option requires four arguments, <x1>:<y1>:<x2>:<y2>\n");
185             exit(1);
186         }
187         custom_clip = 1;
188         clip_x1 = atoi(x1);
189         clip_y1 = atoi(y1);
190         clip_x2 = atoi(x2);
191         clip_y2 = atoi(y2);
192         free(s);
193         return 1;
194     }
195     else if (!strcmp(name, "m"))
196     {
197         char*s = strdup(val);
198         char*c = strchr(s, ':');
199         if(!c) {
200             fprintf(stderr, "-m option requires two arguments, <x>:<y>\n");
201             exit(1);
202         }
203         *c = 0;
204         custom_move = 1;
205         move_x = atoi(val);
206         move_y = atoi(c+1);
207         free(s);
208         return 1;
209     }
210     else if (!strcmp(name, "s"))
211     {
212         char*s = strdup(val);
213         char*c = strchr(s, '=');
214         if(c && *c && c[1])  {
215             *c = 0;
216             c++;
217             driver->set_parameter(driver, s,c);
218             out->setparameter(out, s,c);
219         } else {
220             driver->set_parameter(driver, s,"1");
221             out->setparameter(out, s,"1");
222         }
223         return 1;
224     }
225     else if (!strcmp(name, "S"))
226     {
227         driver->set_parameter(driver, "drawonlyshapes", "1");
228         return 0;
229     }
230     else if (!strcmp(name, "i"))
231     {
232         driver->set_parameter(driver, "ignoredraworder", "1");
233         return 0;
234     }
235 #ifndef WIN32
236     else if (!strcmp(name, "Q"))
237     {
238         max_time = atoi(val);
239         alarm(max_time);
240 # ifdef HAVE_SIGNAL_H
241         signal(SIGALRM, sigalarm);
242 # endif
243         return 1;
244     }
245 #endif
246     else if (!strcmp(name, "z"))
247     {
248         driver->set_parameter(driver, "enablezlib", "1");
249         zlib = 1;
250         return 0;
251     }
252     else if (!strcmp(name, "n"))
253     {
254         driver->set_parameter(driver, "opennewwindow", "1");
255         return 0;
256     }
257     else if (!strcmp(name, "I"))
258     {
259         info_only = 1;
260         return 0;
261     }
262     else if (!strcmp(name, "t"))
263     {
264         driver->set_parameter(driver, "insertstop", "1");
265         return 0;
266     }
267     else if (!strcmp(name, "T"))
268     {
269         if(!strcasecmp(val, "mx"))
270             driver->set_parameter(driver, "flashversion", "6");
271         else
272             driver->set_parameter(driver, "flashversion", val);
273
274         return 1;
275     }
276     else if (!strcmp(name, "f"))
277     {
278         driver->set_parameter(driver, "storeallcharacters", "1");
279         driver->set_parameter(driver, "extrafontdata", "1");
280         return 0;
281     }
282     else if (!strcmp(name, "w"))
283     {
284         driver->set_parameter(driver, "linksopennewwindow", "0");
285         return 0;
286     }
287     else if (!strcmp(name, "O"))
288     {
289         int level = 1;
290         int ret=0;
291         if(val&& val[0] && val[1]==0 && isdigit(val[0])) {
292             level = atoi(val);
293             ret=1;
294         }
295         if(level>=1)
296             driver->set_parameter(driver, "poly2bitmap", "1");
297         if(level>=2)
298             driver->set_parameter(driver, "bitmapfonts", "1");
299         if(level>=3)
300             driver->set_parameter(driver, "ignoredraworder", "1");
301         return ret;
302     }
303     else if (!strcmp(name, "G"))
304     {
305         //driver->set_parameter(driver, "optimize_polygons", "1");
306         flatten = 1;
307         return 0;
308     }
309     else if (!strcmp(name, "F"))
310     {
311         char *s = strdup(val);
312         int l = strlen(s);
313         while(l && s[l-1]=='/') {
314             s[l-1] = 0;
315             l--;
316         }
317         fontpaths[fontpathpos++] = s;
318         return 1;
319     }
320     else if (!strcmp(name, "l"))
321     {
322         char buf[256];
323         sprintf(buf, "%s/default_loader.swf", SWFDIR);
324         preloader = strdup(buf);
325         return 0;
326     }
327     else if (!strcmp(name, "b"))
328     {
329         char buf[256];
330         sprintf(buf, "%s/default_viewer.swf", SWFDIR);
331         viewer = strdup(buf);
332         return 0;
333     }
334     else if (!strcmp(name, "L"))
335     {
336         if(val)
337         {
338             preloader = val;
339         }
340         else
341         {
342             systemf("ls %s/*_loader.swf", SWFDIR);
343             if(!system_quiet)
344                 printf("\n");
345             exit(1);
346         }
347         return 1;
348     }
349     else if (!strcmp(name, "B"))
350     {
351         if(val)
352         {
353             viewer = val;
354         }
355         else
356         {
357             systemf("ls %s/*_viewer.swf", SWFDIR);
358             if(!system_quiet)
359                 printf("\n");
360             exit(1);
361         }
362         return 1;
363     }
364     else if (!strcmp(name, "j"))
365     {
366         if(name[1]) {
367             driver->set_parameter(driver, "jpegquality", &name[1]);
368             return 0;
369         } else {
370             driver->set_parameter(driver, "jpegquality", val);
371             return 1;
372         }
373     }
374     else if (!strcmp(name, "V"))
375     {   
376         printf("pdf2swf - part of %s %s\n", PACKAGE, VERSION);
377         exit(0);
378     }
379     else 
380     {
381         fprintf(stderr, "Unknown option: -%s\n", name);
382         exit(1);
383     }
384     return 0;
385 }
386
387 /*struct docoptions_t options[] =
388 {{"o","output","filename::Specify output file"},
389  {"V","version","Print program version"},
390  {"i","ignore","Ignore draw order (makes the SWF file smaller, but may produce graphic errors)"},
391  {"z","zlib","Use Flash 6 (MX) zlib compression (Needs at least Flash 6 Plugin to play)"},
392  {"s","shapes","Don't use SWF Fonts, but store everything as shape"},
393  {"j","jpegquality","Set quality of embedded jpeg pictures (default: 85)"},
394  {"p","pages","Convert only pages in range. (E.g. 3-85)"},
395  {"w","samewindow","Don't open a new browser window for links in the SWF"},
396  {"f","fonts","Stroe full fonts in SWF. (Don't reduce to used characters)"},
397  {"F","fontpath","path::Add directory to font search path"},
398  {"B","viewer","name::Link viewer \"name\" to the pdf"},
399  {"L","preloader","file.swf::Link preloader \"file.swf\" to the pdf"},
400  {"b","defaultviewer","Link default viewer to the pdf"},
401  {"l","defaultpreloader","Link default preloader to the pdf"}
402  {0,0}
403 };*/
404 static struct options_t options[] = {
405 {"h", "help"},
406 {"V", "version"},
407 {"o", "output"},
408 {"p", "pages"},
409 {"P", "password"},
410 {"v", "verbose"},
411 {"z", "zlib"},
412 {"i", "ignore"},
413 {"j", "jpegquality"},
414 {"s", "set"},
415 {"w", "samewindow"},
416 {"t", "stop"},
417 {"T", "flashversion"},
418 {"F", "fontdir"},
419 {"b", "defaultviewer"},
420 {"l", "defaultloader"},
421 {"B", "viewer"},
422 {"L", "preloader"},
423 {"q", "quiet"},
424 {"S", "shapes"},
425 {"f", "fonts"},
426 {"G", "flatten"},
427 {"I", "info"},
428 {"Q", "maxtime"},
429 {0,0}
430 };
431
432 int args_callback_longoption(char*name,char*val) {
433     return args_long2shortoption(options, name, val);
434 }
435
436 int args_callback_command(char*name, char*val) {
437     if (!filename) 
438         filename = name;
439     else {
440         if(outputname)
441         {
442              fprintf(stderr, "Error: Do you want the output to go to %s or to %s?", 
443                      outputname, name);
444              exit(1);
445         }
446         outputname = name;
447     }
448     return 0;
449 }
450
451 void args_callback_usage(char *name)
452 {
453     printf("\n");
454     printf("Usage: %s [-options] file.pdf -o file.swf\n", name);
455     printf("\n");
456     printf("-h , --help                    Print short help message and exit\n");
457     printf("-V , --version                 Print version info and exit\n");
458     printf("-o , --output file.swf         Direct output to file.swf. If file.swf contains '%d' (file%d.swf), then each page \n");
459     printf("-p , --pages range             Convert only pages in range with range e.g. 1-20 or 1,4,6,9-11 or\n");
460     printf("-P , --password password       Use password for deciphering the pdf.\n");
461     printf("-v , --verbose                 Be verbose. Use more than one -v for greater effect.\n");
462     printf("-z , --zlib                    Use Flash 6 (MX) zlib compression.\n");
463     printf("-i , --ignore                  Allows pdf2swf to change the draw order of the pdf. This may make the generated\n");
464     printf("-j , --jpegquality quality     Set quality of embedded jpeg pictures to quality. 0 is worst (small), 100 is best (big). (default:85)\n");
465     printf("-s , --set param=value         Set a SWF encoder specific parameter.  See pdf2swf -s help for more information.\n");
466     printf("-w , --samewindow              When converting pdf hyperlinks, don't make the links open a new window. \n");
467     printf("-t , --stop                    Insert a stop() command in each page. \n");
468     printf("-T , --flashversion num        Set Flash Version in the SWF header to num.\n");
469     printf("-F , --fontdir directory       Add directory to the font search path.\n");
470     printf("-b , --defaultviewer           Link a standard viewer to the swf file. \n");
471     printf("-l , --defaultloader           Link a standard preloader to the swf file which will be displayed while the main swf is loading.\n");
472     printf("-B , --viewer filename         Link viewer filename to the swf file. \n");
473     printf("-L , --preloader filename      Link preloader filename to the swf file. \n");
474     printf("-q , --quiet                   Suppress normal messages.  Use -qq to suppress warnings, also.\n");
475     printf("-S , --shapes                  Don't use SWF Fonts, but store everything as shape.\n");
476     printf("-f , --fonts                   Store full fonts in SWF. (Don't reduce to used characters).\n");
477     printf("-G , --flatten                 Remove as many clip layers from file as possible. \n");
478     printf("-I , --info                    Don't do actual conversion, just display a list of all pages in the PDF.\n");
479     printf("-Q , --maxtime n               Abort conversion after n seconds. Only available on Unix.\n");
480     printf("\n");
481 }
482
483 float getRate(char*filename)
484 {
485     int fi;
486     SWF swf;
487     fi = open(filename,O_RDONLY|O_BINARY);
488     if(fi<0) { 
489         char buffer[256];
490         sprintf(buffer, "Couldn't open %s", filename);
491         perror(buffer);
492         exit(1);
493     }
494     if(swf_ReadSWF(fi,&swf) < 0)
495     { 
496         fprintf(stderr, "%s is not a valid SWF file or contains errors.\n",filename);
497         close(fi);
498         exit(1);
499     }
500     swf_FreeTags(&swf);
501     return swf.frameRate / 256.0;
502 }
503
504 void show_info(gfxsource_t*driver, char*filename)
505 {
506     gfxdocument_t* pdf = driver->open(driver, filename);
507     int pagenr;
508     FILE*fo=0;
509     if(!pdf) {
510         msg("<error> Couldn't open %s", filename);
511         exit(1);
512     }
513     if(outputname) {
514         fo = fopen(outputname, "wb");
515         if(!fo) {
516             perror(outputname);exit(1);;
517         }
518     } else {
519         fo = stdout;
520     }
521
522     for(pagenr = 1; pagenr <= pdf->num_pages; pagenr++) 
523     {
524         gfxpage_t*page = pdf->getpage(pdf,pagenr);
525         if(is_in_range(pagenr, pagerange)) {
526             fprintf(fo, "page=%d width=%.2f height=%.2f\n", pagenr, page->width, page->height);
527         }
528     }
529     pdf->destroy(pdf);
530 }
531
532 int main(int argn, char *argv[])
533 {
534     int ret;
535     char buf[256];
536     int numfonts = 0;
537     int t;
538     char t1searchpath[1024];
539     int nup_pos = 0;
540     int x,y;
541     char* installPath = getInstallationPath();
542     
543     initLog(0,-1,0,0,-1,loglevel);
544
545     /* not needed anymore since fonts are embedded
546        if(installPath) {
547         fontpaths[fontpathpos++] = concatPaths(installPath, "fonts");
548     }*/
549
550 #ifdef HAVE_SRAND48
551     srand48(time(0));
552 #else
553 #ifdef HAVE_SRAND
554     srand(time(0));
555 #endif
556 #endif
557     driver = gfxsource_pdf_create();
558
559     gfxdevice_t swf,wrap;
560     gfxdevice_swf_init(&swf);
561     
562     gfxdevice_removeclippings_init(&wrap, &swf);
563
564     out = &wrap;
565     processargs(argn, argv);
566     
567     if(!flatten) {
568         out = &swf;
569     }
570     
571     if(!filename)
572     {
573         fprintf(stderr, "Please specify an input file\n");
574         exit(1);
575     }
576
577     if(info_only) {
578         show_info(driver, filename);
579         return 0;
580     }
581
582     if(!outputname)
583     {
584         if(filename) {
585             outputname = stripFilename(filename, ".swf");
586             msg("<notice> Output filename not given. Writing to %s", outputname);
587         } 
588     }
589         
590     if(!outputname)
591     {
592         fprintf(stderr, "Please use -o to specify an output file\n");
593         exit(1);
594     }
595
596     // test if the page range is o.k.
597     is_in_range(0x7fffffff, pagerange);
598
599     if(pagerange)
600         driver->set_parameter(driver, "pages", pagerange);
601
602     if (!filename) {
603         args_callback_usage(argv[0]);
604         exit(0);
605     }
606
607     /* add fonts */
608     for(t=0;t<fontpathpos;t++) {
609         driver->set_parameter(driver, "fontdir", fontpaths[t]);
610     }
611
612     char fullname[256];
613     if(password && *password) {
614         sprintf(fullname, "%s|%s", filename, password);
615         filename = fullname;
616     }
617
618     gfxdocument_t* pdf = driver->open(driver, filename);
619     if(!pdf) {
620         msg("<error> Couldn't open %s", filename);
621         exit(1);
622     }
623
624     struct mypage_t {
625         int x;
626         int y;
627         gfxpage_t*page;
628     } pages[4];
629
630     int pagenum = 0;
631     int frame = 1;
632     int pagenr;
633     
634     for(pagenr = 1; pagenr <= pdf->num_pages; pagenr++) 
635     {
636         if(is_in_range(pagenr, pagerange)) {
637             char mapping[80];
638             sprintf(mapping, "%d:%d", pagenr, frame);
639             pdf->set_parameter(pdf, "pagemap", mapping);
640             pagenum++;
641         }
642         if(pagenum == xnup*ynup || (pagenr == pdf->num_pages && pagenum>1)) {
643             pagenum = 0;
644             frame++;
645         }
646     }
647
648     pagenum = 0;
649
650     for(pagenr = 1; pagenr <= pdf->num_pages; pagenr++) 
651     {
652         if(is_in_range(pagenr, pagerange)) {
653             gfxpage_t* page = pages[pagenum].page = pdf->getpage(pdf, pagenr);
654             pages[pagenum].x = 0;
655             pages[pagenum].y = 0;
656             pages[pagenum].page = page;
657             pagenum++;
658         }
659         if(pagenum == xnup*ynup || (pagenr == pdf->num_pages && pagenum>1)) {
660
661             int t;
662             int xmax[xnup], ymax[xnup];
663             int x,y;
664             int width=0, height=0;
665
666             memset(xmax, 0, xnup*sizeof(int));
667             memset(ymax, 0, ynup*sizeof(int));
668
669             for(y=0;y<ynup;y++)
670             for(x=0;x<xnup;x++) {
671                 int t = y*xnup + x;
672
673                 if(pages[t].page->width > xmax[x])
674                     xmax[x] = (int)pages[t].page->width;
675                 if(pages[t].page->height > ymax[y])
676                     ymax[y] = (int)pages[t].page->height;
677             }
678             for(x=0;x<xnup;x++) {
679                 width += xmax[x];
680                 xmax[x] = width;
681             }
682             for(y=0;y<ynup;y++) {
683                 height += ymax[y];
684                 ymax[y] = height;
685             }
686             if(custom_clip) {
687                 out->startpage(out,clip_x2 - clip_x1, clip_y2 - clip_y1);
688             } else {
689                 out->startpage(out,width,height);
690             }
691             for(t=0;t<pagenum;t++) {
692                 int x = t%xnup;
693                 int y = t/xnup;
694                 int xpos = x>0?xmax[x-1]:0;
695                 int ypos = y>0?ymax[y-1]:0;
696                 msg("<verbose> Render (%d,%d) move:%d/%d\n",
697                         (int)(pages[t].page->width + xpos),
698                         (int)(pages[t].page->height + ypos), xpos, ypos);
699                 pages[t].page->rendersection(pages[t].page, out, custom_move? move_x : xpos, 
700                                                            custom_move? move_y : ypos,
701                                                            custom_clip? clip_x1 : 0 + xpos, 
702                                                            custom_clip? clip_y1 : 0 + ypos, 
703                                                            custom_clip? clip_x2 : pages[t].page->width + xpos, 
704                                                            custom_clip? clip_y2 : pages[t].page->height + ypos);
705             }
706             out->endpage(out);
707             for(t=0;t<pagenum;t++)  {
708                 pages[t].page->destroy(pages[t].page);
709             }
710             pagenum = 0;
711         }
712     }
713     
714     gfxresult_t*result = out->finish(out);
715
716     if(result->save(result, outputname) < 0) {
717         exit(1);
718     }
719
720     int width = (int)result->get(result, "width");
721     int height = (int)result->get(result, "height");
722     msg("<notice> SWF written");
723     
724     result->destroy(result);
725
726     pdf->destroy(pdf);
727     driver->destroy(driver);
728
729     const char*zip = "";
730     if(zlib) {
731         zip = "-z";
732     }
733     if(!preloader && viewer) {
734         systemf("swfcombine %s -X %d -Y %d \"%s\" viewport=\"%s\" -o \"%s\"",zip,width,height,
735                 viewer, outputname, outputname);
736         if(!system_quiet)
737             printf("\n");
738     }
739     if(preloader && !viewer) {
740         msg("<warning> --preloader option without --viewer option doesn't make very much sense.");
741         ret = systemf("swfcombine %s -Y %d -X %d %s/PreLoaderTemplate.swf loader=\"%s\" movie=\"%s\" -o \"%s\"",zip,width,height,
742                 SWFDIR, preloader, outputname, outputname);
743         if(!system_quiet)
744             printf("\n");
745     }
746     if(preloader && viewer) {
747 #ifdef HAVE_MKSTEMP
748         char tmpname[] = "__swf__XXXXXX";
749         mkstemp(tmpname);
750 #else 
751         char*tmpname = "__tmp__.swf";
752 #endif
753         systemf("swfcombine \"%s\" viewport=%s -o %s",
754                 viewer, outputname, tmpname);
755         systemf("swfcombine %s -X %d -Y %d -r %f %s/PreLoaderTemplate.swf loader=%s movie=%s -o \"%s\"",zip,width,height,
756                 getRate(preloader), SWFDIR, preloader, tmpname, outputname);
757         systemf("rm %s", tmpname);
758     }
759
760
761     return 0;
762 }
763