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, D. R. Commander.
8 * 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:
12 *	-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
17 */
18
19#include "cdjpeg.h"		/* Common decls for cjpeg/djpeg applications */
20#include <ctype.h>		/* to declare isdigit(), isspace() */
21
22
23LOCAL(int)
24text_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;
29
30  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
40LOCAL(boolean)
41read_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;
47
48  /* 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));
56
57  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
75#if JPEG_LIB_VERSION < 70
76static int q_scale_factor[NUM_QUANT_TBLS] = {100, 100, 100, 100};
77#endif
78
79GLOBAL(boolean)
80read_quant_tables (j_compress_ptr cinfo, char * filename, boolean force_baseline)
81/* 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)) {
111	fprintf(stderr, "Invalid table data in file %s\n", filename);
112	fclose(fp);
113	return FALSE;
114      }
115      table[i] = (unsigned int) val;
116    }
117#if JPEG_LIB_VERSION >= 70
118    jpeg_add_quant_table(cinfo, tblno, table, cinfo->q_scale_factor[tblno],
119			 force_baseline);
120#else
121    jpeg_add_quant_table(cinfo, tblno, table, q_scale_factor[tblno],
122                         force_baseline);
123#endif
124    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
140LOCAL(boolean)
141read_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);
153  if (isdigit(ch)) {		/* oops, put it back */
154    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
169GLOBAL(boolean)
170read_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;
191#define MAX_SCANS  100		/* quite arbitrary limit */
192  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) {
211	fprintf(stderr, "Too many components in one scan in file %s\n",
212		filename);
213	fclose(fp);
214	return FALSE;
215      }
216      if (! read_scan_integer(fp, &val, &termchar))
217	goto bogus;
218      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 != ' ')
224	goto bogus;
225      scanptr->Ss = (int) val;
226      if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')
227	goto bogus;
228      scanptr->Se = (int) val;
229      if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')
230	goto bogus;
231      scanptr->Ah = (int) val;
232      if (! read_scan_integer(fp, &val, &termchar))
233	goto bogus;
234      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,
264				  scanno * SIZEOF(jpeg_scan_info));
265    MEMCOPY(scanptr, scans, scanno * SIZEOF(jpeg_scan_info));
266    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
277#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,
308		       q_scale_factor[0], force_baseline);
309  jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl,
310		       q_scale_factor[1], force_baseline);
311}
312#endif
313
314
315GLOBAL(boolean)
316set_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{
322  int val = 75;			/* default value */
323  int tblno;
324  char ch;
325
326  for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) {
327    if (*arg) {
328      ch = ',';			/* if not set by sscanf, will be ',' */
329      if (sscanf(arg, "%d%c", &val, &ch) < 1)
330	return FALSE;
331      if (ch != ',')		/* syntax check */
332	return FALSE;
333      /* Convert user 0-100 rating to percentage scaling */
334#if JPEG_LIB_VERSION >= 70
335      cinfo->q_scale_factor[tblno] = jpeg_quality_scaling(val);
336#else
337      q_scale_factor[tblno] = jpeg_quality_scaling(val);
338#endif
339      while (*arg && *arg++ != ',') /* advance to next segment of arg string */
340	;
341    } else {
342      /* reached end of parameter, set remaining factors to last value */
343#if JPEG_LIB_VERSION >= 70
344      cinfo->q_scale_factor[tblno] = jpeg_quality_scaling(val);
345#else
346      q_scale_factor[tblno] = jpeg_quality_scaling(val);
347#endif
348    }
349  }
350  jpeg_default_qtables(cinfo, force_baseline);
351  return TRUE;
352}
353
354
355GLOBAL(boolean)
356set_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{
362  int val = 0;			/* default table # */
363  int ci;
364  char ch;
365
366  for (ci = 0; ci < MAX_COMPONENTS; ci++) {
367    if (*arg) {
368      ch = ',';			/* if not set by sscanf, will be ',' */
369      if (sscanf(arg, "%d%c", &val, &ch) < 1)
370	return FALSE;
371      if (ch != ',')		/* syntax check */
372	return FALSE;
373      if (val < 0 || val >= NUM_QUANT_TBLS) {
374	fprintf(stderr, "JPEG quantization tables are numbered 0..%d\n",
375		NUM_QUANT_TBLS-1);
376	return FALSE;
377      }
378      cinfo->comp_info[ci].quant_tbl_no = val;
379      while (*arg && *arg++ != ',') /* advance to next segment of arg string */
380	;
381    } 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
390GLOBAL(boolean)
391set_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) {
402      ch2 = ',';		/* if not set by sscanf, will be ',' */
403      if (sscanf(arg, "%d%c%d%c", &val1, &ch1, &val2, &ch2) < 3)
404	return FALSE;
405      if ((ch1 != 'x' && ch1 != 'X') || ch2 != ',') /* syntax check */
406	return FALSE;
407      if (val1 <= 0 || val1 > 4 || val2 <= 0 || val2 > 4) {
408	fprintf(stderr, "JPEG sampling factors must be 1..4\n");
409	return FALSE;
410      }
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 */
414	;
415    } 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}
423