1 /*
2 * rdrle.c
3 *
4 * This file was part of the Independent JPEG Group's software:
5 * Copyright (C) 1991-1996, Thomas G. Lane.
6 * It was modified by The libjpeg-turbo Project to include only code and
7 * information relevant to libjpeg-turbo.
8 * 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
24 #include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
25
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:
43 *
44 * 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
53 typedef 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
64 typedef struct _rle_source_struct * rle_source_ptr;
65
66 typedef 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 */
71 JDIMENSION row; /* current row # in the virtual array */
72 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
82 METHODDEF(void)
start_input_rle(j_compress_ptr cinfo,cjpeg_source_ptr sinfo)83 start_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 */
116
117 width = source->header.xmax - source->header.xmin + 1;
118 height = source->header.ymax - source->header.ymin + 1;
119 source->header.xmin = 0; /* realign horizontally */
120 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,
136 1 << source->header.cmaplen);
137 } else if (source->header.ncolors == 3 && source->header.ncmap == 3) {
138 source->visual = TRUECOLOR;
139 TRACEMS3(cinfo, 1, JTRC_RLE_FULLMAP, width, height,
140 1 << source->header.cmaplen);
141 } 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);
146
147 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)
167 ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
168 (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
188 METHODDEF(JDIMENSION)
get_rle_row(j_compress_ptr cinfo,cjpeg_source_ptr sinfo)189 get_rle_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
190 {
191 rle_source_ptr source = (rle_source_ptr) sinfo;
192
193 source->row--;
194 source->pub.buffer = (*cinfo->mem->access_virt_sarray)
195 ((j_common_ptr) cinfo, source->image, source->row, (JDIMENSION) 1, FALSE);
196
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
206 METHODDEF(JDIMENSION)
get_pseudocolor_row(j_compress_ptr cinfo,cjpeg_source_ptr sinfo)207 get_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];
217 source->row--;
218 src_row = * (*cinfo->mem->access_virt_sarray)
219 ((j_common_ptr) cinfo, source->image, source->row, (JDIMENSION) 1, FALSE);
220
221 for (col = cinfo->image_width; col > 0; col--) {
222 val = GETJSAMPLE(*src_row++);
223 *dest_row++ = (JSAMPLE) (colormap[val ] >> 8);
224 *dest_row++ = (JSAMPLE) (colormap[val + 256] >> 8);
225 *dest_row++ = (JSAMPLE) (colormap[val + 512] >> 8);
226 }
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
242 METHODDEF(JDIMENSION)
load_image(j_compress_ptr cinfo,cjpeg_source_ptr sinfo)243 load_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;
257
258 /* Read the RLE data into our virtual array.
259 * We assume here that rle_pixel is represented the same as JSAMPLE.
260 */
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:
275 for (row = 0; row < cinfo->image_height; row++) {
276 rle_row = (rle_pixel **) (*cinfo->mem->access_virt_sarray)
277 ((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE);
278 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:
290 for (row = 0; row < cinfo->image_height; row++) {
291 scanline = * (*cinfo->mem->access_virt_sarray)
292 ((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE);
293 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)
299 (colormap[GETJSAMPLE(rle_row[channel][col]) + 256 * channel] >> 8);
300 }
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:
313 for (row = 0; row < cinfo->image_height; row++) {
314 scanline = * (*cinfo->mem->access_virt_sarray)
315 ((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE);
316 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 }
349 source->row = cinfo->image_height;
350
351 /* And fetch the topmost (bottommost) row */
352 return (*source->pub.get_pixel_rows) (cinfo, sinfo);
353 }
354
355
356 /*
357 * Finish up at the end of the file.
358 */
359
360 METHODDEF(void)
finish_input_rle(j_compress_ptr cinfo,cjpeg_source_ptr sinfo)361 finish_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
371 GLOBAL(cjpeg_source_ptr)
jinit_read_rle(j_compress_ptr cinfo)372 jinit_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 */
389