]> granicus.if.org Git - imagemagick/blobdiff - coders/psd.c
Fixed memory leak that was detected by oss-fuzz.
[imagemagick] / coders / psd.c
index ccbd10ad52564cfbceb599e7655aed42c4ca92bf..4c31d4eecda952d8cbb11aa4750c98fca25354da 100644 (file)
@@ -26,7 +26,7 @@
 %  You may not use this file except in compliance with the License.  You may  %
 %  obtain a copy of the License at                                            %
 %                                                                             %
-%    https://www.imagemagick.org/script/license.php                           %
+%    https://imagemagick.org/script/license.php                               %
 %                                                                             %
 %  Unless required by applicable law or agreed to in writing, software        %
 %  distributed under the License is distributed on an "AS IS" BASIS,          %
@@ -36,6 +36,7 @@
 %                                                                             %
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %
+% Photoshop spec @ https://www.adobe.com/devnet-apps/photoshop/fileformatashtml
 %
 */
 \f
@@ -163,7 +164,7 @@ typedef struct _LayerInfo
   unsigned char
     clipping,
     flags,
-    name[256],
+    name[257],
     visible;
 
   unsigned short
@@ -318,7 +319,7 @@ static MagickBooleanType CorrectPSDAlphaBlend(const ImageInfo *image_info,
     return(MagickTrue);
   status=MagickTrue;
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-#pragma omp parallel for schedule(static,4) shared(status) \
+#pragma omp parallel for schedule(static) shared(status) \
   magick_number_threads(image,image,image->rows,1)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
@@ -397,7 +398,7 @@ static MagickBooleanType ApplyPSDLayerOpacity(Image *image,Quantum opacity,
     (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
   status=MagickTrue;
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-#pragma omp parallel for schedule(static,4) shared(status) \
+#pragma omp parallel for schedule(static) shared(status) \
   magick_number_threads(image,image,image->rows,1)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
@@ -451,14 +452,13 @@ static MagickBooleanType ApplyPSDOpacityMask(Image *image,const Image *mask,
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
       "  applying opacity mask");
-  complete_mask=CloneImage(image,image->columns,image->rows,MagickTrue,
-    exception);
+  complete_mask=CloneImage(image,0,0,MagickTrue,exception);
   if (complete_mask == (Image *) NULL)
     return(MagickFalse);
   complete_mask->alpha_trait=BlendPixelTrait;
   GetPixelInfo(complete_mask,&color);
-  color.red=background;
-  SetImageColor(complete_mask,&color,exception);
+  color.red=(MagickRealType) background;
+  (void) SetImageColor(complete_mask,&color,exception);
   status=CompositeImage(complete_mask,mask,OverCompositeOp,MagickTrue,
     mask->page.x-image->page.x,mask->page.y-image->page.y,exception);
   if (status == MagickFalse)
@@ -468,7 +468,7 @@ static MagickBooleanType ApplyPSDOpacityMask(Image *image,const Image *mask,
     }
   image->alpha_trait=BlendPixelTrait;
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-#pragma omp parallel for schedule(static,4) shared(status) \
+#pragma omp parallel for schedule(static) shared(status) \
   magick_number_threads(image,image,image->rows,1)
 #endif
   for (y=0; y < (ssize_t) image->rows; y++)
@@ -497,7 +497,7 @@ static MagickBooleanType ApplyPSDOpacityMask(Image *image,const Image *mask,
         alpha,
         intensity;
 
-      alpha=GetPixelAlpha(image,q);
+      alpha=(MagickRealType) GetPixelAlpha(image,q);
       intensity=GetPixelIntensity(complete_mask,p);
       if (revert == MagickFalse)
         SetPixelAlpha(image,ClampToQuantum(intensity*(QuantumScale*alpha)),q);
@@ -531,7 +531,7 @@ static void PreservePSDOpacityMask(Image *image,LayerInfo* layer_info,
   random_info=AcquireRandomInfo();
   key_info=GetRandomKey(random_info,2+1);
   key=(char *) GetStringInfoDatum(key_info);
-  key[8]=layer_info->mask.background;
+  key[8]=(char ) layer_info->mask.background;
   key[9]='\0';
   layer_info->mask.image->page.x+=layer_info->page.x;
   layer_info->mask.image->page.y+=layer_info->page.y;
@@ -760,6 +760,9 @@ static StringInfo *ParseImageResourceBlocks(Image *image,
   const unsigned char
     *p;
 
+  ssize_t
+    offset;
+
   StringInfo
     *profile;
 
@@ -791,7 +794,8 @@ static StringInfo *ParseImageResourceBlocks(Image *image,
     if (p > (blocks+length-4))
       break;
     p=PushLongPixel(MSBEndian,p,&count);
-    if ((p+count) > (blocks+length))
+    offset=(ssize_t) count;
+    if (((p+offset) < blocks) || ((p+offset) > (blocks+length)))
       break;
     switch (id)
     {
@@ -806,7 +810,7 @@ static StringInfo *ParseImageResourceBlocks(Image *image,
         /*
           Resolution info.
         */
-        if (count < 16)
+        if (offset < 16)
           break;
         p=PushShortPixel(MSBEndian,p,&resolution);
         image->resolution.x=(double) resolution;
@@ -829,18 +833,18 @@ static StringInfo *ParseImageResourceBlocks(Image *image,
       }
       case 0x0421:
       {
-        if ((count > 3) && (*(p+4) == 0))
+        if ((offset > 4) && (*(p+4) == 0))
           *has_merged_image=MagickFalse;
-        p+=count;
+        p+=offset;
         break;
       }
       default:
       {
-        p+=count;
+        p+=offset;
         break;
       }
     }
-    if ((count & 0x01) != 0)
+    if ((offset & 0x01) != 0)
       p++;
   }
   return(profile);
@@ -933,7 +937,7 @@ static inline void SetPSDPixel(Image *image,const size_t channels,
             SetPixelIndex(image,ScaleQuantumToShort(pixel),q);
         }
       color=image->colormap+(ssize_t) ConstrainColormapIndex(image,
-        GetPixelIndex(image,q),exception);
+        (ssize_t) GetPixelIndex(image,q),exception);
       if ((type == 0) && (channels > 1))
         return;
       else
@@ -988,7 +992,7 @@ static inline void SetPSDPixel(Image *image,const size_t channels,
 }
 
 static MagickBooleanType ReadPSDChannelPixels(Image *image,
-  const size_t channels,const size_t row,const ssize_t type,
+  const size_t channels,const ssize_t row,const ssize_t type,
   const unsigned char *pixels,ExceptionInfo *exception)
 {
   Quantum
@@ -1042,10 +1046,10 @@ static MagickBooleanType ReadPSDChannelPixels(Image *image,
           bit,
           number_bits;
 
-        number_bits=image->columns-x;
+        number_bits=(ssize_t) image->columns-x;
         if (number_bits > 8)
           number_bits=8;
-        for (bit = 0; bit < number_bits; bit++)
+        for (bit = 0; bit < (ssize_t) number_bits; bit++)
         {
           SetPSDPixel(image,channels,type,packet_size,(((unsigned char) pixel)
             & (0x01 << (7-bit))) != 0 ? 0 : QuantumRange,q,exception);
@@ -1067,10 +1071,10 @@ static MagickBooleanType ReadPSDChannelRaw(Image *image,const size_t channels,
     status;
 
   size_t
-    count,
     row_size;
 
   ssize_t
+    count,
     y;
 
   unsigned char
@@ -1092,8 +1096,11 @@ static MagickBooleanType ReadPSDChannelRaw(Image *image,const size_t channels,
     status=MagickFalse;
 
     count=ReadBlob(image,row_size,pixels);
-    if (count != row_size)
-      break;
+    if (count != (ssize_t) row_size)
+      {
+        status=MagickFalse;
+        break;
+      }
 
     status=ReadPSDChannelPixels(image,channels,y,type,pixels,exception);
     if (status == MagickFalse)
@@ -1160,7 +1167,7 @@ static MagickBooleanType ReadPSDChannelRLE(Image *image,const PSDInfo *psd_info,
     if ((MagickOffsetType) length < sizes[y])
       length=(size_t) sizes[y];
 
-  if (length > (row_size+512)) // arbitrary number
+  if (length > (row_size+2048)) /* arbitrary number */
     {
       pixels=(unsigned char *) RelinquishMagickMemory(pixels);
       ThrowBinaryException(ResourceLimitError,"InvalidLength",image->filename);
@@ -1174,7 +1181,7 @@ static MagickBooleanType ReadPSDChannelRLE(Image *image,const PSDInfo *psd_info,
         image->filename);
     }
 
-  (void) ResetMagickMemory(compact_pixels,0,length*sizeof(*compact_pixels));
+  (void) memset(compact_pixels,0,length*sizeof(*compact_pixels));
 
   status=MagickTrue;
   for (y=0; y < (ssize_t) image->rows; y++)
@@ -1232,6 +1239,9 @@ static MagickBooleanType ReadPSDChannelZip(Image *image,const size_t channels,
     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
        "      layer data is ZIP compressed");
 
+  if ((MagickSizeType) compact_size > GetBlobSize(image))
+    ThrowBinaryException(CorruptImageError,"UnexpectedEndOfFile",
+      image->filename);
   compact_pixels=(unsigned char *) AcquireQuantumMemory(compact_size,
     sizeof(*compact_pixels));
   if (compact_pixels == (unsigned char *) NULL)
@@ -1257,7 +1267,7 @@ static MagickBooleanType ReadPSDChannelZip(Image *image,const size_t channels,
         image->filename);
     }
 
-  ResetMagickMemory(&stream,0,sizeof(stream));
+  memset(&stream,0,sizeof(stream));
   stream.data_type=Z_BINARY;
   stream.next_in=(Bytef *)compact_pixels;
   stream.avail_in=(uInt) compact_size;
@@ -1299,10 +1309,12 @@ static MagickBooleanType ReadPSDChannelZip(Image *image,const size_t channels,
               p[2]+=p[0]+((p[1]+p[3]) >> 8);
               p[3]+=p[1];
             }
-          // else if (packet_size == 4)
-          //   {
-          //     TODO: Figure out what to do there.
-          //   }
+          /*
+          else if (packet_size == 4)
+             {
+               TODO: Figure out what to do there.
+             }
+          */
           else
             *(p+1)+=*p;
           p+=packet_size;
@@ -1361,14 +1373,15 @@ static MagickBooleanType ReadPSDChannel(Image *image,
           (layer_info->mask.flags > 2) || ((layer_info->mask.flags & 0x02) &&
            (IsStringTrue(option) == MagickFalse)))
         {
-          SeekBlob(image,layer_info->channel_info[channel].size-2,SEEK_CUR);
+          (void) SeekBlob(image,(MagickOffsetType)
+            layer_info->channel_info[channel].size-2,SEEK_CUR);
           return(MagickTrue);
         }
       mask=CloneImage(image,layer_info->mask.page.width,
         layer_info->mask.page.height,MagickFalse,exception);
       if (mask != (Image *) NULL)
         {
-          SetImageType(mask,GrayscaleType,exception);
+          (void) SetImageType(mask,GrayscaleType,exception);
           channel_image=mask;
         }
     }
@@ -1379,7 +1392,7 @@ static MagickBooleanType ReadPSDChannel(Image *image,
   {
     case Raw:
       status=ReadPSDChannelRaw(channel_image,psd_info->channels,
-        layer_info->channel_info[channel].type,exception);
+        (ssize_t) layer_info->channel_info[channel].type,exception);
       break;
     case RLE:
       {
@@ -1391,7 +1404,7 @@ static MagickBooleanType ReadPSDChannel(Image *image,
           ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
             image->filename);
         status=ReadPSDChannelRLE(channel_image,psd_info,
-          layer_info->channel_info[channel].type,sizes,exception);
+          (ssize_t) layer_info->channel_info[channel].type,sizes,exception);
         sizes=(MagickOffsetType *) RelinquishMagickMemory(sizes);
       }
       break;
@@ -1399,7 +1412,7 @@ static MagickBooleanType ReadPSDChannel(Image *image,
     case ZipWithoutPrediction:
 #ifdef MAGICKCORE_ZLIB_DELEGATE
       status=ReadPSDChannelZip(channel_image,layer_info->channels,
-        layer_info->channel_info[channel].type,compression,
+        (ssize_t) layer_info->channel_info[channel].type,compression,
         layer_info->channel_info[channel].size-2,exception);
 #else
       (void) ThrowMagickException(exception,GetMagickModule(),
@@ -1413,15 +1426,21 @@ static MagickBooleanType ReadPSDChannel(Image *image,
       break;
   }
 
-  SeekBlob(image,offset+layer_info->channel_info[channel].size-2,SEEK_SET);
+  (void) SeekBlob(image,offset+layer_info->channel_info[channel].size-2,
+    SEEK_SET);
   if (status == MagickFalse)
     {
       if (mask != (Image *) NULL)
-        DestroyImage(mask);
+        (void) DestroyImage(mask);
       ThrowBinaryException(CoderError,"UnableToDecompressImage",
         image->filename);
     }
-  layer_info->mask.image=mask;
+  if (mask != (Image *) NULL)
+    {
+      if (layer_info->mask.image != (Image *) NULL)
+        layer_info->mask.image=DestroyImage(layer_info->mask.image);
+      layer_info->mask.image=mask;
+    }
   return(status);
 }
 
@@ -1485,8 +1504,8 @@ static MagickBooleanType ReadPSDLayer(Image *image,const ImageInfo *image_info,
     if (layer_info->channel_info[j].type == -1)
       layer_info->image->alpha_trait=BlendPixelTrait;
 
-    status=ReadPSDChannel(layer_info->image,image_info,psd_info,layer_info,j,
-      compression,exception);
+    status=ReadPSDChannel(layer_info->image,image_info,psd_info,layer_info,
+      (size_t) j,compression,exception);
 
     if (status == MagickFalse)
       break;
@@ -1539,7 +1558,7 @@ static MagickBooleanType CheckPSDChannels(const PSDInfo *psd_info,
     channel_type|=(GreenChannel | BlueChannel);
   if (psd_info->min_channels >= 4)
     channel_type|=BlackChannel;
-  for (i=0; i < layer_info->channels; i++)
+  for (i=0; i < (ssize_t) layer_info->channels; i++)
   {
     short
       type;
@@ -1551,7 +1570,7 @@ static MagickBooleanType CheckPSDChannels(const PSDInfo *psd_info,
         continue;
       }
     if (type < -1)
-      type=MagickAbsoluteValue(type+2);
+      continue;
     if (type == 0)
       channel_type&=~RedChannel;
     else if (type == 1)
@@ -1569,6 +1588,55 @@ static MagickBooleanType CheckPSDChannels(const PSDInfo *psd_info,
   return(MagickFalse);
 }
 
+static void AttachPSDLayers(Image *image,LayerInfo *layer_info,
+  ssize_t number_layers)
+{
+  register ssize_t
+    i;
+
+  ssize_t
+    j;
+
+  for (i=0; i < number_layers; i++)
+  {
+    if (layer_info[i].image == (Image *) NULL)
+      {
+        for (j=i; j < number_layers - 1; j++)
+          layer_info[j] = layer_info[j+1];
+        number_layers--;
+        i--;
+      }
+  }
+  if (number_layers == 0)
+    {
+      layer_info=(LayerInfo *) RelinquishMagickMemory(layer_info);
+      return;
+    }
+  for (i=0; i < number_layers; i++)
+  {
+    if (i > 0)
+      layer_info[i].image->previous=layer_info[i-1].image;
+    if (i < (number_layers-1))
+      layer_info[i].image->next=layer_info[i+1].image;
+    layer_info[i].image->page=layer_info[i].page;
+  }
+  image->next=layer_info[0].image;
+  layer_info[0].image->previous=image;
+  layer_info=(LayerInfo *) RelinquishMagickMemory(layer_info);
+}
+
+static inline MagickBooleanType PSDSkipImage(const ImageInfo *image_info,
+  const size_t index)
+{
+  if (image_info->number_scenes == 0)
+    return(MagickFalse);
+  if (index < image_info->scene)
+    return(MagickTrue);
+  if (index > image_info->scene+image_info->number_scenes-1)
+    return(MagickTrue);
+  return(MagickFalse);
+}
+
 static MagickBooleanType ReadPSDLayersInternal(Image *image,
   const ImageInfo *image_info,const PSDInfo *psd_info,
   const MagickBooleanType skip_layers,ExceptionInfo *exception)
@@ -1601,356 +1669,339 @@ static MagickBooleanType ReadPSDLayersInternal(Image *image,
       */
       (void) ReadBlobLong(image);
       count=ReadBlob(image,4,(unsigned char *) type);
-      ReversePSDString(image,type,4);
-      status=MagickFalse;
-      if ((count == 0) || (LocaleNCompare(type,"8BIM",4) != 0))
+      if (count == 4)
+        ReversePSDString(image,type,(size_t) count);
+      if ((count != 4) || (LocaleNCompare(type,"8BIM",4) != 0))
         return(MagickTrue);
       else
         {
           count=ReadBlob(image,4,(unsigned char *) type);
-          ReversePSDString(image,type,4);
-          if ((count != 0) && ((LocaleNCompare(type,"Lr16",4) == 0) ||
+          if (count == 4)
+            ReversePSDString(image,type,4);
+          if ((count == 4) && ((LocaleNCompare(type,"Lr16",4) == 0) ||
               (LocaleNCompare(type,"Lr32",4) == 0)))
             size=GetPSDSize(psd_info,image);
           else
             return(MagickTrue);
         }
     }
-  status=MagickTrue;
-  if (size != 0)
-    {
-      layer_info=(LayerInfo *) NULL;
-      number_layers=(short) ReadBlobShort(image);
+  if (size == 0)
+    return(MagickTrue);
 
-      if (number_layers < 0)
-        {
-          /*
-            The first alpha channel in the merged result contains the
-            transparency data for the merged result.
-          */
-          number_layers=MagickAbsoluteValue(number_layers);
-          if (image->debug != MagickFalse)
-            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-              "  negative layer count corrected for");
-          image->alpha_trait=BlendPixelTrait;
-        }
+  layer_info=(LayerInfo *) NULL;
+  number_layers=(ssize_t) ReadBlobSignedShort(image);
 
+  if (number_layers < 0)
+    {
       /*
-        We only need to know if the image has an alpha channel
+        The first alpha channel in the merged result contains the
+        transparency data for the merged result.
       */
-      if (skip_layers != MagickFalse)
-        return(MagickTrue);
+      number_layers=MagickAbsoluteValue(number_layers);
+      if (image->debug != MagickFalse)
+        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+          "  negative layer count corrected for");
+      image->alpha_trait=BlendPixelTrait;
+    }
+
+  /*
+    We only need to know if the image has an alpha channel
+  */
+  if (skip_layers != MagickFalse)
+    return(MagickTrue);
 
+  if (image->debug != MagickFalse)
+    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+      "  image contains %.20g layers",(double) number_layers);
+
+  if (number_layers == 0)
+    ThrowBinaryException(CorruptImageError,"InvalidNumberOfLayers",
+      image->filename);
+
+  layer_info=(LayerInfo *) AcquireQuantumMemory((size_t) number_layers,
+    sizeof(*layer_info));
+  if (layer_info == (LayerInfo *) NULL)
+    {
       if (image->debug != MagickFalse)
         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-          "  image contains %.20g layers",(double) number_layers);
+          "  allocation of LayerInfo failed");
+      ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+        image->filename);
+    }
+  (void) memset(layer_info,0,(size_t) number_layers*sizeof(*layer_info));
 
-      if (number_layers == 0)
-        ThrowBinaryException(CorruptImageError,"InvalidNumberOfLayers",
-          image->filename);
+  for (i=0; i < number_layers; i++)
+  {
+    ssize_t
+      x,
+      y;
 
-      layer_info=(LayerInfo *) AcquireQuantumMemory((size_t) number_layers,
-        sizeof(*layer_info));
-      if (layer_info == (LayerInfo *) NULL)
+    if (image->debug != MagickFalse)
+      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+        "  reading layer #%.20g",(double) i+1);
+    layer_info[i].page.y=(ssize_t) ReadBlobSignedLong(image);
+    layer_info[i].page.x=(ssize_t) ReadBlobSignedLong(image);
+    y=(ssize_t) ReadBlobSignedLong(image);
+    x=(ssize_t) ReadBlobSignedLong(image);
+    layer_info[i].page.width=(size_t) (x-layer_info[i].page.x);
+    layer_info[i].page.height=(size_t) (y-layer_info[i].page.y);
+    layer_info[i].channels=ReadBlobShort(image);
+    if (layer_info[i].channels > MaxPSDChannels)
+      {
+        layer_info=DestroyLayerInfo(layer_info,number_layers);
+        ThrowBinaryException(CorruptImageError,"MaximumChannelsExceeded",
+          image->filename);
+      }
+    if (image->debug != MagickFalse)
+      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+        "    offset(%.20g,%.20g), size(%.20g,%.20g), channels=%.20g",
+        (double) layer_info[i].page.x,(double) layer_info[i].page.y,
+        (double) layer_info[i].page.height,(double)
+        layer_info[i].page.width,(double) layer_info[i].channels);
+    for (j=0; j < (ssize_t) layer_info[i].channels; j++)
+    {
+      layer_info[i].channel_info[j].type=(short) ReadBlobShort(image);
+      if ((layer_info[i].channel_info[j].type < -4) ||
+          (layer_info[i].channel_info[j].type > 4))
         {
-          if (image->debug != MagickFalse)
-            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-              "  allocation of LayerInfo failed");
-          ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+          layer_info=DestroyLayerInfo(layer_info,number_layers);
+          ThrowBinaryException(CorruptImageError,"NoSuchImageChannel",
             image->filename);
         }
-      (void) ResetMagickMemory(layer_info,0,(size_t) number_layers*
-        sizeof(*layer_info));
-
-      for (i=0; i < number_layers; i++)
+      layer_info[i].channel_info[j].size=(size_t) GetPSDSize(psd_info,
+        image);
+      if (image->debug != MagickFalse)
+        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+          "    channel[%.20g]: type=%.20g, size=%.20g",(double) j,
+          (double) layer_info[i].channel_info[j].type,
+          (double) layer_info[i].channel_info[j].size);
+    }
+    if (CheckPSDChannels(psd_info,&layer_info[i]) == MagickFalse)
+      {
+        layer_info=DestroyLayerInfo(layer_info,number_layers);
+        ThrowBinaryException(CorruptImageError,"ImproperImageHeader",
+          image->filename);
+      }
+    count=ReadBlob(image,4,(unsigned char *) type);
+    if (count == 4)
+      ReversePSDString(image,type,4);
+    if ((count != 4) || (LocaleNCompare(type,"8BIM",4) != 0))
       {
-        ssize_t
-          x,
-          y;
-
-        if (image->debug != MagickFalse)
-          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-            "  reading layer #%.20g",(double) i+1);
-        layer_info[i].page.y=ReadBlobSignedLong(image);
-        layer_info[i].page.x=ReadBlobSignedLong(image);
-        y=ReadBlobSignedLong(image);
-        x=ReadBlobSignedLong(image);
-        layer_info[i].page.width=(size_t) (x-layer_info[i].page.x);
-        layer_info[i].page.height=(size_t) (y-layer_info[i].page.y);
-        layer_info[i].channels=ReadBlobShort(image);
-        if (layer_info[i].channels > MaxPSDChannels)
-          {
-            layer_info=DestroyLayerInfo(layer_info,number_layers);
-            ThrowBinaryException(CorruptImageError,"MaximumChannelsExceeded",
-              image->filename);
-          }
         if (image->debug != MagickFalse)
           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-            "    offset(%.20g,%.20g), size(%.20g,%.20g), channels=%.20g",
-            (double) layer_info[i].page.x,(double) layer_info[i].page.y,
-            (double) layer_info[i].page.height,(double)
-            layer_info[i].page.width,(double) layer_info[i].channels);
-        for (j=0; j < (ssize_t) layer_info[i].channels; j++)
-        {
-          layer_info[i].channel_info[j].type=(short) ReadBlobShort(image);
-          if ((layer_info[i].channel_info[j].type < -4) ||
-              (layer_info[i].channel_info[j].type > 4))
-            {
-              layer_info=DestroyLayerInfo(layer_info,number_layers);
-              ThrowBinaryException(CorruptImageError,"NoSuchImageChannel",
-                image->filename);
-            }
-          layer_info[i].channel_info[j].size=(size_t) GetPSDSize(psd_info,
-            image);
-          if (image->debug != MagickFalse)
-            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-              "    channel[%.20g]: type=%.20g, size=%.20g",(double) j,
-              (double) layer_info[i].channel_info[j].type,
-              (double) layer_info[i].channel_info[j].size);
-        }
-        if (CheckPSDChannels(psd_info,&layer_info[i]) == MagickFalse)
-          {
-            layer_info=DestroyLayerInfo(layer_info,number_layers);
-            ThrowBinaryException(CorruptImageError,"ImproperImageHeader",
-              image->filename);
-          }
-        count=ReadBlob(image,4,(unsigned char *) type);
-        ReversePSDString(image,type,4);
-        if ((count == 0) || (LocaleNCompare(type,"8BIM",4) != 0))
-          {
-            if (image->debug != MagickFalse)
-              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                "  layer type was %.4s instead of 8BIM", type);
-            layer_info=DestroyLayerInfo(layer_info,number_layers);
-            ThrowBinaryException(CorruptImageError,"ImproperImageHeader",
-              image->filename);
-          }
-        count=ReadBlob(image,4,(unsigned char *) layer_info[i].blendkey);
-        ReversePSDString(image,layer_info[i].blendkey,4);
-        layer_info[i].opacity=(Quantum) ScaleCharToQuantum((unsigned char)
-          ReadBlobByte(image));
-        layer_info[i].clipping=(unsigned char) ReadBlobByte(image);
-        layer_info[i].flags=(unsigned char) ReadBlobByte(image);
-        layer_info[i].visible=!(layer_info[i].flags & 0x02);
+            "  layer type was %.4s instead of 8BIM", type);
+        layer_info=DestroyLayerInfo(layer_info,number_layers);
+        ThrowBinaryException(CorruptImageError,"ImproperImageHeader",
+          image->filename);
+      }
+    count=ReadBlob(image,4,(unsigned char *) layer_info[i].blendkey);
+    if (count != 4)
+      {
+        layer_info=DestroyLayerInfo(layer_info,number_layers);
+        ThrowBinaryException(CorruptImageError,"ImproperImageHeader",
+          image->filename);
+      }
+    ReversePSDString(image,layer_info[i].blendkey,4);
+    layer_info[i].opacity=(Quantum) ScaleCharToQuantum((unsigned char)
+      ReadBlobByte(image));
+    layer_info[i].clipping=(unsigned char) ReadBlobByte(image);
+    layer_info[i].flags=(unsigned char) ReadBlobByte(image);
+    layer_info[i].visible=!(layer_info[i].flags & 0x02);
+    if (image->debug != MagickFalse)
+      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+        "   blend=%.4s, opacity=%.20g, clipping=%s, flags=%d, visible=%s",
+        layer_info[i].blendkey,(double) layer_info[i].opacity,
+        layer_info[i].clipping ? "true" : "false",layer_info[i].flags,
+        layer_info[i].visible ? "true" : "false");
+    (void) ReadBlobByte(image);  /* filler */
+
+    size=ReadBlobLong(image);
+    if (size != 0)
+      {
+        MagickSizeType
+          combined_length,
+          length;
+
         if (image->debug != MagickFalse)
           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-            "   blend=%.4s, opacity=%.20g, clipping=%s, flags=%d, visible=%s",
-            layer_info[i].blendkey,(double) layer_info[i].opacity,
-            layer_info[i].clipping ? "true" : "false",layer_info[i].flags,
-            layer_info[i].visible ? "true" : "false");
-        (void) ReadBlobByte(image);  /* filler */
-
-        size=ReadBlobLong(image);
-        if (size != 0)
+            "    layer contains additional info");
+        length=ReadBlobLong(image);
+        combined_length=length+4;
+        if (length != 0)
           {
-            MagickSizeType
-              combined_length,
-              length;
-
-            if (image->debug != MagickFalse)
-              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                "    layer contains additional info");
-            length=ReadBlobLong(image);
-            combined_length=length+4;
-            if (length != 0)
-              {
-                /*
-                  Layer mask info.
-                */
-                layer_info[i].mask.page.y=ReadBlobSignedLong(image);
-                layer_info[i].mask.page.x=ReadBlobSignedLong(image);
-                layer_info[i].mask.page.height=(size_t) (ReadBlobSignedLong(image)-
-                  layer_info[i].mask.page.y);
-                layer_info[i].mask.page.width=(size_t) (ReadBlobSignedLong(image)-
-                  layer_info[i].mask.page.x);
-                layer_info[i].mask.background=(unsigned char) ReadBlobByte(
-                  image);
-                layer_info[i].mask.flags=(unsigned char) ReadBlobByte(image);
-                if (!(layer_info[i].mask.flags & 0x01))
-                  {
-                    layer_info[i].mask.page.y=layer_info[i].mask.page.y-
-                      layer_info[i].page.y;
-                    layer_info[i].mask.page.x=layer_info[i].mask.page.x-
-                      layer_info[i].page.x;
-                  }
-                if (image->debug != MagickFalse)
-                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                    "      layer mask: offset(%.20g,%.20g), size(%.20g,%.20g), length=%.20g",
-                    (double) layer_info[i].mask.page.x,(double)
-                    layer_info[i].mask.page.y,(double)
-                    layer_info[i].mask.page.width,(double)
-                    layer_info[i].mask.page.height,(double) ((MagickOffsetType)
-                    length)-18);
-                /*
-                  Skip over the rest of the layer mask information.
-                */
-                if (DiscardBlobBytes(image,(MagickSizeType) (length-18)) == MagickFalse)
-                  {
-                    layer_info=DestroyLayerInfo(layer_info,number_layers);
-                    ThrowBinaryException(CorruptImageError,
-                      "UnexpectedEndOfFile",image->filename);
-                  }
-              }
-            length=ReadBlobLong(image);
-            combined_length+=length+4;
-            if (length != 0)
-              {
-                /*
-                  Layer blending ranges info.
-                */
-                if (image->debug != MagickFalse)
-                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                    "      layer blending ranges: length=%.20g",(double)
-                    ((MagickOffsetType) length));
-                if (DiscardBlobBytes(image,length) == MagickFalse)
-                  {
-                    layer_info=DestroyLayerInfo(layer_info,number_layers);
-                    ThrowBinaryException(CorruptImageError,
-                      "UnexpectedEndOfFile",image->filename);
-                  }
-              }
             /*
-              Layer name.
+              Layer mask info.
             */
