]> git.imager.perl.org - imager.git/blobdiff - tga.c
- converted t/t022double.t to use Test::More
[imager.git] / tga.c
diff --git a/tga.c b/tga.c
index a1c0c33a9a3dddeae593de9835ccdcc43a1d6e65..2e373534c02698e723e78250ba6ea965cbabf602 100644 (file)
--- a/tga.c
+++ b/tga.c
@@ -1,5 +1,4 @@
-#include "image.h"
-#include "io.h"
+#include "imagei.h"
 #include "log.h"
 #include "iolayer.h"
 
@@ -30,7 +29,7 @@ entire memory mapped buffer.
 
 Some of these functions are internal.
 
-=over 4
+=over
 
 =cut
 */
@@ -39,7 +38,7 @@ Some of these functions are internal.
 
 
 typedef struct {
-  char  idlength;
+  unsigned char  idlength;
   char  colourmaptype;
   char  datatypecode;
   short int colourmaporigin;
@@ -184,7 +183,6 @@ color_unpack(unsigned char *buf, int bytepp, i_color *val) {
     val->rgba.r = buf[2];
     val->rgba.a = buf[3];
     break;
-  default:
   }
 }
 
@@ -232,7 +230,6 @@ color_pack(unsigned char *buf, int bitspp, i_color *val) {
     buf[2] = val->rgba.r;
     buf[3] = val->rgba.a;
     break;
-  default:
   }
 }
 
@@ -323,6 +320,38 @@ 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 0:
+  case 1:  /* Uncompressed, color-mapped images */ 
+  case 2:  /* Uncompressed, rgb images          */ 
+  case 3:  /* Uncompressed, grayscale images    */ 
+  case 9:  /* Compressed,   color-mapped images */ 
+  case 10: /* Compressed,   rgb images          */ 
+  case 11: /* Compressed,   grayscale images    */ 
+         break;
+       }
+
+  switch (header.colourmaptype) { 
+  default:
+    /*printf("bad colourmaptype!\n");*/
+    return 0;
+  case 0:
+  case 1:
+       break;
+       }
+  
+  return 1;
+}
+
+
 /*
 =item tga_header_pack(header, headbuf)
 
@@ -389,19 +418,24 @@ 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;
     case Rle:
-      ml = min(s->len, pixels-cp);
+      ml = i_min(s->len, pixels-cp);
       for(k=0; k<ml; k++) for(j=0; j<s->bytepp; j++) 
        buf[(cp+k)*s->bytepp+j] = s->cval[j];
-      //      memset(buf+cp, s->cidx, ml);
       cp     += ml;
       s->len -= ml;
       break;
     case Raw:
-      ml = min(s->len, pixels-cp);
+      ml = i_min(s->len, pixels-cp);
       if (s->ig->readcb(s->ig, buf+cp*s->bytepp, ml*s->bytepp) != ml*s->bytepp) return 0;
       cp     += ml;
       s->len -= ml;
@@ -430,7 +464,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;
@@ -442,7 +476,7 @@ tga_dest_write(tga_dest *s, unsigned char *buf, size_t pixels) {
     int nxtrip = find_repeat(buf+cp*s->bytepp, pixels-cp, s->bytepp);
     tlen = (nxtrip == -1) ? pixels-cp : nxtrip;
     while(tlen) {
-      int clen = (tlen>128) ? 128 : tlen;
+      unsigned char clen = (tlen>128) ? 128 : tlen;
       clen--;
       if (s->ig->writecb(s->ig, &clen, 1) != 1) return 0;
       clen++;
@@ -452,8 +486,9 @@ tga_dest_write(tga_dest *s, unsigned char *buf, size_t pixels) {
     }
     if (cp >= pixels) break;
     tlen = find_span(buf+cp*s->bytepp, pixels-cp, s->bytepp);
+    if (tlen <3) continue;
     while (tlen) {
-      int clen = (tlen>128) ? 128 : tlen;
+      unsigned char clen = (tlen>128) ? 128 : tlen;
       clen = (clen - 1) | 0x80;
       if (s->ig->writecb(s->ig, &clen, 1) != 1) return 0;
       clen = (clen & ~0x80) + 1;
@@ -562,17 +597,16 @@ Returns NULL on error.
 
 i_img *
 i_readtga_wiol(io_glue *ig, int length) {
-  i_img* img;
-  int x, y, i;
+  i_img* img = NULL;
+  int x, y;
   int width, height, channels;
   int mapped;
-  char *idstring;
+  char *idstring = NULL;
 
   tga_source src;
   tga_header header;
   unsigned char headbuf[18];
   unsigned char *databuf;
-  unsigned char *reorderbuf;
 
   i_color *linebuf = NULL;
   i_clear_error();
@@ -607,17 +641,18 @@ i_readtga_wiol(io_glue *ig, int length) {
       i_push_error(errno, "short read on targa idstring");
       return NULL;
     }
-    myfree(idstring); /* Move this later, once this is stored in a tag */
   }
 
   width = header.width;
   height = header.height;
