• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)
read_byte(tga_source_ptr sinfo)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)
read_colormap(tga_source_ptr sinfo,int cmaplen,int mapentrysize)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)
read_non_rle_pixel(tga_source_ptr sinfo)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)
read_rle_pixel(tga_source_ptr sinfo)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)
get_8bit_gray_row(j_compress_ptr cinfo,cjpeg_source_ptr sinfo)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)
get_8bit_row(j_compress_ptr cinfo,cjpeg_source_ptr sinfo)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)
get_16bit_row(j_compress_ptr cinfo,cjpeg_source_ptr sinfo)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)
get_24bit_row(j_compress_ptr cinfo,cjpeg_source_ptr sinfo)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)
get_memory_row(j_compress_ptr cinfo,cjpeg_source_ptr sinfo)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)
preload_image(j_compress_ptr cinfo,cjpeg_source_ptr sinfo)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)
start_input_tga(j_compress_ptr cinfo,cjpeg_source_ptr sinfo)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)
finish_input_tga(j_compress_ptr cinfo,cjpeg_source_ptr sinfo)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)
jinit_read_targa(j_compress_ptr cinfo)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