]> granicus.if.org Git - imagemagick/blobdiff - coders/psd.c
Fixed memory leak that was detected by oss-fuzz.
[imagemagick] / coders / psd.c
index a7f09b23b08bf470b0c2b94efbbf8cf850a8ae86..4c31d4eecda952d8cbb11aa4750c98fca25354da 100644 (file)
 %                                December 2013                                %
 %                                                                             %
 %                                                                             %
-%  Copyright 1999-2017 ImageMagick Studio LLC, a non-profit organization      %
+%  Copyright 1999-2018 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  %
 %  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
@@ -116,7 +117,7 @@ typedef enum
 */
 typedef struct _ChannelInfo
 {
-  short int
+  short
     type;
 
   size_t
@@ -163,7 +164,7 @@ typedef struct _LayerInfo
   unsigned char
     clipping,
     flags,
-    name[256],
+    name[257],
     visible;
 
   unsigned short
@@ -318,8 +319,8 @@ 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) \
-  magick_threads(image,image,image->rows,1)
+#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++)
   {
@@ -393,11 +394,12 @@ static MagickBooleanType ApplyPSDLayerOpacity(Image *image,Quantum opacity,
       "  applying layer opacity %.20g", (double) opacity);
   if (opacity == OpaqueAlpha)
     return(MagickTrue);
-  image->alpha_trait=BlendPixelTrait;
+  if (image->alpha_trait != BlendPixelTrait)
+    (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
   status=MagickTrue;
 #if defined(MAGICKCORE_OPENMP_SUPPORT)
-#pragma omp parallel for schedule(static,4) shared(status) \
-  magick_threads(image,image,image->rows,1)
+#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++)
   {
@@ -450,12 +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)
@@ -465,8 +468,8 @@ 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) \
-  magick_threads(image,image,image->rows,1)
+#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++)
   {
@@ -494,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);
@@ -528,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;
@@ -689,18 +692,17 @@ static inline LayerInfo *DestroyLayerInfo(LayerInfo *layer_info,
   return (LayerInfo *) RelinquishMagickMemory(layer_info);
 }
 
-static inline size_t GetPSDPacketSize(Image *image)
+static inline size_t GetPSDPacketSize(const Image *image)
 {
   if (image->storage_class == PseudoClass)
     {
       if (image->colors > 256)
         return(2);
-      else if (image->depth > 8)
-        return(2);
     }
-  else
-    if (image->depth > 8)
-      return(2);
+  if (image->depth > 16)
+    return(4);
+  if (image->depth > 8)
+    return(2);
 
   return(1);
 }
@@ -751,13 +753,16 @@ static MagickBooleanType NegateCMYK(Image *image,ExceptionInfo *exception)
   return(status);
 }
 
