Home | History | Annotate | Download | only in jpeg
      1 /*
      2  * rdrle.c
      3  *
      4  * Copyright (C) 1991-1996, Thomas G. Lane.
      5  * This file is part of the Independent JPEG Group's software.
      6  * For conditions of distribution and use, see the accompanying README file.
      7  *
      8  * This file contains routines to read input images in Utah RLE format.
      9  * The Utah Raster Toolkit library is required (version 3.1 or later).
     10  *
     11  * These routines may need modification for non-Unix environments or
     12  * specialized applications.  As they stand, they assume input from
     13  * an ordinary stdio stream.  They further assume that reading begins
     14  * at the start of the file; start_input may need work if the
     15  * user interface has already read some data (e.g., to determine that
     16  * the file is indeed RLE format).
     17  *
     18  * Based on code contributed by Mike Lijewski,
     19  * with updates from Robert Hutchinson.
     20  */
     21 
     22 #include "cdjpeg.h"		/* Common decls for cjpeg/djpeg applications */
     23 
     24 #ifdef RLE_SUPPORTED
     25 
     26 /* rle.h is provided by the Utah Raster Toolkit. */
     27 
     28 #include <rle.h>
     29 
     30 /*
     31  * We assume that JSAMPLE has the same representation as rle_pixel,
     32  * to wit, "unsigned char".  Hence we can't cope with 12- or 16-bit samples.
     33  */
     34 
     35 #if BITS_IN_JSAMPLE != 8
     36   Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */
     37 #endif
     38 
     39 /*
     40  * We support the following types of RLE files:
     41  *
     42  *   GRAYSCALE   - 8 bits, no colormap
     43  *   MAPPEDGRAY  - 8 bits, 1 channel colomap
     44  *   PSEUDOCOLOR - 8 bits, 3 channel colormap
     45  *   TRUECOLOR   - 24 bits, 3 channel colormap
     46  *   DIRECTCOLOR - 24 bits, no colormap
     47  *
     48  * For now, we ignore any alpha channel in the image.
     49  */
     50 
     51 typedef enum
     52   { GRAYSCALE, MAPPEDGRAY, PSEUDOCOLOR, TRUECOLOR, DIRECTCOLOR } rle_kind;
     53 
     54 
     55 /*
     56  * Since RLE stores scanlines bottom-to-top, we have to invert the image
     57  * to conform to JPEG's top-to-bottom order.  To do this, we read the
     58  * incoming image into a virtual array on the first get_pixel_rows call,
     59  * then fetch the required row from the virtual array on subsequent calls.
     60  */
     61 
     62 typedef struct _rle_source_struct * rle_source_ptr;
     63 
     64 typedef struct _rle_source_struct {
     65   struct cjpeg_source_struct pub; /* public fields */
     66 
     67   rle_kind visual;              /* actual type of input file */
     68   jvirt_sarray_ptr image;       /* virtual array to hold the image */
     69   JDIMENSION row;		/* current row # in the virtual array */
     70   rle_hdr header;               /* Input file information */
     71   rle_pixel** rle_row;          /* holds a row returned by rle_getrow() */
     72 
     73 } rle_source_struct;
     74 
     75 
     76 /*
     77  * Read the file header; return image size and component count.
     78  */
     79 
     80 METHODDEF(void)
     81 start_input_rle (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
     82 {
     83   rle_source_ptr source = (rle_source_ptr) sinfo;
     84   JDIMENSION width, height;
     85 #ifdef PROGRESS_REPORT
     86   cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
     87 #endif
     88 
     89   /* Use RLE library routine to get the header info */
     90   source->header = *rle_hdr_init(NULL);
     91   source->header.rle_file = source->pub.input_file;
     92   switch (rle_get_setup(&(source->header))) {
     93   case RLE_SUCCESS:
     94     /* A-OK */
     95     break;
     96   case RLE_NOT_RLE:
     97     ERREXIT(cinfo, JERR_RLE_NOT);
     98     break;
     99   case RLE_NO_SPACE:
    100     ERREXIT(cinfo, JERR_RLE_MEM);
    101     break;
    102   case RLE_EMPTY:
    103     ERREXIT(cinfo, JERR_RLE_EMPTY);
    104     break;
    105   case RLE_EOF:
    106     ERREXIT(cinfo, JERR_RLE_EOF);
    107     break;
    108   default:
    109     ERREXIT(cinfo, JERR_RLE_BADERROR);
    110     break;
    111   }
    112 
    113   /* Figure out what we have, set private vars and return values accordingly */
    114 
    115   width  = source->header.xmax - source->header.xmin + 1;
    116   height = source->header.ymax - source->header.ymin + 1;
    117   source->header.xmin = 0;		/* realign horizontally */
    118   source->header.xmax = width-1;
    119 
    120   cinfo->image_width      = width;
    121   cinfo->image_height     = height;
    122   cinfo->data_precision   = 8;  /* we can only handle 8 bit data */
    123 
    124   if (source->header.ncolors == 1 && source->header.ncmap == 0) {
    125     source->visual     = GRAYSCALE;
    126     TRACEMS2(cinfo, 1, JTRC_RLE_GRAY, width, height);
    127   } else if (source->header.ncolors == 1 && source->header.ncmap == 1) {
    128     source->visual     = MAPPEDGRAY;
    129     TRACEMS3(cinfo, 1, JTRC_RLE_MAPGRAY, width, height,
    130              1 << source->header.cmaplen);
    131   } else if (source->header.ncolors == 1 && source->header.ncmap == 3) {
    132     source->visual     = PSEUDOCOLOR;
    133     TRACEMS3(cinfo, 1, JTRC_RLE_MAPPED, width, height,
    134 	     1 << source->header.cmaplen);
    135   } else if (source->header.ncolors == 3 && source->header.ncmap == 3) {
    136     source->visual     = TRUECOLOR;
    137     TRACEMS3(cinfo, 1, JTRC_RLE_FULLMAP, width, height,
    138 	     1 << source->header.cmaplen);
    139   } else if (source->header.ncolors == 3 && source->header.ncmap == 0) {
    140     source->visual     = DIRECTCOLOR;
    141     TRACEMS2(cinfo, 1, JTRC_RLE, width, height);
    142   } else
    143     ERREXIT(cinfo, JERR_RLE_UNSUPPORTED);
    144 
    145   if (source->visual == GRAYSCALE || source->visual == MAPPEDGRAY) {
    146     cinfo->in_color_space   = JCS_GRAYSCALE;
    147     cinfo->input_components = 1;
    148   } else {
    149     cinfo->in_color_space   = JCS_RGB;
    150     cinfo->input_components = 3;
    151   }
    152 
    153   /*
    154    * A place to hold each scanline while it's converted.
    155    * (GRAYSCALE scanlines don't need converting)
    156    */
    157   if (source->visual != GRAYSCALE) {
    158     source->rle_row = (rle_pixel**) (*cinfo->mem->alloc_sarray)
    159       ((j_common_ptr) cinfo, JPOOL_IMAGE,
    160        (JDIMENSION) width, (JDIMENSION) cinfo->input_components);
    161   }
    162 
    163   /* request a virtual array to hold the image */
    164   source->image = (*cinfo->mem->request_virt_sarray)
    165     ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
    166      (JDIMENSION) (width * source->header.ncolors),
    167      (JDIMENSION) height, (JDIMENSION) 1);
    168 
    169 #ifdef PROGRESS_REPORT
    170   if (progress != NULL) {
    171     /* count file input as separate pass */
    172     progress->total_extra_passes++;
    173   }
    174 #endif
    175 
    176   source->pub.buffer_height = 1;
    177 }
    178 
    179 
    180 /*
    181  * Read one row of pixels.
    182  * Called only after load_image has read the image into the virtual array.
    183  * Used for GRAYSCALE, MAPPEDGRAY, TRUECOLOR, and DIRECTCOLOR images.
    184  */
    185 
    186 METHODDEF(JDIMENSION)
    187 get_rle_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
    188 {
    189   rle_source_ptr source = (rle_source_ptr) sinfo;
    190 
    191   source->row--;
    192   source->pub.buffer = (*cinfo->mem->access_virt_sarray)
    193     ((j_common_ptr) cinfo, source->image, source->row, (JDIMENSION) 1, FALSE);
    194 
    195   return 1;
    196 }
    197 
    198 /*
    199  * Read one row of pixels.
    200  * Called only after load_image has read the image into the virtual array.
    201  * Used for PSEUDOCOLOR images.
    202  */
    203 
    204 METHODDEF(JDIMENSION)
    205 get_pseudocolor_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
    206 {
    207   rle_source_ptr source = (rle_source_ptr) sinfo;
    208   JSAMPROW src_row, dest_row;
    209   JDIMENSION col;
    210   rle_map *colormap;
    211   int val;
    212 
    213   colormap = source->header.cmap;
    214   dest_row = source->pub.buffer[0];
    215   source->row--;
    216   src_row = * (*cinfo->mem->access_virt_sarray)
    217     ((j_common_ptr) cinfo, source->image, source->row, (JDIMENSION) 1, FALSE);
    218 
    219   for (col = cinfo->image_width; col > 0; col--) {
    220     val = GETJSAMPLE(*src_row++);
    221     *dest_row++ = (JSAMPLE) (colormap[val      ] >> 8);
    222     *dest_row++ = (JSAMPLE) (colormap[val + 256] >> 8);
    223     *dest_row++ = (JSAMPLE) (colormap[val + 512] >> 8);
    224   }
    225 
    226   return 1;
    227 }
    228 
    229 
    230 /*
    231  * Load the image into a virtual array.  We have to do this because RLE
    232  * files start at the lower left while the JPEG standard has them starting
    233  * in the upper left.  This is called the first time we want to get a row
    234  * of input.  What we do is load the RLE data into the array and then call
    235  * the appropriate routine to read one row from the array.  Before returning,
    236  * we set source->pub.get_pixel_rows so that subsequent calls go straight to
    237  * the appropriate row-reading routine.
    238  */
    239 
    240 METHODDEF(JDIMENSION)
    241 load_image (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
    242 {
    243   rle_source_ptr source = (rle_source_ptr) sinfo;
    244   JDIMENSION row, col;
    245   JSAMPROW  scanline, red_ptr, green_ptr, blue_ptr;
    246   rle_pixel **rle_row;
    247   rle_map *colormap;
    248   char channel;
    249 #ifdef PROGRESS_REPORT
    250   cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
    251 #endif
    252 
    253   colormap = source->header.cmap;
    254   rle_row = source->rle_row;
    255 
    256   /* Read the RLE data into our virtual array.
    257    * We assume here that (a) rle_pixel is represented the same as JSAMPLE,
    258    * and (b) we are not on a machine where FAR pointers differ from regular.
    259    */
    260   RLE_CLR_BIT(source->header, RLE_ALPHA); /* don't read the alpha channel */
    261 
    262 #ifdef PROGRESS_REPORT
    263   if (progress != NULL) {
    264     progress->pub.pass_limit = cinfo->image_height;
    265     progress->pub.pass_counter = 0;
    266     (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
    267   }
    268 #endif
    269 
    270   switch (source->visual) {
    271 
    272   case GRAYSCALE:
    273   case PSEUDOCOLOR:
    274     for (row = 0; row < cinfo->image_height; row++) {
    275       rle_row = (rle_pixel **) (*cinfo->mem->access_virt_sarray)
    276          ((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE);
    277       rle_getrow(&source->header, rle_row);
    278 #ifdef PROGRESS_REPORT
    279       if (progress != NULL) {
    280         progress->pub.pass_counter++;
    281         (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
    282       }
    283 #endif
    284     }
    285     break;
    286 
    287   case MAPPEDGRAY:
    288   case TRUECOLOR:
    289     for (row = 0; row < cinfo->image_height; row++) {
    290       scanline = * (*cinfo->mem->access_virt_sarray)
    291         ((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE);
    292       rle_row = source->rle_row;
    293       rle_getrow(&source->header, rle_row);
    294 
    295       for (col = 0; col < cinfo->image_width; col++) {
    296         for (channel = 0; channel < source->header.ncolors; channel++) {
    297           *scanline++ = (JSAMPLE)
    298             (colormap[GETJSAMPLE(rle_row[channel][col]) + 256 * channel] >> 8);
    299         }
    300       }
    301 
    302 #ifdef PROGRESS_REPORT
    303       if (progress != NULL) {
    304         progress->pub.pass_counter++;
    305         (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
    306       }
    307 #endif
    308     }
    309     break;
    310 
    311   case DIRECTCOLOR:
    312     for (row = 0; row < cinfo->image_height; row++) {
    313       scanline = * (*cinfo->mem->access_virt_sarray)
    314         ((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE);
    315       rle_getrow(&source->header, rle_row);
    316 
    317       red_ptr   = rle_row[0];
    318       green_ptr = rle_row[1];
    319       blue_ptr  = rle_row[2];
    320 
    321       for (col = cinfo->image_width; col > 0; col--) {
    322         *scanline++ = *red_ptr++;
    323         *scanline++ = *green_ptr++;
    324         *scanline++ = *blue_ptr++;
    325       }
    326 
    327 #ifdef PROGRESS_REPORT
    328       if (progress != NULL) {
    329         progress->pub.pass_counter++;
    330         (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
    331       }
    332 #endif
    333     }
    334   }
    335 
    336 #ifdef PROGRESS_REPORT
    337   if (progress != NULL)
    338     progress->completed_extra_passes++;
    339 #endif
    340 
    341   /* Set up to call proper row-extraction routine in future */
    342   if (source->visual == PSEUDOCOLOR) {
    343     source->pub.buffer = source->rle_row;
    344     source->pub.get_pixel_rows = get_pseudocolor_row;
    345   } else {
    346     source->pub.get_pixel_rows = get_rle_row;
    347   }
    348   source->row = cinfo->image_height;
    349 
    350   /* And fetch the topmost (bottommost) row */
    351   return (*source->pub.get_pixel_rows) (cinfo, sinfo);
    352 }
    353 
    354 
    355 /*
    356  * Finish up at the end of the file.
    357  */
    358 
    359 METHODDEF(void)
    360 finish_input_rle (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
    361 {
    362   /* no work */
    363 }
    364 
    365 
    366 /*
    367  * The module selection routine for RLE format input.
    368  */
    369 
    370 GLOBAL(cjpeg_source_ptr)
    371 jinit_read_rle (j_compress_ptr cinfo)
    372 {
    373   rle_source_ptr source;
    374 
    375   /* Create module interface object */
    376   source = (rle_source_ptr)
    377       (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
    378                                   SIZEOF(rle_source_struct));
    379   /* Fill in method ptrs */
    380   source->pub.start_input = start_input_rle;
    381   source->pub.finish_input = finish_input_rle;
    382   source->pub.get_pixel_rows = load_image;
    383 
    384   return (cjpeg_source_ptr) source;
    385 }
    386 
    387 #endif /* RLE_SUPPORTED */
    388