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