-static void ParseImageResourceBlocks(Image *image,
+static StringInfo *ParseImageResourceBlocks(Image *image,
   const unsigned char *blocks,size_t length,
   MagickBooleanType *has_merged_image,ExceptionInfo *exception)
 {
   const unsigned char
     *p;
 
+  ssize_t
+    offset;
+
   StringInfo
     *profile;
 
@@ -772,11 +777,10 @@ static void ParseImageResourceBlocks(Image *image,
     short_sans;
 
   if (length < 16)
-    return;
+    return((StringInfo *) NULL);
   profile=BlobToStringInfo((const unsigned char *) NULL,length);
   SetStringInfoDatum(profile,blocks);
-  (void) SetImageProfile(image,"8bim",profile,exception);
-  profile=DestroyStringInfo(profile);
+  SetStringInfoName(profile,"8bim");
   for (p=blocks; (p >= blocks) && (p < (blocks+length-7)); )
   {
     if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
@@ -788,10 +792,11 @@ static void ParseImageResourceBlocks(Image *image,
       name_length++;
     p+=name_length;
     if (p > (blocks+length-4))
-      return;
+      break;
     p=PushLongPixel(MSBEndian,p,&count);
-    if ((p+count) > (blocks+length))
-      return;
+    offset=(ssize_t) count;
+    if (((p+offset) < blocks) || ((p+offset) > (blocks+length)))
+      break;
     switch (id)
     {
       case 0x03ed:
@@ -805,8 +810,8 @@ static void ParseImageResourceBlocks(Image *image,
         /*
           Resolution info.
         */
-        if (count < 16)
-          return;
+        if (offset < 16)
+          break;
         p=PushShortPixel(MSBEndian,p,&resolution);
         image->resolution.x=(double) resolution;
         (void) FormatLocaleString(value,MagickPathExtent,"%g",
@@ -828,21 +833,21 @@ static void 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;
+  return(profile);
 }
 
 static CompositeOperator PSDBlendModeToCompositeOperator(const char *mode)
@@ -932,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
@@ -953,11 +958,13 @@ static inline void SetPSDPixel(Image *image,const size_t channels,
       SetPixelRed(image,pixel,q);
       break;
     }
+    case -3:
     case 1:
     {
       SetPixelGreen(image,pixel,q);
       break;
     }
+    case -4:
     case 2:
     {
       SetPixelBlue(image,pixel,q);
@@ -985,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
@@ -1003,9 +1010,6 @@ static MagickBooleanType ReadPSDChannelPixels(Image *image,
   size_t
     packet_size;
 
-  unsigned short
-    nibble;
-
   p=pixels;
   q=GetAuthenticPixels(image,0,row,image->columns,1,exception);
   if (q == (Quantum *) NULL)
@@ -1015,11 +1019,22 @@ static MagickBooleanType ReadPSDChannelPixels(Image *image,
   {
     if (packet_size == 1)
       pixel=ScaleCharToQuantum(*p++);
-    else
+    else if (packet_size == 2)
       {
+        unsigned short
+          nibble;
+
         p=PushShortPixel(MSBEndian,p,&nibble);
         pixel=ScaleShortToQuantum(nibble);
       }
+    else
+      {
+        MagickFloatType
+          nibble;
+
+        p=PushFloatPixel(MSBEndian,p,&nibble);
+        pixel=ClampToQuantum((MagickRealType)QuantumRange*nibble);
+      }
     if (image->depth > 1)
       {
         SetPSDPixel(image,channels,type,packet_size,pixel,q,exception);
@@ -1031,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);
@@ -1056,10 +1071,10 @@ static MagickBooleanType ReadPSDChannelRaw(Image *image,const size_t channels,
     status;
 
   size_t
-    count,
     row_size;
 
   ssize_t
+    count,
     y;
 
   unsigned char
@@ -1081,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)
@@ -1149,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 + 256) // arbitrary number
+  if (length > (row_size+2048)) /* arbitrary number */
     {
       pixels=(unsigned char *) RelinquishMagickMemory(pixels);
       ThrowBinaryException(ResourceLimitError,"InvalidLength",image->filename);
@@ -1163,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++)
@@ -1221,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)
@@ -1240,12 +1261,13 @@ static MagickBooleanType ReadPSDChannelZip(Image *image,const size_t channels,
     }
   if (ReadBlob(image,compact_size,compact_pixels) != (ssize_t) compact_size)
     {
+      pixels=(unsigned char *) RelinquishMagickMemory(pixels);
       compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
       ThrowBinaryException(CorruptImageError,"UnexpectedEndOfFile",
         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;
@@ -1268,31 +1290,39 @@ static MagickBooleanType ReadPSDChannelZip(Image *image,const size_t channels,
             pixels=(unsigned char *) RelinquishMagickMemory(pixels);
             return(MagickFalse);
           }
+        if (ret == Z_STREAM_END)
+          break;
       }
       (void) inflateEnd(&stream);
     }
 
   if (compression == ZipWithPrediction)
-  {
-     p=pixels;
-     while (count > 0)
-     {
-       length=image->columns;
-       while (--length)
-       {
-         if (packet_size == 2)
-           {
-             p[2]+=p[0]+((p[1]+p[3]) >> 8);
-             p[3]+=p[1];
-           }
-         else
-          *(p+1)+=*p;
-         p+=packet_size;
-       }
-       p+=packet_size;
-       count-=row_size;
-     }
-  }
+    {
+      p=pixels;
+      while (count > 0)
+      {
+        length=image->columns;
+        while (--length)
+        {
+          if (packet_size == 2)
+            {
+              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
+            *(p+1)+=*p;
+          p+=packet_size;
+        }
+        p+=packet_size;
+        count-=row_size;
+      }
+    }
 
   status=MagickTrue;
   p=pixels;
@@ -1343,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;
         }
     }
@@ -1361,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:
       {
@@ -1373,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;
@@ -1381,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(),
@@ -1395,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);
 }
 
@@ -1431,11 +1468,6 @@ static MagickBooleanType ReadPSDLayer(Image *image,const ImageInfo *image_info,
     layer_info->blendkey);
   if (layer_info->visible == MagickFalse)
     layer_info->image->compose=NoCompositeOp;
-  if (psd_info->mode == CMYKMode)
-    SetImageColorspace(layer_info->image,CMYKColorspace,exception);
-  else if ((psd_info->mode == BitmapMode) || (psd_info->mode == DuotoneMode) ||
-           (psd_info->mode == GrayscaleMode))
-    SetImageColorspace(layer_info->image,GRAYColorspace,exception);
   /*
     Set up some hidden attributes for folks that need them.
   */
@@ -1459,12 +1491,21 @@ static MagickBooleanType ReadPSDLayer(Image *image,const ImageInfo *image_info,
         "    reading data for channel %.20g",(double) j);
 
     compression=(PSDCompressionType) ReadBlobShort(layer_info->image);
+
+    /* TODO: Remove this when we figure out how to support this */
+    if ((compression == ZipWithPrediction) && (image->depth == 32))
+      {
+        (void) ThrowMagickException(exception,GetMagickModule(),
+          TypeError,"CompressionNotSupported","ZipWithPrediction(32 bit)");
+        return(MagickFalse);
+      }
+
     layer_info->image->compression=ConvertPSDCompression(compression);
     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;
@@ -1501,6 +1542,101 @@ static MagickBooleanType ReadPSDLayer(Image *image,const ImageInfo *image_info,
   return(status);
 }
 
+static MagickBooleanType CheckPSDChannels(const PSDInfo *psd_info,
+  LayerInfo *layer_info)
+{
+  int
+    channel_type;
+
+  register ssize_t
+    i;
+
+  if (layer_info->channels < psd_info->min_channels)
+    return(MagickFalse);
+  channel_type=RedChannel;
+  if (psd_info->min_channels >= 3)
+    channel_type|=(GreenChannel | BlueChannel);
+  if (psd_info->min_channels >= 4)
+    channel_type|=BlackChannel;
+  for (i=0; i < (ssize_t) layer_info->channels; i++)
+  {
+    short
+      type;
+
+    type=layer_info->channel_info[i].type;
+    if (type == -1)
+      {
+        channel_type|=AlphaChannel;
+        continue;
+      }
+    if (type < -1)
+      continue;
+    if (type == 0)
+      channel_type&=~RedChannel;
+    else if (type == 1)
+      channel_type&=~GreenChannel;
+    else if (type == 2)
+      channel_type&=~BlueChannel;
+    else if (type == 3)
+      channel_type&=~BlackChannel;
+  }
+  if (channel_type == 0)
+    return(MagickTrue);
+  if ((channel_type == AlphaChannel) &&
+      (layer_info->channels >= psd_info->min_channels + 1))
+    return(MagickTrue);
+  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)
@@ -1533,343 +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);
-          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);
-        }
-        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);
           }
+      }
+  }
+
+  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;
+      }
 
