8 * Copyright (C) 1991-1996, Thomas G. Lane.
9 * This file is part of the Independent JPEG Group's software.
10 * For conditions of distribution and use, see the accompanying README file.
12 * This file contains routines to read input images in Utah RLE format.
13 * The Utah Raster Toolkit library is required (version 3.1 or later).
15 * These routines may need modification for non-Unix environments or
16 * specialized applications. As they stand, they assume input from
17 * an ordinary stdio stream. They further assume that reading begins
18 * at the start of the file; start_input may need work if the
19 * user interface has already read some data (e.g., to determine that
20 * the file is indeed RLE format).
22 * Based on code contributed by Mike Lijewski,
23 * with updates from Robert Hutchinson.
26 #include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
30 /* rle.h is provided by the Utah Raster Toolkit. */
35 * We assume that JSAMPLE has the same representation as rle_pixel,
36 * to wit, "unsigned char". Hence we can't cope with 12- or 16-bit samples.
39 #if BITS_IN_JSAMPLE != 8
40 Sorry
, this code only copes with
8-bit JSAMPLEs
. /* deliberate syntax err */
44 * We support the following types of RLE files:
46 * GRAYSCALE - 8 bits, no colormap
47 * MAPPEDGRAY - 8 bits, 1 channel colomap
48 * PSEUDOCOLOR - 8 bits, 3 channel colormap
49 * TRUECOLOR - 24 bits, 3 channel colormap
50 * DIRECTCOLOR - 24 bits, no colormap
52 * For now, we ignore any alpha channel in the image.
56 { GRAYSCALE
, MAPPEDGRAY
, PSEUDOCOLOR
, TRUECOLOR
, DIRECTCOLOR
} rle_kind
;
60 * Since RLE stores scanlines bottom-to-top, we have to invert the image
61 * to conform to JPEG's top-to-bottom order. To do this, we read the
62 * incoming image into a virtual array on the first get_pixel_rows call,
63 * then fetch the required row from the virtual array on subsequent calls.
66 typedef struct _rle_source_struct
* rle_source_ptr
;
68 typedef struct _rle_source_struct
{
69 struct cjpeg_source_struct pub
; /* public fields */
71 rle_kind visual
; /* actual type of input file */
72 jvirt_sarray_ptr image
; /* virtual array to hold the image */
73 JDIMENSION row
; /* current row # in the virtual array */
74 rle_hdr header
; /* Input file information */
75 rle_pixel
** rle_row
; /* holds a row returned by rle_getrow() */
81 * Read the file header; return image size and component count.
85 start_input_rle (j_compress_ptr cinfo
, cjpeg_source_ptr sinfo
)
87 rle_source_ptr source
= (rle_source_ptr
) sinfo
;
88 JDIMENSION width
, height
;
89 #ifdef PROGRESS_REPORT
90 cd_progress_ptr progress
= (cd_progress_ptr
) cinfo
->progress
;
93 /* Use RLE library routine to get the header info */
94 source
->header
= *rle_hdr_init(NULL
);
95 source
->header
.rle_file
= source
->pub
.input_file
;
96 switch (rle_get_setup(&(source
->header
))) {
101 ERREXIT(cinfo
, JERR_RLE_NOT
);
104 ERREXIT(cinfo
, JERR_RLE_MEM
);
107 ERREXIT(cinfo
, JERR_RLE_EMPTY
);
110 ERREXIT(cinfo
, JERR_RLE_EOF
);
113 ERREXIT(cinfo
, JERR_RLE_BADERROR
);
117 /* Figure out what we have, set private vars and return values accordingly */
119 width
= source
->header
.xmax
- source
->header
.xmin
+ 1;
120 height
= source
->header
.ymax
- source
->header
.ymin
+ 1;
121 source
->header
.xmin
= 0; /* realign horizontally */
122 source
->header
.xmax
= width
-1;
124 cinfo
->image_width
= width
;
125 cinfo
->image_height
= height
;
126 cinfo
->data_precision
= 8; /* we can only handle 8 bit data */
128 if (source
->header
.ncolors
== 1 && source
->header
.ncmap
== 0) {
129 source
->visual
= GRAYSCALE
;
130 TRACEMS2(cinfo
, 1, JTRC_RLE_GRAY
, width
, height
);
131 } else if (source
->header
.ncolors
== 1 && source
->header
.ncmap
== 1) {
132 source
->visual
= MAPPEDGRAY
;
133 TRACEMS3(cinfo
, 1, JTRC_RLE_MAPGRAY
, width
, height
,
134 1 << source
->header
.cmaplen
);
135 } else if (source
->header
.ncolors
== 1 && source
->header
.ncmap
== 3) {
136 source
->visual
= PSEUDOCOLOR
;
137 TRACEMS3(cinfo
, 1, JTRC_RLE_MAPPED
, width
, height
,
138 1 << source
->header
.cmaplen
);
139 } else if (source
->header
.ncolors
== 3 && source
->header
.ncmap
== 3) {
140 source
->visual
= TRUECOLOR
;
141 TRACEMS3(cinfo
, 1, JTRC_RLE_FULLMAP
, width
, height
,
142 1 << source
->header
.cmaplen
);
143 } else if (source
->header
.ncolors
== 3 && source
->header
.ncmap
== 0) {
144 source
->visual
= DIRECTCOLOR
;
145 TRACEMS2(cinfo
, 1, JTRC_RLE
, width
, height
);
147 ERREXIT(cinfo
, JERR_RLE_UNSUPPORTED
);
149 if (source
->visual
== GRAYSCALE
|| source
->visual
== MAPPEDGRAY
) {
150 cinfo
->in_color_space
= JCS_GRAYSCALE
;
151 cinfo
->input_components
= 1;
153 cinfo
->in_color_space
= JCS_RGB
;
154 cinfo
->input_components
= 3;
158 * A place to hold each scanline while it's converted.
159 * (GRAYSCALE scanlines don't need converting)
161 if (source
->visual
!= GRAYSCALE
) {
162 source
->rle_row
= (rle_pixel
**) (*cinfo
->mem
->alloc_sarray
)
163 ((j_common_ptr
) cinfo
, JPOOL_IMAGE
,
164 (JDIMENSION
) width
, (JDIMENSION
) cinfo
->input_components
);
167 /* request a virtual array to hold the image */
168 source
->image
= (*cinfo
->mem
->request_virt_sarray
)
169 ((j_common_ptr
) cinfo
, JPOOL_IMAGE
, FALSE
,
170 (JDIMENSION
) (width
* source
->header
.ncolors
),
171 (JDIMENSION
) height
, (JDIMENSION
) 1);
173 #ifdef PROGRESS_REPORT
174 if (progress
!= NULL
) {
175 /* count file input as separate pass */
176 progress
->total_extra_passes
++;
180 source
->pub
.buffer_height
= 1;
185 * Read one row of pixels.
186 * Called only after load_image has read the image into the virtual array.
187 * Used for GRAYSCALE, MAPPEDGRAY, TRUECOLOR, and DIRECTCOLOR images.
190 METHODDEF(JDIMENSION
)
191 get_rle_row (j_compress_ptr cinfo
, cjpeg_source_ptr sinfo
)
193 rle_source_ptr source
= (rle_source_ptr
) sinfo
;
196 source
->pub
.buffer
= (*cinfo
->mem
->access_virt_sarray
)
197 ((j_common_ptr
) cinfo
, source
->image
, source
->row
, (JDIMENSION
) 1, FALSE
);
203 * Read one row of pixels.
204 * Called only after load_image has read the image into the virtual array.
205 * Used for PSEUDOCOLOR images.
208 METHODDEF(JDIMENSION
)
209 get_pseudocolor_row (j_compress_ptr cinfo
, cjpeg_source_ptr sinfo
)
211 rle_source_ptr source
= (rle_source_ptr
) sinfo
;
212 JSAMPROW src_row
, dest_row
;
217 colormap
= source
->header
.cmap
;
218 dest_row
= source
->pub
.buffer
[0];
220 src_row
= * (*cinfo
->mem
->access_virt_sarray
)
221 ((j_common_ptr
) cinfo
, source
->image
, source
->row
, (JDIMENSION
) 1, FALSE
);
223 for (col
= cinfo
->image_width
; col
> 0; col
--) {
224 val
= GETJSAMPLE(*src_row
++);
225 *dest_row
++ = (JSAMPLE
) (colormap
[val
] >> 8);
226 *dest_row
++ = (JSAMPLE
) (colormap
[val
+ 256] >> 8);
227 *dest_row
++ = (JSAMPLE
) (colormap
[val
+ 512] >> 8);
235 * Load the image into a virtual array. We have to do this because RLE
236 * files start at the lower left while the JPEG standard has them starting
237 * in the upper left. This is called the first time we want to get a row
238 * of input. What we do is load the RLE data into the array and then call
239 * the appropriate routine to read one row from the array. Before returning,
240 * we set source->pub.get_pixel_rows so that subsequent calls go straight to
241 * the appropriate row-reading routine.
244 METHODDEF(JDIMENSION
)
245 load_image (j_compress_ptr cinfo
, cjpeg_source_ptr sinfo
)
247 rle_source_ptr source
= (rle_source_ptr
) sinfo
;
249 JSAMPROW scanline
, red_ptr
, green_ptr
, blue_ptr
;
253 #ifdef PROGRESS_REPORT
254 cd_progress_ptr progress
= (cd_progress_ptr
) cinfo
->progress
;
257 colormap
= source
->header
.cmap
;
258 rle_row
= source
->rle_row
;
260 /* Read the RLE data into our virtual array.
261 * We assume here that (a) rle_pixel is represented the same as JSAMPLE,
262 * and (b) we are not on a machine where FAR pointers differ from regular.
264 RLE_CLR_BIT(source
->header
, RLE_ALPHA
); /* don't read the alpha channel */
266 #ifdef PROGRESS_REPORT
267 if (progress
!= NULL
) {
268 progress
->pub
.pass_limit
= cinfo
->image_height
;
269 progress
->pub
.pass_counter
= 0;
270 (*progress
->pub
.progress_monitor
) ((j_common_ptr
) cinfo
);
274 switch (source
->visual
) {
278 for (row
= 0; row
< cinfo
->image_height
; row
++) {
279 rle_row
= (rle_pixel
**) (*cinfo
->mem
->access_virt_sarray
)
280 ((j_common_ptr
) cinfo
, source
->image
, row
, (JDIMENSION
) 1, TRUE
);
281 rle_getrow(&source
->header
, rle_row
);
282 #ifdef PROGRESS_REPORT
283 if (progress
!= NULL
) {
284 progress
->pub
.pass_counter
++;
285 (*progress
->pub
.progress_monitor
) ((j_common_ptr
) cinfo
);
293 for (row
= 0; row
< cinfo
->image_height
; row
++) {
294 scanline
= * (*cinfo
->mem
->access_virt_sarray
)
295 ((j_common_ptr
) cinfo
, source
->image
, row
, (JDIMENSION
) 1, TRUE
);
296 rle_row
= source
->rle_row
;
297 rle_getrow(&source
->header
, rle_row
);
299 for (col
= 0; col
< cinfo
->image_width
; col
++) {
300 for (channel
= 0; channel
< source
->header
.ncolors
; channel
++) {
301 *scanline
++ = (JSAMPLE
)
302 (colormap
[GETJSAMPLE(rle_row
[channel
][col
]) + 256 * channel
] >> 8);
306 #ifdef PROGRESS_REPORT
307 if (progress
!= NULL
) {
308 progress
->pub
.pass_counter
++;
309 (*progress
->pub
.progress_monitor
) ((j_common_ptr
) cinfo
);
316 for (row
= 0; row
< cinfo
->image_height
; row
++) {
317 scanline
= * (*cinfo
->mem
->access_virt_sarray
)
318 ((j_common_ptr
) cinfo
, source
->image
, row
, (JDIMENSION
) 1, TRUE
);
319 rle_getrow(&source
->header
, rle_row
);
321 red_ptr
= rle_row
[0];
322 green_ptr
= rle_row
[1];
323 blue_ptr
= rle_row
[2];
325 for (col
= cinfo
->image_width
; col
> 0; col
--) {
326 *scanline
++ = *red_ptr
++;
327 *scanline
++ = *green_ptr
++;
328 *scanline
++ = *blue_ptr
++;
331 #ifdef PROGRESS_REPORT
332 if (progress
!= NULL
) {
333 progress
->pub
.pass_counter
++;
334 (*progress
->pub
.progress_monitor
) ((j_common_ptr
) cinfo
);
340 #ifdef PROGRESS_REPORT
341 if (progress
!= NULL
)
342 progress
->completed_extra_passes
++;
345 /* Set up to call proper row-extraction routine in future */
346 if (source
->visual
== PSEUDOCOLOR
) {
347 source
->pub
.buffer
= source
->rle_row
;
348 source
->pub
.get_pixel_rows
= get_pseudocolor_row
;
350 source
->pub
.get_pixel_rows
= get_rle_row
;
352 source
->row
= cinfo
->image_height
;
354 /* And fetch the topmost (bottommost) row */
355 return (*source
->pub
.get_pixel_rows
) (cinfo
, sinfo
);
360 * Finish up at the end of the file.
364 finish_input_rle (j_compress_ptr cinfo
, cjpeg_source_ptr sinfo
)
371 * The module selection routine for RLE format input.
374 JGLOBAL(cjpeg_source_ptr
)
375 jinit_read_rle (j_compress_ptr cinfo
)
377 rle_source_ptr source
;
379 /* Create module interface object */
380 source
= (rle_source_ptr
)
381 (*cinfo
->mem
->alloc_small
) ((j_common_ptr
) cinfo
, JPOOL_IMAGE
,
382 SIZEOF(rle_source_struct
));
383 /* Fill in method ptrs */
384 source
->pub
.start_input
= start_input_rle
;
385 source
->pub
.finish_input
= finish_input_rle
;
386 source
->pub
.get_pixel_rows
= load_image
;
388 return (cjpeg_source_ptr
) source
;
391 #endif /* RLE_SUPPORTED */