]> granicus.if.org Git - imagemagick/blobdiff - coders/tga.c
(no commit message)
[imagemagick] / coders / tga.c
index 467ba984b12265d9eeac49c6f553db4020c62daf..cf4539609638775126e5d1c5e6912a3fe2894846 100644 (file)
 %                    Read/Write Truevision Targa Image Format                 %
 %                                                                             %
 %                              Software Design                                %
-%                                John Cristy                                  %
+%                                   Cristy                                    %
 %                                 July 1992                                   %
 %                                                                             %
 %                                                                             %
-%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  Copyright 1999-2014 ImageMagick Studio LLC, a non-profit organization      %
 %  dedicated to making software imaging solutions freely available.           %
 %                                                                             %
 %  You may not use this file except in compliance with the License.  You may  %
 /*
   Include declarations.
 */
-#include "magick/studio.h"
-#include "magick/blob.h"
-#include "magick/blob-private.h"
-#include "magick/cache.h"
-#include "magick/color-private.h"
-#include "magick/colormap.h"
-#include "magick/colormap-private.h"
-#include "magick/colorspace.h"
-#include "magick/exception.h"
-#include "magick/exception-private.h"
-#include "magick/image.h"
-#include "magick/image-private.h"
-#include "magick/list.h"
-#include "magick/magick.h"
-#include "magick/memory_.h"
-#include "magick/monitor.h"
-#include "magick/monitor-private.h"
-#include "magick/property.h"
-#include "magick/quantum-private.h"
-#include "magick/static.h"
-#include "magick/string_.h"
-#include "magick/module.h"
+#include "MagickCore/studio.h"
+#include "MagickCore/attribute.h"
+#include "MagickCore/blob.h"
+#include "MagickCore/blob-private.h"
+#include "MagickCore/cache.h"
+#include "MagickCore/color-private.h"
+#include "MagickCore/colormap.h"
+#include "MagickCore/colormap-private.h"
+#include "MagickCore/colorspace.h"
+#include "MagickCore/colorspace-private.h"
+#include "MagickCore/exception.h"
+#include "MagickCore/exception-private.h"
+#include "MagickCore/image.h"
+#include "MagickCore/image-private.h"
+#include "MagickCore/list.h"
+#include "MagickCore/magick.h"
+#include "MagickCore/memory_.h"
+#include "MagickCore/monitor.h"
+#include "MagickCore/monitor-private.h"
+#include "MagickCore/pixel-accessor.h"
+#include "MagickCore/property.h"
+#include "MagickCore/quantum-private.h"
+#include "MagickCore/static.h"
+#include "MagickCore/string_.h"
+#include "MagickCore/module.h"
 \f
 /*
   Forward declarations.
 */
 static MagickBooleanType
-  WriteTGAImage(const ImageInfo *,Image *);
+  WriteTGAImage(const ImageInfo *,Image *,ExceptionInfo *);
 \f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -131,30 +134,32 @@ static Image *ReadTGAImage(const ImageInfo *image_info,ExceptionInfo *exception)
   Image
     *image;
 
-  IndexPacket
-    index;
-
-  ssize_t
-    y;
-
   MagickBooleanType
     status;
 
-  PixelPacket
+  PixelInfo
     pixel;
 
-  register IndexPacket
-    *indexes;
+  Quantum
+    index;
+
+  register Quantum
+    *q;
 
   register ssize_t
     i,
     x;
 
-  register PixelPacket
-    *q;
+  size_t
+    base,
+    flag,
+    offset,
+    real,
+    skip;
 
   ssize_t
-    count;
+    count,
+    y;
 
   TGAInfo
     tga_info;
@@ -162,14 +167,11 @@ static Image *ReadTGAImage(const ImageInfo *image_info,ExceptionInfo *exception)
   unsigned char
     j,
     k,
+    pixels[4],
     runlength;
 
-  size_t
-    base,
-    flag,
-    offset,
-    real,
-    skip;
+  unsigned int
+    alpha_bits;
 
   /*
     Open image file.
@@ -181,7 +183,7 @@ static Image *ReadTGAImage(const ImageInfo *image_info,ExceptionInfo *exception)
       image_info->filename);
   assert(exception != (ExceptionInfo *) NULL);
   assert(exception->signature == MagickSignature);
-  image=AcquireImage(image_info);
+  image=AcquireImage(image_info,exception);
   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
   if (status == MagickFalse)
     {
@@ -224,7 +226,9 @@ static Image *ReadTGAImage(const ImageInfo *image_info,ExceptionInfo *exception)
   */
   image->columns=tga_info.width;
   image->rows=tga_info.height;
