Merge branch 'upstream' into tizen_base
[platform/upstream/libjpeg-turbo.git] / example.c
1 /*
2  * example.c
3  *
4  * This file was part of the Independent JPEG Group's software.
5  * Copyright (C) 1992-1996, Thomas G. Lane.
6  * libjpeg-turbo Modifications:
7  * Copyright (C) 2017, 2019, 2022-2023, D. R. Commander.
8  * For conditions of distribution and use, see the accompanying README.ijg
9  * file.
10  *
11  * This file illustrates how to use the IJG code as a subroutine library
12  * to read or write JPEG image files with 8-bit or 12-bit data precision.  You
13  * should look at this code in conjunction with the documentation file
14  * libjpeg.txt.
15  *
16  * We present these routines in the same coding style used in the JPEG code
17  * (ANSI function definitions, etc); but you are of course free to code your
18  * routines in a different style if you prefer.
19  */
20
21 /* First-time users of libjpeg-turbo might be better served by looking at
22  * tjexample.c, which uses the more straightforward TurboJPEG API.  Note that
23  * this example, like cjpeg and djpeg, interleaves disk I/O with JPEG
24  * compression/decompression, so it is not suitable for benchmarking purposes.
25  */
26
27 #ifdef _MSC_VER
28 #define _CRT_SECURE_NO_DEPRECATE
29 #endif
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #ifdef _WIN32
36 #define strcasecmp  stricmp
37 #define strncasecmp  strnicmp
38 #endif
39
40 /*
41  * Include file for users of JPEG library.
42  * You will need to have included system headers that define at least
43  * the typedefs FILE and size_t before you can include jpeglib.h.
44  * (stdio.h is sufficient on ANSI-conforming systems.)
45  * You may also wish to include "jerror.h".
46  */
47
48 #include "jpeglib.h"
49 #include "jerror.h"
50
51 /*
52  * <setjmp.h> is used for the optional error recovery mechanism shown in
53  * the second part of the example.
54  */
55
56 #include <setjmp.h>
57
58
59
60 /******************** JPEG COMPRESSION SAMPLE INTERFACE *******************/
61
62 /* This half of the example shows how to feed data into the JPEG compressor.
63  * We present a minimal version that does not worry about refinements such
64  * as error recovery (the JPEG code will just exit() if it gets an error).
65  */
66
67
68 /*
69  * IMAGE DATA FORMATS:
70  *
71  * The standard input image format is a rectangular array of pixels, with
72  * each pixel having the same number of "component" values (color channels).
73  * Each pixel row is an array of JSAMPLEs (which typically are unsigned chars)
74  * or J12SAMPLEs (which typically are shorts).  If you are working with color
75  * data, then the color values for each pixel must be adjacent in the row; for
76  * example, R,G,B,R,G,B,R,G,B,... for 24-bit RGB color.
77  *
78  * For this example, we'll assume that this data structure matches the way
79  * our application has stored the image in memory, so we can just pass a
80  * pointer to our image buffer.  In particular, let's say that the image is
81  * RGB color and is described by:
82  */
83
84 #define WIDTH  640              /* Number of columns in image */
85 #define HEIGHT  480             /* Number of rows in image */
86
87
88 /*
89  * Sample routine for JPEG compression.  We assume that the target file name,
90  * a compression quality factor, and a data precision are passed in.
91  */
92
93 METHODDEF(void)
94 write_JPEG_file(char *filename, int quality, int data_precision)
95 {
96   /* This struct contains the JPEG compression parameters and pointers to
97    * working space (which is allocated as needed by the JPEG library).
98    * It is possible to have several such structures, representing multiple
99    * compression/decompression processes, in existence at once.  We refer
100    * to any one struct (and its associated working data) as a "JPEG object".
101    */
102   struct jpeg_compress_struct cinfo;
103   /* This struct represents a JPEG error handler.  It is declared separately
104    * because applications often want to supply a specialized error handler
105    * (see the second half of this file for an example).  But here we just
106    * take the easy way out and use the standard error handler, which will
107    * print a message on stderr and call exit() if compression fails.
108    * Note that this struct must live as long as the main JPEG parameter
109    * struct, to avoid dangling-pointer problems.
110    */
111   struct jpeg_error_mgr jerr;
112   /* More stuff */
113   FILE *outfile;                /* target file */
114   JSAMPARRAY image_buffer = NULL;
115                                 /* Points to large array of R,G,B-order data */
116   JSAMPROW row_pointer[1];      /* pointer to JSAMPLE row[s] */
117   J12SAMPARRAY image_buffer12 = NULL;
118                                 /* Points to large array of R,G,B-order 12-bit
119                                    data */
120   J12SAMPROW row_pointer12[1];  /* pointer to J12SAMPLE row[s] */
121   int row_stride;               /* physical row width in image buffer */
122   int row, col;
123
124   /* Step 1: allocate and initialize JPEG compression object */
125
126   /* We have to set up the error handler first, in case the initialization
127    * step fails.  (Unlikely, but it could happen if you are out of memory.)
128    * This routine fills in the contents of struct jerr, and returns jerr's
129    * address which we place into the link field in cinfo.
130    */
131   cinfo.err = jpeg_std_error(&jerr);
132   /* Now we can initialize the JPEG compression object. */
133   jpeg_create_compress(&cinfo);
134
135   /* Step 2: specify data destination (eg, a file) */
136   /* Note: steps 2 and 3 can be done in either order. */
137
138   /* Here we use the library-supplied code to send compressed data to a
139    * stdio stream.  You can also write your own code to do something else.
140    * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
141    * requires it in order to write binary files.
142    */
143   if ((outfile = fopen(filename, "wb")) == NULL)
144     ERREXIT(&cinfo, JERR_FILE_WRITE);
145   jpeg_stdio_dest(&cinfo, outfile);
146
147   /* Step 3: set parameters for compression */
148
149   /* First we supply a description of the input image.
150    * Four fields of the cinfo struct must be filled in:
151    */
152   cinfo.image_width = WIDTH;            /* image width and height, in pixels */
153   cinfo.image_height = HEIGHT;
154   cinfo.input_components = 3;           /* # of color components per pixel */
155   cinfo.in_color_space = JCS_RGB;       /* colorspace of input image */
156   cinfo.data_precision = data_precision; /* data precision of input image */
157   /* Now use the library's routine to set default compression parameters.
158    * (You must set at least cinfo.in_color_space before calling this,
159    * since the defaults depend on the source color space.)
160    */
161   jpeg_set_defaults(&cinfo);
162   /* Now you can set any non-default parameters you wish to.
163    * Here we just illustrate the use of quality (quantization table) scaling:
164    */
165   jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
166   /* Use 4:4:4 subsampling (default is 4:2:0) */
167   cinfo.comp_info[0].h_samp_factor = cinfo.comp_info[0].v_samp_factor = 1;
168
169   /* Step 4: Start compressor */
170
171   /* TRUE ensures that we will write a complete interchange-JPEG file.
172    * Pass TRUE unless you are very sure of what you're doing.
173    */
174   jpeg_start_compress(&cinfo, TRUE);
175
176   /* Step 5: allocate and initialize image buffer */
177
178   row_stride = WIDTH * 3;       /* J[12]SAMPLEs per row in image_buffer */
179   /* Make a sample array that will go away when done with image.  Note that,
180    * for the purposes of this example, we could also create a one-row-high
181    * sample array and initialize it for each successive scanline written in the
182    * scanline loop below.
183    */
184   if (cinfo.data_precision == 12) {
185     image_buffer12 = (J12SAMPARRAY)(*cinfo.mem->alloc_sarray)
186       ((j_common_ptr)&cinfo, JPOOL_IMAGE, row_stride, HEIGHT);
187
188     /* Initialize image buffer with a repeating pattern */
189     for (row = 0; row < HEIGHT; row++) {
190       for (col = 0; col < WIDTH; col++) {
191         image_buffer12[row][col * 3] =
192           (col * (MAXJ12SAMPLE + 1) / WIDTH) % (MAXJ12SAMPLE + 1);
193         image_buffer12[row][col * 3 + 1] =
194           (row * (MAXJ12SAMPLE + 1) / HEIGHT) % (MAXJ12SAMPLE + 1);
195         image_buffer12[row][col * 3 + 2] =
196           (row * (MAXJ12SAMPLE + 1) / HEIGHT +
197            col * (MAXJ12SAMPLE + 1) / WIDTH) % (MAXJ12SAMPLE + 1);
198       }
199     }
200   } else {
201     image_buffer = (*cinfo.mem->alloc_sarray)
202       ((j_common_ptr)&cinfo, JPOOL_IMAGE, row_stride, HEIGHT);
203
204     for (row = 0; row < HEIGHT; row++) {
205       for (col = 0; col < WIDTH; col++) {
206         image_buffer[row][col * 3] =
207           (col * (MAXJSAMPLE + 1) / WIDTH) % (MAXJSAMPLE + 1);
208         image_buffer[row][col * 3 + 1] =
209           (row * (MAXJSAMPLE + 1) / HEIGHT) % (MAXJSAMPLE + 1);
210         image_buffer[row][col * 3 + 2] =
211           (row * (MAXJSAMPLE + 1) / HEIGHT + col * (MAXJSAMPLE + 1) / WIDTH) %
212           (MAXJSAMPLE + 1);
213       }
214     }
215   }
216
217   /* Step 6: while (scan lines remain to be written) */
218   /*           jpeg_write_scanlines(...); */
219
220   /* Here we use the library's state variable cinfo.next_scanline as the
221    * loop counter, so that we don't have to keep track ourselves.
222    * To keep things simple, we pass one scanline per call; you can pass
223    * more if you wish, though.
224    */
225   if (cinfo.data_precision == 12) {
226     while (cinfo.next_scanline < cinfo.image_height) {
227       /* jpeg12_write_scanlines expects an array of pointers to scanlines.
228        * Here the array is only one element long, but you could pass
229        * more than one scanline at a time if that's more convenient.
230        */
231       row_pointer12[0] = image_buffer12[cinfo.next_scanline];
232       (void)jpeg12_write_scanlines(&cinfo, row_pointer12, 1);
233     }
234   } else {
235     while (cinfo.next_scanline < cinfo.image_height) {
236       /* jpeg_write_scanlines expects an array of pointers to scanlines.
237        * Here the array is only one element long, but you could pass
238        * more than one scanline at a time if that's more convenient.
239        */
240       row_pointer[0] = image_buffer[cinfo.next_scanline];
241       (void)jpeg_write_scanlines(&cinfo, row_pointer, 1);
242     }
243   }
244
245   /* Step 7: Finish compression */
246
247   jpeg_finish_compress(&cinfo);
248   /* After finish_compress, we can close the output file. */
249   fclose(outfile);
250
251   /* Step 8: release JPEG compression object */
252
253   /* This is an important step since it will release a good deal of memory. */
254   jpeg_destroy_compress(&cinfo);
255
256   /* And we're done! */
257 }
258
259
260 /*
261  * SOME FINE POINTS:
262  *
263  * In the above loop, we ignored the return value of jpeg_write_scanlines,
264  * which is the number of scanlines actually written.  We could get away
265  * with this because we were only relying on the value of cinfo.next_scanline,
266  * which will be incremented correctly.  If you maintain additional loop
267  * variables then you should be careful to increment them properly.
268  * Actually, for output to a stdio stream you needn't worry, because
269  * then jpeg_write_scanlines will write all the lines passed (or else exit
270  * with a fatal error).  Partial writes can only occur if you use a data
271  * destination module that can demand suspension of the compressor.
272  * (If you don't know what that's for, you don't need it.)
273  *
274  * If the compressor requires full-image buffers (for entropy-coding
275  * optimization or a multi-scan JPEG file), it will create temporary
276  * files for anything that doesn't fit within the maximum-memory setting.
277  * (Note that temp files are NOT needed if you use the default parameters.)
278  * On some systems you may need to set up a signal handler to ensure that
279  * temporary files are deleted if the program is interrupted.  See libjpeg.txt.
280  *
281  * Scanlines MUST be supplied in top-to-bottom order if you want your JPEG
282  * files to be compatible with everyone else's.  If you cannot readily read
283  * your data in that order, you'll need an intermediate array to hold the
284  * image.  See rdtarga.c or rdbmp.c for examples of handling bottom-to-top
285  * source data using the JPEG code's internal virtual-array mechanisms.
286  */
287
288
289
290 /******************** JPEG DECOMPRESSION SAMPLE INTERFACE *******************/
291
292 /* This half of the example shows how to read data from the JPEG decompressor.
293  * It's a bit more refined than the above, in that we show:
294  *   (a) how to modify the JPEG library's standard error-reporting behavior;
295  *   (b) how to allocate workspace using the library's memory manager.
296  *
297  * Just to make this example a little different from the first one, we'll
298  * assume that we do not intend to put the whole image into an in-memory
299  * buffer, but to send it line-by-line someplace else.  We need a one-
300  * scanline-high JSAMPLE or J12SAMPLE array as a work buffer, and we will let
301  * the JPEG memory manager allocate it for us.  This approach is actually quite
302  * useful because we don't need to remember to deallocate the buffer
303  * separately: it will go away automatically when the JPEG object is cleaned
304  * up.
305  */
306
307
308 /*
309  * ERROR HANDLING:
310  *
311  * The JPEG library's standard error handler (jerror.c) is divided into
312  * several "methods" which you can override individually.  This lets you
313  * adjust the behavior without duplicating a lot of code, which you might
314  * have to update with each future release.
315  *
316  * Our example here shows how to override the "error_exit" method so that
317  * control is returned to the library's caller when a fatal error occurs,
318  * rather than calling exit() as the standard error_exit method does.
319  *
320  * We use C's setjmp/longjmp facility to return control.  This means that the
321  * routine which calls the JPEG library must first execute a setjmp() call to
322  * establish the return point.  We want the replacement error_exit to do a
323  * longjmp().  But we need to make the setjmp buffer accessible to the
324  * error_exit routine.  To do this, we make a private extension of the
325  * standard JPEG error handler object.  (If we were using C++, we'd say we
326  * were making a subclass of the regular error handler.)
327  *
328  * Here's the extended error handler struct:
329  */
330
331 struct my_error_mgr {
332   struct jpeg_error_mgr pub;    /* "public" fields */
333
334   jmp_buf setjmp_buffer;        /* for return to caller */
335 };
336
337 typedef struct my_error_mgr *my_error_ptr;
338
339 /*
340  * Here's the routine that will replace the standard error_exit method:
341  */
342
343 METHODDEF(void)
344 my_error_exit(j_common_ptr cinfo)
345 {
346   /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
347   my_error_ptr myerr = (my_error_ptr)cinfo->err;
348
349   /* Always display the message. */
350   /* We could postpone this until after returning, if we chose. */
351   (*cinfo->err->output_message) (cinfo);
352
353   /* Return control to the setjmp point */
354   longjmp(myerr->setjmp_buffer, 1);
355 }
356
357
358 METHODDEF(int) do_read_JPEG_file(struct jpeg_decompress_struct *cinfo,
359                                  char *infilename, char *outfilename);
360
361 /*
362  * Sample routine for JPEG decompression.  We assume that the source file name
363  * is passed in.  We want to return 1 on success, 0 on error.
364  */
365
366 METHODDEF(int)
367 read_JPEG_file(char *infilename, char *outfilename)
368 {
369   /* This struct contains the JPEG decompression parameters and pointers to
370    * working space (which is allocated as needed by the JPEG library).
371    */
372   struct jpeg_decompress_struct cinfo;
373
374   return do_read_JPEG_file(&cinfo, infilename, outfilename);
375 }
376
377 /*
378  * We call the libjpeg API from within a separate function, because modifying
379  * the local non-volatile jpeg_decompress_struct instance below the setjmp()
380  * return point and then accessing the instance after setjmp() returns would
381  * result in undefined behavior that may potentially overwrite all or part of
382  * the structure.
383  */
384
385 METHODDEF(int)
386 do_read_JPEG_file(struct jpeg_decompress_struct *cinfo, char *infilename,
387                   char *outfilename)
388 {
389   /* We use our private extension JPEG error handler.
390    * Note that this struct must live as long as the main JPEG parameter
391    * struct, to avoid dangling-pointer problems.
392    */
393   struct my_error_mgr jerr;
394   /* More stuff */
395   FILE *infile;                 /* source file */
396   FILE *outfile;                /* output file */
397   JSAMPARRAY buffer = NULL;     /* Output row buffer */
398   J12SAMPARRAY buffer12 = NULL; /* 12-bit output row buffer */
399   int col;
400   int row_stride;               /* physical row width in output buffer */
401   int little_endian = 1;
402
403   /* In this example we want to open the input and output files before doing
404    * anything else, so that the setjmp() error recovery below can assume the
405    * files are open.
406    *
407    * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
408    * requires it in order to read/write binary files.
409    */
410
411   if ((infile = fopen(infilename, "rb")) == NULL) {
412     fprintf(stderr, "can't open %s\n", infilename);
413     return 0;
414   }
415   if ((outfile = fopen(outfilename, "wb")) == NULL) {
416     fprintf(stderr, "can't open %s\n", outfilename);
417     fclose(infile);
418     return 0;
419   }
420
421   /* Step 1: allocate and initialize JPEG decompression object */
422
423   /* We set up the normal JPEG error routines, then override error_exit. */
424   cinfo->err = jpeg_std_error(&jerr.pub);
425   jerr.pub.error_exit = my_error_exit;
426   /* Establish the setjmp return context for my_error_exit to use. */
427   if (setjmp(jerr.setjmp_buffer)) {
428     /* If we get here, the JPEG code has signaled an error.
429      * We need to clean up the JPEG object, close the input file, and return.
430      */
431     jpeg_destroy_decompress(cinfo);
432     fclose(infile);
433     fclose(outfile);
434     return 0;
435   }
436   /* Now we can initialize the JPEG decompression object. */
437   jpeg_create_decompress(cinfo);
438
439   /* Step 2: specify data source (eg, a file) */
440
441   jpeg_stdio_src(cinfo, infile);
442
443   /* Step 3: read file parameters with jpeg_read_header() */
444
445   (void)jpeg_read_header(cinfo, TRUE);
446   /* We can ignore the return value from jpeg_read_header since
447    *   (a) suspension is not possible with the stdio data source, and
448    *   (b) we passed TRUE to reject a tables-only JPEG file as an error.
449    * See libjpeg.txt for more info.
450    */
451
452   /* emit header for raw PPM format */
453   fprintf(outfile, "P6\n%d %d\n%d\n", WIDTH, HEIGHT,
454           cinfo->data_precision == 12 ? MAXJ12SAMPLE : MAXJSAMPLE);
455
456   /* Step 4: set parameters for decompression */
457
458   /* In this example, we don't need to change any of the defaults set by
459    * jpeg_read_header(), so we do nothing here.
460    */
461
462   /* Step 5: Start decompressor */
463
464   (void)jpeg_start_decompress(cinfo);
465   /* We can ignore the return value since suspension is not possible
466    * with the stdio data source.
467    */
468
469   /* We may need to do some setup of our own at this point before reading
470    * the data.  After jpeg_start_decompress() we have the correct scaled
471    * output image dimensions available, as well as the output colormap
472    * if we asked for color quantization.
473    * In this example, we need to make an output work buffer of the right size.
474    */
475   /* Samples per row in output buffer */
476   row_stride = cinfo->output_width * cinfo->output_components;
477   /* Make a one-row-high sample array that will go away when done with image */
478   if (cinfo->data_precision == 12)
479     buffer12 = (J12SAMPARRAY)(*cinfo->mem->alloc_sarray)
480       ((j_common_ptr)cinfo, JPOOL_IMAGE, row_stride, 1);
481   else
482     buffer = (*cinfo->mem->alloc_sarray)
483       ((j_common_ptr)cinfo, JPOOL_IMAGE, row_stride, 1);
484
485   /* Step 6: while (scan lines remain to be read) */
486   /*           jpeg_read_scanlines(...); */
487
488   /* Here we use the library's state variable cinfo->output_scanline as the
489    * loop counter, so that we don't have to keep track ourselves.
490    */
491   if (cinfo->data_precision == 12) {
492     while (cinfo->output_scanline < cinfo->output_height) {
493       /* jpeg12_read_scanlines expects an array of pointers to scanlines.
494        * Here the array is only one element long, but you could ask for
495        * more than one scanline at a time if that's more convenient.
496        */
497       (void)jpeg12_read_scanlines(cinfo, buffer12, 1);
498       if (*(char *)&little_endian == 1) {
499         /* Swap MSB and LSB in each sample */
500         for (col = 0; col < row_stride; col++)
501           buffer12[0][col] = ((buffer12[0][col] & 0xFF) << 8) |
502                              ((buffer12[0][col] >> 8) & 0xFF);
503       }
504       fwrite(buffer12[0], 1, row_stride * sizeof(J12SAMPLE), outfile);
505     }
506   } else {
507     while (cinfo->output_scanline < cinfo->output_height) {
508       /* jpeg_read_scanlines expects an array of pointers to scanlines.
509        * Here the array is only one element long, but you could ask for
510        * more than one scanline at a time if that's more convenient.
511        */
512       (void)jpeg_read_scanlines(cinfo, buffer, 1);
513       fwrite(buffer[0], 1, row_stride, outfile);
514     }
515   }
516
517   /* Step 7: Finish decompression */
518
519   (void)jpeg_finish_decompress(cinfo);
520   /* We can ignore the return value since suspension is not possible
521    * with the stdio data source.
522    */
523
524   /* Step 8: Release JPEG decompression object */
525
526   /* This is an important step since it will release a good deal of memory. */
527   jpeg_destroy_decompress(cinfo);
528
529   /* After finish_decompress, we can close the input and output files.
530    * Here we postpone it until after no more JPEG errors are possible,
531    * so as to simplify the setjmp error logic above.  (Actually, I don't
532    * think that jpeg_destroy can do an error exit, but why assume anything...)
533    */
534   fclose(infile);
535   fclose(outfile);
536
537   /* At this point you may want to check to see whether any corrupt-data
538    * warnings occurred (test whether jerr.pub.num_warnings is nonzero).
539    */
540
541   /* And we're done! */
542   return 1;
543 }
544
545
546 /*
547  * SOME FINE POINTS:
548  *
549  * In the above code, we ignored the return value of jpeg_read_scanlines,
550  * which is the number of scanlines actually read.  We could get away with
551  * this because we asked for only one line at a time and we weren't using
552  * a suspending data source.  See libjpeg.txt for more info.
553  *
554  * We cheated a bit by calling alloc_sarray() after jpeg_start_decompress();
555  * we should have done it beforehand to ensure that the space would be
556  * counted against the JPEG max_memory setting.  In some systems the above
557  * code would risk an out-of-memory error.  However, in general we don't
558  * know the output image dimensions before jpeg_start_decompress(), unless we
559  * call jpeg_calc_output_dimensions().  See libjpeg.txt for more about this.
560  *
561  * Scanlines are returned in the same order as they appear in the JPEG file,
562  * which is standardly top-to-bottom.  If you must emit data bottom-to-top,
563  * you can use one of the virtual arrays provided by the JPEG memory manager
564  * to invert the data.  See wrbmp.c for an example.
565  *
566  * As with compression, some operating modes may require temporary files.
567  * On some systems you may need to set up a signal handler to ensure that
568  * temporary files are deleted if the program is interrupted.  See libjpeg.txt.
569  */
570
571
572 LOCAL(void)
573 usage(const char *progname)
574 {
575   fprintf(stderr, "usage: %s compress [switches] outputfile[.jpg]\n",
576           progname);
577   fprintf(stderr, "       %s decompress inputfile[.jpg] outputfile[.ppm]\n",
578           progname);
579   fprintf(stderr, "Switches (names may be abbreviated):\n");
580   fprintf(stderr, "  -precision N   Create JPEG file with N-bit data precision\n");
581   fprintf(stderr, "                 (N is 8 or 12; default is 8)\n");
582   fprintf(stderr, "  -quality N     Compression quality (0..100; 5-95 is most useful range,\n");
583   fprintf(stderr, "                 default is 75)\n");
584
585   exit(EXIT_FAILURE);
586 }
587
588
589 typedef enum {
590   COMPRESS,
591   DECOMPRESS
592 } EXAMPLE_MODE;
593
594
595 int
596 main(int argc, char **argv)
597 {
598   int argn, quality = 75;
599   int data_precision = 8;
600   EXAMPLE_MODE mode = -1;
601   char *arg, *filename = NULL;
602
603   if (argc < 3)
604     usage(argv[0]);
605
606   if (!strcasecmp(argv[1], "compress"))
607     mode = COMPRESS;
608   else if (!strcasecmp(argv[1], "decompress"))
609     mode = DECOMPRESS;
610   else
611     usage(argv[0]);
612
613   for (argn = 2; argn < argc; argn++) {
614     arg = argv[argn];
615     if (*arg != '-') {
616       filename = arg;
617       /* Not a switch, must be a file name argument */
618       break;                    /* done parsing switches */
619     }
620     arg++;                      /* advance past switch marker character */
621
622     if (!strncasecmp(arg, "p", 1)) {
623       /* Set data precision. */
624       if (++argn >= argc)       /* advance to next argument */
625         usage(argv[0]);
626       if (sscanf(argv[argn], "%d", &data_precision) < 1 ||
627           (data_precision != 8 && data_precision != 12))
628         usage(argv[0]);
629     } else if (!strncasecmp(arg, "q", 1)) {
630       /* Quality rating (quantization table scaling factor). */
631       if (++argn >= argc)       /* advance to next argument */
632         usage(argv[0]);
633       if (sscanf(argv[argn], "%d", &quality) < 1 || quality < 0 ||
634           quality > 100)
635         usage(argv[0]);
636       if (quality < 1)
637         quality = 1;
638     }
639   }
640
641   if (!filename)
642     usage(argv[0]);
643
644   if (mode == COMPRESS)
645     write_JPEG_file(filename, quality, data_precision);
646   else if (mode == DECOMPRESS) {
647     if (argc - argn < 2)
648       usage(argv[0]);
649
650     read_JPEG_file(argv[argn], argv[argn + 1]);
651   }
652
653   return 0;
654 }