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