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