| /* |
| * 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 */ |