xref: /reactos/dll/3rdparty/libjpeg/rdrle.c (revision b8dd046e)
1 /*
2  * rdrle.c
3  *
4  * Copyright (C) 1991-1996, Thomas G. Lane.
5  * Modified 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.
8  *
9  * This file contains routines to read input images in Utah RLE format.
10  * The Utah Raster Toolkit library is required (version 3.1 or later).
11  *
12  * These routines may need modification for non-Unix environments or
13  * specialized applications.  As they stand, they assume input from
14  * an ordinary stdio stream.  They further assume that reading begins
15  * at the start of the file; start_input may need work if the
16  * user interface has already read some data (e.g., to determine that
17  * the file is indeed RLE format).
18  *
19  * Based on code contributed by Mike Lijewski,
20  * with updates from Robert Hutchinson.
21  */
22 
23 #include "cdjpeg.h"		/* Common decls for cjpeg/djpeg applications */
24 
25 #ifdef RLE_SUPPORTED
26 
27 /* rle.h is provided by the Utah Raster Toolkit. */
28 
29 #include <rle.h>
30 
31 /*
32  * We assume that JSAMPLE has the same representation as rle_pixel,
33  * to wit, "unsigned char".  Hence we can't cope with 12- or 16-bit samples.
34  */
35 
36 #if BITS_IN_JSAMPLE != 8
37   Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */
38 #endif
39 
40 /*
41  * We support the following types of RLE files:
42  *
43  *   GRAYSCALE   - 8 bits, no colormap
44  *   MAPPEDGRAY  - 8 bits, 1 channel colomap
45  *   PSEUDOCOLOR - 8 bits, 3 channel colormap
46  *   TRUECOLOR   - 24 bits, 3 channel colormap
47  *   DIRECTCOLOR - 24 bits, no colormap
48  *
49  * For now, we ignore any alpha channel in the image.
50  */
51 
52 typedef enum
53   { GRAYSCALE, MAPPEDGRAY, PSEUDOCOLOR, TRUECOLOR, DIRECTCOLOR } rle_kind;
54 
55 
56 /*
57  * Since RLE stores scanlines bottom-to-top, we have to invert the image
58  * to conform to JPEG's top-to-bottom order.  To do this, we read the
59  * incoming image into a virtual array on the first get_pixel_rows call,
60  * then fetch the required row from the virtual array on subsequent calls.
61  */
62 
63 typedef struct _rle_source_struct * rle_source_ptr;
64 
65 typedef struct _rle_source_struct {
66   struct cjpeg_source_struct pub; /* public fields */
67 
68   rle_kind visual;              /* actual type of input file */
69   jvirt_sarray_ptr image;       /* virtual array to hold the image */
70   JDIMENSION row;		/* current row # in the virtual array */
71   rle_hdr header;               /* Input file information */
72   rle_pixel **rle_row;          /* holds a row returned by rle_getrow() */
73 
74 } rle_source_struct;
75 
76 
77 /*
78  * Read the file header; return image size and component count.
79  */
80 
81 METHODDEF(void)
82 start_input_rle (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
83 {
84   rle_source_ptr source = (rle_source_ptr) sinfo;
85   JDIMENSION width, height;
86 #ifdef PROGRESS_REPORT
87   cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
88 #endif
89 
90   /* Use RLE library routine to get the header info */
91   source->header = *rle_hdr_init(NULL);
92   source->header.rle_file = source->pub.input_file;
93   switch (rle_get_setup(&(source->header))) {
94   case RLE_SUCCESS:
95     /* A-OK */
96     break;
97   case RLE_NOT_RLE:
98     ERREXIT(cinfo, JERR_RLE_NOT);
99   case RLE_NO_SPACE:
100     ERREXIT(cinfo, JERR_RLE_MEM);
101   case RLE_EMPTY:
102     ERREXIT(cinfo, JERR_RLE_EMPTY);
103   case RLE_EOF:
104     ERREXIT(cinfo, JERR_RLE_EOF);
105   default:
106     ERREXIT(cinfo, JERR_RLE_BADERROR);
107   }
108 
109   /* Figure out what we have, set private vars and return values accordingly */
110 
111   width  = source->header.xmax - source->header.xmin + 1;
112   height = source->header.ymax - source->header.ymin + 1;
113   source->header.xmin = 0;		/* realign horizontally */
114   source->header.xmax = width-1;
115 
116   cinfo->image_width      = width;
117   cinfo->image_height     = height;
118   cinfo->data_precision   = 8;  /* we can only handle 8 bit data */
119 
120   if (source->header.ncolors == 1 && source->header.ncmap == 0) {
121     source->visual     = GRAYSCALE;
122     TRACEMS2(cinfo, 1, JTRC_RLE_GRAY, width, height);
123   } else if (source->header.ncolors == 1 && source->header.ncmap == 1) {
124     source->visual     = MAPPEDGRAY;
125     TRACEMS3(cinfo, 1, JTRC_RLE_MAPGRAY, width, height,
126              1 << source->header.cmaplen);
127   } else if (source->header.ncolors == 1 && source->header.ncmap == 3) {
128     source->visual     = PSEUDOCOLOR;
129     TRACEMS3(cinfo, 1, JTRC_RLE_MAPPED, width, height,
130 	     1 << source->header.cmaplen);
131   } else if (source->header.ncolors == 3 && source->header.ncmap == 3) {
132     source->visual     = TRUECOLOR;
133     TRACEMS3(cinfo, 1, JTRC_RLE_FULLMAP, width, height,
134 	     1 << source->header.cmaplen);
135   } else if (source->header.ncolors == 3 && source->header.ncmap == 0) {
136     source->visual     = DIRECTCOLOR;
137     TRACEMS2(cinfo, 1, JTRC_RLE, width, height);
138   } else
139     ERREXIT(cinfo, JERR_RLE_UNSUPPORTED);
140 
141   if (source->visual == GRAYSCALE || source->visual == MAPPEDGRAY) {
142     cinfo->in_color_space   = JCS_GRAYSCALE;
143     cinfo->input_components = 1;
144   } else {
145     cinfo->in_color_space   = JCS_RGB;
146     cinfo->input_components = 3;
147   }
148 
149   /*
150    * A place to hold each scanline while it's converted.
151    * (GRAYSCALE scanlines don't need converting)
152    */
153   if (source->visual != GRAYSCALE) {
154     source->rle_row = (rle_pixel **) (*cinfo->mem->alloc_sarray)
155       ((j_common_ptr) cinfo, JPOOL_IMAGE,
156        width, (JDIMENSION) cinfo->input_components);
157   }
158 
159   /* request a virtual array to hold the image */
160   source->image = (*cinfo->mem->request_virt_sarray)
161     ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
162      width * (JDIMENSION) source->header.ncolors, height, (JDIMENSION) 1);
163 
164 #ifdef PROGRESS_REPORT
165   if (progress != NULL) {
166     /* count file input as separate pass */
167     progress->total_extra_passes++;
168   }
169 #endif
170 
171   source->pub.buffer_height = 1;
172 }
173 
174 
175 /*
176  * Read one row of pixels.
177  * Called only after load_image has read the image into the virtual array.
178  * Used for GRAYSCALE, MAPPEDGRAY, TRUECOLOR, and DIRECTCOLOR images.
179  */
180 
181 METHODDEF(JDIMENSION)
182 get_rle_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
183 {
184   rle_source_ptr source = (rle_source_ptr) sinfo;
185 
186   source->row--;
187   source->pub.buffer = (*cinfo->mem->access_virt_sarray)
188     ((j_common_ptr) cinfo, source->image, source->row, (JDIMENSION) 1, FALSE);
189 
190   return 1;
191 }
192 
193 /*
194  * Read one row of pixels.
195  * Called only after load_image has read the image into the virtual array.
196  * Used for PSEUDOCOLOR images.
197  */
198 
199 METHODDEF(JDIMENSION)
200 get_pseudocolor_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
201 {
202   rle_source_ptr source = (rle_source_ptr) sinfo;
203   JSAMPROW src_row, dest_row;
204   JDIMENSION col;
205   rle_map *colormap;
206   int val;
207 
208   colormap = source->header.cmap;
209   dest_row = source->pub.buffer[0];
210   source->row--;
211   src_row = * (*cinfo->mem->access_virt_sarray)
212     ((j_common_ptr) cinfo, source->image, source->row, (JDIMENSION) 1, FALSE);
213 
214   for (col = cinfo->image_width; col > 0; col--) {
215     val = GETJSAMPLE(*src_row++);
216     *dest_row++ = (JSAMPLE) (colormap[val      ] >> 8);
217     *dest_row++ = (JSAMPLE) (colormap[val + 256] >> 8);
218     *dest_row++ = (JSAMPLE) (colormap[val + 512] >> 8);
219   }
220 
221   return 1;
222 }
223 
224 
225 /*
226  * Load the image into a virtual array.  We have to do this because RLE
227  * files start at the lower left while the JPEG standard has them starting
228  * in the upper left.  This is called the first time we want to get a row
229  * of input.  What we do is load the RLE data into the array and then call
230  * the appropriate routine to read one row from the array.  Before returning,
231  * we set source->pub.get_pixel_rows so that subsequent calls go straight to
232  * the appropriate row-reading routine.
233  */
234 
235 METHODDEF(JDIMENSION)
236 load_image (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
237 {
238   rle_source_ptr source = (rle_source_ptr) sinfo;
239   JDIMENSION row, col;
240   JSAMPROW scanline, red_ptr, green_ptr, blue_ptr;
241   rle_pixel **rle_row;
242   rle_map *colormap;
243   char channel;
244 #ifdef PROGRESS_REPORT
245   cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
246 #endif
247 
248   /* Read the RLE data into our virtual array.
249    * We assume here that (a) rle_pixel is represented the same as JSAMPLE,
250    * and (b) we are not on a machine where FAR pointers differ from regular.
251    */
252   RLE_CLR_BIT(source->header, RLE_ALPHA); /* don't read the alpha channel */
253 
254 #ifdef PROGRESS_REPORT
255   if (progress != NULL) {
256     progress->pub.pass_limit = cinfo->image_height;
257     progress->pub.pass_counter = 0;
258     (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
259   }
260 #endif
261 
262   switch (source->visual) {
263 
264   case GRAYSCALE:
265   case PSEUDOCOLOR:
266     for (row = 0; row < cinfo->image_height; row++) {
267       rle_row = (rle_pixel **) (*cinfo->mem->access_virt_sarray)
268 	((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE);
269       rle_getrow(&source->header, rle_row);
270 #ifdef PROGRESS_REPORT
271       if (progress != NULL) {
272 	progress->pub.pass_counter++;
273 	(*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
274       }
275 #endif
276     }
277     break;
278 
279   case MAPPEDGRAY:
280   case TRUECOLOR:
281     rle_row = source->rle_row;
282     colormap = source->header.cmap;
283     for (row = 0; row < cinfo->image_height; row++) {
284       rle_getrow(&source->header, rle_row);
285       scanline = * (*cinfo->mem->access_virt_sarray)
286 	((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE);
287 
288       for (col = 0; col < cinfo->image_width; col++) {
289 	for (channel = 0; channel < source->header.ncolors; channel++) {
290 	  *scanline++ = (JSAMPLE)
291 	    (colormap[GETJSAMPLE(rle_row[channel][col]) + 256 * channel] >> 8);
292 	}
293       }
294 
295 #ifdef PROGRESS_REPORT
296       if (progress != NULL) {
297 	progress->pub.pass_counter++;
298 	(*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
299       }
300 #endif
301     }
302     break;
303 
304   case DIRECTCOLOR:
305     rle_row = source->rle_row;
306     for (row = 0; row < cinfo->image_height; row++) {
307       rle_getrow(&source->header, rle_row);
308       scanline = * (*cinfo->mem->access_virt_sarray)
309 	((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE);
310 
311       red_ptr   = rle_row[0];
312       green_ptr = rle_row[1];
313       blue_ptr  = rle_row[2];
314 
315       for (col = cinfo->image_width; col > 0; col--) {
316 	*scanline++ = *red_ptr++;
317 	*scanline++ = *green_ptr++;
318 	*scanline++ = *blue_ptr++;
319       }
320 
321 #ifdef PROGRESS_REPORT
322       if (progress != NULL) {
323 	progress->pub.pass_counter++;
324 	(*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
325       }
326 #endif
327     }
328   }
329 
330 #ifdef PROGRESS_REPORT
331   if (progress != NULL)
332     progress->completed_extra_passes++;
333 #endif
334 
335   /* Set up to call proper row-extraction routine in future */
336   if (source->visual == PSEUDOCOLOR) {
337     source->pub.buffer = source->rle_row;
338     source->pub.get_pixel_rows = get_pseudocolor_row;
339   } else {
340     source->pub.get_pixel_rows = get_rle_row;
341   }
342   source->row = cinfo->image_height;
343 
344   /* And fetch the topmost (bottommost) row */
345   return (*source->pub.get_pixel_rows) (cinfo, sinfo);
346 }
347 
348 
349 /*
350  * Finish up at the end of the file.
351  */
352 
353 METHODDEF(void)
354 finish_input_rle (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
355 {
356   /* no work */
357 }
358 
359 
360 /*
361  * The module selection routine for RLE format input.
362  */
363 
364 GLOBAL(cjpeg_source_ptr)
365 jinit_read_rle (j_compress_ptr cinfo)
366 {
367   rle_source_ptr source;
368 
369   /* Create module interface object */
370   source = (rle_source_ptr) (*cinfo->mem->alloc_small)
371     ((j_common_ptr) cinfo, JPOOL_IMAGE, SIZEOF(rle_source_struct));
372   /* Fill in method ptrs */
373   source->pub.start_input = start_input_rle;
374   source->pub.finish_input = finish_input_rle;
375   source->pub.get_pixel_rows = load_image;
376 
377   return &source->pub;
378 }
379 
380 #endif /* RLE_SUPPORTED */
381