Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
6417 ashmew2 1
/*
2
 * jpegtran.c
3
 *
4
 * Copyright (C) 1995-1997, Thomas G. Lane.
5
 * This file is part of the Independent JPEG Group's software.
6
 * For conditions of distribution and use, see the accompanying README file.
7
 *
8
 * This file contains a command-line user interface for JPEG transcoding.
9
 * It is very similar to cjpeg.c, but provides lossless transcoding between
10
 * different JPEG file formats.  It also provides some lossless and sort-of-
11
 * lossless transformations of JPEG data.
12
 */
13
 
14
#include "cdjpeg.h"		/* Common decls for cjpeg/djpeg applications */
15
#include "transupp.h"		/* Support routines for jpegtran */
16
#include "jversion.h"		/* for version message */
17
 
18
#ifdef USE_CCOMMAND		/* command-line reader for Macintosh */
19
#ifdef __MWERKS__
20
#include               /* Metrowerks needs this */
21
#include 		/* ... and this */
22
#endif
23
#ifdef THINK_C
24
#include 		/* Think declares it here */
25
#endif
26
#endif
27
 
28
 
29
/*
30
 * Argument-parsing code.
31
 * The switch parser is designed to be useful with DOS-style command line
32
 * syntax, ie, intermixed switches and file names, where only the switches
33
 * to the left of a given file name affect processing of that file.
34
 * The main program in this file doesn't actually use this capability...
35
 */
36
 
37
 
38
static const char * progname;	/* program name for error messages */
39
static char * outfilename;	/* for -outfile switch */
40
static JCOPY_OPTION copyoption;	/* -copy switch */
41
static jpeg_transform_info transformoption; /* image transformation options */
42
 
43
 
44
LOCAL(void)
45
usage (void)
46
/* complain about bad command line */
47
{
48
  fprintf(stderr, "usage: %s [switches] ", progname);
49
#ifdef TWO_FILE_COMMANDLINE
50
  fprintf(stderr, "inputfile outputfile\n");
51
#else
52
  fprintf(stderr, "[inputfile]\n");
53
#endif
54
 
55
  fprintf(stderr, "Switches (names may be abbreviated):\n");
56
  fprintf(stderr, "  -copy none     Copy no extra markers from source file\n");
57
  fprintf(stderr, "  -copy comments Copy only comment markers (default)\n");
58
  fprintf(stderr, "  -copy all      Copy all extra markers\n");
59
#ifdef ENTROPY_OPT_SUPPORTED
60
  fprintf(stderr, "  -optimize      Optimize Huffman table (smaller file, but slow compression)\n");
61
#endif
62
#ifdef C_PROGRESSIVE_SUPPORTED
63
  fprintf(stderr, "  -progressive   Create progressive JPEG file\n");
64
#endif
65
#if TRANSFORMS_SUPPORTED
66
  fprintf(stderr, "Switches for modifying the image:\n");
67
  fprintf(stderr, "  -grayscale     Reduce to grayscale (omit color data)\n");
68
  fprintf(stderr, "  -flip [horizontal|vertical]  Mirror image (left-right or top-bottom)\n");
69
  fprintf(stderr, "  -rotate [90|180|270]         Rotate image (degrees clockwise)\n");
70
  fprintf(stderr, "  -transpose     Transpose image\n");
71
  fprintf(stderr, "  -transverse    Transverse transpose image\n");
72
  fprintf(stderr, "  -trim          Drop non-transformable edge blocks\n");
73
#endif /* TRANSFORMS_SUPPORTED */
74
  fprintf(stderr, "Switches for advanced users:\n");
75
  fprintf(stderr, "  -restart N     Set restart interval in rows, or in blocks with B\n");
76
  fprintf(stderr, "  -maxmemory N   Maximum memory to use (in kbytes)\n");
77
  fprintf(stderr, "  -outfile name  Specify name for output file\n");
78
  fprintf(stderr, "  -verbose  or  -debug   Emit debug output\n");
79
  fprintf(stderr, "Switches for wizards:\n");
80
#ifdef C_ARITH_CODING_SUPPORTED
81
  fprintf(stderr, "  -arithmetic    Use arithmetic coding\n");
82
#endif
83
#ifdef C_MULTISCAN_FILES_SUPPORTED
84
  fprintf(stderr, "  -scans file    Create multi-scan JPEG per script file\n");
85
#endif
86
  exit(EXIT_FAILURE);
87
}
88
 
