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