3 JPEG to SWF converter tool
5 Part of the swftools package.
7 Copyright (c) 2001 Rainer Böhme <rfxswf@reflex-studio.de>
8 Copyright (c) 2002,2003 Matthias Kramm <kramm@quiss.org>
10 This file is distributed under the GPL, see file COPYING for details
18 #include "../lib/rfxswf.h"
19 #include "../lib/args.h" // not really a header ;-)
21 #define MAX_INPUT_FILES 1024
22 #define VERBOSE(x) (global.verbose>=x)
37 typedef struct _image {
43 image_t image[MAX_INPUT_FILES];
47 TAG *MovieStart(SWF * swf, int framerate, int dx, int dy)
52 memset(swf, 0x00, sizeof(SWF));
55 swf->frameRate = (25600 / framerate);
56 swf->movieSize.xmax = dx * 20;
57 swf->movieSize.ymax = dy * 20;
59 t = swf->firstTag = swf_InsertTag(NULL, ST_SETBACKGROUNDCOLOR);
61 rgb.r = rgb.g = rgb.b = rgb.a = 0x00;
65 t = swf_InsertTag(t, ST_DEFINEVIDEOSTREAM);
66 swf_SetU16(t, 0xf00d);
67 swf_SetVideoStreamDefine(t, &stream, 65535, dx, dy);
73 int MovieFinish(SWF * swf, TAG * t, char *sname)
75 int handle, so = fileno(stdout);
76 t = swf_InsertTag(t, ST_END);
78 if ((!isatty(so)) && (!sname))
83 handle = open(sname, O_BINARY | O_RDWR | O_CREAT | O_TRUNC, 0666);
85 if (swf_WriteSWF(handle, swf)<0)
86 fprintf(stderr, "Unable to write output file: %s\n", sname);
94 int getJPEG(char*filename, int* width, int* height, RGBA**pic2)
96 struct jpeg_decompress_struct cinfo;
97 struct jpeg_error_mgr jerr;
98 struct jpeg_source_mgr mgr;
104 if ((f=fopen(filename,"rb"))==NULL) {
105 fprintf(stderr, "rfxswf: file open error\n");
109 cinfo.err = jpeg_std_error(&jerr);
110 jpeg_create_decompress(&cinfo);
111 jpeg_stdio_src(&cinfo, f);
112 jpeg_read_header(&cinfo, TRUE);
113 jpeg_start_decompress(&cinfo);
115 pic = malloc(cinfo.output_width*cinfo.output_height*sizeof(RGBA));
116 buf = malloc(cinfo.output_width*4);
117 memset(pic, 255, cinfo.output_width*cinfo.output_height*sizeof(RGBA));
120 *width = cinfo.output_width;
121 *height = cinfo.output_height;
123 for (y=0;y<cinfo.output_height;y++) {
125 jpeg_read_scanlines(&cinfo,&buf,1);
127 if(cinfo.out_color_space == JCS_GRAYSCALE) {
128 for(x=0;x<cinfo.output_width;x++) {
129 js[x].r = js[x].g = js[x].b = buf[x];
131 } else if(cinfo.out_color_space == JCS_RGB) {
132 for (x=0;x<cinfo.output_width;x++)
134 js[x].r = buf[x*3+0];
135 js[x].g = buf[x*3+1];
136 js[x].b = buf[x*3+2];
138 } else if(cinfo.out_color_space == JCS_YCCK) {
140 fprintf(stderr, "Error: Can't convert YCCK to RGB.\n");
142 } else if(cinfo.out_color_space == JCS_YCbCr) {
143 for(x=0;x<cinfo.output_width;x++) {
147 js[x].r = y + ((360*(v-128))>>8);
148 js[x].g = y - ((88*(u-128)+183*(v-128))>>8);
149 js[x].b = y + ((455 * (u-128))>>8);
152 else if(cinfo.out_color_space == JCS_CMYK)
154 for(x=0;x<cinfo.output_width;x++) {
155 int white = 255 - buf[x*4+3];
156 js[x].r = white - ((buf[x*4]*white)>>8);
157 js[x].g = white - ((buf[x*4+1]*white)>>8);
158 js[x].b = white - ((buf[x*4+2]*white)>>8);
161 js += cinfo.output_width;
164 jpeg_finish_decompress(&cinfo);
165 jpeg_destroy_decompress(&cinfo);
174 TAG *MovieAddFrame(SWF * swf, TAG * t, char *sname, int quality,
175 int id, int width, int height)
188 getJPEG(sname, &sizex, &sizey, &pic2);
189 if(sizex != stream.owidth || sizey != stream.oheight) {
190 fprintf(stderr, "All images must have the same dimensions if using -m!");
194 t = swf_InsertTag(t, ST_VIDEOFRAME);
195 swf_SetU16(t, 0xf00d);
196 quant = 1+(30-(30*quality)/100);
198 swf_SetVideoStreamIFrame(t, &stream, pic2, quant);
200 swf_SetVideoStreamPFrame(t, &stream, pic2, quant);
203 t = swf_InsertTag(t, ST_PLACEOBJECT2);
204 swf_GetPlaceObject(0, &obj);
213 swf_SetPlaceObject(t,&obj);
215 t = swf_InsertTag(t, ST_SHOWFRAME);
217 t = swf_InsertTag(t, ST_DEFINEBITSJPEG2);
218 swf_SetU16(t, id); // id
219 swf_SetJPEGBits(t,sname,quality);
221 t = swf_InsertTag(t, ST_DEFINESHAPE);
223 swf_GetMatrix(NULL, &m);
226 fs = swf_ShapeAddBitmapFillStyle(s, &m, id, 0);
227 swf_SetU16(t, id + 1); // id
230 r.ymax = height * 20;
232 swf_SetShapeHeader(t, s);
233 swf_ShapeSetAll(t, s, 0, 0, 0, fs, 0);
234 swf_ShapeSetLine(t, s, r.xmax, 0);
235 swf_ShapeSetLine(t, s, 0, r.ymax);
236 swf_ShapeSetLine(t, s, -r.xmax, 0);
237 swf_ShapeSetLine(t, s, 0, -r.ymax);
240 t = swf_InsertTag(t, ST_REMOVEOBJECT2);
241 swf_SetU16(t, 1); // depth
243 t = swf_InsertTag(t, ST_PLACEOBJECT2);
244 swf_GetMatrix(NULL, &m);
245 m.tx = (swf->movieSize.xmax - (int) width * 20) / 2;
246 m.ty = (swf->movieSize.ymax - (int) height * 20) / 2;
247 swf_ObjectPlace(t, id + 1, 1, &m, NULL, NULL);
249 t = swf_InsertTag(t, ST_SHOWFRAME);
256 int CheckInputFile(image_t* i, char *fname, char **realname)
258 struct jpeg_decompress_struct cinfo;
259 struct jpeg_error_mgr jerr;
261 char *s = malloc(strlen(fname) + 5);
269 // Check whether file exists (with typical extensions)
271 if ((f = fopen(s, "rb")) == NULL) {
272 sprintf(s, "%s.jpg", fname);
273 if ((f = fopen(s, "rb")) == NULL) {
274 sprintf(s, "%s.jpeg", fname);
275 if ((f = fopen(s, "rb")) == NULL) {
276 sprintf(s, "%s.JPG", fname);
277 if ((f = fopen(s, "rb")) == NULL) {
278 sprintf(s, "%s.JPEG", fname);
279 if ((f = fopen(s, "rb")) == NULL)
286 cinfo.err = jpeg_std_error(&jerr);
287 jpeg_create_decompress(&cinfo);
288 jpeg_stdio_src(&cinfo, f);
289 jpeg_read_header(&cinfo, TRUE);
291 width = cinfo.image_width;
292 height = cinfo.image_height;
297 // Get image dimensions
299 if (global.max_image_width < width)
300 global.max_image_width = width;
301 if (global.max_image_height < height)
302 global.max_image_height = height;
304 jpeg_destroy_decompress(&cinfo);
310 int args_callback_option(char *arg, char *val)
319 global.quality = atoi(val);
320 if ((global.quality < 1) ||(global.quality > 100)) {
323 "Error: You must specify a valid quality between 1 and 100.\n");
331 global.framerate = atoi(val);
332 if ((global.framerate < 1) ||(global.framerate > 5000)) {
335 "Error: You must specify a valid framerate between 1 and 10000.\n");
343 global.outfile = val;
349 global.verbose = atoi(val);
355 global.force_width = atoi(val);
365 global.force_height = atoi(val);
370 printf("jpeg2swf - part of %s %s\n", PACKAGE, VERSION);
380 fprintf(stderr, "Unknown option: -%s\n", arg);
387 struct options_t options[] = { {"q", "quality"},
397 int args_callback_longoption(char *name, char *val)
399 return args_long2shortoption(options, name, val);
402 int args_callback_command(char *arg, char *next) // actually used as filename
405 image_t* i = &image[global.nfiles];
406 if (CheckInputFile(i, arg, &s) < 0) {
408 fprintf(stderr, "Unable to open input file: %s\n", arg);
412 i->quality = global.quality;
414 if (global.nfiles >= MAX_INPUT_FILES) {
416 fprintf(stderr, "Error: Too many input files.\n");
423 void args_callback_usage(char *name)
426 ("Usage: %s [-options [value]] imagefiles[.jpg]|[.jpeg] [...]\n",
429 ("-o outputfile --output explicitly specify output file. (otherwise, output.swf will be used)\n");
431 ("-m --mx Use Flash MX H.263 compression (use for correlated images)\n");
433 ("-q quality --quality Set compression quality (1-100, 1=worst, 100=best)\n");
435 ("-r framerate --rate Set movie framerate (100/sec)\n");
437 ("-o outputfile --output Set name for SWF output file\n");
439 ("-X pixel --width Force movie width to pixel (default: autodetect)\n");
441 ("-Y pixel --height Force movie height to pixel (default: autodetect)\n");
443 ("-v level --verbose Set verbose level (0=quiet, 1=default, 2=debug)\n");
445 ("-V --version Print version information and exit\n");
447 ("The following options can be set independently for each image: -q -s\n");
451 int main(int argc, char **argv)
456 memset(&global, 0x00, sizeof(global));
459 global.framerate = 100;
462 processargs(argc, argv);
465 fprintf(stderr, "Processing %i file(s)...\n", global.nfiles);
467 t = MovieStart(&swf, global.framerate,
468 global.force_width ? global.force_width : global.
470 global.force_height ? global.force_height : global.
475 for (i = 0; i < global.nfiles; i++) {
477 fprintf(stderr, "[%03i] %s (%i%%, 1/%i)\n", i,
478 image[i].filename, image[i].quality);
479 t = MovieAddFrame(&swf, t, image[i].filename, image[i].quality,
481 image[i].width, image[i].height);
482 free(image[i].filename);
486 MovieFinish(&swf, t, global.outfile);