-          if (number_layers > 0)
+    /*
+      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);
 }
@@ -1906,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);
 
@@ -1928,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;
@@ -1976,11 +2118,14 @@ static Image *ReadPSDImage(const ImageInfo *image_info,ExceptionInfo *exception)
   register ssize_t
     i;
 
+  size_t
+    imageListLength;
+
   ssize_t
     count;
 
-  unsigned char
-    *data;
+  StringInfo
+    *profile;
 
   /*
     Open image file.
@@ -2006,11 +2151,13 @@ 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);
   psd_info.channels=ReadBlobMSBShort(image);
+  if (psd_info.channels < 1)
+    ThrowReaderException(CorruptImageError,"MissingImageChannel");
   if (psd_info.channels > MaxPSDChannels)
     ThrowReaderException(CorruptImageError,"MaximumChannelsExceeded");
   psd_info.rows=ReadBlobMSBLong(image);
@@ -2019,15 +2166,20 @@ static Image *ReadPSDImage(const ImageInfo *image_info,ExceptionInfo *exception)
       (psd_info.columns > 30000)))
     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
   psd_info.depth=ReadBlobMSBShort(image);
-  if ((psd_info.depth != 1) && (psd_info.depth != 8) && (psd_info.depth != 16))
+  if ((psd_info.depth != 1) && (psd_info.depth != 8) &&
+      (psd_info.depth != 16) && (psd_info.depth != 32))
     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
   psd_info.mode=ReadBlobMSBShort(image);
+  if ((psd_info.mode == IndexedMode) && (psd_info.channels > 3))
+    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
   if (image->debug != MagickFalse)
     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
       "  Image is %.20g x %.20g with channels=%.20g, depth=%.20g, mode=%s",
       (double) psd_info.columns,(double) psd_info.rows,(double)
       psd_info.channels,(double) psd_info.depth,ModeToString((PSDImageType)
       psd_info.mode));
+  if (EOFBlob(image) != MagickFalse)
+    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
   /*
     Initialize image.
   */
