1 
2 
3 /* ---------------------------------------------------------------------------
4  * Truevision Targa Reader/Writer
5  * Copyright (C) 2001-2003, Emil Mikulic.
6  *
7  * Source and binary redistribution of this code, with or without changes, for
8  * free or for profit, is allowed as long as this copyright notice is kept
9  * intact.  Modified versions must be clearly marked as modified.
10  *
11  * This code is provided without any warranty.  The copyright holder is
12  * not liable for anything bad that might happen as a result of the
13  * code.
14  * -------------------------------------------------------------------------*/
15 
16 /*
17  * preso da http://dmr.ath.cx/gfx/targa/
18  * modificato da gmt
19  *
20  */
21 
22 /*@unused@*/ static const char rcsid[] =
23     "$Id: targa.c,v 1.7 2003/06/21 09:30:53 emikulic Exp $";
24 
25 #define TGA_KEEP_MACROS /* BIT, htole16, letoh16 */
26 #include "targa.h"
27 #include <stdlib.h>
28 #include <string.h> /* memcpy, memcmp */
29 
30 #define SANE_DEPTH(x) ((x) == 8 || (x) == 16 || (x) == 24 || (x) == 32)
31 #define UNMAP_DEPTH(x) ((x) == 16 || (x) == 24 || (x) == 32)
32 
33 static const char tga_id[] =
34     "\0\0\0\0" /* extension area offset */
35     "\0\0\0\0" /* developer directory offset */
36     "TRUEVISION-XFILE.";
37 
38 static const size_t tga_id_length = 26; /* tga_id + \0 */
39 
40 /* helpers */
41 static tga_result tga_read_rle(tga_image *dest, FILE *fp);
42 static tga_result tga_write_row_RLE(FILE *fp, const tga_image *src,
43                                     const uint8_t *row);
44 typedef enum { RAW, RLE } packet_type;
45 static packet_type rle_packet_type(const uint8_t *row, const uint16_t pos,
46                                    const uint16_t width, const uint16_t bpp);
47 static uint8_t rle_packet_len(const uint8_t *row, const uint16_t pos,
48                               const uint16_t width, const uint16_t bpp,
49                               const packet_type type);
50 
tga_get_attribute_bits(const tga_image * tga)51 uint8_t tga_get_attribute_bits(const tga_image *tga) {
52   return tga->image_descriptor & TGA_ATTRIB_BITS;
53 }
54 
tga_is_right_to_left(const tga_image * tga)55 int tga_is_right_to_left(const tga_image *tga) {
56   return (tga->image_descriptor & TGA_R_TO_L_BIT) != 0;
57 }
58 
tga_is_top_to_bottom(const tga_image * tga)59 int tga_is_top_to_bottom(const tga_image *tga) {
60   return (tga->image_descriptor & TGA_T_TO_B_BIT) != 0;
61 }
62 
tga_is_colormapped(const tga_image * tga)63 int tga_is_colormapped(const tga_image *tga) {
64   return (tga->image_type == TGA_IMAGE_TYPE_COLORMAP ||
65           tga->image_type == TGA_IMAGE_TYPE_COLORMAP_RLE);
66 }
67 
tga_is_rle(const tga_image * tga)68 int tga_is_rle(const tga_image *tga) {
69   return (tga->image_type == TGA_IMAGE_TYPE_COLORMAP_RLE ||
70           tga->image_type == TGA_IMAGE_TYPE_BGR_RLE ||
71           tga->image_type == TGA_IMAGE_TYPE_MONO_RLE);
72 }
73 
tga_is_mono(const tga_image * tga)74 int tga_is_mono(const tga_image *tga) {
75   return (tga->image_type == TGA_IMAGE_TYPE_MONO ||
76           tga->image_type == TGA_IMAGE_TYPE_MONO_RLE);
77 }
78 
79 /* ---------------------------------------------------------------------------
80  * Convert the numerical <errcode> into a verbose error string.
81  *
82  * Returns: an error string
83  */
tga_error(const tga_result errcode)84 const char *tga_error(const tga_result errcode) {
85   switch (errcode) {
86   case TGA_NOERR:
87     return "no error";
88   case TGAERR_FOPEN:
89     return "error opening file";
90   case TGAERR_EOF:
91     return "premature end of file";
92   case TGAERR_WRITE:
93     return "error writing to file";
94   case TGAERR_CMAP_TYPE:
95     return "invalid color map type";
96   case TGAERR_IMG_TYPE:
97     return "invalid image type";
98   case TGAERR_NO_IMG:
99     return "no image data included";
100   case TGAERR_CMAP_MISSING:
101     return "color-mapped image without color map";
102   case TGAERR_CMAP_PRESENT:
103     return "non-color-mapped image with extraneous color map";
104   case TGAERR_CMAP_LENGTH:
105     return "color map has zero length";
106   case TGAERR_CMAP_DEPTH:
107     return "invalid color map depth";
108   case TGAERR_ZERO_SIZE:
109     return "the image dimensions are zero";
110   case TGAERR_PIXEL_DEPTH:
111     return "invalid pixel depth";
112   case TGAERR_NO_MEM:
113     return "out of memory";
114   case TGAERR_NOT_CMAP:
115     return "image is not color mapped";
116   case TGAERR_RLE:
117     return "RLE data is corrupt";
118   case TGAERR_INDEX_RANGE:
119     return "color map index out of range";
120   case TGAERR_MONO:
121     return "image is mono";
122   default:
123     return "unknown error code";
124   }
125 }
126 
127 /* ---------------------------------------------------------------------------
128  * Read a Targa image from a file named <filename> to <dest>.  This is just a
129  * wrapper around tga_read_from_FILE().
130  *
131  * Returns: TGA_NOERR on success, or a matching TGAERR_* code on failure.
132  */
tga_read(tga_image * dest,const char * filename)133 tga_result tga_read(tga_image *dest, const char *filename) {
134   tga_result result;
135   FILE *fp = fopen(filename, "rb");
136   if (fp == NULL) return TGAERR_FOPEN;
137   result = tga_read_from_FILE(dest, fp);
138   fclose(fp);
139   return result;
140 }
141 
142 /* ---------------------------------------------------------------------------
143  * Read a Targa image from <fp> to <dest>.
144  *
145  * Returns: TGA_NOERR on success, or a TGAERR_* code on failure.  In the
146  *          case of failure, the contents of dest are not guaranteed to be
147  *          valid.
148  */
tga_read_from_FILE(tga_image * dest,FILE * fp)149 tga_result tga_read_from_FILE(tga_image *dest, FILE *fp) {
150 #define BARF(errcode)                                                          \
151   {                                                                            \
152     tga_free_buffers(dest);                                                    \
153     return errcode;                                                            \
154   }
155 
156 #define READ(destptr, size)                                                    \
157   if (fread(destptr, size, 1, fp) != 1) BARF(TGAERR_EOF)
158 
159 #define READ16(dest)                                                           \
160   {                                                                            \
161     if (fread(&(dest), 2, 1, fp) != 1) BARF(TGAERR_EOF);                       \
162     dest = letoh16(dest);                                                      \
163   }
164 
165   dest->image_id       = NULL;
166   dest->color_map_data = NULL;
167   dest->image_data     = NULL;
168 
169   READ(&dest->image_id_length, 1);
170   READ(&dest->color_map_type, 1);
171   if (dest->color_map_type != TGA_COLOR_MAP_ABSENT &&
172       dest->color_map_type != TGA_COLOR_MAP_PRESENT)
173     BARF(TGAERR_CMAP_TYPE);
174 
175   READ(&dest->image_type, 1);
176   if (dest->image_type == TGA_IMAGE_TYPE_NONE) BARF(TGAERR_NO_IMG);
177 
178   if (dest->image_type != TGA_IMAGE_TYPE_COLORMAP &&
179       dest->image_type != TGA_IMAGE_TYPE_BGR &&
180       dest->image_type != TGA_IMAGE_TYPE_MONO &&
181       dest->image_type != TGA_IMAGE_TYPE_COLORMAP_RLE &&
182       dest->image_type != TGA_IMAGE_TYPE_BGR_RLE &&
183       dest->image_type != TGA_IMAGE_TYPE_MONO_RLE)
184     BARF(TGAERR_IMG_TYPE);
185 
186   if (tga_is_colormapped(dest) && dest->color_map_type == TGA_COLOR_MAP_ABSENT)
187     BARF(TGAERR_CMAP_MISSING);
188 
189   if (!tga_is_colormapped(dest) &&
190       dest->color_map_type == TGA_COLOR_MAP_PRESENT)
191     BARF(TGAERR_CMAP_PRESENT);
192 
193   READ16(dest->color_map_origin);
194   READ16(dest->color_map_length);
195   READ(&dest->color_map_depth, 1);
196   if (dest->color_map_type == TGA_COLOR_MAP_PRESENT) {
197     if (dest->color_map_length == 0) BARF(TGAERR_CMAP_LENGTH);
198 
199     if (!UNMAP_DEPTH(dest->color_map_depth)) BARF(TGAERR_CMAP_DEPTH);
200   }
201 
202   READ16(dest->origin_x);
203   READ16(dest->origin_y);
204   READ16(dest->width);
205   READ16(dest->height);
206 
207   if (dest->width == 0 || dest->height == 0) BARF(TGAERR_ZERO_SIZE);
208 
209   READ(&dest->pixel_depth, 1);
210   if (!SANE_DEPTH(dest->pixel_depth) ||
211       (dest->pixel_depth != 8 && tga_is_colormapped(dest)))
212     BARF(TGAERR_PIXEL_DEPTH);
213 
214   READ(&dest->image_descriptor, 1);
215 
216   if (dest->image_id_length > 0) {
217     dest->image_id = (uint8_t *)malloc(dest->image_id_length);
218     if (dest->image_id == NULL) BARF(TGAERR_NO_MEM);
219     READ(dest->image_id, dest->image_id_length);
220   }
221 
222   if (dest->color_map_type == TGA_COLOR_MAP_PRESENT) {
223     dest->color_map_data =
224         (uint8_t *)malloc((dest->color_map_origin + dest->color_map_length) *
225                           dest->color_map_depth / 8);
226     if (dest->color_map_data == NULL) BARF(TGAERR_NO_MEM);
227     READ(dest->color_map_data +
228              (dest->color_map_origin * dest->color_map_depth / 8),
229          dest->color_map_length * dest->color_map_depth / 8);
230   }
231 
232   dest->image_data =
233       (uint8_t *)malloc(dest->width * dest->height * dest->pixel_depth / 8);
234   if (dest->image_data == NULL) BARF(TGAERR_NO_MEM);
235 
236   if (tga_is_rle(dest)) {
237     /* read RLE */
238     tga_result result = tga_read_rle(dest, fp);
239     if (result != TGA_NOERR) BARF(result);
240   } else {
241     /* uncompressed */
242     READ(dest->image_data, dest->width * dest->height * dest->pixel_depth / 8);
243   }
244 
245   return TGA_NOERR;
246 #undef BARF
247 #undef READ
248 #undef READ16
249 }
250 
251 /* ---------------------------------------------------------------------------
252  * Helper function for tga_read_from_FILE().  Decompresses RLE image data from
253  * <fp>.  Assumes <dest> header fields are set correctly.
254  */
tga_read_rle(tga_image * dest,FILE * fp)255 static tga_result tga_read_rle(tga_image *dest, FILE *fp) {
256 #define RLE_BIT BIT(7)
257 #define READ(dest, size)                                                       \
258   if (fread(dest, size, 1, fp) != 1) return TGAERR_EOF
259 
260   uint8_t *pos;
261   uint32_t p_loaded = 0, p_expected = dest->width * dest->height;
262   uint8_t bpp = dest->pixel_depth / 8; /* bytes per pixel */
263 
264   pos = dest->image_data;
265 
266   while ((p_loaded < p_expected) && !feof(fp)) {
267     uint8_t b;
268     READ(&b, 1);
269     if (b & RLE_BIT) {
270       /* is an RLE packet */
271       uint8_t count, tmp[4], i;
272 
273       count = (b & ~RLE_BIT) + 1;
274       READ(tmp, bpp);
275 
276       for (i = 0; i < count; i++) {
277         p_loaded++;
278         if (p_loaded > p_expected) return TGAERR_RLE;
279         memcpy(pos, tmp, bpp);
280         pos += bpp;
281       }
282     } else /* RAW packet */
283     {
284       uint8_t count;
285 
286       count = (b & ~RLE_BIT) + 1;
287       if (p_loaded + count > p_expected) return TGAERR_RLE;
288 
289       p_loaded += count;
290       READ(pos, bpp * count);
291       pos += count * bpp;
292     }
293   }
294   return TGA_NOERR;
295 #undef RLE_BIT
296 #undef READ
297 }
298 
299 /* ---------------------------------------------------------------------------
300  * Write a Targa image to a file named <filename> from <src>.  This is just a
301  * wrapper around tga_write_to_FILE().
302  *
303  * Returns: TGA_NOERR on success, or a matching TGAERR_* code on failure.
304  */
tga_write(const char * filename,const tga_image * src)305 tga_result tga_write(const char *filename, const tga_image *src) {
306   tga_result result;
307   FILE *fp = fopen(filename, "wb");
308   if (fp == NULL) return TGAERR_FOPEN;
309   result = tga_write_to_FILE(fp, src);
310   fclose(fp);
311   return result;
312 }
313 
314 /* ---------------------------------------------------------------------------
315  * Write one row of an image to <fp> using RLE.  This is a helper function
316  * called from tga_write_to_FILE().  It assumes that <src> has its header
317  * fields set up correctly.
318  */
319 #define PIXEL(ofs) (row + (ofs)*bpp)
tga_write_row_RLE(FILE * fp,const tga_image * src,const uint8_t * row)320 static tga_result tga_write_row_RLE(FILE *fp, const tga_image *src,
321                                     const uint8_t *row) {
322 #define WRITE(src, size)                                                       \
323   if (fwrite(src, size, 1, fp) != 1) return TGAERR_WRITE
324 
325   uint16_t pos = 0;
326   uint16_t bpp = src->pixel_depth / 8;
327 
328   while (pos < src->width) {
329     packet_type type = rle_packet_type(row, pos, src->width, bpp);
330     uint8_t len      = rle_packet_len(row, pos, src->width, bpp, type);
331     uint8_t packet_header;
332 
333     packet_header = len - 1;
334     if (type == RLE) packet_header |= BIT(7);
335 
336     WRITE(&packet_header, 1);
337     if (type == RLE) {
338       WRITE(PIXEL(pos), bpp);
339     } else /* type == RAW */
340     {
341       WRITE(PIXEL(pos), bpp * len);
342     }
343 
344     pos += len;
345   }
346 
347   return TGA_NOERR;
348 #undef WRITE
349 }
350 
351 /* ---------------------------------------------------------------------------
352  * Determine whether the next packet should be RAW or RLE for maximum
353  * efficiency.  This is a helper function called from rle_packet_len() and
354  * tga_write_row_RLE().
355  */
356 #define SAME(ofs1, ofs2) (memcmp(PIXEL(ofs1), PIXEL(ofs2), bpp) == 0)
357 
rle_packet_type(const uint8_t * row,const uint16_t pos,const uint16_t width,const uint16_t bpp)358 static packet_type rle_packet_type(const uint8_t *row, const uint16_t pos,
359                                    const uint16_t width, const uint16_t bpp) {
360   if (pos == width - 1) return RAW; /* one pixel */
361   if (SAME(pos, pos + 1))           /* dupe pixel */
362   {
363     if (bpp > 1) return RLE; /* inefficient for bpp=1 */
364 
365     /* three repeats makes the bpp=1 case efficient enough */
366     if ((pos < width - 2) && SAME(pos + 1, pos + 2)) return RLE;
367   }
368   return RAW;
369 }
370 
371 /* ---------------------------------------------------------------------------
372  * Find the length of the current RLE packet.  This is a helper function
373  * called from tga_write_row_RLE().
374  */
rle_packet_len(const uint8_t * row,const uint16_t pos,const uint16_t width,const uint16_t bpp,const packet_type type)375 static uint8_t rle_packet_len(const uint8_t *row, const uint16_t pos,
376                               const uint16_t width, const uint16_t bpp,
377                               const packet_type type) {
378   uint8_t len = 2;
379 
380   if (pos == width - 1) return 1;
381   if (pos == width - 2) return 2;
382 
383   if (type == RLE) {
384     while (pos + len < width) {
385       if (SAME(pos, pos + len))
386         len++;
387       else
388         return len;
389 
390       if (len == 128) return 128;
391     }
392   } else /* type == RAW */
393   {
394     while (pos + len < width) {
395       if (rle_packet_type(row, pos + len, width, bpp) == RAW)
396         len++;
397       else
398         return len;
399       if (len == 128) return 128;
400     }
401   }
402   return len; /* hit end of row (width) */
403 }
404 #undef SAME
405 #undef PIXEL
406 
407 /* ---------------------------------------------------------------------------
408  * Writes a Targa image to <fp> from <src>.
409  *
410  * Returns: TGA_NOERR on success, or a TGAERR_* code on failure.
411  *          On failure, the contents of the file are not guaranteed
412  *          to be valid.
413  */
tga_write_to_FILE(FILE * fp,const tga_image * src)414 tga_result tga_write_to_FILE(FILE *fp, const tga_image *src) {
415 #define WRITE(srcptr, size)                                                    \
416   if (fwrite(srcptr, size, 1, fp) != 1) return TGAERR_WRITE
417 
418 #define WRITE16(src)                                                           \
419   {                                                                            \
420     uint16_t _temp = htole16(src);                                             \
421     if (fwrite(&_temp, 2, 1, fp) != 1) return TGAERR_WRITE;                    \
422   }
423 
424   WRITE(&src->image_id_length, 1);
425 
426   if (src->color_map_type != TGA_COLOR_MAP_ABSENT &&
427       src->color_map_type != TGA_COLOR_MAP_PRESENT)
428     return TGAERR_CMAP_TYPE;
429   WRITE(&src->color_map_type, 1);
430 
431   if (src->image_type == TGA_IMAGE_TYPE_NONE) return TGAERR_NO_IMG;
432   if (src->image_type != TGA_IMAGE_TYPE_COLORMAP &&
433       src->image_type != TGA_IMAGE_TYPE_BGR &&
434       src->image_type != TGA_IMAGE_TYPE_MONO &&
435       src->image_type != TGA_IMAGE_TYPE_COLORMAP_RLE &&
436       src->image_type != TGA_IMAGE_TYPE_BGR_RLE &&
437       src->image_type != TGA_IMAGE_TYPE_MONO_RLE)
438     return TGAERR_IMG_TYPE;
439   WRITE(&src->image_type, 1);
440 
441   if (tga_is_colormapped(src) && src->color_map_type == TGA_COLOR_MAP_ABSENT)
442     return TGAERR_CMAP_MISSING;
443   if (!tga_is_colormapped(src) && src->color_map_type == TGA_COLOR_MAP_PRESENT)
444     return TGAERR_CMAP_PRESENT;
445   if (src->color_map_type == TGA_COLOR_MAP_PRESENT) {
446     if (src->color_map_length == 0) return TGAERR_CMAP_LENGTH;
447 
448     if (!UNMAP_DEPTH(src->color_map_depth)) return TGAERR_CMAP_DEPTH;
449   }
450   WRITE16(src->color_map_origin);
451   WRITE16(src->color_map_length);
452   WRITE(&src->color_map_depth, 1);
453 
454   WRITE16(src->origin_x);
455   WRITE16(src->origin_y);
456 
457   if (src->width == 0 || src->height == 0) return TGAERR_ZERO_SIZE;
458   WRITE16(src->width);
459   WRITE16(src->height);
460 
461   if (!SANE_DEPTH(src->pixel_depth) ||
462       (src->pixel_depth != 8 && tga_is_colormapped(src)))
463     return TGAERR_PIXEL_DEPTH;
464   WRITE(&src->pixel_depth, 1);
465 
466   WRITE(&src->image_descriptor, 1);
467 
468   if (src->image_id_length > 0) WRITE(&src->image_id, src->image_id_length);
469 
470   if (src->color_map_type == TGA_COLOR_MAP_PRESENT)
471     WRITE(src->color_map_data +
472               (src->color_map_origin * src->color_map_depth / 8),
473           src->color_map_length * src->color_map_depth / 8);
474 
475   if (tga_is_rle(src)) {
476     uint16_t row;
477     for (row = 0; row < src->height; row++) {
478       tga_result result = tga_write_row_RLE(
479           fp, src, src->image_data + row * src->width * src->pixel_depth / 8);
480       if (result != TGA_NOERR) return result;
481     }
482   } else {
483     /* uncompressed */
484     WRITE(src->image_data, src->width * src->height * src->pixel_depth / 8);
485   }
486 
487   WRITE(tga_id, tga_id_length);
488 
489   return TGA_NOERR;
490 #undef WRITE
491 #undef WRITE16
492 }
493 
494 /* Convenient writing functions --------------------------------------------*/
495 
496 /*
497  * This is just a helper function to initialise the header fields in a
498  * tga_image struct.
499  */
init_tga_image(tga_image * img,uint8_t * image,const uint16_t width,const uint16_t height,const uint8_t depth)500 static void init_tga_image(tga_image *img, uint8_t *image, const uint16_t width,
501                            const uint16_t height, const uint8_t depth) {
502   img->image_id_length  = 0;
503   img->color_map_type   = TGA_COLOR_MAP_ABSENT;
504   img->image_type       = TGA_IMAGE_TYPE_NONE; /* override this below! */
505   img->color_map_origin = 0;
506   img->color_map_length = 0;
507   img->color_map_depth  = 0;
508   img->origin_x         = 0;
509   img->origin_y         = 0;
510   img->width            = width;
511   img->height           = height;
512   img->pixel_depth      = depth;
513   img->image_descriptor = TGA_T_TO_B_BIT;
514   img->image_id         = NULL;
515   img->color_map_data   = NULL;
516   img->image_data       = image;
517 }
518 
tga_write_mono(const char * filename,uint8_t * image,const uint16_t width,const uint16_t height)519 tga_result tga_write_mono(const char *filename, uint8_t *image,
520                           const uint16_t width, const uint16_t height) {
521   tga_image img;
522   init_tga_image(&img, image, width, height, 8);
523   img.image_type = TGA_IMAGE_TYPE_MONO;
524   return tga_write(filename, &img);
525 }
526 
tga_write_mono_rle(const char * filename,uint8_t * image,const uint16_t width,const uint16_t height)527 tga_result tga_write_mono_rle(const char *filename, uint8_t *image,
528                               const uint16_t width, const uint16_t height) {
529   tga_image img;
530   init_tga_image(&img, image, width, height, 8);
531   img.image_type = TGA_IMAGE_TYPE_MONO_RLE;
532   return tga_write(filename, &img);
533 }
534 
tga_write_bgr(const char * filename,uint8_t * image,const uint16_t width,const uint16_t height,const uint8_t depth)535 tga_result tga_write_bgr(const char *filename, uint8_t *image,
536                          const uint16_t width, const uint16_t height,
537                          const uint8_t depth) {
538   tga_image img;
539   init_tga_image(&img, image, width, height, depth);
540   img.image_type = TGA_IMAGE_TYPE_BGR;
541   return tga_write(filename, &img);
542 }
543 
tga_write_bgr_rle(const char * filename,uint8_t * image,const uint16_t width,const uint16_t height,const uint8_t depth)544 tga_result tga_write_bgr_rle(const char *filename, uint8_t *image,
545                              const uint16_t width, const uint16_t height,
546                              const uint8_t depth) {
547   tga_image img;
548   init_tga_image(&img, image, width, height, depth);
549   img.image_type = TGA_IMAGE_TYPE_BGR_RLE;
550   return tga_write(filename, &img);
551 }
552 
553 /* Note: this function will MODIFY <image> */
tga_write_rgb(const char * filename,uint8_t * image,const uint16_t width,const uint16_t height,const uint8_t depth)554 tga_result tga_write_rgb(const char *filename, uint8_t *image,
555                          const uint16_t width, const uint16_t height,
556                          const uint8_t depth) {
557   tga_image img;
558   init_tga_image(&img, image, width, height, depth);
559   img.image_type = TGA_IMAGE_TYPE_BGR;
560   (void)tga_swap_red_blue(&img);
561   return tga_write(filename, &img);
562 }
563 
564 /* Note: this function will MODIFY <image> */
tga_write_rgb_rle(const char * filename,uint8_t * image,const uint16_t width,const uint16_t height,const uint8_t depth)565 tga_result tga_write_rgb_rle(const char *filename, uint8_t *image,
566                              const uint16_t width, const uint16_t height,
567                              const uint8_t depth) {
568   tga_image img;
569   init_tga_image(&img, image, width, height, depth);
570   img.image_type = TGA_IMAGE_TYPE_BGR_RLE;
571   (void)tga_swap_red_blue(&img);
572   return tga_write(filename, &img);
573 }
574 
575 /* Convenient manipulation functions ---------------------------------------*/
576 
577 /* ---------------------------------------------------------------------------
578  * Horizontally flip the image in place.  Reverses the right-to-left bit in
579  * the image descriptor.
580  */
tga_flip_horiz(tga_image * img)581 tga_result tga_flip_horiz(tga_image *img) {
582   uint16_t row;
583   size_t bpp;
584   uint8_t *left, *right;
585   int r_to_l;
586 
587   if (!SANE_DEPTH(img->pixel_depth)) return TGAERR_PIXEL_DEPTH;
588   bpp = (size_t)(img->pixel_depth / 8); /* bytes per pixel */
589 
590   for (row = 0; row < img->height; row++) {
591     left  = img->image_data + row * img->width * bpp;
592     right = left + (img->width - 1) * bpp;
593 
594     /* reverse from left to right */
595     while (left < right) {
596       uint8_t buffer[4];
597 
598       /* swap */
599       memcpy(buffer, left, bpp);
600       memcpy(left, right, bpp);
601       memcpy(right, buffer, bpp);
602 
603       left += bpp;
604       right -= bpp;
605     }
606   }
607 
608   /* Correct image_descriptor's left-to-right-ness. */
609   r_to_l = tga_is_right_to_left(img);
610   img->image_descriptor &= ~TGA_R_TO_L_BIT; /* mask out r-to-l bit */
611   if (!r_to_l)                              /* was l-to-r, need to set r_to_l */
612     img->image_descriptor |= TGA_R_TO_L_BIT;
613   /* else bit is already rubbed out */
614 
615   return TGA_NOERR;
616 }
617 
618 /* ---------------------------------------------------------------------------
619  * Vertically flip the image in place.  Reverses the top-to-bottom bit in
620  * the image descriptor.
621  */
tga_flip_vert(tga_image * img)622 tga_result tga_flip_vert(tga_image *img) {
623   uint16_t col;
624   size_t bpp, line;
625   uint8_t *top, *bottom;
626   int t_to_b;
627 
628   if (!SANE_DEPTH(img->pixel_depth)) return TGAERR_PIXEL_DEPTH;
629   bpp  = (size_t)(img->pixel_depth / 8); /* bytes per pixel */
630   line = bpp * img->width;               /* bytes per line */
631 
632   for (col = 0; col < img->width; col++) {
633     top    = img->image_data + col * bpp;
634     bottom = top + (img->height - 1) * line;
635 
636     /* reverse from top to bottom */
637     while (top < bottom) {
638       uint8_t buffer[4];
639 
640       /* swap */
641       memcpy(buffer, top, bpp);
642       memcpy(top, bottom, bpp);
643       memcpy(bottom, buffer, bpp);
644 
645       top += line;
646       bottom -= line;
647     }
648   }
649 
650   /* Correct image_descriptor's top-to-bottom-ness. */
651   t_to_b = tga_is_top_to_bottom(img);
652   img->image_descriptor &= ~TGA_T_TO_B_BIT; /* mask out t-to-b bit */
653   if (!t_to_b)                              /* was b-to-t, need to set t_to_b */
654     img->image_descriptor |= TGA_T_TO_B_BIT;
655   /* else bit is already rubbed out */
656 
657   return TGA_NOERR;
658 }
659 
660 /* ---------------------------------------------------------------------------
661  * Convert a color-mapped image to unmapped BGR.  Reallocates image_data to a
662  * bigger size, then converts the image backwards to avoid using a secondary
663  * buffer.  Alters the necessary header fields and deallocates the color map.
664  */
tga_color_unmap(tga_image * img)665 tga_result tga_color_unmap(tga_image *img) {
666   uint8_t bpp = img->color_map_depth / 8; /* bytes per pixel */
667   int pos;
668   void *tmp;
669 
670   if (!tga_is_colormapped(img)) return TGAERR_NOT_CMAP;
671   if (img->pixel_depth != 8) return TGAERR_PIXEL_DEPTH;
672   if (!SANE_DEPTH(img->color_map_depth)) return TGAERR_CMAP_DEPTH;
673 
674   tmp = realloc(img->image_data, img->width * img->height * bpp);
675   if (tmp == NULL) return TGAERR_NO_MEM;
676   img->image_data = (uint8_t *)tmp;
677 
678   for (pos = img->width * img->height - 1; pos >= 0; pos--) {
679     uint8_t c_index = img->image_data[pos];
680     uint8_t *c_bgr  = img->color_map_data + (c_index * bpp);
681 
682     if (c_index >= img->color_map_origin + img->color_map_length)
683       return TGAERR_INDEX_RANGE;
684 
685     memcpy(img->image_data + (pos * bpp), c_bgr, (size_t)bpp);
686   }
687 
688   /* clean up */
689   img->image_type  = TGA_IMAGE_TYPE_BGR;
690   img->pixel_depth = img->color_map_depth;
691 
692   free(img->color_map_data);
693   img->color_map_data   = NULL;
694   img->color_map_type   = TGA_COLOR_MAP_ABSENT;
695   img->color_map_origin = 0;
696   img->color_map_length = 0;
697   img->color_map_depth  = 0;
698 
699   return TGA_NOERR;
700 }
701 
702 /* ---------------------------------------------------------------------------
703  * Return a pointer to a given pixel.  Accounts for image orientation (T_TO_B,
704  * R_TO_L, etc).  Returns NULL if the pixel is out of range.
705  */
tga_find_pixel(const tga_image * img,uint16_t x,uint16_t y)706 uint8_t *tga_find_pixel(const tga_image *img, uint16_t x, uint16_t y) {
707   if (x >= img->width || y >= img->height) return NULL;
708 
709   if (!tga_is_top_to_bottom(img)) y = img->height - 1 - y;
710   if (tga_is_right_to_left(img)) x  = img->width - 1 - x;
711   return img->image_data + (x + y * img->width) * img->pixel_depth / 8;
712 }
713 
714 /* ---------------------------------------------------------------------------
715  * Unpack the pixel at the src pointer according to bits.  Any of b,g,r,a can
716  * be set to NULL if not wanted.  Returns TGAERR_PIXEL_DEPTH if a stupid
717  * number of bits is given.
718  */
tga_unpack_pixel(const uint8_t * src,const uint8_t bits,uint8_t * b,uint8_t * g,uint8_t * r,uint8_t * a)719 tga_result tga_unpack_pixel(const uint8_t *src, const uint8_t bits, uint8_t *b,
720                             uint8_t *g, uint8_t *r, uint8_t *a) {
721   switch (bits) {
722   case 32:
723     if (b) *b = src[0];
724     if (g) *g = src[1];
725     if (r) *r = src[2];
726     if (a) *a = src[3];
727     break;
728 
729   case 24:
730     if (b) *b = src[0];
731     if (g) *g = src[1];
732     if (r) *r = src[2];
733     if (a) *a = 0;
734     break;
735 
736   case 16: {
737     uint16_t src16 = (uint16_t)(src[1] << 8) | (uint16_t)src[0];
738 
739 #define FIVE_BITS (BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4))
740     if (b) *b = ((src16)&FIVE_BITS) << 3;
741     if (g) *g = ((src16 >> 5) & FIVE_BITS) << 3;
742     if (r) *r = ((src16 >> 10) & FIVE_BITS) << 3;
743     if (a) *a = (uint8_t)((src16 & BIT(15)) ? 255 : 0);
744 #undef FIVE_BITS
745     break;
746   }
747 
748   case 8:
749     if (b) *b = *src;
750     if (g) *g = *src;
751     if (r) *r = *src;
752     if (a) *a = 0;
753     break;
754 
755   default:
756     return TGAERR_PIXEL_DEPTH;
757   }
758   return TGA_NOERR;
759 }
760 
761 /* ---------------------------------------------------------------------------
762  * Pack the pixel at the dest pointer according to bits.  Returns
763  * TGAERR_PIXEL_DEPTH if a stupid number of bits is given.
764  */
tga_pack_pixel(uint8_t * dest,const uint8_t bits,const uint8_t b,const uint8_t g,const uint8_t r,const uint8_t a)765 tga_result tga_pack_pixel(uint8_t *dest, const uint8_t bits, const uint8_t b,
766                           const uint8_t g, const uint8_t r, const uint8_t a) {
767   switch (bits) {
768   case 32:
769     dest[0] = b;
770     dest[1] = g;
771     dest[2] = r;
772     dest[3] = a;
773     break;
774 
775   case 24:
776     dest[0] = b;
777     dest[1] = g;
778     dest[2] = r;
779     break;
780 
781   case 16: {
782     uint16_t tmp;
783 
784 #define FIVE_BITS (BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4))
785     tmp = (b >> 3) & FIVE_BITS;
786     tmp |= ((g >> 3) & FIVE_BITS) << 5;
787     tmp |= ((r >> 3) & FIVE_BITS) << 10;
788     if (a > 127) tmp |= BIT(15);
789 #undef FIVE_BITS
790 
791     dest[0] = (uint8_t)(tmp & 0x00FF);
792     dest[1] = (uint8_t)((tmp & 0xFF00) >> 8);
793     break;
794   }
795 
796   default:
797     return TGAERR_PIXEL_DEPTH;
798   }
799   return TGA_NOERR;
800 }
801 
802 /* ---------------------------------------------------------------------------
803  * Desaturate the specified Targa using the specified coefficients:
804  *      output = ( red * cr + green * cg + blue * cb ) / dv
805  */
tga_desaturate(tga_image * img,const int cr,const int cg,const int cb,const int dv)806 tga_result tga_desaturate(tga_image *img, const int cr, const int cg,
807                           const int cb, const int dv) {
808   uint8_t bpp = img->pixel_depth / 8; /* bytes per pixel */
809   uint8_t *dest, *src, *tmp;
810 
811   if (tga_is_mono(img)) return TGAERR_MONO;
812   if (tga_is_colormapped(img)) {
813     tga_result result = tga_color_unmap(img);
814     if (result != TGA_NOERR) return result;
815   }
816   if (!UNMAP_DEPTH(img->pixel_depth)) return TGAERR_PIXEL_DEPTH;
817 
818   dest = img->image_data;
819   for (src = img->image_data;
820        src < img->image_data + img->width * img->height * bpp; src += bpp) {
821     uint8_t b, g, r;
822     (void)tga_unpack_pixel(src, img->pixel_depth, &b, &g, &r, NULL);
823 
824     *dest = (uint8_t)(((int)b * cb + (int)g * cg + (int)r * cr) / dv);
825     dest++;
826   }
827 
828   /* shrink */
829   tmp = realloc(img->image_data, img->width * img->height);
830   if (tmp == NULL) return TGAERR_NO_MEM;
831   img->image_data = tmp;
832 
833   img->pixel_depth = 8;
834   img->image_type  = TGA_IMAGE_TYPE_MONO;
835   return TGA_NOERR;
836 }
837 
tga_desaturate_rec_601_1(tga_image * img)838 tga_result tga_desaturate_rec_601_1(tga_image *img) {
839   return tga_desaturate(img, 2989, 5866, 1145, 10000);
840 }
841 
tga_desaturate_rec_709(tga_image * img)842 tga_result tga_desaturate_rec_709(tga_image *img) {
843   return tga_desaturate(img, 2126, 7152, 722, 10000);
844 }
845 
tga_desaturate_itu(tga_image * img)846 tga_result tga_desaturate_itu(tga_image *img) {
847   return tga_desaturate(img, 2220, 7067, 713, 10000);
848 }
849 
tga_desaturate_avg(tga_image * img)850 tga_result tga_desaturate_avg(tga_image *img) {
851   return tga_desaturate(img, 1, 1, 1, 3);
852 }
853 
854 /* ---------------------------------------------------------------------------
855  * Convert an image to the given pixel depth. (one of 32, 24, 16)  Avoids
856  * using a secondary buffer to do the conversion.
857  */
tga_convert_depth(tga_image * img,const uint8_t bits)858 tga_result tga_convert_depth(tga_image *img, const uint8_t bits) {
859   size_t src_size, dest_size;
860   uint8_t src_bpp, dest_bpp;
861   uint8_t *src, *dest;
862 
863   if (!UNMAP_DEPTH(bits) || !SANE_DEPTH(img->pixel_depth))
864     return TGAERR_PIXEL_DEPTH;
865 
866   if (tga_is_colormapped(img)) {
867     tga_result result = tga_color_unmap(img);
868     if (result != TGA_NOERR) return result;
869   }
870 
871   if (img->pixel_depth == bits) return TGA_NOERR; /* no op, no err */
872 
873   src_bpp  = img->pixel_depth / 8;
874   dest_bpp = bits / 8;
875 
876   src_size  = (size_t)(img->width * img->height * src_bpp);
877   dest_size = (size_t)(img->width * img->height * dest_bpp);
878 
879   if (src_size > dest_size) {
880     void *tmp;
881 
882     /* convert forwards */
883     dest = img->image_data;
884     for (src = img->image_data;
885          src < img->image_data + img->width * img->height * src_bpp;
886          src += src_bpp) {
887       uint8_t r, g, b, a;
888       (void)tga_unpack_pixel(src, img->pixel_depth, &r, &g, &b, &a);
889       (void)tga_pack_pixel(dest, bits, r, g, b, a);
890       dest += dest_bpp;
891     }
892 
893     /* shrink */
894     tmp = realloc(img->image_data, img->width * img->height * dest_bpp);
895     if (tmp == NULL) return TGAERR_NO_MEM;
896     img->image_data = tmp;
897   } else {
898     /* expand */
899     void *tmp = realloc(img->image_data, img->width * img->height * dest_bpp);
900     if (tmp == NULL) return TGAERR_NO_MEM;
901     img->image_data = (uint8_t *)tmp;
902 
903     /* convert backwards */
904     dest = img->image_data + (img->width * img->height - 1) * dest_bpp;
905     for (src = img->image_data + (img->width * img->height - 1) * src_bpp;
906          src >= img->image_data; src -= src_bpp) {
907       uint8_t r, g, b, a;
908       (void)tga_unpack_pixel(src, img->pixel_depth, &r, &g, &b, &a);
909       (void)tga_pack_pixel(dest, bits, r, g, b, a);
910       dest -= dest_bpp;
911     }
912   }
913 
914   img->pixel_depth = bits;
915   return TGA_NOERR;
916 }
917 
918 /* ---------------------------------------------------------------------------
919  * Swap red and blue (RGB becomes BGR and vice verse).  (in-place)
920  */
tga_swap_red_blue(tga_image * img)921 tga_result tga_swap_red_blue(tga_image *img) {
922   uint8_t *ptr;
923   uint8_t bpp = img->pixel_depth / 8;
924 
925   if (!UNMAP_DEPTH(img->pixel_depth)) return TGAERR_PIXEL_DEPTH;
926 
927   for (ptr = img->image_data;
928        ptr < img->image_data + (img->width * img->height - 1) * bpp;
929        ptr += bpp) {
930     uint8_t r, g, b, a;
931     (void)tga_unpack_pixel(ptr, img->pixel_depth, &b, &g, &r, &a);
932     (void)tga_pack_pixel(ptr, img->pixel_depth, r, g, b, a);
933   }
934   return TGA_NOERR;
935 }
936 
937 /* ---------------------------------------------------------------------------
938  * Free the image_id, color_map_data and image_data buffers of the specified
939  * tga_image, if they're not already NULL.
940  */
tga_free_buffers(tga_image * img)941 void tga_free_buffers(tga_image *img) {
942   if (img->image_id != NULL) {
943     free(img->image_id);
944     img->image_id = NULL;
945   }
946   if (img->color_map_data != NULL) {
947     free(img->color_map_data);
948     img->color_map_data = NULL;
949   }
950   if (img->image_data != NULL) {
951     free(img->image_data);
952     img->image_data = NULL;
953   }
954 }
955 
956 /* vim:set tabstop=4 shiftwidth=4 textwidth=78 expandtab: */
957