blob: a0aa37c70560a8f309eb5f6bf7b7b9152f0e4434 [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.
Thomas G. Lanebc79e061995-08-02 00:00:00 +00008 * For conditions of distribution and use, see the accompanying README file.
9 *
10 * This file contains routines to process some of cjpeg's more complicated
11 * command-line switches. Switches processed here are:
DRCe5eaf372014-05-09 18:00:32 +000012 * -qtables file Read quantization tables from text file
13 * -scans file Read scan script from text file
14 * -quality N[,N,...] Set quality ratings
15 * -qslots N[,N,...] Set component quantization table selectors
16 * -sample HxV[,HxV,...] Set component sampling factors
Thomas G. Lanebc79e061995-08-02 00:00:00 +000017 */
18
DRCe5eaf372014-05-09 18:00:32 +000019#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
20#include <ctype.h> /* to declare isdigit(), isspace() */
Thomas G. Lanebc79e061995-08-02 00:00:00 +000021
22
Thomas G. Lane489583f1996-02-07 00:00:00 +000023LOCAL(int)
Thomas G. Lanebc79e061995-08-02 00:00:00 +000024text_getc (FILE * file)
25/* Read next char, skipping over any comments (# to end of line) */
26/* A comment/newline sequence is returned as a newline */
27{
28 register int ch;
DRCe5eaf372014-05-09 18:00:32 +000029
Thomas G. Lanebc79e061995-08-02 00:00:00 +000030 ch = getc(file);
31 if (ch == '#') {
32 do {
33 ch = getc(file);
34 } while (ch != '\n' && ch != EOF);
35 }
36 return ch;
37}
38
39
Thomas G. Lane489583f1996-02-07 00:00:00 +000040LOCAL(boolean)
Thomas G. Lanebc79e061995-08-02 00:00:00 +000041read_text_integer (FILE * file, long * result, int * termchar)
42/* Read an unsigned decimal integer from a file, store it in result */
43/* Reads one trailing character after the integer; returns it in termchar */
44{
45 register int ch;
46 register long val;
DRCe5eaf372014-05-09 18:00:32 +000047
Thomas G. Lanebc79e061995-08-02 00:00:00 +000048 /* Skip any leading whitespace, detect EOF */
49 do {
50 ch = text_getc(file);
51 if (ch == EOF) {
52 *termchar = ch;
53 return FALSE;
54 }
55 } while (isspace(ch));
DRCe5eaf372014-05-09 18:00:32 +000056
Thomas G. Lanebc79e061995-08-02 00:00:00 +000057 if (! isdigit(ch)) {
58 *termchar = ch;
59 return FALSE;
60 }
61
62 val = ch - '0';
63 while ((ch = text_getc(file)) != EOF) {
64 if (! isdigit(ch))
65 break;
66 val *= 10;
67 val += ch - '0';
68 }
69 *result = val;
70 *termchar = ch;
71 return TRUE;
72}
73
74
DRC294079c2010-10-10 07:21:55 +000075#if JPEG_LIB_VERSION < 70
DRCed16ad12010-10-11 23:36:04 +000076static int q_scale_factor[NUM_QUANT_TBLS] = {100, 100, 100, 100};
DRC294079c2010-10-10 07:21:55 +000077#endif
78
Thomas G. Lane489583f1996-02-07 00:00:00 +000079GLOBAL(boolean)
Guido Vollbeding5996a252009-06-27 00:00:00 +000080read_quant_tables (j_compress_ptr cinfo, char * filename, boolean force_baseline)
Thomas G. Lanebc79e061995-08-02 00:00:00 +000081/* Read a set of quantization tables from the specified file.
82 * The file is plain ASCII text: decimal numbers with whitespace between.
83 * Comments preceded by '#' may be included in the file.
84 * There may be one to NUM_QUANT_TBLS tables in the file, each of 64 values.
85 * The tables are implicitly numbered 0,1,etc.
86 * NOTE: does not affect the qslots mapping, which will default to selecting
87 * table 0 for luminance (or primary) components, 1 for chrominance components.
88 * You must use -qslots if you want a different component->table mapping.
89 */
90{
91 FILE * fp;
92 int tblno, i, termchar;
93 long val;
94 unsigned int table[DCTSIZE2];
95
96 if ((fp = fopen(filename, "r")) == NULL) {
97 fprintf(stderr, "Can't open table file %s\n", filename);
98 return FALSE;
99 }
100 tblno = 0;
101
102 while (read_text_integer(fp, &val, &termchar)) { /* read 1st element of table */
103 if (tblno >= NUM_QUANT_TBLS) {
104 fprintf(stderr, "Too many tables in file %s\n", filename);
105 fclose(fp);
106 return FALSE;
107 }
108 table[0] = (unsigned int) val;
109 for (i = 1; i < DCTSIZE2; i++) {
110 if (! read_text_integer(fp, &val, &termchar)) {
DRCe5eaf372014-05-09 18:00:32 +0000111 fprintf(stderr, "Invalid table data in file %s\n", filename);
112 fclose(fp);
113 return FALSE;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000114 }
Thomas G. Lane489583f1996-02-07 00:00:00 +0000115 table[i] = (unsigned int) val;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000116 }
DRC294079c2010-10-10 07:21:55 +0000117#if JPEG_LIB_VERSION >= 70
Guido Vollbeding5996a252009-06-27 00:00:00 +0000118 jpeg_add_quant_table(cinfo, tblno, table, cinfo->q_scale_factor[tblno],
DRCe5eaf372014-05-09 18:00:32 +0000119 force_baseline);
DRC294079c2010-10-10 07:21:55 +0000120#else
DRCed16ad12010-10-11 23:36:04 +0000121 jpeg_add_quant_table(cinfo, tblno, table, q_scale_factor[tblno],
122 force_baseline);
DRC294079c2010-10-10 07:21:55 +0000123#endif
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000124 tblno++;
125 }
126
127 if (termchar != EOF) {
128 fprintf(stderr, "Non-numeric data in file %s\n", filename);
129 fclose(fp);
130 return FALSE;
131 }
132
133 fclose(fp);
134 return TRUE;
135}
136
137
138#ifdef C_MULTISCAN_FILES_SUPPORTED
139
Thomas G. Lane489583f1996-02-07 00:00:00 +0000140LOCAL(boolean)
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000141read_scan_integer (FILE * file, long * result, int * termchar)
142/* Variant of read_text_integer that always looks for a non-space termchar;
143 * this simplifies parsing of punctuation in scan scripts.
144 */
145{
146 register int ch;
147
148 if (! read_text_integer(file, result, termchar))
149 return FALSE;
150 ch = *termchar;
151 while (ch != EOF && isspace(ch))
152 ch = text_getc(file);
DRCe5eaf372014-05-09 18:00:32 +0000153 if (isdigit(ch)) { /* oops, put it back */
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000154 if (ungetc(ch, file) == EOF)
155 return FALSE;
156 ch = ' ';
157 } else {
158 /* Any separators other than ';' and ':' are ignored;
159 * this allows user to insert commas, etc, if desired.
160 */
161 if (ch != EOF && ch != ';' && ch != ':')
162 ch = ' ';
163 }
164 *termchar = ch;
165 return TRUE;
166}
167
168
Thomas G. Lane489583f1996-02-07 00:00:00 +0000169GLOBAL(boolean)
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000170read_scan_script (j_compress_ptr cinfo, char * filename)
171/* Read a scan script from the specified text file.
172 * Each entry in the file defines one scan to be emitted.
173 * Entries are separated by semicolons ';'.
174 * An entry contains one to four component indexes,
175 * optionally followed by a colon ':' and four progressive-JPEG parameters.
176 * The component indexes denote which component(s) are to be transmitted
177 * in the current scan. The first component has index 0.
178 * Sequential JPEG is used if the progressive-JPEG parameters are omitted.
179 * The file is free format text: any whitespace may appear between numbers
180 * and the ':' and ';' punctuation marks. Also, other punctuation (such
181 * as commas or dashes) can be placed between numbers if desired.
182 * Comments preceded by '#' may be included in the file.
183 * Note: we do very little validity checking here;
184 * jcmaster.c will validate the script parameters.
185 */
186{
187 FILE * fp;
188 int scanno, ncomps, termchar;
189 long val;
190 jpeg_scan_info * scanptr;
DRCe5eaf372014-05-09 18:00:32 +0000191#define MAX_SCANS 100 /* quite arbitrary limit */
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000192 jpeg_scan_info scans[MAX_SCANS];
193
194 if ((fp = fopen(filename, "r")) == NULL) {
195 fprintf(stderr, "Can't open scan definition file %s\n", filename);
196 return FALSE;
197 }
198 scanptr = scans;
199 scanno = 0;
200
201 while (read_scan_integer(fp, &val, &termchar)) {
202 if (scanno >= MAX_SCANS) {
203 fprintf(stderr, "Too many scans defined in file %s\n", filename);
204 fclose(fp);
205 return FALSE;
206 }
207 scanptr->component_index[0] = (int) val;
208 ncomps = 1;
209 while (termchar == ' ') {
210 if (ncomps >= MAX_COMPS_IN_SCAN) {
DRCe5eaf372014-05-09 18:00:32 +0000211 fprintf(stderr, "Too many components in one scan in file %s\n",
212 filename);
213 fclose(fp);
214 return FALSE;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000215 }
216 if (! read_scan_integer(fp, &val, &termchar))
DRCe5eaf372014-05-09 18:00:32 +0000217 goto bogus;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000218 scanptr->component_index[ncomps] = (int) val;
219 ncomps++;
220 }
221 scanptr->comps_in_scan = ncomps;
222 if (termchar == ':') {
223 if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')
DRCe5eaf372014-05-09 18:00:32 +0000224 goto bogus;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000225 scanptr->Ss = (int) val;
226 if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')
DRCe5eaf372014-05-09 18:00:32 +0000227 goto bogus;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000228 scanptr->Se = (int) val;
229 if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')
DRCe5eaf372014-05-09 18:00:32 +0000230 goto bogus;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000231 scanptr->Ah = (int) val;
232 if (! read_scan_integer(fp, &val, &termchar))
DRCe5eaf372014-05-09 18:00:32 +0000233 goto bogus;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000234 scanptr->Al = (int) val;
235 } else {
236 /* set non-progressive parameters */
237 scanptr->Ss = 0;
238 scanptr->Se = DCTSIZE2-1;
239 scanptr->Ah = 0;
240 scanptr->Al = 0;
241 }
242 if (termchar != ';' && termchar != EOF) {
243bogus:
244 fprintf(stderr, "Invalid scan entry format in file %s\n", filename);
245 fclose(fp);
246 return FALSE;
247 }
248 scanptr++, scanno++;
249 }
250
251 if (termchar != EOF) {
252 fprintf(stderr, "Non-numeric data in file %s\n", filename);
253 fclose(fp);
254 return FALSE;
255 }
256
257 if (scanno > 0) {
258 /* Stash completed scan list in cinfo structure.
259 * NOTE: for cjpeg's use, JPOOL_IMAGE is the right lifetime for this data,
260 * but if you want to compress multiple images you'd want JPOOL_PERMANENT.
261 */
262 scanptr = (jpeg_scan_info *)
263 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
DRC5de454b2014-05-18 19:04:03 +0000264 scanno * sizeof(jpeg_scan_info));
265 MEMCOPY(scanptr, scans, scanno * sizeof(jpeg_scan_info));
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000266 cinfo->scan_info = scanptr;
267 cinfo->num_scans = scanno;
268 }
269
270 fclose(fp);
271 return TRUE;
272}
273
274#endif /* C_MULTISCAN_FILES_SUPPORTED */
275
276
DRCed16ad12010-10-11 23:36:04 +0000277#if JPEG_LIB_VERSION < 70
278/* These are the sample quantization tables given in JPEG spec section K.1.
279 * The spec says that the values given produce "good" quality, and
280 * when divided by 2, "very good" quality.
281 */
282static const unsigned int std_luminance_quant_tbl[DCTSIZE2] = {
283 16, 11, 10, 16, 24, 40, 51, 61,
284 12, 12, 14, 19, 26, 58, 60, 55,
285 14, 13, 16, 24, 40, 57, 69, 56,
286 14, 17, 22, 29, 51, 87, 80, 62,
287 18, 22, 37, 56, 68, 109, 103, 77,
288 24, 35, 55, 64, 81, 104, 113, 92,
289 49, 64, 78, 87, 103, 121, 120, 101,
290 72, 92, 95, 98, 112, 100, 103, 99
291};
292static const unsigned int std_chrominance_quant_tbl[DCTSIZE2] = {
293 17, 18, 24, 47, 99, 99, 99, 99,
294 18, 21, 26, 66, 99, 99, 99, 99,
295 24, 26, 56, 99, 99, 99, 99, 99,
296 47, 66, 99, 99, 99, 99, 99, 99,
297 99, 99, 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};
302
303
304LOCAL(void)
305jpeg_default_qtables (j_compress_ptr cinfo, boolean force_baseline)
306{
307 jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl,
DRCe5eaf372014-05-09 18:00:32 +0000308 q_scale_factor[0], force_baseline);
DRCed16ad12010-10-11 23:36:04 +0000309 jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl,
DRCe5eaf372014-05-09 18:00:32 +0000310 q_scale_factor[1], force_baseline);
DRCed16ad12010-10-11 23:36:04 +0000311}
312#endif
313
314
Thomas G. Lane489583f1996-02-07 00:00:00 +0000315GLOBAL(boolean)
Guido Vollbeding5996a252009-06-27 00:00:00 +0000316set_quality_ratings (j_compress_ptr cinfo, char *arg, boolean force_baseline)
317/* Process a quality-ratings parameter string, of the form
318 * N[,N,...]
319 * If there are more q-table slots than parameters, the last value is replicated.
320 */
321{
DRCe5eaf372014-05-09 18:00:32 +0000322 int val = 75; /* default value */
Guido Vollbeding5996a252009-06-27 00:00:00 +0000323 int tblno;
324 char ch;
325
326 for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) {
327 if (*arg) {
DRCe5eaf372014-05-09 18:00:32 +0000328 ch = ','; /* if not set by sscanf, will be ',' */
Guido Vollbeding5996a252009-06-27 00:00:00 +0000329 if (sscanf(arg, "%d%c", &val, &ch) < 1)
DRCe5eaf372014-05-09 18:00:32 +0000330 return FALSE;
331 if (ch != ',') /* syntax check */
332 return FALSE;
Guido Vollbeding5996a252009-06-27 00:00:00 +0000333 /* Convert user 0-100 rating to percentage scaling */
DRC294079c2010-10-10 07:21:55 +0000334#if JPEG_LIB_VERSION >= 70
Guido Vollbeding5996a252009-06-27 00:00:00 +0000335 cinfo->q_scale_factor[tblno] = jpeg_quality_scaling(val);
DRCed16ad12010-10-11 23:36:04 +0000336#else
337 q_scale_factor[tblno] = jpeg_quality_scaling(val);
DRC294079c2010-10-10 07:21:55 +0000338#endif
Guido Vollbeding5996a252009-06-27 00:00:00 +0000339 while (*arg && *arg++ != ',') /* advance to next segment of arg string */
DRCe5eaf372014-05-09 18:00:32 +0000340 ;
Guido Vollbeding5996a252009-06-27 00:00:00 +0000341 } else {
342 /* reached end of parameter, set remaining factors to last value */
DRC294079c2010-10-10 07:21:55 +0000343#if JPEG_LIB_VERSION >= 70
Guido Vollbeding5996a252009-06-27 00:00:00 +0000344 cinfo->q_scale_factor[tblno] = jpeg_quality_scaling(val);
DRCed16ad12010-10-11 23:36:04 +0000345#else
346 q_scale_factor[tblno] = jpeg_quality_scaling(val);
DRC294079c2010-10-10 07:21:55 +0000347#endif
Guido Vollbeding5996a252009-06-27 00:00:00 +0000348 }
349 }
350 jpeg_default_qtables(cinfo, force_baseline);
351 return TRUE;
352}
353
354
355GLOBAL(boolean)
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000356set_quant_slots (j_compress_ptr cinfo, char *arg)
357/* Process a quantization-table-selectors parameter string, of the form
358 * N[,N,...]
359 * If there are more components than parameters, the last value is replicated.
360 */
361{
DRCe5eaf372014-05-09 18:00:32 +0000362 int val = 0; /* default table # */
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000363 int ci;
364 char ch;
365
366 for (ci = 0; ci < MAX_COMPONENTS; ci++) {
367 if (*arg) {
DRCe5eaf372014-05-09 18:00:32 +0000368 ch = ','; /* if not set by sscanf, will be ',' */
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000369 if (sscanf(arg, "%d%c", &val, &ch) < 1)
DRCe5eaf372014-05-09 18:00:32 +0000370 return FALSE;
371 if (ch != ',') /* syntax check */
372 return FALSE;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000373 if (val < 0 || val >= NUM_QUANT_TBLS) {
DRCe5eaf372014-05-09 18:00:32 +0000374 fprintf(stderr, "JPEG quantization tables are numbered 0..%d\n",
375 NUM_QUANT_TBLS-1);
376 return FALSE;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000377 }
378 cinfo->comp_info[ci].quant_tbl_no = val;
379 while (*arg && *arg++ != ',') /* advance to next segment of arg string */
DRCe5eaf372014-05-09 18:00:32 +0000380 ;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000381 } else {
382 /* reached end of parameter, set remaining components to last table */
383 cinfo->comp_info[ci].quant_tbl_no = val;
384 }
385 }
386 return TRUE;
387}
388
389
Thomas G. Lane489583f1996-02-07 00:00:00 +0000390GLOBAL(boolean)
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000391set_sample_factors (j_compress_ptr cinfo, char *arg)
392/* Process a sample-factors parameter string, of the form
393 * HxV[,HxV,...]
394 * If there are more components than parameters, "1x1" is assumed for the rest.
395 */
396{
397 int ci, val1, val2;
398 char ch1, ch2;
399
400 for (ci = 0; ci < MAX_COMPONENTS; ci++) {
401 if (*arg) {
DRCe5eaf372014-05-09 18:00:32 +0000402 ch2 = ','; /* if not set by sscanf, will be ',' */
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000403 if (sscanf(arg, "%d%c%d%c", &val1, &ch1, &val2, &ch2) < 3)
DRCe5eaf372014-05-09 18:00:32 +0000404 return FALSE;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000405 if ((ch1 != 'x' && ch1 != 'X') || ch2 != ',') /* syntax check */
DRCe5eaf372014-05-09 18:00:32 +0000406 return FALSE;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000407 if (val1 <= 0 || val1 > 4 || val2 <= 0 || val2 > 4) {
DRCe5eaf372014-05-09 18:00:32 +0000408 fprintf(stderr, "JPEG sampling factors must be 1..4\n");
409 return FALSE;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000410 }
411 cinfo->comp_info[ci].h_samp_factor = val1;
412 cinfo->comp_info[ci].v_samp_factor = val2;
413 while (*arg && *arg++ != ',') /* advance to next segment of arg string */
DRCe5eaf372014-05-09 18:00:32 +0000414 ;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000415 } else {
416 /* reached end of parameter, set remaining components to 1x1 sampling */
417 cinfo->comp_info[ci].h_samp_factor = 1;
418 cinfo->comp_info[ci].v_samp_factor = 1;
419 }
420 }
421 return TRUE;
422}