-  image->matte=(tga_info.attributes & 0x0FU) != 0 ? MagickTrue : MagickFalse;
+  alpha_bits=(tga_info.attributes & 0x0FU);
+  image->alpha_trait=(alpha_bits > 0) || (tga_info.bits_per_pixel == 32) ||
+    (tga_info.colormap_size == 32) ?  BlendPixelTrait : UndefinedPixelTrait;
   if ((tga_info.image_type != TGAColormap) &&
       (tga_info.image_type != TGARLEColormap))
     image->depth=(size_t) ((tga_info.bits_per_pixel <= 8) ? 8 :
@@ -256,7 +260,7 @@ static Image *ReadTGAImage(const ImageInfo *image_info,ExceptionInfo *exception)
 
           one=1;
           image->colors=one << tga_info.bits_per_pixel;
-          if (AcquireImageColormap(image,image->colors) == MagickFalse)
+          if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
         }
     }
@@ -273,24 +277,24 @@ static Image *ReadTGAImage(const ImageInfo *image_info,ExceptionInfo *exception)
       */
       length=(size_t) tga_info.id_length;
       comment=(char *) NULL;
-      if (~length >= MaxTextExtent)
+      if (~length >= (MaxTextExtent-1))
         comment=(char *) AcquireQuantumMemory(length+MaxTextExtent,
           sizeof(*comment));
       if (comment == (char *) NULL)
         ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
       count=ReadBlob(image,tga_info.id_length,(unsigned char *) comment);
       comment[tga_info.id_length]='\0';
-      (void) SetImageProperty(image,"comment",comment);
+      (void) SetImageProperty(image,"comment",comment,exception);
       comment=DestroyString(comment);
     }
   (void) ResetMagickMemory(&pixel,0,sizeof(pixel));
-  pixel.opacity=(Quantum) OpaqueOpacity;
+  pixel.alpha=(MagickRealType) OpaqueAlpha;
   if (tga_info.colormap_type != 0)
     {
       /*
         Read TGA raster colormap.
       */
-      if (AcquireImageColormap(image,image->colors) == MagickFalse)
+      if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
         ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
       for (i=0; i < (ssize_t) image->colors; i++)
       {
@@ -302,7 +306,8 @@ static Image *ReadTGAImage(const ImageInfo *image_info,ExceptionInfo *exception)
             /*
               Gray scale.
             */
-            pixel.red=ScaleCharToQuantum((unsigned char) ReadBlobByte(image));
+            pixel.red=(MagickRealType) ScaleCharToQuantum((unsigned char)
+              ReadBlobByte(image));
             pixel.green=pixel.red;
             pixel.blue=pixel.red;
             break;
@@ -319,21 +324,39 @@ static Image *ReadTGAImage(const ImageInfo *image_info,ExceptionInfo *exception)
             j=(unsigned char) ReadBlobByte(image);
             k=(unsigned char) ReadBlobByte(image);
             range=GetQuantumRange(5UL);
-            pixel.red=ScaleAnyToQuantum(1UL*(k & 0x7c) >> 2,range);
-            pixel.green=ScaleAnyToQuantum((1UL*(k & 0x03) << 3)+
-              (1UL*(j & 0xe0) >> 5),range);
-            pixel.blue=ScaleAnyToQuantum(1UL*(j & 0x1f),range);
+            pixel.red=(MagickRealType) ScaleAnyToQuantum(1UL*(k & 0x7c) >> 2,
+              range);
+            pixel.green=(MagickRealType) ScaleAnyToQuantum((1UL*(k & 0x03)
+              << 3)+(1UL*(j & 0xe0) >> 5),range);
+            pixel.blue=(MagickRealType) ScaleAnyToQuantum(1UL*(j & 0x1f),range);
             break;
           }
           case 24:
-          case 32:
           {
             /*
               8 bits each of blue, green and red.
             */
-            pixel.blue=ScaleCharToQuantum((unsigned char) ReadBlobByte(image));
-            pixel.green=ScaleCharToQuantum((unsigned char) ReadBlobByte(image));
-            pixel.red=ScaleCharToQuantum((unsigned char) ReadBlobByte(image));
+            pixel.blue=(MagickRealType) ScaleCharToQuantum((unsigned char)
+              ReadBlobByte(image));
+            pixel.green=(MagickRealType) ScaleCharToQuantum((unsigned char)
+              ReadBlobByte(image));
+            pixel.red=(MagickRealType) ScaleCharToQuantum((unsigned char)
+              ReadBlobByte(image));
+            break;
+          }
+          case 32:
+          {
+            /*
+              8 bits each of blue, green, red, and alpha.
+            */
+            pixel.blue=(MagickRealType) ScaleCharToQuantum((unsigned char)
+              ReadBlobByte(image));
+            pixel.green=(MagickRealType) ScaleCharToQuantum((unsigned char)
+              ReadBlobByte(image));
+            pixel.red=(MagickRealType) ScaleCharToQuantum((unsigned char)
+              ReadBlobByte(image));
+            pixel.alpha=(MagickRealType) ScaleCharToQuantum((unsigned char)
+              ReadBlobByte(image));
             break;
           }
         }
