]> granicus.if.org Git - imagemagick/blobdiff - coders/icon.c
(no commit message)
[imagemagick] / coders / icon.c
index 9dd025ea17ac6a06d76adc875f3dbd9aef9a0c64..c8d6d6e6065ddcdb0ce939933a714bbd7e010405 100644 (file)
 %                   Read Microsoft Windows Icon Format                        %
 %                                                                             %
 %                              Software Design                                %
-%                                John Cristy                                  %
+%                                   Cristy                                    %
 %                                 July 1992                                   %
 %                                                                             %
 %                                                                             %
-%  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
+%  Copyright 1999-2015 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  %
@@ -46,6 +46,7 @@
 #include "MagickCore/cache.h"
 #include "MagickCore/colormap.h"
 #include "MagickCore/colorspace.h"
+#include "MagickCore/colorspace-private.h"
 #include "MagickCore/exception.h"
 #include "MagickCore/exception-private.h"
 #include "MagickCore/image.h"
@@ -57,6 +58,7 @@
 #include "MagickCore/monitor.h"
 #include "MagickCore/monitor-private.h"
 #include "MagickCore/nt-base-private.h"
+#include "MagickCore/option.h"
 #include "MagickCore/pixel-accessor.h"
 #include "MagickCore/quantize.h"
 #include "MagickCore/quantum-private.h"
@@ -67,7 +69,7 @@
 /*
   Define declarations.
 */
-#if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__MINGW32__)
+#if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__MINGW32__) || defined(__MINGW64__)
 #define BI_RGB  0
 #define BI_RLE8  1
 #define BI_BITFIELDS  3
@@ -140,8 +142,73 @@ typedef struct _IconInfo
 /*
   Forward declaractions.
 */
+static Image
+  *AutoResizeImage(const Image *,const char *,MagickOffsetType *,
+    ExceptionInfo *);
+
 static MagickBooleanType
   WriteICONImage(const ImageInfo *,Image *,ExceptionInfo *);
+
+Image *AutoResizeImage(const Image *image,const char *option,
+  MagickOffsetType *count,ExceptionInfo *exception)
+{
+  #define MAX_SIZES 16
+
+  char
+    *q;
+
+  const char
+    *p;
+
+  Image
+    *resized,
+    *images;
+
+  register ssize_t
+    i;
+
+  size_t
+    sizes[MAX_SIZES]={256,192,128,96,64,48,40,32,24,16};
+
+  images=NULL;
+  *count=0;
+  i=0;
+  p=option;
+  while (*p != '\0' && i < MAX_SIZES)
+  {
+    size_t
+      size;
+
+    while ((isspace((int) ((unsigned char) *p)) != 0))
+      p++;
+
+    size=(size_t)strtol(p,&q,10);
+    if (p == q || size < 16 || size > 256)
+        return((Image *) NULL);
+
+    p=q;
+    sizes[i++]=size;
+
+    while ((isspace((int) ((unsigned char) *p)) != 0) || (*p == ','))
+      p++;
+  }
+
+  if (i==0)
+    i=10;
+  *count=i;
+  for (i=0; i < *count; i++)
+  {
+    resized=ResizeImage(image,sizes[i],sizes[i],image->filter,exception);
+    if (resized == (Image *) NULL)
+      return(DestroyImageList(images));
+
+    if (images == (Image *) NULL)
+      images=resized;
+    else
+      AppendImageToList(&images,resized);
+  }
+  return(images);
+}
 \f
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -240,6 +307,12 @@ static Image *ReadICONImage(const ImageInfo *image_info,
       ReadBlobLSBShort(image);
     icon_file.directory[i].size=ReadBlobLSBLong(image);
     icon_file.directory[i].offset=ReadBlobLSBLong(image);
+    if (EOFBlob(image) != MagickFalse)
+      {
+        ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
+          image->filename);
+        break;
+      }
   }
   one=1;
   for (i=0; i < icon_file.count; i++)
