]> granicus.if.org Git - imagemagick/blobdiff - coders/gif.c
(no commit message)
[imagemagick] / coders / gif.c
index 16b424758a8bf18a87d38f0ddc9c83118a3c13b6..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
 /*
@@ -441,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++;
@@ -530,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
@@ -657,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)
@@ -1051,7 +1052,6 @@ static Image *ReadGIFImage(const ImageInfo *image_info,ExceptionInfo *exception)
         /*
           GIF Extension block.
         */
-
         count=ReadBlob(image,1,&c);
         if (count != 1)
           {
@@ -1079,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;
 
@@ -1128,7 +1135,8 @@ static Image *ReadGIFImage(const ImageInfo *image_info,ExceptionInfo *exception)
                 MagickBooleanType
                   i8bim,
                   icc,
-                  iptc;
+                  iptc,
+                  magick;
 
                 StringInfo
                   *profile;
@@ -1139,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++;
@@ -1174,17 +1184,23 @@ static Image *ReadGIFImage(const ImageInfo *image_info,ExceptionInfo *exception)
                 if (profile == (StringInfo *) NULL)
                   ThrowReaderException(ResourceLimitError,
                     "MemoryAllocationFailed");
-                info=(unsigned char *) RelinquishMagickMemory(info);
                 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);
@@ -1227,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;
@@ -1268,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];
             }
         }
@@ -1288,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(
@@ -1308,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;
@@ -1451,9 +1474,6 @@ ModuleExport void UnregisterGIFImage(void)
 static MagickBooleanType WriteGIFImage(const ImageInfo *image_info,Image *image,
   ExceptionInfo *exception)
 {
-  Image
-    *next_image;
-
   int
     c;
 
@@ -1532,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);
   /*
@@ -1563,8 +1572,8 @@ 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)
       {
@@ -1631,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++)
     {
@@ -1652,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 */
@@ -1681,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);
@@ -1726,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 ( ; ; )
         {
@@ -1767,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");
                  }
@@ -1775,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");
                    }
@@ -1785,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");
@@ -1797,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);
@@ -1856,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(