89
 
90
LOCAL(void)
91
select_transform (JXFORM_CODE transform)
92
/* Silly little routine to detect multiple transform options,
93
 * which we can't handle.
94
 */
95
{
96
#if TRANSFORMS_SUPPORTED
97
  if (transformoption.transform == JXFORM_NONE ||
98
      transformoption.transform == transform) {
99
    transformoption.transform = transform;
100
  } else {
101
    fprintf(stderr, "%s: can only do one image transformation at a time\n",
102
	    progname);
103
    usage();
104
  }
105
#else
106
  fprintf(stderr, "%s: sorry, image transformation was not compiled\n",
107
	  progname);
108
  exit(EXIT_FAILURE);
109
#endif
110
}
111
 
112
 
113
LOCAL(int)
114
parse_switches (j_compress_ptr cinfo, int argc, char **argv,
115
		int last_file_arg_seen, boolean for_real)
116
/* Parse optional switches.
117
 * Returns argv[] index of first file-name argument (== argc if none).
118
 * Any file names with indexes <= last_file_arg_seen are ignored;
119
 * they have presumably been processed in a previous iteration.
120
 * (Pass 0 for last_file_arg_seen on the first or only iteration.)
121
 * for_real is FALSE on the first (dummy) pass; we may skip any expensive
122
 * processing.
123
 */
