233 lines
6.6 KiB
C
233 lines
6.6 KiB
C
/*
|
|
* jwrrle.c
|
|
*
|
|
* Copyright (C) 1991, 1992, 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((void *) 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((void *) &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");
|
|
|
|
/* 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 */
|