Closed memory leaks when an error occurs during load of targa images. Fixed
authorArnar Mar Hrafnkelsson <addi@cpan.org>
Tue, 23 Oct 2001 18:49:00 +0000 (18:49 +0000)
committerArnar Mar Hrafnkelsson <addi@cpan.org>
Tue, 23 Oct 2001 18:49:00 +0000 (18:49 +0000)
scaling bug which only occured for some scaling ratios.

Changes
Imager.pm
image.c
tga.c

diff --git a/Changes b/Changes
index fdedc24c6dbaf7cc9b52604cadad4ffe11ab9044..d5ca92248792f834f9d1fe5133042f14615166ac 100644 (file)
--- a/Changes
+++ b/Changes
@@ -527,8 +527,12 @@ Revision history for Perl extension Imager.
         - added basic POD to trans2.c
         - transform2 now uses the error interface
         - myrealloc() is implemented for malloc debug mode
-        - now buffer chains are freed when destructor for Imager::IOi
+        - now buffer chains are freed when destructor for Imager::IO
           is called
+       - adjusted the Lanczos window width for the scaling code and
+         added code to normalize the filter generated to preserve
+         intensity scaling.
+
 
 =================================================================
 
index 90507be1815f2401244067011ad35c38ffb44fca..70dade6d68dc29ddd453d984471a253d3d091064 100644 (file)
--- a/Imager.pm
+++ b/Imager.pm
@@ -1818,7 +1818,7 @@ sub flood_fill {
     $self->{ERRSTR} = "missing seed x and y parameters";
     return undef;
   }
