4 * Copyright (C) 1991-1996, Thomas G. Lane.
5 * Modified 2017-2019 by Guido Vollbeding.
6 * This file is part of the Independent JPEG Group's software.
7 * For conditions of distribution and use, see the accompanying README file.
9 * This file contains routines to write output images in RLE format.
10 * The Utah Raster Toolkit library is required (version 3.1 or later).
12 * These routines may need modification for non-Unix environments or
13 * specialized applications. As they stand, they assume output to
14 * an ordinary stdio stream.
16 * Based on code contributed by Mike Lijewski,
17 * with updates from Robert Hutchinson.
20 #include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
24 /* rle.h is provided by the Utah Raster Toolkit. */
29 * We assume that JSAMPLE has the same representation as rle_pixel,
30 * to wit, "unsigned char". Hence we can't cope with 12- or 16-bit samples.
33 #if BITS_IN_JSAMPLE != 8
34 Sorry
, this code only copes with
8-bit JSAMPLEs
. /* deliberate syntax err */
39 * Since RLE stores scanlines bottom-to-top, we have to invert the image
40 * from JPEG's top-to-bottom order. To do this, we save the outgoing data
41 * in a virtual array during put_pixel_row calls, then actually emit the
42 * RLE file during finish_output.
47 * For now, if we emit an RLE color map then it is always 256 entries long,
48 * though not all of the entries need be used.
52 #define CMAPLENGTH (1<<(CMAPBITS))
55 struct djpeg_dest_struct pub
; /* public fields */
57 jvirt_sarray_ptr image
; /* virtual array to store the output image */
58 rle_map
*colormap
; /* RLE-style color map, or NULL if none */
59 rle_pixel
**rle_row
; /* To pass rows to rle_putrow() */
63 typedef rle_dest_struct
* rle_dest_ptr
;
66 /* Forward declarations */
67 METHODDEF(void) rle_put_pixel_rows
68 JPP((j_decompress_ptr cinfo
, djpeg_dest_ptr dinfo
,
69 JDIMENSION rows_supplied
));
73 * Write the file header.
75 * In this module it's easier to wait till finish_output to write anything.
79 start_output_rle (j_decompress_ptr cinfo
, djpeg_dest_ptr dinfo
)
81 rle_dest_ptr dest
= (rle_dest_ptr
) dinfo
;
84 #ifdef PROGRESS_REPORT
85 cd_progress_ptr progress
= (cd_progress_ptr
) cinfo
->progress
;
89 * Make sure the image can be stored in RLE format.
91 * - RLE stores image dimensions as *signed* 16 bit integers. JPEG
92 * uses unsigned, so we have to check the width.
94 * - Colorspace is expected to be grayscale or RGB.
96 * - The number of channels (components) is expected to be 1 (grayscale/
97 * pseudocolor) or 3 (truecolor/directcolor).
98 * (could be 2 or 4 if using an alpha channel, but we aren't)
101 if (cinfo
->output_width
> 32767 || cinfo
->output_height
> 32767)
102 ERREXIT2(cinfo
, JERR_RLE_DIMENSIONS
, cinfo
->output_width
,
103 cinfo
->output_height
);
105 if (cinfo
->out_color_space
!= JCS_GRAYSCALE
&&
106 cinfo
->out_color_space
!= JCS_RGB
)
107 ERREXIT(cinfo
, JERR_RLE_COLORSPACE
);
109 if (cinfo
->output_components
!= 1 && cinfo
->output_components
!= 3)
110 ERREXIT1(cinfo
, JERR_RLE_TOOMANYCHANNELS
, cinfo
->num_components
);
112 /* Convert colormap, if any, to RLE format. */
114 dest
->colormap
= NULL
;
116 if (cinfo
->quantize_colors
) {
117 /* Allocate storage for RLE-style cmap, zero any extra entries */
118 cmapsize
= cinfo
->out_color_components
* CMAPLENGTH
* SIZEOF(rle_map
);
119 dest
->colormap
= (rle_map
*) (*cinfo
->mem
->alloc_small
)
120 ((j_common_ptr
) cinfo
, JPOOL_IMAGE
, cmapsize
);
121 MEMZERO(dest
->colormap
, cmapsize
);
123 /* Save away data in RLE format --- note 8-bit left shift! */
124 /* Shifting would need adjustment for JSAMPLEs wider than 8 bits. */
125 for (ci
= 0; ci
< cinfo
->out_color_components
; ci
++) {
126 for (i
= 0; i
< cinfo
->actual_number_of_colors
; i
++) {
127 dest
->colormap
[ci
* CMAPLENGTH
+ i
] =
128 GETJSAMPLE(cinfo
->colormap
[ci
][i
]) << 8;
133 /* Set the output buffer to the first row */
134 dest
->pub
.buffer
= (*cinfo
->mem
->access_virt_sarray
)
135 ((j_common_ptr
) cinfo
, dest
->image
, (JDIMENSION
) 0, (JDIMENSION
) 1, TRUE
);
136 dest
->pub
.buffer_height
= 1;
138 dest
->pub
.put_pixel_rows
= rle_put_pixel_rows
;
140 #ifdef PROGRESS_REPORT
141 if (progress
!= NULL
) {
142 progress
->total_extra_passes
++; /* count file writing as separate pass */
149 * Write some pixel data.
151 * This routine just saves the data away in a virtual array.
155 rle_put_pixel_rows (j_decompress_ptr cinfo
, djpeg_dest_ptr dinfo
,
156 JDIMENSION rows_supplied
)
158 rle_dest_ptr dest
= (rle_dest_ptr
) dinfo
;
160 if (cinfo
->output_scanline
< cinfo
->output_height
) {
161 dest
->pub
.buffer
= (*cinfo
->mem
->access_virt_sarray
)
162 ((j_common_ptr
) cinfo
, dest
->image
,
163 cinfo
->output_scanline
, (JDIMENSION
) 1, TRUE
);
169 * Finish up at the end of the file.
171 * Here is where we really output the RLE file.
175 finish_output_rle (j_decompress_ptr cinfo
, djpeg_dest_ptr dinfo
)
177 rle_dest_ptr dest
= (rle_dest_ptr
) dinfo
;
178 rle_hdr header
; /* Output file information */
179 rle_pixel
**rle_row
, *red_ptr
, *green_ptr
, *blue_ptr
;
181 char cmapcomment
[80];
184 #ifdef PROGRESS_REPORT
185 cd_progress_ptr progress
= (cd_progress_ptr
) cinfo
->progress
;
188 /* Initialize the header info */
189 header
= *rle_hdr_init(NULL
);
190 header
.rle_file
= dest
->pub
.output_file
;
192 header
.xmax
= cinfo
->output_width
- 1;
194 header
.ymax
= cinfo
->output_height
- 1;
196 header
.ncolors
= cinfo
->output_components
;
197 for (ci
= 0; ci
< cinfo
->output_components
; ci
++) {
198 RLE_SET_BIT(header
, ci
);
200 if (cinfo
->quantize_colors
) {
201 header
.ncmap
= cinfo
->out_color_components
;
202 header
.cmaplen
= CMAPBITS
;
203 header
.cmap
= dest
->colormap
;
204 /* Add a comment to the output image with the true colormap length. */
205 sprintf(cmapcomment
, "color_map_length=%d", cinfo
->actual_number_of_colors
);
206 rle_putcom(cmapcomment
, &header
);
209 /* Emit the RLE header and color map (if any) */
210 rle_put_setup(&header
);
212 /* Now output the RLE data from our virtual array.
213 * We assume here that (a) rle_pixel is represented the same as JSAMPLE,
214 * and (b) we are not on a machine where FAR pointers differ from regular.
217 #ifdef PROGRESS_REPORT
218 if (progress
!= NULL
) {
219 progress
->pub
.pass_limit
= cinfo
->output_height
;
220 progress
->pub
.pass_counter
= 0;
221 (*progress
->pub
.progress_monitor
) ((j_common_ptr
) cinfo
);
225 if (cinfo
->output_components
== 1) {
226 for (row
= cinfo
->output_height
- 1; row
>= 0; row
--) {
227 rle_row
= (rle_pixel
**) (*cinfo
->mem
->access_virt_sarray
)
228 ((j_common_ptr
) cinfo
, dest
->image
,
229 (JDIMENSION
) row
, (JDIMENSION
) 1, FALSE
);
230 rle_putrow(rle_row
, (int) cinfo
->output_width
, &header
);
231 #ifdef PROGRESS_REPORT
232 if (progress
!= NULL
) {
233 progress
->pub
.pass_counter
++;
234 (*progress
->pub
.progress_monitor
) ((j_common_ptr
) cinfo
);
239 for (row
= cinfo
->output_height
- 1; row
>= 0; row
--) {
240 output_row
= * (*cinfo
->mem
->access_virt_sarray
)
241 ((j_common_ptr
) cinfo
, dest
->image
,
242 (JDIMENSION
) row
, (JDIMENSION
) 1, FALSE
);
243 rle_row
= dest
->rle_row
;
244 red_ptr
= rle_row
[0];
245 green_ptr
= rle_row
[1];
246 blue_ptr
= rle_row
[2];
247 for (col
= cinfo
->output_width
; col
> 0; col
--) {
248 *red_ptr
++ = GETJSAMPLE(*output_row
++);
249 *green_ptr
++ = GETJSAMPLE(*output_row
++);
250 *blue_ptr
++ = GETJSAMPLE(*output_row
++);
252 rle_putrow(rle_row
, (int) cinfo
->output_width
, &header
);
253 #ifdef PROGRESS_REPORT
254 if (progress
!= NULL
) {
255 progress
->pub
.pass_counter
++;
256 (*progress
->pub
.progress_monitor
) ((j_common_ptr
) cinfo
);
262 #ifdef PROGRESS_REPORT
263 if (progress
!= NULL
)
264 progress
->completed_extra_passes
++;
267 /* Emit file trailer */
269 JFFLUSH(dest
->pub
.output_file
);
270 if (JFERROR(dest
->pub
.output_file
))
271 ERREXIT(cinfo
, JERR_FILE_WRITE
);
276 * The module selection routine for RLE format output.
279 GLOBAL(djpeg_dest_ptr
)
280 jinit_write_rle (j_decompress_ptr cinfo
)
284 /* Create module interface object, fill in method pointers */
285 dest
= (rle_dest_ptr
) (*cinfo
->mem
->alloc_small
)
286 ((j_common_ptr
) cinfo
, JPOOL_IMAGE
, SIZEOF(rle_dest_struct
));
287 dest
->pub
.start_output
= start_output_rle
;
288 dest
->pub
.finish_output
= finish_output_rle
;
290 /* Calculate output image dimensions so we can allocate space */
291 jpeg_calc_output_dimensions(cinfo
);
293 /* Allocate a work array for output to the RLE library. */
294 dest
->rle_row
= (*cinfo
->mem
->alloc_sarray
) ((j_common_ptr
) cinfo
,
295 JPOOL_IMAGE
, cinfo
->output_width
, (JDIMENSION
) cinfo
->output_components
);
297 /* Allocate a virtual array to hold the image. */
298 dest
->image
= (*cinfo
->mem
->request_virt_sarray
)
299 ((j_common_ptr
) cinfo
, JPOOL_IMAGE
, FALSE
,
300 cinfo
->output_width
* (JDIMENSION
) cinfo
->output_components
,
301 cinfo
->output_height
, (JDIMENSION
) 1);
306 #endif /* RLE_SUPPORTED */