| /* |
| * jrdrle.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 read input images in Utah 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 input from |
| * an ordinary stdio stream. They further assume that reading begins |
| * at the start of the file; input_init may need work if the |
| * user interface has already read some data (e.g., to determine that |
| * the file is indeed RLE format). |
| * |
| * These routines are invoked via the methods get_input_row |
| * and input_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> |
| |
| |
| /* |
| * load_image 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 |
| |
| |
| /* |
| * We support the following types of RLE files: |
| * |
| * GRAYSCALE - 8 bits, no colormap |
| * PSEUDOCOLOR - 8 bits, colormap |
| * TRUECOLOR - 24 bits, colormap |
| * DIRECTCOLOR - 24 bits, no colormap |
| * |
| * For now, we ignore any alpha channel in the image. |
| */ |
| |
| typedef enum { GRAYSCALE, PSEUDOCOLOR, TRUECOLOR, DIRECTCOLOR } rle_kind; |
| |
| static rle_kind visual; /* actual type of input file */ |
| |
| /* |
| * Since RLE stores scanlines bottom-to-top, we have to invert the image |
| * to conform to JPEG's top-to-bottom order. To do this, we read the |
| * incoming image into a virtual array on the first get_input_row call, |
| * then fetch the required row from the virtual array on subsequent calls. |
| */ |
| |
| static big_sarray_ptr image; /* single array for GRAYSCALE/PSEUDOCOLOR */ |
| static big_sarray_ptr red_channel; /* three arrays for TRUECOLOR/DIRECTCOLOR */ |
| static big_sarray_ptr green_channel; |
| static big_sarray_ptr blue_channel; |
| static long cur_row_number; /* last row# read from virtual array */ |
| |
| static rle_hdr header; /* Input file information */ |
| static rle_map *colormap; /* RLE colormap, if any */ |
| |
| |
| /* |
| * Read the file header; return image size and component count. |
| */ |
| |
| METHODDEF void |
| input_init (compress_info_ptr cinfo) |
| { |
| long width, height; |
| |
| /* Use RLE library routine to get the header info */ |
| header.rle_file = cinfo->input_file; |
| switch (rle_get_setup(&header)) { |
| case RLE_SUCCESS: |
| /* A-OK */ |
| break; |
| case RLE_NOT_RLE: |
| ERREXIT(cinfo->emethods, "Not an RLE file"); |
| break; |
| case RLE_NO_SPACE: |
| ERREXIT(cinfo->emethods, "Insufficient memory for RLE header"); |
| break; |
| case RLE_EMPTY: |
| ERREXIT(cinfo->emethods, "Empty RLE file"); |
| break; |
| case RLE_EOF: |
| ERREXIT(cinfo->emethods, "Premature EOF in RLE header"); |
| break; |
| default: |
| ERREXIT(cinfo->emethods, "Bogus RLE error code"); |
| break; |
| } |
| |
| /* Figure out what we have, set private vars and return values accordingly */ |
| |
| width = header.xmax - header.xmin + 1; |
| height = header.ymax - header.ymin + 1; |
| header.xmin = 0; /* realign horizontally */ |
| header.xmax = width-1; |
| |
| cinfo->image_width = width; |
| cinfo->image_height = height; |
| cinfo->data_precision = 8; /* we can only handle 8 bit data */ |
| |
| if (header.ncolors == 1 && header.ncmap == 0) { |
| visual = GRAYSCALE; |
| TRACEMS(cinfo->emethods, 1, "Gray-scale RLE file"); |
| } else if (header.ncolors == 1 && header.ncmap == 3) { |
| visual = PSEUDOCOLOR; |
| colormap = header.cmap; |
| TRACEMS1(cinfo->emethods, 1, "Colormapped RLE file with map of length %d", |
| 1 << header.cmaplen); |
| } else if (header.ncolors == 3 && header.ncmap == 3) { |
| visual = TRUECOLOR; |
| colormap = header.cmap; |
| TRACEMS1(cinfo->emethods, 1, "Full-color RLE file with map of length %d", |
| 1 << header.cmaplen); |
| } else if (header.ncolors == 3 && header.ncmap == 0) { |
| visual = DIRECTCOLOR; |
| TRACEMS(cinfo->emethods, 1, "Full-color RLE file"); |
| } else |
| ERREXIT(cinfo->emethods, "Can't handle this RLE setup"); |
| |
| switch (visual) { |
| case GRAYSCALE: |
| /* request one big array to hold the grayscale image */ |
| image = (*cinfo->emethods->request_big_sarray) (width, height, 1L); |
| cinfo->in_color_space = CS_GRAYSCALE; |
| cinfo->input_components = 1; |
| break; |
| case PSEUDOCOLOR: |
| /* request one big array to hold the pseudocolor image */ |
| image = (*cinfo->emethods->request_big_sarray) (width, height, 1L); |
| cinfo->in_color_space = CS_RGB; |
| cinfo->input_components = 3; |
| break; |
| case TRUECOLOR: |
| case DIRECTCOLOR: |
| /* request three big arrays to hold the RGB channels */ |
| red_channel = (*cinfo->emethods->request_big_sarray) (width, height, 1L); |
| green_channel = (*cinfo->emethods->request_big_sarray) (width, height, 1L); |
| blue_channel = (*cinfo->emethods->request_big_sarray) (width, height, 1L); |
| cinfo->in_color_space = CS_RGB; |
| cinfo->input_components = 3; |
| break; |
| } |
| |
| cinfo->total_passes++; /* count file reading as separate pass */ |
| } |
| |
| |
| /* |
| * Read one row of pixels. |
| * These are called only after load_image has read the image into |
| * the virtual array(s). |
| */ |
| |
| |
| METHODDEF void |
| get_grayscale_row (compress_info_ptr cinfo, JSAMPARRAY pixel_row) |
| /* This is used for GRAYSCALE images */ |
| { |
| JSAMPROW inputrows[1]; /* a pseudo JSAMPARRAY structure */ |
| |
| cur_row_number--; /* work down in array */ |
| |
| inputrows[0] = *((*cinfo->emethods->access_big_sarray) |
| (image, cur_row_number, FALSE)); |
| |
| jcopy_sample_rows(inputrows, 0, pixel_row, 0, 1, cinfo->image_width); |
| } |
| |
| |
| METHODDEF void |
| get_pseudocolor_row (compress_info_ptr cinfo, JSAMPARRAY pixel_row) |
| /* This is used for PSEUDOCOLOR images */ |
| { |
| long col; |
| JSAMPROW image_ptr, ptr0, ptr1, ptr2; |
| int val; |
| |
| cur_row_number--; /* work down in array */ |
| |
| image_ptr = *((*cinfo->emethods->access_big_sarray) |
| (image, cur_row_number, FALSE)); |
| |
| ptr0 = pixel_row[0]; |
| ptr1 = pixel_row[1]; |
| ptr2 = pixel_row[2]; |
| |
| for (col = cinfo->image_width; col > 0; col--) { |
| val = GETJSAMPLE(*image_ptr++); |
| *ptr0++ = colormap[val ] >> 8; |
| *ptr1++ = colormap[val + 256] >> 8; |
| *ptr2++ = colormap[val + 512] >> 8; |
| } |
| } |
| |
| |
| METHODDEF void |
| get_truecolor_row (compress_info_ptr cinfo, JSAMPARRAY pixel_row) |
| /* This is used for TRUECOLOR images */ |
| /* The colormap consists of 3 independent lookup tables */ |
| { |
| long col; |
| JSAMPROW red_ptr, green_ptr, blue_ptr, ptr0, ptr1, ptr2; |
| |
| cur_row_number--; /* work down in array */ |
| |
| red_ptr = *((*cinfo->emethods->access_big_sarray) |
| (red_channel, cur_row_number, FALSE)); |
| green_ptr = *((*cinfo->emethods->access_big_sarray) |
| (green_channel, cur_row_number, FALSE)); |
| blue_ptr = *((*cinfo->emethods->access_big_sarray) |
| (blue_channel, cur_row_number, FALSE)); |
| |
| ptr0 = pixel_row[0]; |
| ptr1 = pixel_row[1]; |
| ptr2 = pixel_row[2]; |
| |
| for (col = cinfo->image_width; col > 0; col--) { |
| *ptr0++ = colormap[GETJSAMPLE(*red_ptr++) ] >> 8; |
| *ptr1++ = colormap[GETJSAMPLE(*green_ptr++) + 256] >> 8; |
| *ptr2++ = colormap[GETJSAMPLE(*blue_ptr++) + 512] >> 8; |
| } |
| } |
| |
| |
| METHODDEF void |
| get_directcolor_row (compress_info_ptr cinfo, JSAMPARRAY pixel_row) |
| /* This is used for DIRECTCOLOR images */ |
| { |
| JSAMPROW inputrows[3]; /* a pseudo JSAMPARRAY structure */ |
| |
| cur_row_number--; /* work down in array */ |
| |
| inputrows[0] = *((*cinfo->emethods->access_big_sarray) |
| (red_channel, cur_row_number, FALSE)); |
| inputrows[1] = *((*cinfo->emethods->access_big_sarray) |
| (green_channel, cur_row_number, FALSE)); |
| inputrows[2] = *((*cinfo->emethods->access_big_sarray) |
| (blue_channel, cur_row_number, FALSE)); |
| |
| jcopy_sample_rows(inputrows, 0, pixel_row, 0, 3, cinfo->image_width); |
| } |
| |
| |
| /* |
| * Load the color channels into separate arrays. We have to do |
| * this because RLE files start at the lower left while the JPEG standard |
| * has them starting in the upper left. This is called the first time |
| * we want to get a row of input. What we do is load the RLE data into |
| * big arrays and then call the appropriate routine to read one row from |
| * the big arrays. We also change cinfo->methods->get_input_row so that |
| * subsequent calls go straight to the row-reading routine. |
| */ |
| |
| METHODDEF void |
| load_image (compress_info_ptr cinfo, JSAMPARRAY pixel_row) |
| { |
| long row; |
| rle_pixel *rle_row[3]; |
| |
| /* Read the RLE data into 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. |
| */ |
| RLE_CLR_BIT(header, RLE_ALPHA); /* don't read the alpha channel */ |
| |
| switch (visual) { |
| case GRAYSCALE: |
| case PSEUDOCOLOR: |
| for (row = 0; row < cinfo->image_height; row++) { |
| (*cinfo->methods->progress_monitor) (cinfo, row, cinfo->image_height); |
| /* |
| * Read a row of the image directly into our big array. |
| * Too bad this doesn't seem to return any indication of errors :-(. |
| */ |
| rle_row[0] = (rle_pixel *) *((*cinfo->emethods->access_big_sarray) |
| (image, row, TRUE)); |
| rle_getrow(&header, rle_row); |
| } |
| break; |
| case TRUECOLOR: |
| case DIRECTCOLOR: |
| for (row = 0; row < cinfo->image_height; row++) { |
| (*cinfo->methods->progress_monitor) (cinfo, row, cinfo->image_height); |
| /* |
| * Read a row of the image directly into our big arrays. |
| * Too bad this doesn't seem to return any indication of errors :-(. |
| */ |
| rle_row[0] = (rle_pixel *) *((*cinfo->emethods->access_big_sarray) |
| (red_channel, row, TRUE)); |
| rle_row[1] = (rle_pixel *) *((*cinfo->emethods->access_big_sarray) |
| (green_channel, row, TRUE)); |
| rle_row[2] = (rle_pixel *) *((*cinfo->emethods->access_big_sarray) |
| (blue_channel, row, TRUE)); |
| rle_getrow(&header, rle_row); |
| } |
| break; |
| } |
| cinfo->completed_passes++; |
| |
| /* Set up to call proper row-extraction routine in future */ |
| switch (visual) { |
| case GRAYSCALE: |
| cinfo->methods->get_input_row = get_grayscale_row; |
| break; |
| case PSEUDOCOLOR: |
| cinfo->methods->get_input_row = get_pseudocolor_row; |
| break; |
| case TRUECOLOR: |
| cinfo->methods->get_input_row = get_truecolor_row; |
| break; |
| case DIRECTCOLOR: |
| cinfo->methods->get_input_row = get_directcolor_row; |
| break; |
| } |
| |
| /* And fetch the topmost (bottommost) row */ |
| cur_row_number = cinfo->image_height; |
| (*cinfo->methods->get_input_row) (cinfo, pixel_row); |
| } |
| |
| |
| /* |
| * Finish up at the end of the file. |
| */ |
| |
| METHODDEF void |
| input_term (compress_info_ptr cinfo) |
| { |
| /* no work (we let free_all release the workspace) */ |
| } |
| |
| |
| /* |
| * The method selection routine for RLE format input. |
| * Note that this must be called by the user interface before calling |
| * jpeg_compress. If multiple input formats are supported, the |
| * user interface is responsible for discovering the file format and |
| * calling the appropriate method selection routine. |
| */ |
| |
| GLOBAL void |
| jselrrle (compress_info_ptr cinfo) |
| { |
| cinfo->methods->input_init = input_init; |
| cinfo->methods->get_input_row = load_image; /* until first call */ |
| cinfo->methods->input_term = input_term; |
| } |
| |
| #endif /* RLE_SUPPORTED */ |