blob: 6e6ab1b3a0b68481c6856136f853c23d8e110fd2 [file] [log] [blame]
Thomas G. Lanebc79e061995-08-02 00:00:00 +00001/*
2 * rdswitch.c
3 *
DRCa73e8702012-12-31 02:52:30 +00004 * This file was part of the Independent JPEG Group's software:
Thomas G. Lane489583f1996-02-07 00:00:00 +00005 * Copyright (C) 1991-1996, Thomas G. Lane.
DRCa6ef2822013-09-28 03:23:49 +00006 * libjpeg-turbo Modifications:
DRCed16ad12010-10-11 23:36:04 +00007 * Copyright (C) 2010, D. R. Commander.
DRC7e3acc02015-10-10 10:25:46 -05008 * For conditions of distribution and use, see the accompanying README.ijg
9 * file.
Thomas G. Lanebc79e061995-08-02 00:00:00 +000010 *
11 * This file contains routines to process some of cjpeg's more complicated
12 * command-line switches. Switches processed here are:
DRCe5eaf372014-05-09 18:00:32 +000013 * -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
Thomas G. Lanebc79e061995-08-02 00:00:00 +000018 */
19
DRCe5eaf372014-05-09 18:00:32 +000020#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
21#include <ctype.h> /* to declare isdigit(), isspace() */
Thomas G. Lanebc79e061995-08-02 00:00:00 +000022
23
Thomas G. Lane489583f1996-02-07 00:00:00 +000024LOCAL(int)
Thomas G. Lanebc79e061995-08-02 00:00:00 +000025text_getc (FILE * file)
26/* Read next char, skipping over any comments (# to end of line) */
27/* A comment/newline sequence is returned as a newline */
28{
29 register int ch;
DRCe5eaf372014-05-09 18:00:32 +000030
Thomas G. Lanebc79e061995-08-02 00:00:00 +000031 ch = getc(file);
32 if (ch == '#') {
33 do {
34 ch = getc(file);
35 } while (ch != '\n' && ch != EOF);
36 }
37 return ch;
38}
39
40
Thomas G. Lane489583f1996-02-07 00:00:00 +000041LOCAL(boolean)
Thomas G. Lanebc79e061995-08-02 00:00:00 +000042read_text_integer (FILE * file, long * result, int * termchar)
43/* Read an unsigned decimal integer from a file, store it in result */
44/* Reads one trailing character after the integer; returns it in termchar */
45{
46 register int ch;
47 register long val;
DRCe5eaf372014-05-09 18:00:32 +000048
Thomas G. Lanebc79e061995-08-02 00:00:00 +000049 /* Skip any leading whitespace, detect EOF */
50 do {
51 ch = text_getc(file);
52 if (ch == EOF) {
53 *termchar = ch;
54 return FALSE;
55 }
56 } while (isspace(ch));
DRCe5eaf372014-05-09 18:00:32 +000057
Thomas G. Lanebc79e061995-08-02 00:00:00 +000058 if (! isdigit(ch)) {
59 *termchar = ch;
60 return FALSE;
61 }
62
63 val = ch - '0';
64 while ((ch = text_getc(file)) != EOF) {
65 if (! isdigit(ch))
66 break;
67 val *= 10;
68 val += ch - '0';
69 }
70 *result = val;
71 *termchar = ch;
72 return TRUE;
73}
74
75
DRC294079c2010-10-10 07:21:55 +000076#if JPEG_LIB_VERSION < 70
DRCed16ad12010-10-11 23:36:04 +000077static int q_scale_factor[NUM_QUANT_TBLS] = {100, 100, 100, 100};
DRC294079c2010-10-10 07:21:55 +000078#endif
79
Thomas G. Lane489583f1996-02-07 00:00:00 +000080GLOBAL(boolean)
Guido Vollbeding5996a252009-06-27 00:00:00 +000081read_quant_tables (j_compress_ptr cinfo, char * filename, boolean force_baseline)
Thomas G. Lanebc79e061995-08-02 00:00:00 +000082/* Read a set of quantization tables from the specified file.
83 * The file is plain ASCII text: decimal numbers with whitespace between.
84 * Comments preceded by '#' may be included in the file.
85 * There may be one to NUM_QUANT_TBLS tables in the file, each of 64 values.
86 * The tables are implicitly numbered 0,1,etc.
87 * NOTE: does not affect the qslots mapping, which will default to selecting
88 * table 0 for luminance (or primary) components, 1 for chrominance components.
89 * You must use -qslots if you want a different component->table mapping.
90 */
91{
92 FILE * fp;
93 int tblno, i, termchar;
94 long val;
95 unsigned int table[DCTSIZE2];
96
97 if ((fp = fopen(filename, "r")) == NULL) {
98 fprintf(stderr, "Can't open table file %s\n", filename);
99 return FALSE;
100 }
101 tblno = 0;
102
103 while (read_text_integer(fp, &val, &termchar)) { /* read 1st element of table */
104 if (tblno >= NUM_QUANT_TBLS) {
105 fprintf(stderr, "Too many tables in file %s\n", filename);
106 fclose(fp);
107 return FALSE;
108 }
109 table[0] = (unsigned int) val;
110 for (i = 1; i < DCTSIZE2; i++) {
111 if (! read_text_integer(fp, &val, &termchar)) {
DRCe5eaf372014-05-09 18:00:32 +0000112 fprintf(stderr, "Invalid table data in file %s\n", filename);
113 fclose(fp);
114 return FALSE;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000115 }
Thomas G. Lane489583f1996-02-07 00:00:00 +0000116 table[i] = (unsigned int) val;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000117 }
DRC294079c2010-10-10 07:21:55 +0000118#if JPEG_LIB_VERSION >= 70
Guido Vollbeding5996a252009-06-27 00:00:00 +0000119 jpeg_add_quant_table(cinfo, tblno, table, cinfo->q_scale_factor[tblno],
DRCe5eaf372014-05-09 18:00:32 +0000120 force_baseline);
DRC294079c2010-10-10 07:21:55 +0000121#else
DRCed16ad12010-10-11 23:36:04 +0000122 jpeg_add_quant_table(cinfo, tblno, table, q_scale_factor[tblno],
123 force_baseline);
DRC294079c2010-10-10 07:21:55 +0000124#endif
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000125 tblno++;
126 }
127
128 if (termchar != EOF) {
129 fprintf(stderr, "Non-numeric data in file %s\n", filename);
130 fclose(fp);
131 return FALSE;
132 }
133
134 fclose(fp);
135 return TRUE;
136}
137
138
139#ifdef C_MULTISCAN_FILES_SUPPORTED
140
Thomas G. Lane489583f1996-02-07 00:00:00 +0000141LOCAL(boolean)
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000142read_scan_integer (FILE * file, long * result, int * termchar)
143/* Variant of read_text_integer that always looks for a non-space termchar;
144 * this simplifies parsing of punctuation in scan scripts.
145 */
146{
147 register int ch;
148
149 if (! read_text_integer(file, result, termchar))
150 return FALSE;
151 ch = *termchar;
152 while (ch != EOF && isspace(ch))
153 ch = text_getc(file);
DRCe5eaf372014-05-09 18:00:32 +0000154 if (isdigit(ch)) { /* oops, put it back */
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000155 if (ungetc(ch, file) == EOF)
156 return FALSE;
157 ch = ' ';
158 } else {
159 /* Any separators other than ';' and ':' are ignored;
160 * this allows user to insert commas, etc, if desired.
161 */
162 if (ch != EOF && ch != ';' && ch != ':')
163 ch = ' ';
164 }
165 *termchar = ch;
166 return TRUE;
167}
168
169
Thomas G. Lane489583f1996-02-07 00:00:00 +0000170GLOBAL(boolean)
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000171read_scan_script (j_compress_ptr cinfo, char * filename)
172/* Read a scan script from the specified text file.
173 * Each entry in the file defines one scan to be emitted.
174 * Entries are separated by semicolons ';'.
175 * An entry contains one to four component indexes,
176 * optionally followed by a colon ':' and four progressive-JPEG parameters.
177 * The component indexes denote which component(s) are to be transmitted
178 * in the current scan. The first component has index 0.
179 * Sequential JPEG is used if the progressive-JPEG parameters are omitted.
180 * The file is free format text: any whitespace may appear between numbers
181 * and the ':' and ';' punctuation marks. Also, other punctuation (such
182 * as commas or dashes) can be placed between numbers if desired.
183 * Comments preceded by '#' may be included in the file.
184 * Note: we do very little validity checking here;
185 * jcmaster.c will validate the script parameters.
186 */
187{
188 FILE * fp;
189 int scanno, ncomps, termchar;
190 long val;
191 jpeg_scan_info * scanptr;
DRCe5eaf372014-05-09 18:00:32 +0000192#define MAX_SCANS 100 /* quite arbitrary limit */
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000193 jpeg_scan_info scans[MAX_SCANS];
194
195 if ((fp = fopen(filename, "r")) == NULL) {
196 fprintf(stderr, "Can't open scan definition file %s\n", filename);
197 return FALSE;
198 }
199 scanptr = scans;
200 scanno = 0;
201
202 while (read_scan_integer(fp, &val, &termchar)) {
203 if (scanno >= MAX_SCANS) {
204 fprintf(stderr, "Too many scans defined in file %s\n", filename);
205 fclose(fp);
206 return FALSE;
207 }
208 scanptr->component_index[0] = (int) val;
209 ncomps = 1;
210 while (termchar == ' ') {
211 if (ncomps >= MAX_COMPS_IN_SCAN) {
DRCe5eaf372014-05-09 18:00:32 +0000212 fprintf(stderr, "Too many components in one scan in file %s\n",
213 filename);
214 fclose(fp);
215 return FALSE;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000216 }
217 if (! read_scan_integer(fp, &val, &termchar))
DRCe5eaf372014-05-09 18:00:32 +0000218 goto bogus;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000219 scanptr->component_index[ncomps] = (int) val;
220 ncomps++;
221 }
222 scanptr->comps_in_scan = ncomps;
223 if (termchar == ':') {
224 if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')
DRCe5eaf372014-05-09 18:00:32 +0000225 goto bogus;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000226 scanptr->Ss = (int) val;
227 if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')
DRCe5eaf372014-05-09 18:00:32 +0000228 goto bogus;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000229 scanptr->Se = (int) val;
230 if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')
DRCe5eaf372014-05-09 18:00:32 +0000231 goto bogus;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000232 scanptr->Ah = (int) val;
233 if (! read_scan_integer(fp, &val, &termchar))
DRCe5eaf372014-05-09 18:00:32 +0000234 goto bogus;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000235 scanptr->Al = (int) val;
236 } else {
237 /* set non-progressive parameters */
238 scanptr->Ss = 0;
239 scanptr->Se = DCTSIZE2-1;
240 scanptr->Ah = 0;
241 scanptr->Al = 0;
242 }
243 if (termchar != ';' && termchar != EOF) {
244bogus:
245 fprintf(stderr, "Invalid scan entry format in file %s\n", filename);
246 fclose(fp);
247 return FALSE;
248 }
249 scanptr++, scanno++;
250 }
251
252 if (termchar != EOF) {
253 fprintf(stderr, "Non-numeric data in file %s\n", filename);
254 fclose(fp);
255 return FALSE;
256 }
257
258 if (scanno > 0) {
259 /* Stash completed scan list in cinfo structure.
260 * NOTE: for cjpeg's use, JPOOL_IMAGE is the right lifetime for this data,
261 * but if you want to compress multiple images you'd want JPOOL_PERMANENT.
262 */
263 scanptr = (jpeg_scan_info *)
264 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
DRC5de454b2014-05-18 19:04:03 +0000265 scanno * sizeof(jpeg_scan_info));
266 MEMCOPY(scanptr, scans, scanno * sizeof(jpeg_scan_info));
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000267 cinfo->scan_info = scanptr;
268 cinfo->num_scans = scanno;
269 }
270
271 fclose(fp);
272 return TRUE;
273}
274
275#endif /* C_MULTISCAN_FILES_SUPPORTED */
276
277
DRCed16ad12010-10-11 23:36:04 +0000278#if JPEG_LIB_VERSION < 70
279/* These are the sample quantization tables given in JPEG spec section K.1.
280 * The spec says that the values given produce "good" quality, and
281 * when divided by 2, "very good" quality.
282 */
283static const unsigned int std_luminance_quant_tbl[DCTSIZE2] = {
284 16, 11, 10, 16, 24, 40, 51, 61,
285 12, 12, 14, 19, 26, 58, 60, 55,
286 14, 13, 16, 24, 40, 57, 69, 56,
287 14, 17, 22, 29, 51, 87, 80, 62,
288 18, 22, 37, 56, 68, 109, 103, 77,
289 24, 35, 55, 64, 81, 104, 113, 92,
290 49, 64, 78, 87, 103, 121, 120, 101,
291 72, 92, 95, 98, 112, 100, 103, 99
292};
293static const unsigned int std_chrominance_quant_tbl[DCTSIZE2] = {
294 17, 18, 24, 47, 99, 99, 99, 99,
295 18, 21, 26, 66, 99, 99, 99, 99,
296 24, 26, 56, 99, 99, 99, 99, 99,
297 47, 66, 99, 99, 99, 99, 99, 99,
298 99, 99, 99, 99, 99, 99, 99, 99,
299 99, 99, 99, 99, 99, 99, 99, 99,
300 99, 99, 99, 99, 99, 99, 99, 99,
301 99, 99, 99, 99, 99, 99, 99, 99
302};
303
304
305LOCAL(void)
306jpeg_default_qtables (j_compress_ptr cinfo, boolean force_baseline)
307{
308 jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl,
DRCe5eaf372014-05-09 18:00:32 +0000309 q_scale_factor[0], force_baseline);
DRCed16ad12010-10-11 23:36:04 +0000310 jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl,
DRCe5eaf372014-05-09 18:00:32 +0000311 q_scale_factor[1], force_baseline);
DRCed16ad12010-10-11 23:36:04 +0000312}
313#endif
314
315
Thomas G. Lane489583f1996-02-07 00:00:00 +0000316GLOBAL(boolean)
Guido Vollbeding5996a252009-06-27 00:00:00 +0000317set_quality_ratings (j_compress_ptr cinfo, char *arg, boolean force_baseline)
318/* Process a quality-ratings parameter string, of the form
319 * N[,N,...]
320 * If there are more q-table slots than parameters, the last value is replicated.
321 */
322{
DRCe5eaf372014-05-09 18:00:32 +0000323 int val = 75; /* default value */
Guido Vollbeding5996a252009-06-27 00:00:00 +0000324 int tblno;
325 char ch;
326
327 for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) {
328 if (*arg) {
DRCe5eaf372014-05-09 18:00:32 +0000329 ch = ','; /* if not set by sscanf, will be ',' */
Guido Vollbeding5996a252009-06-27 00:00:00 +0000330 if (sscanf(arg, "%d%c", &val, &ch) < 1)
DRCe5eaf372014-05-09 18:00:32 +0000331 return FALSE;
332 if (ch != ',') /* syntax check */
333 return FALSE;
Guido Vollbeding5996a252009-06-27 00:00:00 +0000334 /* Convert user 0-100 rating to percentage scaling */
DRC294079c2010-10-10 07:21:55 +0000335#if JPEG_LIB_VERSION >= 70
Guido Vollbeding5996a252009-06-27 00:00:00 +0000336 cinfo->q_scale_factor[tblno] = jpeg_quality_scaling(val);
DRCed16ad12010-10-11 23:36:04 +0000337#else
338 q_scale_factor[tblno] = jpeg_quality_scaling(val);
DRC294079c2010-10-10 07:21:55 +0000339#endif
Guido Vollbeding5996a252009-06-27 00:00:00 +0000340 while (*arg && *arg++ != ',') /* advance to next segment of arg string */
DRCe5eaf372014-05-09 18:00:32 +0000341 ;
Guido Vollbeding5996a252009-06-27 00:00:00 +0000342 } else {
343 /* reached end of parameter, set remaining factors to last value */
DRC294079c2010-10-10 07:21:55 +0000344#if JPEG_LIB_VERSION >= 70
Guido Vollbeding5996a252009-06-27 00:00:00 +0000345 cinfo->q_scale_factor[tblno] = jpeg_quality_scaling(val);
DRCed16ad12010-10-11 23:36:04 +0000346#else
347 q_scale_factor[tblno] = jpeg_quality_scaling(val);
DRC294079c2010-10-10 07:21:55 +0000348#endif
Guido Vollbeding5996a252009-06-27 00:00:00 +0000349 }
350 }
351 jpeg_default_qtables(cinfo, force_baseline);
352 return TRUE;
353}
354
355
356GLOBAL(boolean)
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000357set_quant_slots (j_compress_ptr cinfo, char *arg)
358/* Process a quantization-table-selectors parameter string, of the form
359 * N[,N,...]
360 * If there are more components than parameters, the last value is replicated.
361 */
362{
DRCe5eaf372014-05-09 18:00:32 +0000363 int val = 0; /* default table # */
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000364 int ci;
365 char ch;
366
367 for (ci = 0; ci < MAX_COMPONENTS; ci++) {
368 if (*arg) {
DRCe5eaf372014-05-09 18:00:32 +0000369 ch = ','; /* if not set by sscanf, will be ',' */
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000370 if (sscanf(arg, "%d%c", &val, &ch) < 1)
DRCe5eaf372014-05-09 18:00:32 +0000371 return FALSE;
372 if (ch != ',') /* syntax check */
373 return FALSE;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000374 if (val < 0 || val >= NUM_QUANT_TBLS) {
DRCe5eaf372014-05-09 18:00:32 +0000375 fprintf(stderr, "JPEG quantization tables are numbered 0..%d\n",
376 NUM_QUANT_TBLS-1);
377 return FALSE;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000378 }
379 cinfo->comp_info[ci].quant_tbl_no = val;
380 while (*arg && *arg++ != ',') /* advance to next segment of arg string */
DRCe5eaf372014-05-09 18:00:32 +0000381 ;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000382 } else {
383 /* reached end of parameter, set remaining components to last table */
384 cinfo->comp_info[ci].quant_tbl_no = val;
385 }
386 }
387 return TRUE;
388}
389
390
Thomas G. Lane489583f1996-02-07 00:00:00 +0000391GLOBAL(boolean)
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000392set_sample_factors (j_compress_ptr cinfo, char *arg)
393/* Process a sample-factors parameter string, of the form
394 * HxV[,HxV,...]
395 * If there are more components than parameters, "1x1" is assumed for the rest.
396 */
397{
398 int ci, val1, val2;
399 char ch1, ch2;
400
401 for (ci = 0; ci < MAX_COMPONENTS; ci++) {
402 if (*arg) {
DRCe5eaf372014-05-09 18:00:32 +0000403 ch2 = ','; /* if not set by sscanf, will be ',' */
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000404 if (sscanf(arg, "%d%c%d%c", &val1, &ch1, &val2, &ch2) < 3)
DRCe5eaf372014-05-09 18:00:32 +0000405 return FALSE;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000406 if ((ch1 != 'x' && ch1 != 'X') || ch2 != ',') /* syntax check */
DRCe5eaf372014-05-09 18:00:32 +0000407 return FALSE;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000408 if (val1 <= 0 || val1 > 4 || val2 <= 0 || val2 > 4) {
DRCe5eaf372014-05-09 18:00:32 +0000409 fprintf(stderr, "JPEG sampling factors must be 1..4\n");
410 return FALSE;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000411 }
412 cinfo->comp_info[ci].h_samp_factor = val1;
413 cinfo->comp_info[ci].v_samp_factor = val2;
414 while (*arg && *arg++ != ',') /* advance to next segment of arg string */
DRCe5eaf372014-05-09 18:00:32 +0000415 ;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000416 } else {
417 /* reached end of parameter, set remaining components to 1x1 sampling */
418 cinfo->comp_info[ci].h_samp_factor = 1;
419 cinfo->comp_info[ci].v_samp_factor = 1;
420 }
421 }
422 return TRUE;
423}