Home | History | Annotate | Download | only in libjpeg-turbo
      1 /*
      2  * rdtarga.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 relevant
      7  * 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 Targa format.
     12  *
     13  * These routines may need modification for non-Unix environments or
     14  * specialized applications.  As they stand, they assume input from
     15  * an ordinary stdio stream.  They further assume that reading begins
     16  * at the start of the file; start_input may need work if the
     17  * user interface has already read some data (e.g., to determine that
     18  * the file is indeed Targa format).
     19  *
     20  * Based on code contributed by Lee Daniel Crocker.
     21  */
     22 
     23 #include "cdjpeg.h"             /* Common decls for cjpeg/djpeg applications */
     24 
     25 #ifdef TARGA_SUPPORTED
     26 
     27 
     28 /* Macros to deal with unsigned chars as efficiently as compiler allows */
     29 
     30 #ifdef HAVE_UNSIGNED_CHAR
     31 typedef unsigned char U_CHAR;
     32 #define UCH(x)  ((int) (x))
     33 #else /* !HAVE_UNSIGNED_CHAR */
     34 #ifdef __CHAR_UNSIGNED__
     35 typedef char U_CHAR;
     36 #define UCH(x)  ((int) (x))
     37 #else
     38 typedef char U_CHAR;
     39 #define UCH(x)  ((int) (x) & 0xFF)
     40 #endif
     41 #endif /* HAVE_UNSIGNED_CHAR */
     42 
     43 
     44 #define ReadOK(file,buffer,len) (JFREAD(file,buffer,len) == ((size_t) (len)))
     45 
     46 
     47 /* Private version of data source object */
     48 
     49 typedef struct _tga_source_struct *tga_source_ptr;
     50 
     51 typedef struct _tga_source_struct {
     52   struct cjpeg_source_struct pub; /* public fields */
     53 
     54   j_compress_ptr cinfo;         /* back link saves passing separate parm */
     55 
     56   JSAMPARRAY colormap;          /* Targa colormap (converted to my format) */
     57 
     58   jvirt_sarray_ptr whole_image; /* Needed if funny input row order */
     59   JDIMENSION current_row;       /* Current logical row number to read */
     60 
     61   /* Pointer to routine to extract next Targa pixel from input file */
     62   void (*read_pixel) (tga_source_ptr sinfo);
     63 
     64   /* Result of read_pixel is delivered here: */
     65   U_CHAR tga_pixel[4];
     66 
     67   int pixel_size;               /* Bytes per Targa pixel (1 to 4) */
     68 
     69   /* State info for reading RLE-coded pixels; both counts must be init to 0 */
     70   int block_count;              /* # of pixels remaining in RLE block */
     71   int dup_pixel_count;          /* # of times to duplicate previous pixel */
     72 
     73   /* This saves the correct pixel-row-expansion method for preload_image */
     74   JDIMENSION (*get_pixel_rows) (j_compress_ptr cinfo, cjpeg_source_ptr sinfo);
     75 } tga_source_struct;
     76 
     77 
     78 /* For expanding 5-bit pixel values to 8-bit with best rounding */
     79 
     80 static const UINT8 c5to8bits[32] = {
     81     0,   8,  16,  25,  33,  41,  49,  58,
     82    66,  74,  82,  90,  99, 107, 115, 123,
     83   132, 140, 148, 156, 165, 173, 181, 189,
     84   197, 206, 214, 222, 230, 239, 247, 255
     85 };
     86 
     87 
     88 
     89 LOCAL(int)
     90 read_byte (tga_source_ptr sinfo)
     91 /* Read next byte from Targa file */
     92 {
     93   register FILE *infile = sinfo->pub.input_file;
     94   register int c;
     95 
     96   if ((c = getc(infile)) == EOF)
     97     ERREXIT(sinfo->cinfo, JERR_INPUT_EOF);
     98   return c;
     99 }
    100 
    101 
    102 LOCAL(void)
    103 read_colormap (tga_source_ptr sinfo, int cmaplen, int mapentrysize)
    104 /* Read the colormap from a Targa file */
    105 {
    106   int i;
    107 
    108   /* Presently only handles 24-bit BGR format */
    109   if (mapentrysize != 24)
    110     ERREXIT(sinfo->cinfo, JERR_TGA_BADCMAP);
    111 
    112   for (i = 0; i < cmaplen; i++) {
    113     sinfo->colormap[2][i] = (JSAMPLE) read_byte(sinfo);
    114     sinfo->colormap[1][i] = (JSAMPLE) read_byte(sinfo);
    115     sinfo->colormap[0][i] = (JSAMPLE) read_byte(sinfo);
    116   }
    117 }
    118 
    119 
    120 /*
    121  * read_pixel methods: get a single pixel from Targa file into tga_pixel[]
    122  */
    123 
    124 METHODDEF(void)
    125 read_non_rle_pixel (tga_source_ptr sinfo)
    126 /* Read one Targa pixel from the input file; no RLE expansion */
    127 {
    128   register FILE *infile = sinfo->pub.input_file;
    129   register int i;
    130 
    131   for (i = 0; i < sinfo->pixel_size; i++) {
    132     sinfo->tga_pixel[i] = (U_CHAR) getc(infile);
    133   }
    134 }
    135 
    136 
    137 METHODDEF(void)
    138 read_rle_pixel (tga_source_ptr sinfo)
    139 /* Read one Targa pixel from the input file, expanding RLE data as needed */
    140 {
    141   register FILE *infile = sinfo->pub.input_file;
    142   register int i;
    143 
    144   /* Duplicate previously read pixel? */
    145   if (sinfo->dup_pixel_count > 0) {
    146     sinfo->dup_pixel_count--;
    147     return;
    148   }
    149 
    150   /* Time to read RLE block header? */
    151   if (--sinfo->block_count < 0) { /* decrement pixels remaining in block */
    152     i = read_byte(sinfo);
    153     if (i & 0x80) {             /* Start of duplicate-pixel block? */
    154       sinfo->dup_pixel_count = i & 0x7F; /* number of dups after this one */
    155       sinfo->block_count = 0;   /* then read new block header */
    156     } else {
    157       sinfo->block_count = i & 0x7F; /* number of pixels after this one */
    158     }
    159   }
    160 
    161   /* Read next pixel */
    162   for (i = 0; i < sinfo->pixel_size; i++) {
    163     sinfo->tga_pixel[i] = (U_CHAR) getc(infile);
    164   }
    165 }
    166 
    167 
    168 /*
    169  * Read one row of pixels.
    170  *
    171  * We provide several different versions depending on input file format.
    172  */
    173 
    174 
    175 METHODDEF(JDIMENSION)
    176 get_8bit_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
    177 /* This version is for reading 8-bit grayscale pixels */
    178 {
    179   tga_source_ptr source = (tga_source_ptr) sinfo;
    180   register JSAMPROW ptr;
    181   register JDIMENSION col;
    182 
    183   ptr = source->pub.buffer[0];
    184   for (col = cinfo->image_width; col > 0; col--) {
    185     (*source->read_pixel) (source); /* Load next pixel into tga_pixel */
    186     *ptr++ = (JSAMPLE) UCH(source->tga_pixel[0]);
    187   }
    188   return 1;
    189 }
    190 
    191 METHODDEF(JDIMENSION)
    192 get_8bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
    193 /* This version is for reading 8-bit colormap indexes */
    194 {
    195   tga_source_ptr source = (tga_source_ptr) sinfo;
    196   register int t;
    197   register JSAMPROW ptr;
    198   register JDIMENSION col;
    199   register JSAMPARRAY colormap = source->colormap;
    200 
    201   ptr = source->pub.buffer[0];
    202   for (col = cinfo->image_width; col > 0; col--) {
    203     (*source->read_pixel) (source); /* Load next pixel into tga_pixel */
    204     t = UCH(source->tga_pixel[0]);
    205     *ptr++ = colormap[0][t];
    206     *ptr++ = colormap[1][t];
    207     *ptr++ = colormap[2][t];
    208   }
    209   return 1;
    210 }
    211 
    212 METHODDEF(JDIMENSION)
    213 get_16bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
    214 /* This version is for reading 16-bit pixels */
    215 {
    216   tga_source_ptr source = (tga_source_ptr) sinfo;
    217   register int t;
    218   register JSAMPROW ptr;
    219   register JDIMENSION col;
    220 
    221   ptr = source->pub.buffer[0];
    222   for (col = cinfo->image_width; col > 0; col--) {
    223     (*source->read_pixel) (source); /* Load next pixel into tga_pixel */
    224     t = UCH(source->tga_pixel[0]);
    225     t += UCH(source->tga_pixel[1]) << 8;
    226     /* We expand 5 bit data to 8 bit sample width.
    227      * The format of the 16-bit (LSB first) input word is
    228      *     xRRRRRGGGGGBBBBB
    229      */
    230     ptr[2] = (JSAMPLE) c5to8bits[t & 0x1F];
    231     t >>= 5;
    232     ptr[1] = (JSAMPLE) c5to8bits[t & 0x1F];
    233     t >>= 5;
    234     ptr[0] = (JSAMPLE) c5to8bits[t & 0x1F];
    235     ptr += 3;
    236   }
    237   return 1;
    238 }
    239 
    240 METHODDEF(JDIMENSION)
    241 get_24bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
    242 /* This version is for reading 24-bit pixels */
    243 {
    244   tga_source_ptr source = (tga_source_ptr) sinfo;
    245   register JSAMPROW ptr;
    246   register JDIMENSION col;
    247 
    248   ptr = source->pub.buffer[0];
    249   for (col = cinfo->image_width; col > 0; col--) {
    250     (*source->read_pixel) (source); /* Load next pixel into tga_pixel */
    251     *ptr++ = (JSAMPLE) UCH(source->tga_pixel[2]); /* change BGR to RGB order */
    252     *ptr++ = (JSAMPLE) UCH(source->tga_pixel[1]);
    253     *ptr++ = (JSAMPLE) UCH(source->tga_pixel[0]);
    254   }
    255   return 1;
    256 }
    257 
    258 /*
    259  * Targa also defines a 32-bit pixel format with order B,G,R,A.
    260  * We presently ignore the attribute byte, so the code for reading
    261  * these pixels is identical to the 24-bit routine above.
    262  * This works because the actual pixel length is only known to read_pixel.
    263  */
    264 
    265 #define get_32bit_row  get_24bit_row
    266 
    267 
    268 /*
    269  * This method is for re-reading the input data in standard top-down
    270  * row order.  The entire image has already been read into whole_image
    271  * with proper conversion of pixel format, but it's in a funny row order.
    272  */
    273 
    274 METHODDEF(JDIMENSION)
    275 get_memory_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
    276 {
    277   tga_source_ptr source = (tga_source_ptr) sinfo;
    278   JDIMENSION source_row;
    279 
    280   /* Compute row of source that maps to current_row of normal order */
    281   /* For now, assume image is bottom-up and not interlaced. */
    282   /* NEEDS WORK to support interlaced images! */
    283   source_row = cinfo->image_height - source->current_row - 1;
    284 
    285   /* Fetch that row from virtual array */
    286   source->pub.buffer = (*cinfo->mem->access_virt_sarray)
    287     ((j_common_ptr) cinfo, source->whole_image,
    288      source_row, (JDIMENSION) 1, FALSE);
    289 
    290   source->current_row++;
    291   return 1;
    292 }
    293 
    294 
    295 /*
    296  * This method loads the image into whole_image during the first call on
    297  * get_pixel_rows.  The get_pixel_rows pointer is then adjusted to call
    298  * get_memory_row on subsequent calls.
    299  */
    300 
    301 METHODDEF(JDIMENSION)
    302 preload_image (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
    303 {
    304   tga_source_ptr source = (tga_source_ptr) sinfo;
    305   JDIMENSION row;
    306   cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
    307 
    308   /* Read the data into a virtual array in input-file row order. */
    309   for (row = 0; row < cinfo->image_height; row++) {
    310     if (progress != NULL) {
    311       progress->pub.pass_counter = (long) row;
    312       progress->pub.pass_limit = (long) cinfo->image_height;
    313       (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
    314     }
    315     source->pub.buffer = (*cinfo->mem->access_virt_sarray)
    316       ((j_common_ptr) cinfo, source->whole_image, row, (JDIMENSION) 1, TRUE);
    317     (*source->get_pixel_rows) (cinfo, sinfo);
    318   }
    319   if (progress != NULL)
    320     progress->completed_extra_passes++;
    321 
    322   /* Set up to read from the virtual array in unscrambled order */
    323   source->pub.get_pixel_rows = get_memory_row;
    324   source->current_row = 0;
    325   /* And read the first row */
    326   return get_memory_row(cinfo, sinfo);
    327 }
    328 
    329 
    330 /*
    331  * Read the file header; return image size and component count.
    332  */
    333 
    334 METHODDEF(void)
    335 start_input_tga (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
    336 {
    337   tga_source_ptr source = (tga_source_ptr) sinfo;
    338   U_CHAR targaheader[18];
    339   int idlen, cmaptype, subtype, flags, interlace_type, components;
    340   unsigned int width, height, maplen;
    341   boolean is_bottom_up;
    342 
    343 #define GET_2B(offset)  ((unsigned int) UCH(targaheader[offset]) + \
    344                          (((unsigned int) UCH(targaheader[offset+1])) << 8))
    345 
    346   if (! ReadOK(source->pub.input_file, targaheader, 18))
    347     ERREXIT(cinfo, JERR_INPUT_EOF);
    348 
    349   /* Pretend "15-bit" pixels are 16-bit --- we ignore attribute bit anyway */
    350   if (targaheader[16] == 15)
    351     targaheader[16] = 16;
    352 
    353   idlen = UCH(targaheader[0]);
    354   cmaptype = UCH(targaheader[1]);
    355   subtype = UCH(targaheader[2]);
    356   maplen = GET_2B(5);
    357   width = GET_2B(12);
    358   height = GET_2B(14);
    359   source->pixel_size = UCH(targaheader[16]) >> 3;
    360   flags = UCH(targaheader[17]); /* Image Descriptor byte */
    361 
    362   is_bottom_up = ((flags & 0x20) == 0); /* bit 5 set => top-down */
    363   interlace_type = flags >> 6;  /* bits 6/7 are interlace code */
    364 
    365   if (cmaptype > 1 ||           /* cmaptype must be 0 or 1 */
    366       source->pixel_size < 1 || source->pixel_size > 4 ||
    367       (UCH(targaheader[16]) & 7) != 0 || /* bits/pixel must be multiple of 8 */
    368       interlace_type != 0 ||      /* currently don't allow interlaced image */
    369       width == 0 || height == 0)  /* image width/height must be non-zero */
    370     ERREXIT(cinfo, JERR_TGA_BADPARMS);
    371 
    372   if (subtype > 8) {
    373     /* It's an RLE-coded file */
    374     source->read_pixel = read_rle_pixel;
    375     source->block_count = source->dup_pixel_count = 0;
    376     subtype -= 8;
    377   } else {
    378     /* Non-RLE file */
    379     source->read_pixel = read_non_rle_pixel;
    380   }
    381 
    382   /* Now should have subtype 1, 2, or 3 */
    383   components = 3;               /* until proven different */
    384   cinfo->in_color_space = JCS_RGB;
    385 
    386   switch (subtype) {
    387   case 1:                       /* Colormapped image */
    388     if (source->pixel_size == 1 && cmaptype == 1)
    389       source->get_pixel_rows = get_8bit_row;
    390     else
    391       ERREXIT(cinfo, JERR_TGA_BADPARMS);
    392     TRACEMS2(cinfo, 1, JTRC_TGA_MAPPED, width, height);
    393     break;
    394   case 2:                       /* RGB image */
    395     switch (source->pixel_size) {
    396     case 2:
    397       source->get_pixel_rows = get_16bit_row;
    398       break;
    399     case 3:
    400       source->get_pixel_rows = get_24bit_row;
    401       break;
    402     case 4:
    403       source->get_pixel_rows = get_32bit_row;
    404       break;
    405     default:
    406       ERREXIT(cinfo, JERR_TGA_BADPARMS);
    407       break;
    408     }
    409     TRACEMS2(cinfo, 1, JTRC_TGA, width, height);
    410     break;
    411   case 3:                       /* Grayscale image */
    412     components = 1;
    413     cinfo->in_color_space = JCS_GRAYSCALE;
    414     if (source->pixel_size == 1)
    415       source->get_pixel_rows = get_8bit_gray_row;
    416     else
    417       ERREXIT(cinfo, JERR_TGA_BADPARMS);
    418     TRACEMS2(cinfo, 1, JTRC_TGA_GRAY, width, height);
    419     break;
    420   default:
    421     ERREXIT(cinfo, JERR_TGA_BADPARMS);
    422     break;
    423   }
    424 
    425   if (is_bottom_up) {
    426     /* Create a virtual array to buffer the upside-down image. */
    427     source->whole_image = (*cinfo->mem->request_virt_sarray)
    428       ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
    429        (JDIMENSION) width * components, (JDIMENSION) height, (JDIMENSION) 1);
    430     if (cinfo->progress != NULL) {
    431       cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
    432       progress->total_extra_passes++; /* count file input as separate pass */
    433     }
    434     /* source->pub.buffer will point to the virtual array. */
    435     source->pub.buffer_height = 1; /* in case anyone looks at it */
    436     source->pub.get_pixel_rows = preload_image;
    437   } else {
    438     /* Don't need a virtual array, but do need a one-row input buffer. */
    439     source->whole_image = NULL;
    440     source->pub.buffer = (*cinfo->mem->alloc_sarray)
    441       ((j_common_ptr) cinfo, JPOOL_IMAGE,
    442        (JDIMENSION) width * components, (JDIMENSION) 1);
    443     source->pub.buffer_height = 1;
    444     source->pub.get_pixel_rows = source->get_pixel_rows;
    445   }
    446 
    447   while (idlen--)               /* Throw away ID field */
    448     (void) read_byte(source);
    449 
    450   if (maplen > 0) {
    451     if (maplen > 256 || GET_2B(3) != 0)
    452       ERREXIT(cinfo, JERR_TGA_BADCMAP);
    453     /* Allocate space to store the colormap */
    454     source->colormap = (*cinfo->mem->alloc_sarray)
    455       ((j_common_ptr) cinfo, JPOOL_IMAGE, (JDIMENSION) maplen, (JDIMENSION) 3);
    456     /* and read it from the file */
    457     read_colormap(source, (int) maplen, UCH(targaheader[7]));
    458   } else {
    459     if (cmaptype)               /* but you promised a cmap! */
    460       ERREXIT(cinfo, JERR_TGA_BADPARMS);
    461     source->colormap = NULL;
    462   }
    463 
    464   cinfo->input_components = components;
    465   cinfo->data_precision = 8;
    466   cinfo->image_width = width;
    467   cinfo->image_height = height;
    468 }
    469 
    470 
    471 /*
    472  * Finish up at the end of the file.
    473  */
    474 
    475 METHODDEF(void)
    476 finish_input_tga (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
    477 {
    478   /* no work */
    479 }
    480 
    481 
    482 /*
    483  * The module selection routine for Targa format input.
    484  */
    485 
    486 GLOBAL(cjpeg_source_ptr)
    487 jinit_read_targa (j_compress_ptr cinfo)
    488 {
    489   tga_source_ptr source;
    490 
    491   /* Create module interface object */
    492   source = (tga_source_ptr)
    493       (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
    494                                   sizeof(tga_source_struct));
    495   source->cinfo = cinfo;        /* make back link for subroutines */
    496   /* Fill in method ptrs, except get_pixel_rows which start_input sets */
    497   source->pub.start_input = start_input_tga;
    498   source->pub.finish_input = finish_input_tga;
    499 
    500   return (cjpeg_source_ptr) source;
    501 }
    502 
    503 #endif /* TARGA_SUPPORTED */
    504