@@ -2037,56 +2189,53 @@ static Image *ReadPSDImage(const ImageInfo *image_info,ExceptionInfo *exception)
   status=SetImageExtent(image,image->columns,image->rows,exception);
   if (status == MagickFalse)
     return(DestroyImageList(image));
-  if (SetImageBackgroundColor(image,exception) == MagickFalse)
-    {
-      image=DestroyImageList(image);
-      return((Image *) NULL);
-    }
+  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)
     {
-      SetImageColorspace(image,CMYKColorspace,exception);
-      if (psd_info.channels > 4)
-        SetImageAlphaChannel(image,ActivateAlphaChannel,exception);
+      psd_info.min_channels=4;
+      (void) SetImageColorspace(image,CMYKColorspace,exception);
     }
   else if ((psd_info.mode == BitmapMode) || (psd_info.mode == GrayscaleMode) ||
            (psd_info.mode == DuotoneMode))
     {
-      status=AcquireImageColormap(image,psd_info.depth != 16 ? 256 : 65536,
-        exception);
-      if (status == MagickFalse)
-        ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
-      if (image->debug != MagickFalse)
-        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
-          "  Image colormap allocated");
-      SetImageColorspace(image,GRAYColorspace,exception);
-      if (psd_info.channels > 1)
-        SetImageAlphaChannel(image,ActivateAlphaChannel,exception);
+      if (psd_info.depth != 32)
+        {
+          status=AcquireImageColormap(image,(size_t) (psd_info.depth < 16 ?
+            256 : 65536),exception);
+          if (status == MagickFalse)
+            ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
+          if (image->debug != MagickFalse)
+            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+              "  Image colormap allocated");
+        }
+      psd_info.min_channels=1;
+      (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");
   /*
     Read PSD raster colormap only present for indexed and duotone images.
   */
   length=ReadBlobMSBLong(image);
+  if ((psd_info.mode == IndexedMode) && (length < 3))
+    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
   if (length != 0)
     {
       if (image->debug != MagickFalse)
         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
           "  reading colormap");
-      if (psd_info.mode == DuotoneMode)
+      if ((psd_info.mode == DuotoneMode) || (psd_info.depth == 32))
         {
           /*
             Duotone image data;  the format of this data is undocumented.
+            32 bits per pixel;  the colormap is ignored.
           */
-          data=(unsigned char *) AcquireQuantumMemory((size_t) length,
-            sizeof(*data));
-          if (data == (unsigned char *) NULL)
-            ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
-          (void) ReadBlob(image,(size_t) length,data);
-          data=(unsigned char *) RelinquishMagickMemory(data);
+          (void) SeekBlob(image,(const MagickOffsetType) length,SEEK_CUR);
         }
       else
         {
@@ -2096,26 +2245,27 @@ 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;
         }
     }
   if ((image->depth == 1) && (image->storage_class != PseudoClass))
     ThrowReaderException(CorruptImageError, "ImproperImageHeader");
   has_merged_image=MagickTrue;
