1 /****************************************************************
2 * amain.c
3 *
4 * Copyright (C) 1995-2002 Klaus Ehrenfried
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 *
20 *************************************************************************/
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include "apro.h"
25
26 static const char ppm2fli_env_var[]="PPM2FLIFILTER";
27 static int output_file_created;
28 static char *output_name;
29
30 #define SCANINT(x,y) \
31 if (sscanf(x,"%d",y) != 1) \
32 { fprintf(stderr,"Invalid number '%s' in argument %d\n",x,i);\
33 print_hint(); return(1); }
34
35 #define GETNUMBER(x) \
36 ppa++; \
37 if (*ppa == '\0') { pending_number = &(x); pp_flag = 1; } \
38 else { SCANINT(ppa,&(x)); }
39
40 #define GETNAME(x) \
41 ppa++; \
42 if (*ppa == '\0') { pending_name = &(x); pp_flag = 2; } \
43 else { x = ppa; }
44
45
46 /****************************************************************
47 * print_usage
48 ****************************************************************/
49
print_usage()50 static int print_usage()
51 {
52 fprintf(stdout,"PPM2FLI version 2.1 by Klaus Ehrenfried (C) 1995,2002\n");
53 fprintf(stdout,"Usage: ppm2fli [options] list-file fli-file\n");
54
55 return(1);
56 }
57
58 /****************************************************************
59 * print_hint()
60 ****************************************************************/
61
print_hint()62 static int print_hint()
63 {
64 fprintf(stderr,"Type 'ppm2fli -h' for help\n");
65 return(1);
66 }
67
68 /****************************************************************
69 * print_usage
70 ****************************************************************/
71
print_help()72 static int print_help()
73 {
74 fprintf(stdout,"Function:\n\
75 Reads from 'list-file' line by line file names of PPM/PGM/PBM/FBM images,\n\
76 generates a common color-table by scanning all images,\n\
77 quantizes the images and assembles a FLI/FLC animation,\n\
78 which is written to 'fli-file'\n");
79
80 fprintf(stdout,"Quantize options:\n\
81 -I Individual quantize: Don't use common color table,\n\
82 generate for each image separate table\n\
83 -Qc<colors> Set max number of colors (9 - 256; default = 256)\n\
84 -Qd<depth> Set color depth (2 - 8; default = 8)\n\
85 -Qn<limit> Set node limit in Octree (16 - 2048; default = 512)\n\
86 -Qr<value> Set max number of reduce levels (0 - 8; default = 8)\n\
87 -m<file> Don't scan all images previously, generate color-table\n\
88 by scanning only the image in specified file\n\
89 (ppm or fbm, read filter is ineffective)\n\
90 -w<file> Write generated color-table to file (256x1 PPM ascii)\n\
91 and stop, don't make FLI/FLC\n");
92
93 fprintf(stdout,"FLI/FLC options:\n\
94 -D Double buffer optimization (for special players)\n\
95 -N Reverse play suitability (nice when using XAnim)\n\
96 -O Generate old format FLI instead of FLC\n\
97 -b<color> Set border color (default = 0)\n\
98 -g<width>x<height> Set width and height (10x10 - 1280x1024),\n\
99 default is 640x480 (320x200 when using '-O')\n\
100 +/-ox<pos> Switch off horizontal centering of input images,\n\
101 locate the left/right border at specified position\n\
102 +/-oy<pos> Switch off vertical centering of input images,\n\
103 locate the upper/lower border at specified position\n\
104 -s<speed> Set play speed stored in FLI/FLC file\n");
105
106 fprintf(stdout,"General options:\n\
107 -v Verbose ('-vv' is more verbose)\n\
108 +/-f<filter> Read all input images via the specified filter\n\
109 (e.g. '-fgunzip', '-fgiftopnm', '-ffbcat', etc.),\n\
110 '+f' filter needs file name as argument\n\
111 '-f' filter reads from stdin\n\
112 -t Test file magic: use read filter only for files\n\
113 without PPM,PGM,PBM or FBM magic\n");
114 fprintf(stdout,"For more details, please read the manual pages\n");
115 return(1);
116 }
117
118 /****************************************************************
119 * exitialise
120 ****************************************************************/
121
exitialise(int error_flag)122 int exitialise(int error_flag)
123 {
124 if (error_flag != 0)
125 {
126 if (output_file_created == 1)
127 {
128 if (output != NULL) fclose(output);
129
130 fprintf(stderr,"Remove incomplete output file '%s'\n",output_name);
131 (void) remove(output_name);
132 }
133 fprintf(stderr,"Abnormal termination\n");
134 }
135 return(1);
136 }
137
138 /****************************************************************
139 * main
140 ****************************************************************/
141
main(int argc,char * argv[])142 int main (int argc, char *argv[])
143 {
144 FILE *fopen();
145 char *listfile, *ppa, *ppb, *map_file, *output_pal_file, *geom;
146 char **pending_name;
147 char abuff[10];
148 int answer_flag, max_chunk_size;
149 int s_speed;
150 int i, itest, pp_flag, list_input_flag;
151 int *pending_number;
152 int help_filter_flag;
153 int help_origin;
154
155 /* octree defaults */
156 max_colors=FLI_MAX_COLORS;
157 node_limit = 2 * FLI_MAX_COLORS;
158 reduce_dynamics=MAXDEPTH;
159 color_depth=8;
160
161 /* -- -- - - -- -- */
162 tmp_file_name = NULL;
163 verbose_flag = 0;
164
165 geom=NULL;
166 listfile=NULL;
167 output_name=NULL;
168 map_file=NULL;
169 input=0;
170 output=0;
171
172 output_file_created=0;
173
174 pixel_chunk_buffer=NULL;
175
176 Xorigin=0;
177 Xorigin_flag=0;
178 Yorigin=0;
179 Yorigin_flag=0;
180 s_speed=-1;
181
182 border_color=0;
183 map_color_flag=0;
184 use_next_flag=0;
185 double_buffer=0;
186 old_format_flag=0;
187
188 write_pal_flag = 0;
189 individual_flag = 0;
190 filter_flag = 0;
191 help_filter_flag = 0;
192 test_magic_flag = 0;
193
194 wobbel_flag=0;
195
196 /* scan arguments */
197
198 pp_flag = 0;
199 pending_number = NULL;
200 pending_name = NULL;
201 ppa = ppb = NULL;
202
203 if (argc == 1)
204 { print_usage(); return(1); }
205
206 for (i=1; i < argc; i++)
207 {
208 ppa=argv[i];
209 if (pp_flag == 1)
210 { SCANINT(ppa, pending_number); pp_flag = 0; }
211 else if (pp_flag == 2)
212 { *pending_name = ppa; pp_flag = 0; }
213 else if ((*ppa == '-') || (*ppa == '+'))
214 {
215 ppb = (ppa++);
216 switch (*ppa)
217 {
218 case 'h': print_usage(); print_help(); return(1);
219 case 'b': GETNUMBER(border_color); break;
220 case 'D': double_buffer=1; break;
221 case 'g': GETNAME(geom); break;
222 case 'f':
223 GETNAME(filter_name);
224 if (*ppb == '+')
225 {help_filter_flag = 2;}
226 else
227 {help_filter_flag = 1;}
228 break;
229 case 'I': individual_flag=1; break;
230 case 'm': GETNAME(map_file); map_color_flag=1; break;
231 case 'N': use_next_flag=1; break;
232 case 'O': old_format_flag=1; break;
233 case 'o':
234 if (*ppb == '+')
235 {help_origin = 1;}
236 else
237 {help_origin = 2;}
238 ppa++;
239 if (*ppa == 'x')
240 { GETNUMBER(Xorigin); Xorigin_flag = help_origin;}
241 else if (*ppa == 'y')
242 { GETNUMBER(Yorigin); Yorigin_flag = help_origin;}
243 else
244 { goto invalid_option;}
245 break;
246 case 'Q':
247 ppa++;
248 if (*ppa == 'c')
249 { GETNUMBER(max_colors);}
250 else if (*ppa == 'd')
251 { GETNUMBER(color_depth);}
252 else if (*ppa == 'n')
253 { GETNUMBER(node_limit);}
254 else if (*ppa == 'r')
255 { GETNUMBER(reduce_dynamics);}
256 else
257 { goto invalid_option;}
258 break;
259 case 's': GETNUMBER(s_speed); break;
260 case 't': test_magic_flag = 1; break;
261 case 'v':
262 ppa++;
263 if (*ppa == 'v') {verbose_flag = 2;} else {verbose_flag = 1;}
264 break;
265 case 'w': GETNAME(output_pal_file); write_pal_flag=1; break;
266 case 'W': wobbel_flag = 1; break;
267 invalid_option:
268 default:
269 fprintf(stderr,"Invalid option '%s'\n",ppb);
270 print_hint();
271 return(1);
272 }
273 }
274 else if (listfile == NULL)
275 {
276 listfile=ppa;
277 }
278 else if (output_name == NULL)
279 {
280 output_name=ppa;
281 }
282 else
283 {
284 fprintf(stderr,"Too many parameters specified\n");
285 print_hint();
286 return(1);
287 }
288 }
289
290 if (pp_flag != 0)
291 {
292 fprintf(stderr,"Missing parameter behind option '%s'\n",ppb);
293 print_hint();
294 return(1);
295 }
296
297 /* -- check if all necessary file names are given -- */
298
299 if ((map_color_flag) && (write_pal_flag))
300 { list_input_flag = 0; }
301 else
302 { list_input_flag = 1; }
303
304 if (listfile == NULL)
305 {
306 if (list_input_flag)
307 {
308 fprintf(stderr,"No list-file specified\n");
309 print_hint();
310 return(1);
311 }
312 }
313 else
314 {
315 if (!list_input_flag)
316 {
317 fprintf(stderr,"No list-file required: file name '%s' ignored\n",
318 listfile);
319 }
320 }
321
322 if (output_name == NULL)
323 {
324 if (!write_pal_flag)
325 {
326 fprintf(stderr,"No FLI-file specified\n");
327 print_hint();
328 return(1);
329 }
330 }
331 else
332 {
333 if (write_pal_flag)
334 {
335 fprintf(stderr,"Only write color table: file name '%s' ignored\n",
336 output_name);
337 }
338 }
339
340 /* --- check for incompatibilities --- */
341
342 if (use_next_flag)
343 {
344 if (double_buffer)
345 {
346 fprintf(stderr,"Invalid combination of '-D' and '-N'\n");
347 print_hint();
348 return (1);
349 }
350 double_buffer = 1;
351 }
352
353 if (individual_flag)
354 {
355 if (map_color_flag)
356 {
357 fprintf(stderr,"Invalid combination of '-I' and '-m <file>'\n");
358 print_hint();
359 return (1);
360 }
361 if (write_pal_flag)
362 {
363 fprintf(stderr,"Invalid combination of '-I' and '-w <file>'\n");
364 print_hint();
365 return (1);
366 }
367 }
368
369 /* --- check options for quantize --- */
370
371 if ((node_limit < MIN_NODE_LIMIT) || (node_limit > MAX_NODE_LIMIT))
372 {
373 fprintf(stderr,"Invalid node limit specified: %d\n",node_limit);
374 print_hint();
375 return (1);
376 }
377
378 if (color_depth > 8 || color_depth < 2)
379 {
380 fprintf (stderr,"Invalid color depth specified: %d\n",color_depth);
381 print_hint();
382 return (1);
383 }
384
385 if (max_colors > 256 || max_colors < 9)
386 {
387 fprintf (stderr, "Invalid number of colors specified: %d\n",
388 max_colors);
389 print_hint();
390 return (1);
391 }
392
393 if (reduce_dynamics < 0) reduce_dynamics = 0;
394
395 /* --- output format --- */
396
397 if (write_pal_flag)
398 {
399 output_name = output_pal_file;
400 }
401 else
402 {
403 if (old_format_flag == 1)
404 {
405 fli_width=320;
406 fli_height=200;
407 fli_speed=5;
408 }
409 else
410 {
411 fli_width=640;
412 fli_height=480;
413 fli_speed=72;
414 }
415
416 if (geom != NULL)
417 {
418 if ((sscanf(geom,"%dx%d",&fli_width,&fli_height)) != 2)
419 {
420 fprintf (stderr,"Invalid geometry: '%s'\n",geom);
421 print_hint();
422 return (1);
423 }
424
425 if ((fli_width % 2) == 1) fli_width++; /* no odd width */
426 if ((fli_width < 10) || (fli_width > FLI_MAX_X))
427 {
428 fprintf (stderr,"Invalid width: %d\n",fli_width);
429 print_hint();
430 return (1);
431 }
432 if ((fli_height < 10) || (fli_height > FLI_MAX_Y))
433 {
434 fprintf (stderr,"Invalid height: %d\n",fli_height);
435 print_hint();
436 return (1);
437 }
438 }
439
440 fli_size = fli_width * fli_height;
441
442 if (s_speed >= 0) /* be tolerant */
443 fli_speed = s_speed;
444 }
445
446 if (list_input_flag)
447 {
448 if ((input = fopen(listfile, "r")) == NULL)
449 {
450 fprintf(stderr,"Error opening list-file '%s'\n",listfile);
451 return(1);
452 }
453 }
454 else
455 {
456 input = NULL;
457 }
458
459 if (verbose_flag > 0)
460 {
461 fprintf(stdout,"Output: '%s'\n",output_name);
462 }
463
464 if (check_exist(output_name) == 1)
465 {
466 fprintf(stderr,"%s already exists\n",output_name);
467 answer_flag=0;
468 while (answer_flag == 0)
469 {
470 fprintf(stderr," overwrite %s (y/n) ",output_name);
471 fflush(stdout);
472 if ((itest=get_next_line(stdin, abuff, 2)) == 1)
473 {
474 if ((abuff[0] == 'y') || (abuff[0] == 'Y'))
475 answer_flag=1;
476 else if ((abuff[0] == 'n') || (abuff[0] == 'N'))
477 answer_flag=2;
478 }
479 }
480 if (answer_flag != 1) return(1);
481 }
482
483 /* ............. open output file ........ */
484
485 if (write_pal_flag)
486 {
487 if ((output = fopen(output_name, "w")) == NULL)
488 {
489 fprintf(stderr,"Error opening color table file '%s'\n",output_name);
490 return(1);
491 }
492 output_file_created = 1;
493 }
494 else
495 {
496 if ((output = fopen(output_name, "wb")) == NULL)
497 {
498 fprintf(stderr,"Error opening fli-file '%s'\n",output_name);
499 return(1);
500 }
501 output_file_created = 1;
502
503 if (border_color > 0x00FF) border_color=0x00FF;
504 if (border_color < 0x0000) border_color=0x0000;
505
506 if (verbose_flag > 0)
507 {
508 fprintf(stdout," Resolution: %dx%d\n",fli_width,fli_height);
509 fprintf(stdout," Origin: %dx%d\n",Yorigin,Xorigin);
510 fprintf(stdout," Speed: %d\n",fli_speed);
511 }
512
513 max_chunk_size=fli_height*(2*fli_width+10)+1024;
514
515 pixel_chunk_buffer = malloc(max_chunk_size);
516 if (pixel_chunk_buffer == NULL)
517 {
518 fprintf(stderr,"Can't allocate %d bytes\n",max_chunk_size);
519 exitialise(1);
520 return(1);
521 }
522 }
523
524 if (map_color_flag == 1)
525 {
526 fprintf(stdout,"Generate color table from file '%s'\n",map_file);
527 clear_octree();
528 scan_rgb_image(map_file);
529 prepare_quantize();
530 }
531
532 if (help_filter_flag == 0)
533 {
534 filter_name = getenv(ppm2fli_env_var);
535 if (filter_name != NULL)
536 {
537 help_filter_flag = 1;
538 if (*filter_name == '-')
539 {
540 filter_name++;
541 }
542 else if (*filter_name == '+')
543 {
544 filter_name++;
545 help_filter_flag = 2;
546 }
547 }
548 }
549
550 filter_flag = help_filter_flag;
551
552 if (make_fli() < 0)
553 {
554 exitialise(1);
555 return(1);
556 }
557
558 fprintf(stdout,"Ready\n");
559 exitialise(0);
560 return(0);
561 }
562
563 /* -- FIN -- */
564