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 write output images in 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 output to
13 * an ordinary stdio stream.
15 * Based on code contributed by Mike Lijewski,
16 * with updates from Robert Hutchinson.
19 #include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
23 /* rle.h is provided by the Utah Raster Toolkit. */
28 * We assume that JSAMPLE has the same representation as rle_pixel,
29 * to wit, "unsigned char". Hence we can't cope with 12- or 16-bit samples.
32 #if BITS_IN_JSAMPLE != 8
33 Sorry
, this code only copes with
8-bit JSAMPLEs
. /* deliberate syntax err */
38 * Since RLE stores scanlines bottom-to-top, we have to invert the image
39 * from JPEG's top-to-bottom order. To do this, we save the outgoing data
40 * in a virtual array during put_pixel_row calls, then actually emit the
41 * RLE file during finish_output.
46 * For now, if we emit an RLE color map then it is always 256 entries long,
47 * though not all of the entries need be used.
51 #define CMAPLENGTH (1<<(CMAPBITS))
54 struct djpeg_dest_struct pub
; /* public fields */
56 jvirt_sarray_ptr image
; /* virtual array to store the output image */
57 rle_map
*colormap
; /* RLE-style color map, or NULL if none */
58 rle_pixel
**rle_row
; /* To pass rows to rle_putrow() */
62 typedef rle_dest_struct
* rle_dest_ptr
;
64 /* Forward declarations */
65 METHODDEF(void) rle_put_pixel_rows
66 JPP((j_decompress_ptr cinfo
, djpeg_dest_ptr dinfo
,
67 JDIMENSION rows_supplied
));
71 * Write the file header.
73 * In this module it's easier to wait till finish_output to write anything.
77 start_output_rle (j_decompress_ptr cinfo
, djpeg_dest_ptr dinfo
)
79 rle_dest_ptr dest
= (rle_dest_ptr
) dinfo
;
82 #ifdef PROGRESS_REPORT
83 cd_progress_ptr progress
= (cd_progress_ptr
) cinfo
->progress
;
87 * Make sure the image can be stored in RLE format.
89 * - RLE stores image dimensions as *signed* 16 bit integers. JPEG
90 * uses unsigned, so we have to check the width.
92 * - Colorspace is expected to be grayscale or RGB.
94 * - The number of channels (components) is expected to be 1 (grayscale/
95 * pseudocolor) or 3 (truecolor/directcolor).
96 * (could be 2 or 4 if using an alpha channel, but we aren't)
99 if (cinfo
->output_width
> 32767 || cinfo
->output_height
> 32767)
100 ERREXIT2(cinfo
, JERR_RLE_DIMENSIONS
, cinfo
->output_width
,
101 cinfo
->output_height
);
103 if (cinfo
->out_color_space
!= JCS_GRAYSCALE
&&
104 cinfo
->out_color_space
!= JCS_RGB
)
105 ERREXIT(cinfo
, JERR_RLE_COLORSPACE
);
107 if (cinfo
->output_components
!= 1 && cinfo
->output_components
!= 3)
108 ERREXIT1(cinfo
, JERR_RLE_TOOMANYCHANNELS
, cinfo
->num_components
);
110 /* Convert colormap, if any, to RLE format. */
112 dest
->colormap
= NULL
;
114 if (cinfo
->quantize_colors
) {
115 /* Allocate storage for RLE-style cmap, zero any extra entries */
116 cmapsize
= cinfo
->out_color_components
* CMAPLENGTH
* SIZEOF(rle_map
);
117 dest
->colormap
= (rle_map
*) (*cinfo
->mem
->alloc_small
)
118 ((j_common_ptr
) cinfo
, JPOOL_IMAGE
, cmapsize
);
119 MEMZERO(dest
->colormap
, cmapsize
);
121 /* Save away data in RLE format --- note 8-bit left shift! */
122 /* Shifting would need adjustment for JSAMPLEs wider than 8 bits. */
123 for (ci
= 0; ci
< cinfo
->out_color_components
; ci
++) {
124 for (i
= 0; i
< cinfo
->actual_number_of_colors
; i
++) {
125 dest
->colormap
[ci
* CMAPLENGTH
+ i
] =
126 GETJSAMPLE(cinfo
->colormap
[ci
][i
]) << 8;
131 /* Set the output buffer to the first row */
132 dest
->pub
.buffer
= (*cinfo
->mem
->access_virt_sarray
)
133 ((j_common_ptr
) cinfo
, dest
->image
, (JDIMENSION
) 0, (JDIMENSION
) 1, TRUE
);
134 dest
->pub
.buffer_height
= 1;
136 dest
->pub
.put_pixel_rows
= rle_put_pixel_rows
;
138 #ifdef PROGRESS_REPORT
139 if (progress
!= NULL
) {
140 progress
->total_extra_passes
++; /* count file writing as separate pass */
147 * Write some pixel data.
149 * This routine just saves the data away in a virtual array.
153 rle_put_pixel_rows (j_decompress_ptr cinfo
, djpeg_dest_ptr dinfo
,
154 JDIMENSION rows_supplied
)
156 rle_dest_ptr dest
= (rle_dest_ptr
) dinfo
;
158 if (cinfo
->output_scanline
< cinfo
->output_height
) {
159 dest
->pub
.buffer
= (*cinfo
->mem
->access_virt_sarray
)
160 ((j_common_ptr
) cinfo
, dest
->image
,
161 cinfo
->output_scanline
, (JDIMENSION
) 1, TRUE
);
166 * Finish up at the end of the file.
168 * Here is where we really output the RLE file.
172 finish_output_rle (j_decompress_ptr cinfo
, djpeg_dest_ptr dinfo
)
174 rle_dest_ptr dest
= (rle_dest_ptr
) dinfo
;
175 rle_hdr header
; /* Output file information */
176 rle_pixel
**rle_row
, *red
, *green
, *blue
;
178 char cmapcomment
[80];
181 #ifdef PROGRESS_REPORT
182 cd_progress_ptr progress
= (cd_progress_ptr
) cinfo
->progress
;
185 /* Initialize the header info */
186 header
= *rle_hdr_init(NULL
);
187 header
.rle_file
= dest
->pub
.output_file
;
189 header
.xmax
= cinfo
->output_width
- 1;
191 header
.ymax
= cinfo
->output_height
- 1;
193 header
.ncolors
= cinfo
->output_components
;
194 for (ci
= 0; ci
< cinfo
->output_components
; ci
++) {
195 RLE_SET_BIT(header
, ci
);
197 if (cinfo
->quantize_colors
) {
198 header
.ncmap
= cinfo
->out_color_components
;
199 header
.cmaplen
= CMAPBITS
;
200 header
.cmap
= dest
->colormap
;
201 /* Add a comment to the output image with the true colormap length. */
202 sprintf(cmapcomment
, "color_map_length=%d", cinfo
->actual_number_of_colors
);
203 rle_putcom(cmapcomment
, &header
);
206 /* Emit the RLE header and color map (if any) */
207 rle_put_setup(&header
);
209 /* Now output the RLE data from our virtual array.
210 * We assume here that (a) rle_pixel is represented the same as JSAMPLE,
211 * and (b) we are not on a machine where FAR pointers differ from regular.
214 #ifdef PROGRESS_REPORT
215 if (progress
!= NULL
) {
216 progress
->pub
.pass_limit
= cinfo
->output_height
;
217 progress
->pub
.pass_counter
= 0;
218 (*progress
->pub
.progress_monitor
) ((j_common_ptr
) cinfo
);
222 if (cinfo
->output_components
== 1) {
223 for (row
= cinfo
->output_height
-1; row
>= 0; row
--) {
224 rle_row
= (rle_pixel
**) (*cinfo
->mem
->access_virt_sarray
)
225 ((j_common_ptr
) cinfo
, dest
->image
,
226 (JDIMENSION
) row
, (JDIMENSION
) 1, FALSE
);
227 rle_putrow(rle_row
, (int) cinfo
->output_width
, &header
);
228 #ifdef PROGRESS_REPORT
229 if (progress
!= NULL
) {
230 progress
->pub
.pass_counter
++;
231 (*progress
->pub
.progress_monitor
) ((j_common_ptr
) cinfo
);
236 for (row
= cinfo
->output_height
-1; row
>= 0; row
--) {
237 rle_row
= (rle_pixel
**) dest
->rle_row
;
238 output_row
= * (*cinfo
->mem
->access_virt_sarray
)
239 ((j_common_ptr
) cinfo
, dest
->image
,
240 (JDIMENSION
) row
, (JDIMENSION
) 1, FALSE
);
244 for (col
= cinfo
->output_width
; col
> 0; col
--) {
245 *red
++ = GETJSAMPLE(*output_row
++);
246 *green
++ = GETJSAMPLE(*output_row
++);
247 *blue
++ = GETJSAMPLE(*output_row
++);
249 rle_putrow(rle_row
, (int) cinfo
->output_width
, &header
);
250 #ifdef PROGRESS_REPORT
251 if (progress
!= NULL
) {
252 progress
->pub
.pass_counter
++;
253 (*progress
->pub
.progress_monitor
) ((j_common_ptr
) cinfo
);
259 #ifdef PROGRESS_REPORT
260 if (progress
!= NULL
)
261 progress
->completed_extra_passes
++;
264 /* Emit file trailer */
266 fflush(dest
->pub
.output_file
);
267 if (ferror(dest
->pub
.output_file
))
268 ERREXIT(cinfo
, JERR_FILE_WRITE
);
273 * The module selection routine for RLE format output.
276 GLOBAL(djpeg_dest_ptr
)
277 jinit_write_rle (j_decompress_ptr cinfo
)
281 /* Create module interface object, fill in method pointers */
282 dest
= (rle_dest_ptr
)
283 (*cinfo
->mem
->alloc_small
) ((j_common_ptr
) cinfo
, JPOOL_IMAGE
,
284 SIZEOF(rle_dest_struct
));
285 dest
->pub
.start_output
= start_output_rle
;
286 dest
->pub
.finish_output
= finish_output_rle
;
288 /* Calculate output image dimensions so we can allocate space */
289 jpeg_calc_output_dimensions(cinfo
);
291 /* Allocate a work array for output to the RLE library. */
292 dest
->rle_row
= (*cinfo
->mem
->alloc_sarray
)
293 ((j_common_ptr
) cinfo
, JPOOL_IMAGE
,
294 cinfo
->output_width
, (JDIMENSION
) cinfo
->output_components
);
296 /* Allocate a virtual array to hold the image. */
297 dest
->image
= (*cinfo
->mem
->request_virt_sarray
)
298 ((j_common_ptr
) cinfo
, JPOOL_IMAGE
, FALSE
,
299 (JDIMENSION
) (cinfo
->output_width
* cinfo
->output_components
),
300 cinfo
->output_height
, (JDIMENSION
) 1);
302 return (djpeg_dest_ptr
) dest
;
305 #endif /* RLE_SUPPORTED */