Home | History | Annotate | Download | only in libjpeg-turbo
      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.ijg
      9  * file.
     10  *
     11  * This file contains routines to process some of cjpeg's more complicated
     12  * command-line switches.  Switches processed here are:
     13  *      -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
     18  */
     19 
     20 #include "cdjpeg.h"             /* Common decls for cjpeg/djpeg applications */
     21 #include <ctype.h>              /* to declare isdigit(), isspace() */
     22 
     23 
     24 LOCAL(int)
     25 text_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;
     30 
     31   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 
     41 LOCAL(boolean)
     42 read_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;
     48 
     49   /* 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));
     57 
     58   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 
     76 #if JPEG_LIB_VERSION < 70
     77 static int q_scale_factor[NUM_QUANT_TBLS] = {100, 100, 100, 100};
     78 #endif
     79 
     80 GLOBAL(boolean)
     81 read_quant_tables (j_compress_ptr cinfo, char *filename,
     82                    boolean force_baseline)
     83 /* 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 {
     93   FILE *fp;
     94   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)) {
    113         fprintf(stderr, "Invalid table data in file %s\n", filename);
    114         fclose(fp);
    115         return FALSE;
    116       }
    117       table[i] = (unsigned int) val;
    118     }
    119 #if JPEG_LIB_VERSION >= 70
    120     jpeg_add_quant_table(cinfo, tblno, table, cinfo->q_scale_factor[tblno],
    121                          force_baseline);
    122 #else
    123     jpeg_add_quant_table(cinfo, tblno, table, q_scale_factor[tblno],
    124                          force_baseline);
    125 #endif
    126     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 
    142 LOCAL(boolean)
    143 read_scan_integer (FILE *file, long *result, int *termchar)
    144 /* 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);
    155   if (isdigit(ch)) {            /* oops, put it back */
    156     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 
    171 GLOBAL(boolean)
    172 read_scan_script (j_compress_ptr cinfo, char *filename)
    173 /* 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 {
    189   FILE *fp;
    190   int scanno, ncomps, termchar;
    191   long val;
    192   jpeg_scan_info *scanptr;
    193 #define MAX_SCANS  100          /* quite arbitrary limit */
    194   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) {
    213         fprintf(stderr, "Too many components in one scan in file %s\n",
    214                 filename);
    215         fclose(fp);
    216         return FALSE;
    217       }
    218       if (! read_scan_integer(fp, &val, &termchar))
    219         goto bogus;
    220       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 != ' ')
    226         goto bogus;
    227       scanptr->Ss = (int) val;
    228       if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')
    229         goto bogus;
    230       scanptr->Se = (int) val;
    231       if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')
    232         goto bogus;
    233       scanptr->Ah = (int) val;
    234       if (! read_scan_integer(fp, &val, &termchar))
    235         goto bogus;
    236       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) {
    245 bogus:
    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,
    266                                   scanno * sizeof(jpeg_scan_info));
    267     MEMCOPY(scanptr, scans, scanno * sizeof(jpeg_scan_info));
    268     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 
    279 #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  */
    284 static 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 };
    294 static 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 
    306 LOCAL(void)
    307 jpeg_default_qtables (j_compress_ptr cinfo, boolean force_baseline)
    308 {
    309   jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl,
    310                        q_scale_factor[0], force_baseline);
    311   jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl,
    312                        q_scale_factor[1], force_baseline);
    313 }
    314 #endif
    315 
    316 
    317 GLOBAL(boolean)
    318 set_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 {
    324   int val = 75;                 /* default value */
    325   int tblno;
    326   char ch;
    327 
    328   for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) {
    329     if (*arg) {
    330       ch = ',';                 /* if not set by sscanf, will be ',' */
    331       if (sscanf(arg, "%d%c", &val, &ch) < 1)
    332         return FALSE;
    333       if (ch != ',')            /* syntax check */
    334         return FALSE;
    335       /* Convert user 0-100 rating to percentage scaling */
    336 #if JPEG_LIB_VERSION >= 70
    337       cinfo->q_scale_factor[tblno] = jpeg_quality_scaling(val);
    338 #else
    339       q_scale_factor[tblno] = jpeg_quality_scaling(val);
    340 #endif
    341       while (*arg && *arg++ != ',') /* advance to next segment of arg string */
    342         ;
    343     } else {
    344       /* reached end of parameter, set remaining factors to last value */
    345 #if JPEG_LIB_VERSION >= 70
    346       cinfo->q_scale_factor[tblno] = jpeg_quality_scaling(val);
    347 #else
    348       q_scale_factor[tblno] = jpeg_quality_scaling(val);
    349 #endif
    350     }
    351   }
    352   jpeg_default_qtables(cinfo, force_baseline);
    353   return TRUE;
    354 }
    355 
    356 
    357 GLOBAL(boolean)
    358 set_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 {
    364   int val = 0;                  /* default table # */
    365   int ci;
    366   char ch;
    367 
    368   for (ci = 0; ci < MAX_COMPONENTS; ci++) {
    369     if (*arg) {
    370       ch = ',';                 /* if not set by sscanf, will be ',' */
    371       if (sscanf(arg, "%d%c", &val, &ch) < 1)
    372         return FALSE;
    373       if (ch != ',')            /* syntax check */
    374         return FALSE;
    375       if (val < 0 || val >= NUM_QUANT_TBLS) {
    376         fprintf(stderr, "JPEG quantization tables are numbered 0..%d\n",
    377                 NUM_QUANT_TBLS-1);
    378         return FALSE;
    379       }
    380       cinfo->comp_info[ci].quant_tbl_no = val;
    381       while (*arg && *arg++ != ',') /* advance to next segment of arg string */
    382         ;
    383     } 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 
    392 GLOBAL(boolean)
    393 set_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) {
    404       ch2 = ',';                /* if not set by sscanf, will be ',' */
    405       if (sscanf(arg, "%d%c%d%c", &val1, &ch1, &val2, &ch2) < 3)
    406         return FALSE;
    407       if ((ch1 != 'x' && ch1 != 'X') || ch2 != ',') /* syntax check */
    408         return FALSE;
    409       if (val1 <= 0 || val1 > 4 || val2 <= 0 || val2 > 4) {
    410         fprintf(stderr, "JPEG sampling factors must be 1..4\n");
    411         return FALSE;
    412       }
    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 */
    416         ;
    417     } 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 }
    425