+  profile=(StringInfo *) NULL;
   length=ReadBlobMSBLong(image);
   if (length != 0)
     {
@@ -2142,8 +2292,8 @@ static Image *ReadPSDImage(const ImageInfo *image_info,ExceptionInfo *exception)
           blocks=(unsigned char *) RelinquishMagickMemory(blocks);
           ThrowReaderException(CorruptImageError,"ImproperImageHeader");
         }
-      ParseImageResourceBlocks(image,blocks,(size_t) length,&has_merged_image,
-        exception);
+      profile=ParseImageResourceBlocks(image,blocks,(size_t) length,
+        &has_merged_image,exception);
       blocks=(unsigned char *) RelinquishMagickMemory(blocks);
     }
   /*
@@ -2176,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);
@@ -2184,13 +2336,21 @@ 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.
   */
+  if (EOFBlob(image) != MagickFalse)
+    {
+      if (profile != (StringInfo *) NULL)
+        profile=DestroyStringInfo(profile);
+      ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
+    }
   if (image_info->ping != MagickFalse)
     {
+      if (profile != (StringInfo *) NULL)
+        profile=DestroyStringInfo(profile);
       (void) CloseBlob(image);
       return(GetFirstImageInList(image));
     }
@@ -2200,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);
@@ -2221,14 +2384,34 @@ 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)
+    {
+      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);
   return(GetFirstImageInList(image));
 }
@@ -2336,25 +2519,25 @@ static inline ssize_t SetPSDOffset(const PSDInfo *psd_info,Image *image,
 {
   if (psd_info->version == 1)
     return(WriteBlobMSBShort(image,(unsigned short) offset));
-  return(WriteBlobMSBLong(image,(unsigned short) offset));
+  return(WriteBlobMSBLong(image,(unsigned int) offset));
 }
 
 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 short) size));
-  SeekBlob(image,current_offset,SEEK_SET);
+    result=WriteBlobMSBLong(image,(unsigned int) size);
+  (void) SeekBlob(image,current_offset,SEEK_SET);
   return(result);
 }
 
@@ -2367,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);
 }
 