@@ -347,7 +370,7 @@ static Image *ReadTGAImage(const ImageInfo *image_info,ExceptionInfo *exception)
   flag=0;
   skip=MagickFalse;
   real=0;
-  index=(IndexPacket) 0;
+  index=0;
   runlength=0;
   offset=0;
   for (y=0; y < (ssize_t) image->rows; y++)
@@ -356,9 +379,8 @@ static Image *ReadTGAImage(const ImageInfo *image_info,ExceptionInfo *exception)
     if (((unsigned char) (tga_info.attributes & 0x20) >> 5) == 0)
       real=image->rows-real-1;
     q=QueueAuthenticPixels(image,0,(ssize_t) real,image->columns,1,exception);
-    if (q == (PixelPacket *) NULL)
+    if (q == (Quantum *) NULL)
       break;
-    indexes=GetAuthenticIndexQueue(image);
     for (x=0; x < (ssize_t) image->columns; x++)
     {
       if ((tga_info.image_type == TGARLEColormap) ||
@@ -390,15 +412,18 @@ static Image *ReadTGAImage(const ImageInfo *image_info,ExceptionInfo *exception)
             /*
               Gray scale.
             */
-            index=(IndexPacket) ReadBlobByte(image);
+            index=(Quantum) ReadBlobByte(image);
             if (tga_info.colormap_type != 0)
               pixel=image->colormap[(ssize_t) ConstrainColormapIndex(image,
-                1UL*index)];
+                1UL*index,exception)];
             else
               {
-                pixel.red=ScaleCharToQuantum((unsigned char) index);
-                pixel.green=ScaleCharToQuantum((unsigned char) index);
-                pixel.blue=ScaleCharToQuantum((unsigned char) index);
+                pixel.red=(MagickRealType) ScaleCharToQuantum((unsigned char)
+                  index);
+                pixel.green=(MagickRealType) ScaleCharToQuantum((unsigned char)
+                  index);
+                pixel.blue=(MagickRealType) ScaleCharToQuantum((unsigned char)
+                  index);
               }
             break;
           }
@@ -409,47 +434,61 @@ static Image *ReadTGAImage(const ImageInfo *image_info,ExceptionInfo *exception)
               range;
 
             /*
-              5 bits each of red green and blue.
+              5 bits each of RGB.
             */
-            j=(unsigned char) ReadBlobByte(image);
-            k=(unsigned char) ReadBlobByte(image);
+            if (ReadBlob(image,2,pixels) != 2)
+              ThrowReaderException(CorruptImageError,"UnableToReadImageData");
+            j=pixels[0];
+            k=pixels[1];
             range=GetQuantumRange(5UL);
-            pixel.red=ScaleAnyToQuantum(1UL*(k & 0x7c) >> 2,range);
-            pixel.green=ScaleAnyToQuantum((1UL*(k & 0x03) << 3)+
-              (1UL*(j & 0xe0) >> 5),range);
-            pixel.blue=ScaleAnyToQuantum(1UL*(j & 0x1f),range);
-            if (image->matte != MagickFalse)
-              pixel.opacity=(k & 0x80) == 0 ? (Quantum) OpaqueOpacity :
-                (Quantum) TransparentOpacity; 
+            pixel.red=(MagickRealType) ScaleAnyToQuantum(1UL*(k & 0x7c) >> 2,
+              range);
+            pixel.green=(MagickRealType) ScaleAnyToQuantum((1UL*(k & 0x03)
+              << 3)+(1UL*(j & 0xe0) >> 5),range);
+            pixel.blue=(MagickRealType) ScaleAnyToQuantum(1UL*(j & 0x1f),range);
+            if (image->alpha_trait == BlendPixelTrait)
+              pixel.alpha=(MagickRealType) ((k & 0x80) == 0 ? (Quantum)
+                OpaqueAlpha : (Quantum) TransparentAlpha); 
             if (image->storage_class == PseudoClass)