-  
+
   if ($opts{fill}) {
     unless (UNIVERSAL::isa($opts{fill}, 'Imager::Fill')) {
       # assume it's a hash ref
@@ -2347,6 +2347,14 @@ of Imager::Color objects.  Note that the local means algorithm needs
 much more cpu time but also gives considerable better results than the
 median cut algorithm.
 
+When storing targa images rle compression can be activated with the
+'compress' parameter, the 'idstring' parameter can be used to set the
+targa comment field and the 'wierdpack' option can be used to use the
+15 and 16 bit targa formats for rgb and rgba data.  The 15 bit format
+has 5 of each red, green and blue.  The 16 bit format in addition
+allows 1 bit of alpha.  The most significant bits are used for each
+channel.
+
 Currently just for gif files, you can specify various options for the
 conversion from Imager's internal RGB format to the target's indexed
 file format.  If you set the gifquant option to 'gen', you can use the
@@ -3784,9 +3792,9 @@ Someone decides that the filter is not working as it should -
 dyntest.c modified and recompiled.
 
   load_plugin("dynfilt/dyntest.so") || die "unable to load plugin\n";
-  $img->filter(%hsh); 
+  $img->filter(%hsh);
 
-An example plugin comes with the module - Please send feedback to 
+An example plugin comes with the module - Please send feedback to
 addi@umich.edu if you test this.
 
 Note: This seems to test ok on the following systems:
@@ -3970,7 +3978,7 @@ from Tony Cook.  See the README for a complete list.
 
 =head1 SEE ALSO
 
-perl(1), Imager::Color(3), Imager::Font(3), Imager::Matrix2d(3), 
+perl(1), Imager::Color(3), Imager::Font(3), Imager::Matrix2d(3),
 Affix::Infix2Postfix(3), Parse::RecDescent(3) 
 http://www.eecs.umich.edu/~addi/perl/Imager/
 
diff --git a/image.c b/image.c
index d4c3f6f400116ef069fce1ed2564088143adfc50..8c6149d72dca75f11704a67a04ae1aaa6f7fa147 100644 (file)
--- a/image.c
+++ b/image.c
@@ -409,7 +409,7 @@ Destroy image and free data via exorcise.
 
 void
 i_img_destroy(i_img *im) {
-  mm_log((1,"i_img_destroy(im* 0x%x)\n",im));
+  mm_log((1,"i_img_destroy(im %p)\n",im));
   i_img_exorcise(im);
   if (im) { myfree(im); }
 }
@@ -923,71 +923,78 @@ i_scaleaxis(i_img *im, float Value, int Axis) {
   int hsize, vsize, i, j, k, l, lMax, iEnd, jEnd;
   int LanczosWidthFactor;
   float *l0, *l1, OldLocation;
-  int T, TempJump1, TempJump2;
+  int T; 
+  float t;
   float F, PictureValue[MAXCHANNELS];
   short psave;
   i_color val,val1,val2;
   i_img *new_img;
 
-  mm_log((1,"i_scaleaxis(im 0x%x,Value %.2f,Axis %d)\n",im,Value,Axis));
+  mm_log((1,"i_scaleaxis(im %p,Value %.2f,Axis %d)\n",im,Value,Axis));
 
   if (Axis == XAXIS) {
-    hsize = (int) ((float) im->xsize * Value);
+    hsize = (int)(0.5 + im->xsize * Value);
     vsize = im->ysize;
     
     jEnd = hsize;
     iEnd = vsize;
-    
-    TempJump1 = (hsize - 1) * 3;
-    TempJump2 = hsize * (vsize - 1) * 3 + TempJump1;
   } else {
     hsize = im->xsize;
-    vsize = (int) ((float) im->ysize * Value);
-    
+    vsize = (int)(0.5 + im->ysize * Value);
+
     jEnd = vsize;
     iEnd = hsize;
-    
-    TempJump1 = 0;
-    TempJump2 = 0;
   }
   
-  new_img=i_img_empty_ch(NULL,hsize,vsize,im->channels);
-  
-  if (Value >=1) LanczosWidthFactor = 1;
-  else LanczosWidthFactor = (int) (1.0/Value);
+  new_img = i_img_empty_ch(NULL, hsize, vsize, im->channels);
   
+  /* 1.5 is a magic number, setting it to 2 will cause rather blurred images */
+  LanczosWidthFactor = (Value >= 1) ? 1 : (int) (1.4/Value); 
   lMax = LanczosWidthFactor << 1;
   
-  l0 = (float *) mymalloc(lMax * sizeof(float));
-  l1 = (float *) mymalloc(lMax * sizeof(float));
+  l0 = mymalloc(lMax * sizeof(float));
+  l1 = mymalloc(lMax * sizeof(float));
   
   for (j=0; j<jEnd; j++) {
     OldLocation = ((float) j) / Value;
     T = (int) (OldLocation);
     F = OldLocation - (float) T;
     
-    for (l = 0; l < lMax; l++) {
+    for (l = 0; l<lMax; l++) {
       l0[lMax-l-1] = Lanczos(((float) (lMax-l-1) + F) / (float) LanczosWidthFactor);
-      l1[l] = Lanczos(((float) (l + 1) - F) / (float) LanczosWidthFactor);
+      l1[l]        = Lanczos(((float) (l+1)      - F) / (float) LanczosWidthFactor);
+    }
+    
+    /* Make sure filter is normalized */
+    t = 0.0;
+    for(l=0; l<lMax; l++) {
+      t+=l0[l];
+      t+=l1[l];
     }
+    t /= (float)LanczosWidthFactor;
     
-    if (Axis== XAXIS) {
+    for(l=0; l<lMax; l++) {
+      l0[l] /= t;
+      l1[l] /= t;
+    }
+
+    if (Axis == XAXIS) {
       
       for (i=0; i<iEnd; i++) {
        for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
        for (l=0; l < lMax; l++) {
-         i_gpix(im,T+l+1, i, &val1);
-         i_gpix(im,T-lMax+l+1, i, &val2);
+         i_gpix(im, T+l+1,      i, &val1);
+         i_gpix(im, T-lMax+l+1, i, &val2);
          for (k=0; k<im->channels; k++) {
-           PictureValue[k] += l1[l] * val1.channel[k];
+           PictureValue[k] += l1[l]        * val1.channel[k];
            PictureValue[k] += l0[lMax-l-1] * val2.channel[k];
          }
        }
        for(k=0;k<im->channels;k++) {
-         psave = (short)( PictureValue[k] / LanczosWidthFactor);
+         psave = (short)(0.5+(PictureValue[k] / LanczosWidthFactor));
          val.channel[k]=minmax(0,255,psave);
        }
-       i_ppix(new_img,j,i,&val);
+       i_ppix(new_img, j, i, &val);
       }
       
     } else {
@@ -995,8 +1002,8 @@ i_scaleaxis(i_img *im, float Value, int Axis) {
       for (i=0; i<iEnd; i++) {
        for (k=0; k<im->channels; k++) PictureValue[k] = 0.0;
        for (l=0; l < lMax; l++) {
-         i_gpix(im,i, T+l+1, &val1);
-         i_gpix(im,i, T-lMax+l+1, &val2);
+         i_gpix(im, i, T+l+1, &val1);
+         i_gpix(im, i, T-lMax+l+1, &val2);
          for (k=0; k<im->channels; k++) {
            PictureValue[k] += l1[l] * val1.channel[k];
            PictureValue[k] += l0[lMax-l-1] * val2.channel[k]; 
@@ -1004,9 +1011,9 @@ i_scaleaxis(i_img *im, float Value, int Axis) {
        }
        for (k=0; k<im->channels; k++) {
          psave = (short)( PictureValue[k] / LanczosWidthFactor);
-         val.channel[k]=minmax(0,255,psave);
+         val.channel[k] = minmax(0, 255, psave);
        }
-       i_ppix(new_img,i,j,&val);
+       i_ppix(new_img, i, j, &val);
       }
       
     }
@@ -1014,7 +1021,7 @@ i_scaleaxis(i_img *im, float Value, int Axis) {
   myfree(l0);
   myfree(l1);
 
-  mm_log((1,"(0x%x) <- i_scaleaxis\n",new_img));
+  mm_log((1,"(%p) <- i_scaleaxis\n", new_img));
 
   return new_img;
 }
diff --git a/tga.c b/tga.c
index a1c0c33a9a3dddeae593de9835ccdcc43a1d6e65..4bd4f89476459933088936f40a68bb62f7f6756c 100644 (file)
--- a/tga.c
+++ b/tga.c
@@ -452,6 +452,7 @@ 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;
       clen = (clen - 1) | 0x80;
@@ -562,11 +563,11 @@ Returns NULL on error.
 
 i_img *
 i_readtga_wiol(io_glue *ig, int length) {
-  i_img* img;
+  i_img* img = NULL;
   int x, y, i;
   int width, height, channels;
   int mapped;
-  char *idstring;
+  char *idstring = NULL;
 
   tga_source src;
   tga_header header;
@@ -607,7 +608,6 @@ 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;
@@ -618,6 +618,7 @@ i_readtga_wiol(io_glue *ig, int length) {
   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 +627,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 +637,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;
   }
@@ -667,6 +672,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    */
@@ -680,6 +686,11 @@ i_readtga_wiol(io_glue *ig, int length) {
     i_img_pal_new(width, height, channels, 256) :
     i_img_empty_ch(NULL, width, height, channels);
   
+  if (idstring) {
+    i_tags_add(&img->tags, "tga_idstring", 0, idstring, header.idlength, 0);
+    free(idstring);
+  }
+
   if (mapped &&
       !tga_palette_read(ig,
                        img,
@@ -687,6 +698,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 +711,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 +723,9 @@ i_readtga_wiol(io_glue *ig, int length) {
   }
   myfree(databuf);
   if (linebuf) myfree(linebuf);
+  
+  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;
 }