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