124
{
125
  int argn;
126
  char * arg;
127
  boolean simple_progressive;
128
  char * scansarg = NULL;	/* saves -scans parm if any */
129
 
130
  /* Set up default JPEG parameters. */
131
  simple_progressive = FALSE;
132
  outfilename = NULL;
133
  copyoption = JCOPYOPT_DEFAULT;
134
  transformoption.transform = JXFORM_NONE;
135
  transformoption.trim = FALSE;
136
  transformoption.force_grayscale = FALSE;
137
  cinfo->err->trace_level = 0;
138
 
139
  /* Scan command line options, adjust parameters */
140
 
141
  for (argn = 1; argn < argc; argn++) {
142
    arg = argv[argn];
143
    if (*arg != '-') {
144
      /* Not a switch, must be a file name argument */
145
      if (argn <= last_file_arg_seen) {
146
	outfilename = NULL;	/* -outfile applies to just one input file */
147
	continue;		/* ignore this name if previously processed */
148
      }
149
      break;			/* else done parsing switches */
150
    }
151
    arg++;			/* advance past switch marker character */
152
 
153
    if (keymatch(arg, "arithmetic", 1)) {
154
      /* Use arithmetic coding. */
155
#ifdef C_ARITH_CODING_SUPPORTED
156
      cinfo->arith_code = TRUE;
157
#else
158
      fprintf(stderr, "%s: sorry, arithmetic coding not supported\n",
159
	      progname);
160
      exit(EXIT_FAILURE);
161
#endif
162
 
163
    } else if (keymatch(arg, "copy", 1)) {
164
      /* Select which extra markers to copy. */
165
      if (++argn >= argc)	/* advance to next argument */
166
	usage();
167
      if (keymatch(argv[argn], "none", 1)) {
168
	copyoption = JCOPYOPT_NONE;
169
      } else if (keymatch(argv[argn], "comments", 1)) {
170
	copyoption = JCOPYOPT_COMMENTS;
171
      } else if (keymatch(argv[argn], "all", 1)) {
172
	copyoption = JCOPYOPT_ALL;
173
      } else
174
	usage();
175
 
176
    } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) {
177
      /* Enable debug printouts. */
178
      /* On first -d, print version identification */
179
      static boolean printed_version = FALSE;
180
 
181
      if (! printed_version) {
182
	fprintf(stderr, "Independent JPEG Group's JPEGTRAN, version %s\n%s\n",
183
		JVERSION, JCOPYRIGHT);
184
	printed_version = TRUE;
185
      }
186
      cinfo->err->trace_level++;
187
 
188
    } else if (keymatch(arg, "flip", 1)) {
189
      /* Mirror left-right or top-bottom. */
190
      if (++argn >= argc)	/* advance to next argument */
191
	usage();
192
      if (keymatch(argv[argn], "horizontal", 1))
193
	select_transform(JXFORM_FLIP_H);
194
      else if (keymatch(argv[argn], "vertical", 1))
195
	select_transform(JXFORM_FLIP_V);
196
      else
197
	usage();
198
 
199
    } else if (keymatch(arg, "grayscale", 1) || keymatch(arg, "greyscale",1)) {
200
      /* Force to grayscale. */
201
#if TRANSFORMS_SUPPORTED
202
      transformoption.force_grayscale = TRUE;
203
#else
204
      select_transform(JXFORM_NONE);	/* force an error */
205
#endif
206
 
207
    } else if (keymatch(arg, "maxmemory", 3)) {
208
      /* Maximum memory in Kb (or Mb with 'm'). */
209
      long lval;
210
      char ch = 'x';
211
 
212
      if (++argn >= argc)	/* advance to next argument */
213
	usage();
214
      if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
215
	usage();
216
      if (ch == 'm' || ch == 'M')
217
	lval *= 1000L;
218
      cinfo->mem->max_memory_to_use = lval * 1000L;
219
 
220
    } else if (keymatch(arg, "optimize", 1) || keymatch(arg, "optimise", 1)) {
221
      /* Enable entropy parm optimization. */
222
#ifdef ENTROPY_OPT_SUPPORTED
223
      cinfo->optimize_coding = TRUE;
224
#else
225
      fprintf(stderr, "%s: sorry, entropy optimization was not compiled\n",
226
	      progname);
227
      exit(EXIT_FAILURE);
228
#endif
229
 
230
    } else if (keymatch(arg, "outfile", 4)) {
231
      /* Set output file name. */
232
      if (++argn >= argc)	/* advance to next argument */
233
	usage();
234
      outfilename = argv[argn];	/* save it away for later use */
235
 
236
    } else if (keymatch(arg, "progressive", 1)) {
237
      /* Select simple progressive mode. */
238
#ifdef C_PROGRESSIVE_SUPPORTED
239
      simple_progressive = TRUE;
240
      /* We must postpone execution until num_components is known. */
241
#else
242
      fprintf(stderr, "%s: sorry, progressive output was not compiled\n",
243
	      progname);
244
      exit(EXIT_FAILURE);
245
#endif
246
 
247
    } else if (keymatch(arg, "restart", 1)) {
248
      /* Restart interval in MCU rows (or in MCUs with 'b'). */
249
      long lval;
250
      char ch = 'x';
251
 
252
      if (++argn >= argc)	/* advance to next argument */
253
	usage();
254
      if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
255
	usage();
256
      if (lval < 0 || lval > 65535L)
257
	usage();
258
      if (ch == 'b' || ch == 'B') {
259
	cinfo->restart_interval = (unsigned int) lval;
260
	cinfo->restart_in_rows = 0; /* else prior '-restart n' overrides me */
261
      } else {
262
	cinfo->restart_in_rows = (int) lval;
263
	/* restart_interval will be computed during startup */
264
      }
265
 
266
    } else if (keymatch(arg, "rotate", 2)) {
267
      /* Rotate 90, 180, or 270 degrees (measured clockwise). */
268
      if (++argn >= argc)	/* advance to next argument */
269
	usage();
270
      if (keymatch(argv[argn], "90", 2))
271
	select_transform(JXFORM_ROT_90);
272
      else if (keymatch(argv[argn], "180", 3))
273
	select_transform(JXFORM_ROT_180);
274
      else if (keymatch(argv[argn], "270", 3))
275
	select_transform(JXFORM_ROT_270);
276
      else
277
	usage();
278
 
279
    } else if (keymatch(arg, "scans", 1)) {
280
      /* Set scan script. */
281
#ifdef C_MULTISCAN_FILES_SUPPORTED
282
      if (++argn >= argc)	/* advance to next argument */
283
	usage();
284
      scansarg = argv[argn];
285
      /* We must postpone reading the file in case -progressive appears. */
286
#else
287
      fprintf(stderr, "%s: sorry, multi-scan output was not compiled\n",
288
	      progname);
289
      exit(EXIT_FAILURE);
290
#endif
291
 
292
    } else if (keymatch(arg, "transpose", 1)) {
293
      /* Transpose (across UL-to-LR axis). */
294
      select_transform(JXFORM_TRANSPOSE);
295
 
296
    } else if (keymatch(arg, "transverse", 6)) {
297
      /* Transverse transpose (across UR-to-LL axis). */
298
      select_transform(JXFORM_TRANSVERSE);
299
 
300
    } else if (keymatch(arg, "trim", 3)) {
301
      /* Trim off any partial edge MCUs that the transform can't handle. */
302
      transformoption.trim = TRUE;
303
 
304
    } else {
305
      usage();			/* bogus switch */
306
    }
307
  }
