blob: 7d870c309d4f6db1ae04ed70ba080d796b5b63e9 [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)
DRCbd498032016-02-19 08:53:33 -060025text_getc (FILE *file)
Thomas G. Lanebc79e061995-08-02 00:00:00 +000026/* 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)
DRCbd498032016-02-19 08:53:33 -060042read_text_integer (FILE *file, long *result, int *termchar)
Thomas G. Lanebc79e061995-08-02 00:00:00 +000043/* 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)
DRCbd498032016-02-19 08:53:33 -060081read_quant_tables (j_compress_ptr cinfo, char *filename,
82 boolean force_baseline)
Thomas G. Lanebc79e061995-08-02 00:00:00 +000083/* Read a set of quantization tables from the specified file.
84 * The file is plain ASCII text: decimal numbers with whitespace between.
85 * Comments preceded by '#' may be included in the file.
86 * There may be one to NUM_QUANT_TBLS tables in the file, each of 64 values.
87 * The tables are implicitly numbered 0,1,etc.
88 * NOTE: does not affect the qslots mapping, which will default to selecting
89 * table 0 for luminance (or primary) components, 1 for chrominance components.
90 * You must use -qslots if you want a different component->table mapping.
91 */
92{
DRCbd498032016-02-19 08:53:33 -060093 FILE *fp;
Thomas G. Lanebc79e061995-08-02 00:00:00 +000094 int tblno, i, termchar;
95 long val;
96 unsigned int table[DCTSIZE2];
97
98 if ((fp = fopen(filename, "r")) == NULL) {
99 fprintf(stderr, "Can't open table file %s\n", filename);
100 return FALSE;
101 }
102 tblno = 0;
103
104 while (read_text_integer(fp, &val, &termchar)) { /* read 1st element of table */
105 if (tblno >= NUM_QUANT_TBLS) {
106 fprintf(stderr, "Too many tables in file %s\n", filename);
107 fclose(fp);
108 return FALSE;
109 }
110 table[0] = (unsigned int) val;
111 for (i = 1; i < DCTSIZE2; i++) {
112 if (! read_text_integer(fp, &val, &termchar)) {
DRCe5eaf372014-05-09 18:00:32 +0000113 fprintf(stderr, "Invalid table data in file %s\n", filename);
114 fclose(fp);
115 return FALSE;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000116 }
Thomas G. Lane489583f1996-02-07 00:00:00 +0000117 table[i] = (unsigned int) val;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000118 }
DRC294079c2010-10-10 07:21:55 +0000119#if JPEG_LIB_VERSION >= 70
Guido Vollbeding5996a252009-06-27 00:00:00 +0000120 jpeg_add_quant_table(cinfo, tblno, table, cinfo->q_scale_factor[tblno],
DRCe5eaf372014-05-09 18:00:32 +0000121 force_baseline);
DRC294079c2010-10-10 07:21:55 +0000122#else
DRCed16ad12010-10-11 23:36:04 +0000123 jpeg_add_quant_table(cinfo, tblno, table, q_scale_factor[tblno],
124 force_baseline);
DRC294079c2010-10-10 07:21:55 +0000125#endif
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000126 tblno++;
127 }
128
129 if (termchar != EOF) {
130 fprintf(stderr, "Non-numeric data in file %s\n", filename);
131 fclose(fp);
132 return FALSE;
133 }
134
135 fclose(fp);
136 return TRUE;
137}
138
139
140#ifdef C_MULTISCAN_FILES_SUPPORTED
141
Thomas G. Lane489583f1996-02-07 00:00:00 +0000142LOCAL(boolean)
DRCbd498032016-02-19 08:53:33 -0600143read_scan_integer (FILE *file, long *result, int *termchar)
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000144/* Variant of read_text_integer that always looks for a non-space termchar;
145 * this simplifies parsing of punctuation in scan scripts.
146 */
147{
148 register int ch;
149
150 if (! read_text_integer(file, result, termchar))
151 return FALSE;
152 ch = *termchar;
153 while (ch != EOF && isspace(ch))
154 ch = text_getc(file);
DRCe5eaf372014-05-09 18:00:32 +0000155 if (isdigit(ch)) { /* oops, put it back */
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000156 if (ungetc(ch, file) == EOF)
157 return FALSE;
158 ch = ' ';
159 } else {
160 /* Any separators other than ';' and ':' are ignored;
161 * this allows user to insert commas, etc, if desired.
162 */
163 if (ch != EOF && ch != ';' && ch != ':')
164 ch = ' ';
165 }
166 *termchar = ch;
167 return TRUE;
168}
169
170
Thomas G. Lane489583f1996-02-07 00:00:00 +0000171GLOBAL(boolean)
DRCbd498032016-02-19 08:53:33 -0600172read_scan_script (j_compress_ptr cinfo, char *filename)
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000173/* Read a scan script from the specified text file.
174 * Each entry in the file defines one scan to be emitted.
175 * Entries are separated by semicolons ';'.
176 * An entry contains one to four component indexes,
177 * optionally followed by a colon ':' and four progressive-JPEG parameters.
178 * The component indexes denote which component(s) are to be transmitted
179 * in the current scan. The first component has index 0.
180 * Sequential JPEG is used if the progressive-JPEG parameters are omitted.
181 * The file is free format text: any whitespace may appear between numbers
182 * and the ':' and ';' punctuation marks. Also, other punctuation (such
183 * as commas or dashes) can be placed between numbers if desired.
184 * Comments preceded by '#' may be included in the file.
185 * Note: we do very little validity checking here;
186 * jcmaster.c will validate the script parameters.
187 */
188{
DRCbd498032016-02-19 08:53:33 -0600189 FILE *fp;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000190 int scanno, ncomps, termchar;
191 long val;
DRCbd498032016-02-19 08:53:33 -0600192 jpeg_scan_info *scanptr;
DRCe5eaf372014-05-09 18:00:32 +0000193#define MAX_SCANS 100 /* quite arbitrary limit */
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000194 jpeg_scan_info scans[MAX_SCANS];
195
196 if ((fp = fopen(filename, "r")) == NULL) {
197 fprintf(stderr, "Can't open scan definition file %s\n", filename);
198 return FALSE;
199 }
200 scanptr = scans;
201 scanno = 0;
202
203 while (read_scan_integer(fp, &val, &termchar)) {
204 if (scanno >= MAX_SCANS) {
205 fprintf(stderr, "Too many scans defined in file %s\n", filename);
206 fclose(fp);
207 return FALSE;
208 }
209 scanptr->component_index[0] = (int) val;
210 ncomps = 1;
211 while (termchar == ' ') {
212 if (ncomps >= MAX_COMPS_IN_SCAN) {
DRCe5eaf372014-05-09 18:00:32 +0000213 fprintf(stderr, "Too many components in one scan in file %s\n",
214 filename);
215 fclose(fp);
216 return FALSE;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000217 }
218 if (! read_scan_integer(fp, &val, &termchar))
DRCe5eaf372014-05-09 18:00:32 +0000219 goto bogus;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000220 scanptr->component_index[ncomps] = (int) val;
221 ncomps++;
222 }
223 scanptr->comps_in_scan = ncomps;
224 if (termchar == ':') {
225 if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')
DRCe5eaf372014-05-09 18:00:32 +0000226 goto bogus;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000227 scanptr->Ss = (int) val;
228 if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')
DRCe5eaf372014-05-09 18:00:32 +0000229 goto bogus;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000230 scanptr->Se = (int) val;
231 if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')
DRCe5eaf372014-05-09 18:00:32 +0000232 goto bogus;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000233 scanptr->Ah = (int) val;
234 if (! read_scan_integer(fp, &val, &termchar))
DRCe5eaf372014-05-09 18:00:32 +0000235 goto bogus;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000236 scanptr->Al = (int) val;
237 } else {
238 /* set non-progressive parameters */
239 scanptr->Ss = 0;
240 scanptr->Se = DCTSIZE2-1;
241 scanptr->Ah = 0;
242 scanptr->Al = 0;
243 }
244 if (termchar != ';' && termchar != EOF) {
245bogus:
246 fprintf(stderr, "Invalid scan entry format in file %s\n", filename);
247 fclose(fp);
248 return FALSE;
249 }
250 scanptr++, scanno++;
251 }
252
253 if (termchar != EOF) {
254 fprintf(stderr, "Non-numeric data in file %s\n", filename);
255 fclose(fp);
256 return FALSE;
257 }
258
259 if (scanno > 0) {
260 /* Stash completed scan list in cinfo structure.
261 * NOTE: for cjpeg's use, JPOOL_IMAGE is the right lifetime for this data,
262 * but if you want to compress multiple images you'd want JPOOL_PERMANENT.
263 */
264 scanptr = (jpeg_scan_info *)
265 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
DRC5de454b2014-05-18 19:04:03 +0000266 scanno * sizeof(jpeg_scan_info));
267 MEMCOPY(scanptr, scans, scanno * sizeof(jpeg_scan_info));
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000268 cinfo->scan_info = scanptr;
269 cinfo->num_scans = scanno;
270 }
271
272 fclose(fp);
273 return TRUE;
274}
275
276#endif /* C_MULTISCAN_FILES_SUPPORTED */
277
278
DRCed16ad12010-10-11 23:36:04 +0000279#if JPEG_LIB_VERSION < 70
280/* These are the sample quantization tables given in JPEG spec section K.1.
281 * The spec says that the values given produce "good" quality, and
282 * when divided by 2, "very good" quality.
283 */
284static const unsigned int std_luminance_quant_tbl[DCTSIZE2] = {
285 16, 11, 10, 16, 24, 40, 51, 61,
286 12, 12, 14, 19, 26, 58, 60, 55,
287 14, 13, 16, 24, 40, 57, 69, 56,
288 14, 17, 22, 29, 51, 87, 80, 62,
289 18, 22, 37, 56, 68, 109, 103, 77,
290 24, 35, 55, 64, 81, 104, 113, 92,
291 49, 64, 78, 87, 103, 121, 120, 101,
292 72, 92, 95, 98, 112, 100, 103, 99
293};
294static const unsigned int std_chrominance_quant_tbl[DCTSIZE2] = {
295 17, 18, 24, 47, 99, 99, 99, 99,
296 18, 21, 26, 66, 99, 99, 99, 99,
297 24, 26, 56, 99, 99, 99, 99, 99,
298 47, 66, 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 99, 99, 99, 99, 99, 99, 99, 99
303};
304
305
306LOCAL(void)
307jpeg_default_qtables (j_compress_ptr cinfo, boolean force_baseline)
308{
309 jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl,
DRCe5eaf372014-05-09 18:00:32 +0000310 q_scale_factor[0], force_baseline);
DRCed16ad12010-10-11 23:36:04 +0000311 jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl,
DRCe5eaf372014-05-09 18:00:32 +0000312 q_scale_factor[1], force_baseline);
DRCed16ad12010-10-11 23:36:04 +0000313}
314#endif
315
316
Thomas G. Lane489583f1996-02-07 00:00:00 +0000317GLOBAL(boolean)
Guido Vollbeding5996a252009-06-27 00:00:00 +0000318set_quality_ratings (j_compress_ptr cinfo, char *arg, boolean force_baseline)
319/* Process a quality-ratings parameter string, of the form
320 * N[,N,...]
321 * If there are more q-table slots than parameters, the last value is replicated.
322 */
323{
DRCe5eaf372014-05-09 18:00:32 +0000324 int val = 75; /* default value */
Guido Vollbeding5996a252009-06-27 00:00:00 +0000325 int tblno;
326 char ch;
327
328 for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) {
329 if (*arg) {
DRCe5eaf372014-05-09 18:00:32 +0000330 ch = ','; /* if not set by sscanf, will be ',' */
Guido Vollbeding5996a252009-06-27 00:00:00 +0000331 if (sscanf(arg, "%d%c", &val, &ch) < 1)
DRCe5eaf372014-05-09 18:00:32 +0000332 return FALSE;
333 if (ch != ',') /* syntax check */
334 return FALSE;
Guido Vollbeding5996a252009-06-27 00:00:00 +0000335 /* Convert user 0-100 rating to percentage scaling */
DRC294079c2010-10-10 07:21:55 +0000336#if JPEG_LIB_VERSION >= 70
Guido Vollbeding5996a252009-06-27 00:00:00 +0000337 cinfo->q_scale_factor[tblno] = jpeg_quality_scaling(val);
DRCed16ad12010-10-11 23:36:04 +0000338#else
339 q_scale_factor[tblno] = jpeg_quality_scaling(val);
DRC294079c2010-10-10 07:21:55 +0000340#endif
Guido Vollbeding5996a252009-06-27 00:00:00 +0000341 while (*arg && *arg++ != ',') /* advance to next segment of arg string */
DRCe5eaf372014-05-09 18:00:32 +0000342 ;
Guido Vollbeding5996a252009-06-27 00:00:00 +0000343 } else {
344 /* reached end of parameter, set remaining factors to last value */
DRC294079c2010-10-10 07:21:55 +0000345#if JPEG_LIB_VERSION >= 70
Guido Vollbeding5996a252009-06-27 00:00:00 +0000346 cinfo->q_scale_factor[tblno] = jpeg_quality_scaling(val);
DRCed16ad12010-10-11 23:36:04 +0000347#else
348 q_scale_factor[tblno] = jpeg_quality_scaling(val);
DRC294079c2010-10-10 07:21:55 +0000349#endif
Guido Vollbeding5996a252009-06-27 00:00:00 +0000350 }
351 }
352 jpeg_default_qtables(cinfo, force_baseline);
353 return TRUE;
354}
355
356
357GLOBAL(boolean)
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000358set_quant_slots (j_compress_ptr cinfo, char *arg)
359/* Process a quantization-table-selectors parameter string, of the form
360 * N[,N,...]
361 * If there are more components than parameters, the last value is replicated.
362 */
363{
DRCe5eaf372014-05-09 18:00:32 +0000364 int val = 0; /* default table # */
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000365 int ci;
366 char ch;
367
368 for (ci = 0; ci < MAX_COMPONENTS; ci++) {
369 if (*arg) {
DRCe5eaf372014-05-09 18:00:32 +0000370 ch = ','; /* if not set by sscanf, will be ',' */
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000371 if (sscanf(arg, "%d%c", &val, &ch) < 1)
DRCe5eaf372014-05-09 18:00:32 +0000372 return FALSE;
373 if (ch != ',') /* syntax check */
374 return FALSE;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000375 if (val < 0 || val >= NUM_QUANT_TBLS) {
DRCe5eaf372014-05-09 18:00:32 +0000376 fprintf(stderr, "JPEG quantization tables are numbered 0..%d\n",
377 NUM_QUANT_TBLS-1);
378 return FALSE;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000379 }
380 cinfo->comp_info[ci].quant_tbl_no = val;
381 while (*arg && *arg++ != ',') /* advance to next segment of arg string */
DRCe5eaf372014-05-09 18:00:32 +0000382 ;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000383 } else {
384 /* reached end of parameter, set remaining components to last table */
385 cinfo->comp_info[ci].quant_tbl_no = val;
386 }
387 }
388 return TRUE;
389}
390
391
Thomas G. Lane489583f1996-02-07 00:00:00 +0000392GLOBAL(boolean)
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000393set_sample_factors (j_compress_ptr cinfo, char *arg)
394/* Process a sample-factors parameter string, of the form
395 * HxV[,HxV,...]
396 * If there are more components than parameters, "1x1" is assumed for the rest.
397 */
398{
399 int ci, val1, val2;
400 char ch1, ch2;
401
402 for (ci = 0; ci < MAX_COMPONENTS; ci++) {
403 if (*arg) {
DRCe5eaf372014-05-09 18:00:32 +0000404 ch2 = ','; /* if not set by sscanf, will be ',' */
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000405 if (sscanf(arg, "%d%c%d%c", &val1, &ch1, &val2, &ch2) < 3)
DRCe5eaf372014-05-09 18:00:32 +0000406 return FALSE;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000407 if ((ch1 != 'x' && ch1 != 'X') || ch2 != ',') /* syntax check */
DRCe5eaf372014-05-09 18:00:32 +0000408 return FALSE;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000409 if (val1 <= 0 || val1 > 4 || val2 <= 0 || val2 > 4) {
DRCe5eaf372014-05-09 18:00:32 +0000410 fprintf(stderr, "JPEG sampling factors must be 1..4\n");
411 return FALSE;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000412 }
413 cinfo->comp_info[ci].h_samp_factor = val1;
414 cinfo->comp_info[ci].v_samp_factor = val2;
415 while (*arg && *arg++ != ',') /* advance to next segment of arg string */
DRCe5eaf372014-05-09 18:00:32 +0000416 ;
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000417 } else {
418 /* reached end of parameter, set remaining components to 1x1 sampling */
419 cinfo->comp_info[ci].h_samp_factor = 1;
420 cinfo->comp_info[ci].v_samp_factor = 1;
421 }
422 }
423 return TRUE;
424}