4 * Copyright (C) 1991-1996, Thomas G. Lane.
5 * This file is part of the Independent JPEG Group's software.
6 * For conditions of distribution and use, see the accompanying README file.
8 * This file contains routines to read input images in Utah RLE format.
9 * The Utah Raster Toolkit library is required (version 3.1 or later).
11 * These routines may need modification for non-Unix environments or
12 * specialized applications. As they stand, they assume input from
13 * an ordinary stdio stream. They further assume that reading begins
14 * at the start of the file; start_input may need work if the
15 * user interface has already read some data (e.g., to determine that
16 * the file is indeed RLE format).
18 * Based on code contributed by Mike Lijewski,
19 * with updates from Robert Hutchinson.
22 #include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
26 /* rle.h is provided by the Utah Raster Toolkit. */
31 * We assume that JSAMPLE has the same representation as rle_pixel,
32 * to wit, "unsigned char". Hence we can't cope with 12- or 16-bit samples.
35 #if BITS_IN_JSAMPLE != 8
36 Sorry
, this code only copes with
8-bit JSAMPLEs
. /* deliberate syntax err */
40 * We support the following types of RLE files:
42 * GRAYSCALE - 8 bits, no colormap
43 * MAPPEDGRAY - 8 bits, 1 channel colomap
44 * PSEUDOCOLOR - 8 bits, 3 channel colormap
45 * TRUECOLOR - 24 bits, 3 channel colormap
46 * DIRECTCOLOR - 24 bits, no colormap
48 * For now, we ignore any alpha channel in the image.
52 { GRAYSCALE
, MAPPEDGRAY
, PSEUDOCOLOR
, TRUECOLOR
, DIRECTCOLOR
} rle_kind
;
56 * Since RLE stores scanlines bottom-to-top, we have to invert the image
57 * to conform to JPEG's top-to-bottom order. To do this, we read the
58 * incoming image into a virtual array on the first get_pixel_rows call,
59 * then fetch the required row from the virtual array on subsequent calls.
62 typedef struct _rle_source_struct
* rle_source_ptr
;
64 typedef struct _rle_source_struct
{
65 struct cjpeg_source_struct pub
; /* public fields */
67 rle_kind visual
; /* actual type of input file */
68 jvirt_sarray_ptr image
; /* virtual array to hold the image */
69 JDIMENSION row
; /* current row # in the virtual array */
70 rle_hdr header
; /* Input file information */
71 rle_pixel
** rle_row
; /* holds a row returned by rle_getrow() */
77 * Read the file header; return image size and component count.
81 start_input_rle (j_compress_ptr cinfo
, cjpeg_source_ptr sinfo
)
83 rle_source_ptr source
= (rle_source_ptr
) sinfo
;
84 JDIMENSION width
, height
;
85 #ifdef PROGRESS_REPORT
86 cd_progress_ptr progress
= (cd_progress_ptr
) cinfo
->progress
;
89 /* Use RLE library routine to get the header info */
90 source
->header
= *rle_hdr_init(NULL
);
91 source
->header
.rle_file
= source
->pub
.input_file
;
92 switch (rle_get_setup(&(source
->header
))) {
97 ERREXIT(cinfo
, JERR_RLE_NOT
);
100 ERREXIT(cinfo
, JERR_RLE_MEM
);
103 ERREXIT(cinfo
, JERR_RLE_EMPTY
);
106 ERREXIT(cinfo
, JERR_RLE_EOF
);
109 ERREXIT(cinfo
, JERR_RLE_BADERROR
);
113 /* Figure out what we have, set private vars and return values accordingly */
115 width
= source
->header
.xmax
- source
->header
.xmin
+ 1;
116 height
= source
->header
.ymax
- source
->header
.ymin
+ 1;
117 source
->header
.xmin
= 0; /* realign horizontally */
118 source
->header
.xmax
= width
-1;
120 cinfo
->image_width
= width
;
121 cinfo
->image_height
= height
;
122 cinfo
->data_precision
= 8; /* we can only handle 8 bit data */
124 if (source
->header
.ncolors
== 1 && source
->header
.ncmap
== 0) {
125 source
->visual
= GRAYSCALE
;
126 TRACEMS2(cinfo
, 1, JTRC_RLE_GRAY
, width
, height
);
127 } else if (source
->header
.ncolors
== 1 && source
->header
.ncmap
== 1) {
128 source
->visual
= MAPPEDGRAY
;
129 TRACEMS3(cinfo
, 1, JTRC_RLE_MAPGRAY
, width
, height
,
130 1 << source
->header
.cmaplen
);
131 } else if (source
->header
.ncolors
== 1 && source
->header
.ncmap
== 3) {
132 source
->visual
= PSEUDOCOLOR
;
133 TRACEMS3(cinfo
, 1, JTRC_RLE_MAPPED
, width
, height
,
134 1 << source
->header
.cmaplen
);
135 } else if (source
->header
.ncolors
== 3 && source
->header
.ncmap
== 3) {
136 source
->visual
= TRUECOLOR
;
137 TRACEMS3(cinfo
, 1, JTRC_RLE_FULLMAP
, width
, height
,
138 1 << source
->header
.cmaplen
);
139 } else if (source
->header
.ncolors
== 3 && source
->header
.ncmap
== 0) {
140 source
->visual
= DIRECTCOLOR
;
141 TRACEMS2(cinfo
, 1, JTRC_RLE
, width
, height
);
143 ERREXIT(cinfo
, JERR_RLE_UNSUPPORTED
);
145 if (source
->visual
== GRAYSCALE
|| source
->visual
== MAPPEDGRAY
) {
146 cinfo
->in_color_space
= JCS_GRAYSCALE
;
147 cinfo
->input_components
= 1;
149 cinfo
->in_color_space
= JCS_RGB
;
150 cinfo
->input_components
= 3;
154 * A place to hold each scanline while it's converted.
155 * (GRAYSCALE scanlines don't need converting)
157 if (source
->visual
!= GRAYSCALE
) {
158 source
->rle_row
= (rle_pixel
**) (*cinfo
->mem
->alloc_sarray
)
159 ((j_common_ptr
) cinfo
, JPOOL_IMAGE
,
160 (JDIMENSION
) width
, (JDIMENSION
) cinfo
->input_components
);
163 /* request a virtual array to hold the image */
164 source
->image
= (*cinfo
->mem
->request_virt_sarray
)
165 ((j_common_ptr
) cinfo
, JPOOL_IMAGE
, FALSE
,
166 (JDIMENSION
) (width
* source
->header
.ncolors
),
167 (JDIMENSION
) height
, (JDIMENSION
) 1);
169 #ifdef PROGRESS_REPORT
170 if (progress
!= NULL
) {
171 /* count file input as separate pass */
172 progress
->total_extra_passes
++;
176 source
->pub
.buffer_height
= 1;
181 * Read one row of pixels.
182 * Called only after load_image has read the image into the virtual array.
183 * Used for GRAYSCALE, MAPPEDGRAY, TRUECOLOR, and DIRECTCOLOR images.
186 METHODDEF(JDIMENSION
)
187 get_rle_row (j_compress_ptr cinfo
, cjpeg_source_ptr sinfo
)
189 rle_source_ptr source
= (rle_source_ptr
) sinfo
;
192 source
->pub
.buffer
= (*cinfo
->mem
->access_virt_sarray
)
193 ((j_common_ptr
) cinfo
, source
->image
, source
->row
, (JDIMENSION
) 1, FALSE
);
199 * Read one row of pixels.
200 * Called only after load_image has read the image into the virtual array.
201 * Used for PSEUDOCOLOR images.
204 METHODDEF(JDIMENSION
)
205 get_pseudocolor_row (j_compress_ptr cinfo
, cjpeg_source_ptr sinfo
)
207 rle_source_ptr source
= (rle_source_ptr
) sinfo
;
208 JSAMPROW src_row
, dest_row
;
213 colormap
= source
->header
.cmap
;
214 dest_row
= source
->pub
.buffer
[0];
216 src_row
= * (*cinfo
->mem
->access_virt_sarray
)
217 ((j_common_ptr
) cinfo
, source
->image
, source
->row
, (JDIMENSION
) 1, FALSE
);
219 for (col
= cinfo
->image_width
; col
> 0; col
--) {
220 val
= GETJSAMPLE(*src_row
++);
221 *dest_row
++ = (JSAMPLE
) (colormap
[val
] >> 8);
222 *dest_row
++ = (JSAMPLE
) (colormap
[val
+ 256] >> 8);
223 *dest_row
++ = (JSAMPLE
) (colormap
[val
+ 512] >> 8);
231 * Load the image into a virtual array. We have to do this because RLE
232 * files start at the lower left while the JPEG standard has them starting
233 * in the upper left. This is called the first time we want to get a row
234 * of input. What we do is load the RLE data into the array and then call
235 * the appropriate routine to read one row from the array. Before returning,
236 * we set source->pub.get_pixel_rows so that subsequent calls go straight to
237 * the appropriate row-reading routine.
240 METHODDEF(JDIMENSION
)
241 load_image (j_compress_ptr cinfo
, cjpeg_source_ptr sinfo
)
243 rle_source_ptr source
= (rle_source_ptr
) sinfo
;
245 JSAMPROW scanline
, red_ptr
, green_ptr
, blue_ptr
;
249 #ifdef PROGRESS_REPORT
250 cd_progress_ptr progress
= (cd_progress_ptr
) cinfo
->progress
;
253 colormap
= source
->header
.cmap
;
254 rle_row
= source
->rle_row
;
256 /* Read the RLE data into our virtual array.
257 * We assume here that (a) rle_pixel is represented the same as JSAMPLE,
258 * and (b) we are not on a machine where FAR pointers differ from regular.
260 RLE_CLR_BIT(source
->header
, RLE_ALPHA
); /* don't read the alpha channel */
262 #ifdef PROGRESS_REPORT
263 if (progress
!= NULL
) {
264 progress
->pub
.pass_limit
= cinfo
->image_height
;
265 progress
->pub
.pass_counter
= 0;
266 (*progress
->pub
.progress_monitor
) ((j_common_ptr
) cinfo
);
270 switch (source
->visual
) {
274 for (row
= 0; row
< cinfo
->image_height
; row
++) {
275 rle_row
= (rle_pixel
**) (*cinfo
->mem
->access_virt_sarray
)
276 ((j_common_ptr
) cinfo
, source
->image
, row
, (JDIMENSION
) 1, TRUE
);
277 rle_getrow(&source
->header
, rle_row
);
278 #ifdef PROGRESS_REPORT
279 if (progress
!= NULL
) {
280 progress
->pub
.pass_counter
++;
281 (*progress
->pub
.progress_monitor
) ((j_common_ptr
) cinfo
);
289 for (row
= 0; row
< cinfo
->image_height
; row
++) {
290 scanline
= * (*cinfo
->mem
->access_virt_sarray
)
291 ((j_common_ptr
) cinfo
, source
->image
, row
, (JDIMENSION
) 1, TRUE
);
292 rle_row
= source
->rle_row
;
293 rle_getrow(&source
->header
, rle_row
);
295 for (col
= 0; col
< cinfo
->image_width
; col
++) {
296 for (channel
= 0; channel
< source
->header
.ncolors
; channel
++) {
297 *scanline
++ = (JSAMPLE
)
298 (colormap
[GETJSAMPLE(rle_row
[channel
][col
]) + 256 * channel
] >> 8);
302 #ifdef PROGRESS_REPORT
303 if (progress
!= NULL
) {
304 progress
->pub
.pass_counter
++;
305 (*progress
->pub
.progress_monitor
) ((j_common_ptr
) cinfo
);
312 for (row
= 0; row
< cinfo
->image_height
; row
++) {
313 scanline
= * (*cinfo
->mem
->access_virt_sarray
)
314 ((j_common_ptr
) cinfo
, source
->image
, row
, (JDIMENSION
) 1, TRUE
);
315 rle_getrow(&source
->header
, rle_row
);
317 red_ptr
= rle_row
[0];
318 green_ptr
= rle_row
[1];
319 blue_ptr
= rle_row
[2];
321 for (col
= cinfo
->image_width
; col
> 0; col
--) {
322 *scanline
++ = *red_ptr
++;
323 *scanline
++ = *green_ptr
++;
324 *scanline
++ = *blue_ptr
++;
327 #ifdef PROGRESS_REPORT
328 if (progress
!= NULL
) {
329 progress
->pub
.pass_counter
++;
330 (*progress
->pub
.progress_monitor
) ((j_common_ptr
) cinfo
);
336 #ifdef PROGRESS_REPORT
337 if (progress
!= NULL
)
338 progress
->completed_extra_passes
++;
341 /* Set up to call proper row-extraction routine in future */
342 if (source
->visual
== PSEUDOCOLOR
) {
343 source
->pub
.buffer
= source
->rle_row
;
344 source
->pub
.get_pixel_rows
= get_pseudocolor_row
;
346 source
->pub
.get_pixel_rows
= get_rle_row
;
348 source
->row
= cinfo
->image_height
;
350 /* And fetch the topmost (bottommost) row */
351 return (*source
->pub
.get_pixel_rows
) (cinfo
, sinfo
);
356 * Finish up at the end of the file.
360 finish_input_rle (j_compress_ptr cinfo
, cjpeg_source_ptr sinfo
)
367 * The module selection routine for RLE format input.
370 GLOBAL(cjpeg_source_ptr
)
371 jinit_read_rle (j_compress_ptr cinfo
)
373 rle_source_ptr source
;
375 /* Create module interface object */
376 source
= (rle_source_ptr
)
377 (*cinfo
->mem
->alloc_small
) ((j_common_ptr
) cinfo
, JPOOL_IMAGE
,
378 SIZEOF(rle_source_struct
));
379 /* Fill in method ptrs */
380 source
->pub
.start_input
= start_input_rle
;
381 source
->pub
.finish_input
= finish_input_rle
;
382 source
->pub
.get_pixel_rows
= load_image
;
384 return (cjpeg_source_ptr
) source
;
387 #endif /* RLE_SUPPORTED */