blob: a82cc3a3fb7dc2eba5083bb2d4a3c34eea3bb5a1 [file] [log] [blame]
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +00001/*
2 * rdrle.c
3 *
DRC5033f3e2014-05-18 18:33:44 +00004 * This file was part of the Independent JPEG Group's software:
Thomas G. Lane489583f1996-02-07 00:00:00 +00005 * Copyright (C) 1991-1996, Thomas G. Lane.
DRC5033f3e2014-05-18 18:33:44 +00006 * It was modified by The libjpeg-turbo Project to include only information
7 * relevant to libjpeg-turbo.
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +00008 * For conditions of distribution and use, see the accompanying README file.
9 *
10 * This file contains routines to read input images in Utah RLE format.
11 * The Utah Raster Toolkit library is required (version 3.1 or later).
12 *
13 * These routines may need modification for non-Unix environments or
14 * specialized applications. As they stand, they assume input from
15 * an ordinary stdio stream. They further assume that reading begins
16 * at the start of the file; start_input may need work if the
17 * user interface has already read some data (e.g., to determine that
18 * the file is indeed RLE format).
19 *
20 * Based on code contributed by Mike Lijewski,
21 * with updates from Robert Hutchinson.
22 */
23
DRCe5eaf372014-05-09 18:00:32 +000024#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +000025
26#ifdef RLE_SUPPORTED
27
28/* rle.h is provided by the Utah Raster Toolkit. */
29
30#include <rle.h>
31
32/*
33 * We assume that JSAMPLE has the same representation as rle_pixel,
34 * to wit, "unsigned char". Hence we can't cope with 12- or 16-bit samples.
35 */
36
37#if BITS_IN_JSAMPLE != 8
38 Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */
39#endif
40
41/*
42 * We support the following types of RLE files:
DRCe5eaf372014-05-09 18:00:32 +000043 *
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +000044 * GRAYSCALE - 8 bits, no colormap
45 * MAPPEDGRAY - 8 bits, 1 channel colomap
46 * PSEUDOCOLOR - 8 bits, 3 channel colormap
47 * TRUECOLOR - 24 bits, 3 channel colormap
48 * DIRECTCOLOR - 24 bits, no colormap
49 *
50 * For now, we ignore any alpha channel in the image.
51 */
52
53typedef enum
54 { GRAYSCALE, MAPPEDGRAY, PSEUDOCOLOR, TRUECOLOR, DIRECTCOLOR } rle_kind;
55
56
57/*
58 * Since RLE stores scanlines bottom-to-top, we have to invert the image
59 * to conform to JPEG's top-to-bottom order. To do this, we read the
60 * incoming image into a virtual array on the first get_pixel_rows call,
61 * then fetch the required row from the virtual array on subsequent calls.
62 */
63
64typedef struct _rle_source_struct * rle_source_ptr;
65
66typedef struct _rle_source_struct {
67 struct cjpeg_source_struct pub; /* public fields */
68
69 rle_kind visual; /* actual type of input file */
70 jvirt_sarray_ptr image; /* virtual array to hold the image */
DRCe5eaf372014-05-09 18:00:32 +000071 JDIMENSION row; /* current row # in the virtual array */
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +000072 rle_hdr header; /* Input file information */
73 rle_pixel** rle_row; /* holds a row returned by rle_getrow() */
74
75} rle_source_struct;
76
77
78/*
79 * Read the file header; return image size and component count.
80 */
81
Thomas G. Lane489583f1996-02-07 00:00:00 +000082METHODDEF(void)
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +000083start_input_rle (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
84{
85 rle_source_ptr source = (rle_source_ptr) sinfo;
86 JDIMENSION width, height;
87#ifdef PROGRESS_REPORT
88 cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
89#endif
90
91 /* Use RLE library routine to get the header info */
92 source->header = *rle_hdr_init(NULL);
93 source->header.rle_file = source->pub.input_file;
94 switch (rle_get_setup(&(source->header))) {
95 case RLE_SUCCESS:
96 /* A-OK */
97 break;
98 case RLE_NOT_RLE:
99 ERREXIT(cinfo, JERR_RLE_NOT);
100 break;
101 case RLE_NO_SPACE:
102 ERREXIT(cinfo, JERR_RLE_MEM);
103 break;
104 case RLE_EMPTY:
105 ERREXIT(cinfo, JERR_RLE_EMPTY);
106 break;
107 case RLE_EOF:
108 ERREXIT(cinfo, JERR_RLE_EOF);
109 break;
110 default:
111 ERREXIT(cinfo, JERR_RLE_BADERROR);
112 break;
113 }
114
115 /* Figure out what we have, set private vars and return values accordingly */
DRCe5eaf372014-05-09 18:00:32 +0000116
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +0000117 width = source->header.xmax - source->header.xmin + 1;
118 height = source->header.ymax - source->header.ymin + 1;
DRCe5eaf372014-05-09 18:00:32 +0000119 source->header.xmin = 0; /* realign horizontally */
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +0000120 source->header.xmax = width-1;
121
122 cinfo->image_width = width;
123 cinfo->image_height = height;
124 cinfo->data_precision = 8; /* we can only handle 8 bit data */
125
126 if (source->header.ncolors == 1 && source->header.ncmap == 0) {
127 source->visual = GRAYSCALE;
128 TRACEMS2(cinfo, 1, JTRC_RLE_GRAY, width, height);
129 } else if (source->header.ncolors == 1 && source->header.ncmap == 1) {
130 source->visual = MAPPEDGRAY;
131 TRACEMS3(cinfo, 1, JTRC_RLE_MAPGRAY, width, height,
132 1 << source->header.cmaplen);
133 } else if (source->header.ncolors == 1 && source->header.ncmap == 3) {
134 source->visual = PSEUDOCOLOR;
135 TRACEMS3(cinfo, 1, JTRC_RLE_MAPPED, width, height,
DRCe5eaf372014-05-09 18:00:32 +0000136 1 << source->header.cmaplen);
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +0000137 } else if (source->header.ncolors == 3 && source->header.ncmap == 3) {
138 source->visual = TRUECOLOR;
139 TRACEMS3(cinfo, 1, JTRC_RLE_FULLMAP, width, height,
DRCe5eaf372014-05-09 18:00:32 +0000140 1 << source->header.cmaplen);
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +0000141 } else if (source->header.ncolors == 3 && source->header.ncmap == 0) {
142 source->visual = DIRECTCOLOR;
143 TRACEMS2(cinfo, 1, JTRC_RLE, width, height);
144 } else
145 ERREXIT(cinfo, JERR_RLE_UNSUPPORTED);
DRCe5eaf372014-05-09 18:00:32 +0000146
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +0000147 if (source->visual == GRAYSCALE || source->visual == MAPPEDGRAY) {
148 cinfo->in_color_space = JCS_GRAYSCALE;
149 cinfo->input_components = 1;
150 } else {
151 cinfo->in_color_space = JCS_RGB;
152 cinfo->input_components = 3;
153 }
154
155 /*
156 * A place to hold each scanline while it's converted.
157 * (GRAYSCALE scanlines don't need converting)
158 */
159 if (source->visual != GRAYSCALE) {
160 source->rle_row = (rle_pixel**) (*cinfo->mem->alloc_sarray)
161 ((j_common_ptr) cinfo, JPOOL_IMAGE,
162 (JDIMENSION) width, (JDIMENSION) cinfo->input_components);
163 }
164
165 /* request a virtual array to hold the image */
166 source->image = (*cinfo->mem->request_virt_sarray)
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000167 ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +0000168 (JDIMENSION) (width * source->header.ncolors),
169 (JDIMENSION) height, (JDIMENSION) 1);
170
171#ifdef PROGRESS_REPORT
172 if (progress != NULL) {
173 /* count file input as separate pass */
174 progress->total_extra_passes++;
175 }
176#endif
177
178 source->pub.buffer_height = 1;
179}
180
181
182/*
183 * Read one row of pixels.
184 * Called only after load_image has read the image into the virtual array.
185 * Used for GRAYSCALE, MAPPEDGRAY, TRUECOLOR, and DIRECTCOLOR images.
186 */
187
Thomas G. Lane489583f1996-02-07 00:00:00 +0000188METHODDEF(JDIMENSION)
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +0000189get_rle_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
190{
191 rle_source_ptr source = (rle_source_ptr) sinfo;
192
Thomas G. Lane9ba2f5e1994-12-07 00:00:00 +0000193 source->row--;
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +0000194 source->pub.buffer = (*cinfo->mem->access_virt_sarray)
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000195 ((j_common_ptr) cinfo, source->image, source->row, (JDIMENSION) 1, FALSE);
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +0000196
197 return 1;
198}
199
200/*
201 * Read one row of pixels.
202 * Called only after load_image has read the image into the virtual array.
203 * Used for PSEUDOCOLOR images.
204 */
205
Thomas G. Lane489583f1996-02-07 00:00:00 +0000206METHODDEF(JDIMENSION)
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +0000207get_pseudocolor_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
208{
209 rle_source_ptr source = (rle_source_ptr) sinfo;
210 JSAMPROW src_row, dest_row;
211 JDIMENSION col;
212 rle_map *colormap;
213 int val;
214
215 colormap = source->header.cmap;
216 dest_row = source->pub.buffer[0];
Thomas G. Lane9ba2f5e1994-12-07 00:00:00 +0000217 source->row--;
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +0000218 src_row = * (*cinfo->mem->access_virt_sarray)
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000219 ((j_common_ptr) cinfo, source->image, source->row, (JDIMENSION) 1, FALSE);
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +0000220
221 for (col = cinfo->image_width; col > 0; col--) {
222 val = GETJSAMPLE(*src_row++);
Thomas G. Lane9ba2f5e1994-12-07 00:00:00 +0000223 *dest_row++ = (JSAMPLE) (colormap[val ] >> 8);
224 *dest_row++ = (JSAMPLE) (colormap[val + 256] >> 8);
225 *dest_row++ = (JSAMPLE) (colormap[val + 512] >> 8);
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +0000226 }
227
228 return 1;
229}
230
231
232/*
233 * Load the image into a virtual array. We have to do this because RLE
234 * files start at the lower left while the JPEG standard has them starting
235 * in the upper left. This is called the first time we want to get a row
236 * of input. What we do is load the RLE data into the array and then call
237 * the appropriate routine to read one row from the array. Before returning,
238 * we set source->pub.get_pixel_rows so that subsequent calls go straight to
239 * the appropriate row-reading routine.
240 */
241
Thomas G. Lane489583f1996-02-07 00:00:00 +0000242METHODDEF(JDIMENSION)
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +0000243load_image (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
244{
245 rle_source_ptr source = (rle_source_ptr) sinfo;
246 JDIMENSION row, col;
247 JSAMPROW scanline, red_ptr, green_ptr, blue_ptr;
248 rle_pixel **rle_row;
249 rle_map *colormap;
250 char channel;
251#ifdef PROGRESS_REPORT
252 cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
253#endif
254
255 colormap = source->header.cmap;
256 rle_row = source->rle_row;
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +0000257
258 /* Read the RLE data into our virtual array.
DRC5033f3e2014-05-18 18:33:44 +0000259 * We assume here that rle_pixel is represented the same as JSAMPLE.
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +0000260 */
261 RLE_CLR_BIT(source->header, RLE_ALPHA); /* don't read the alpha channel */
262
263#ifdef PROGRESS_REPORT
264 if (progress != NULL) {
265 progress->pub.pass_limit = cinfo->image_height;
266 progress->pub.pass_counter = 0;
267 (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
268 }
269#endif
270
271 switch (source->visual) {
272
273 case GRAYSCALE:
274 case PSEUDOCOLOR:
Thomas G. Lane9ba2f5e1994-12-07 00:00:00 +0000275 for (row = 0; row < cinfo->image_height; row++) {
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +0000276 rle_row = (rle_pixel **) (*cinfo->mem->access_virt_sarray)
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000277 ((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE);
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +0000278 rle_getrow(&source->header, rle_row);
279#ifdef PROGRESS_REPORT
280 if (progress != NULL) {
281 progress->pub.pass_counter++;
282 (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
283 }
284#endif
285 }
286 break;
287
288 case MAPPEDGRAY:
289 case TRUECOLOR:
Thomas G. Lane9ba2f5e1994-12-07 00:00:00 +0000290 for (row = 0; row < cinfo->image_height; row++) {
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +0000291 scanline = * (*cinfo->mem->access_virt_sarray)
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000292 ((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE);
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +0000293 rle_row = source->rle_row;
294 rle_getrow(&source->header, rle_row);
295
296 for (col = 0; col < cinfo->image_width; col++) {
297 for (channel = 0; channel < source->header.ncolors; channel++) {
298 *scanline++ = (JSAMPLE)
Thomas G. Lane9ba2f5e1994-12-07 00:00:00 +0000299 (colormap[GETJSAMPLE(rle_row[channel][col]) + 256 * channel] >> 8);
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +0000300 }
301 }
302
303#ifdef PROGRESS_REPORT
304 if (progress != NULL) {
305 progress->pub.pass_counter++;
306 (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
307 }
308#endif
309 }
310 break;
311
312 case DIRECTCOLOR:
Thomas G. Lane9ba2f5e1994-12-07 00:00:00 +0000313 for (row = 0; row < cinfo->image_height; row++) {
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +0000314 scanline = * (*cinfo->mem->access_virt_sarray)
Thomas G. Lanebc79e061995-08-02 00:00:00 +0000315 ((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE);
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +0000316 rle_getrow(&source->header, rle_row);
317
318 red_ptr = rle_row[0];
319 green_ptr = rle_row[1];
320 blue_ptr = rle_row[2];
321
322 for (col = cinfo->image_width; col > 0; col--) {
323 *scanline++ = *red_ptr++;
324 *scanline++ = *green_ptr++;
325 *scanline++ = *blue_ptr++;
326 }
327
328#ifdef PROGRESS_REPORT
329 if (progress != NULL) {
330 progress->pub.pass_counter++;
331 (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
332 }
333#endif
334 }
335 }
336
337#ifdef PROGRESS_REPORT
338 if (progress != NULL)
339 progress->completed_extra_passes++;
340#endif
341
342 /* Set up to call proper row-extraction routine in future */
343 if (source->visual == PSEUDOCOLOR) {
344 source->pub.buffer = source->rle_row;
345 source->pub.get_pixel_rows = get_pseudocolor_row;
346 } else {
347 source->pub.get_pixel_rows = get_rle_row;
348 }
Thomas G. Lane9ba2f5e1994-12-07 00:00:00 +0000349 source->row = cinfo->image_height;
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +0000350
351 /* And fetch the topmost (bottommost) row */
DRCe5eaf372014-05-09 18:00:32 +0000352 return (*source->pub.get_pixel_rows) (cinfo, sinfo);
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +0000353}
354
355
356/*
357 * Finish up at the end of the file.
358 */
359
Thomas G. Lane489583f1996-02-07 00:00:00 +0000360METHODDEF(void)
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +0000361finish_input_rle (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
362{
363 /* no work */
364}
365
366
367/*
368 * The module selection routine for RLE format input.
369 */
370
Thomas G. Lane489583f1996-02-07 00:00:00 +0000371GLOBAL(cjpeg_source_ptr)
Thomas G. Lane36a4ccc1994-09-24 00:00:00 +0000372jinit_read_rle (j_compress_ptr cinfo)
373{
374 rle_source_ptr source;
375
376 /* Create module interface object */
377 source = (rle_source_ptr)
378 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
379 SIZEOF(rle_source_struct));
380 /* Fill in method ptrs */
381 source->pub.start_input = start_input_rle;
382 source->pub.finish_input = finish_input_rle;
383 source->pub.get_pixel_rows = load_image;
384
385 return (cjpeg_source_ptr) source;
386}
387
388#endif /* RLE_SUPPORTED */