-              index=ConstrainColormapIndex(image,((size_t) k << 8)+j);
+              index=ConstrainColormapIndex(image,((size_t) k << 8)+j,exception);
             break;
           }
           case 24:
+          {
+            /*
+              BGR pixels.
+            */
+            if (ReadBlob(image,3,pixels) != 3)
+              ThrowReaderException(CorruptImageError,"UnableToReadImageData");
+            pixel.blue=(MagickRealType) ScaleCharToQuantum(pixels[0]);
+            pixel.green=(MagickRealType) ScaleCharToQuantum(pixels[1]);
+            pixel.red=(MagickRealType) ScaleCharToQuantum(pixels[2]);
+            break;
+          }
           case 32:
           {
             /*
-              8 bits each of blue green and red.
+              BGRA pixels.
             */
-            pixel.blue=ScaleCharToQuantum((unsigned char) ReadBlobByte(image));
-            pixel.green=ScaleCharToQuantum((unsigned char) ReadBlobByte(image));
-            pixel.red=ScaleCharToQuantum((unsigned char) ReadBlobByte(image));
-            if (tga_info.bits_per_pixel == 32)
-              pixel.opacity=(Quantum) (QuantumRange-ScaleCharToQuantum(
-                (unsigned char) ReadBlobByte(image)));
+            if (ReadBlob(image,4,pixels) != 4)
+              ThrowReaderException(CorruptImageError,"UnableToReadImageData");
+            pixel.blue=(MagickRealType) ScaleCharToQuantum(pixels[0]);
+            pixel.green=(MagickRealType) ScaleCharToQuantum(pixels[1]);
+            pixel.red=(MagickRealType) ScaleCharToQuantum(pixels[2]);
+            pixel.alpha=(MagickRealType) ScaleCharToQuantum(pixels[3]);
             break;
           }
         }
       if (status == MagickFalse)
         ThrowReaderException(CorruptImageError,"UnableToReadImageData");
       if (image->storage_class == PseudoClass)
-        indexes[x]=index;
-      SetRedPixelComponent(q,pixel.red);
-      SetGreenPixelComponent(q,pixel.green);
-      SetBluePixelComponent(q,pixel.blue);
-      if (image->matte != MagickFalse)
-        SetOpacityPixelComponent(q,pixel.opacity);
-      q++;
+        SetPixelIndex(image,index,q);
+      SetPixelRed(image,ClampToQuantum(pixel.red),q);
+      SetPixelGreen(image,ClampToQuantum(pixel.green),q);
+      SetPixelBlue(image,ClampToQuantum(pixel.blue),q);
+      if (image->alpha_trait == BlendPixelTrait)
+        SetPixelAlpha(image,ClampToQuantum(pixel.alpha),q);
+      q+=GetPixelChannels(image);
     }
     if (((unsigned char) (tga_info.attributes & 0xc0) >> 6) == 4)
       offset+=4;
@@ -582,7 +621,8 @@ ModuleExport void UnregisterTGAImage(void)
 %
 %  The format of the WriteTGAImage method is:
 %
-%      MagickBooleanType WriteTGAImage(const ImageInfo *image_info,Image *image)
+%      MagickBooleanType WriteTGAImage(const ImageInfo *image_info,
+%        Image *image,ExceptionInfo *exception)
 %
 %  A description of each parameter follows.
 %
@@ -599,7 +639,8 @@ static inline size_t MagickMin(const size_t x,const size_t y)
   return(y);
 }
 
