Home | History | Annotate | Download | only in jpeg
      1 /*
      2  * wrrle.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 write output images in 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 output to
     13  * an ordinary stdio stream.
     14  *
     15  * Based on code contributed by Mike Lijewski,
     16  * with updates from Robert Hutchinson.
     17  */
     18 
     19 #include "cdjpeg.h"		/* Common decls for cjpeg/djpeg applications */
     20 
     21 #ifdef RLE_SUPPORTED
     22 
     23 /* rle.h is provided by the Utah Raster Toolkit. */
     24 
     25 #include <rle.h>
     26 
     27 /*
     28  * We assume that JSAMPLE has the same representation as rle_pixel,
     29  * to wit, "unsigned char".  Hence we can't cope with 12- or 16-bit samples.
     30  */
     31 
     32 #if BITS_IN_JSAMPLE != 8
     33   Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */
     34 #endif
     35 
     36 
     37 /*
     38  * Since RLE stores scanlines bottom-to-top, we have to invert the image
     39  * from JPEG's top-to-bottom order.  To do this, we save the outgoing data
     40  * in a virtual array during put_pixel_row calls, then actually emit the
     41  * RLE file during finish_output.
     42  */
     43 
     44 
     45 /*
     46  * For now, if we emit an RLE color map then it is always 256 entries long,
     47  * though not all of the entries need be used.
     48  */
     49 
     50 #define CMAPBITS	8
     51 #define CMAPLENGTH	(1<<(CMAPBITS))
     52 
     53 typedef struct {
     54   struct djpeg_dest_struct pub; /* public fields */
     55 
     56   jvirt_sarray_ptr image;	/* virtual array to store the output image */
     57   rle_map *colormap;	 	/* RLE-style color map, or NULL if none */
     58   rle_pixel **rle_row;		/* To pass rows to rle_putrow() */
     59 
     60 } rle_dest_struct;
     61 
     62 typedef rle_dest_struct * rle_dest_ptr;
     63 
     64 /* Forward declarations */
     65 METHODDEF(void) rle_put_pixel_rows
     66     JPP((j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
     67 	 JDIMENSION rows_supplied));
     68 
     69 
     70 /*
     71  * Write the file header.
     72  *
     73  * In this module it's easier to wait till finish_output to write anything.
     74  */
     75 
     76 METHODDEF(void)
     77 start_output_rle (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
     78 {
     79   rle_dest_ptr dest = (rle_dest_ptr) dinfo;
     80   size_t cmapsize;
     81   int i, ci;
     82 #ifdef PROGRESS_REPORT
     83   cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
     84 #endif
     85 
     86   /*
     87    * Make sure the image can be stored in RLE format.
     88    *
     89    * - RLE stores image dimensions as *signed* 16 bit integers.  JPEG
     90    *   uses unsigned, so we have to check the width.
     91    *
     92    * - Colorspace is expected to be grayscale or RGB.
     93    *
     94    * - The number of channels (components) is expected to be 1 (grayscale/
     95    *   pseudocolor) or 3 (truecolor/directcolor).
     96    *   (could be 2 or 4 if using an alpha channel, but we aren't)
     97    */
     98 
     99   if (cinfo->output_width > 32767 || cinfo->output_height > 32767)
    100     ERREXIT2(cinfo, JERR_RLE_DIMENSIONS, cinfo->output_width,
    101 	     cinfo->output_height);
    102 
    103   if (cinfo->out_color_space != JCS_GRAYSCALE &&
    104       cinfo->out_color_space != JCS_RGB)
    105     ERREXIT(cinfo, JERR_RLE_COLORSPACE);
    106 
    107   if (cinfo->output_components != 1 && cinfo->output_components != 3)
    108     ERREXIT1(cinfo, JERR_RLE_TOOMANYCHANNELS, cinfo->num_components);
    109 
    110   /* Convert colormap, if any, to RLE format. */
    111 
    112   dest->colormap = NULL;
    113 
    114   if (cinfo->quantize_colors) {
    115     /* Allocate storage for RLE-style cmap, zero any extra entries */
    116     cmapsize = cinfo->out_color_components * CMAPLENGTH * SIZEOF(rle_map);
    117     dest->colormap = (rle_map *) (*cinfo->mem->alloc_small)
    118       ((j_common_ptr) cinfo, JPOOL_IMAGE, cmapsize);
    119     MEMZERO(dest->colormap, cmapsize);
    120 
    121     /* Save away data in RLE format --- note 8-bit left shift! */
    122     /* Shifting would need adjustment for JSAMPLEs wider than 8 bits. */
    123     for (ci = 0; ci < cinfo->out_color_components; ci++) {
    124       for (i = 0; i < cinfo->actual_number_of_colors; i++) {
    125         dest->colormap[ci * CMAPLENGTH + i] =
    126           GETJSAMPLE(cinfo->colormap[ci][i]) << 8;
    127       }
    128     }
    129   }
    130 
    131   /* Set the output buffer to the first row */
    132   dest->pub.buffer = (*cinfo->mem->access_virt_sarray)
    133     ((j_common_ptr) cinfo, dest->image, (JDIMENSION) 0, (JDIMENSION) 1, TRUE);
    134   dest->pub.buffer_height = 1;
    135 
    136   dest->pub.put_pixel_rows = rle_put_pixel_rows;
    137 
    138 #ifdef PROGRESS_REPORT
    139   if (progress != NULL) {
    140     progress->total_extra_passes++;  /* count file writing as separate pass */
    141   }
    142 #endif
    143 }
    144 
    145 
    146 /*
    147  * Write some pixel data.
    148  *
    149  * This routine just saves the data away in a virtual array.
    150  */
    151 
    152 METHODDEF(void)
    153 rle_put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
    154 		    JDIMENSION rows_supplied)
    155 {
    156   rle_dest_ptr dest = (rle_dest_ptr) dinfo;
    157 
    158   if (cinfo->output_scanline < cinfo->output_height) {
    159     dest->pub.buffer = (*cinfo->mem->access_virt_sarray)
    160       ((j_common_ptr) cinfo, dest->image,
    161        cinfo->output_scanline, (JDIMENSION) 1, TRUE);
    162   }
    163 }
    164 
    165 /*
    166  * Finish up at the end of the file.
    167  *
    168  * Here is where we really output the RLE file.
    169  */
    170 
    171 METHODDEF(void)
    172 finish_output_rle (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
    173 {
    174   rle_dest_ptr dest = (rle_dest_ptr) dinfo;
    175   rle_hdr header;		/* Output file information */
    176   rle_pixel **rle_row, *red, *green, *blue;
    177   JSAMPROW output_row;
    178   char cmapcomment[80];
    179   int row, col;
    180   int ci;
    181 #ifdef PROGRESS_REPORT
    182   cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
    183 #endif
    184 
    185   /* Initialize the header info */
    186   header = *rle_hdr_init(NULL);
    187   header.rle_file = dest->pub.output_file;
    188   header.xmin     = 0;
    189   header.xmax     = cinfo->output_width  - 1;
    190   header.ymin     = 0;
    191   header.ymax     = cinfo->output_height - 1;
    192   header.alpha    = 0;
    193   header.ncolors  = cinfo->output_components;
    194   for (ci = 0; ci < cinfo->output_components; ci++) {
    195     RLE_SET_BIT(header, ci);
    196   }
    197   if (cinfo->quantize_colors) {
    198     header.ncmap   = cinfo->out_color_components;
    199     header.cmaplen = CMAPBITS;
    200     header.cmap    = dest->colormap;
    201     /* Add a comment to the output image with the true colormap length. */
    202     sprintf(cmapcomment, "color_map_length=%d", cinfo->actual_number_of_colors);
    203     rle_putcom(cmapcomment, &header);
    204   }
    205 
    206   /* Emit the RLE header and color map (if any) */
    207   rle_put_setup(&header);
    208 
    209   /* Now output the RLE data from our virtual array.
    210    * We assume here that (a) rle_pixel is represented the same as JSAMPLE,
    211    * and (b) we are not on a machine where FAR pointers differ from regular.
    212    */
    213 
    214 #ifdef PROGRESS_REPORT
    215   if (progress != NULL) {
    216     progress->pub.pass_limit = cinfo->output_height;
    217     progress->pub.pass_counter = 0;
    218     (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
    219   }
    220 #endif
    221 
    222   if (cinfo->output_components == 1) {
    223     for (row = cinfo->output_height-1; row >= 0; row--) {
    224       rle_row = (rle_pixel **) (*cinfo->mem->access_virt_sarray)
    225         ((j_common_ptr) cinfo, dest->image,
    226 	 (JDIMENSION) row, (JDIMENSION) 1, FALSE);
    227       rle_putrow(rle_row, (int) cinfo->output_width, &header);
    228 #ifdef PROGRESS_REPORT
    229       if (progress != NULL) {
    230         progress->pub.pass_counter++;
    231         (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
    232       }
    233 #endif
    234     }
    235   } else {
    236     for (row = cinfo->output_height-1; row >= 0; row--) {
    237       rle_row = (rle_pixel **) dest->rle_row;
    238       output_row = * (*cinfo->mem->access_virt_sarray)
    239         ((j_common_ptr) cinfo, dest->image,
    240 	 (JDIMENSION) row, (JDIMENSION) 1, FALSE);
    241       red = rle_row[0];
    242       green = rle_row[1];
    243       blue = rle_row[2];
    244       for (col = cinfo->output_width; col > 0; col--) {
    245         *red++ = GETJSAMPLE(*output_row++);
    246         *green++ = GETJSAMPLE(*output_row++);
    247         *blue++ = GETJSAMPLE(*output_row++);
    248       }
    249       rle_putrow(rle_row, (int) cinfo->output_width, &header);
    250 #ifdef PROGRESS_REPORT
    251       if (progress != NULL) {
    252         progress->pub.pass_counter++;
    253         (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
    254       }
    255 #endif
    256     }
    257   }
    258 
    259 #ifdef PROGRESS_REPORT
    260   if (progress != NULL)
    261     progress->completed_extra_passes++;
    262 #endif
    263 
    264   /* Emit file trailer */
    265   rle_puteof(&header);
    266   fflush(dest->pub.output_file);
    267   if (ferror(dest->pub.output_file))
    268     ERREXIT(cinfo, JERR_FILE_WRITE);
    269 }
    270 
    271 
    272 /*
    273  * The module selection routine for RLE format output.
    274  */
    275 
    276 GLOBAL(djpeg_dest_ptr)
    277 jinit_write_rle (j_decompress_ptr cinfo)
    278 {
    279   rle_dest_ptr dest;
    280 
    281   /* Create module interface object, fill in method pointers */
    282   dest = (rle_dest_ptr)
    283       (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
    284                                   SIZEOF(rle_dest_struct));
    285   dest->pub.start_output = start_output_rle;
    286   dest->pub.finish_output = finish_output_rle;
    287 
    288   /* Calculate output image dimensions so we can allocate space */
    289   jpeg_calc_output_dimensions(cinfo);
    290 
    291   /* Allocate a work array for output to the RLE library. */
    292   dest->rle_row = (*cinfo->mem->alloc_sarray)
    293     ((j_common_ptr) cinfo, JPOOL_IMAGE,
    294      cinfo->output_width, (JDIMENSION) cinfo->output_components);
    295 
    296   /* Allocate a virtual array to hold the image. */
    297   dest->image = (*cinfo->mem->request_virt_sarray)
    298     ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
    299      (JDIMENSION) (cinfo->output_width * cinfo->output_components),
    300      cinfo->output_height, (JDIMENSION) 1);
    301 
    302   return (djpeg_dest_ptr) dest;
    303 }
    304 
    305 #endif /* RLE_SUPPORTED */
    306