@@ -2494,7 +2677,8 @@ static size_t PSDPackbitsEncodeImage(Image *image,const size_t length,
 }
 
 static size_t WriteCompressionStart(const PSDInfo *psd_info,Image *image,
-  const Image *next_image,const ssize_t channels)
+  const Image *next_image,const CompressionType compression,
+  const ssize_t channels)
 {
   size_t
     length;
@@ -2503,19 +2687,19 @@ static size_t WriteCompressionStart(const PSDInfo *psd_info,Image *image,
     i,
     y;
 
-  if (next_image->compression == RLECompression)
+  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 (next_image->compression == ZipCompression)
-    length=WriteBlobShort(image,ZipWithoutPrediction);
+  else if (compression == ZipCompression)
+    length=(size_t) WriteBlobShort(image,ZipWithoutPrediction);
 #endif
   else
-    length=WriteBlobShort(image,Raw);
+    length=(size_t) WriteBlobShort(image,Raw);
   return(length);
 }
 
@@ -2523,11 +2707,8 @@ static size_t WritePSDChannel(const PSDInfo *psd_info,
   const ImageInfo *image_info,Image *image,Image *next_image,
   const QuantumType quantum_type, unsigned char *compact_pixels,
   MagickOffsetType size_offset,const MagickBooleanType separate,
-  ExceptionInfo *exception)
+  const CompressionType compression,ExceptionInfo *exception)
 {
-  int
-    y;
-
   MagickBooleanType
     monochrome;
 
@@ -2544,6 +2725,9 @@ static size_t WritePSDChannel(const PSDInfo *psd_info,
     count,
     length;
 
+  ssize_t
+    y;
+
   unsigned char
     *pixels;
 
@@ -2568,7 +2752,7 @@ static size_t WritePSDChannel(const PSDInfo *psd_info,
   if (separate != MagickFalse)
     {
       size_offset=TellBlob(image)+2;
-      count+=WriteCompressionStart(psd_info,image,next_image,1);
+      count+=WriteCompressionStart(psd_info,image,next_image,compression,1);
     }
   if (next_image->depth > 8)
     next_image->depth=16;
@@ -2579,7 +2763,7 @@ static size_t WritePSDChannel(const PSDInfo *psd_info,
     return(0);
   pixels=(unsigned char *) GetQuantumPixels(quantum_info);
 #ifdef MAGICKCORE_ZLIB_DELEGATE
-  if (next_image->compression == ZipCompression)
+  if (compression == ZipCompression)
     {
       compressed_pixels=(unsigned char *) AcquireQuantumMemory(CHUNK,
         sizeof(*compressed_pixels));
@@ -2588,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))
@@ -2610,7 +2794,7 @@ static size_t WritePSDChannel(const PSDInfo *psd_info,
     if (monochrome != MagickFalse)
       for (i=0; i < (ssize_t) length; i++)
         pixels[i]=(~pixels[i]);
-    if (next_image->compression == RLECompression)
+    if (compression == RLECompression)
       {
         length=PSDPackbitsEncodeImage(image,length,pixels,compact_pixels,
           exception);
@@ -2618,7 +2802,7 @@ static size_t WritePSDChannel(const PSDInfo *psd_info,
         size_offset+=WritePSDOffset(psd_info,image,length,size_offset);
       }
 #ifdef MAGICKCORE_ZLIB_DELEGATE
-    else if (next_image->compression == ZipCompression)
+    else if (compression == ZipCompression)
       {
         stream.avail_in=(uInt) length;
         stream.next_in=(Bytef *) pixels;
@@ -2639,7 +2823,7 @@ static size_t WritePSDChannel(const PSDInfo *psd_info,
       count+=WriteBlob(image,length,pixels);
   }
 #ifdef MAGICKCORE_ZLIB_DELEGATE
-  if (next_image->compression == ZipCompression)
+  if (compression == ZipCompression)
     {
       (void) deflateEnd(&stream);
       compressed_pixels=(unsigned char *) RelinquishMagickMemory(
@@ -2675,6 +2859,9 @@ static size_t WritePSDChannels(const PSDInfo *psd_info,
   MagickOffsetType size_offset,const MagickBooleanType separate,
   ExceptionInfo *exception)
 {
+  CompressionType
+    compression;
+
   Image
     *mask;
 
@@ -2694,7 +2881,10 @@ static size_t WritePSDChannels(const PSDInfo *psd_info,
   offset_length=0;
   rows_offset=0;
   compact_pixels=(unsigned char *) NULL;
-  if (next_image->compression == RLECompression)
+  compression=next_image->compression;
+  if (image_info->compression != UndefinedCompression)
+    compression=image_info->compression;
+  if (compression == RLECompression)
     {
       compact_pixels=AcquireCompactPixels(next_image,exception);
       if (compact_pixels == (unsigned char *) NULL)
@@ -2706,19 +2896,22 @@ 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,channels);
+      count+=WriteCompressionStart(psd_info,image,next_image,compression,
+        (ssize_t) channels);
       offset_length=(next_image->rows*(psd_info->version == 1 ? 2 : 4));
     }
   size_offset+=2;
   if (next_image->storage_class == PseudoClass)
     {
       length=WritePSDChannel(psd_info,image_info,image,next_image,
-        IndexQuantum,compact_pixels,rows_offset,separate,exception);
+        IndexQuantum,compact_pixels,rows_offset,separate,compression,
+        exception);
       if (separate != MagickFalse)
         size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
       else
@@ -2730,7 +2923,8 @@ static size_t WritePSDChannels(const PSDInfo *psd_info,
       if (IsImageGray(next_image) != MagickFalse)
         {
           length=WritePSDChannel(psd_info,image_info,image,next_image,
-            GrayQuantum,compact_pixels,rows_offset,separate,exception);
+            GrayQuantum,compact_pixels,rows_offset,separate,compression,
+            exception);
           if (separate != MagickFalse)
             size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
           else
@@ -2743,7 +2937,8 @@ static size_t WritePSDChannels(const PSDInfo *psd_info,
             (void) NegateCMYK(next_image,exception);
 
           length=WritePSDChannel(psd_info,image_info,image,next_image,
-            RedQuantum,compact_pixels,rows_offset,separate,exception);
+            RedQuantum,compact_pixels,rows_offset,separate,compression,
+            exception);
           if (separate != MagickFalse)
             size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
           else
@@ -2751,7 +2946,8 @@ static size_t WritePSDChannels(const PSDInfo *psd_info,
           count+=length;
 
           length=WritePSDChannel(psd_info,image_info,image,next_image,
-            GreenQuantum,compact_pixels,rows_offset,separate,exception);
+            GreenQuantum,compact_pixels,rows_offset,separate,compression,
+            exception);
           if (separate != MagickFalse)
             size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
           else
@@ -2759,7 +2955,8 @@ static size_t WritePSDChannels(const PSDInfo *psd_info,
           count+=length;
 
           length=WritePSDChannel(psd_info,image_info,image,next_image,
-            BlueQuantum,compact_pixels,rows_offset,separate,exception);
+            BlueQuantum,compact_pixels,rows_offset,separate,compression,
+            exception);
           if (separate != MagickFalse)
             size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
           else
@@ -2769,7 +2966,8 @@ static size_t WritePSDChannels(const PSDInfo *psd_info,
           if (next_image->colorspace == CMYKColorspace)
             {
               length=WritePSDChannel(psd_info,image_info,image,next_image,
-                BlackQuantum,compact_pixels,rows_offset,separate,exception);
+                BlackQuantum,compact_pixels,rows_offset,separate,compression,
+                exception);
               if (separate != MagickFalse)
                 size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
               else
@@ -2780,7 +2978,8 @@ static size_t WritePSDChannels(const PSDInfo *psd_info,
       if (next_image->alpha_trait != UndefinedPixelTrait)
         {
           length=WritePSDChannel(psd_info,image_info,image,next_image,
-            AlphaQuantum,compact_pixels,rows_offset,separate,exception);
+            AlphaQuantum,compact_pixels,rows_offset,separate,compression,
+            exception);
           if (separate != MagickFalse)
             size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
           else
@@ -2803,14 +3002,15 @@ static size_t WritePSDChannels(const PSDInfo *psd_info,
             exception);
           if (mask != (Image *) NULL)
             {
-              if (mask->compression == RLECompression)
+              if (compression == RLECompression)
                 {
                   compact_pixels=AcquireCompactPixels(mask,exception);
                   if (compact_pixels == (unsigned char *) NULL)
                     return(0);
                 }
               length=WritePSDChannel(psd_info,image_info,image,mask,
-                RedQuantum,compact_pixels,rows_offset,MagickTrue,exception);
+                RedQuantum,compact_pixels,rows_offset,MagickTrue,compression,
+                exception);
               (void) WritePSDSize(psd_info,image,length,size_offset);
               count+=length;
               compact_pixels=(unsigned char *) RelinquishMagickMemory(
@@ -2889,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);
 }
@@ -2938,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;
@@ -2990,9 +3190,10 @@ static void RemoveResolutionFromResourceBlock(StringInfo *bim_profile)
     cnt=PSDQuantum(count);
     if (cnt < 0)
       return;
-    if ((id == 0x000003ed) && (cnt < (ssize_t) (length-12)))
+    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;
       }
@@ -3062,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;
@@ -3088,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;
@@ -3098,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);
 }
 
@@ -3143,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; )
   {
@@ -3177,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);
@@ -3185,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++;
@@ -3203,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)
       {
@@ -3217,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);
@@ -3247,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);
@@ -3301,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);
   }
 
@@ -3438,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);
     }
@@ -3484,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)
@@ -3497,11 +3701,11 @@ 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+
-        (psd_info.version == 1 ? 8 : 16),size_offset);
+        (psd_info.version == 1 ? 8 : 12),size_offset);
     }
   (void) WriteBlobMSBLong(image,0);  /* user mask data */
   /*
@@ -3515,6 +3719,8 @@ static MagickBooleanType WritePSDImage(const ImageInfo *image_info,
       compression=image->compression;
       if (image->compression == ZipCompression)
         image->compression=RLECompression;
+      if (image_info->compression != UndefinedCompression)
+        image->compression=image_info->compression;
       if (WritePSDChannels(&psd_info,image_info,image,image,0,MagickFalse,
           exception) == 0)
         status=MagickFalse;