-            length=(MagickSizeType) (unsigned char) ReadBlobByte(image);
-            combined_length+=length+1;
-            if (length > 0)
-              (void) ReadBlob(image,(size_t) length++,layer_info[i].name);
-            layer_info[i].name[length]='\0';
-            if (image->debug != MagickFalse)
-              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                "      layer name: %s",layer_info[i].name);
-            if ((length % 4) != 0)
+            layer_info[i].mask.page.y=(ssize_t) ReadBlobSignedLong(image);
+            layer_info[i].mask.page.x=(ssize_t) ReadBlobSignedLong(image);
+            layer_info[i].mask.page.height=(size_t)
+              (ReadBlobSignedLong(image)-layer_info[i].mask.page.y);
+            layer_info[i].mask.page.width=(size_t) (
+              ReadBlobSignedLong(image)-layer_info[i].mask.page.x);
+            layer_info[i].mask.background=(unsigned char) ReadBlobByte(
+              image);
+            layer_info[i].mask.flags=(unsigned char) ReadBlobByte(image);
+            if (!(layer_info[i].mask.flags & 0x01))
               {
-                length=4-(length % 4);
-                combined_length+=length;
-                /* Skip over the padding of the layer name */
-                if (DiscardBlobBytes(image,length) == MagickFalse)
-                  {
-                    layer_info=DestroyLayerInfo(layer_info,number_layers);
-                    ThrowBinaryException(CorruptImageError,
-                      "UnexpectedEndOfFile",image->filename);
-                  }
+                layer_info[i].mask.page.y=layer_info[i].mask.page.y-
+                  layer_info[i].page.y;
+                layer_info[i].mask.page.x=layer_info[i].mask.page.x-
+                  layer_info[i].page.x;
               }
