bugfix: error message on <file not found> without last guessed extension
[swftools.git] / src / jpeg2swf.c
1 /* jpeg2swf.c\r
2 \r
3    JPEG to SWF converter tool\r
4 \r
5    Part of the swftools package.\r
6 \r
7    Copyright (c) 2001 Rainer Böhme <rfxswf@reflex-studio.de>\r
8  \r
9    This file is distributed under the GPL, see file COPYING for details \r
10 \r
11 */\r
12 \r
13 #include <stdio.h>\r
14 #include <math.h>\r
15 #include <fcntl.h>\r
16 #include <jpeglib.h>\r
17 #include "../lib/rfxswf.h"\r
18 #include "../lib/args.h" // not really a header ;-)\r
19 \r
20 #define MAX_INPUT_FILES 1024\r
21 #define VERBOSE(x) (global.verbose>=x)\r
22 \r
23 struct\r
24 { int quality;\r
25   int framerate;\r
26   int max_image_width;\r
27   int max_image_height;\r
28   int force_width;\r
29   int force_height;\r
30   int nfiles;\r
31   int verbose;\r
32   char * files[MAX_INPUT_FILES];\r
33   char * outfile;\r
34 } global;\r
35 \r
36 TAG * MovieStart(SWF * swf,int framerate,int dx,int dy)\r
37 { TAG * t;\r
38   RGBA rgb;\r
39 \r
40   memset(swf,0x00,sizeof(SWF));\r
41 \r
42   swf->FileVersion       = 4;\r
43   swf->FrameRate         = (25600/framerate);\r
44   swf->MovieSize.xmax    = dx*20;\r
45   swf->MovieSize.ymax    = dy*20;\r
46 \r
47   t = swf->FirstTag = InsertTag(NULL,ST_SETBACKGROUNDCOLOR);\r
48 \r
49   rgb.r = rgb.g = rgb.b = rgb.a  = 0x00;\r
50   SetRGB(t,&rgb);\r
51 \r
52   return t;\r
53 }\r
54 \r
55 int MovieFinish(SWF * swf,TAG * t,char * sname)\r
56 {  int handle, so = fileno(stdout);\r
57    t = InsertTag(t,ST_END);\r
58 \r
59    if ((!isatty(so))&&(!sname)) handle = so;\r
60    else\r
61    { if (!sname) sname = "out.swf";\r
62      handle = open(sname,O_RDWR|O_CREAT|O_TRUNC,0666);\r
63    }\r
64    if FAILED(WriteSWF(handle,swf)) if (VERBOSE(1)) fprintf(stderr,"Unable to write output file: %s\n",sname);\r
65    if (handle!=so) close(handle);\r
66    \r
67    FreeTags(swf);\r
68    return 0;\r
69 }\r
70 \r
71 TAG * MovieAddFrame(SWF * swf,TAG * t,char * sname,int quality,int id)\r
72 { SHAPE * s;\r
73   SRECT r;\r
74   MATRIX m;\r
75   int fs;\r
76   \r
77   struct jpeg_decompress_struct cinfo;\r
78   struct jpeg_error_mgr jerr;\r
79   LPJPEGBITS out;\r
80   FILE * f;\r
81   U8 * scanline;\r
82 \r
83   if ((f=fopen(sname,"rb"))==NULL)\r
84   { if (VERBOSE(1)) fprintf(stderr,"Read access failed: %s\n",sname);\r
85     return t;\r
86   }\r
87   \r
88   cinfo.err = jpeg_std_error(&jerr);\r
89   jpeg_create_decompress(&cinfo); \r
90   jpeg_stdio_src(&cinfo,f);\r
91   jpeg_read_header(&cinfo, TRUE);\r
92   jpeg_start_decompress(&cinfo);\r
93 \r
94   t = InsertTag(t,ST_DEFINEBITSJPEG2);\r
95 \r
96         SetU16(t,id);  // id\r
97   \r
98         out = SetJPEGBitsStart(t,cinfo.output_width,cinfo.output_height,quality);\r
99         scanline = (U8*)malloc(4*cinfo.output_width);\r
100   \r
101         if (scanline)\r
102         { int y;\r
103           U8 * js = scanline;\r
104           for (y=0;y<cinfo.output_height;y++)\r
105           { jpeg_read_scanlines(&cinfo,&js,1);\r
106             SetJPEGBitsLines(out,(U8**)&js,1);\r
107           }\r
108           free(scanline);\r
109         }\r
110         \r
111         SetJPEGBitsFinish(out);\r
112     \r
113   t = InsertTag(t,ST_DEFINESHAPE);\r
114 \r
115         NewShape(&s);\r
116         GetMatrix(NULL,&m);\r
117         m.sx = 20*0x10000;\r
118         m.sy = 20*0x10000;\r
119         fs = ShapeAddBitmapFillStyle(s,&m,id,0);\r
120         \r
121         SetU16(t,id+1); // id\r
122 \r
123 \r
124         r.xmin = r.ymin = 0;\r
125         r.xmax = cinfo.output_width*20;\r
126         r.ymax = cinfo.output_height*20;\r
127         SetRect(t,&r);\r
128         \r
129         SetShapeHeader(t,s);\r
130 \r
131         ShapeSetAll(t,s,0,0,0,fs,0);\r
132         ShapeSetLine(t,s,r.xmax,0);\r
133         ShapeSetLine(t,s,0,r.ymax);\r
134         ShapeSetLine(t,s,-r.xmax,0);\r
135         ShapeSetLine(t,s,0,-r.ymax);\r
136         \r
137         ShapeSetEnd(t);\r
138         \r
139   t = InsertTag(t,ST_REMOVEOBJECT2);\r
140         SetU16(t,1); // depth\r
141 \r
142   t = InsertTag(t,ST_PLACEOBJECT2);\r
143 \r
144         GetMatrix(NULL,&m);\r
145         m.tx = (swf->MovieSize.xmax-(int)cinfo.output_width*20)/2;\r
146         m.ty = (swf->MovieSize.ymax-(int)cinfo.output_height*20)/2;\r
147         ObjectPlace(t,id+1,1,&m,NULL,NULL);\r
148 \r
149   t = InsertTag(t,ST_SHOWFRAME);\r
150 \r
151   jpeg_finish_decompress(&cinfo);\r
152   fclose(f);\r
153 \r
154   return t;\r
155 }\r
156 \r
157 int CheckInputFile(char * fname,char ** realname)\r
158 { struct jpeg_decompress_struct cinfo;\r
159   struct jpeg_error_mgr jerr;\r
160   FILE * f;\r
161   char * s = malloc(strlen(fname)+5);\r
162   \r
163   if (!s) exit(2);\r
164   (*realname) = s;\r
165   strcpy(s,fname);\r
166 \r
167   // Check whether file exists (with typical extensions)\r
168 \r
169   if ((f=fopen(s,"rb"))==NULL)\r
170   { sprintf(s,"%s.jpg",fname);\r
171     if ((f=fopen(s,"rb"))==NULL)\r
172     { sprintf(s,"%s.jpeg",fname);\r
173       if ((f=fopen(s,"rb"))==NULL)\r
174       { sprintf(s,"%s.JPG",fname);\r
175         if ((f=fopen(s,"rb"))==NULL)\r
176         { sprintf(s,"%s.JPEG",fname);\r
177           if ((f=fopen(s,"rb"))==NULL)\r
178             return -1;\r
179         }\r
180       }\r
181     }\r
182   }\r
183   \r
184   cinfo.err = jpeg_std_error(&jerr);\r
185   jpeg_create_decompress(&cinfo); \r
186   jpeg_stdio_src(&cinfo,f);\r
187   jpeg_read_header(&cinfo, TRUE);\r
188 \r
189   // Get image dimensions\r
190 \r
191   if (global.max_image_width<cinfo.image_width) global.max_image_width = cinfo.image_width;\r
192   if (global.max_image_height<cinfo.image_height) global.max_image_height = cinfo.image_height;\r
193   \r
194   jpeg_destroy_decompress(&cinfo);\r
195   fclose(f);\r
196 \r
197   return 0;\r
198 }\r
199 \r
200 int args_callback_option(char*arg,char*val)\r
201 { int res = 0;\r
202   if (arg[1]) res = -1;\r
203   else switch (arg[0])\r
204   { case 'q':\r
205       if (val) global.quality = atoi(val);\r
206       if ((global.quality<1)||(global.quality>100))\r
207       { if (VERBOSE(1)) fprintf(stderr,"Error: You must specify a valid quality between 1 and 100.\n");\r
208         exit(1);\r
209       }\r
210       res = 1;\r
211       break;\r
212 \r
213     case 'r':\r
214       if (val) global.framerate = atoi(val);\r
215       if ((global.framerate<1)||(global.framerate>5000))\r
216       { if (VERBOSE(1)) fprintf(stderr,"Error: You must specify a valid framerate between 1 and 10000.\n");\r
217         exit(1);\r
218       }\r
219       res = 1;\r
220       break;\r
221 \r
222     case 'o':\r
223       if (val) global.outfile = val; res = 1; break;\r
224 \r
225     case 'v':\r
226       if (val) global.verbose = atoi(val); res = 1; break;\r
227 \r
228     case 'X':\r
229       if (val) global.force_width = atoi(val); res = 1; break;\r
230 \r
231     case 'Y':\r
232       if (val) global.force_height = atoi(val); res = 1; break;\r
233 \r
234     case 'V':\r
235       printf("jpeg2swf - part of %s %s\n", PACKAGE, VERSION);exit(0);\r
236       \r
237     default:\r
238       res = -1;\r
239       break;\r
240   }\r
241   \r
242   if (res<0)\r
243   { if (VERBOSE(1)) fprintf(stderr,"Unknown option: -v%s\n",arg);\r
244     return 0;\r
245   }\r
246   return res;\r
247 }\r
248 \r
249 struct options_t options[] =\r
250 {{"q","quality"},\r
251  {"o","output"},\r
252  {"r","rate"},\r
253  {"v","verbose"},\r
254  {"X","width"},\r
255  {"Y","height"},\r
256  {"V","version"}\r
257 };\r
258 \r
259 int args_callback_longoption(char*name,char*val) {\r
260     return args_long2shortoption(options, name, val);\r
261 }\r
262 \r
263 int args_callback_command(char*arg,char*next)  // actually used as filename\r
264 { char * s;\r
265   if (CheckInputFile(arg,&s)<0)\r
266   { if (VERBOSE(1)) fprintf(stderr, "Unable to open input file: %s\n",arg);\r
267     free(s);\r
268   }\r
269   else\r
270   { global.files[global.nfiles] = s;\r
271     global.nfiles++;\r
272     if (global.nfiles>=MAX_INPUT_FILES)\r
273     { if (VERBOSE(1)) fprintf(stderr, "Error: Too many input files.\n");\r
274       exit(1);\r
275     }\r
276   }\r
277   return 0;\r
278 }\r
279 \r
280 void args_callback_usage(char*name)\r
281 { fprintf(stderr,"Usage: %s imagefiles[.jpg]|[.jpeg] [...] [-options [value]]\n",name);\r
282   fprintf(stderr,"-q quality            (quality) Set JPEG compression quality (1-100)\n");\r
283   fprintf(stderr,"-r framerate          (rate) Set movie framerate (100/sec)\n");\r
284   fprintf(stderr,"-o outputfile         (output) Set name for SWF output file\n");\r
285   fprintf(stderr,"-v level              (verbose) Set verbose level (0=quiet, 1=default, 2=debug)\n");\r
286   fprintf(stderr,"-X pixel              (width) Force movie width to scale (default: autodetect)\n");\r
287   fprintf(stderr,"-Y pixel              (height) Force movie height to scale (default: autodetect)\n");\r
288   fprintf(stderr,"-V                    (version) Print version information and exit\n");\r
289 }\r
290 \r
291 \r
292 int main(int argc, char ** argv)\r
293 { SWF swf;\r
294   TAG * t;\r
295 \r
296   memset(&global,0x00,sizeof(global));\r
297     \r
298   global.quality                = 60;\r
299   global.framerate              = 100;\r
300   global.verbose                = 1;\r
301   \r
302   processargs(argc, argv);\r
303 \r
304   if (VERBOSE(2)) fprintf(stderr,"Processing %i file(s)...\n",global.nfiles);\r
305 \r
306   t = MovieStart(&swf,global.framerate,\r
307                       global.force_width?global.force_width:global.max_image_width,\r
308                       global.force_height?global.force_height:global.max_image_height);\r
309 \r
310   { int i;\r
311     for (i=0;i<global.nfiles;i++)\r
312     { if (VERBOSE(3)) fprintf(stderr,"[%03i] %s\n",i,global.files[i]);\r
313       t = MovieAddFrame(&swf,t,global.files[i],global.quality,(i*2)+1);\r
314       free(global.files[i]);\r
315     }\r
316   }\r
317 \r
318   MovieFinish(&swf,t,global.outfile);\r
319 \r
320   return 0;\r
321 }\r
322 \r
323 \r
324 // Old main routine\r
325 \r
326 /*\r
327 int ConvertJPEG2SWF(char * sname,char * dname,int quality)\r
328 { RGBA rgb;\r
329   SWF swf;\r
330   TAG * t;\r
331   \r
332   SHAPE * s;\r
333   SRECT r;\r
334   MATRIX m;\r
335   int fs;\r
336   \r
337   struct jpeg_decompress_struct cinfo;\r
338   struct jpeg_error_mgr jerr;\r
339   LPJPEGBITS out;\r
340   FILE * f;\r
341   U8 * scanline;\r
342 \r
343   int handle;\r
344 \r
345   cinfo.err = jpeg_std_error(&jerr);\r
346   jpeg_create_decompress(&cinfo); \r
347 \r
348   if ((f=fopen(sname,"rb"))==NULL)\r
349   { fprintf(stderr,"Read access failed: %s\n",sname);\r
350     return -1;\r
351   }\r
352   \r
353   jpeg_stdio_src(&cinfo,f);\r
354   jpeg_read_header(&cinfo, TRUE);\r
355   jpeg_start_decompress(&cinfo);\r
356   \r
357   memset(&swf,0x00,sizeof(SWF));\r
358 \r
359   swf.FileVersion       = 4;\r
360   swf.FrameRate         = 0x1000;\r
361   swf.MovieSize.xmax    = cinfo.output_width*20;\r
362   swf.MovieSize.ymax    = cinfo.output_height*20;\r
363 \r
364   printf("dx = %i, dy = %i\n",cinfo.output_width,cinfo.output_height);\r
365 \r
366   t = swf.FirstTag = InsertTag(NULL,ST_SETBACKGROUNDCOLOR);\r
367 \r
368         rgb.r = rgb.g = rgb.b = rgb.a  = 0x00;\r
369         SetRGB(t,&rgb);\r
370 \r
371   t = InsertTag(t,ST_DEFINEBITSJPEG2);\r
372 \r
373         SetU16(t,1);  // id\r
374   \r
375         out = SetJPEGBitsStart(t,cinfo.output_width,cinfo.output_height,quality);\r
376         scanline = (U8*)malloc(4*cinfo.output_width);\r
377   \r
378         if (scanline)\r
379         { int y;\r
380           U8 * js = scanline;\r
381           for (y=0;y<cinfo.output_height;y++)\r
382           { jpeg_read_scanlines(&cinfo,&js,1);\r
383             SetJPEGBitsLines(out,(U8**)&js,1);\r
384           }\r
385           free(scanline);\r
386         }\r
387         \r
388         SetJPEGBitsFinish(out);\r
389 \r
390         printf("JPEG Tag-Length: %06x\n",GetDataSize(t));\r
391 \r
392   t = InsertTag(t,ST_DEFINESHAPE);\r
393 \r
394         NewShape(&s);\r
395         GetMatrix(NULL,&m);\r
396         m.sx = 20*0x10000;\r
397         m.sy = 20*0x10000;\r
398         rgb.r = 0xff;\r
399         fs = ShapeAddBitmapFillStyle(s,&m,1,0);\r
400 //        fs = ShapeAddSolidFillStyle(s,&rgb);\r
401         \r
402         SetU16(t,2); // id\r
403         SetRect(t,&swf.MovieSize);\r
404         SetShapeHeader(t,s);\r
405 \r
406         ShapeSetAll(t,s,0,0,0,fs,0);\r
407         ShapeSetLine(t,s,swf.MovieSize.xmax,0);\r
408         ShapeSetLine(t,s,0,swf.MovieSize.ymax);\r
409         ShapeSetLine(t,s,-swf.MovieSize.xmax,0);\r
410         ShapeSetLine(t,s,0,-swf.MovieSize.ymax);\r
411         \r
412         ShapeSetEnd(t);\r
413 \r
414   t = InsertTag(t,ST_PLACEOBJECT2);\r
415 \r
416         ObjectPlace(t,2,1,NULL,NULL,NULL);\r
417 \r
418   t = InsertTag(t,ST_SHOWFRAME);\r
419   \r
420   t = InsertTag(t,ST_END);\r
421 \r
422   jpeg_finish_decompress(&cinfo);\r
423   fclose(f);\r
424   \r
425   handle = open(dname,O_RDWR|O_CREAT|O_TRUNC,0666);\r
426   if FAILED(WriteSWF(handle,&swf)) fprintf(stderr,"WriteSWF() failed.\n");\r
427   close(handle);\r
428 \r
429   return 0;\r
430 }\r
431 */\r
432 \r