308
 
309
  /* Post-switch-scanning cleanup */
310
 
311
  if (for_real) {
312
 
313
#ifdef C_PROGRESSIVE_SUPPORTED
314
    if (simple_progressive)	/* process -progressive; -scans can override */
315
      jpeg_simple_progression(cinfo);
316
#endif
317
 
318
#ifdef C_MULTISCAN_FILES_SUPPORTED
319
    if (scansarg != NULL)	/* process -scans if it was present */
320
      if (! read_scan_script(cinfo, scansarg))
321
	usage();
322
#endif
323
  }
324
 
325
  return argn;			/* return index of next arg (file name) */
326
}
327
 
328
 
329
/*
330
 * The main program.
331
 */
332
 
333
int
334
main (int argc, char **argv)
335
{
336
  struct jpeg_decompress_struct srcinfo;
337
  struct jpeg_compress_struct dstinfo;
338
  struct jpeg_error_mgr jsrcerr, jdsterr;
339
#ifdef PROGRESS_REPORT
340
  struct cdjpeg_progress_mgr progress;
341
#endif
342
  jvirt_barray_ptr * src_coef_arrays;
343
  jvirt_barray_ptr * dst_coef_arrays;
344
  int file_index;
345
  FILE * input_file;
346
  FILE * output_file;
347
 
348
  /* On Mac, fetch a command line. */
349
#ifdef USE_CCOMMAND
350
  argc = ccommand(&argv);
351
#endif
352
 
353
  progname = argv[0];
354
  if (progname == NULL || progname[0] == 0)
355
    progname = "jpegtran";	/* in case C library doesn't provide it */
356
 
357
  /* Initialize the JPEG decompression object with default error handling. */
358
  srcinfo.err = jpeg_std_error(&jsrcerr);
359
  jpeg_create_decompress(&srcinfo);
360
  /* Initialize the JPEG compression object with default error handling. */
361
  dstinfo.err = jpeg_std_error(&jdsterr);
362
  jpeg_create_compress(&dstinfo);
363
 
364
  /* Now safe to enable signal catcher.
365
   * Note: we assume only the decompression object will have virtual arrays.
366
   */
367
#ifdef NEED_SIGNAL_CATCHER
368
  enable_signal_catcher((j_common_ptr) &srcinfo);
369
#endif
370
 
371
  /* Scan command line to find file names.
372
   * It is convenient to use just one switch-parsing routine, but the switch
373
   * values read here are mostly ignored; we will rescan the switches after
374
   * opening the input file.  Also note that most of the switches affect the
375
   * destination JPEG object, so we parse into that and then copy over what
376
   * needs to affects the source too.
377
   */
378
 
379
  file_index = parse_switches(&dstinfo, argc, argv, 0, FALSE);
380
  jsrcerr.trace_level = jdsterr.trace_level;
381
  srcinfo.mem->max_memory_to_use = dstinfo.mem->max_memory_to_use;
382
 
383
#ifdef TWO_FILE_COMMANDLINE
384
  /* Must have either -outfile switch or explicit output file name */
385
  if (outfilename == NULL) {
386
    if (file_index != argc-2) {
387
      fprintf(stderr, "%s: must name one input and one output file\n",
388
	      progname);
389
      usage();
390
    }
391
    outfilename = argv[file_index+1];
392
  } else {
393
    if (file_index != argc-1) {
394
      fprintf(stderr, "%s: must name one input and one output file\n",
395
	      progname);
396
      usage();
397
    }
398
  }
399
#else
400
  /* Unix style: expect zero or one file name */
401
  if (file_index < argc-1) {
402
    fprintf(stderr, "%s: only one input file\n", progname);
403
    usage();
404
  }
405
#endif /* TWO_FILE_COMMANDLINE */
406
 
407
  /* Open the input file. */
408
  if (file_index < argc) {
409
    if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) {
410
      fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]);
