]> git.imager.perl.org - imager.git/blobdiff - tga.c
add flood fill test image
[imager.git] / tga.c
diff --git a/tga.c b/tga.c
index bd574187bf1c6309e3feec81c9fc76301f2003c6..96e1f9444ce2817cf5e4c7c40d464fdcf70e5a82 100644 (file)
--- a/tga.c
+++ b/tga.c
@@ -1,5 +1,4 @@
-#include "image.h"
-#include "io.h"
+#include "imageri.h"
 #include "log.h"
 #include "iolayer.h"
 
@@ -39,7 +38,7 @@ Some of these functions are internal.
 
 
 typedef struct {
-  char  idlength;
+  unsigned char  idlength;
   char  colourmaptype;
   char  datatypecode;
   short int colourmaporigin;
@@ -108,27 +107,31 @@ bpp_to_bytes(unsigned int bpp) {
 /*
 =item bpp_to_channels(bpp)
 
-Convert bits per pixel into channels in the image
+Convert bits per pixel and the number of attribute bits into channels
+in the image
 
    bpp - bits per pixel
+   attr_bit_count - number of attribute bits
 
 =cut
 */
 
 static
 int
-bpp_to_channels(unsigned int bpp) {
+bpp_to_channels(unsigned int bpp, int attr_bit_count) {
   switch (bpp) {
   case 8:
     return 1;
+  case 16:
+    if (attr_bit_count == 1)
+      return 4;
   case 15:
     return 3;
-  case 16:
-    return 4;
+  case 32:
+    if (attr_bit_count == 8)
+      return 4;
   case 24:
     return 3;
-  case 32:
-    return 4;
   }
   return 0;
 }
@@ -168,7 +171,7 @@ color_unpack(unsigned char *buf, int bytepp, i_color *val) {
     val->rgba.r = (buf[1] & 0x7c) << 1;
     val->rgba.g = ((buf[1] & 0x03) << 6) | ((buf[0] & 0xe0) >> 2);
     val->rgba.b = (buf[0] & 0x1f) << 3;
-    val->rgba.a = (buf[1] & 0x80) ? 255 : 0;
+    val->rgba.a = (buf[1] & 0x80) ? 0 : 255;
     val->rgba.r |= val->rgba.r >> 5;
     val->rgba.g |= val->rgba.g >> 5;
     val->rgba.b |= val->rgba.b >> 5;
@@ -212,13 +215,18 @@ color_pack(unsigned char *buf, int bitspp, i_color *val) {
   case 8:
     buf[0] = val->gray.gray_color;
     break;
+  case 16:
+    buf[0]  = (val->rgba.b >> 3);
+    buf[0] |= (val->rgba.g & 0x38) << 2;
+    buf[1]  = (val->rgba.r & 0xf8)>> 1;
+    buf[1] |= (val->rgba.g >> 6);
+    buf[1] |=  val->rgba.a > 0x7f ? 0 : 0x80;
+    break;
   case 15:
     buf[0]  = (val->rgba.b >> 3);
     buf[0] |= (val->rgba.g & 0x38) << 2;
     buf[1]  = (val->rgba.r & 0xf8)>> 1;
     buf[1] |= (val->rgba.g >> 6);
-  case 16:
-    buf[1] |=  val->rgba.a & 0x80;
     break;
   case 24:
     buf[0] = val->rgb.b;
@@ -321,6 +329,57 @@ tga_header_unpack(tga_header *header, unsigned char headbuf[18]) {
 }
 
 
+/* this function should never produce diagnostics to stdout, maybe to the logfile */
+int
+tga_header_verify(unsigned char headbuf[18]) {
+  tga_header header;
+  tga_header_unpack(&header, headbuf);
+  switch (header.datatypecode) { 
+  default:
+    /*printf("bad typecode!\n");*/
+    return 0;
+  case 1:  /* Uncompressed, color-mapped images */ 
+  case 3:  /* Uncompressed, grayscale images    */ 
+  case 9:  /* Compressed,   color-mapped images */ 
+  case 11: /* Compressed,   grayscale images    */ 
+    if (header.bitsperpixel != 8)
+      return 0;
+    break;
+  case 0:
+  case 2:  /* Uncompressed, rgb images          */ 
+  case 10: /* Compressed,   rgb images          */ 
+    if (header.bitsperpixel != 15 && header.bitsperpixel != 16
+       && header.bitsperpixel != 24 && header.bitsperpixel != 32)
+      return 0;
+    break;
+       }
+
+  switch (header.colourmaptype) { 
+  default:
+    /*printf("bad colourmaptype!\n");*/
+    return 0;
+  case 1:
+    if (header.datatypecode != 1 && header.datatypecode != 9)
+      return 0; /* only get a color map on a color mapped image */
+  case 0:
+       break;
+       }
+
+  switch (header.colourmapdepth) {
+  default:
+    return 0;
+  case 0: /* can be 0 if no colour map */
+  case 15:
+  case 16:
+  case 24:
+  case 32:
+    break;
+  }
+  
+  return 1;
+}
+
+
 /*
 =item tga_header_pack(header, headbuf)
 
@@ -388,9 +447,11 @@ tga_source_read(tga_source *s, unsigned char *buf, size_t pixels) {
       s->len = (s->hdr &~(1<<7))+1;
       s->state = (s->hdr & (1<<7)) ? Rle : Raw;
       {
+/*
        static cnt = 0;
        printf("%04d %s: %d\n", cnt++, s->state==Rle?"RLE":"RAW", s->len);
-      }
+ */
+     }
       if (s->state == Rle && s->ig->readcb(s->ig, s->cval, s->bytepp) != s->bytepp) return 0;
 
       break;
@@ -431,7 +492,7 @@ destination is compressed.
 static
 int
 tga_dest_write(tga_dest *s, unsigned char *buf, size_t pixels) {
-  int cp = 0, j, k;
+  int cp = 0;
 
   if (!s->compressed) {
     if (s->ig->writecb(s->ig, buf, pixels*s->bytepp) != pixels*s->bytepp) return 0;
@@ -565,7 +626,7 @@ Returns NULL on error.
 i_img *
 i_readtga_wiol(io_glue *ig, int length) {
   i_img* img = NULL;
-  int x, y, i;
+  int x, y;
   int width, height, channels;
   int mapped;
   char *idstring = NULL;
@@ -574,7 +635,6 @@ i_readtga_wiol(io_glue *ig, int length) {
   tga_header header;
   unsigned char headbuf[18];
   unsigned char *databuf;
-  unsigned char *reorderbuf;
 
   i_color *linebuf = NULL;
   i_clear_error();
@@ -613,6 +673,7 @@ i_readtga_wiol(io_glue *ig, int length) {
 
   width = header.width;
   height = header.height;
+
   
   /* Set tags here */
   
@@ -663,7 +724,6 @@ i_readtga_wiol(io_glue *ig, int length) {
   
   mapped = 1;
   switch (header.datatypecode) {
-    int tbpp;
   case 2:  /* Uncompressed, rgb images          */
   case 10: /* Compressed,   rgb images          */
     mapped = 0;
@@ -671,7 +731,8 @@ i_readtga_wiol(io_glue *ig, int length) {
   case 9:  /* Compressed,   color-mapped images */
     if ((channels = bpp_to_channels(mapped ? 
                                   header.colourmapdepth : 
-                                  header.bitsperpixel))) break;
+                                  header.bitsperpixel,
+                                   header.imagedescriptor & 0xF))) break;
     i_push_error(0, "Targa Image has none of 15/16/24/32 pixel layout");
     if (idstring) myfree(idstring);
     return NULL;
@@ -681,11 +742,26 @@ i_readtga_wiol(io_glue *ig, int length) {
     mapped = 0;
     channels = 1;
     break;
+  default:
+    i_push_error(0, "invalid or unsupported datatype code");
+    return NULL;
+  }
+
+  if (!i_int_check_image_file_limits(width, height, channels, 
+                                    sizeof(i_sample_t))) {
+    mm_log((1, "i_readtga_wiol: image size exceeds limits\n"));
+    return NULL;
   }
   
   img = mapped ? 
     i_img_pal_new(width, height, channels, 256) :
     i_img_empty_ch(NULL, width, height, channels);
+
+  if (!img) {
+    if (idstring) 
+      myfree(idstring);
+    return NULL;
+  }
   
   if (idstring) {
     i_tags_add(&img->tags, "tga_idstring", 0, idstring, header.idlength, 0);
@@ -711,6 +787,7 @@ i_readtga_wiol(io_glue *ig, int length) {
   for(y=0; y<height; y++) {
     if (!tga_source_read(&src, databuf, width)) {
       i_push_error(errno, "read for targa data failed");
+      if (linebuf) myfree(linebuf);
       myfree(databuf);
       if (img) i_img_destroy(img);
       return NULL;
@@ -725,6 +802,7 @@ i_readtga_wiol(io_glue *ig, int length) {
   myfree(databuf);
   if (linebuf) myfree(linebuf);
   
+  i_tags_add(&img->tags, "i_format", 0, "tga", -1, 0);
   i_tags_addn(&img->tags, "tga_bitspp", 0, mapped?header.colourmapdepth:header.bitsperpixel);
   if (src.compressed) i_tags_addn(&img->tags, "compressed", 0, 1);
   return img;
@@ -745,11 +823,11 @@ Writes an image in targa format.  Returns 0 on error.
 
 undef_int
 i_writetga_wiol(i_img *img, io_glue *ig, int wierdpack, int compress, char *idstring, size_t idlen) {
-  static int rgb_chan[] = { 2, 1, 0, 3 };
   tga_header header;
   tga_dest dest;
   unsigned char headbuf[18];
   unsigned int bitspp;
+  unsigned int attr_bits = 0;
   
   int mapped;
 
@@ -770,7 +848,8 @@ i_writetga_wiol(i_img *img, io_glue *ig, int wierdpack, int compress, char *idst
   mm_log((1, "channels %d\n", img->channels));
   
   i_clear_error();
-  
+  io_glue_commit_types(ig);
+
   switch (img->channels) {
   case 1:
     bitspp = 8;
@@ -788,15 +867,13 @@ i_writetga_wiol(i_img *img, io_glue *ig, int wierdpack, int compress, char *idst
     break;
   case 4:
     bitspp = wierdpack ? 16 : 32;
+    attr_bits = wierdpack ? 1 : 8;
     break;
   default:
     i_push_error(0, "Targa only handles 1,3 and 4 channel images.");
     return 0;
   }
 
-  io_glue_commit_types(ig);
-  
-  header.idlength;
   header.idlength = idlen;
   header.colourmaptype   = mapped ? 1 : 0;
   header.datatypecode    = mapped ? 1 : img->channels == 1 ? 3 : 2;
@@ -810,7 +887,7 @@ i_writetga_wiol(i_img *img, io_glue *ig, int wierdpack, int compress, char *idst
   header.width           = img->xsize;
   header.height          = img->ysize;
   header.bitsperpixel    = mapped ? 8 : bitspp;
-  header.imagedescriptor = (1<<5); /* normal order instead of upside down */
+  header.imagedescriptor = (1<<5) | attr_bits; /* normal order instead of upside down */
 
   tga_header_pack(&header, headbuf);
 
@@ -835,8 +912,6 @@ i_writetga_wiol(i_img *img, io_glue *ig, int wierdpack, int compress, char *idst
   mm_log((1, "dest.bytepp = %d\n", dest.bytepp));
 
   if (img->type == i_palette_type) {
-    int i;
-    int bytepp = bpp_to_bytes(bitspp);
     if (!tga_palette_write(ig, img, bitspp, i_colorcount(img))) return 0;
     
     if (!img->virtual && !dest.compressed) {