-            length=(MagickSizeType) size-combined_length;
-            if (length > 0)
+            if (image->debug != MagickFalse)
+              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                "      layer mask: offset(%.20g,%.20g), size(%.20g,%.20g), length=%.20g",
+                (double) layer_info[i].mask.page.x,(double)
+                layer_info[i].mask.page.y,(double)
+                layer_info[i].mask.page.width,(double)
+                layer_info[i].mask.page.height,(double) ((MagickOffsetType)
+                length)-18);
+            /*
+              Skip over the rest of the layer mask information.
+            */
+            if (DiscardBlobBytes(image,(MagickSizeType) (length-18)) == MagickFalse)
               {
-                unsigned char
-                  *info;
-
-                if (length > GetBlobSize(image))
-                  {
-                    layer_info=DestroyLayerInfo(layer_info,number_layers);
-                    ThrowBinaryException(CorruptImageError,
-                      "InsufficientImageDataInFile",image->filename);
-                  }
-                layer_info[i].info=AcquireStringInfo((const size_t) length);
-                info=GetStringInfoDatum(layer_info[i].info);
-                (void) ReadBlob(image,(const size_t) length,info);
+                layer_info=DestroyLayerInfo(layer_info,number_layers);
+                ThrowBinaryException(CorruptImageError,
+                  "UnexpectedEndOfFile",image->filename);
               }
           }
