Back to index

plt-scheme  4.2.1
rdtarga.c
Go to the documentation of this file.
00001 /*
00002  * rdtarga.c
00003  *
00004  * Copyright (C) 1991-1996, Thomas G. Lane.
00005  * This file is part of the Independent JPEG Group's software.
00006  * For conditions of distribution and use, see the accompanying README file.
00007  *
00008  * This file contains routines to read input images in Targa format.
00009  *
00010  * These routines may need modification for non-Unix environments or
00011  * specialized applications.  As they stand, they assume input from
00012  * an ordinary stdio stream.  They further assume that reading begins
00013  * at the start of the file; start_input may need work if the
00014  * user interface has already read some data (e.g., to determine that
00015  * the file is indeed Targa format).
00016  *
00017  * Based on code contributed by Lee Daniel Crocker.
00018  */
00019 
00020 #include "cdjpeg.h"         /* Common decls for cjpeg/djpeg applications */
00021 
00022 #ifdef TARGA_SUPPORTED
00023 
00024 
00025 /* Macros to deal with unsigned chars as efficiently as compiler allows */
00026 
00027 #ifdef HAVE_UNSIGNED_CHAR
00028 typedef unsigned char U_CHAR;
00029 #define UCH(x)       ((int) (x))
00030 #else /* !HAVE_UNSIGNED_CHAR */
00031 #ifdef CHAR_IS_UNSIGNED
00032 typedef char U_CHAR;
00033 #define UCH(x)       ((int) (x))
00034 #else
00035 typedef char U_CHAR;
00036 #define UCH(x)       ((int) (x) & 0xFF)
00037 #endif
00038 #endif /* HAVE_UNSIGNED_CHAR */
00039 
00040 
00041 #define       ReadOK(file,buffer,len)     (JFREAD(file,buffer,len) == ((size_t) (len)))
00042 
00043 
00044 /* Private version of data source object */
00045 
00046 typedef struct _tga_source_struct * tga_source_ptr;
00047 
00048 typedef struct _tga_source_struct {
00049   struct cjpeg_source_struct pub; /* public fields */
00050 
00051   j_compress_ptr cinfo;            /* back link saves passing separate parm */
00052 
00053   JSAMPARRAY colormap;             /* Targa colormap (converted to my format) */
00054 
00055   jvirt_sarray_ptr whole_image;    /* Needed if funny input row order */
00056   JDIMENSION current_row;   /* Current logical row number to read */
00057 
00058   /* Pointer to routine to extract next Targa pixel from input file */
00059   JMETHOD(void, read_pixel, (tga_source_ptr sinfo));
00060 
00061   /* Result of read_pixel is delivered here: */
00062   U_CHAR tga_pixel[4];
00063 
00064   int pixel_size;           /* Bytes per Targa pixel (1 to 4) */
00065 
00066   /* State info for reading RLE-coded pixels; both counts must be init to 0 */
00067   int block_count;          /* # of pixels remaining in RLE block */
00068   int dup_pixel_count;             /* # of times to duplicate previous pixel */
00069 
00070   /* This saves the correct pixel-row-expansion method for preload_image */
00071   JMETHOD(JDIMENSION, get_pixel_rows, (j_compress_ptr cinfo,
00072                                    cjpeg_source_ptr sinfo));
00073 } tga_source_struct;
00074 
00075 
00076 /* For expanding 5-bit pixel values to 8-bit with best rounding */
00077 
00078 static const UINT8 c5to8bits[32] = {
00079     0,   8,  16,  25,  33,  41,  49,  58,
00080    66,  74,  82,  90,  99, 107, 115, 123,
00081   132, 140, 148, 156, 165, 173, 181, 189,
00082   197, 206, 214, 222, 230, 239, 247, 255
00083 };
00084 
00085 
00086 
00087 LOCAL(int)
00088 read_byte (tga_source_ptr sinfo)
00089 /* Read next byte from Targa file */
00090 {
00091   register FILE *infile = sinfo->pub.input_file;
00092   register int c;
00093 
00094   if ((c = getc(infile)) == EOF)
00095     ERREXIT(sinfo->cinfo, JERR_INPUT_EOF);
00096   return c;
00097 }
00098 
00099 
00100 LOCAL(void)
00101 read_colormap (tga_source_ptr sinfo, int cmaplen, int mapentrysize)
00102 /* Read the colormap from a Targa file */
00103 {
00104   int i;
00105 
00106   /* Presently only handles 24-bit BGR format */
00107   if (mapentrysize != 24)
00108     ERREXIT(sinfo->cinfo, JERR_TGA_BADCMAP);
00109 
00110   for (i = 0; i < cmaplen; i++) {
00111     sinfo->colormap[2][i] = (JSAMPLE) read_byte(sinfo);
00112     sinfo->colormap[1][i] = (JSAMPLE) read_byte(sinfo);
00113     sinfo->colormap[0][i] = (JSAMPLE) read_byte(sinfo);
00114   }
00115 }
00116 
00117 
00118 /*
00119  * read_pixel methods: get a single pixel from Targa file into tga_pixel[]
00120  */
00121 
00122 METHODDEF(void)
00123 read_non_rle_pixel (tga_source_ptr sinfo)
00124 /* Read one Targa pixel from the input file; no RLE expansion */
00125 {
00126   register FILE *infile = sinfo->pub.input_file;
00127   register int i;
00128 
00129   for (i = 0; i < sinfo->pixel_size; i++) {
00130     sinfo->tga_pixel[i] = (U_CHAR) getc(infile);
00131   }
00132 }
00133 
00134 
00135 METHODDEF(void)
00136 read_rle_pixel (tga_source_ptr sinfo)
00137 /* Read one Targa pixel from the input file, expanding RLE data as needed */
00138 {
00139   register FILE *infile = sinfo->pub.input_file;
00140   register int i;
00141 
00142   /* Duplicate previously read pixel? */
00143   if (sinfo->dup_pixel_count > 0) {
00144     sinfo->dup_pixel_count--;
00145     return;
00146   }
00147 
00148   /* Time to read RLE block header? */
00149   if (--sinfo->block_count < 0) { /* decrement pixels remaining in block */
00150     i = read_byte(sinfo);
00151     if (i & 0x80) {         /* Start of duplicate-pixel block? */
00152       sinfo->dup_pixel_count = i & 0x7F; /* number of dups after this one */
00153       sinfo->block_count = 0;      /* then read new block header */
00154     } else {
00155       sinfo->block_count = i & 0x7F; /* number of pixels after this one */
00156     }
00157   }
00158 
00159   /* Read next pixel */
00160   for (i = 0; i < sinfo->pixel_size; i++) {
00161     sinfo->tga_pixel[i] = (U_CHAR) getc(infile);
00162   }
00163 }
00164 
00165 
00166 /*
00167  * Read one row of pixels.
00168  *
00169  * We provide several different versions depending on input file format.
00170  */
00171 
00172 
00173 METHODDEF(JDIMENSION)
00174 get_8bit_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
00175 /* This version is for reading 8-bit grayscale pixels */
00176 {
00177   tga_source_ptr source = (tga_source_ptr) sinfo;
00178   register JSAMPROW ptr;
00179   register JDIMENSION col;
00180   
00181   ptr = source->pub.buffer[0];
00182   for (col = cinfo->image_width; col > 0; col--) {
00183     (*source->read_pixel) (source); /* Load next pixel into tga_pixel */
00184     *ptr++ = (JSAMPLE) UCH(source->tga_pixel[0]);
00185   }
00186   return 1;
00187 }
00188 
00189 METHODDEF(JDIMENSION)
00190 get_8bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
00191 /* This version is for reading 8-bit colormap indexes */
00192 {
00193   tga_source_ptr source = (tga_source_ptr) sinfo;
00194   register int t;
00195   register JSAMPROW ptr;
00196   register JDIMENSION col;
00197   register JSAMPARRAY colormap = source->colormap;
00198 
00199   ptr = source->pub.buffer[0];
00200   for (col = cinfo->image_width; col > 0; col--) {
00201     (*source->read_pixel) (source); /* Load next pixel into tga_pixel */
00202     t = UCH(source->tga_pixel[0]);
00203     *ptr++ = colormap[0][t];
00204     *ptr++ = colormap[1][t];
00205     *ptr++ = colormap[2][t];
00206   }
00207   return 1;
00208 }
00209 
00210 METHODDEF(JDIMENSION)
00211 get_16bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
00212 /* This version is for reading 16-bit pixels */
00213 {
00214   tga_source_ptr source = (tga_source_ptr) sinfo;
00215   register int t;
00216   register JSAMPROW ptr;
00217   register JDIMENSION col;
00218   
00219   ptr = source->pub.buffer[0];
00220   for (col = cinfo->image_width; col > 0; col--) {
00221     (*source->read_pixel) (source); /* Load next pixel into tga_pixel */
00222     t = UCH(source->tga_pixel[0]);
00223     t += UCH(source->tga_pixel[1]) << 8;
00224     /* We expand 5 bit data to 8 bit sample width.
00225      * The format of the 16-bit (LSB first) input word is
00226      *     xRRRRRGGGGGBBBBB
00227      */
00228     ptr[2] = (JSAMPLE) c5to8bits[t & 0x1F];
00229     t >>= 5;
00230     ptr[1] = (JSAMPLE) c5to8bits[t & 0x1F];
00231     t >>= 5;
00232     ptr[0] = (JSAMPLE) c5to8bits[t & 0x1F];
00233     ptr += 3;
00234   }
00235   return 1;
00236 }
00237 
00238 METHODDEF(JDIMENSION)
00239 get_24bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
00240 /* This version is for reading 24-bit pixels */
00241 {
00242   tga_source_ptr source = (tga_source_ptr) sinfo;
00243   register JSAMPROW ptr;
00244   register JDIMENSION col;
00245   
00246   ptr = source->pub.buffer[0];
00247   for (col = cinfo->image_width; col > 0; col--) {
00248     (*source->read_pixel) (source); /* Load next pixel into tga_pixel */
00249     *ptr++ = (JSAMPLE) UCH(source->tga_pixel[2]); /* change BGR to RGB order */
00250     *ptr++ = (JSAMPLE) UCH(source->tga_pixel[1]);
00251     *ptr++ = (JSAMPLE) UCH(source->tga_pixel[0]);
00252   }
00253   return 1;
00254 }
00255 
00256 /*
00257  * Targa also defines a 32-bit pixel format with order B,G,R,A.
00258  * We presently ignore the attribute byte, so the code for reading
00259  * these pixels is identical to the 24-bit routine above.
00260  * This works because the actual pixel length is only known to read_pixel.
00261  */
00262 
00263 #define get_32bit_row  get_24bit_row
00264 
00265 
00266 /*
00267  * This method is for re-reading the input data in standard top-down
00268  * row order.  The entire image has already been read into whole_image
00269  * with proper conversion of pixel format, but it's in a funny row order.
00270  */
00271 
00272 METHODDEF(JDIMENSION)
00273 get_memory_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
00274 {
00275   tga_source_ptr source = (tga_source_ptr) sinfo;
00276   JDIMENSION source_row;
00277 
00278   /* Compute row of source that maps to current_row of normal order */
00279   /* For now, assume image is bottom-up and not interlaced. */
00280   /* NEEDS WORK to support interlaced images! */
00281   source_row = cinfo->image_height - source->current_row - 1;
00282 
00283   /* Fetch that row from virtual array */
00284   source->pub.buffer = (*cinfo->mem->access_virt_sarray)
00285     ((j_common_ptr) cinfo, source->whole_image,
00286      source_row, (JDIMENSION) 1, FALSE);
00287 
00288   source->current_row++;
00289   return 1;
00290 }
00291 
00292 
00293 /*
00294  * This method loads the image into whole_image during the first call on
00295  * get_pixel_rows.  The get_pixel_rows pointer is then adjusted to call
00296  * get_memory_row on subsequent calls.
00297  */
00298 
00299 METHODDEF(JDIMENSION)
00300 preload_image (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
00301 {
00302   tga_source_ptr source = (tga_source_ptr) sinfo;
00303   JDIMENSION row;
00304   cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
00305 
00306   /* Read the data into a virtual array in input-file row order. */
00307   for (row = 0; row < cinfo->image_height; row++) {
00308     if (progress != NULL) {
00309       progress->pub.pass_counter = (long) row;
00310       progress->pub.pass_limit = (long) cinfo->image_height;
00311       (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
00312     }
00313     source->pub.buffer = (*cinfo->mem->access_virt_sarray)
00314       ((j_common_ptr) cinfo, source->whole_image, row, (JDIMENSION) 1, TRUE);
00315     (*source->get_pixel_rows) (cinfo, sinfo);
00316   }
00317   if (progress != NULL)
00318     progress->completed_extra_passes++;
00319 
00320   /* Set up to read from the virtual array in unscrambled order */
00321   source->pub.get_pixel_rows = get_memory_row;
00322   source->current_row = 0;
00323   /* And read the first row */
00324   return get_memory_row(cinfo, sinfo);
00325 }
00326 
00327 
00328 /*
00329  * Read the file header; return image size and component count.
00330  */
00331 
00332 METHODDEF(void)
00333 start_input_tga (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
00334 {
00335   tga_source_ptr source = (tga_source_ptr) sinfo;
00336   U_CHAR targaheader[18];
00337   int idlen, cmaptype, subtype, flags, interlace_type, components;
00338   unsigned int width, height, maplen;
00339   boolean is_bottom_up;
00340 
00341 #define GET_2B(offset)      ((unsigned int) UCH(targaheader[offset]) + \
00342                       (((unsigned int) UCH(targaheader[offset+1])) << 8))
00343 
00344   if (! ReadOK(source->pub.input_file, targaheader, 18))
00345     ERREXIT(cinfo, JERR_INPUT_EOF);
00346 
00347   /* Pretend "15-bit" pixels are 16-bit --- we ignore attribute bit anyway */
00348   if (targaheader[16] == 15)
00349     targaheader[16] = 16;
00350 
00351   idlen = UCH(targaheader[0]);
00352   cmaptype = UCH(targaheader[1]);
00353   subtype = UCH(targaheader[2]);
00354   maplen = GET_2B(5);
00355   width = GET_2B(12);
00356   height = GET_2B(14);
00357   source->pixel_size = UCH(targaheader[16]) >> 3;
00358   flags = UCH(targaheader[17]);    /* Image Descriptor byte */
00359 
00360   is_bottom_up = ((flags & 0x20) == 0);   /* bit 5 set => top-down */
00361   interlace_type = flags >> 6;     /* bits 6/7 are interlace code */
00362 
00363   if (cmaptype > 1 ||              /* cmaptype must be 0 or 1 */
00364       source->pixel_size < 1 || source->pixel_size > 4 ||
00365       (UCH(targaheader[16]) & 7) != 0 || /* bits/pixel must be multiple of 8 */
00366       interlace_type != 0)  /* currently don't allow interlaced image */
00367     ERREXIT(cinfo, JERR_TGA_BADPARMS);
00368   
00369   if (subtype > 8) {
00370     /* It's an RLE-coded file */
00371     source->read_pixel = read_rle_pixel;
00372     source->block_count = source->dup_pixel_count = 0;
00373     subtype -= 8;
00374   } else {
00375     /* Non-RLE file */
00376     source->read_pixel = read_non_rle_pixel;
00377   }
00378 
00379   /* Now should have subtype 1, 2, or 3 */
00380   components = 3;           /* until proven different */
00381   cinfo->in_color_space = JCS_RGB;
00382 
00383   switch (subtype) {
00384   case 1:                   /* Colormapped image */
00385     if (source->pixel_size == 1 && cmaptype == 1)
00386       source->get_pixel_rows = get_8bit_row;
00387     else
00388       ERREXIT(cinfo, JERR_TGA_BADPARMS);
00389     TRACEMS2(cinfo, 1, JTRC_TGA_MAPPED, width, height);
00390     break;
00391   case 2:                   /* RGB image */
00392     switch (source->pixel_size) {
00393     case 2:
00394       source->get_pixel_rows = get_16bit_row;
00395       break;
00396     case 3:
00397       source->get_pixel_rows = get_24bit_row;
00398       break;
00399     case 4:
00400       source->get_pixel_rows = get_32bit_row;
00401       break;
00402     default:
00403       ERREXIT(cinfo, JERR_TGA_BADPARMS);
00404       break;
00405     }
00406     TRACEMS2(cinfo, 1, JTRC_TGA, width, height);
00407     break;
00408   case 3:                   /* Grayscale image */
00409     components = 1;
00410     cinfo->in_color_space = JCS_GRAYSCALE;
00411     if (source->pixel_size == 1)
00412       source->get_pixel_rows = get_8bit_gray_row;
00413     else
00414       ERREXIT(cinfo, JERR_TGA_BADPARMS);
00415     TRACEMS2(cinfo, 1, JTRC_TGA_GRAY, width, height);
00416     break;
00417   default:
00418     ERREXIT(cinfo, JERR_TGA_BADPARMS);
00419     break;
00420   }
00421 
00422   if (is_bottom_up) {
00423     /* Create a virtual array to buffer the upside-down image. */
00424     source->whole_image = (*cinfo->mem->request_virt_sarray)
00425       ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
00426        (JDIMENSION) width * components, (JDIMENSION) height, (JDIMENSION) 1);
00427     if (cinfo->progress != NULL) {
00428       cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
00429       progress->total_extra_passes++; /* count file input as separate pass */
00430     }
00431     /* source->pub.buffer will point to the virtual array. */
00432     source->pub.buffer_height = 1; /* in case anyone looks at it */
00433     source->pub.get_pixel_rows = preload_image;
00434   } else {
00435     /* Don't need a virtual array, but do need a one-row input buffer. */
00436     source->whole_image = NULL;
00437     source->pub.buffer = (*cinfo->mem->alloc_sarray)
00438       ((j_common_ptr) cinfo, JPOOL_IMAGE,
00439        (JDIMENSION) width * components, (JDIMENSION) 1);
00440     source->pub.buffer_height = 1;
00441     source->pub.get_pixel_rows = source->get_pixel_rows;
00442   }
00443   
00444   while (idlen--)           /* Throw away ID field */
00445     (void) read_byte(source);
00446 
00447   if (maplen > 0) {
00448     if (maplen > 256 || GET_2B(3) != 0)
00449       ERREXIT(cinfo, JERR_TGA_BADCMAP);
00450     /* Allocate space to store the colormap */
00451     source->colormap = (*cinfo->mem->alloc_sarray)
00452       ((j_common_ptr) cinfo, JPOOL_IMAGE, (JDIMENSION) maplen, (JDIMENSION) 3);
00453     /* and read it from the file */
00454     read_colormap(source, (int) maplen, UCH(targaheader[7]));
00455   } else {
00456     if (cmaptype)           /* but you promised a cmap! */
00457       ERREXIT(cinfo, JERR_TGA_BADPARMS);
00458     source->colormap = NULL;
00459   }
00460 
00461   cinfo->input_components = components;
00462   cinfo->data_precision = 8;
00463   cinfo->image_width = width;
00464   cinfo->image_height = height;
00465 }
00466 
00467 
00468 /*
00469  * Finish up at the end of the file.
00470  */
00471 
00472 METHODDEF(void)
00473 finish_input_tga (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
00474 {
00475   /* no work */
00476 }
00477 
00478 
00479 /*
00480  * The module selection routine for Targa format input.
00481  */
00482 
00483 GLOBAL(cjpeg_source_ptr)
00484 jinit_read_targa (j_compress_ptr cinfo)
00485 {
00486   tga_source_ptr source;
00487 
00488   /* Create module interface object */
00489   source = (tga_source_ptr)
00490       (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
00491                               SIZEOF(tga_source_struct));
00492   source->cinfo = cinfo;    /* make back link for subroutines */
00493   /* Fill in method ptrs, except get_pixel_rows which start_input sets */
00494   source->pub.start_input = start_input_tga;
00495   source->pub.finish_input = finish_input_tga;
00496 
00497   return (cjpeg_source_ptr) source;
00498 }
00499 
00500 #endif /* TARGA_SUPPORTED */