blob: 0c8718e32d281d383c76efbd1c2a1b9a42403222 [file] [log] [blame]
/*
* jwrrle.c
*
* Copyright (C) 1991, 1992, 1993, Thomas G. Lane.
* This file is part of the Independent JPEG Group's software.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains routines to write output images in RLE format.
* The Utah Raster Toolkit library is required (version 3.0).
*
* These routines may need modification for non-Unix environments or
* specialized applications. As they stand, they assume output to
* an ordinary stdio stream.
*
* These routines are invoked via the methods put_pixel_rows, put_color_map,
* and output_init/term.
*
* Based on code contributed by Mike Lijewski.
*/
#include "jinclude.h"
#ifdef RLE_SUPPORTED
/* rle.h is provided by the Utah Raster Toolkit. */
#include <rle.h>
/*
* output_term assumes that JSAMPLE has the same representation as rle_pixel,
* to wit, "unsigned char". Hence we can't cope with 12- or 16-bit samples.
*/
#ifndef EIGHT_BIT_SAMPLES
Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */
#endif
/*
* Since RLE stores scanlines bottom-to-top, we have to invert the image
* from JPEG's top-to-bottom order. To do this, we save the outgoing data
* in virtual array(s) during put_pixel_row calls, then actually emit the
* RLE file during output_term. We use one virtual array if the output is
* grayscale or colormapped, more if it is full color.
*/
#define MAX_CHANS 4 /* allow up to four color components */
static big_sarray_ptr channels[MAX_CHANS]; /* Virtual arrays for saved data */
static long cur_output_row; /* next row# to write to virtual array(s) */
/*
* For now, if we emit an RLE color map then it is always 256 entries long,
* though not all of the entries need be used.
*/
#define CMAPBITS 8
#define CMAPLENGTH (1<<(CMAPBITS))
static rle_map *output_colormap; /* RLE-style color map, or NULL if none */
static int number_colors; /* Number of colors actually used */
/*
* Write the file header.
*
* In this module it's easier to wait till output_term to actually write
* anything; here we just request the big arrays we'll need.
*/
METHODDEF void
output_init (decompress_info_ptr cinfo)
{
short ci;
if (cinfo->final_out_comps > MAX_CHANS)
ERREXIT1(cinfo->emethods, "Cannot handle %d output channels for RLE",
cinfo->final_out_comps);
for (ci = 0; ci < cinfo->final_out_comps; ci++) {
channels[ci] = (*cinfo->emethods->request_big_sarray)
(cinfo->image_width, cinfo->image_height, 1L);
}
output_colormap = NULL; /* No output colormap as yet */
number_colors = 0;
cur_output_row = 0; /* Start filling virtual arrays at row 0 */
cinfo->total_passes++; /* count file writing as separate pass */
}
/*
* Write some pixel data.
*
* This routine just saves the data away in virtual arrays.
*/
METHODDEF void
put_pixel_rows (decompress_info_ptr cinfo, int num_rows,
JSAMPIMAGE pixel_data)
{
JSAMPROW outputrow[1]; /* a pseudo JSAMPARRAY structure */
int row;
short ci;
for (row = 0; row < num_rows; row++) {
for (ci = 0; ci < cinfo->final_out_comps; ci++) {
outputrow[0] = *((*cinfo->emethods->access_big_sarray)
(channels[ci], cur_output_row, TRUE));
jcopy_sample_rows(pixel_data[ci], row, outputrow, 0,
1, cinfo->image_width);
}
cur_output_row++;
}
}
/*
* Write the color map.
*
* For RLE output we just save the colormap for the output stage.
*/
METHODDEF void
put_color_map (decompress_info_ptr cinfo, int num_colors, JSAMPARRAY colormap)
{
size_t cmapsize;
short ci;
int i;
if (num_colors > CMAPLENGTH)
ERREXIT1(cinfo->emethods, "Cannot handle %d colormap entries for RLE",
num_colors);
/* Allocate storage for RLE-style cmap, zero any extra entries */
cmapsize = cinfo->color_out_comps * CMAPLENGTH * SIZEOF(rle_map);
output_colormap = (rle_map *) (*cinfo->emethods->alloc_small) (cmapsize);
MEMZERO(output_colormap, cmapsize);
/* Save away data in RLE format --- note 8-bit left shift! */
/* Shifting would need adjustment for JSAMPLEs wider than 8 bits. */
for (ci = 0; ci < cinfo->color_out_comps; ci++) {
for (i = 0; i < num_colors; i++) {
output_colormap[ci * CMAPLENGTH + i] = GETJSAMPLE(colormap[ci][i]) << 8;
}
}
number_colors = num_colors;
}
/*
* Finish up at the end of the file.
*
* Here is where we really output the RLE file.
*/
METHODDEF void
output_term (decompress_info_ptr cinfo)
{
rle_hdr header; /* Output file information */
rle_pixel *output_rows[MAX_CHANS];
char cmapcomment[80];
short ci;
long row;
/* Initialize the header info */
MEMZERO(&header, SIZEOF(rle_hdr)); /* make sure all bits are 0 */
header.rle_file = cinfo->output_file;
header.xmin = 0;
header.xmax = cinfo->image_width - 1;
header.ymin = 0;
header.ymax = cinfo->image_height - 1;
header.alpha = 0;
header.ncolors = cinfo->final_out_comps;
for (ci = 0; ci < cinfo->final_out_comps; ci++) {
RLE_SET_BIT(header, ci);
}
if (number_colors > 0) {
header.ncmap = cinfo->color_out_comps;
header.cmaplen = CMAPBITS;
header.cmap = output_colormap;
/* Add a comment to the output image with the true colormap length. */
sprintf(cmapcomment, "color_map_length=%d", number_colors);
rle_putcom(cmapcomment, &header);
}
/* Emit the RLE header and color map (if any) */
rle_put_setup(&header);
/* Now output the RLE data from our virtual array(s).
* We assume here that (a) rle_pixel is represented the same as JSAMPLE,
* and (b) we are not on a machine where FAR pointers differ from regular.
*/
for (row = cinfo->image_height-1; row >= 0; row--) {
(*cinfo->methods->progress_monitor) (cinfo, cinfo->image_height-row-1,
cinfo->image_height);
for (ci = 0; ci < cinfo->final_out_comps; ci++) {
output_rows[ci] = (rle_pixel *) *((*cinfo->emethods->access_big_sarray)
(channels[ci], row, FALSE));
}
rle_putrow(output_rows, (int) cinfo->image_width, &header);
}
cinfo->completed_passes++;
/* Emit file trailer */
rle_puteof(&header);
fflush(cinfo->output_file);
if (ferror(cinfo->output_file))
ERREXIT(cinfo->emethods, "Output file write error --- out of disk space?");
/* Release memory */
/* no work (we let free_all release the workspace) */
}
/*
* The method selection routine for RLE format output.
* This should be called from d_ui_method_selection if RLE output is wanted.
*/
GLOBAL void
jselwrle (decompress_info_ptr cinfo)
{
cinfo->methods->output_init = output_init;
cinfo->methods->put_color_map = put_color_map;
cinfo->methods->put_pixel_rows = put_pixel_rows;
cinfo->methods->output_term = output_term;
}
#endif /* RLE_SUPPORTED */