-      }
-
-      for (i=0; i < number_layers; i++)
-      {
-        if ((layer_info[i].page.width == 0) || (layer_info[i].page.height == 0))
+        length=ReadBlobLong(image);
+        combined_length+=length+4;
+        if (length != 0)
           {
+            /*
+              Layer blending ranges info.
+            */
             if (image->debug != MagickFalse)
               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                "      layer data is empty");
-            if (layer_info[i].info != (StringInfo *) NULL)
-              layer_info[i].info=DestroyStringInfo(layer_info[i].info);
-            continue;
+                "      layer blending ranges: length=%.20g",(double)
+                ((MagickOffsetType) length));
+            if (DiscardBlobBytes(image,length) == MagickFalse)
+              {
+                layer_info=DestroyLayerInfo(layer_info,number_layers);
+                ThrowBinaryException(CorruptImageError,
+                  "UnexpectedEndOfFile",image->filename);
+              }
           }
-
         /*
-          Allocate layered image.
+          Layer name.
         */
-        layer_info[i].image=CloneImage(image,layer_info[i].page.width,
-          layer_info[i].page.height,MagickFalse,exception);
-        if (layer_info[i].image == (Image *) NULL)
-          {
-            layer_info=DestroyLayerInfo(layer_info,number_layers);
-            if (image->debug != MagickFalse)
-              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                "  allocation of image for layer %.20g failed",(double) i);
-            ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
-              image->filename);
-          }
-        if (layer_info[i].info != (StringInfo *) NULL)
-          {
-            (void) SetImageProfile(layer_info[i].image,"psd:additional-info",
-              layer_info[i].info,exception);
-            layer_info[i].info=DestroyStringInfo(layer_info[i].info);
-          }
-      }
-
-      if (image_info->ping == MagickFalse)
-        {
-          for (i=0; i < number_layers; i++)
+        length=(MagickSizeType) (unsigned char) ReadBlobByte(image);
+        combined_length+=length+1;
+        if (length > 0)
+          (void) ReadBlob(image,(size_t) length++,layer_info[i].name);
+        layer_info[i].name[length]='\0';
+        if (image->debug != MagickFalse)
+          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+            "      layer name: %s",layer_info[i].name);
+        if ((length % 4) != 0)
           {
-            if (layer_info[i].image == (Image *) NULL)
+            length=4-(length % 4);
+            combined_length+=length;
+            /* Skip over the padding of the layer name */
+            if (DiscardBlobBytes(image,length) == MagickFalse)
               {
-                for (j=0; j < layer_info[i].channels; j++)
-                {
-                  if (DiscardBlobBytes(image,(MagickSizeType)
-                      layer_info[i].channel_info[j].size) == MagickFalse)
-                    {
-                      layer_info=DestroyLayerInfo(layer_info,number_layers);
-                      ThrowBinaryException(CorruptImageError,
-                        "UnexpectedEndOfFile",image->filename);
-                    }
-                }
-                continue;
+                layer_info=DestroyLayerInfo(layer_info,number_layers);
+                ThrowBinaryException(CorruptImageError,
+                  "UnexpectedEndOfFile",image->filename);
               }
-
-            if (image->debug != MagickFalse)
-              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-                "  reading data for layer %.20g",(double) i);
-
-            status=ReadPSDLayer(image,image_info,psd_info,&layer_info[i],
-              exception);
-            if (status == MagickFalse)
-              break;
-
-            status=SetImageProgress(image,LoadImagesTag,i,(MagickSizeType)
-              number_layers);
-            if (status == MagickFalse)
-              break;
           }
