• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * rdswitch.c
3  *
4  * This file was part of the Independent JPEG Group's software:
5  * Copyright (C) 1991-1996, Thomas G. Lane.
6  * libjpeg-turbo Modifications:
7  * Copyright (C) 2010, 2018, 2022, D. R. Commander.
8  * For conditions of distribution and use, see the accompanying README.ijg
9  * file.
10  *
11  * This file contains routines to process some of cjpeg's more complicated
12  * command-line switches.  Switches processed here are:
13  *      -qtables file           Read quantization tables from text file
14  *      -scans file             Read scan script from text file
15  *      -quality N[,N,...]      Set quality ratings
16  *      -qslots N[,N,...]       Set component quantization table selectors
17  *      -sample HxV[,HxV,...]   Set component sampling factors
18  */
19 
20 #ifdef _MSC_VER
21 #define _CRT_SECURE_NO_DEPRECATE
22 #endif
23 
24 #include "cdjpeg.h"             /* Common decls for cjpeg/djpeg applications */
25 #include <ctype.h>              /* to declare isdigit(), isspace() */
26 
27 
28 LOCAL(int)
text_getc(FILE * file)29 text_getc(FILE *file)
30 /* Read next char, skipping over any comments (# to end of line) */
31 /* A comment/newline sequence is returned as a newline */
32 {
33   register int ch;
34 
35   ch = getc(file);
36   if (ch == '#') {
37     do {
38       ch = getc(file);
39     } while (ch != '\n' && ch != EOF);
40   }
41   return ch;
42 }
43 
44 
45 LOCAL(boolean)
read_text_integer(FILE * file,long * result,int * termchar)46 read_text_integer(FILE *file, long *result, int *termchar)
47 /* Read an unsigned decimal integer from a file, store it in result */
48 /* Reads one trailing character after the integer; returns it in termchar */
49 {
50   register int ch;
51   register long val;
52 
53   /* Skip any leading whitespace, detect EOF */
54   do {
55     ch = text_getc(file);
56     if (ch == EOF) {
57       *termchar = ch;
58       return FALSE;
59     }
60   } while (isspace(ch));
61 
62   if (!isdigit(ch)) {
63     *termchar = ch;
64     return FALSE;
65   }
66 
67   val = ch - '0';
68   while ((ch = text_getc(file)) != EOF) {
69     if (!isdigit(ch))
70       break;
71     val *= 10;
72     val += ch - '0';
73   }
74   *result = val;
75   *termchar = ch;
76   return TRUE;
77 }
78 
79 
80 #if JPEG_LIB_VERSION < 70
81 static int q_scale_factor[NUM_QUANT_TBLS] = { 100, 100, 100, 100 };
82 #endif
83 
84 GLOBAL(boolean)
read_quant_tables(j_compress_ptr cinfo,char * filename,boolean force_baseline)85 read_quant_tables(j_compress_ptr cinfo, char *filename, boolean force_baseline)
86 /* Read a set of quantization tables from the specified file.
87  * The file is plain ASCII text: decimal numbers with whitespace between.
88  * Comments preceded by '#' may be included in the file.
89  * There may be one to NUM_QUANT_TBLS tables in the file, each of 64 values.
90  * The tables are implicitly numbered 0,1,etc.
91  * NOTE: does not affect the qslots mapping, which will default to selecting
92  * table 0 for luminance (or primary) components, 1 for chrominance components.
93  * You must use -qslots if you want a different component->table mapping.
94  */
95 {
96   FILE *fp;
97   int tblno, i, termchar;
98   long val;
99   unsigned int table[DCTSIZE2];
100 
101   if ((fp = fopen(filename, "r")) == NULL) {
102     fprintf(stderr, "Can't open table file %s\n", filename);
103     return FALSE;
104   }
105   tblno = 0;
106 
107   while (read_text_integer(fp, &val, &termchar)) { /* read 1st element of table */
108     if (tblno >= NUM_QUANT_TBLS) {
109       fprintf(stderr, "Too many tables in file %s\n", filename);
110       fclose(fp);
111       return FALSE;
112     }
113     table[0] = (unsigned int)val;
114     for (i = 1; i < DCTSIZE2; i++) {
115       if (!read_text_integer(fp, &val, &termchar)) {
116         fprintf(stderr, "Invalid table data in file %s\n", filename);
117         fclose(fp);
118         return FALSE;
119       }
120       table[i] = (unsigned int)val;
121     }
122 #if JPEG_LIB_VERSION >= 70
123     jpeg_add_quant_table(cinfo, tblno, table, cinfo->q_scale_factor[tblno],
124                          force_baseline);
125 #else
126     jpeg_add_quant_table(cinfo, tblno, table, q_scale_factor[tblno],
127                          force_baseline);
128 #endif
129     tblno++;
130   }
131 
132   if (termchar != EOF) {
133     fprintf(stderr, "Non-numeric data in file %s\n", filename);
134     fclose(fp);
135     return FALSE;
136   }
137 
138   fclose(fp);
139   return TRUE;
140 }
141 
142 
143 #ifdef C_MULTISCAN_FILES_SUPPORTED
144 
145 LOCAL(boolean)
read_scan_integer(FILE * file,long * result,int * termchar)146 read_scan_integer(FILE *file, long *result, int *termchar)
147 /* Variant of read_text_integer that always looks for a non-space termchar;
148  * this simplifies parsing of punctuation in scan scripts.
149  */
150 {
151   register int ch;
152 
153   if (!read_text_integer(file, result, termchar))
154     return FALSE;
155   ch = *termchar;
156   while (ch != EOF && isspace(ch))
157     ch = text_getc(file);
158   if (isdigit(ch)) {            /* oops, put it back */
159     if (ungetc(ch, file) == EOF)
160       return FALSE;
161     ch = ' ';
162   } else {
163     /* Any separators other than ';' and ':' are ignored;
164      * this allows user to insert commas, etc, if desired.
165      */
166     if (ch != EOF && ch != ';' && ch != ':')
167       ch = ' ';
168   }
169   *termchar = ch;
170   return TRUE;
171 }
172 
173 
174 GLOBAL(boolean)
read_scan_script(j_compress_ptr cinfo,char * filename)175 read_scan_script(j_compress_ptr cinfo, char *filename)
176 /* Read a scan script from the specified text file.
177  * Each entry in the file defines one scan to be emitted.
178  * Entries are separated by semicolons ';'.
179  * An entry contains one to four component indexes,
180  * optionally followed by a colon ':' and four progressive-JPEG parameters.
181  * The component indexes denote which component(s) are to be transmitted
182  * in the current scan.  The first component has index 0.
183  * Sequential JPEG is used if the progressive-JPEG parameters are omitted.
184  * The file is free format text: any whitespace may appear between numbers
185  * and the ':' and ';' punctuation marks.  Also, other punctuation (such
186  * as commas or dashes) can be placed between numbers if desired.
187  * Comments preceded by '#' may be included in the file.
188  * Note: we do very little validity checking here;
189  * jcmaster.c will validate the script parameters.
190  */
191 {
192   FILE *fp;
193   int scanno, ncomps, termchar;
194   long val;
195   jpeg_scan_info *scanptr;
196 #define MAX_SCANS  100          /* quite arbitrary limit */
197   jpeg_scan_info scans[MAX_SCANS];
198 
199   if ((fp = fopen(filename, "r")) == NULL) {
200     fprintf(stderr, "Can't open scan definition file %s\n", filename);
201     return FALSE;
202   }
203   scanptr = scans;
204   scanno = 0;
205 
206   while (read_scan_integer(fp, &val, &termchar)) {
207     if (scanno >= MAX_SCANS) {
208       fprintf(stderr, "Too many scans defined in file %s\n", filename);
209       fclose(fp);
210       return FALSE;
211     }
212     scanptr->component_index[0] = (int)val;
213     ncomps = 1;
214     while (termchar == ' ') {
215       if (ncomps >= MAX_COMPS_IN_SCAN) {
216         fprintf(stderr, "Too many components in one scan in file %s\n",
217                 filename);
218         fclose(fp);
219         return FALSE;
220       }
221       if (!read_scan_integer(fp, &val, &termchar))
222         goto bogus;
223       scanptr->component_index[ncomps] = (int)val;
224       ncomps++;
225     }
226     scanptr->comps_in_scan = ncomps;
227     if (termchar == ':') {
228       if (!read_scan_integer(fp, &val, &termchar) || termchar != ' ')
229         goto bogus;
230       scanptr->Ss = (int)val;
231       if (!read_scan_integer(fp, &val, &termchar) || termchar != ' ')
232         goto bogus;
233       scanptr->Se = (int)val;
234       if (!read_scan_integer(fp, &val, &termchar) || termchar != ' ')
235         goto bogus;
236       scanptr->Ah = (int)val;
237       if (!read_scan_integer(fp, &val, &termchar))
238         goto bogus;
239       scanptr->Al = (int)val;
240     } else {
241       /* set non-progressive parameters */
242       scanptr->Ss = 0;
243       scanptr->Se = DCTSIZE2 - 1;
244       scanptr->Ah = 0;
245       scanptr->Al = 0;
246     }
247     if (termchar != ';' && termchar != EOF) {
248 bogus:
249       fprintf(stderr, "Invalid scan entry format in file %s\n", filename);
250       fclose(fp);
251       return FALSE;
252     }
253     scanptr++, scanno++;
254   }
255 
256   if (termchar != EOF) {
257     fprintf(stderr, "Non-numeric data in file %s\n", filename);
258     fclose(fp);
259     return FALSE;
260   }
261 
262   if (scanno > 0) {
263     /* Stash completed scan list in cinfo structure.
264      * NOTE: for cjpeg's use, JPOOL_IMAGE is the right lifetime for this data,
265      * but if you want to compress multiple images you'd want JPOOL_PERMANENT.
266      */
267     scanptr = (jpeg_scan_info *)
268       (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
269                                   scanno * sizeof(jpeg_scan_info));
270     memcpy(scanptr, scans, scanno * sizeof(jpeg_scan_info));
271     cinfo->scan_info = scanptr;
272     cinfo->num_scans = scanno;
273   }
274 
275   fclose(fp);
276   return TRUE;
277 }
278 
279 #endif /* C_MULTISCAN_FILES_SUPPORTED */
280 
281 
282 #if JPEG_LIB_VERSION < 70
283 /* These are the sample quantization tables given in Annex K (Clause K.1) of
284  * Recommendation ITU-T T.81 (1992) | ISO/IEC 10918-1:1994.
285  * The spec says that the values given produce "good" quality, and
286  * when divided by 2, "very good" quality.
287  */
288 static const unsigned int std_luminance_quant_tbl[DCTSIZE2] = {
289   16,  11,  10,  16,  24,  40,  51,  61,
290   12,  12,  14,  19,  26,  58,  60,  55,
291   14,  13,  16,  24,  40,  57,  69,  56,
292   14,  17,  22,  29,  51,  87,  80,  62,
293   18,  22,  37,  56,  68, 109, 103,  77,
294   24,  35,  55,  64,  81, 104, 113,  92,
295   49,  64,  78,  87, 103, 121, 120, 101,
296   72,  92,  95,  98, 112, 100, 103,  99
297 };
298 static const unsigned int std_chrominance_quant_tbl[DCTSIZE2] = {
299   17,  18,  24,  47,  99,  99,  99,  99,
300   18,  21,  26,  66,  99,  99,  99,  99,
301   24,  26,  56,  99,  99,  99,  99,  99,
302   47,  66,  99,  99,  99,  99,  99,  99,
303   99,  99,  99,  99,  99,  99,  99,  99,
304   99,  99,  99,  99,  99,  99,  99,  99,
305   99,  99,  99,  99,  99,  99,  99,  99,
306   99,  99,  99,  99,  99,  99,  99,  99
307 };
308 
309 
310 LOCAL(void)
jpeg_default_qtables(j_compress_ptr cinfo,boolean force_baseline)311 jpeg_default_qtables(j_compress_ptr cinfo, boolean force_baseline)
312 {
313   jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl, q_scale_factor[0],
314                        force_baseline);
315   jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl, q_scale_factor[1],
316                        force_baseline);
317 }
318 #endif
319 
320 
321 GLOBAL(boolean)
set_quality_ratings(j_compress_ptr cinfo,char * arg,boolean force_baseline)322 set_quality_ratings(j_compress_ptr cinfo, char *arg, boolean force_baseline)
323 /* Process a quality-ratings parameter string, of the form
324  *     N[,N,...]
325  * If there are more q-table slots than parameters, the last value is replicated.
326  */
327 {
328   int val = 75;                 /* default value */
329   int tblno;
330   char ch;
331 
332   for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) {
333     if (*arg) {
334       ch = ',';                 /* if not set by sscanf, will be ',' */
335       if (sscanf(arg, "%d%c", &val, &ch) < 1)
336         return FALSE;
337       if (ch != ',')            /* syntax check */
338         return FALSE;
339       /* Convert user 0-100 rating to percentage scaling */
340 #if JPEG_LIB_VERSION >= 70
341       cinfo->q_scale_factor[tblno] = jpeg_quality_scaling(val);
342 #else
343       q_scale_factor[tblno] = jpeg_quality_scaling(val);
344 #endif
345       while (*arg && *arg++ != ','); /* advance to next segment of arg
346                                         string */
347     } else {
348       /* reached end of parameter, set remaining factors to last value */
349 #if JPEG_LIB_VERSION >= 70
350       cinfo->q_scale_factor[tblno] = jpeg_quality_scaling(val);
351 #else
352       q_scale_factor[tblno] = jpeg_quality_scaling(val);
353 #endif
354     }
355   }
356   jpeg_default_qtables(cinfo, force_baseline);
357   return TRUE;
358 }
359 
360 
361 GLOBAL(boolean)
set_quant_slots(j_compress_ptr cinfo,char * arg)362 set_quant_slots(j_compress_ptr cinfo, char *arg)
363 /* Process a quantization-table-selectors parameter string, of the form
364  *     N[,N,...]
365  * If there are more components than parameters, the last value is replicated.
366  */
367 {
368   int val = 0;                  /* default table # */
369   int ci;
370   char ch;
371 
372   for (ci = 0; ci < MAX_COMPONENTS; ci++) {
373     if (*arg) {
374       ch = ',';                 /* if not set by sscanf, will be ',' */
375       if (sscanf(arg, "%d%c", &val, &ch) < 1)
376         return FALSE;
377       if (ch != ',')            /* syntax check */
378         return FALSE;
379       if (val < 0 || val >= NUM_QUANT_TBLS) {
380         fprintf(stderr, "JPEG quantization tables are numbered 0..%d\n",
381                 NUM_QUANT_TBLS - 1);
382         return FALSE;
383       }
384       cinfo->comp_info[ci].quant_tbl_no = val;
385       while (*arg && *arg++ != ','); /* advance to next segment of arg
386                                         string */
387     } else {
388       /* reached end of parameter, set remaining components to last table */
389       cinfo->comp_info[ci].quant_tbl_no = val;
390     }
391   }
392   return TRUE;
393 }
394 
395 
396 GLOBAL(boolean)
set_sample_factors(j_compress_ptr cinfo,char * arg)397 set_sample_factors(j_compress_ptr cinfo, char *arg)
398 /* Process a sample-factors parameter string, of the form
399  *     HxV[,HxV,...]
400  * If there are more components than parameters, "1x1" is assumed for the rest.
401  */
402 {
403   int ci, val1, val2;
404   char ch1, ch2;
405 
406   for (ci = 0; ci < MAX_COMPONENTS; ci++) {
407     if (*arg) {
408       ch2 = ',';                /* if not set by sscanf, will be ',' */
409       if (sscanf(arg, "%d%c%d%c", &val1, &ch1, &val2, &ch2) < 3)
410         return FALSE;
411       if ((ch1 != 'x' && ch1 != 'X') || ch2 != ',') /* syntax check */
412         return FALSE;
413       if (val1 <= 0 || val1 > 4 || val2 <= 0 || val2 > 4) {
414         fprintf(stderr, "JPEG sampling factors must be 1..4\n");
415         return FALSE;
416       }
417       cinfo->comp_info[ci].h_samp_factor = val1;
418       cinfo->comp_info[ci].v_samp_factor = val2;
419       while (*arg && *arg++ != ',');  /* advance to next segment of arg
420                                          string */
421     } else {
422       /* reached end of parameter, set remaining components to 1x1 sampling */
423       cinfo->comp_info[ci].h_samp_factor = 1;
424       cinfo->comp_info[ci].v_samp_factor = 1;
425     }
426   }
427   return TRUE;
428 }
429