new parameter -s textonly
[swftools.git] / src / png2swf.c
1 /* png2swf.c
2
3    PNG to SWF converter tool
4
5    Part of the swftools package.
6
7    Copyright (c) 2002,2003 Matthias Kramm <kramm@quiss.org>
8  
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
22  
23 #include <stdio.h>
24 #include <math.h>
25 #include <fcntl.h>
26 #include <zlib.h>
27 #include "../lib/rfxswf.h"
28 #include "../lib/args.h"
29 #include "../lib/png.h"
30
31 #define MAX_INPUT_FILES 1024
32 #define VERBOSE(x) (global.verbose>=x)
33
34 struct {
35     float framerate;
36     int max_image_width;
37     int max_image_height;
38     int force_width;
39     int force_height;
40     int nfiles;
41     int verbose;
42     int do_cgi;
43     int version;
44     char *outfile;
45     int mkjpeg;
46     float scale;
47 } global;
48
49 struct {
50     char *filename;
51 } image[MAX_INPUT_FILES];
52
53 static int custom_move=0;
54 static int move_x=0;
55 static int move_y=0;
56 static int clip_x1=0,clip_y1=0,clip_x2=0,clip_y2=0;
57 static int custom_clip = 0;
58
59 TAG *MovieStart(SWF * swf, float framerate, int dx, int dy)
60 {
61     TAG *t;
62     RGBA rgb;
63
64     memset(swf, 0x00, sizeof(SWF));
65
66     swf->fileVersion = global.version;
67     swf->frameRate = (int)(256.0 * framerate);
68     if(custom_clip) {
69         swf->movieSize.xmin = clip_x1 * 20;
70         swf->movieSize.ymin = clip_y1 * 20;
71         swf->movieSize.xmax = clip_x2 * 20;
72         swf->movieSize.ymax = clip_y2 * 20;
73     } else {
74         swf->movieSize.xmax = dx * 20;
75         swf->movieSize.ymax = dy * 20;
76     }
77
78     t = swf->firstTag = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
79
80     rgb.r = rgb.g = rgb.b = rgb.a = 0x00;
81     //rgb.g = 0xff; //<--- handy for testing alpha conversion
82     swf_SetRGB(t, &rgb);
83
84     return t;
85 }
86
87 int MovieFinish(SWF * swf, TAG * t, char *sname)
88 {
89     int f, so = fileno(stdout);
90     t = swf_InsertTag(t, ST_END);
91
92     if ((!isatty(so)) && (!sname))
93         f = so;
94     else {
95         if (!sname)
96             sname = "output.swf";
97         f = open(sname,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
98     }
99
100     if(global.do_cgi) {
101         if FAILED(swf_WriteCGI(swf)) fprintf(stderr,"WriteCGI() failed.\n");
102     } else {
103         if (swf_WriteSWF(f, swf)<0) 
104             fprintf(stderr, "Unable to write output file: %s\n", sname);
105         if (f != so)
106             close(f);
107     }
108
109     swf_FreeTags(swf);
110     return 0;
111 }
112
113 int png_read_chunk(char (*head)[4], int*destlen, U8**destdata, FILE*fi)
114 {
115     unsigned int len;
116     if(destlen) *destlen=0;
117     if(destdata) *destdata=0;
118     if(!fread(&len, 4, 1, fi))
119         return 0;
120     if(!fread(head, 4, 1, fi))
121         return 0;
122     len = BE_32_TO_NATIVE(len);
123     if(destlen) *destlen = len;
124     if(destdata) {
125         if(len)
126             *destdata = malloc(len);
127         else 
128             *destdata = 0;
129         if(!fread(*destdata, len, 1, fi)) {
130             *destdata = 0;
131             if(destlen) *destlen=0;
132             return 0;
133         }
134         fseek(fi, 4, SEEK_CUR);
135
136     } else {
137         fseek(fi, len+4, SEEK_CUR);
138     }
139     return 1;
140 }
141
142 unsigned int png_get_dword(FILE*fi)
143 {
144     unsigned int a;
145     fread(&a,4,1,fi);
146     return BE_32_TO_NATIVE(a);
147 }
148
149 struct png_header
150 {
151     int width;
152     int height;
153     int bpp;
154     int mode;
155 };
156
157 int png_read_header(FILE*fi, struct png_header*header)
158 {
159     char id[4];
160     int len;
161     int ok=0;
162     U8 head[8] = {137,80,78,71,13,10,26,10};
163     U8 head2[8];
164     U8*data;
165     fread(head2,8,1,fi);
166     if(strncmp((char*)head,(char*)head2,4))
167         return 0;
168    
169     while(png_read_chunk(&id, &len, &data, fi))
170     {
171         if(VERBOSE(2))
172             printf("%c%c%c%c %d\n", id[0],id[1],id[2],id[3],len);
173         if(!strncasecmp(id, "IHDR", 4)) {
174             char a,b,c,f,i;
175             if(len < 8) exit(1);
176             header->width = BE_32_TO_NATIVE(*(U32*)&data[0]);
177             header->height = BE_32_TO_NATIVE(*(U32*)&data[4]);
178             a = data[8];      // should be 8
179             b = data[9];      // should be 3(indexed), 2(rgb), 0(grayscale) or 6(truecolor+alpha)
180
181             c = data[10];     // compression mode (0)
182             f = data[11];     // filter mode (0)
183             i = data[12];     // interlace mode (0)
184         
185             if(VERBOSE(2)) printf("image mode:%d\n", b);
186             if(VERBOSE(2)) printf("bpp: %d\n", a);
187             if(VERBOSE(2)) printf("compression: %d\n", c);
188             if(VERBOSE(2)) printf("filter: %d\n", f);
189             if(VERBOSE(2)) printf("interlace: %d\n", i);
190
191             if(b!=0 && b!=2 && b!=3 && b!=6) {
192                 fprintf(stderr, "Image mode %d not supported!\n", b);
193                 if(b == 4) {
194                     fprintf(stderr, "(This is a grayscale image with alpha channel-\n");
195                     fprintf(stderr, " try converting it into an RGB image with alpha channel)\n");
196                 }
197                 exit(1);
198             }
199             if(a!=8 && (b==2 || b==6)) {
200                 fprintf(stderr, "Bpp %d in mode %d not supported!\n", b, a);
201                 exit(1);
202             }
203             if(c!=0) {
204                 fprintf(stderr, "Compression mode %d not supported!\n", c);
205                 exit(1);
206             }
207             if(f!=0) {
208                 fprintf(stderr, "Filter mode %d not supported!\n", f);
209                 exit(1);
210             }
211             if(i!=0) {
212                 fprintf(stderr, "Interlace mode %d not supported!\n", i);
213                 exit(1);
214             }
215             if(VERBOSE(2))
216                 printf("%dx%d %d %d %d %d %d\n",header->width, header->height, a,b,c,f,i);
217             header->bpp = a;
218             header->mode = b;
219             ok = 1;
220         } 
221         
222         free(data);
223     }
224     return ok;
225 }
226
227 typedef unsigned char byte;
228 #define ABS(a) ((a)>0?(a):(-(a)))
229 byte inline PaethPredictor (byte a,byte b,byte c)
230 {
231         // a = left, b = above, c = upper left
232         int p = a + b - c;        // initial estimate
233         int pa = ABS(p - a);      // distances to a, b, c
234         int pb = ABS(p - b);
235         int pc = ABS(p - c);
236         // return nearest of a,b,c,
237         // breaking ties in order a,b,c.
238         if (pa <= pb && pa <= pc) 
239                 return a;
240         else if (pb <= pc) 
241                 return b;
242         else return c;
243 }
244
245 void applyfilter3(int mode, U8*src, U8*old, U8*dest, int width)
246 {
247     int x;
248     unsigned char lastr=0;
249     unsigned char lastg=0;
250     unsigned char lastb=0;
251     unsigned char upperlastr=0;
252     unsigned char upperlastg=0;
253     unsigned char upperlastb=0;
254
255     if(mode==0) {
256         for(x=0;x<width;x++) {
257             dest[0] = 255;
258             dest[1] = src[0];
259             dest[2] = src[1];
260             dest[3] = src[2];
261             dest+=4;
262             src+=3;
263         }
264     }
265     else if(mode==1) {
266         for(x=0;x<width;x++) {
267             dest[0] = 255;
268             dest[1] = src[0]+lastr;
269             dest[2] = src[1]+lastg;
270             dest[3] = src[2]+lastb;
271             lastr = dest[1];
272             lastg = dest[2];
273             lastb = dest[3];
274             dest+=4;
275             src+=3;
276         }
277     }
278     else if(mode==2) {
279         for(x=0;x<width;x++) {
280             dest[0] = 255;
281             dest[1] = src[0]+old[1];
282             dest[2] = src[1]+old[2];
283             dest[3] = src[2]+old[3];
284             dest+=4;
285             old+=4;
286             src+=3;
287         }
288     }
289     else if(mode==3) {
290         for(x=0;x<width;x++) {
291             dest[0] = 255;
292             dest[1] = src[0]+(old[1]+lastr)/2;
293             dest[2] = src[1]+(old[2]+lastg)/2;
294             dest[3] = src[2]+(old[3]+lastb)/2;
295             lastr = dest[1];
296             lastg = dest[2];
297             lastb = dest[3];
298             dest+=4;
299             old+=4;
300             src+=3;
301         }
302     }
303     else if(mode==4) {
304         for(x=0;x<width;x++) {
305             dest[0] = 255;
306             dest[1] = src[0]+PaethPredictor(lastr,old[1],upperlastr);
307             dest[2] = src[1]+PaethPredictor(lastg,old[2],upperlastg);
308             dest[3] = src[2]+PaethPredictor(lastb,old[3],upperlastb);
309             lastr = dest[1];
310             lastg = dest[2];
311             lastb = dest[3];
312             upperlastr = old[1];
313             upperlastg = old[2];
314             upperlastb = old[3];
315             dest+=4;
316             old+=4;
317             src+=3;
318         }
319     }    
320 }
321
322 void applyfilter4(int mode, U8*src, U8*old, U8*dest, int width)
323 {
324     int x;
325     unsigned char lastr=0;
326     unsigned char lastg=0;
327     unsigned char lastb=0;
328     unsigned char lasta=0; //TODO: 255?
329     unsigned char upperlastr=0;
330     unsigned char upperlastg=0;
331     unsigned char upperlastb=0;
332     unsigned char upperlasta=0; //TODO: 255?
333
334     if(mode==0) {
335         for(x=0;x<width;x++) {
336             dest[0] = src[3];
337             dest[1] = src[0];
338             dest[2] = src[1];
339             dest[3] = src[2];
340             dest+=4;
341             src+=4;
342         }
343     }
344     else if(mode==1) {
345         for(x=0;x<width;x++) {
346             dest[0] = src[3]+lasta;
347             dest[1] = src[0]+lastr;
348             dest[2] = src[1]+lastg;
349             dest[3] = src[2]+lastb;
350             lasta = dest[0];
351             lastr = dest[1];
352             lastg = dest[2];
353             lastb = dest[3];
354             dest+=4;
355             src+=4;
356         }
357     }
358     else if(mode==2) {
359         for(x=0;x<width;x++) {
360             dest[0] = src[3]+old[0];
361             dest[1] = src[0]+old[1];
362             dest[2] = src[1]+old[2];
363             dest[3] = src[2]+old[3];
364             dest+=4;
365             old+=4;
366             src+=4;
367         }
368     }
369     else if(mode==3) {
370         for(x=0;x<width;x++) {
371             dest[0] = src[3]+(old[0]+lasta)/2;
372             dest[1] = src[0]+(old[1]+lastr)/2;
373             dest[2] = src[1]+(old[2]+lastg)/2;
374             dest[3] = src[2]+(old[3]+lastb)/2;
375             lasta = dest[0];
376             lastr = dest[1];
377             lastg = dest[2];
378             lastb = dest[3];
379             dest+=4;
380             old+=4;
381             src+=4;
382         }
383     }
384     else if(mode==4) {
385         for(x=0;x<width;x++) {
386             dest[0] = src[3]+PaethPredictor(lasta,old[0],upperlasta);
387             dest[1] = src[0]+PaethPredictor(lastr,old[1],upperlastr);
388             dest[2] = src[1]+PaethPredictor(lastg,old[2],upperlastg);
389             dest[3] = src[2]+PaethPredictor(lastb,old[3],upperlastb);
390             lasta = dest[0];
391             lastr = dest[1];
392             lastg = dest[2];
393             lastb = dest[3];
394             upperlasta = old[0];
395             upperlastr = old[1];
396             upperlastg = old[2];
397             upperlastb = old[3];
398             dest+=4;
399             old+=4;
400             src+=4;
401         }
402     }    
403
404 }
405
406 void applyfilter1(int mode, U8*src, U8*old, U8*dest, int width)
407 {
408     int x;
409     unsigned char last=0;
410     unsigned char upperlast=0;
411
412     if(mode==0) {
413         for(x=0;x<width;x++) {
414             *dest = *src;
415             dest++;
416             src++;
417         }
418     }
419     else if(mode==1) {
420         for(x=0;x<width;x++) {
421             *dest = *src+last;
422             last = *dest;
423             dest++;
424             src++;
425         }
426     }
427     else if(mode==2) {
428         for(x=0;x<width;x++) {
429             *dest = *src+*old;
430             dest++;
431             old++;
432             src++;
433         }
434     }
435     else if(mode==3) {
436         for(x=0;x<width;x++) {
437             *dest = *src+(*old+last)/2;
438             last = *dest;
439             dest++;
440             old++;
441             src++;
442         }
443     }
444     else if(mode==4) {
445         for(x=0;x<width;x++) {
446             *dest = *src+PaethPredictor(last,*old,upperlast);
447             last = *dest;
448             upperlast = *old;
449             dest++;
450             old++;
451             src++;
452         }
453     }    
454
455 }
456
457 TAG *MovieAddFrame(SWF * swf, TAG * t, char *sname, int id)
458 {
459     SHAPE *s;
460     SRECT r;
461     MATRIX m;
462     int fs;
463
464     unsigned width=0, height=0;
465
466 #ifndef HAVE_JPEGLIB
467     if(global.mkjpeg) {
468         global.mkjpeg = 0;
469         msg("<warning> No jpeg support compiled in");
470     }
471 #endif
472     if(global.mkjpeg) {
473 #ifdef HAVE_JPEGLIB
474         RGBA*data = 0;
475         png_load(sname, &width, &height, (unsigned char**)&data);
476         if(!data) 
477             exit(1);
478         if(swf_ImageHasAlpha(data, width, height)) {
479             t = swf_InsertTag(t, ST_DEFINEBITSJPEG3);
480             swf_SetU16(t, id);
481             swf_SetJPEGBits3(t, width,height,data,global.mkjpeg);
482         } else {
483             t = swf_InsertTag(t, ST_DEFINEBITSJPEG2);
484             swf_SetU16(t, id);
485             swf_SetJPEGBits2(t, width,height,data,global.mkjpeg);
486         }
487 #endif
488     } else {
489         RGBA*data = 0;
490         png_load(sname, &width, &height, (unsigned char**)&data);
491         if(!data) 
492             exit(1);
493         t = swf_InsertTag(t, ST_DEFINEBITSLOSSLESS);
494         swf_SetU16(t, id);
495         swf_SetLosslessImage(t, data,width,height);
496     }
497
498     t = swf_InsertTag(t, ST_DEFINESHAPE3);
499
500     swf_ShapeNew(&s);
501     swf_GetMatrix(NULL, &m);
502     m.sx = (int)(20 * 0x10000);
503     m.sy = (int)(20 * 0x10000);
504     m.tx = 0;
505     m.ty = 0;
506     fs = swf_ShapeAddBitmapFillStyle(s, &m, id, 1);
507
508     swf_SetU16(t, id + 1);      // id
509
510     r.xmin = r.ymin = 0;
511     r.xmax = width * 20;
512     r.ymax = height * 20;
513     swf_SetRect(t, &r);
514
515     swf_SetShapeHeader(t, s);
516
517     swf_ShapeSetAll(t, s, 0, 0, 0, fs, 0);
518     swf_ShapeSetLine(t, s, r.xmax, 0);
519     swf_ShapeSetLine(t, s, 0, r.ymax);
520     swf_ShapeSetLine(t, s, -r.xmax, 0);
521     swf_ShapeSetLine(t, s, 0, -r.ymax);
522
523     swf_ShapeSetEnd(t);
524
525     t = swf_InsertTag(t, ST_REMOVEOBJECT2);
526     swf_SetU16(t, 50);          // depth
527
528     t = swf_InsertTag(t, ST_PLACEOBJECT2);
529
530     swf_GetMatrix(NULL, &m);
531     m.sx = (int)(0x10000 * global.scale);
532     m.sy = (int)(0x10000 * global.scale);
533
534     if(custom_move) {
535         m.tx = move_x*20;
536         m.ty = move_y*20;
537     } else {
538         m.tx = (swf->movieSize.xmax - (int) (width * global.scale * 20)) / 2;
539         m.ty = (swf->movieSize.ymax - (int) (height * global.scale * 20)) / 2;
540     }
541     swf_ObjectPlace(t, id + 1, 50, &m, NULL, NULL);
542
543     t = swf_InsertTag(t, ST_SHOWFRAME);
544
545     return t;
546 }
547
548
549 int CheckInputFile(char *fname, char **realname)
550 {
551     FILE *fi;
552     char *s = malloc(strlen(fname) + 5);
553     struct png_header head;
554
555     if (!s)
556         exit(2);
557     (*realname) = s;
558     strcpy(s, fname);
559
560     // Check whether file exists (with typical extensions)
561
562     if ((fi = fopen(s, "rb")) == NULL) {
563         sprintf(s, "%s.png", fname);
564         if ((fi = fopen(s, "rb")) == NULL) {
565             sprintf(s, "%s.PNG", fname);
566             if ((fi = fopen(s, "rb")) == NULL) {
567                 sprintf(s, "%s.Png", fname);
568                 if ((fi = fopen(s, "rb")) == NULL) {
569                     fprintf(stderr, "Couldn't open %s!\n", fname);
570                     return -1;
571                 }
572             }
573         }
574     }
575
576     if(!png_read_header(fi, &head)) {
577         fprintf(stderr, "%s is not a PNG file!\n", fname);
578         return -1;
579     }
580
581     if (global.max_image_width < head.width)
582         global.max_image_width = head.width;
583     if (global.max_image_height < head.height)
584         global.max_image_height = head.height;
585
586     fclose(fi);
587
588     return 0;
589 }
590
591 int args_callback_option(char *arg, char *val)
592 {
593     int res = 0;
594     if (arg[1])
595         res = -1;
596     else
597         switch (arg[0]) {
598         case 'r':
599             if (val)
600                 global.framerate = atof(val);
601             /* removed framerate>0 restriction in order to make
602                Flash Communication Server compatible SWFs */
603             if ((global.framerate < 0) ||(global.framerate >= 256.0)) {
604                 if (VERBOSE(1))
605                     fprintf(stderr,
606                             "Error: You must specify a valid framerate between 1/256 and 255.\n");
607                 exit(1);
608             }
609             res = 1;
610             break;
611
612         case 'o':
613             if (val)
614                 global.outfile = val;
615             res = 1;
616             break;
617
618         case 's':
619             global.scale = atof(val)/100;
620             res = 1;
621             break;
622
623         case 'z':
624             if(global.version<6)
625                 global.version = 6;
626             res = 0;
627             break;
628
629         case 'j':
630             global.mkjpeg = atoi(val);
631             res = 1;
632             break;
633
634         case 'T':
635             global.version = atoi(val);
636             res = 1;
637             break;
638
639         case 'C':
640             global.do_cgi = 1;
641             break;
642
643         case 'v':
644             global.verbose++;
645             res = 0;
646             break;
647
648         case 'q':
649             global.verbose--;
650             if(global.verbose<0)
651                 global.verbose = 0;
652             res = 0;
653             break;
654
655         case 'X':
656             if (val)
657                 global.force_width = atoi(val);
658             res = 1;
659             break;
660
661         case 'Y':
662             if (val)
663                 global.force_height = atoi(val);
664             res = 1;
665             break;
666         
667         case 'V':
668             printf("png2swf - part of %s %s\n", PACKAGE, VERSION);
669             exit(0);
670    
671         case 'c': {
672             char*s = strdup(val);
673             char*x1 = strtok(s, ":");
674             char*y1 = strtok(0, ":");
675             char*x2 = strtok(0, ":");
676             char*y2 = strtok(0, ":");
677             if(!(x1 && y1 && x2 && y2)) {
678                 fprintf(stderr, "-m option requires four arguments, <x1>:<y1>:<x2>:<y2>\n");
679                 exit(1);
680             }
681             custom_clip = 1;
682             clip_x1 = atoi(x1);
683             clip_y1 = atoi(y1);
684             clip_x2 = atoi(x2);
685             clip_y2 = atoi(y2);
686             free(s);
687
688             res = 1;
689             break;
690         }
691
692         case 'm': {
693             char*s = strdup(val);
694             char*c = strchr(s, ':');
695             if(!c) {
696                 fprintf(stderr, "-m option requires two arguments, <x>:<y>\n");
697                 exit(1);
698             }
699             *c = 0;
700             custom_move = 1;
701             move_x = atoi(val);
702             move_y = atoi(c+1);
703             free(s);
704
705             res = 1;
706             break;
707         }
708
709         default:
710             res = -1;
711             break;
712         }
713
714     if (res < 0) {
715         if (VERBOSE(1))
716             fprintf(stderr, "Unknown option: -%s\n", arg);
717         exit(1);
718         return 0;
719     }
720     return res;
721 }
722
723 static struct options_t options[] = {
724 {"r", "rate"},
725 {"o", "output"},
726 {"j", "jpeg"},
727 {"z", "zlib"},
728 {"T", "flashversion"},
729 {"X", "pixel"},
730 {"Y", "pixel"},
731 {"v", "verbose"},
732 {"q", "quiet"},
733 {"C", "cgi"},
734 {"V", "version"},
735 {"s", "scale"},
736 {0,0}
737 };
738
739 int args_callback_longoption(char *name, char *val)
740 {
741     return args_long2shortoption(options, name, val);
742 }
743
744 int args_callback_command(char *arg, char *next)        // actually used as filename
745 {
746     char *s;
747     if (CheckInputFile(arg, &s) < 0) {
748         if (VERBOSE(1))
749             fprintf(stderr, "Error opening input file: %s\n", arg);
750         free(s);
751     } else {
752         image[global.nfiles].filename = s;
753         global.nfiles++;
754         if (global.nfiles >= MAX_INPUT_FILES) {
755             if (VERBOSE(1))
756                 fprintf(stderr, "Error: Too many input files.\n");
757             exit(1);
758         }
759     }
760     return 0;
761 }
762
763 void args_callback_usage(char *name)
764 {
765     printf("\n");
766     printf("Usage: %s [-X width] [-Y height] [-o file.swf] [-r rate] file1.png [file2.png...]\n", name);
767     printf("\n");
768     printf("-r , --rate <framerate>        Set movie framerate (frames per second)\n");
769     printf("-o , --output <filename>       Set name for SWF output file.\n");
770     printf("-j , --jpeg <quality>          Generate a lossy jpeg bitmap inside the SWF, with a given quality (1-100)\n");
771     printf("-z , --zlib <zlib>             Enable Flash 6 (MX) Zlib Compression\n");
772     printf("-T , --flashversion            Set the flash version to generate\n");
773     printf("-X , --pixel <width>           Force movie width to <width> (default: autodetect)\n");
774     printf("-Y , --pixel <height>          Force movie height to <height> (default: autodetect)\n");
775     printf("-v , --verbose <level>         Set verbose level (0=quiet, 1=default, 2=debug)\n");
776     printf("-q , --quiet                   Omit normal log messages, only log errors\n");
777     printf("-C , --cgi                     For use as CGI- prepend http header, write to stdout\n");
778     printf("-V , --version                 Print version information and exit\n");
779     printf("-s , --scale <percent>         Scale image to <percent>%% size.\n");
780     printf("\n");
781 }
782
783 int main(int argc, char **argv)
784 {
785     SWF swf;
786     TAG *t;
787
788     memset(&global, 0x00, sizeof(global));
789
790     global.framerate = 1.0;
791     global.verbose = 1;
792     global.version = 8;
793     global.scale = 1.0;
794
795     processargs(argc, argv);
796     
797     if(global.nfiles<=0) {
798         fprintf(stderr, "No png files found in arguments\n");
799         return 1;
800     }
801
802     if (VERBOSE(2))
803         fprintf(stderr, "Processing %i file(s)...\n", global.nfiles);
804
805     t = MovieStart(&swf, global.framerate,
806                    global.force_width ? global.force_width : (int)(global.max_image_width*global.scale),
807                    global.force_height ? global.force_height : (int)(global.max_image_height*global.scale));
808
809     {
810         int i;
811         for (i = 0; i < global.nfiles; i++) {
812             if (VERBOSE(3))
813                 fprintf(stderr, "[%03i] %s\n", i,
814                         image[i].filename);
815             t = MovieAddFrame(&swf, t, image[i].filename, (i * 2) + 1);
816             free(image[i].filename);
817         }
818     }
819
820     MovieFinish(&swf, t, global.outfile);
821
822     return 0;
823 }