-        }
-
-      if (status != MagickFalse)
-        {
-          for (i=0; i < number_layers; i++)
+        length=(MagickSizeType) size-combined_length;
+        if (length > 0)
           {
-            if (layer_info[i].image == (Image *) NULL)
+            unsigned char
+              *info;
+
+            if (length > GetBlobSize(image))
               {
-                for (j=i; j < number_layers - 1; j++)
-                  layer_info[j] = layer_info[j+1];
-                number_layers--;
-                i--;
+                layer_info=DestroyLayerInfo(layer_info,number_layers);
+                ThrowBinaryException(CorruptImageError,
+                  "InsufficientImageDataInFile",image->filename);
               }
+            layer_info[i].info=AcquireStringInfo((const size_t) length);
+            info=GetStringInfoDatum(layer_info[i].info);
+            (void) ReadBlob(image,(const size_t) length,info);
           }
+      }
+  }
 
-          if (number_layers > 0)
+  for (i=0; i < number_layers; i++)
+  {
+    if ((layer_info[i].page.width == 0) || (layer_info[i].page.height == 0))
+      {
+        if (image->debug != MagickFalse)
+          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+            "      layer data is empty");
+        if (layer_info[i].info != (StringInfo *) NULL)
+          layer_info[i].info=DestroyStringInfo(layer_info[i].info);
+        continue;
+      }
+
+    /*
+      Allocate layered image.
+    */
+    layer_info[i].image=CloneImage(image,layer_info[i].page.width,
+      layer_info[i].page.height,MagickFalse,exception);
+    if (layer_info[i].image == (Image *) NULL)
+      {
+        layer_info=DestroyLayerInfo(layer_info,number_layers);
+        if (image->debug != MagickFalse)
+          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+            "  allocation of image for layer %.20g failed",(double) i);
+        ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
+          image->filename);
+      }
+    if (layer_info[i].info != (StringInfo *) NULL)
+      {
+        (void) SetImageProfile(layer_info[i].image,"psd:additional-info",
+          layer_info[i].info,exception);
+        layer_info[i].info=DestroyStringInfo(layer_info[i].info);
+      }
+  }
+  if (image_info->ping != MagickFalse)
+    {
+      AttachPSDLayers(image,layer_info,number_layers);
+      return(MagickTrue);
+    }
+  status=MagickTrue;
+  for (i=0; i < number_layers; i++)
+  {
+    if ((layer_info[i].image == (Image *) NULL) ||
+        (PSDSkipImage(image_info,i) != MagickFalse))
+      {
+        for (j=0; j < (ssize_t) layer_info[i].channels; j++)
+        {
+          if (DiscardBlobBytes(image,(MagickSizeType)
+              layer_info[i].channel_info[j].size) == MagickFalse)
             {
-              for (i=0; i < number_layers; i++)
-              {
-                if (i > 0)
-                  layer_info[i].image->previous=layer_info[i-1].image;
-                if (i < (number_layers-1))
-                  layer_info[i].image->next=layer_info[i+1].image;
-                layer_info[i].image->page=layer_info[i].page;
-              }
-              image->next=layer_info[0].image;
-              layer_info[0].image->previous=image;
+              layer_info=DestroyLayerInfo(layer_info,number_layers);
+              ThrowBinaryException(CorruptImageError,
+                "UnexpectedEndOfFile",image->filename);
             }
-          layer_info=(LayerInfo *) RelinquishMagickMemory(layer_info);
         }
-      else
-        layer_info=DestroyLayerInfo(layer_info,number_layers);
-    }
+        continue;
+      }
+
+    if (image->debug != MagickFalse)
+      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+        "  reading data for layer %.20g",(double) i);
+
+    status=ReadPSDLayer(image,image_info,psd_info,&layer_info[i],
+      exception);
+    if (status == MagickFalse)
+      break;
+
+    status=SetImageProgress(image,LoadImagesTag,(MagickOffsetType) i,
+      (MagickSizeType) number_layers);
+    if (status == MagickFalse)
+      break;
+  }
+
+  if (status != MagickFalse)
+    AttachPSDLayers(image,layer_info,number_layers);
+  else
+    layer_info=DestroyLayerInfo(layer_info,number_layers);
 
   return(status);
 }