+
   
   /* Set tags here */
   
   switch (header.datatypecode) {
   case 0: /* No data in image */
     i_push_error(0, "Targa image contains no image data");
+    if (idstring) myfree(idstring);
     return NULL;
     break;
   case 1:  /* Uncompressed, color-mapped images */
@@ -626,6 +661,7 @@ i_readtga_wiol(io_glue *ig, int length) {
   case 11: /* Compressed,   grayscale images    */
     if (header.bitsperpixel != 8) {
       i_push_error(0, "Targa: mapped/grayscale image's bpp is not 8, unsupported.");
+      if (idstring) myfree(idstring);
       return NULL;
     }
     src.bytepp = 1;
@@ -635,15 +671,18 @@ i_readtga_wiol(io_glue *ig, int length) {
     if ((src.bytepp = bpp_to_bytes(header.bitsperpixel)))
       break;
     i_push_error(0, "Targa: direct color image's bpp is not 15/16/24/32 - unsupported.");
+    if (idstring) myfree(idstring);
     return NULL;
     break;
   case 32: /* Compressed color-mapped, Huffman, Delta and runlength */
   case 33: /* Compressed color-mapped, Huffman, Delta and runlength */
     i_push_error(0, "Unsupported Targa (Huffman/delta/rle/quadtree) subformat is not supported");
+    if (idstring) myfree(idstring);
     return NULL;
     break;
   default: /* All others which we don't know which might be */
     i_push_error(0, "Unknown targa format");
+    if (idstring) myfree(idstring);
     return NULL;
     break;
   }
@@ -657,7 +696,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;
@@ -667,6 +705,7 @@ i_readtga_wiol(io_glue *ig, int length) {
                                   header.colourmapdepth : 
                                   header.bitsperpixel))) break;
     i_push_error(0, "Targa Image has none of 15/16/24/32 pixel layout");
+    if (idstring) myfree(idstring);
     return NULL;
     break;
   case 3:  /* Uncompressed, grayscale images    */
@@ -675,11 +714,28 @@ i_readtga_wiol(io_glue *ig, int length) {
     channels = 1;
     break;
   }
+
+  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);
+    myfree(idstring);
+  }
+
   if (mapped &&
       !tga_palette_read(ig,
                        img,
@@ -687,6 +743,8 @@ i_readtga_wiol(io_glue *ig, int length) {
                        header.colourmaplength)
       ) {
     i_push_error(0, "Targa Image has none of 15/16/24/32 pixel layout");
+    if (idstring) myfree(idstring);
+    if (img) i_img_destroy(img);
     return NULL;
   }
   
@@ -698,6 +756,7 @@ i_readtga_wiol(io_glue *ig, int length) {
     if (!tga_source_read(&src, databuf, width)) {
       i_push_error(errno, "read for targa data failed");
       myfree(databuf);
+      if (img) i_img_destroy(img);
       return NULL;
     }
     if (mapped && header.colourmaporigin) for(x=0; x<width; x++) databuf[x] -= header.colourmaporigin;
@@ -709,6 +768,10 @@ 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;
 }
 
@@ -727,11 +790,9 @@ 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 char *data;
   unsigned int bitspp;
   
   int mapped;
@@ -779,7 +840,6 @@ i_writetga_wiol(i_img *img, io_glue *ig, int wierdpack, int compress, char *idst
 
   io_glue_commit_types(ig);
   
-  header.idlength;
   header.idlength = idlen;
   header.colourmaptype   = mapped ? 1 : 0;
   header.datatypecode    = mapped ? 1 : img->channels == 1 ? 3 : 2;
@@ -818,8 +878,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) {
@@ -851,5 +909,22 @@ i_writetga_wiol(i_img *img, io_glue *ig, int wierdpack, int compress, char *idst
     myfree(buf);
     myfree(vals);
   }
+
+  ig->closecb(ig);
+
   return 1;
 }
+
+/*
+=back
+
+=head1 AUTHOR
+
+Arnar M. Hrafnkelsson <addi@umich.edu>
+
+=head1 SEE ALSO
+
+Imager(3)
+
+=cut
+*/