4 * Copyright (C) 1991-1996, Thomas G. Lane.
5 * Modified 2017 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
;
65 /* Forward declarations */
66 METHODDEF(void) rle_put_pixel_rows
67 JPP((j_decompress_ptr cinfo
, djpeg_dest_ptr dinfo
,
68 JDIMENSION rows_supplied
));
72 * Write the file header.
74 * In this module it's easier to wait till finish_output to write anything.
78 start_output_rle (j_decompress_ptr cinfo
, djpeg_dest_ptr dinfo
)
80 rle_dest_ptr dest
= (rle_dest_ptr
) dinfo
;
83 #ifdef PROGRESS_REPORT
84 cd_progress_ptr progress
= (cd_progress_ptr
) cinfo
->progress
;
88 * Make sure the image can be stored in RLE format.
90 * - RLE stores image dimensions as *signed* 16 bit integers. JPEG
91 * uses unsigned, so we have to check the width.
93 * - Colorspace is expected to be grayscale or RGB.
95 * - The number of channels (components) is expected to be 1 (grayscale/
96 * pseudocolor) or 3 (truecolor/directcolor).
97 * (could be 2 or 4 if using an alpha channel, but we aren't)
100 if (cinfo
->output_width
> 32767 || cinfo
->output_height
> 32767)
101 ERREXIT2(cinfo
, JERR_RLE_DIMENSIONS
, cinfo
->output_width
,
102 cinfo
->output_height
);
104 if (cinfo
->out_color_space
!= JCS_GRAYSCALE
&&
105 cinfo
->out_color_space
!= JCS_RGB
)
106 ERREXIT(cinfo
, JERR_RLE_COLORSPACE
);
108 if (cinfo
->output_components
!= 1 && cinfo
->output_components
!= 3)
109 ERREXIT1(cinfo
, JERR_RLE_TOOMANYCHANNELS
, cinfo
->num_components
);
111 /* Convert colormap, if any, to RLE format. */
113 dest
->colormap
= NULL
;
115 if (cinfo
->quantize_colors
) {
116 /* Allocate storage for RLE-style cmap, zero any extra entries */
117 cmapsize
= cinfo
->out_color_components
* CMAPLENGTH
* SIZEOF(rle_map
);
118 dest
->colormap
= (rle_map
*) (*cinfo
->mem
->alloc_small
)
119 ((j_common_ptr
) cinfo
, JPOOL_IMAGE
, cmapsize
);
120 MEMZERO(dest
->colormap
, cmapsize
);
122 /* Save away data in RLE format --- note 8-bit left shift! */
123 /* Shifting would need adjustment for JSAMPLEs wider than 8 bits. */
124 for (ci
= 0; ci
< cinfo
->out_color_components
; ci
++) {
125 for (i
= 0; i
< cinfo
->actual_number_of_colors
; i
++) {
126 dest
->colormap
[ci
* CMAPLENGTH
+ i
] =
127 GETJSAMPLE(cinfo
->colormap
[ci
][i
]) << 8;
132 /* Set the output buffer to the first row */
133 dest
->pub
.buffer
= (*cinfo
->mem
->access_virt_sarray
)
134 ((j_common_ptr
) cinfo
, dest
->image
, (JDIMENSION
) 0, (JDIMENSION
) 1, TRUE
);
135 dest
->pub
.buffer_height
= 1;
137 dest
->pub
.put_pixel_rows
= rle_put_pixel_rows
;
139 #ifdef PROGRESS_REPORT
140 if (progress
!= NULL
) {
141 progress
->total_extra_passes
++; /* count file writing as separate pass */
148 * Write some pixel data.
150 * This routine just saves the data away in a virtual array.
154 rle_put_pixel_rows (j_decompress_ptr cinfo
, djpeg_dest_ptr dinfo
,
155 JDIMENSION rows_supplied
)
157 rle_dest_ptr dest
= (rle_dest_ptr
) dinfo
;
159 if (cinfo
->output_scanline
< cinfo
->output_height
) {
160 dest
->pub
.buffer
= (*cinfo
->mem
->access_virt_sarray
)
161 ((j_common_ptr
) cinfo
, dest
->image
,
162 cinfo
->output_scanline
, (JDIMENSION
) 1, TRUE
);
167 * Finish up at the end of the file.
169 * Here is where we really output the RLE file.
173 finish_output_rle (j_decompress_ptr cinfo
, djpeg_dest_ptr dinfo
)
175 rle_dest_ptr dest
= (rle_dest_ptr
) dinfo
;
176 rle_hdr header
; /* Output file information */
177 rle_pixel
**rle_row
, *red
, *green
, *blue
;
179 char cmapcomment
[80];
182 #ifdef PROGRESS_REPORT
183 cd_progress_ptr progress
= (cd_progress_ptr
) cinfo
->progress
;
186 /* Initialize the header info */
187 header
= *rle_hdr_init(NULL
);
188 header
.rle_file
= dest
->pub
.output_file
;
190 header
.xmax
= cinfo
->output_width
- 1;
192 header
.ymax
= cinfo
->output_height
- 1;
194 header
.ncolors
= cinfo
->output_components
;
195 for (ci
= 0; ci
< cinfo
->output_components
; ci
++) {
196 RLE_SET_BIT(header
, ci
);
198 if (cinfo
->quantize_colors
) {
199 header
.ncmap
= cinfo
->out_color_components
;
200 header
.cmaplen
= CMAPBITS
;
201 header
.cmap
= dest
->colormap
;
202 /* Add a comment to the output image with the true colormap length. */
203 sprintf(cmapcomment
, "color_map_length=%d", cinfo
->actual_number_of_colors
);
204 rle_putcom(cmapcomment
, &header
);
207 /* Emit the RLE header and color map (if any) */
208 rle_put_setup(&header
);
210 /* Now output the RLE data from our virtual array.
211 * We assume here that (a) rle_pixel is represented the same as JSAMPLE,
212 * and (b) we are not on a machine where FAR pointers differ from regular.
215 #ifdef PROGRESS_REPORT
216 if (progress
!= NULL
) {
217 progress
->pub
.pass_limit
= cinfo
->output_height
;
218 progress
->pub
.pass_counter
= 0;
219 (*progress
->pub
.progress_monitor
) ((j_common_ptr
) cinfo
);
223 if (cinfo
->output_components
== 1) {
224 for (row
= cinfo
->output_height
-1; row
>= 0; row
--) {
225 rle_row
= (rle_pixel
**) (*cinfo
->mem
->access_virt_sarray
)
226 ((j_common_ptr
) cinfo
, dest
->image
,
227 (JDIMENSION
) row
, (JDIMENSION
) 1, FALSE
);
228 rle_putrow(rle_row
, (int) cinfo
->output_width
, &header
);
229 #ifdef PROGRESS_REPORT
230 if (progress
!= NULL
) {
231 progress
->pub
.pass_counter
++;
232 (*progress
->pub
.progress_monitor
) ((j_common_ptr
) cinfo
);
237 for (row
= cinfo
->output_height
-1; row
>= 0; row
--) {
238 rle_row
= (rle_pixel
**) dest
->rle_row
;
239 output_row
= * (*cinfo
->mem
->access_virt_sarray
)
240 ((j_common_ptr
) cinfo
, dest
->image
,
241 (JDIMENSION
) row
, (JDIMENSION
) 1, FALSE
);
245 for (col
= cinfo
->output_width
; col
> 0; col
--) {
246 *red
++ = GETJSAMPLE(*output_row
++);
247 *green
++ = GETJSAMPLE(*output_row
++);
248 *blue
++ = GETJSAMPLE(*output_row
++);
250 rle_putrow(rle_row
, (int) cinfo
->output_width
, &header
);
251 #ifdef PROGRESS_REPORT
252 if (progress
!= NULL
) {
253 progress
->pub
.pass_counter
++;
254 (*progress
->pub
.progress_monitor
) ((j_common_ptr
) cinfo
);
260 #ifdef PROGRESS_REPORT
261 if (progress
!= NULL
)
262 progress
->completed_extra_passes
++;
265 /* Emit file trailer */
267 JFFLUSH(dest
->pub
.output_file
);
268 if (JFERROR(dest
->pub
.output_file
))
269 ERREXIT(cinfo
, JERR_FILE_WRITE
);
274 * The module selection routine for RLE format output.
277 GLOBAL(djpeg_dest_ptr
)
278 jinit_write_rle (j_decompress_ptr cinfo
)
282 /* Create module interface object, fill in method pointers */
283 dest
= (rle_dest_ptr
)
284 (*cinfo
->mem
->alloc_small
) ((j_common_ptr
) cinfo
, JPOOL_IMAGE
,
285 SIZEOF(rle_dest_struct
));
286 dest
->pub
.start_output
= start_output_rle
;
287 dest
->pub
.finish_output
= finish_output_rle
;
289 /* Calculate output image dimensions so we can allocate space */
290 jpeg_calc_output_dimensions(cinfo
);
292 /* Allocate a work array for output to the RLE library. */
293 dest
->rle_row
= (*cinfo
->mem
->alloc_sarray
)
294 ((j_common_ptr
) cinfo
, JPOOL_IMAGE
,
295 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 (JDIMENSION
) (cinfo
->output_width
* cinfo
->output_components
),
301 cinfo
->output_height
, (JDIMENSION
) 1);
306 #endif /* RLE_SUPPORTED */