@@ -1987,6 +2038,8 @@ static MagickBooleanType ReadPSDMergedImage(const ImageInfo *image_info,
   register ssize_t
     i;
 
+  if ((image_info->number_scenes != 0) && (image_info->scene != 0))
+    return(MagickTrue);
   compression=(PSDCompressionType) ReadBlobMSBShort(image);
   image->compression=ConvertPSDCompression(compression);
 
@@ -2009,14 +2062,22 @@ static MagickBooleanType ReadPSDMergedImage(const ImageInfo *image_info,
   status=MagickTrue;
   for (i=0; i < (ssize_t) psd_info->channels; i++)
   {
+    ssize_t
+      type;
+
+    type=i;
+    if ((type == 1) && (psd_info->channels == 2))
+      type=-1;
+
     if (compression == RLE)
-      status=ReadPSDChannelRLE(image,psd_info,i,sizes+(i*image->rows),
+      status=ReadPSDChannelRLE(image,psd_info,type,sizes+(i*image->rows),
         exception);
     else
-      status=ReadPSDChannelRaw(image,psd_info->channels,i,exception);
+      status=ReadPSDChannelRaw(image,psd_info->channels,type,exception);
 
     if (status != MagickFalse)
-      status=SetImageProgress(image,LoadImagesTag,i,psd_info->channels);
+      status=SetImageProgress(image,LoadImagesTag,(MagickOffsetType) i,
+        psd_info->channels);
 
     if (status == MagickFalse)
       break;
@@ -2057,6 +2118,9 @@ static Image *ReadPSDImage(const ImageInfo *image_info,ExceptionInfo *exception)
   register ssize_t
     i;
 
+  size_t
+    imageListLength;
+
   ssize_t
     count;
 
@@ -2087,7 +2151,7 @@ static Image *ReadPSDImage(const ImageInfo *image_info,ExceptionInfo *exception)
   image->endian=MSBEndian;
   count=ReadBlob(image,4,(unsigned char *) psd_info.signature);
   psd_info.version=ReadBlobMSBShort(image);
-  if ((count == 0) || (LocaleNCompare(psd_info.signature,"8BPS",4) != 0) ||
+  if ((count != 4) || (LocaleNCompare(psd_info.signature,"8BPS",4) != 0) ||
       ((psd_info.version != 1) && (psd_info.version != 2)))
     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
   (void) ReadBlob(image,6,psd_info.reserved);
@@ -2123,25 +2187,26 @@ static Image *ReadPSDImage(const ImageInfo *image_info,ExceptionInfo *exception)
   image->columns=psd_info.columns;
   image->rows=psd_info.rows;
   status=SetImageExtent(image,image->columns,image->rows,exception);
+  if (status == MagickFalse)
+    return(DestroyImageList(image));
+  status=ResetImagePixels(image,exception);
   if (status == MagickFalse)
     return(DestroyImageList(image));
   psd_info.min_channels=3;
   if (psd_info.mode == LabMode)
-    SetImageColorspace(image,LabColorspace,exception);
+    (void) SetImageColorspace(image,LabColorspace,exception);
   if (psd_info.mode == CMYKMode)
     {
       psd_info.min_channels=4;
-      SetImageColorspace(image,CMYKColorspace,exception);
-      if (psd_info.channels > 4)
-        SetImageAlphaChannel(image,ActivateAlphaChannel,exception);
+      (void) SetImageColorspace(image,CMYKColorspace,exception);
     }
   else if ((psd_info.mode == BitmapMode) || (psd_info.mode == GrayscaleMode) ||
            (psd_info.mode == DuotoneMode))
     {
       if (psd_info.depth != 32)
         {
-          status=AcquireImageColormap(image,psd_info.depth < 16 ? 256 : 65536,
-            exception);
+          status=AcquireImageColormap(image,(size_t) (psd_info.depth < 16 ?
+            256 : 65536),exception);
           if (status == MagickFalse)
             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
           if (image->debug != MagickFalse)
@@ -2149,13 +2214,8 @@ static Image *ReadPSDImage(const ImageInfo *image_info,ExceptionInfo *exception)
               "  Image colormap allocated");
         }
       psd_info.min_channels=1;
-      SetImageColorspace(image,GRAYColorspace,exception);
-      if (psd_info.channels > 1)
-        SetImageAlphaChannel(image,ActivateAlphaChannel,exception);
+      (void) SetImageColorspace(image,GRAYColorspace,exception);
     }
-  else
-    if (psd_info.channels > 3)
-      SetImageAlphaChannel(image,ActivateAlphaChannel,exception);
   if (psd_info.channels < psd_info.min_channels)
     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
   /*
@@ -2185,20 +2245,20 @@ static Image *ReadPSDImage(const ImageInfo *image_info,ExceptionInfo *exception)
           /*
             Read PSD raster colormap.
           */
-          number_colors=length/3;
+          number_colors=(size_t) length/3;
           if (number_colors > 65536)
             ThrowReaderException(CorruptImageError,"ImproperImageHeader");
           if (AcquireImageColormap(image,number_colors,exception) == MagickFalse)
             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
           for (i=0; i < (ssize_t) image->colors; i++)
-            image->colormap[i].red=ScaleCharToQuantum((unsigned char)
-              ReadBlobByte(image));
+            image->colormap[i].red=(MagickRealType) ScaleCharToQuantum(
+              (unsigned char) ReadBlobByte(image));
           for (i=0; i < (ssize_t) image->colors; i++)
-            image->colormap[i].green=ScaleCharToQuantum((unsigned char)
-              ReadBlobByte(image));
+            image->colormap[i].green=(MagickRealType) ScaleCharToQuantum(
+              (unsigned char) ReadBlobByte(image));
           for (i=0; i < (ssize_t) image->colors; i++)
-            image->colormap[i].blue=ScaleCharToQuantum((unsigned char)
-              ReadBlobByte(image));
+            image->colormap[i].blue=(MagickRealType) ScaleCharToQuantum(
+              (unsigned char) ReadBlobByte(image));
           image->alpha_trait=UndefinedPixelTrait;
         }
     }
@@ -2266,6 +2326,8 @@ static Image *ReadPSDImage(const ImageInfo *image_info,ExceptionInfo *exception)
       if (ReadPSDLayersInternal(image,image_info,&psd_info,skip_layers,
             exception) != MagickTrue)
         {
+          if (profile != (StringInfo *) NULL)
+            profile=DestroyStringInfo(profile);
           (void) CloseBlob(image);
           image=DestroyImageList(image);
           return((Image *) NULL);
@@ -2274,7 +2336,7 @@ static Image *ReadPSDImage(const ImageInfo *image_info,ExceptionInfo *exception)
       /*
          Skip the rest of the layer and mask information.
       */
-      SeekBlob(image,offset+length,SEEK_SET);
+      (void) SeekBlob(image,offset+length,SEEK_SET);
     }
   /*
     If we are only "pinging" the image, then we're done - so return.
@@ -2287,6 +2349,8 @@ static Image *ReadPSDImage(const ImageInfo *image_info,ExceptionInfo *exception)
     }
   if (image_info->ping != MagickFalse)
     {
+      if (profile != (StringInfo *) NULL)
+        profile=DestroyStringInfo(profile);
       (void) CloseBlob(image);
       return(GetFirstImageInList(image));
     }
@@ -2296,17 +2360,20 @@ static Image *ReadPSDImage(const ImageInfo *image_info,ExceptionInfo *exception)
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
       "  reading the precombined layer");
-  if ((has_merged_image != MagickFalse) || (GetImageListLength(image) == 1))
+  imageListLength=GetImageListLength(image);
+  if ((has_merged_image != MagickFalse) || (imageListLength == 1))
     has_merged_image=(MagickBooleanType) ReadPSDMergedImage(image_info,image,
       &psd_info,exception);
-  if ((has_merged_image == MagickFalse) && (GetImageListLength(image) == 1) &&
+  if ((has_merged_image == MagickFalse) && (imageListLength == 1) &&
       (length != 0))
     {
-      SeekBlob(image,offset,SEEK_SET);
+      (void) SeekBlob(image,offset,SEEK_SET);
       status=ReadPSDLayersInternal(image,image_info,&psd_info,MagickFalse,
         exception);
       if (status != MagickTrue)
         {
+          if (profile != (StringInfo *) NULL)
+            profile=DestroyStringInfo(profile);
           (void) CloseBlob(image);
           image=DestroyImageList(image);
           return((Image *) NULL);
@@ -2317,18 +2384,32 @@ static Image *ReadPSDImage(const ImageInfo *image_info,ExceptionInfo *exception)
       Image
         *merged;
 
-      if (GetImageListLength(image) == 1)
-        ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
-      SetImageAlphaChannel(image,TransparentAlphaChannel,exception);
-      image->background_color.alpha=TransparentAlpha;
+      if (imageListLength == 1)
+        {
+          if (profile != (StringInfo *) NULL)
+            profile=DestroyStringInfo(profile);
+          ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
+        }
+      image->background_color.alpha=(MagickRealType) TransparentAlpha;
       image->background_color.alpha_trait=BlendPixelTrait;
+      (void) SetImageBackgroundColor(image,exception);
       merged=MergeImageLayers(image,FlattenLayer,exception);
       ReplaceImageInList(&image,merged);
     }
   if (profile != (StringInfo *) NULL)
     {
-      (void) SetImageProfile(image,GetStringInfoName(profile),profile,
-        exception);
+      Image
+        *next;
+
+      i=0;
+      next=image;
+      while (next != (Image *) NULL)
+      {
+        if (PSDSkipImage(image_info,i++) == MagickFalse)
+          (void) SetImageProfile(next,GetStringInfoName(profile),profile,
+            exception);
+        next=next->next;
+      }
       profile=DestroyStringInfo(profile);
     }
   (void) CloseBlob(image);
@@ -2442,21 +2523,21 @@ static inline ssize_t SetPSDOffset(const PSDInfo *psd_info,Image *image,
 }
 
 static inline ssize_t WritePSDOffset(const PSDInfo *psd_info,Image *image,
-  const MagickSizeType size,const MagickSizeType offset)
+  const MagickSizeType size,const MagickOffsetType offset)
 {
-  MagickSizeType
+  MagickOffsetType
     current_offset;
 
   ssize_t
     result;
 
   current_offset=TellBlob(image);
-  SeekBlob(image,offset,SEEK_SET);
+  (void) SeekBlob(image,offset,SEEK_SET);
   if (psd_info->version == 1)
     result=WriteBlobMSBShort(image,(unsigned short) size);
   else
     result=WriteBlobMSBLong(image,(unsigned int) size);
-  SeekBlob(image,current_offset,SEEK_SET);
+  (void) SeekBlob(image,current_offset,SEEK_SET);
   return(result);
 }
 
@@ -2469,18 +2550,18 @@ static inline ssize_t SetPSDSize(const PSDInfo *psd_info,Image *image,
 }
 
 static inline ssize_t WritePSDSize(const PSDInfo *psd_info,Image *image,
-  const MagickSizeType size,const MagickSizeType offset)
+  const MagickSizeType size,const MagickOffsetType offset)
 {
-  MagickSizeType
+  MagickOffsetType
     current_offset;
 
   ssize_t
     result;
 
   current_offset=TellBlob(image);
-  SeekBlob(image,offset,SEEK_SET);
-  result=SetPSDSize(psd_info, image, size);
-  SeekBlob(image,current_offset,SEEK_SET);
+  (void) SeekBlob(image,offset,SEEK_SET);
+  result=SetPSDSize(psd_info,image,size);
+  (void) SeekBlob(image,current_offset,SEEK_SET);
   return(result);
 }
 
@@ -2608,17 +2689,17 @@ static size_t WriteCompressionStart(const PSDInfo *psd_info,Image *image,
 
   if (compression == RLECompression)
     {
-      length=WriteBlobShort(image,RLE);
+      length=(size_t) WriteBlobShort(image,RLE);
       for (i=0; i < channels; i++)
         for (y=0; y < (ssize_t) next_image->rows; y++)
           length+=SetPSDOffset(psd_info,image,0);
     }
 #ifdef MAGICKCORE_ZLIB_DELEGATE
   else if (compression == ZipCompression)
-    length=WriteBlobShort(image,ZipWithoutPrediction);
+    length=(size_t) WriteBlobShort(image,ZipWithoutPrediction);
 #endif
   else
-    length=WriteBlobShort(image,Raw);
+    length=(size_t) WriteBlobShort(image,Raw);
   return(length);
 }
 
@@ -2628,9 +2709,6 @@ static size_t WritePSDChannel(const PSDInfo *psd_info,
   MagickOffsetType size_offset,const MagickBooleanType separate,
   const CompressionType compression,ExceptionInfo *exception)
 {
-  int
-    y;
-
   MagickBooleanType
     monochrome;
 
@@ -2647,6 +2725,9 @@ static size_t WritePSDChannel(const PSDInfo *psd_info,
     count,
     length;
 
+  ssize_t
+    y;
+
   unsigned char
     *pixels;
 
@@ -2691,7 +2772,7 @@ static size_t WritePSDChannel(const PSDInfo *psd_info,
           quantum_info=DestroyQuantumInfo(quantum_info);
           return(0);
         }
-      ResetMagickMemory(&stream,0,sizeof(stream));
+      memset(&stream,0,sizeof(stream));
       stream.data_type=Z_BINARY;
       level=Z_DEFAULT_COMPRESSION;
       if ((image_info->quality > 0 && image_info->quality < 10))
@@ -2815,13 +2896,14 @@ static size_t WritePSDChannels(const PSDInfo *psd_info,
       if (next_image->storage_class != PseudoClass)
         {
           if (IsImageGray(next_image) == MagickFalse)
-            channels=next_image->colorspace == CMYKColorspace ? 4 : 3;
+            channels=(size_t) (next_image->colorspace == CMYKColorspace ? 4 :
+              3);
           if (next_image->alpha_trait != UndefinedPixelTrait)
             channels++;
         }
       rows_offset=TellBlob(image)+2;
       count+=WriteCompressionStart(psd_info,image,next_image,compression,
-        channels);
+        (ssize_t) channels);
       offset_length=(next_image->rows*(psd_info->version == 1 ? 2 : 4));
     }
   size_offset+=2;
@@ -3007,7 +3089,7 @@ static inline size_t WriteChannelSize(const PSDInfo *psd_info,Image *image,
   size_t
     count;
 
-  count=(size_t) WriteBlobShort(image,channel);
+  count=(size_t) WriteBlobShort(image,(const unsigned short) channel);
   count+=SetPSDSize(psd_info,image,0);
   return(count);
 }
@@ -3056,7 +3138,7 @@ static void RemoveICCProfileFromResourceBlock(StringInfo *bim_profile)
         if ((quantum >= 12) && (quantum < (ssize_t) length))
           {
             if ((q+quantum < (datum+length-16)))
-              (void) CopyMagickMemory(q,q+quantum,length-quantum-(q-datum));
+              (void) memmove(q,q+quantum,length-quantum-(q-datum));
             SetStringInfoLength(bim_profile,length-quantum);
           }
         break;
@@ -3111,7 +3193,7 @@ static void RemoveResolutionFromResourceBlock(StringInfo *bim_profile)
     if ((id == 0x000003ed) && (cnt < (ssize_t) (length-12)) &&
         ((ssize_t) length-(cnt+12)-(q-datum)) > 0)
       {
-        (void) CopyMagickMemory(q,q+cnt+12,length-(cnt+12)-(q-datum));
+        (void) memmove(q,q+cnt+12,length-(cnt+12)-(q-datum));
         SetStringInfoLength(bim_profile,length-(cnt+12));
         break;
       }
@@ -3181,10 +3263,10 @@ static const StringInfo *GetAdditionalInformation(const ImageInfo *image_info,
   {
     /* skip over signature */
     p+=4;
-    key[0]=(*p++);
-    key[1]=(*p++);
-    key[2]=(*p++);
-    key[3]=(*p++);
+    key[0]=(char) (*p++);
+    key[1]=(char) (*p++);
+    key[2]=(char) (*p++);
+    key[3]=(char) (*p++);
     key[4]='\0';
     size=(unsigned int) (*p++) << 24;
     size|=(unsigned int) (*p++) << 16;
@@ -3207,7 +3289,7 @@ static const StringInfo *GetAdditionalInformation(const ImageInfo *image_info,
     if (found == MagickFalse)
       {
         if (remaining_length > 0)
-          p=(unsigned char *) CopyMagickMemory(p-12,p+size,remaining_length);
+          p=(unsigned char *) memmove(p-12,p+size,remaining_length);
         continue;
       }
     length+=(size_t) size+12;
@@ -3217,7 +3299,7 @@ static const StringInfo *GetAdditionalInformation(const ImageInfo *image_info,
   if (length == 0)
     return(DestroyStringInfo(profile));
   SetStringInfoLength(profile,(const size_t) length);
-  SetImageProfile(image,"psd:additional-info",info,exception);
+  (void) SetImageProfile(image,"psd:additional-info",info,exception);
   return(profile);
 }
 
@@ -3262,7 +3344,7 @@ static MagickBooleanType WritePSDLayersInternal(Image *image,
     base_image=image;
   size=0;
   size_offset=TellBlob(image);
-  SetPSDSize(psd_info,image,0);
+  (void) SetPSDSize(psd_info,image,0);
   layer_count=0;
   for (next_image=base_image; next_image != NULL; )
   {
@@ -3296,7 +3378,7 @@ static MagickBooleanType WritePSDLayersInternal(Image *image,
     if (property != (const char *) NULL)
       {
         mask=(Image *) GetImageRegistry(ImageRegistryType,property,exception);
-        default_color=strlen(property) == 9 ? 255 : 0;
+        default_color=(unsigned char) (strlen(property) == 9 ? 255 : 0);
       }
     size+=WriteBlobSignedLong(image,(signed int) next_image->page.y);
     size+=WriteBlobSignedLong(image,(signed int) next_image->page.x);
@@ -3304,10 +3386,11 @@ static MagickBooleanType WritePSDLayersInternal(Image *image,
       next_image->rows));
     size+=WriteBlobSignedLong(image,(signed int) (next_image->page.x+
       next_image->columns));
-    channels=1U;
+    channels=1;
     if ((next_image->storage_class != PseudoClass) &&
         (IsImageGray(next_image) == MagickFalse))
-      channels=next_image->colorspace == CMYKColorspace ? 4U : 3U;
+      channels=(unsigned short) (next_image->colorspace == CMYKColorspace ? 4 :
+        3);
     total_channels=channels;
     if (next_image->alpha_trait != UndefinedPixelTrait)
       total_channels++;
@@ -3322,7 +3405,7 @@ static MagickBooleanType WritePSDLayersInternal(Image *image,
     if (mask != (Image *) NULL)
       size+=WriteChannelSize(psd_info,image,-2);
     size+=WriteBlobString(image,image->endian == LSBEndian ? "MIB8" :"8BIM");
-    size+=WriteBlobString(image,CompositeOperatorToPSDBlendMode(image));
+    size+=WriteBlobString(image,CompositeOperatorToPSDBlendMode(next_image));
     property=GetImageArtifact(next_image,"psd:layer.opacity");
     if (property != (const char *) NULL)
       {
@@ -3336,8 +3419,8 @@ static MagickBooleanType WritePSDLayersInternal(Image *image,
     else
       size+=WriteBlobByte(image,255);
     size+=WriteBlobByte(image,0);
-    size+=WriteBlobByte(image,next_image->compose==NoCompositeOp ?
-      1 << 0x02 : 1); /* layer properties - visible, etc. */
+    size+=WriteBlobByte(image,(const unsigned char)
+      (next_image->compose == NoCompositeOp ? 1 << 0x02 : 1)); /* layer properties - visible, etc. */
     size+=WriteBlobByte(image,0);
     info=GetAdditionalInformation(image_info,next_image,exception);
     property=(const char *) GetImageProperty(next_image,"label",exception);
@@ -3366,14 +3449,15 @@ static MagickBooleanType WritePSDLayersInternal(Image *image,
         mask->page.y+=image->page.y;
         mask->page.x+=image->page.x;
         size+=WriteBlobLong(image,20);
-        size+=WriteBlobSignedLong(image,mask->page.y);
-        size+=WriteBlobSignedLong(image,mask->page.x);
-        size+=WriteBlobSignedLong(image,(const signed int) mask->rows+
-          mask->page.y);
-        size+=WriteBlobSignedLong(image,(const signed int) mask->columns+
-          mask->page.x);
+        size+=WriteBlobSignedLong(image,(const signed int) mask->page.y);
+        size+=WriteBlobSignedLong(image,(const signed int) mask->page.x);
+        size+=WriteBlobSignedLong(image,(const signed int) (mask->rows+
+          mask->page.y));
+        size+=WriteBlobSignedLong(image,(const signed int) (mask->columns+
+          mask->page.x));
         size+=WriteBlobByte(image,default_color);
-        size+=WriteBlobByte(image,mask->compose == NoCompositeOp ? 2 : 0);
+        size+=WriteBlobByte(image,(const unsigned char)
+          (mask->compose == NoCompositeOp ? 2 : 0));
         size+=WriteBlobMSBShort(image,0);
       }
     size+=WriteBlobLong(image,0);
@@ -3420,7 +3504,7 @@ static MagickBooleanType WritePSDLayersInternal(Image *image,
   {
     property=GetImageArtifact(next_image,"psd:opacity-mask");
     if (property != (const char *) NULL)
-      DeleteImageRegistry(property);
+      (void) DeleteImageRegistry(property);
     next_image=GetNextImageInList(next_image);
   }
 
@@ -3557,16 +3641,18 @@ static MagickBooleanType WritePSDImage(const ImageInfo *image_info,
       */
       (void) WriteBlobMSBLong(image,768);
       for (i=0; i < (ssize_t) image->colors; i++)
-        (void) WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].red));
+        (void) WriteBlobByte(image,ScaleQuantumToChar(ClampToQuantum(
+          image->colormap[i].red)));
       for ( ; i < 256; i++)
         (void) WriteBlobByte(image,0);
       for (i=0; i < (ssize_t) image->colors; i++)
-        (void) WriteBlobByte(image,ScaleQuantumToChar(
-          image->colormap[i].green));
+        (void) WriteBlobByte(image,ScaleQuantumToChar(ClampToQuantum(
+          image->colormap[i].green)));
       for ( ; i < 256; i++)
         (void) WriteBlobByte(image,0);
       for (i=0; i < (ssize_t) image->colors; i++)
-        (void) WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].blue));
+        (void) WriteBlobByte(image,ScaleQuantumToChar(ClampToQuantum(
+          image->colormap[i].blue)));
       for ( ; i < 256; i++)
         (void) WriteBlobByte(image,0);
     }
@@ -3603,8 +3689,7 @@ static MagickBooleanType WritePSDImage(const ImageInfo *image_info,
         icc_profile));
       (void) WriteBlob(image,GetStringInfoLength(icc_profile),
         GetStringInfoDatum(icc_profile));
-      if ((MagickOffsetType) GetStringInfoLength(icc_profile) !=
-          PSDQuantum(GetStringInfoLength(icc_profile)))
+      if ((ssize_t) GetStringInfoLength(icc_profile) != PSDQuantum(GetStringInfoLength(icc_profile)))
         (void) WriteBlobByte(image,0);
     }
   if (status != MagickFalse)
@@ -3616,7 +3701,7 @@ static MagickBooleanType WritePSDImage(const ImageInfo *image_info,
         size;
 
       size_offset=TellBlob(image);
-      SetPSDSize(&psd_info,image,0);
+      (void) SetPSDSize(&psd_info,image,0);
       status=WritePSDLayersInternal(image,image_info,&psd_info,&size,
         exception);
       size_offset+=WritePSDSize(&psd_info,image,size+