]> granicus.if.org Git - imagemagick/commitdiff
Fixed layer RLE compression.
authordirk <dirk@git.imagemagick.org>
Fri, 9 Sep 2016 21:16:51 +0000 (23:16 +0200)
committerdirk <dirk@git.imagemagick.org>
Fri, 16 Sep 2016 20:12:50 +0000 (22:12 +0200)
coders/psd.c

index 5edca197b02eca8da1dd03f9464514fa82d5e612..d09c3fa890d627484d5ad4d467ab26f2f14c1266 100644 (file)
@@ -945,7 +945,7 @@ static MagickBooleanType ReadPSDChannelRaw(Image *image,const size_t channels,
   return(status);
 }
 
-static inline MagickOffsetType *ReadPSDRLEOffsets(Image *image,
+static inline MagickOffsetType *ReadPSDRLESizes(Image *image,
   const PSDInfo *psd_info,const size_t size)
 {
   MagickOffsetType
@@ -969,7 +969,7 @@ static inline MagickOffsetType *ReadPSDRLEOffsets(Image *image,
 }
 
 static MagickBooleanType ReadPSDChannelRLE(Image *image,const PSDInfo *psd_info,
-  const ssize_t type,MagickOffsetType *offsets,ExceptionInfo *exception)
+  const ssize_t type,MagickOffsetType *sizes,ExceptionInfo *exception)
 {
   MagickBooleanType
     status;
@@ -998,8 +998,8 @@ static MagickBooleanType ReadPSDChannelRLE(Image *image,const PSDInfo *psd_info,
 
   length=0;
   for (y=0; y < (ssize_t) image->rows; y++)
-    if ((MagickOffsetType) length < offsets[y])
-      length=(size_t) offsets[y];
+    if ((MagickOffsetType) length < sizes[y])
+      length=(size_t) sizes[y];
 
   if (length > row_size + 256) // arbitrary number
     {
@@ -1023,11 +1023,11 @@ static MagickBooleanType ReadPSDChannelRLE(Image *image,const PSDInfo *psd_info,
   {
     status=MagickFalse;
 
-    count=ReadBlob(image,(size_t) offsets[y],compact_pixels);
-    if (count != (ssize_t) offsets[y])
+    count=ReadBlob(image,(size_t) sizes[y],compact_pixels);
+    if (count != (ssize_t) sizes[y])
       break;
 
-    count=DecodePSDPixels((size_t) offsets[y],compact_pixels,
+    count=DecodePSDPixels((size_t) sizes[y],compact_pixels,
       (ssize_t) (image->depth == 1 ? 123456 : image->depth),row_size,pixels);
     if (count != (ssize_t) row_size)
       break;
@@ -1203,15 +1203,15 @@ static MagickBooleanType ReadPSDChannel(Image *image,const PSDInfo *psd_info,
     case RLE:
       {
         MagickOffsetType
-          *offsets;
+          *sizes;
 
-        offsets=ReadPSDRLEOffsets(channel_image,psd_info,channel_image->rows);
-        if (offsets == (MagickOffsetType *) NULL)
+        sizes=ReadPSDRLESizes(channel_image,psd_info,channel_image->rows);
+        if (sizes == (MagickOffsetType *) NULL)
           ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
             image->filename);
         status=ReadPSDChannelRLE(channel_image,psd_info,
-          layer_info->channel_info[channel].type,offsets,exception);
-        offsets=(MagickOffsetType *) RelinquishMagickMemory(offsets);
+          layer_info->channel_info[channel].type,sizes,exception);
+        sizes=(MagickOffsetType *) RelinquishMagickMemory(sizes);
       }
       break;
     case ZipWithPrediction:
@@ -1719,7 +1719,7 @@ static MagickBooleanType ReadPSDMergedImage(const ImageInfo *image_info,
   Image *image,const PSDInfo *psd_info,ExceptionInfo *exception)
 {
   MagickOffsetType
-    *offsets;
+    *sizes;
 
   MagickBooleanType
     status;
@@ -1740,11 +1740,11 @@ static MagickBooleanType ReadPSDMergedImage(const ImageInfo *image_info,
       return(MagickFalse);
     }
 
-  offsets=(MagickOffsetType *) NULL;
+  sizes=(MagickOffsetType *) NULL;
   if (compression == RLE)
   {
-    offsets=ReadPSDRLEOffsets(image,psd_info,image->rows*psd_info->channels);
-    if (offsets == (MagickOffsetType *) NULL)
+    sizes=ReadPSDRLESizes(image,psd_info,image->rows*psd_info->channels);
+    if (sizes == (MagickOffsetType *) NULL)
       ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
         image->filename);
   }
@@ -1753,7 +1753,7 @@ static MagickBooleanType ReadPSDMergedImage(const ImageInfo *image_info,
   for (i=0; i < (ssize_t) psd_info->channels; i++)
   {
     if (compression == RLE)
-      status=ReadPSDChannelRLE(image,psd_info,i,offsets+(i*image->rows),
+      status=ReadPSDChannelRLE(image,psd_info,i,sizes+(i*image->rows),
         exception);
     else
       status=ReadPSDChannelRaw(image,psd_info->channels,i,exception);
@@ -1771,8 +1771,7 @@ static MagickBooleanType ReadPSDMergedImage(const ImageInfo *image_info,
   if (status != MagickFalse)
     status=CorrectPSDAlphaBlend(image_info,image,exception);
 
-  if (offsets != (MagickOffsetType *) NULL)
-    offsets=(MagickOffsetType *) RelinquishMagickMemory(offsets);
+  sizes=(MagickOffsetType *) RelinquishMagickMemory(sizes);
 
   return(status);
 }
@@ -2159,6 +2158,25 @@ static inline ssize_t SetPSDOffset(const PSDInfo *psd_info,Image *image,
   return(WriteBlobMSBLong(image,(unsigned short) offset));
 }
 
+static inline ssize_t WritePSDOffset(const PSDInfo *psd_info,Image *image,
+  const MagickSizeType size,const MagickSizeType offset)
+{
+  MagickSizeType
+    current_offset;
+
+  ssize_t
+    result;
+
+  current_offset=TellBlob(image);
+  SeekBlob(image,offset,SEEK_SET);
+  if (psd_info->version == 1)
+    result=WriteBlobMSBShort(image,(unsigned short) size);
+  else
+    result=(WriteBlobMSBLong(image,(unsigned short) offset));
+  SeekBlob(image,current_offset,SEEK_SET);
+  return(result);
+}
+
 static inline ssize_t SetPSDSize(const PSDInfo *psd_info,Image *image,
   const MagickSizeType size)
 {
@@ -2167,6 +2185,25 @@ static inline ssize_t SetPSDSize(const PSDInfo *psd_info,Image *image,
   return(WriteBlobMSBLongLong(image,size));
 }
 
+static inline ssize_t WritePSDSize(const PSDInfo *psd_info,Image *image,
+  const MagickSizeType size,const MagickSizeType offset)
+{
+  MagickSizeType
+    current_offset;
+
+  ssize_t
+    result;
+
+  current_offset=TellBlob(image);
+  SeekBlob(image,offset,SEEK_SET);
+  if (psd_info->version == 1)
+    result=WriteBlobMSBLong(image,(unsigned int) size);
+  else
+    result=WriteBlobMSBLongLong(image,size);
+  SeekBlob(image,current_offset,SEEK_SET);
+  return(result);
+}
+
 static size_t PSDPackbitsEncodeImage(Image *image,const size_t length,
   const unsigned char *pixels,unsigned char *compact_pixels,
   ExceptionInfo *exception)
@@ -2277,50 +2314,32 @@ static size_t PSDPackbitsEncodeImage(Image *image,const size_t length,
   return((size_t) (q-compact_pixels));
 }
 
-static void WritePackbitsLength(const PSDInfo *psd_info,
-  const ImageInfo *image_info,Image *image,Image *next_image,
-  unsigned char *compact_pixels,const QuantumType quantum_type,
-  ExceptionInfo *exception)
+static size_t WriteCompressionStart(const PSDInfo *psd_info,Image *image,
+  const Image *next_image,const ssize_t channels)
 {
-  QuantumInfo
-    *quantum_info;
-
-  register const Quantum
-    *p;
-
   size_t
-    length,
-    packet_size;
+    length;
 
   ssize_t
+    i,
     y;
 
-  unsigned char
-    *pixels;
-
-  if (next_image->depth > 8)
-    next_image->depth=16;
-  packet_size=next_image->depth > 8UL ? 2UL : 1UL;
-  (void) packet_size;
-  quantum_info=AcquireQuantumInfo(image_info,image);
-  pixels=(unsigned char *) GetQuantumPixels(quantum_info);
-  for (y=0; y < (ssize_t) next_image->rows; y++)
-  {
-    p=GetVirtualPixels(next_image,0,y,next_image->columns,1,exception);
-    if (p == (const Quantum *) NULL)
-      break;
-    length=ExportQuantumPixels(next_image,(CacheView *) NULL,quantum_info,
-      quantum_type,pixels,exception);
-    length=PSDPackbitsEncodeImage(image,length,pixels,compact_pixels,
-      exception);
-    (void) SetPSDOffset(psd_info,image,length);
-  }
-  quantum_info=DestroyQuantumInfo(quantum_info);
+  if (next_image->compression == RLECompression)
+    {
+      length=WriteBlobMSBShort(image,1);
+      for (i=0; i < channels; i++)
+        for (y=0; y < (ssize_t) next_image->rows; y++)
+          length+=SetPSDOffset(psd_info,image,0);
+    }
+  else
+    length=WriteBlobMSBShort(image,0);
+  return(length);
 }
 
-static void WriteOneChannel(const ImageInfo *image_info,Image *image,
-  Image *next_image,unsigned char *compact_pixels,
-  const QuantumType quantum_type,const MagickBooleanType compression_flag,
+static size_t WriteOneChannel(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)
 {
   int
@@ -2339,21 +2358,22 @@ static void WriteOneChannel(const ImageInfo *image_info,Image *image,
     i;
 
   size_t
-    length,
-    packet_size;
+    count,
+    length;
 
   unsigned char
     *pixels;
 
-  if ((compression_flag != MagickFalse) &&
-      (next_image->compression != RLECompression))
-    (void) WriteBlobMSBShort(image,0);
+  count=0;
+  if (separate != MagickFalse)
+    {
+      size_offset=TellBlob(image)+2;
+      count+=WriteCompressionStart(psd_info,image,next_image,1);
+    }
   if (next_image->depth > 8)
     next_image->depth=16;
   monochrome=IsImageMonochrome(image) && (image->depth == 1) ?
     MagickTrue : MagickFalse;
-  packet_size=next_image->depth > 8UL ? 2UL : 1UL;
-  (void) packet_size;
   quantum_info=AcquireQuantumInfo(image_info,image);
   pixels=(unsigned char *) GetQuantumPixels(quantum_info);
   for (y=0; y < (ssize_t) next_image->rows; y++)
@@ -2367,136 +2387,154 @@ static void WriteOneChannel(const ImageInfo *image_info,Image *image,
       for (i=0; i < (ssize_t) length; i++)
         pixels[i]=(~pixels[i]);
     if (next_image->compression != RLECompression)
-      (void) WriteBlob(image,length,pixels);
+       count+=WriteBlob(image,length,pixels);
     else
       {
         length=PSDPackbitsEncodeImage(image,length,pixels,compact_pixels,
           exception);
-        (void) WriteBlob(image,length,compact_pixels);
+        count+=WriteBlob(image,length,compact_pixels);
+        size_offset+=WritePSDOffset(psd_info,image,length,size_offset);
       }
   }
   quantum_info=DestroyQuantumInfo(quantum_info);
+  return(count);
 }
 
 static MagickBooleanType WriteImageChannels(const PSDInfo *psd_info,
   const ImageInfo *image_info,Image *image,Image *next_image,
-  const MagickBooleanType separate,ExceptionInfo *exception)
+  MagickOffsetType size_offset,const MagickBooleanType separate,
+  ExceptionInfo *exception)
 {
+  Image
+    *mask;
+
+  MagickOffsetType
+    rows_offset;
+
   size_t
     channels,
-    packet_size;
+    count,
+    length,
+    offset_length;
 
   unsigned char
     *compact_pixels;
 
-  /*
-    Write uncompressed pixels as separate planes.
-  */
-  channels=1;
-  packet_size=next_image->depth > 8UL ? 2UL : 1UL;
+  count=0;
+  offset_length=0;
+  rows_offset=0;
   compact_pixels=(unsigned char *) NULL;
   if (next_image->compression == RLECompression)
     {
-      compact_pixels=(unsigned char *) AcquireQuantumMemory((9*channels*
+      size_t
+        packet_size;
+
+      packet_size=next_image->depth > 8UL ? 2UL : 1UL;
+      compact_pixels=(unsigned char *) AcquireQuantumMemory((9*
         next_image->columns)+1,packet_size*sizeof(*compact_pixels));
       if (compact_pixels == (unsigned char *) NULL)
-        ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
-    }
-  if (IsImageGray(next_image) != MagickFalse)
-    {
-      if (next_image->compression == RLECompression)
         {
-          /*
-            Packbits compression.
-          */
-          (void) WriteBlobMSBShort(image,1);
-          WritePackbitsLength(psd_info,image_info,image,next_image,
-            compact_pixels,GrayQuantum,exception);
-          if (next_image->alpha_trait != UndefinedPixelTrait)
-            WritePackbitsLength(psd_info,image_info,image,next_image,
-              compact_pixels,AlphaQuantum,exception);
+          (void) ThrowMagickException(exception,GetMagickModule(),
+            ResourceLimitError,"MemoryAllocationFailed","`%s'",
+            image->filename);
+          return(0);
         }
-      WriteOneChannel(image_info,image,next_image,compact_pixels,GrayQuantum,
-        MagickTrue,exception);
+    }
+  channels=1;
+  if (separate == MagickFalse)
+    {
+      if (IsImageGray(next_image) == MagickFalse)
+        channels=next_image->colorspace == CMYKColorspace ? 4 : 3;
       if (next_image->alpha_trait != UndefinedPixelTrait)
-        WriteOneChannel(image_info,image,next_image,compact_pixels,
-          AlphaQuantum,separate,exception);
-      (void) SetImageProgress(image,SaveImagesTag,0,1);
+        channels++;
+      rows_offset=TellBlob(image)+2;
+      count+=WriteCompressionStart(psd_info,image,next_image,channels);
+      offset_length=(next_image->rows*(psd_info->version == 1 ? 2 : 4));
+    }
+  size_offset+=2;
+  if (next_image->storage_class == PseudoClass)
+    {
+      length=WriteOneChannel(psd_info,image_info,image,next_image,
+        IndexQuantum,compact_pixels,rows_offset,separate,exception);
+      if (separate != MagickFalse)
+        size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
+      else
+        rows_offset+=offset_length;
+      count+=length;
     }
   else
-    if (next_image->storage_class == PseudoClass)
-      {
-        if (next_image->compression == RLECompression)
-          {
-            /*
-              Packbits compression.
-            */
-            (void) WriteBlobMSBShort(image,1);
-            WritePackbitsLength(psd_info,image_info,image,next_image,
-              compact_pixels,IndexQuantum,exception);
-            if (next_image->alpha_trait != UndefinedPixelTrait)
-              WritePackbitsLength(psd_info,image_info,image,next_image,
-                compact_pixels,AlphaQuantum,exception);
-          }
-        WriteOneChannel(image_info,image,next_image,compact_pixels,
-          IndexQuantum,MagickTrue,exception);
-        if (next_image->alpha_trait != UndefinedPixelTrait)
-          WriteOneChannel(image_info,image,next_image,compact_pixels,
-            AlphaQuantum,separate,exception);
-        (void) SetImageProgress(image,SaveImagesTag,0,1);
-      }
-    else
-      {
-        if (next_image->colorspace == CMYKColorspace)
-          (void) NegateCMYK(next_image,exception);
-        if (next_image->compression == RLECompression)
-          {
-            /*
-              Packbits compression.
-            */
-            (void) WriteBlobMSBShort(image,1);
-            WritePackbitsLength(psd_info,image_info,image,next_image,
-              compact_pixels,RedQuantum,exception);
-            WritePackbitsLength(psd_info,image_info,image,next_image,
-              compact_pixels,GreenQuantum,exception);
-            WritePackbitsLength(psd_info,image_info,image,next_image,
-              compact_pixels,BlueQuantum,exception);
-            if (next_image->colorspace == CMYKColorspace)
-              WritePackbitsLength(psd_info,image_info,image,next_image,
-                compact_pixels,BlackQuantum,exception);
-            if (next_image->alpha_trait != UndefinedPixelTrait)
-              WritePackbitsLength(psd_info,image_info,image,next_image,
-                compact_pixels,AlphaQuantum,exception);
-          }
-        (void) SetImageProgress(image,SaveImagesTag,0,6);
-        WriteOneChannel(image_info,image,next_image,compact_pixels,RedQuantum,
-          MagickTrue,exception);
-        (void) SetImageProgress(image,SaveImagesTag,1,6);
-        WriteOneChannel(image_info,image,next_image,compact_pixels,
-          GreenQuantum,separate,exception);
-        (void) SetImageProgress(image,SaveImagesTag,2,6);
-        WriteOneChannel(image_info,image,next_image,compact_pixels,BlueQuantum,
-          separate,exception);
-        (void) SetImageProgress(image,SaveImagesTag,3,6);
-        if (next_image->colorspace == CMYKColorspace)
-          WriteOneChannel(image_info,image,next_image,compact_pixels,
-            BlackQuantum,separate,exception);
-        (void) SetImageProgress(image,SaveImagesTag,4,6);
-        if (next_image->alpha_trait != UndefinedPixelTrait)
-          WriteOneChannel(image_info,image,next_image,compact_pixels,
-            AlphaQuantum,separate,exception);
-        (void) SetImageProgress(image,SaveImagesTag,5,6);
-        if (next_image->colorspace == CMYKColorspace)
-          (void) NegateCMYK(next_image,exception);
-      }
-  if (next_image->compression == RLECompression)
-    compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
-  return(MagickTrue);
+    {
+      if (IsImageGray(next_image) != MagickFalse)
+        {
+          length=WriteOneChannel(psd_info,image_info,image,next_image,
+            GrayQuantum,compact_pixels,rows_offset,separate,exception);
+          if (separate != MagickFalse)
+            size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
+          else
+            rows_offset+=offset_length;
+          count+=length;
+        }
+      else
+        {
+          if (next_image->colorspace == CMYKColorspace)
+            (void) NegateCMYK(next_image,exception);
+
+          length=WriteOneChannel(psd_info,image_info,image,next_image,
+            RedQuantum,compact_pixels,rows_offset,separate,exception);
+          if (separate != MagickFalse)
+            size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
+          else
+            rows_offset+=offset_length;
+          count+=length;
+
+          length=WriteOneChannel(psd_info,image_info,image,next_image,
+            GreenQuantum,compact_pixels,rows_offset,separate,exception);
+          if (separate != MagickFalse)
+            size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
+          else
+            rows_offset+=offset_length;
+          count+=length;
+
+          length=WriteOneChannel(psd_info,image_info,image,next_image,
+            BlueQuantum,compact_pixels,rows_offset,separate,exception);
+          if (separate != MagickFalse)
+            size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
+          else
+            rows_offset+=offset_length;
+          count+=length;
+
+          if (next_image->colorspace == CMYKColorspace)
+            {
+              length=WriteOneChannel(psd_info,image_info,image,next_image,
+                BlackQuantum,compact_pixels,rows_offset,separate,exception);
+              if (separate != MagickFalse)
+                size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
+              else
+                rows_offset+=offset_length;
+              count+=length;
+            }
+        }
+    }
+  if (next_image->alpha_trait != UndefinedPixelTrait)
+    {
+      length=WriteOneChannel(psd_info,image_info,image,next_image,AlphaQuantum,
+        compact_pixels,rows_offset,separate,exception);
+      if (separate != MagickFalse)
+        size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
+      else
+        rows_offset+=offset_length;
+      count+=length;
+    }
+  if (next_image->colorspace == CMYKColorspace)
+    (void) NegateCMYK(next_image,exception);
+
+  return(count);
 }
 
-static void WritePascalString(Image* inImage,const char *inString,int inPad)
+static size_t WritePascalString(Image *image,const char *value,size_t padding)
 {
   size_t
+    count,
     length;
 
   register ssize_t
@@ -2505,19 +2543,21 @@ static void WritePascalString(Image* inImage,const char *inString,int inPad)
   /*
     Max length is 255.
   */
-  length=(strlen(inString) > 255UL ) ? 255UL : strlen(inString);
+  count=0;
+  length=(strlen(value) > 255UL ) ? 255UL : strlen(value);
   if (length ==  0)
-    (void) WriteBlobByte(inImage,0);
+    count+=WriteBlobByte(image,0);
   else
     {
-      (void) WriteBlobByte(inImage,(unsigned char) length);
-      (void) WriteBlob(inImage, length, (const unsigned char *) inString);
+      count+=WriteBlobByte(image,(unsigned char) length);
+      count+=WriteBlob(image,length,(const unsigned char *) value);
     }
   length++;
-  if ((length % inPad) == 0)
-    return;
-  for (i=0; i < (ssize_t) (inPad-(length % inPad)); i++)
-    (void) WriteBlobByte(inImage,0);
+  if ((length % padding) == 0)
+    return(count);
+  for (i=0; i < (ssize_t) (padding-(length % padding)); i++)
+    count+=WriteBlobByte(image,0);
+  return(count);
 }
 
 static void WriteResolutionResourceBlock(Image *image)
@@ -2553,6 +2593,17 @@ static void WriteResolutionResourceBlock(Image *image)
   (void) WriteBlobMSBShort(image,units); /* height unit */
 }
 
+static inline size_t WriteChannelSize(const PSDInfo *psd_info,Image *image,
+  const unsigned short channel)
+{
+  size_t
+    count;
+
+  count=WriteBlobMSBShort(image,channel);
+  count+=SetPSDSize(psd_info,image,0);
+  return(count);
+}
+
 static void RemoveICCProfileFromResourceBlock(StringInfo *bim_profile)
 {
   register const unsigned char
@@ -2781,6 +2832,10 @@ static MagickBooleanType WritePSDImage(const ImageInfo *image_info,
   MagickBooleanType
     status;
 
+  MagickOffsetType
+    *layer_size_offsets,
+    size_offset;
+
   PSDInfo
     psd_info;
 
@@ -2791,12 +2846,13 @@ static MagickBooleanType WritePSDImage(const ImageInfo *image_info,
     channel_size,
     channelLength,
     layer_count,
-    layer_info_size,
+    layer_index,
     length,
     name_length,
     num_channels,
     packet_size,
-    rounded_layer_info_size;
+    rounded_size,
+    size;
 
   StringInfo
     *bim_profile;
@@ -2939,173 +2995,120 @@ static MagickBooleanType WritePSDImage(const ImageInfo *image_info,
           PSDQuantum(GetStringInfoLength(icc_profile)))
         (void) WriteBlobByte(image,0);
     }
-  layer_count=0;
-  layer_info_size=2;
   base_image=GetNextImageInList(image);
   if (base_image == (Image *) NULL)
     base_image=image;
-  next_image=base_image;
-  while (next_image != (Image *) NULL)
+  size=0;
+  size_offset=TellBlob(image);
+  SetPSDSize(&psd_info,image,0);
+  SetPSDSize(&psd_info,image,0);
+  layer_count=0;
+  for (next_image=base_image; next_image != NULL; )
   {
-    packet_size=next_image->depth > 8 ? 2UL : 1UL;
-    if (IsImageGray(next_image) != MagickFalse)
-      num_channels=next_image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL;
-    else
-      if (next_image->storage_class == PseudoClass)
-        num_channels=next_image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL;
-      else
-        if (next_image->colorspace != CMYKColorspace)
-          num_channels=next_image->alpha_trait != UndefinedPixelTrait ? 4UL : 3UL;
-        else
-          num_channels=next_image->alpha_trait != UndefinedPixelTrait ? 5UL : 4UL;
-    channelLength=(size_t) (next_image->columns*next_image->rows*packet_size+2);
-    layer_info_size+=(size_t) (4*4+2+num_channels*6+(psd_info.version == 1 ? 8 :
-      16)+4*1+4+num_channels*channelLength);
+    layer_count++;
+    next_image=GetNextImageInList(next_image);
+  }
+  if (image->alpha_trait != UndefinedPixelTrait)
+    size+=WriteBlobMSBShort(image,-(unsigned short) layer_count);
+  else
+    size+=WriteBlobMSBShort(image,(unsigned short) layer_count);
+  layer_size_offsets=(MagickOffsetType *) AcquireQuantumMemory(
+    (size_t) layer_count,sizeof(MagickOffsetType));
+  if (layer_size_offsets == (MagickOffsetType *) NULL)
+    ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
+  layer_index=0;
+  for (next_image=base_image; next_image != NULL; )
+  {
+    unsigned short
+      channels,
+      total_channels;
+
+    size+=WriteBlobMSBLong(image,(unsigned int) next_image->page.y);
+    size+=WriteBlobMSBLong(image,(unsigned int) next_image->page.x);
+    size+=WriteBlobMSBLong(image,(unsigned int) (next_image->page.y+
+      next_image->rows));
+    size+=WriteBlobMSBLong(image,(unsigned int) (next_image->page.x+
+      next_image->columns));
+    channels=1U;
+    if (IsImageGray(next_image) == MagickFalse)
+      channels=next_image->colorspace == CMYKColorspace ? 4U : 3U;
+    total_channels=channels;
+    if (next_image->alpha_trait != UndefinedPixelTrait)
+      total_channels++;
+    size+=WriteBlobMSBShort(image,total_channels);
+    layer_size_offsets[layer_index++]=TellBlob(image);
+    for (i=0; i < (ssize_t) channels; i++)
+      size+=WriteChannelSize(&psd_info,image,(unsigned short) i);
+    if (next_image->alpha_trait != UndefinedPixelTrait)
+      size+=WriteChannelSize(&psd_info,image,(unsigned short) -1);
+    size+=WriteBlob(image,4,(const unsigned char *) "8BIM");
+    size+=WriteBlob(image,4,(const unsigned char *)
+      CompositeOperatorToPSDBlendMode(next_image->compose));
+    size+=WriteBlobByte(image,255); /* layer opacity */
+    size+=WriteBlobByte(image,0);
+    size+=WriteBlobByte(image,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);
     if (property == (const char *) NULL)
       {
         (void) FormatLocaleString(layer_name,MagickPathExtent,"L%.20g",
-          (double) layer_count+1);
+          (double) layer_index);
         property=layer_name;
       }
     name_length=strlen(property)+1;
     if ((name_length % 4) != 0)
       name_length+=(4-(name_length % 4));
-    layer_info_size+=8+name_length;
-    info=GetAdditionalInformation(image_info,next_image,exception);
     if (info != (const StringInfo *) NULL)
-      layer_info_size+=GetStringInfoLength(info);
-    layer_count++;
+      name_length+=GetStringInfoLength(info);
+    size+=WriteBlobMSBLong(image,(unsigned int) name_length+8);
+    size+=WriteBlobMSBLong(image,0);
+    size+=WriteBlobMSBLong(image,0);
+    size+=WritePascalString(image,property,4);
+    if (info != (const StringInfo *) NULL)
+      size+=WriteBlob(image,GetStringInfoLength(info),
+        GetStringInfoDatum(info));
     next_image=GetNextImageInList(next_image);
   }
-  if (layer_count == 0)
-    (void) SetPSDSize(&psd_info,image,0);
-  else
-    {
-      CompressionType
-        compression;
-
-      (void) SetPSDSize(&psd_info,image,layer_info_size+
-        (psd_info.version == 1 ? 8 : 16));
-      if ((layer_info_size/2) != ((layer_info_size+1)/2))
-        rounded_layer_info_size=layer_info_size+1;
-      else
-        rounded_layer_info_size=layer_info_size;
-      (void) SetPSDSize(&psd_info,image,rounded_layer_info_size);
-      if (image->alpha_trait != UndefinedPixelTrait)
-        (void) WriteBlobMSBShort(image,-(unsigned short) layer_count);
-      else
-        (void) WriteBlobMSBShort(image,(unsigned short) layer_count);
-      layer_count=1;
-      compression=base_image->compression;
-      for (next_image=base_image; next_image != NULL; )
-      {
-        next_image->compression=NoCompression;
-        (void) WriteBlobMSBLong(image,(unsigned int) next_image->page.y);
-        (void) WriteBlobMSBLong(image,(unsigned int) next_image->page.x);
-        (void) WriteBlobMSBLong(image,(unsigned int) (next_image->page.y+
-          next_image->rows));
-        (void) WriteBlobMSBLong(image,(unsigned int) (next_image->page.x+
-          next_image->columns));
-        packet_size=next_image->depth > 8 ? 2UL : 1UL;
-        channel_size=(unsigned int) ((packet_size*next_image->rows*
-          next_image->columns)+2);
-        if ((IsImageGray(next_image) != MagickFalse) ||
-            (next_image->storage_class == PseudoClass))
-          {
-             (void) WriteBlobMSBShort(image,(unsigned short)
-               (next_image->alpha_trait != UndefinedPixelTrait ? 2 : 1));
-             (void) WriteBlobMSBShort(image,0);
-             (void) SetPSDSize(&psd_info,image,channel_size);
-             if (next_image->alpha_trait != UndefinedPixelTrait)
-               {
-                 (void) WriteBlobMSBShort(image,(unsigned short) -1);
-                 (void) SetPSDSize(&psd_info,image,channel_size);
-               }
-           }
-          else
-            if (next_image->colorspace != CMYKColorspace)
-              {
-                (void) WriteBlobMSBShort(image,(unsigned short)
-                  (next_image->alpha_trait != UndefinedPixelTrait ? 4 : 3));
-               (void) WriteBlobMSBShort(image,0);
-               (void) SetPSDSize(&psd_info,image,channel_size);
-               (void) WriteBlobMSBShort(image,1);
-               (void) SetPSDSize(&psd_info,image,channel_size);
-               (void) WriteBlobMSBShort(image,2);
-               (void) SetPSDSize(&psd_info,image,channel_size);
-               if (next_image->alpha_trait != UndefinedPixelTrait)
-                 {
-                   (void) WriteBlobMSBShort(image,(unsigned short) -1);
-                   (void) SetPSDSize(&psd_info,image,channel_size);
-                 }
-             }
-           else
-             {
-               (void) WriteBlobMSBShort(image,(unsigned short)
-                 (next_image->alpha_trait ? 5 : 4));
-               (void) WriteBlobMSBShort(image,0);
-               (void) SetPSDSize(&psd_info,image,channel_size);
-               (void) WriteBlobMSBShort(image,1);
-               (void) SetPSDSize(&psd_info,image,channel_size);
-               (void) WriteBlobMSBShort(image,2);
-               (void) SetPSDSize(&psd_info,image,channel_size);
-               (void) WriteBlobMSBShort(image,3);
-               (void) SetPSDSize(&psd_info,image,channel_size);
-               if (next_image->alpha_trait)
-                 {
-                   (void) WriteBlobMSBShort(image,(unsigned short) -1);
-                   (void) SetPSDSize(&psd_info,image,channel_size);
-                 }
-             }
-        (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
-        (void) WriteBlob(image,4,(const unsigned char *)
-          CompositeOperatorToPSDBlendMode(next_image->compose));
-        (void) WriteBlobByte(image,255); /* layer opacity */
-        (void) WriteBlobByte(image,0);
-        (void) WriteBlobByte(image,next_image->compose==NoCompositeOp ?
-          1 << 0x02 : 1); /* layer properties - visible, etc. */
-        (void) WriteBlobByte(image,0);
-        info=GetImageProfile(next_image,PSDAdditionalInfo);
-        property=(const char *) GetImageProperty(next_image,"label",exception);
-        if (property == (const char *) NULL)
-          {
-            (void) FormatLocaleString(layer_name,MagickPathExtent,"L%.20g",
-              (double) layer_count++);
-            property=layer_name;
-          }
-        name_length=strlen(property)+1;
-        if ((name_length % 4) != 0)
-          name_length+=(4-(name_length % 4));
-        if (info != (const StringInfo *) NULL)
-          name_length+=GetStringInfoLength(info);
-        (void) WriteBlobMSBLong(image,(unsigned int)name_length+8);
-        (void) WriteBlobMSBLong(image,0);
-        (void) WriteBlobMSBLong(image,0);
-        WritePascalString(image,property,4);
-        if (info != (const StringInfo *) NULL)
-          (void) WriteBlob(image,GetStringInfoLength(info),GetStringInfoDatum(info));
-        next_image=GetNextImageInList(next_image);
-      }
-      /*
-        Now the image data!
-      */
-      next_image=base_image;
-      while (next_image != NULL)
+  /*
+    Now the image data!
+  */
+  next_image=base_image;
+  layer_index=0;
+  while (next_image != NULL)
+  {
+    length=WriteImageChannels(&psd_info,image_info,image,next_image,
+      layer_size_offsets[layer_index++],MagickTrue,exception);
+    if (length == 0)
       {
-        status=WriteImageChannels(&psd_info,image_info,image,next_image,
-          MagickTrue,exception);
-        next_image=GetNextImageInList(next_image);
+        status=MagickFalse;
+        break;
       }
-      (void) WriteBlobMSBLong(image,0);  /* user mask data */
-      base_image->compression=compression;
-    }
+    size+=length;
+    next_image=GetNextImageInList(next_image);
+  }
+  (void) WriteBlobMSBLong(image,0);  /* user mask data */
+  /*
+    Write the total size
+  */
+  size_offset+=WritePSDSize(&psd_info,image,size+
+    (psd_info.version == 1 ? 8 : 16),size_offset);
+  if ((size/2) != ((size+1)/2))
+    rounded_size=size+1;
+  else
+    rounded_size=size;
+  (void) WritePSDSize(&psd_info,image,rounded_size,size_offset);
+  layer_size_offsets=RelinquishMagickMemory(layer_size_offsets);
   /*
     Write composite image.
   */
   if (status != MagickFalse)
-    status=WriteImageChannels(&psd_info,image_info,image,image,MagickFalse,
-      exception);
+    {
+      if (WriteImageChannels(&psd_info,image_info,image,image,0,
+          MagickFalse,exception) == 0)
+        status=MagickFalse;
+    }
   (void) CloseBlob(image);
   return(status);
 }