]> granicus.if.org Git - imagemagick/blobdiff - coders/gif.c
(no commit message)
[imagemagick] / coders / gif.c
index 27e0f60ad26a676b940606b1b754fc0172c78bd5..4d9ce5baeaadf53ce4e719e59edaa61ec828860e 100644 (file)
@@ -17,7 +17,7 @@
 %                                 July 1992                                   %
 %                                                                             %
 %                                                                             %
-%  Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization      %
+%  Copyright 1999-2012 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  %
@@ -68,6 +68,7 @@
 #include "MagickCore/quantum-private.h"
 #include "MagickCore/static.h"
 #include "MagickCore/string_.h"
+#include "MagickCore/string-private.h"
 #include "MagickCore/module.h"
 \f
 /*
@@ -387,11 +388,9 @@ static int ReadBlobLZWByte(LZWInfo *lzw_info)
   return(PopLZWStack(lzw_info->stack));
 }
 
-static MagickBooleanType DecodeImage(Image *image,const ssize_t opacity)
+static MagickBooleanType DecodeImage(Image *image,const ssize_t opacity,
+  ExceptionInfo *exception)
 {
-  ExceptionInfo
-    *exception;
-
   int
     c;
 
@@ -425,7 +424,6 @@ static MagickBooleanType DecodeImage(Image *image,const ssize_t opacity)
   if (lzw_info == (LZWInfo *) NULL)
     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
       image->filename);
-  exception=(&image->exception);
   pass=0;
   offset=0;
   for (y=0; y < (ssize_t) image->rows; y++)
@@ -444,9 +442,9 @@ static MagickBooleanType DecodeImage(Image *image,const ssize_t opacity)
       c=ReadBlobLZWByte(lzw_info);
       if (c < 0)
         break;
-      index=ConstrainColormapIndex(image,(size_t) c);
+      index=ConstrainColormapIndex(image,(size_t) c,exception);
       SetPixelIndex(image,index,q);
-      SetPixelPacket(image,image->colormap+(ssize_t) index,q);
+      SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q);
       SetPixelAlpha(image,(ssize_t) index == opacity ? TransparentAlpha :
         OpaqueAlpha,q);
       x++;
@@ -533,7 +531,7 @@ static MagickBooleanType DecodeImage(Image *image,const ssize_t opacity)
 %
 */
 static MagickBooleanType EncodeImage(const ImageInfo *image_info,Image *image,
-  const size_t data_size)
+  const size_t data_size,ExceptionInfo *exception)
 {
 #define MaxCode(number_bits)  ((one << (number_bits))-1)
 #define MaxHashTable  5003
@@ -660,7 +658,7 @@ static MagickBooleanType EncodeImage(const ImageInfo *image_info,Image *image,
     register ssize_t
       x;
 
-    p=GetVirtualPixels(image,0,offset,image->columns,1,&image->exception);
+    p=GetVirtualPixels(image,0,offset,image->columns,1,exception);
     if (p == (const Quantum *) NULL)
       break;
     if (y == 0)
@@ -930,7 +928,7 @@ static inline size_t MagickMin(const size_t x,const size_t y)
   return(y);
 }
 
-static MagickBooleanType PingGIFImage(Image *image)
+static MagickBooleanType PingGIFImage(Image *image,ExceptionInfo *exception)
 {
   unsigned char
     buffer[256],
@@ -1010,7 +1008,7 @@ static Image *ReadGIFImage(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)
     {
@@ -1054,7 +1052,6 @@ static Image *ReadGIFImage(const ImageInfo *image_info,ExceptionInfo *exception)
         /*
           GIF Extension block.
         */
-
         count=ReadBlob(image,1,&c);
         if (count != 1)
           {
@@ -1082,26 +1079,33 @@ static Image *ReadGIFImage(const ImageInfo *image_info,ExceptionInfo *exception)
             char
               *comments;
 
+            size_t
+              length;
+
             /*
               Read comment extension.
             */
             comments=AcquireString((char *) NULL);
-            for ( ; ; )
+            for (length=0; ; length+=count)
             {
               count=(ssize_t) ReadBlobBlock(image,header);
               if (count == 0)
                 break;
               header[count]='\0';
-              (void) ConcatenateString(&comments,(const char *) header);
+              comments=(char *) ResizeQuantumMemory(comments,length+count,
+                sizeof(*comments));
+              if (comments == (char *) NULL)
+                ThrowReaderException(ResourceLimitError,
+                  "MemoryAllocationFailed");
+              (void) CopyMagickMemory(comments+length,header,(size_t) count);
             }
-            (void) SetImageProperty(image,"comment",comments);
+            comments[length+count]='\0';
+            (void) SetImageProperty(image,"comment",comments,exception);
             comments=DestroyString(comments);
             break;
           }
           case 0xff:
           {
-            /* Read GIF application extension */
-
             MagickBooleanType
               loop;
 
@@ -1131,7 +1135,8 @@ static Image *ReadGIFImage(const ImageInfo *image_info,ExceptionInfo *exception)
                 MagickBooleanType
                   i8bim,
                   icc,
-                  iptc;
+                  iptc,
+                  magick;
 
                 StringInfo
                   *profile;
@@ -1142,10 +1147,12 @@ static Image *ReadGIFImage(const ImageInfo *image_info,ExceptionInfo *exception)
                 /*
                   Store GIF application extension as a generic profile.
                 */
-                i8bim=LocaleNCompare((char *) header,"MGK8BIM0000",11) == 0 ?
-                  MagickTrue : MagickFalse;
                 icc=LocaleNCompare((char *) header,"ICCRGBG1012",11) == 0 ?
                   MagickTrue : MagickFalse;
+                magick=LocaleNCompare((char *) header,"ImageMagick",11) == 0 ?
+                  MagickTrue : MagickFalse;
+                i8bim=LocaleNCompare((char *) header,"MGK8BIM0000",11) == 0 ?
+                  MagickTrue : MagickFalse;
                 iptc=LocaleNCompare((char *) header,"MGKIPTC0000",11) == 0 ?
                   MagickTrue : MagickFalse;
                 number_extensionss++;
@@ -1153,6 +1160,9 @@ static Image *ReadGIFImage(const ImageInfo *image_info,ExceptionInfo *exception)
                   "    Reading GIF application extension");
                 info=(unsigned char *) AcquireQuantumMemory(255UL,
                   sizeof(*info));
+                if (info == (unsigned char *) NULL)
+                  ThrowReaderException(ResourceLimitError,
+                    "MemoryAllocationFailed");
                 reserved_length=255;
                 for (info_length=0; ; )
                 {
@@ -1165,23 +1175,32 @@ static Image *ReadGIFImage(const ImageInfo *image_info,ExceptionInfo *exception)
                        reserved_length+=4096;
                        info=(unsigned char *) ResizeQuantumMemory(info,
                          (size_t) reserved_length,sizeof(*info));
+                       if (info == (unsigned char *) NULL)
+                         ThrowReaderException(ResourceLimitError,
+                           "MemoryAllocationFailed");
                     }
                 }
-                info=(unsigned char *) ResizeQuantumMemory(info,(size_t)
-                  (info_length+1),sizeof(*info));
-                profile=AcquireStringInfo((size_t) info_length);
-                SetStringInfoDatum(profile,(const unsigned char *) info);
+                profile=BlobToStringInfo(info,(size_t) info_length);
+                if (profile == (StringInfo *) NULL)
+                  ThrowReaderException(ResourceLimitError,
+                    "MemoryAllocationFailed");
                 if (i8bim == MagickTrue)
                   (void) CopyMagickString(name,"8bim",sizeof(name));
                 else if (icc == MagickTrue)
                   (void) CopyMagickString(name,"icc",sizeof(name));
                 else if (iptc == MagickTrue)
                   (void) CopyMagickString(name,"iptc",sizeof(name));
+                else if (magick == MagickTrue)
+                  {
+                    (void) CopyMagickString(name,"magick",sizeof(name));
+                    image->gamma=StringToDouble((char *) info+6,(char **) NULL);
+                  }
                 else
                   (void) FormatLocaleString(name,sizeof(name),"gif:%.11s",
                     header);
-                (void) SetImageProfile(image,name,profile);
                 info=(unsigned char *) RelinquishMagickMemory(info);
+                if (magick == MagickFalse)
+                  (void) SetImageProfile(image,name,profile,exception);
                 profile=DestroyStringInfo(profile);
                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                   "      profile name=%s",name);
@@ -1202,7 +1221,7 @@ static Image *ReadGIFImage(const ImageInfo *image_info,ExceptionInfo *exception)
         /*
           Allocate next image structure.
         */
-        AcquireNextImage(image_info,image);
+        AcquireNextImage(image_info,image,exception);
         if (GetNextImageInList(image) == (Image *) NULL)
           {
             image=DestroyImageList(image);
@@ -1224,10 +1243,9 @@ static Image *ReadGIFImage(const ImageInfo *image_info,ExceptionInfo *exception)
     image->rows=ReadBlobLSBShort(image);
     image->depth=8;
     flag=(unsigned char) ReadBlobByte(image);
-    image->interlace=BitSet((int) flag,0x40) != 0 ? GIFInterlace :
-      NoInterlace;
-    image->colors=BitSet((int) flag,0x80) == 0 ? global_colors :
-      one << ((size_t) (flag & 0x07)+1);
+    image->interlace=BitSet((int) flag,0x40) != 0 ? GIFInterlace : NoInterlace;
+    image->colors=BitSet((int) flag,0x80) == 0 ? global_colors : one <<
+      ((size_t) (flag & 0x07)+1);
     if (opacity >= (ssize_t) image->colors)
       opacity=(-1);
     image->page.width=page.width;
@@ -1251,7 +1269,7 @@ static Image *ReadGIFImage(const ImageInfo *image_info,ExceptionInfo *exception)
     /*
       Inititialize colormap.
     */
-    if (AcquireImageColormap(image,image->colors) == MagickFalse)
+    if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
       {
         global_colormap=(unsigned char *) RelinquishMagickMemory(
           global_colormap);
@@ -1265,12 +1283,12 @@ static Image *ReadGIFImage(const ImageInfo *image_info,ExceptionInfo *exception)
         p=global_colormap;
         for (i=0; i < (ssize_t) image->colors; i++)
         {
-          image->colormap[i].red=ScaleCharToQuantum(*p++);
-          image->colormap[i].green=ScaleCharToQuantum(*p++);
-          image->colormap[i].blue=ScaleCharToQuantum(*p++);
+          image->colormap[i].red=(double) ScaleCharToQuantum(*p++);
+          image->colormap[i].green=(double) ScaleCharToQuantum(*p++);
+          image->colormap[i].blue=(double) ScaleCharToQuantum(*p++);
           if (i == opacity)
             {
-              image->colormap[i].alpha=(Quantum) TransparentAlpha;
+              image->colormap[i].alpha=(double) TransparentAlpha;
               image->transparent_color=image->colormap[opacity];
             }
         }
@@ -1285,8 +1303,8 @@ static Image *ReadGIFImage(const ImageInfo *image_info,ExceptionInfo *exception)
         /*
           Read local colormap.
         */
-        colormap=(unsigned char *) AcquireQuantumMemory(image->colors,
-          3*sizeof(*colormap));
+        colormap=(unsigned char *) AcquireQuantumMemory(image->colors,3*
+          sizeof(*colormap));
         if (colormap == (unsigned char *) NULL)
           {
             global_colormap=(unsigned char *) RelinquishMagickMemory(
@@ -1305,14 +1323,22 @@ static Image *ReadGIFImage(const ImageInfo *image_info,ExceptionInfo *exception)
         p=colormap;
         for (i=0; i < (ssize_t) image->colors; i++)
         {
-          image->colormap[i].red=ScaleCharToQuantum(*p++);
-          image->colormap[i].green=ScaleCharToQuantum(*p++);
-          image->colormap[i].blue=ScaleCharToQuantum(*p++);
+          image->colormap[i].red=(double) ScaleCharToQuantum(*p++);
+          image->colormap[i].green=(double) ScaleCharToQuantum(*p++);
+          image->colormap[i].blue=(double) ScaleCharToQuantum(*p++);
           if (i == opacity)
-            image->colormap[i].alpha=(Quantum) TransparentAlpha;
+            image->colormap[i].alpha=(double) TransparentAlpha;
         }
         colormap=(unsigned char *) RelinquishMagickMemory(colormap);
       }
+    if (image->gamma == 1.0)
+      {
+        for (i=0; i < (ssize_t) image->colors; i++)
+          if (IsPixelInfoGray(image->colormap+i) == MagickFalse)
+            break;
+        (void) SetImageColorspace(image,i == (ssize_t) image->colors ? 
+          GRAYColorspace : RGBColorspace,exception);
+      }
     if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
         break;
@@ -1320,9 +1346,9 @@ static Image *ReadGIFImage(const ImageInfo *image_info,ExceptionInfo *exception)
       Decode image.
     */
     if (image_info->ping != MagickFalse)
-      status=PingGIFImage(image);
+      status=PingGIFImage(image,exception);
     else
-      status=DecodeImage(image,opacity);
+      status=DecodeImage(image,opacity,exception);
     if ((image_info->ping == MagickFalse) && (status == MagickFalse))
       {
         global_colormap=(unsigned char *) RelinquishMagickMemory(
@@ -1448,9 +1474,6 @@ ModuleExport void UnregisterGIFImage(void)
 static MagickBooleanType WriteGIFImage(const ImageInfo *image_info,Image *image,
   ExceptionInfo *exception)
 {
-  Image
-    *next_image;
-
   int
     c;
 
@@ -1529,24 +1552,13 @@ static MagickBooleanType WriteGIFImage(const ImageInfo *image_info,Image *image,
     Determine image bounding box.
   */
   page.width=image->columns;
+  if (image->page.width > page.width)
+    page.width=image->page.width;
   page.height=image->rows;
-  page.x=0;
-  page.y=0;
-  if (write_info->adjoin != MagickFalse)
-    for (next_image=image; next_image != (Image *) NULL; )
-    {
-      page.x=next_image->page.x;
-      page.y=next_image->page.y;
-      if ((next_image->page.width+page.x) > page.width)
-        page.width=next_image->page.width+page.x;
-      if ((next_image->page.height+page.y) > page.height)
-        page.height=next_image->page.height+page.y;
-      next_image=GetNextImageInList(next_image);
-    }
+  if (image->page.height > page.height)
+    page.height=image->page.height;
   page.x=image->page.x;
   page.y=image->page.y;
-  if ((image->page.width != 0) && (image->page.height != 0))
-    page=image->page;
   (void) WriteBlobLSBShort(image,(unsigned short) page.width);
   (void) WriteBlobLSBShort(image,(unsigned short) page.height);
   /*
@@ -1560,13 +1572,13 @@ static MagickBooleanType WriteGIFImage(const ImageInfo *image_info,Image *image,
   one=1;
   do
   {
-    if (IsRGBColorspace(image->colorspace) == MagickFalse)
-      (void) TransformImageColorspace(image,RGBColorspace);
+    if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
+      (void) TransformImageColorspace(image,sRGBColorspace,exception);
     opacity=(-1);
     if (IsImageOpaque(image,exception) != MagickFalse)
       {
         if ((image->storage_class == DirectClass) || (image->colors > 256))
-          (void) SetImageType(image,PaletteType);
+          (void) SetImageType(image,PaletteType,exception);
       }
     else
       {
@@ -1578,7 +1590,7 @@ static MagickBooleanType WriteGIFImage(const ImageInfo *image_info,Image *image,
           Identify transparent colormap index.
         */
         if ((image->storage_class == DirectClass) || (image->colors > 256))
-          (void) SetImageType(image,PaletteBilevelMatteType);
+          (void) SetImageType(image,PaletteBilevelMatteType,exception);
         for (i=0; i < (ssize_t) image->colors; i++)
           if (image->colormap[i].alpha != OpaqueAlpha)
             {
@@ -1596,7 +1608,7 @@ static MagickBooleanType WriteGIFImage(const ImageInfo *image_info,Image *image,
             }
         if (opacity == -1)
           {
-            (void) SetImageType(image,PaletteBilevelMatteType);
+            (void) SetImageType(image,PaletteBilevelMatteType,exception);
             for (i=0; i < (ssize_t) image->colors; i++)
               if (image->colormap[i].alpha != OpaqueAlpha)
                 {
@@ -1628,9 +1640,9 @@ static MagickBooleanType WriteGIFImage(const ImageInfo *image_info,Image *image,
     q=colormap;
     for (i=0; i < (ssize_t) image->colors; i++)
     {
-      *q++=ScaleQuantumToChar(image->colormap[i].red);
-      *q++=ScaleQuantumToChar(image->colormap[i].green);
-      *q++=ScaleQuantumToChar(image->colormap[i].blue);
+      *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].red));
+      *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].green));
+      *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].blue));
     }
     for ( ; i < (ssize_t) (one << bits_per_pixel); i++)
     {
@@ -1649,7 +1661,7 @@ static MagickBooleanType WriteGIFImage(const ImageInfo *image_info,Image *image,
         c|=(bits_per_pixel-1);   /* size of global colormap */
         (void) WriteBlobByte(image,(unsigned char) c);
         for (j=0; j < (ssize_t) image->colors; j++)
-          if (IsPixelPacketEquivalent(&image->background_color,image->colormap+j))
+          if (IsPixelInfoEquivalent(&image->background_color,image->colormap+j))
             break;
         (void) WriteBlobByte(image,(unsigned char)
           (j == (ssize_t) image->colors ? 0 : j));  /* background color */
@@ -1678,25 +1690,24 @@ static MagickBooleanType WriteGIFImage(const ImageInfo *image_info,Image *image,
           0));
         (void) WriteBlobByte(image,(unsigned char) 0x00);
         if ((LocaleCompare(write_info->magick,"GIF87") != 0) &&
-            (GetImageProperty(image,"comment") != (const char *) NULL))
+            (GetImageProperty(image,"comment",exception) != (const char *) NULL))
           {
             const char
               *value;
 
-            register const char
+            register const char 
               *p;
 
             size_t
               count;
-
+    
             /*
-              Write Comment extension.
+              Write comment extension.
             */
             (void) WriteBlobByte(image,(unsigned char) 0x21);
             (void) WriteBlobByte(image,(unsigned char) 0xfe);
-            value=GetImageProperty(image,"comment");
-            p=value;
-            while (strlen(p) != 0)
+            value=GetImageProperty(image,"comment",exception);
+            for (p=value; *p != '\0'; )
             {
               count=MagickMin(strlen(p),255);
               (void) WriteBlobByte(image,(unsigned char) count);
@@ -1723,6 +1734,29 @@ static MagickBooleanType WriteGIFImage(const ImageInfo *image_info,Image *image,
             (void) WriteBlobLSBShort(image,(unsigned short) image->iterations);
             (void) WriteBlobByte(image,(unsigned char) 0x00);
           }
+        if ((image->gamma != 1.0f/2.2f))
+          {
+            char
+              attributes[MaxTextExtent];
+
+            ssize_t
+              length;
+
+            /*
+              Write ImageMagick extension.
+            */
+            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+               "  Writing GIF Extension %s","ImageMagick");
+            (void) WriteBlobByte(image,(unsigned char) 0x21);
+            (void) WriteBlobByte(image,(unsigned char) 0xff);
+            (void) WriteBlobByte(image,(unsigned char) 0x0b);
+            (void) WriteBlob(image,11,(unsigned char *) "ImageMagick");
+            length=FormatLocaleString(attributes,MaxTextExtent,"gamma=%g",
+              image->gamma);
+            (void) WriteBlobByte(image,(unsigned char) length);
+            (void) WriteBlob(image,length,(unsigned char *) attributes);
+            (void) WriteBlobByte(image,(unsigned char) 0x00);
+          }
         ResetImageProfileIterator(image);
         for ( ; ; )
         {
@@ -1764,7 +1798,7 @@ static MagickBooleanType WriteGIFImage(const ImageInfo *image_info,Image *image,
                    /*
                      Write ICC extension.
                    */
-                   (void) WriteBlob(image,11,(unsigned char *)"ICCRGBG1012");
+                   (void) WriteBlob(image,11,(unsigned char *) "ICCRGBG1012");
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                        "  Writing GIF Extension %s","ICCRGBG1012");
                  }
@@ -1772,9 +1806,9 @@ static MagickBooleanType WriteGIFImage(const ImageInfo *image_info,Image *image,
                  if ((LocaleCompare(name,"IPTC") == 0))
                    {
                      /*
-                       write IPTC extension.
+                       Write IPTC extension.
                      */
-                     (void) WriteBlob(image,11,(unsigned char *)"MGKIPTC0000");
+                     (void) WriteBlob(image,11,(unsigned char *) "MGKIPTC0000");
                      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
                          "  Writing GIF Extension %s","MGKIPTC0000");
                    }
@@ -1782,7 +1816,7 @@ static MagickBooleanType WriteGIFImage(const ImageInfo *image_info,Image *image,
                    if ((LocaleCompare(name,"8BIM") == 0))
                      {
                        /*
-                         Write 8BIM extension>
+                         Write 8BIM extension.
                        */
                         (void) WriteBlob(image,11,(unsigned char *)
                           "MGK8BIM0000");
@@ -1794,7 +1828,9 @@ static MagickBooleanType WriteGIFImage(const ImageInfo *image_info,Image *image,
                        char
                          extension[MaxTextExtent];
 
-                       /* write generic extension */
+                       /*
+                         Write generic extension.
+                       */
                        (void) CopyMagickString(extension,name+4,
                          sizeof(extension));
                        (void) WriteBlob(image,11,(unsigned char *) extension);
@@ -1853,7 +1889,8 @@ static MagickBooleanType WriteGIFImage(const ImageInfo *image_info,Image *image,
     */
     c=(int) MagickMax(bits_per_pixel,2);
     (void) WriteBlobByte(image,(unsigned char) c);
-    status=EncodeImage(write_info,image,(size_t) MagickMax(bits_per_pixel,2)+1);
+    status=EncodeImage(write_info,image,(size_t) MagickMax(bits_per_pixel,2)+1,
+      exception);
     if (status == MagickFalse)
       {
         global_colormap=(unsigned char *) RelinquishMagickMemory(