]> granicus.if.org Git - imagemagick/blobdiff - coders/tga.c
(no commit message)
[imagemagick] / coders / tga.c
index f963b88a49a47bbf086fb13288d954513bc462f5..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,19 +134,16 @@ static Image *ReadTGAImage(const ImageInfo *image_info,ExceptionInfo *exception)
   Image
     *image;
 
-  IndexPacket
-    index;
-
   MagickBooleanType
     status;
 
-  PixelPacket
+  PixelInfo
     pixel;
 
-  register IndexPacket
-    *indexes;
+  Quantum
+    index;
 
-  register PixelPacket
+  register Quantum
     *q;
 
   register ssize_t
@@ -167,8 +167,12 @@ static Image *ReadTGAImage(const ImageInfo *image_info,ExceptionInfo *exception)
   unsigned char
     j,
     k,
+    pixels[4],
     runlength;
 
+  unsigned int
+    alpha_bits;
+
   /*
     Open image file.
   */
@@ -179,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)
     {
@@ -222,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 :
@@ -254,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");
         }
     }
@@ -278,17 +284,17 @@ static Image *ReadTGAImage(const ImageInfo *image_info,ExceptionInfo *exception)
         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++)
       {
@@ -300,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;
@@ -317,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;
           }
         }
@@ -345,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++)
@@ -354,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) ||
@@ -388,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;
           }
@@ -407,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)
-        SetIndexPixelComponent(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;
@@ -580,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.
 %
@@ -597,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
@@ -637,10 +680,7 @@ static MagickBooleanType WriteTGAImage(const ImageInfo *image_info,Image *image)
   MagickBooleanType
     status;
 
-  register const IndexPacket
-    *indexes;
-
-  register const PixelPacket
+  register const Quantum
     *p;
 
   register ssize_t
@@ -671,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);
   /*
@@ -679,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;
@@ -698,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))
@@ -709,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 */
@@ -758,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);
@@ -776,30 +817,27 @@ 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) GetIndexPixelComponent(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(
-                GetAlphaPixelComponent(p));
-            if (image->colorspace == CMYKColorspace)
-              *q++=ScaleQuantumToChar(GetIndexPixelComponent(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)