-static MagickBooleanType WriteTGAImage(const ImageInfo *image_info,Image *image)
+static MagickBooleanType WriteTGAImage(const ImageInfo *image_info,Image *image,
+  ExceptionInfo *exception)
 {
 #define TargaColormap 1
 #define TargaRGB 2
@@ -636,16 +677,10 @@ static MagickBooleanType WriteTGAImage(const ImageInfo *image_info,Image *image)
   const char
     *value;
 
-  ssize_t
-    y;
-
   MagickBooleanType
     status;
 
-  register const IndexPacket
-    *indexes;
-
-  register const PixelPacket
+  register const Quantum
     *p;
 
   register ssize_t
@@ -658,7 +693,8 @@ static MagickBooleanType WriteTGAImage(const ImageInfo *image_info,Image *image)
     *q;
 
   ssize_t
-    count;
+    count,
+    y;
 
   TargaInfo
     targa_info;
@@ -675,7 +711,9 @@ static MagickBooleanType WriteTGAImage(const ImageInfo *image_info,Image *image)
   assert(image->signature == MagickSignature);
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
-  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
+  assert(exception != (ExceptionInfo *) NULL);
+  assert(exception->signature == MagickSignature);
+  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
   if (status == MagickFalse)
     return(status);
   /*
@@ -683,10 +721,9 @@ static MagickBooleanType WriteTGAImage(const ImageInfo *image_info,Image *image)
   */
   if ((image->columns > 65535L) || (image->rows > 65535L))
     ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
-  if (image->colorspace != RGBColorspace)
-    (void) TransformImageColorspace(image,RGBColorspace);
+  (void) TransformImageColorspace(image,sRGBColorspace,exception);
   targa_info.id_length=0;
-  value=GetImageProperty(image,"comment");
+  value=GetImageProperty(image,"comment",exception);
   if (value != (const char *) NULL)
     targa_info.id_length=(unsigned char) MagickMin(strlen(value),255);
   targa_info.colormap_type=0;
@@ -702,8 +739,8 @@ static MagickBooleanType WriteTGAImage(const ImageInfo *image_info,Image *image)
   if ((image_info->type != TrueColorType) &&
       (image_info->type != TrueColorMatteType) &&
       (image_info->type != PaletteType) &&
-      (image->matte == MagickFalse) &&
-      (IsGrayImage(image,&image->exception) != MagickFalse))
+      (image->alpha_trait != BlendPixelTrait) &&
+      (IsImageGray(image,exception) != MagickFalse))
     targa_info.image_type=TargaMonochrome;
   else
     if ((image->storage_class == DirectClass) || (image->colors > 256))
@@ -713,7 +750,7 @@ static MagickBooleanType WriteTGAImage(const ImageInfo *image_info,Image *image)
         */
         targa_info.image_type=TargaRGB;
         targa_info.bits_per_pixel=24;
-        if (image->matte != MagickFalse)
+        if (image->alpha_trait == BlendPixelTrait)
           {
             targa_info.bits_per_pixel=32;
             targa_info.attributes=8;  /* # of alpha bits */
@@ -762,9 +799,9 @@ static MagickBooleanType WriteTGAImage(const ImageInfo *image_info,Image *image)
       q=targa_colormap;
       for (i=0; i < (ssize_t) image->colors; i++)
       {
-        *q++=ScaleQuantumToChar(image->colormap[i].blue);
-        *q++=ScaleQuantumToChar(image->colormap[i].green);
-        *q++=ScaleQuantumToChar(image->colormap[i].red);
+        *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].blue));
+        *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].green));
+        *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].red));
       }
       (void) WriteBlob(image,(size_t) (3*targa_info.colormap_length),
         targa_colormap);
@@ -780,36 +817,33 @@ static MagickBooleanType WriteTGAImage(const ImageInfo *image_info,Image *image)
     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
   for (y=(ssize_t) (image->rows-1); y >= 0; y--)
   {
-    p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
-    if (p == (const PixelPacket *) NULL)
+    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
+    if (p == (const Quantum *) NULL)
       break;
     q=targa_pixels;
-    indexes=GetVirtualIndexQueue(image);
     for (x=0; x < (ssize_t) image->columns; x++)
     {
       if (targa_info.image_type == TargaColormap)
-        *q++=(unsigned char) indexes[x];
+        *q++=(unsigned char) GetPixelIndex(image,p);
       else
         if (targa_info.image_type == TargaMonochrome)
-          *q++=(unsigned char) ScaleQuantumToChar(PixelIntensityToQuantum(p));
+          *q++=(unsigned char) ScaleQuantumToChar((ClampToQuantum(
+            GetPixelLuma(image,p))));
         else
           {
-            *q++=ScaleQuantumToChar(GetBluePixelComponent(p));
-            *q++=ScaleQuantumToChar(GetGreenPixelComponent(p));
-            *q++=ScaleQuantumToChar(GetRedPixelComponent(p));
-            if (image->matte != MagickFalse)
-              *q++=(unsigned char) ScaleQuantumToChar((Quantum)
-                (GetAlphaPixelComponent(p)));
-            if (image->colorspace == CMYKColorspace)
-              *q++=ScaleQuantumToChar(indexes[x]);
+            *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
+            *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
+            *q++=ScaleQuantumToChar(GetPixelRed(image,p));
+            if (image->alpha_trait == BlendPixelTrait)
+              *q++=(unsigned char) ScaleQuantumToChar(GetPixelAlpha(image,p));
           }
-      p++;
+      p+=GetPixelChannels(image);
     }
     (void) WriteBlob(image,(size_t) (q-targa_pixels),targa_pixels);
     if (image->previous == (Image *) NULL)
       {
         status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
-              image->rows);
+          image->rows);
         if (status == MagickFalse)
           break;
       }