@@ -256,7 +329,14 @@ static Image *ReadICONImage(const ImageInfo *image_info,
     icon_info.height=(unsigned char) ((int) ReadBlobLSBLong(image)/2);
     icon_info.planes=ReadBlobLSBShort(image);
     icon_info.bits_per_pixel=ReadBlobLSBShort(image);
-    if ((icon_info.planes == 18505) && (icon_info.bits_per_pixel == 21060))
+    if (EOFBlob(image) != MagickFalse)
+      {
+        ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
+          image->filename);
+        break;
+      }
+    if (((icon_info.planes == 18505) && (icon_info.bits_per_pixel == 21060)) || 
+        (icon_info.size == 0x474e5089))
       {
         Image
           *icon_image;
@@ -283,19 +363,20 @@ static Image *ReadICONImage(const ImageInfo *image_info,
         png[14]=(unsigned char) icon_info.bits_per_pixel;
         png[15]=(unsigned char) (icon_info.bits_per_pixel >> 8);
         count=ReadBlob(image,length-16,png+16);
-        if (count != (ssize_t) (length-16))
+        icon_image=(Image *) NULL;
+        if (count > 0)
           {
-            png=(unsigned char *) RelinquishMagickMemory(png);
-            ThrowReaderException(CorruptImageError,
-              "InsufficientImageDataInFile");
+            read_info=CloneImageInfo(image_info);
+            (void) CopyMagickString(read_info->magick,"PNG",MaxTextExtent);
+            icon_image=BlobToImage(read_info,png,length+16,exception);
+            read_info=DestroyImageInfo(read_info);
           }
-        read_info=CloneImageInfo(image_info);
-        (void) CopyMagickString(read_info->magick,"PNG",MaxTextExtent);
-        icon_image=BlobToImage(read_info,png,length+16,exception);
-        read_info=DestroyImageInfo(read_info);
         png=(unsigned char *) RelinquishMagickMemory(png);
         if (icon_image == (Image *) NULL)
           {
+            if (count != (ssize_t) (length-16))
+              ThrowReaderException(CorruptImageError,
+                "InsufficientImageDataInFile");
             image=DestroyImageList(image);
             return((Image *) NULL);
           }
@@ -313,7 +394,7 @@ static Image *ReadICONImage(const ImageInfo *image_info,
         icon_info.y_pixels=ReadBlobLSBLong(image);
         icon_info.number_colors=ReadBlobLSBLong(image);
         icon_info.colors_important=ReadBlobLSBLong(image);
-        image->matte=MagickTrue;
+        image->alpha_trait=BlendPixelTrait;
         image->columns=(size_t) icon_file.directory[i].width;
         if ((ssize_t) image->columns > icon_info.width)
           image->columns=(size_t) icon_info.width;
@@ -342,7 +423,7 @@ static Image *ReadICONImage(const ImageInfo *image_info,
             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
               "   bpp    = %.20g",(double) icon_info.bits_per_pixel);
           }
-      if ((icon_info.number_colors != 0) || (icon_info.bits_per_pixel <= 16))
+      if ((icon_info.number_colors != 0) || (icon_info.bits_per_pixel <= 16U))
         {
           image->storage_class=PseudoClass;
           image->colors=icon_info.number_colors;
@@ -354,19 +435,14 @@ static Image *ReadICONImage(const ImageInfo *image_info,
           register ssize_t
             i;
 
-          size_t
-            number_colors,
-            one;
-
           unsigned char
             *icon_colormap;
 
           /*
             Read Icon raster colormap.
           */
-          one=1;
-          number_colors=one << icon_info.bits_per_pixel;
-          if (AcquireImageColormap(image,number_colors,exception) == MagickFalse)
+          if (AcquireImageColormap(image,image->colors,exception) ==
+              MagickFalse)
             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
           icon_colormap=(unsigned char *) AcquireQuantumMemory((size_t)
             image->colors,4UL*sizeof(*icon_colormap));
@@ -393,6 +469,9 @@ static Image *ReadICONImage(const ImageInfo *image_info,
             (image_info->number_scenes != 0))
           if (image->scene >= (image_info->scene+image_info->number_scenes-1))
             break;
+        status=SetImageExtent(image,image->columns,image->rows,exception);
+        if (status == MagickFalse)
+          return(DestroyImageList(image));
         bytes_per_line=(((image->columns*icon_info.bits_per_pixel)+31) &
           ~31) >> 3;
         (void) bytes_per_line;
@@ -691,24 +770,23 @@ ModuleExport size_t RegisterICONImage(void)
   entry=SetMagickInfo("CUR");
   entry->decoder=(DecodeImageHandler *) ReadICONImage;
   entry->encoder=(EncodeImageHandler *) WriteICONImage;
-  entry->adjoin=MagickFalse;
-  entry->seekable_stream=MagickTrue;
+  entry->flags^=CoderAdjoinFlag;
+  entry->flags|=CoderSeekableStreamFlag;
   entry->description=ConstantString("Microsoft icon");
   entry->module=ConstantString("CUR");
   (void) RegisterMagickInfo(entry);
   entry=SetMagickInfo("ICO");
   entry->decoder=(DecodeImageHandler *) ReadICONImage;
   entry->encoder=(EncodeImageHandler *) WriteICONImage;
-  entry->adjoin=MagickTrue;
-  entry->seekable_stream=MagickTrue;
+  entry->flags|=CoderSeekableStreamFlag;
   entry->description=ConstantString("Microsoft icon");
   entry->module=ConstantString("ICON");
   (void) RegisterMagickInfo(entry);
   entry=SetMagickInfo("ICON");
   entry->decoder=(DecodeImageHandler *) ReadICONImage;
   entry->encoder=(EncodeImageHandler *) WriteICONImage;
-  entry->adjoin=MagickFalse;
-  entry->seekable_stream=MagickTrue;
+  entry->flags^=CoderAdjoinFlag;
+  entry->flags|=CoderSeekableStreamFlag;
   entry->description=ConstantString("Microsoft icon");
   entry->module=ConstantString("ICON");
   (void) RegisterMagickInfo(entry);
@@ -756,6 +834,10 @@ ModuleExport void UnregisterICONImage(void)
 %  image format, version 3 for Windows or (if the image has a matte channel)
 %  version 4.
 %
+%  It encodes any subimage as a compressed PNG image ("BI_PNG)", only when its
+%  dimensions are 256x256 and image->compression is undefined or is defined as
+%  ZipCompression.
+%
 %  The format of the WriteICONImage method is:
 %
 %      MagickBooleanType WriteICONImage(const ImageInfo *image_info,
@@ -773,6 +855,9 @@ ModuleExport void UnregisterICONImage(void)
 static MagickBooleanType WriteICONImage(const ImageInfo *image_info,
   Image *image,ExceptionInfo *exception)
 {
+  const char
+    *option;
+
   IconFile
     icon_file;
 
@@ -780,6 +865,7 @@ static MagickBooleanType WriteICONImage(const ImageInfo *image_info,
     icon_info;
 
   Image
+    *images,
     *next;
   
   MagickBooleanType
@@ -824,15 +910,26 @@ static MagickBooleanType WriteICONImage(const ImageInfo *image_info,
   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
   if (status == MagickFalse)
     return(status);
-  scene=0;
-  next=image;
-  do
-  {
-    if ((image->columns > 256L) || (image->rows > 256L))
-      ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
-    scene++;
-    next=SyncNextImageInList(next);
-  } while ((next != (Image *) NULL) && (image_info->adjoin != MagickFalse));
+  images=(Image *) NULL;
+  option=GetImageOption(image_info,"icon:auto-resize");
+  if (option != (const char *) NULL)
+    {
+      images=AutoResizeImage(image,option,&scene,exception);
+      if (images == (Image *) NULL)
+        ThrowWriterException(ImageError,"InvalidDimensions");
+    }
+  else
+    {
+      scene=0;
+      next=image;
+      do
+      {
+        if ((image->columns > 256L) || (image->rows > 256L))
+          ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
+        scene++;
+        next=SyncNextImageInList(next);
+      } while ((next != (Image *) NULL) && (image_info->adjoin != MagickFalse));
+    }
   /*
     Dump out a ICON header template to be properly initialized later.
   */
@@ -842,7 +939,7 @@ static MagickBooleanType WriteICONImage(const ImageInfo *image_info,
   (void) ResetMagickMemory(&icon_file,0,sizeof(icon_file));
   (void) ResetMagickMemory(&icon_info,0,sizeof(icon_info));
   scene=0;
-  next=image;
+  next=(images != (Image *) NULL) ? images : image;
   do
   {
     (void) WriteBlobByte(image,icon_file.directory[scene].width);
@@ -859,10 +956,12 @@ static MagickBooleanType WriteICONImage(const ImageInfo *image_info,
     next=SyncNextImageInList(next);
   } while ((next != (Image *) NULL) && (image_info->adjoin != MagickFalse));
   scene=0;
-  next=image;
+  next=(images != (Image *) NULL) ? images : image;
   do
   {
-    if (next->compression == ZipCompression)
+    if ((next->columns > 255L) && (next->rows > 255L) &&
+        ((next->compression == UndefinedCompression) ||
+        (next->compression == ZipCompression)))
       {
         Image
           *write_image;
@@ -876,25 +975,30 @@ static MagickBooleanType WriteICONImage(const ImageInfo *image_info,
         unsigned char
           *png;
 
-        /*
-          Icon image encoded as a compressed PNG image.
-        */
         write_image=CloneImage(next,0,0,MagickTrue,exception);
         if (write_image == (Image *) NULL)
-          return(MagickFalse);
+          {
+            images=DestroyImageList(images);
+            return(MagickFalse);
+          }
         write_info=CloneImageInfo(image_info);
         (void) CopyMagickString(write_info->filename,"PNG:",MaxTextExtent);
 
-        /* Don't write any ancillary chunks except for gAMA and tRNS */
-        (void) SetImageArtifact(write_image,"png:include-chunk",
-           "none,trns,gama");
+        /* Don't write any ancillary chunks except for gAMA */
+        (void) SetImageArtifact(write_image,"png:include-chunk","none,gama");
+
+        /* Only write PNG32 formatted PNG (32-bit RGBA), 8 bits per channel */
+        (void) SetImageArtifact(write_image,"png:format","png32");
 
         png=(unsigned char *) ImageToBlob(write_info,write_image,&length,
           exception);
         write_image=DestroyImage(write_image);
         write_info=DestroyImageInfo(write_info);
         if (png == (unsigned char *) NULL)
-          return(MagickFalse);
+          {
+            images=DestroyImageList(images);
+            return(MagickFalse);
+          }
         icon_file.directory[scene].width=0;
         icon_file.directory[scene].height=0;
         icon_file.directory[scene].colors=0;
@@ -911,8 +1015,7 @@ static MagickBooleanType WriteICONImage(const ImageInfo *image_info,
         /*
           Initialize ICON raster file header.
         */
-        if (next->colorspace != RGBColorspace)
-          (void) TransformImageColorspace(next,RGBColorspace,exception);
+        (void) TransformImageColorspace(next,sRGBColorspace,exception);
         icon_info.file_size=14+12+28;
         icon_info.offset_bits=icon_info.file_size;
         icon_info.compression=BI_RGB;
@@ -1000,7 +1103,10 @@ static MagickBooleanType WriteICONImage(const ImageInfo *image_info,
         pixels=(unsigned char *) AcquireQuantumMemory((size_t)
           icon_info.image_size,sizeof(*pixels));
         if (pixels == (unsigned char *) NULL)
-          ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
+          {
+            images=DestroyImageList(images);
+            ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
+          }
         (void) ResetMagickMemory(pixels,0,(size_t) icon_info.image_size);
         switch (icon_info.bits_per_pixel)
         {
@@ -1128,7 +1234,7 @@ static MagickBooleanType WriteICONImage(const ImageInfo *image_info,
                 *q++=ScaleQuantumToChar(GetPixelBlue(next,p));
                 *q++=ScaleQuantumToChar(GetPixelGreen(next,p));
                 *q++=ScaleQuantumToChar(GetPixelRed(next,p));
-                if (next->matte == MagickFalse)
+                if (next->alpha_trait == UndefinedPixelTrait)
                   *q++=ScaleQuantumToChar(QuantumRange);
                 else
                   *q++=ScaleQuantumToChar(GetPixelAlpha(next,p));
@@ -1181,7 +1287,11 @@ static MagickBooleanType WriteICONImage(const ImageInfo *image_info,
             icon_colormap=(unsigned char *) AcquireQuantumMemory((size_t)
               (1UL << icon_info.bits_per_pixel),4UL*sizeof(*icon_colormap));
             if (icon_colormap == (unsigned char *) NULL)
-              ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
+              {
+                images=DestroyImageList(images);
+                ThrowWriterException(ResourceLimitError,
+                  "MemoryAllocationFailed");
+              }
             q=icon_colormap;
             for (i=0; i < (ssize_t) next->colors; i++)
             {
@@ -1218,7 +1328,7 @@ static MagickBooleanType WriteICONImage(const ImageInfo *image_info,
           for (x=0; x < (ssize_t) next->columns; x++)
           {
             byte<<=1;
-            if ((next->matte == MagickTrue) &&
+            if ((next->alpha_trait != UndefinedPixelTrait) &&
                 (GetPixelAlpha(next,p) == (Quantum) TransparentAlpha))
               byte|=0x01;
             bit++;
@@ -1238,11 +1348,11 @@ static MagickBooleanType WriteICONImage(const ImageInfo *image_info,
       }
     if (GetNextImageInList(next) == (Image *) NULL)
       break;
-    next=SyncNextImageInList(next);
     status=SetImageProgress(next,SaveImagesTag,scene++,
       GetImageListLength(next));
     if (status == MagickFalse)
       break;
+    next=SyncNextImageInList(next);
   } while ((next != (Image *) NULL) && (image_info->adjoin != MagickFalse));
   offset=SeekBlob(image,0,SEEK_SET);
   (void) offset;
@@ -1250,7 +1360,7 @@ static MagickBooleanType WriteICONImage(const ImageInfo *image_info,
   (void) WriteBlobLSBShort(image,1);
   (void) WriteBlobLSBShort(image,(unsigned short) (scene+1));
   scene=0;
-  next=image;
+  next=(images != (Image *) NULL) ? images : image;
   do
   {
     (void) WriteBlobByte(image,icon_file.directory[scene].width);
@@ -1267,5 +1377,6 @@ static MagickBooleanType WriteICONImage(const ImageInfo *image_info,
     next=SyncNextImageInList(next);
   } while ((next != (Image *) NULL) && (image_info->adjoin != MagickFalse));
   (void) CloseBlob(image);
+  images=DestroyImageList(images);
   return(MagickTrue);
 }