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