411
      exit(EXIT_FAILURE);
412
    }
413
  } else {
414
    /* default input file is stdin */
415
    input_file = read_stdin();
416
  }
417
 
418
  /* Open the output file. */
419
  if (outfilename != NULL) {
420
    if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) {
421
      fprintf(stderr, "%s: can't open %s\n", progname, outfilename);
422
      exit(EXIT_FAILURE);
423
    }
424
  } else {
425
    /* default output file is stdout */
426
    output_file = write_stdout();
427
  }
428
 
429
#ifdef PROGRESS_REPORT
430
  start_progress_monitor((j_common_ptr) &dstinfo, &progress);
431
#endif
432
 
433
  /* Specify data source for decompression */
434
  jpeg_stdio_src(&srcinfo, input_file);
435
 
436
  /* Enable saving of extra markers that we want to copy */
437
  jcopy_markers_setup(&srcinfo, copyoption);
438
 
439
  /* Read file header */
440
  (void) jpeg_read_header(&srcinfo, TRUE);
441
 
442
  /* Any space needed by a transform option must be requested before
443
   * jpeg_read_coefficients so that memory allocation will be done right.
444
   */
445
#if TRANSFORMS_SUPPORTED
446
  jtransform_request_workspace(&srcinfo, &transformoption);
447
#endif
448
 
449
  /* Read source file as DCT coefficients */
450
  src_coef_arrays = jpeg_read_coefficients(&srcinfo);
451
 
452
  /* Initialize destination compression parameters from source values */
453
  jpeg_copy_critical_parameters(&srcinfo, &dstinfo);
454
 
455
  /* Adjust destination parameters if required by transform options;
456
   * also find out which set of coefficient arrays will hold the output.
457
   */
458
#if TRANSFORMS_SUPPORTED
459
  dst_coef_arrays = jtransform_adjust_parameters(&srcinfo, &dstinfo,
460
						 src_coef_arrays,
461
						 &transformoption);
462
#else
463
  dst_coef_arrays = src_coef_arrays;
464
#endif
465
 
466
  /* Adjust default compression parameters by re-parsing the options */
467
  file_index = parse_switches(&dstinfo, argc, argv, 0, TRUE);
468
 
469
  /* Specify data destination for compression */
470
  jpeg_stdio_dest(&dstinfo, output_file);
471
 
472
  /* Start compressor (note no image data is actually written here) */
473
  jpeg_write_coefficients(&dstinfo, dst_coef_arrays);
474
 
475
  /* Copy to the output file any extra markers that we want to preserve */
476
  jcopy_markers_execute(&srcinfo, &dstinfo, copyoption);
477
 
478
  /* Execute image transformation, if any */
479
#if TRANSFORMS_SUPPORTED
480
  jtransform_execute_transformation(&srcinfo, &dstinfo,
481
				    src_coef_arrays,
482
				    &transformoption);
483
#endif
484
 
485
  /* Finish compression and release memory */
486
  jpeg_finish_compress(&dstinfo);
487
  jpeg_destroy_compress(&dstinfo);
488
  (void) jpeg_finish_decompress(&srcinfo);
489
  jpeg_destroy_decompress(&srcinfo);
490
 
491
  /* Close files, if we opened them */
492
  if (input_file != stdin)
493
    fclose(input_file);
494
  if (output_file != stdout)
495
    fclose(output_file);
496
 
497
#ifdef PROGRESS_REPORT
498
  end_progress_monitor((j_common_ptr) &dstinfo);
499
#endif
500
 
501
  /* All done. */
502
  exit(jsrcerr.num_warnings + jdsterr.num_warnings ?EXIT_WARNING:EXIT_SUCCESS);
503
  return 0;			/* suppress no-return-value warnings */
504
}