implemented --framerate.
[swftools.git] / src / jpeg2swf.c
index cdcde70..a9a413c 100644 (file)
-/* jpeg2swf.c\r
-\r
-   JPEG to SWF converter tool\r
-\r
-   Part of the swftools package.\r
-\r
-   Copyright (c) 2001 Rainer Böhme <rfxswf@reflex-studio.de>\r
\r
-   This file is distributed under the GPL, see file COPYING for details \r
-\r
-*/\r
-\r
-#include <stdio.h>\r
-#include <math.h>\r
-#include <fcntl.h>\r
-#include <jpeglib.h>\r
-#include "../lib/rfxswf.h"\r
-#include "../lib/args.h" // not really a header ;-)\r
-\r
-#define MAX_INPUT_FILES 1024\r
-#define VERBOSE(x) (global.verbose>=x)\r
-\r
-struct\r
-{ int quality;\r
-  int framerate;\r
-  int max_image_width;\r
-  int max_image_height;\r
-  int force_width;\r
-  int force_height;\r
-  int nfiles;\r
-  int verbose;\r
-  char * files[MAX_INPUT_FILES];\r
-  char * outfile;\r
-} global;\r
-\r
-TAG * MovieStart(SWF * swf,int framerate,int dx,int dy)\r
-{ TAG * t;\r
-  RGBA rgb;\r
-\r
-  memset(swf,0x00,sizeof(SWF));\r
-\r
-  swf->FileVersion       = 4;\r
-  swf->FrameRate         = (25600/framerate);\r
-  swf->MovieSize.xmax    = dx*20;\r
-  swf->MovieSize.ymax    = dy*20;\r
-\r
-  t = swf->FirstTag = InsertTag(NULL,ST_SETBACKGROUNDCOLOR);\r
-\r
-  rgb.r = rgb.g = rgb.b = rgb.a  = 0x00;\r
-  SetRGB(t,&rgb);\r
-\r
-  return t;\r
-}\r
-\r
-int MovieFinish(SWF * swf,TAG * t,char * sname)\r
-{  int handle, so = fileno(stdout);\r
-   t = InsertTag(t,ST_END);\r
-\r
-   if ((!isatty(so))&&(!sname)) handle = so;\r
-   else\r
-   { if (!sname) sname = "out.swf";\r
-     handle = open(sname,O_RDWR|O_CREAT|O_TRUNC,0666);\r
-   }\r
-   if FAILED(WriteSWF(handle,swf)) if (VERBOSE(1)) fprintf(stderr,"Unable to write output file: %s\n",sname);\r
-   if (handle!=so) close(handle);\r
-   \r
-   FreeTags(swf);\r
-   return 0;\r
-}\r
-\r
-TAG * MovieAddFrame(SWF * swf,TAG * t,char * sname,int quality,int id)\r
-{ SHAPE * s;\r
-  SRECT r;\r
-  MATRIX m;\r
-  int fs;\r
-  \r
-  struct jpeg_decompress_struct cinfo;\r
-  struct jpeg_error_mgr jerr;\r
-  LPJPEGBITS out;\r
-  FILE * f;\r
-  U8 * scanline;\r
-\r
-  if ((f=fopen(sname,"rb"))==NULL)\r
-  { if (VERBOSE(1)) fprintf(stderr,"Read access failed: %s\n",sname);\r
-    return t;\r
-  }\r
-  \r
-  cinfo.err = jpeg_std_error(&jerr);\r
-  jpeg_create_decompress(&cinfo); \r
-  jpeg_stdio_src(&cinfo,f);\r
-  jpeg_read_header(&cinfo, TRUE);\r
-  jpeg_start_decompress(&cinfo);\r
-\r
-  t = InsertTag(t,ST_DEFINEBITSJPEG2);\r
-\r
-        SetU16(t,id);  // id\r
-  \r
-        out = SetJPEGBitsStart(t,cinfo.output_width,cinfo.output_height,quality);\r
-        scanline = (U8*)malloc(4*cinfo.output_width);\r
-  \r
-        if (scanline)\r
-        { int y;\r
-          U8 * js = scanline;\r
-          for (y=0;y<cinfo.output_height;y++)\r
-          { jpeg_read_scanlines(&cinfo,&js,1);\r
-            SetJPEGBitsLines(out,(U8**)&js,1);\r
-          }\r
-          free(scanline);\r
-        }\r
-        \r
-        SetJPEGBitsFinish(out);\r
-    \r
-  t = InsertTag(t,ST_DEFINESHAPE);\r
-\r
-        NewShape(&s);\r
-        GetMatrix(NULL,&m);\r
-        m.sx = 20*0x10000;\r
-        m.sy = 20*0x10000;\r
-        fs = ShapeAddBitmapFillStyle(s,&m,id,0);\r
-        \r
-        SetU16(t,id+1); // id\r
-\r
-\r
-        r.xmin = r.ymin = 0;\r
-        r.xmax = cinfo.output_width*20;\r
-        r.ymax = cinfo.output_height*20;\r
-        SetRect(t,&r);\r
-        \r
-        SetShapeHeader(t,s);\r
-\r
-        ShapeSetAll(t,s,0,0,0,fs,0);\r
-        ShapeSetLine(t,s,r.xmax,0);\r
-        ShapeSetLine(t,s,0,r.ymax);\r
-        ShapeSetLine(t,s,-r.xmax,0);\r
-        ShapeSetLine(t,s,0,-r.ymax);\r
-        \r
-        ShapeSetEnd(t);\r
-        \r
-  t = InsertTag(t,ST_REMOVEOBJECT2);\r
-        SetU16(t,1); // depth\r
-\r
-  t = InsertTag(t,ST_PLACEOBJECT2);\r
-\r
-        GetMatrix(NULL,&m);\r
-        m.tx = (swf->MovieSize.xmax-(int)cinfo.output_width*20)/2;\r
-        m.ty = (swf->MovieSize.ymax-(int)cinfo.output_height*20)/2;\r
-        ObjectPlace(t,id+1,1,&m,NULL,NULL);\r
-\r
-  t = InsertTag(t,ST_SHOWFRAME);\r
-\r
-  jpeg_finish_decompress(&cinfo);\r
-  fclose(f);\r
-\r
-  return t;\r
-}\r
-\r
-int CheckInputFile(char * fname,char ** realname)\r
-{ struct jpeg_decompress_struct cinfo;\r
-  struct jpeg_error_mgr jerr;\r
-  FILE * f;\r
-  char * s = malloc(strlen(fname)+5);\r
-  \r
-  if (!s) exit(2);\r
-  (*realname) = s;\r
-  strcpy(s,fname);\r
-\r
-  // Check whether file exists (with typical extensions)\r
-\r
-  if ((f=fopen(s,"rb"))==NULL)\r
-  { sprintf(s,"%s.jpg",fname);\r
-    if ((f=fopen(s,"rb"))==NULL)\r
-    { sprintf(s,"%s.jpeg",fname);\r
-      if ((f=fopen(s,"rb"))==NULL)\r
-      { sprintf(s,"%s.JPG",fname);\r
-        if ((f=fopen(s,"rb"))==NULL)\r
-        { sprintf(s,"%s.JPEG",fname);\r
-          if ((f=fopen(s,"rb"))==NULL)\r
-            return 0;\r
-        }\r
-      }\r
-    }\r
-  }\r
-  \r
-  cinfo.err = jpeg_std_error(&jerr);\r
-  jpeg_create_decompress(&cinfo); \r
-  jpeg_stdio_src(&cinfo,f);\r
-  jpeg_read_header(&cinfo, TRUE);\r
-\r
-  // Get image dimensions\r
-\r
-  if (global.max_image_width<cinfo.image_width) global.max_image_width = cinfo.image_width;\r
-  if (global.max_image_height<cinfo.image_height) global.max_image_height = cinfo.image_height;\r
-  \r
-  jpeg_destroy_decompress(&cinfo);\r
-  fclose(f);\r
-\r
-  return 0;\r
-}\r
-\r
-int args_callback_option(char*arg,char*val)\r
-{ int res = 0;\r
-  if (arg[1]) res = -1;\r
-  else switch (arg[0])\r
-  { case 'q':\r
-      if (val) global.quality = atoi(val);\r
-      if ((global.quality<1)||(global.quality>100))\r
-      { if (VERBOSE(1)) fprintf(stderr,"Error: You must specify a valid quality between 1 and 100.\n");\r
-        exit(1);\r
-      }\r
-      res = 1;\r
-      break;\r
-\r
-    case 'r':\r
-      if (val) global.framerate = atoi(val);\r
-      if ((global.framerate<1)||(global.framerate>5000))\r
-      { if (VERBOSE(1)) fprintf(stderr,"Error: You must specify a valid framerate between 1 and 10000.\n");\r
-        exit(1);\r
-      }\r
-      res = 1;\r
-      break;\r
-\r
-    case 'o':\r
-      if (val) global.outfile = val; res = 1; break;\r
-\r
-    case 'v':\r
-      if (val) global.verbose = atoi(val); res = 1; break;\r
-\r
-    case 'X':\r
-      if (val) global.force_width = atoi(val); res = 1; break;\r
-\r
-    case 'Y':\r
-      if (val) global.force_height = atoi(val); res = 1; break;\r
-\r
-    case 'V':\r
-      printf("jpeg2swf - part of %s %s\n", PACKAGE, VERSION);exit(0);\r
-      \r
-    default:\r
-      res = -1;\r
-      break;\r
-  }\r
-  \r
-  if (res<0)\r
-  { if (VERBOSE(1)) fprintf(stderr,"Unknown option: -v%s\n",arg);\r
-    return 0;\r
-  }\r
-  return res;\r
-}\r
-\r
-struct options_t\r
-{ char*shortoption;\r
-  char*longoption;\r
-} options[] =\r
-{{"q","quality"},\r
- {"o","output"},\r
- {"r","rate"},\r
- {"v","verbose"},\r
- {"X","width"},\r
- {"Y","height"},\r
- {"v","verbose"},\r
- {"V","version"}\r
-};\r
-\r
-int args_callback_longoption(char*name,char*val) {\r
-    int t;\r
-    for(t=0;t<sizeof(options)/sizeof(struct options_t);t++)\r
-        if(!strcmp(options[t].longoption, name))\r
-            return args_callback_option(options[t].shortoption,val);\r
-    if (VERBOSE(1)) fprintf(stderr, "Unknown option: --%s\n", name);\r
-    exit(1);\r
-}\r
-\r
-int args_callback_command(char*arg,char*next)  // actually used as filename\r
-{ char * s;\r
-  if (CheckInputFile(arg,&s)<0)\r
-  { if (VERBOSE(1)) fprintf(stderr, "Unable to open input file: %s\n",arg);\r
-    free(s);\r
-  }\r
-  else\r
-  { global.files[global.nfiles] = s;\r
-    global.nfiles++;\r
-    if (global.nfiles>=MAX_INPUT_FILES)\r
-    { if (VERBOSE(1)) fprintf(stderr, "Error: Too many input files.\n");\r
-      exit(1);\r
-    }\r
-  }\r
-  return 0;\r
-}\r
-\r
-void args_callback_usage(char*name)\r
-{ fprintf(stderr,"Usage: %s imagefiles[.jpg]|[.jpeg] [...] [-options [value]]\n",name);\r
-  fprintf(stderr,"-q quality            (quality) Set JPEG compression quality (1-100)\n");\r
-  fprintf(stderr,"-r framerate          (rate) Set movie framerate (100/sec)\n");\r
-  fprintf(stderr,"-o outputfile         (output) Set name for SWF output file\n");\r
-  fprintf(stderr,"-v level              (verbose) Set verbose level (0=quiet, 1=default, 2=debug)\n");\r
-  fprintf(stderr,"-X pixel              (width) Force movie width to scale (default: autodetect)\n");\r
-  fprintf(stderr,"-Y pixel              (height) Force movie height to scale (default: autodetect)\n");\r
-  fprintf(stderr,"-V                    (version) Print version information and exit\n");\r
-}\r
-\r
-\r
-int main(int argc, char ** argv)\r
-{ SWF swf;\r
-  TAG * t;\r
-\r
-  memset(&global,0x00,sizeof(global));\r
-    \r
-  global.quality                = 60;\r
-  global.framerate              = 100;\r
-  global.verbose                = 1;\r
-  \r
-  processargs(argc, argv);\r
-\r
-  if (VERBOSE(2)) fprintf(stderr,"Processing %i file(s)...\n",global.nfiles);\r
-\r
-  t = MovieStart(&swf,global.framerate,\r
-                      global.force_width?global.force_width:global.max_image_width,\r
-                      global.force_height?global.force_height:global.max_image_height);\r
-\r
-  { int i;\r
-    for (i=0;i<global.nfiles;i++)\r
-    { if (VERBOSE(3)) fprintf(stderr,"[%03i] %s\n",i,global.files[i]);\r
-      t = MovieAddFrame(&swf,t,global.files[i],global.quality,(i*2)+1);\r
-      free(global.files[i]);\r
-    }\r
-  }\r
-\r
-  MovieFinish(&swf,t,global.outfile);\r
-\r
-  return 0;\r
-}\r
-\r
-\r
-// Old main routine\r
-\r
-/*\r
-int ConvertJPEG2SWF(char * sname,char * dname,int quality)\r
-{ RGBA rgb;\r
-  SWF swf;\r
-  TAG * t;\r
-  \r
-  SHAPE * s;\r
-  SRECT r;\r
-  MATRIX m;\r
-  int fs;\r
-  \r
-  struct jpeg_decompress_struct cinfo;\r
-  struct jpeg_error_mgr jerr;\r
-  LPJPEGBITS out;\r
-  FILE * f;\r
-  U8 * scanline;\r
-\r
-  int handle;\r
-\r
-  cinfo.err = jpeg_std_error(&jerr);\r
-  jpeg_create_decompress(&cinfo); \r
-\r
-  if ((f=fopen(sname,"rb"))==NULL)\r
-  { fprintf(stderr,"Read access failed: %s\n",sname);\r
-    return -1;\r
-  }\r
-  \r
-  jpeg_stdio_src(&cinfo,f);\r
-  jpeg_read_header(&cinfo, TRUE);\r
-  jpeg_start_decompress(&cinfo);\r
-  \r
-  memset(&swf,0x00,sizeof(SWF));\r
-\r
-  swf.FileVersion       = 4;\r
-  swf.FrameRate         = 0x1000;\r
-  swf.MovieSize.xmax    = cinfo.output_width*20;\r
-  swf.MovieSize.ymax    = cinfo.output_height*20;\r
-\r
-  printf("dx = %i, dy = %i\n",cinfo.output_width,cinfo.output_height);\r
-\r
-  t = swf.FirstTag = InsertTag(NULL,ST_SETBACKGROUNDCOLOR);\r
-\r
-        rgb.r = rgb.g = rgb.b = rgb.a  = 0x00;\r
-        SetRGB(t,&rgb);\r
-\r
-  t = InsertTag(t,ST_DEFINEBITSJPEG2);\r
-\r
-        SetU16(t,1);  // id\r
-  \r
-        out = SetJPEGBitsStart(t,cinfo.output_width,cinfo.output_height,quality);\r
-        scanline = (U8*)malloc(4*cinfo.output_width);\r
-  \r
-        if (scanline)\r
-        { int y;\r
-          U8 * js = scanline;\r
-          for (y=0;y<cinfo.output_height;y++)\r
-          { jpeg_read_scanlines(&cinfo,&js,1);\r
-            SetJPEGBitsLines(out,(U8**)&js,1);\r
-          }\r
-          free(scanline);\r
-        }\r
-        \r
-        SetJPEGBitsFinish(out);\r
-\r
-        printf("JPEG Tag-Length: %06x\n",GetDataSize(t));\r
-\r
-  t = InsertTag(t,ST_DEFINESHAPE);\r
-\r
-        NewShape(&s);\r
-        GetMatrix(NULL,&m);\r
-        m.sx = 20*0x10000;\r
-        m.sy = 20*0x10000;\r
-        rgb.r = 0xff;\r
-        fs = ShapeAddBitmapFillStyle(s,&m,1,0);\r
-//        fs = ShapeAddSolidFillStyle(s,&rgb);\r
-        \r
-        SetU16(t,2); // id\r
-        SetRect(t,&swf.MovieSize);\r
-        SetShapeHeader(t,s);\r
-\r
-        ShapeSetAll(t,s,0,0,0,fs,0);\r
-        ShapeSetLine(t,s,swf.MovieSize.xmax,0);\r
-        ShapeSetLine(t,s,0,swf.MovieSize.ymax);\r
-        ShapeSetLine(t,s,-swf.MovieSize.xmax,0);\r
-        ShapeSetLine(t,s,0,-swf.MovieSize.ymax);\r
-        \r
-        ShapeSetEnd(t);\r
-\r
-  t = InsertTag(t,ST_PLACEOBJECT2);\r
-\r
-        ObjectPlace(t,2,1,NULL,NULL,NULL);\r
-\r
-  t = InsertTag(t,ST_SHOWFRAME);\r
-  \r
-  t = InsertTag(t,ST_END);\r
-\r
-  jpeg_finish_decompress(&cinfo);\r
-  fclose(f);\r
-  \r
-  handle = open(dname,O_RDWR|O_CREAT|O_TRUNC,0666);\r
-  if FAILED(WriteSWF(handle,&swf)) fprintf(stderr,"WriteSWF() failed.\n");\r
-  close(handle);\r
-\r
-  return 0;\r
-}\r
-*/\r
-\r
+/* jpeg2swf.c
+
+   JPEG to SWF converter tool
+
+   Part of the swftools package.
+
+   Copyright (c) 2001 Rainer Böhme <rfxswf@reflex-studio.de>
+   This file is distributed under the GPL, see file COPYING for details 
+
+*/
+
+#include <stdio.h>
+#include <math.h>
+#include <fcntl.h>
+#include <jpeglib.h>
+#include "../lib/rfxswf.h"
+#include "../lib/args.h" // not really a header ;-)
+
+#define MAX_INPUT_FILES 1024
+#define VERBOSE(x) (global.verbose>=x)
+
+struct
+{ int quality;
+  int framerate;
+  int max_image_width;
+  int max_image_height;
+  int force_width;
+  int force_height;
+  int prescale;
+  int nfiles;
+  int verbose;
+  char * outfile;
+} global;
+
+struct
+{ char * filename;
+  int scale;
+  int quality;
+} image[MAX_INPUT_FILES];
+
+TAG * MovieStart(SWF * swf,int framerate,int dx,int dy)
+{ TAG * t;
+  RGBA rgb;
+
+  memset(swf,0x00,sizeof(SWF));
+
+  swf->fileVersion       = 4;
+  swf->frameRate         = (25600/framerate);
+  swf->movieSize.xmax    = dx*20;
+  swf->movieSize.ymax    = dy*20;
+
+  t = swf->firstTag = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
+
+  rgb.r = rgb.g = rgb.b = rgb.a  = 0x00;
+  swf_SetRGB(t,&rgb);
+
+  return t;
+}
+
+int MovieFinish(SWF * swf,TAG * t,char * sname)
+{  int handle, so = fileno(stdout);
+   t = swf_InsertTag(t,ST_END);
+
+   if ((!isatty(so))&&(!sname)) handle = so;
+   else
+   { if (!sname) sname = "output.swf";
+     handle = open(sname,O_RDWR|O_CREAT|O_TRUNC,0666);
+   }
+   if FAILED(swf_WriteSWF(handle,swf)) if (VERBOSE(1)) fprintf(stderr,"Unable to write output file: %s\n",sname);
+   if (handle!=so) close(handle);
+   
+   swf_FreeTags(swf);
+   return 0;
+}
+
+TAG * MovieAddFrame(SWF * swf,TAG * t,char * sname,int quality,int scale,int id)
+{ SHAPE * s;
+  SRECT r;
+  MATRIX m;
+  int fs;
+  
+  struct jpeg_decompress_struct cinfo;
+  struct jpeg_error_mgr jerr;
+  LPJPEGBITS out;
+  FILE * f;
+  U8 * scanline;
+
+  if ((f=fopen(sname,"rb"))==NULL)
+  { if (VERBOSE(1)) fprintf(stderr,"Read access failed: %s\n",sname);
+    return t;
+  }
+  
+  cinfo.err = jpeg_std_error(&jerr);
+  jpeg_create_decompress(&cinfo); 
+  jpeg_stdio_src(&cinfo,f);
+  jpeg_read_header(&cinfo, TRUE);
+  
+  if (scale>1)
+  { cinfo.scale_num = 1;
+    cinfo.scale_denom = scale;
+  }
+    
+  jpeg_start_decompress(&cinfo);
+
+  t = swf_InsertTag(t,ST_DEFINEBITSJPEG2);
+
+        swf_SetU16(t,id);  // id
+  
+        out = swf_SetJPEGBitsStart(t,cinfo.output_width,cinfo.output_height,quality);
+        scanline = (U8*)malloc(4*cinfo.output_width);
+       // the following code is a duplication of swf_SetJPEGBits in ../lib/modules/swfbits.c
+        if (scanline)
+        { int y;
+          U8 * js = scanline;
+
+         if(cinfo.out_color_space == JCS_GRAYSCALE) 
+         {
+             for (y=0;y<cinfo.output_height;y++)
+             { int x;
+               jpeg_read_scanlines(&cinfo,&js,1);
+               for(x=cinfo.output_width-1;x>=0;x--) {
+                   js[x*3] = js[x*3+1] = js[x*3+2] = js[x];
+               }
+               swf_SetJPEGBitsLines(out,(U8**)&js,1);
+             }
+         }
+         else if(cinfo.out_color_space == JCS_RGB) 
+         {
+             for (y=0;y<cinfo.output_height;y++)
+             { jpeg_read_scanlines(&cinfo,&js,1);
+               swf_SetJPEGBitsLines(out,(U8**)&js,1);
+             }
+         }
+          free(scanline);
+        }
+        
+        swf_SetJPEGBitsFinish(out);
+    
+  t = swf_InsertTag(t,ST_DEFINESHAPE);
+
+        swf_ShapeNew(&s);
+        swf_GetMatrix(NULL,&m);
+        m.sx = 20*0x10000;
+        m.sy = 20*0x10000;
+        fs = swf_ShapeAddBitmapFillStyle(s,&m,id,0);
+        
+        swf_SetU16(t,id+1); // id
+
+
+        r.xmin = r.ymin = 0;
+        r.xmax = cinfo.output_width*20;
+        r.ymax = cinfo.output_height*20;
+        swf_SetRect(t,&r);
+        
+        swf_SetShapeHeader(t,s);
+
+        swf_ShapeSetAll(t,s,0,0,0,fs,0);
+        swf_ShapeSetLine(t,s,r.xmax,0);
+        swf_ShapeSetLine(t,s,0,r.ymax);
+        swf_ShapeSetLine(t,s,-r.xmax,0);
+        swf_ShapeSetLine(t,s,0,-r.ymax);
+        
+        swf_ShapeSetEnd(t);
+        
+  t = swf_InsertTag(t,ST_REMOVEOBJECT2);
+        swf_SetU16(t,1); // depth
+
+  t = swf_InsertTag(t,ST_PLACEOBJECT2);
+
+        swf_GetMatrix(NULL,&m);
+        m.tx = (swf->movieSize.xmax-(int)cinfo.output_width*20)/2;
+        m.ty = (swf->movieSize.ymax-(int)cinfo.output_height*20)/2;
+        swf_ObjectPlace(t,id+1,1,&m,NULL,NULL);
+
+  t = swf_InsertTag(t,ST_SHOWFRAME);
+
+  jpeg_finish_decompress(&cinfo);
+  fclose(f);
+
+  return t;
+}
+
+int CheckInputFile(char * fname,char ** realname)
+{ struct jpeg_decompress_struct cinfo;
+  struct jpeg_error_mgr jerr;
+  FILE * f;
+  char * s = malloc(strlen(fname)+5);
+  int width, height;
+  
+  if (!s) exit(2);
+  (*realname) = s;
+  strcpy(s,fname);
+
+  // Check whether file exists (with typical extensions)
+
+  if ((f=fopen(s,"rb"))==NULL)
+  { sprintf(s,"%s.jpg",fname);
+    if ((f=fopen(s,"rb"))==NULL)
+    { sprintf(s,"%s.jpeg",fname);
+      if ((f=fopen(s,"rb"))==NULL)
+      { sprintf(s,"%s.JPG",fname);
+        if ((f=fopen(s,"rb"))==NULL)
+        { sprintf(s,"%s.JPEG",fname);
+          if ((f=fopen(s,"rb"))==NULL)
+            return -1;
+        }
+      }
+    }
+  }
+  
+  cinfo.err = jpeg_std_error(&jerr);
+  jpeg_create_decompress(&cinfo); 
+  jpeg_stdio_src(&cinfo,f);
+  jpeg_read_header(&cinfo, TRUE);
+
+  // Apply scaling (scale option can be used several times to set different scales)
+
+  if (global.prescale>1)
+  { cinfo.scale_num = 1;
+    cinfo.scale_denom = global.prescale;
+
+    jpeg_calc_output_dimensions(&cinfo);
+
+    width  = cinfo.output_width;
+    height = cinfo.output_height;
+  }
+  else
+  { width  = cinfo.image_width;
+    height = cinfo.image_height;
+  }
+
+  // Get image dimensions
+
+  if (global.max_image_width<width) global.max_image_width = width;
+  if (global.max_image_height<height) global.max_image_height = height;
+  
+  jpeg_destroy_decompress(&cinfo);
+  fclose(f);
+
+  return 0;
+}
+
+int args_callback_option(char*arg,char*val)
+{ int res = 0;
+  if (arg[1]) res = -1;
+  else switch (arg[0])
+  { case 'q':
+      if (val) global.quality = atoi(val);
+      if ((global.quality<1)||(global.quality>100))
+      { if (VERBOSE(1)) fprintf(stderr,"Error: You must specify a valid quality between 1 and 100.\n");
+        exit(1);
+      }
+      res = 1;
+      break;
+
+    case 'r':
+      if (val) global.framerate = atoi(val);
+      if ((global.framerate<1)||(global.framerate>5000))
+      { if (VERBOSE(1)) fprintf(stderr,"Error: You must specify a valid framerate between 1 and 10000.\n");
+        exit(1);
+      }
+      res = 1;
+      break;
+
+    case 's':
+      if (val) global.prescale = atoi(val);
+      if (!((global.prescale==1)||(global.prescale==2)||(global.prescale==4)||(global.prescale==8)))
+      { if (VERBOSE(1)) fprintf(stderr,"Error: Prescale denominator is limited to 2, 4 or 8\n");
+        exit(1);
+      }
+      res = 1;
+      break;
+
+    case 'o':
+      if (val) global.outfile = val; res = 1; break;
+
+    case 'v':
+      if (val) global.verbose = atoi(val); res = 1; break;
+
+    case 'X':
+      if (val) global.force_width = atoi(val); res = 1; break;
+
+    case 'Y':
+      if (val) global.force_height = atoi(val); res = 1; break;
+
+    case 'V':
+      printf("jpeg2swf - part of %s %s\n", PACKAGE, VERSION);exit(0);
+      
+    default:
+      res = -1;
+      break;
+  }
+  
+  if (res<0)
+  { if (VERBOSE(1)) fprintf(stderr,"Unknown option: -%s\n",arg);
+    exit(1);
+    return 0;
+  }
+  return res;
+}
+
+struct options_t options[] =
+{{"q","quality"},
+ {"o","output"},
+ {"r","rate"},
+ {"v","verbose"},
+ {"X","width"},
+ {"Y","height"},
+ {"V","version"},
+ {"s","scale"}
+ };
+
+int args_callback_longoption(char*name,char*val) {
+    return args_long2shortoption(options, name, val);
+}
+
+int args_callback_command(char*arg,char*next)  // actually used as filename
+{ char * s;
+  int scale;
+  if (CheckInputFile(arg,&s)<0)
+  { if (VERBOSE(1)) fprintf(stderr, "Unable to open input file: %s\n",arg);
+    free(s);
+  }
+  else
+  { image[global.nfiles].filename = s;
+    image[global.nfiles].scale   = global.prescale;
+    image[global.nfiles].quality = global.quality;
+    global.nfiles++;
+    if (global.nfiles>=MAX_INPUT_FILES)
+    { if (VERBOSE(1)) fprintf(stderr, "Error: Too many input files.\n");
+      exit(1);
+    }
+  }
+  return 0;
+}
+
+void args_callback_usage(char*name)
+{ fprintf(stderr,"Usage: %s  [-options [value]] imagefiles[.jpg]|[.jpeg] [...]\n",name);
+  fprintf(stderr,"-q quality            (quality) Set JPEG compression quality (1-100)\n");
+  fprintf(stderr,"-s denominator        (scale) 2, 4 or 8: Reduce image size to 1/2, 1/4, 1/8\n");
+  fprintf(stderr,"-r framerate          (rate) Set movie framerate (100/sec)\n");
+  fprintf(stderr,"-o outputfile         (output) Set name for SWF output file\n");
+  fprintf(stderr,"-X pixel              (width) Force movie width to scale (default: autodetect)\n");
+  fprintf(stderr,"-Y pixel              (height) Force movie height to scale (default: autodetect)\n");
+  fprintf(stderr,"-v level              (verbose) Set verbose level (0=quiet, 1=default, 2=debug)\n");
+  fprintf(stderr,"-V                    (version) Print version information and exit\n");
+  fprintf(stderr,"The following options can be set independently for each image: -q -s\n");
+}
+
+
+int main(int argc, char ** argv)
+{ SWF swf;
+  TAG * t;
+
+  memset(&global,0x00,sizeof(global));
+    
+  global.quality                = 60;
+  global.framerate              = 100;
+  global.verbose                = 1;
+  global.prescale               = 1;
+  
+  processargs(argc, argv);
+
+  if (VERBOSE(2)) fprintf(stderr,"Processing %i file(s)...\n",global.nfiles);
+
+  t = MovieStart(&swf,global.framerate,
+                      global.force_width?global.force_width:global.max_image_width,
+                      global.force_height?global.force_height:global.max_image_height);
+
+  { int i;
+    for (i=0;i<global.nfiles;i++)
+    { if (VERBOSE(3)) fprintf(stderr,"[%03i] %s (%i%%, 1/%i)\n",i,image[i].filename,image[i].quality,image[i].scale);
+      t = MovieAddFrame(&swf,t,image[i].filename,
+                               image[i].quality,
+                               image[i].scale,(i*2)+1);
+      free(image[i].filename);
+    }
+  }
+
+  MovieFinish(&swf,t,global.outfile);
+
+  return 0;
+}
+
+
+// Old main routine
+
+/*
+int ConvertJPEG2SWF(char * sname,char * dname,int quality)
+{ RGBA rgb;
+  SWF swf;
+  TAG * t;
+  
+  SHAPE * s;
+  SRECT r;
+  MATRIX m;
+  int fs;
+  
+  struct jpeg_decompress_struct cinfo;
+  struct jpeg_error_mgr jerr;
+  LPJPEGBITS out;
+  FILE * f;
+  U8 * scanline;
+
+  int handle;
+
+  cinfo.err = jpeg_std_error(&jerr);
+  jpeg_create_decompress(&cinfo); 
+
+  if ((f=fopen(sname,"rb"))==NULL)
+  { fprintf(stderr,"Read access failed: %s\n",sname);
+    return -1;
+  }
+  
+  jpeg_stdio_src(&cinfo,f);
+  jpeg_read_header(&cinfo, TRUE);
+  jpeg_start_decompress(&cinfo);
+  
+  memset(&swf,0x00,sizeof(SWF));
+
+  swf.FileVersion       = 4;
+  swf.FrameRate         = 0x1000;
+  swf.MovieSize.xmax    = cinfo.output_width*20;
+  swf.MovieSize.ymax    = cinfo.output_height*20;
+
+  printf("dx = %i, dy = %i\n",cinfo.output_width,cinfo.output_height);
+
+  t = swf.FirstTag = InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
+
+        rgb.r = rgb.g = rgb.b = rgb.a  = 0x00;
+        SetRGB(t,&rgb);
+
+  t = InsertTag(t,ST_DEFINEBITSJPEG2);
+
+        SetU16(t,1);  // id
+  
+        out = SetJPEGBitsStart(t,cinfo.output_width,cinfo.output_height,quality);
+        scanline = (U8*)malloc(4*cinfo.output_width);
+  
+        if (scanline)
+        { int y;
+          U8 * js = scanline;
+          for (y=0;y<cinfo.output_height;y++)
+          { jpeg_read_scanlines(&cinfo,&js,1);
+            SetJPEGBitsLines(out,(U8**)&js,1);
+          }
+          free(scanline);
+        }
+        
+        SetJPEGBitsFinish(out);
+
+        printf("JPEG Tag-Length: %06x\n",GetDataSize(t));
+
+  t = InsertTag(t,ST_DEFINESHAPE);
+
+        NewShape(&s);
+        GetMatrix(NULL,&m);
+        m.sx = 20*0x10000;
+        m.sy = 20*0x10000;
+        rgb.r = 0xff;
+        fs = ShapeAddBitmapFillStyle(s,&m,1,0);
+//        fs = ShapeAddSolidFillStyle(s,&rgb);
+        
+        SetU16(t,2); // id
+        SetRect(t,&swf.MovieSize);
+        SetShapeHeader(t,s);
+
+        ShapeSetAll(t,s,0,0,0,fs,0);
+        ShapeSetLine(t,s,swf.MovieSize.xmax,0);
+        ShapeSetLine(t,s,0,swf.MovieSize.ymax);
+        ShapeSetLine(t,s,-swf.MovieSize.xmax,0);
+        ShapeSetLine(t,s,0,-swf.MovieSize.ymax);
+        
+        ShapeSetEnd(t);
+
+  t = InsertTag(t,ST_PLACEOBJECT2);
+
+        ObjectPlace(t,2,1,NULL,NULL,NULL);
+
+  t = InsertTag(t,ST_SHOWFRAME);
+  
+  t = InsertTag(t,ST_END);
+
+  jpeg_finish_decompress(&cinfo);
+  fclose(f);
+  
+  handle = open(dname,O_RDWR|O_CREAT|O_TRUNC,0666);
+  if FAILED(WriteSWF(handle,&swf)) fprintf(stderr,"WriteSWF() failed.\n");
+  close(handle);
+
+  return 0;
+}
+*/
+