13ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
23ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
33ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
43ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
53ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
63ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                            PPPP   SSSSS  DDDD                               %
73ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                            P   P  SS     D   D                              %
83ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                            PPPP    SSS   D   D                              %
93ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                            P         SS  D   D                              %
103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                            P      SSSSS  DDDD                               %
113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                   Read/Write Adobe Photoshop Image Format                   %
143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                              Software Design                                %
16de984cdc3631106b1cbbb8d3972b76a0fc27e8e8cristy%                                   Cristy                                    %
173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                              Leonard Rosenthol                              %
183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                 July 1992                                   %
19b41f080d52a5ff2d9c235cffac1419b84028bd31dirk%                                Dirk Lemstra                                 %
20b41f080d52a5ff2d9c235cffac1419b84028bd31dirk%                                December 2013                                %
213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
237ce65e7125a4e1df1a274ce373c537a9df9c16cdCristy%  Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization      %
243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  dedicated to making software imaging solutions freely available.           %
253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  You may not use this file except in compliance with the License.  You may  %
273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  obtain a copy of the License at                                            %
283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    http://www.imagemagick.org/script/license.php                            %
303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Unless required by applicable law or agreed to in writing, software        %
323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  distributed under the License is distributed on an "AS IS" BASIS,          %
333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  See the License for the specific language governing permissions and        %
353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  limitations under the License.                                             %
363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Include declarations.
443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
454c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/studio.h"
464c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/artifact.h"
474c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/attribute.h"
484c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/blob.h"
494c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/blob-private.h"
504c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/cache.h"
5118c0e4dff391a0a98e7f478d0d86bbd08f7708d0dirk#include "MagickCore/channel.h"
524c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/colormap.h"
53f432c635c526259b858c9aad3d409c5c44545686cristy#include "MagickCore/colormap-private.h"
544c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/colorspace.h"
55510d06a3f7063e91993e13d546d5685048248074cristy#include "MagickCore/colorspace-private.h"
564c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/constitute.h"
574c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/enhance.h"
584c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/exception.h"
594c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/exception-private.h"
604c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/image.h"
614c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/image-private.h"
624c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/list.h"
634c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/log.h"
644c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/magick.h"
654c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/memory_.h"
664c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/module.h"
674c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/monitor-private.h"
68b20a1794de28edf28c46f2268914c15781482530dirk#include "MagickCore/option.h"
694c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/pixel.h"
704c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/pixel-accessor.h"
714c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/profile.h"
724c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/property.h"
734c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/quantum-private.h"
744c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/static.h"
754c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/string_.h"
76b20a1794de28edf28c46f2268914c15781482530dirk#include "MagickCore/thread-private.h"
77b41f080d52a5ff2d9c235cffac1419b84028bd31dirk#ifdef MAGICKCORE_ZLIB_DELEGATE
78b41f080d52a5ff2d9c235cffac1419b84028bd31dirk#include <zlib.h>
79b41f080d52a5ff2d9c235cffac1419b84028bd31dirk#endif
8014c08dcd1910ecd8360f51d13885b2c9c39b655ddirk#include "psd-private.h"
8114c08dcd1910ecd8360f51d13885b2c9c39b655ddirk
823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
832d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy  Define declaractions.
842d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy*/
85aca3ec5b866931810b1d66b13099129a6fbe1b39cristy#define MaxPSDChannels  56
86bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy#define PSDQuantum(x) (((ssize_t) (x)+1) & -2)
872d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy
882d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy/*
892d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy  Enumerated declaractions.
902d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy*/
912d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristytypedef enum
922d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy{
93b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  Raw = 0,
94b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  RLE = 1,
95b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  ZipWithoutPrediction = 2,
96b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  ZipWithPrediction = 3
97b41f080d52a5ff2d9c235cffac1419b84028bd31dirk} PSDCompressionType;
98b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
99b41f080d52a5ff2d9c235cffac1419b84028bd31dirktypedef enum
100b41f080d52a5ff2d9c235cffac1419b84028bd31dirk{
1012d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy  BitmapMode = 0,
1022d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy  GrayscaleMode = 1,
1032d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy  IndexedMode = 2,
1042d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy  RGBMode = 3,
1052d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy  CMYKMode = 4,
1062d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy  MultichannelMode = 7,
1072d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy  DuotoneMode = 8,
1082d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy  LabMode = 9
1092d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy} PSDImageType;
1102d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy
1112d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy/*
1122d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy  Typedef declaractions.
1132d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy*/
1142d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristytypedef struct _ChannelInfo
1152d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy{
1162d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy  short int
1172d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy    type;
1182d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy
119bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  size_t
1202d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy    size;
1212d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy} ChannelInfo;
1222d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy
123a41d97fa7de942f144af6cfcceba24c523775c54dirktypedef struct _MaskInfo
1242d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy{
125a41d97fa7de942f144af6cfcceba24c523775c54dirk  Image
126a41d97fa7de942f144af6cfcceba24c523775c54dirk    *image;
127a41d97fa7de942f144af6cfcceba24c523775c54dirk
1282d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy  RectangleInfo
129a41d97fa7de942f144af6cfcceba24c523775c54dirk    page;
1302d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy
131a41d97fa7de942f144af6cfcceba24c523775c54dirk  unsigned char
132a41d97fa7de942f144af6cfcceba24c523775c54dirk    background,
133a41d97fa7de942f144af6cfcceba24c523775c54dirk    flags;
134a41d97fa7de942f144af6cfcceba24c523775c54dirk} MaskInfo;
1352d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy
136a41d97fa7de942f144af6cfcceba24c523775c54dirktypedef struct _LayerInfo
137a41d97fa7de942f144af6cfcceba24c523775c54dirk{
1382d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy  ChannelInfo
1392d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy    channel_info[MaxPSDChannels];
1402d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy
1412d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy  char
1422d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy    blendkey[4];
1432d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy
144a41d97fa7de942f144af6cfcceba24c523775c54dirk  Image
145a41d97fa7de942f144af6cfcceba24c523775c54dirk    *image;
146a41d97fa7de942f144af6cfcceba24c523775c54dirk
147a41d97fa7de942f144af6cfcceba24c523775c54dirk  MaskInfo
148a41d97fa7de942f144af6cfcceba24c523775c54dirk    mask;
149a41d97fa7de942f144af6cfcceba24c523775c54dirk
1502d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy  Quantum
1512d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy    opacity;
1522d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy
153a41d97fa7de942f144af6cfcceba24c523775c54dirk  RectangleInfo
154a41d97fa7de942f144af6cfcceba24c523775c54dirk    page;
1552d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy
156bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  size_t
1572d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy    offset_x,
1582d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy    offset_y;
1592d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy
1602d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy  unsigned char
161a41d97fa7de942f144af6cfcceba24c523775c54dirk    clipping,
162a41d97fa7de942f144af6cfcceba24c523775c54dirk    flags,
163a41d97fa7de942f144af6cfcceba24c523775c54dirk    name[256],
164a41d97fa7de942f144af6cfcceba24c523775c54dirk    visible;
1652d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy
166a41d97fa7de942f144af6cfcceba24c523775c54dirk  unsigned short
167a41d97fa7de942f144af6cfcceba24c523775c54dirk    channels;
1682d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy} LayerInfo;
169a41d97fa7de942f144af6cfcceba24c523775c54dirk
1702d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy/*
1713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Forward declarations.
1723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
1733ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic MagickBooleanType
1743a37efd7ece979e9c63dc8f2f2d3816bab8b1156cristy  WritePSDImage(const ImageInfo *,Image *,ExceptionInfo *);
1753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
1773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   I s P S D                                                                 %
1823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  IsPSD()() returns MagickTrue if the image format type, identified by the
1883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  magick string, is PSD.
1893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the IsPSD method is:
1913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      MagickBooleanType IsPSD(const unsigned char *magick,const size_t length)
1933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
1953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o magick: compare image format pattern against these bytes.
1973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o length: Specifies the length of the magick string.
1993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
2013ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic MagickBooleanType IsPSD(const unsigned char *magick,const size_t length)
2023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
2033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (length < 4)
2043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(MagickFalse);
2053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (LocaleNCompare((const char *) magick,"8BPS",4) == 0)
2063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(MagickTrue);
2073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(MagickFalse);
2083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
2093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
2113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   R e a d P S D I m a g e                                                   %
2163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
2193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  ReadPSDImage() reads an Adobe Photoshop image file and returns it.  It
2223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  allocates the memory necessary for the new Image structure and returns a
2233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  pointer to the new image.
2243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the ReadPSDImage method is:
2263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
22790de83d3fe5221a8896ab53556c2e7992078a96ccristy%      Image *ReadPSDImage(image_info,ExceptionInfo *exception)
2283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
2303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image_info: the image info.
2323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o exception: return any errors or warnings in this structure.
2343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
2363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
23719eb64195ef744f61293025952df1e5e6de66524cristystatic const char *CompositeOperatorToPSDBlendMode(CompositeOperator op)
238cd0817764b65f779425ef95dfd90abbcf76d0a46cristy{
239cd0817764b65f779425ef95dfd90abbcf76d0a46cristy  const char
240cd0817764b65f779425ef95dfd90abbcf76d0a46cristy    *blend_mode;
241cd0817764b65f779425ef95dfd90abbcf76d0a46cristy
24219eb64195ef744f61293025952df1e5e6de66524cristy  switch (op)
243cd0817764b65f779425ef95dfd90abbcf76d0a46cristy  {
244fdc035a228cf5dbcefcb3e86f57dfbfbfd77ee13cristy    case ColorBurnCompositeOp:  blend_mode = "idiv";  break;
245fdc035a228cf5dbcefcb3e86f57dfbfbfd77ee13cristy    case ColorDodgeCompositeOp: blend_mode = "div ";  break;
246216b90f9cd72e8dbcc34653fe1e040ab4f876a5ecristy    case ColorizeCompositeOp:   blend_mode = "colr";  break;
247216b90f9cd72e8dbcc34653fe1e040ab4f876a5ecristy    case DarkenCompositeOp:     blend_mode = "dark";  break;
248216b90f9cd72e8dbcc34653fe1e040ab4f876a5ecristy    case DifferenceCompositeOp: blend_mode = "diff";  break;
249216b90f9cd72e8dbcc34653fe1e040ab4f876a5ecristy    case DissolveCompositeOp:   blend_mode = "diss";  break;
250fdc035a228cf5dbcefcb3e86f57dfbfbfd77ee13cristy    case ExclusionCompositeOp:  blend_mode = "smud";  break;
251216b90f9cd72e8dbcc34653fe1e040ab4f876a5ecristy    case HardLightCompositeOp:  blend_mode = "hLit";  break;
252fdc035a228cf5dbcefcb3e86f57dfbfbfd77ee13cristy    case HardMixCompositeOp:    blend_mode = "hMix";  break;
253216b90f9cd72e8dbcc34653fe1e040ab4f876a5ecristy    case HueCompositeOp:        blend_mode = "hue ";  break;
254216b90f9cd72e8dbcc34653fe1e040ab4f876a5ecristy    case LightenCompositeOp:    blend_mode = "lite";  break;
255fdc035a228cf5dbcefcb3e86f57dfbfbfd77ee13cristy    case LinearBurnCompositeOp: blend_mode = "lbrn";  break;
256fdc035a228cf5dbcefcb3e86f57dfbfbfd77ee13cristy    case LinearDodgeCompositeOp:blend_mode = "lddg";  break;
257fdc035a228cf5dbcefcb3e86f57dfbfbfd77ee13cristy    case LinearLightCompositeOp:blend_mode = "lLit";  break;
258216b90f9cd72e8dbcc34653fe1e040ab4f876a5ecristy    case LuminizeCompositeOp:   blend_mode = "lum ";  break;
259216b90f9cd72e8dbcc34653fe1e040ab4f876a5ecristy    case MultiplyCompositeOp:   blend_mode = "mul ";  break;
260216b90f9cd72e8dbcc34653fe1e040ab4f876a5ecristy    case OverCompositeOp:       blend_mode = "norm";  break;
261216b90f9cd72e8dbcc34653fe1e040ab4f876a5ecristy    case OverlayCompositeOp:    blend_mode = "over";  break;
262fdc035a228cf5dbcefcb3e86f57dfbfbfd77ee13cristy    case PinLightCompositeOp:   blend_mode = "pLit";  break;
263216b90f9cd72e8dbcc34653fe1e040ab4f876a5ecristy    case SaturateCompositeOp:   blend_mode = "sat ";  break;
264216b90f9cd72e8dbcc34653fe1e040ab4f876a5ecristy    case ScreenCompositeOp:     blend_mode = "scrn";  break;
265216b90f9cd72e8dbcc34653fe1e040ab4f876a5ecristy    case SoftLightCompositeOp:  blend_mode = "sLit";  break;
266fdc035a228cf5dbcefcb3e86f57dfbfbfd77ee13cristy    case VividLightCompositeOp: blend_mode = "vLit";  break;
267216b90f9cd72e8dbcc34653fe1e040ab4f876a5ecristy    default:                    blend_mode = "norm";
268cd0817764b65f779425ef95dfd90abbcf76d0a46cristy  }
269cd0817764b65f779425ef95dfd90abbcf76d0a46cristy  return(blend_mode);
270cd0817764b65f779425ef95dfd90abbcf76d0a46cristy}
271cd0817764b65f779425ef95dfd90abbcf76d0a46cristy
272b20a1794de28edf28c46f2268914c15781482530dirk/*
273b20a1794de28edf28c46f2268914c15781482530dirk  For some reason Photoshop seems to blend semi-transparent pixels with white.
274b20a1794de28edf28c46f2268914c15781482530dirk  This method reverts the blending. This can be disabled by setting the
275b20a1794de28edf28c46f2268914c15781482530dirk  option 'psd:alpha-unblend' to off.
276b20a1794de28edf28c46f2268914c15781482530dirk*/
277b20a1794de28edf28c46f2268914c15781482530dirkstatic MagickBooleanType CorrectPSDAlphaBlend(const ImageInfo *image_info,
278b20a1794de28edf28c46f2268914c15781482530dirk  Image *image,ExceptionInfo* exception)
279b20a1794de28edf28c46f2268914c15781482530dirk{
280b20a1794de28edf28c46f2268914c15781482530dirk  const char
281b20a1794de28edf28c46f2268914c15781482530dirk    *option;
282b20a1794de28edf28c46f2268914c15781482530dirk
283b20a1794de28edf28c46f2268914c15781482530dirk  MagickBooleanType
284b20a1794de28edf28c46f2268914c15781482530dirk    status;
285b20a1794de28edf28c46f2268914c15781482530dirk
286b20a1794de28edf28c46f2268914c15781482530dirk  ssize_t
287b20a1794de28edf28c46f2268914c15781482530dirk    y;
288b20a1794de28edf28c46f2268914c15781482530dirk
289b20a1794de28edf28c46f2268914c15781482530dirk  if (image->alpha_trait != BlendPixelTrait || image->colorspace != sRGBColorspace)
290b20a1794de28edf28c46f2268914c15781482530dirk    return(MagickTrue);
291b20a1794de28edf28c46f2268914c15781482530dirk  option=GetImageOption(image_info,"psd:alpha-unblend");
292b20a1794de28edf28c46f2268914c15781482530dirk  if (IsStringFalse(option) != MagickFalse)
293b20a1794de28edf28c46f2268914c15781482530dirk    return(MagickTrue);
294b20a1794de28edf28c46f2268914c15781482530dirk  status=MagickTrue;
295b20a1794de28edf28c46f2268914c15781482530dirk#if defined(MAGICKCORE_OPENMP_SUPPORT)
296b20a1794de28edf28c46f2268914c15781482530dirk#pragma omp parallel for schedule(static,4) shared(status) \
297b20a1794de28edf28c46f2268914c15781482530dirk  magick_threads(image,image,image->rows,1)
298b20a1794de28edf28c46f2268914c15781482530dirk#endif
299b20a1794de28edf28c46f2268914c15781482530dirk  for (y=0; y < (ssize_t) image->rows; y++)
300b20a1794de28edf28c46f2268914c15781482530dirk  {
301b20a1794de28edf28c46f2268914c15781482530dirk    register Quantum
30205d2ff7ebf21f659f5b11e45afb294e152f4330cdirk      *magick_restrict q;
303b20a1794de28edf28c46f2268914c15781482530dirk
304b20a1794de28edf28c46f2268914c15781482530dirk    register ssize_t
305b20a1794de28edf28c46f2268914c15781482530dirk      x;
306b20a1794de28edf28c46f2268914c15781482530dirk
307b20a1794de28edf28c46f2268914c15781482530dirk    if (status == MagickFalse)
308b20a1794de28edf28c46f2268914c15781482530dirk      continue;
309b20a1794de28edf28c46f2268914c15781482530dirk    q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
310b20a1794de28edf28c46f2268914c15781482530dirk    if (q == (Quantum *) NULL)
311b20a1794de28edf28c46f2268914c15781482530dirk    {
312b20a1794de28edf28c46f2268914c15781482530dirk      status=MagickFalse;
313b20a1794de28edf28c46f2268914c15781482530dirk      continue;
314b20a1794de28edf28c46f2268914c15781482530dirk    }
315b20a1794de28edf28c46f2268914c15781482530dirk    for (x=0; x < (ssize_t) image->columns; x++)
316b20a1794de28edf28c46f2268914c15781482530dirk    {
317b20a1794de28edf28c46f2268914c15781482530dirk      double
318b20a1794de28edf28c46f2268914c15781482530dirk        gamma;
319b20a1794de28edf28c46f2268914c15781482530dirk
320b20a1794de28edf28c46f2268914c15781482530dirk      register ssize_t
321b20a1794de28edf28c46f2268914c15781482530dirk        i;
322b20a1794de28edf28c46f2268914c15781482530dirk
323b20a1794de28edf28c46f2268914c15781482530dirk      gamma=QuantumScale*GetPixelAlpha(image, q);
324b20a1794de28edf28c46f2268914c15781482530dirk      if (gamma != 0.0 && gamma != 1.0)
325b20a1794de28edf28c46f2268914c15781482530dirk        {
326b20a1794de28edf28c46f2268914c15781482530dirk          for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
327b20a1794de28edf28c46f2268914c15781482530dirk          {
328b20a1794de28edf28c46f2268914c15781482530dirk            PixelChannel channel=GetPixelChannelChannel(image,i);
329b20a1794de28edf28c46f2268914c15781482530dirk            if (channel != AlphaPixelChannel)
330b20a1794de28edf28c46f2268914c15781482530dirk              q[i]=ClampToQuantum((q[i]-((1.0-gamma)*QuantumRange))/gamma);
331b20a1794de28edf28c46f2268914c15781482530dirk          }
332b20a1794de28edf28c46f2268914c15781482530dirk        }
333b20a1794de28edf28c46f2268914c15781482530dirk      q+=GetPixelChannels(image);
334b20a1794de28edf28c46f2268914c15781482530dirk    }
335b20a1794de28edf28c46f2268914c15781482530dirk    if (SyncAuthenticPixels(image,exception) == MagickFalse)
336b20a1794de28edf28c46f2268914c15781482530dirk      status=MagickFalse;
337b20a1794de28edf28c46f2268914c15781482530dirk  }
338b20a1794de28edf28c46f2268914c15781482530dirk
339b20a1794de28edf28c46f2268914c15781482530dirk  return(status);
340b20a1794de28edf28c46f2268914c15781482530dirk}
341b20a1794de28edf28c46f2268914c15781482530dirk
342b41f080d52a5ff2d9c235cffac1419b84028bd31dirkstatic inline CompressionType ConvertPSDCompression(
343b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  PSDCompressionType compression)
344b41f080d52a5ff2d9c235cffac1419b84028bd31dirk{
345b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  switch (compression)
346b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  {
347b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    case RLE:
348b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      return RLECompression;
349b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    case ZipWithPrediction:
350b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    case ZipWithoutPrediction:
351b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      return ZipCompression;
352b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    default:
353b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      return NoCompression;
354b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  }
355b41f080d52a5ff2d9c235cffac1419b84028bd31dirk}
356b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
357b20a1794de28edf28c46f2268914c15781482530dirkstatic MagickBooleanType CorrectPSDOpacity(LayerInfo *layer_info,
358b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  ExceptionInfo *exception)
359b41f080d52a5ff2d9c235cffac1419b84028bd31dirk{
360b20a1794de28edf28c46f2268914c15781482530dirk  MagickBooleanType
361b20a1794de28edf28c46f2268914c15781482530dirk    status;
362b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
363b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  ssize_t
364b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    y;
365b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
366b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  if (layer_info->opacity == OpaqueAlpha)
367b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    return(MagickTrue);
368b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
369b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  layer_info->image->alpha_trait=BlendPixelTrait;
370b20a1794de28edf28c46f2268914c15781482530dirk  status=MagickTrue;
371b20a1794de28edf28c46f2268914c15781482530dirk#if defined(MAGICKCORE_OPENMP_SUPPORT)
372b20a1794de28edf28c46f2268914c15781482530dirk#pragma omp parallel for schedule(static,4) shared(status) \
373b20a1794de28edf28c46f2268914c15781482530dirk  magick_threads(layer_info->image,layer_info->image,layer_info->image->rows,1)
374b20a1794de28edf28c46f2268914c15781482530dirk#endif
375b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  for (y=0; y < (ssize_t) layer_info->image->rows; y++)
376b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  {
377b20a1794de28edf28c46f2268914c15781482530dirk    register Quantum
37805d2ff7ebf21f659f5b11e45afb294e152f4330cdirk      *magick_restrict q;
379b20a1794de28edf28c46f2268914c15781482530dirk
380b20a1794de28edf28c46f2268914c15781482530dirk    register ssize_t
381b20a1794de28edf28c46f2268914c15781482530dirk      x;
382b20a1794de28edf28c46f2268914c15781482530dirk
383b20a1794de28edf28c46f2268914c15781482530dirk    if (status == MagickFalse)
384b20a1794de28edf28c46f2268914c15781482530dirk      continue;
385d8083a693bea157df66921cb7570880bb081dcd1cristy    q=GetAuthenticPixels(layer_info->image,0,y,layer_info->image->columns,1,
386d8083a693bea157df66921cb7570880bb081dcd1cristy      exception);
387b20a1794de28edf28c46f2268914c15781482530dirk    if (q == (Quantum *)NULL)
388b20a1794de28edf28c46f2268914c15781482530dirk      {
389b20a1794de28edf28c46f2268914c15781482530dirk        status=MagickFalse;
390b20a1794de28edf28c46f2268914c15781482530dirk        continue;
391b20a1794de28edf28c46f2268914c15781482530dirk      }
392b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    for (x=0; x < (ssize_t) layer_info->image->columns; x++)
393b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    {
394b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      SetPixelAlpha(layer_info->image,(Quantum) (QuantumScale*(GetPixelAlpha(
395b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        layer_info->image,q))*layer_info->opacity),q);
396b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      q+=GetPixelChannels(layer_info->image);
397b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    }
398b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    if (SyncAuthenticPixels(layer_info->image,exception) == MagickFalse)
399b20a1794de28edf28c46f2268914c15781482530dirk      status=MagickFalse;
400b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  }
401b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
402b20a1794de28edf28c46f2268914c15781482530dirk  return(status);
403b41f080d52a5ff2d9c235cffac1419b84028bd31dirk}
404b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
405cd0817764b65f779425ef95dfd90abbcf76d0a46cristystatic ssize_t DecodePSDPixels(const size_t number_compact_pixels,
406bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  const unsigned char *compact_pixels,const ssize_t depth,
407cd0817764b65f779425ef95dfd90abbcf76d0a46cristy  const size_t number_pixels,unsigned char *pixels)
408cd0817764b65f779425ef95dfd90abbcf76d0a46cristy{
409891df41d828a641db63d8bae45ca027d0e28341ddirk#define CheckNumberCompactPixels \
410891df41d828a641db63d8bae45ca027d0e28341ddirk  if (packets == 0) \
411891df41d828a641db63d8bae45ca027d0e28341ddirk    return(i); \
412891df41d828a641db63d8bae45ca027d0e28341ddirk  packets--
413891df41d828a641db63d8bae45ca027d0e28341ddirk
414891df41d828a641db63d8bae45ca027d0e28341ddirk#define CheckNumberPixels(count) \
415891df41d828a641db63d8bae45ca027d0e28341ddirk  if (((ssize_t) i + count) > (ssize_t) number_pixels) \
416891df41d828a641db63d8bae45ca027d0e28341ddirk    return(i); \
417891df41d828a641db63d8bae45ca027d0e28341ddirk  i+=count
418891df41d828a641db63d8bae45ca027d0e28341ddirk
419cd0817764b65f779425ef95dfd90abbcf76d0a46cristy  int
420cd0817764b65f779425ef95dfd90abbcf76d0a46cristy    pixel;
421cd0817764b65f779425ef95dfd90abbcf76d0a46cristy
422cd0817764b65f779425ef95dfd90abbcf76d0a46cristy  register ssize_t
423cd0817764b65f779425ef95dfd90abbcf76d0a46cristy    i,
424cd0817764b65f779425ef95dfd90abbcf76d0a46cristy    j;
425cd0817764b65f779425ef95dfd90abbcf76d0a46cristy
426cd0817764b65f779425ef95dfd90abbcf76d0a46cristy  size_t
427cd0817764b65f779425ef95dfd90abbcf76d0a46cristy    length;
428cd0817764b65f779425ef95dfd90abbcf76d0a46cristy
429802d364f093d693396e7052869766dd9fbe4d94bcristy  ssize_t
430802d364f093d693396e7052869766dd9fbe4d94bcristy    packets;
431802d364f093d693396e7052869766dd9fbe4d94bcristy
432cd0817764b65f779425ef95dfd90abbcf76d0a46cristy  packets=(ssize_t) number_compact_pixels;
433cd0817764b65f779425ef95dfd90abbcf76d0a46cristy  for (i=0; (packets > 1) && (i < (ssize_t) number_pixels); )
434cd0817764b65f779425ef95dfd90abbcf76d0a46cristy  {
435db435e2035e894ad4e7bda613cc95bb02ca4dac3dirk    packets--;
43640084fae9e39c89210ccb4a80dcdd32fc16e640edirk    length=(size_t) (*compact_pixels++);
437cd0817764b65f779425ef95dfd90abbcf76d0a46cristy    if (length == 128)
438cd0817764b65f779425ef95dfd90abbcf76d0a46cristy      continue;
439cd0817764b65f779425ef95dfd90abbcf76d0a46cristy    if (length > 128)
440cd0817764b65f779425ef95dfd90abbcf76d0a46cristy      {
441cd0817764b65f779425ef95dfd90abbcf76d0a46cristy        length=256-length+1;
442891df41d828a641db63d8bae45ca027d0e28341ddirk        CheckNumberCompactPixels;
443cd0817764b65f779425ef95dfd90abbcf76d0a46cristy        pixel=(*compact_pixels++);
444284c7d8f94022fc8106d28e9659bd4e4ff2154ffcristy        for (j=0; j < (ssize_t) length; j++)
445cd0817764b65f779425ef95dfd90abbcf76d0a46cristy        {
446cd0817764b65f779425ef95dfd90abbcf76d0a46cristy          switch (depth)
447cd0817764b65f779425ef95dfd90abbcf76d0a46cristy          {
448cd0817764b65f779425ef95dfd90abbcf76d0a46cristy            case 1:
449cd0817764b65f779425ef95dfd90abbcf76d0a46cristy            {
450891df41d828a641db63d8bae45ca027d0e28341ddirk              CheckNumberPixels(8);
451284c7d8f94022fc8106d28e9659bd4e4ff2154ffcristy              *pixels++=(pixel >> 7) & 0x01 ? 0U : 255U;
452284c7d8f94022fc8106d28e9659bd4e4ff2154ffcristy              *pixels++=(pixel >> 6) & 0x01 ? 0U : 255U;
453284c7d8f94022fc8106d28e9659bd4e4ff2154ffcristy              *pixels++=(pixel >> 5) & 0x01 ? 0U : 255U;
454284c7d8f94022fc8106d28e9659bd4e4ff2154ffcristy              *pixels++=(pixel >> 4) & 0x01 ? 0U : 255U;
455284c7d8f94022fc8106d28e9659bd4e4ff2154ffcristy              *pixels++=(pixel >> 3) & 0x01 ? 0U : 255U;
456284c7d8f94022fc8106d28e9659bd4e4ff2154ffcristy              *pixels++=(pixel >> 2) & 0x01 ? 0U : 255U;
457284c7d8f94022fc8106d28e9659bd4e4ff2154ffcristy              *pixels++=(pixel >> 1) & 0x01 ? 0U : 255U;
458284c7d8f94022fc8106d28e9659bd4e4ff2154ffcristy              *pixels++=(pixel >> 0) & 0x01 ? 0U : 255U;
459cd0817764b65f779425ef95dfd90abbcf76d0a46cristy              break;
460cd0817764b65f779425ef95dfd90abbcf76d0a46cristy            }
461cd0817764b65f779425ef95dfd90abbcf76d0a46cristy            case 2:
462cd0817764b65f779425ef95dfd90abbcf76d0a46cristy            {
463891df41d828a641db63d8bae45ca027d0e28341ddirk              CheckNumberPixels(4);
464284c7d8f94022fc8106d28e9659bd4e4ff2154ffcristy              *pixels++=(unsigned char) ((pixel >> 6) & 0x03);
465284c7d8f94022fc8106d28e9659bd4e4ff2154ffcristy              *pixels++=(unsigned char) ((pixel >> 4) & 0x03);
466284c7d8f94022fc8106d28e9659bd4e4ff2154ffcristy              *pixels++=(unsigned char) ((pixel >> 2) & 0x03);
467284c7d8f94022fc8106d28e9659bd4e4ff2154ffcristy              *pixels++=(unsigned char) ((pixel & 0x03) & 0x03);
468891df41d828a641db63d8bae45ca027d0e28341ddirk              break;
469891df41d828a641db63d8bae45ca027d0e28341ddirk            }
470891df41d828a641db63d8bae45ca027d0e28341ddirk            case 4:
471891df41d828a641db63d8bae45ca027d0e28341ddirk            {
472891df41d828a641db63d8bae45ca027d0e28341ddirk              CheckNumberPixels(2);
473891df41d828a641db63d8bae45ca027d0e28341ddirk              *pixels++=(unsigned char) ((pixel >> 4) & 0xff);
474891df41d828a641db63d8bae45ca027d0e28341ddirk              *pixels++=(unsigned char) ((pixel & 0x0f) & 0xff);
475cd0817764b65f779425ef95dfd90abbcf76d0a46cristy              break;
476cd0817764b65f779425ef95dfd90abbcf76d0a46cristy            }
477cd0817764b65f779425ef95dfd90abbcf76d0a46cristy            default:
478cd0817764b65f779425ef95dfd90abbcf76d0a46cristy            {
479891df41d828a641db63d8bae45ca027d0e28341ddirk              CheckNumberPixels(1);
480284c7d8f94022fc8106d28e9659bd4e4ff2154ffcristy              *pixels++=(unsigned char) pixel;
481cd0817764b65f779425ef95dfd90abbcf76d0a46cristy              break;
482cd0817764b65f779425ef95dfd90abbcf76d0a46cristy            }
483cd0817764b65f779425ef95dfd90abbcf76d0a46cristy          }
484cd0817764b65f779425ef95dfd90abbcf76d0a46cristy        }
485cd0817764b65f779425ef95dfd90abbcf76d0a46cristy        continue;
486cd0817764b65f779425ef95dfd90abbcf76d0a46cristy      }
487cd0817764b65f779425ef95dfd90abbcf76d0a46cristy    length++;
488284c7d8f94022fc8106d28e9659bd4e4ff2154ffcristy    for (j=0; j < (ssize_t) length; j++)
489cd0817764b65f779425ef95dfd90abbcf76d0a46cristy    {
49030eec879c8b446b0ea9a3bb0da1a441cc8482bc4dirk      CheckNumberCompactPixels;
491cd0817764b65f779425ef95dfd90abbcf76d0a46cristy      switch (depth)
492cd0817764b65f779425ef95dfd90abbcf76d0a46cristy      {
493cd0817764b65f779425ef95dfd90abbcf76d0a46cristy        case 1:
494cd0817764b65f779425ef95dfd90abbcf76d0a46cristy        {
495891df41d828a641db63d8bae45ca027d0e28341ddirk          CheckNumberPixels(8);
496284c7d8f94022fc8106d28e9659bd4e4ff2154ffcristy          *pixels++=(*compact_pixels >> 7) & 0x01 ? 0U : 255U;
497284c7d8f94022fc8106d28e9659bd4e4ff2154ffcristy          *pixels++=(*compact_pixels >> 6) & 0x01 ? 0U : 255U;
498284c7d8f94022fc8106d28e9659bd4e4ff2154ffcristy          *pixels++=(*compact_pixels >> 5) & 0x01 ? 0U : 255U;
499284c7d8f94022fc8106d28e9659bd4e4ff2154ffcristy          *pixels++=(*compact_pixels >> 4) & 0x01 ? 0U : 255U;
500284c7d8f94022fc8106d28e9659bd4e4ff2154ffcristy          *pixels++=(*compact_pixels >> 3) & 0x01 ? 0U : 255U;
501284c7d8f94022fc8106d28e9659bd4e4ff2154ffcristy          *pixels++=(*compact_pixels >> 2) & 0x01 ? 0U : 255U;
502284c7d8f94022fc8106d28e9659bd4e4ff2154ffcristy          *pixels++=(*compact_pixels >> 1) & 0x01 ? 0U : 255U;
503284c7d8f94022fc8106d28e9659bd4e4ff2154ffcristy          *pixels++=(*compact_pixels >> 0) & 0x01 ? 0U : 255U;
504cd0817764b65f779425ef95dfd90abbcf76d0a46cristy          break;
505cd0817764b65f779425ef95dfd90abbcf76d0a46cristy        }
506cd0817764b65f779425ef95dfd90abbcf76d0a46cristy        case 2:
507cd0817764b65f779425ef95dfd90abbcf76d0a46cristy        {
508891df41d828a641db63d8bae45ca027d0e28341ddirk          CheckNumberPixels(4);
509618a96665a51cb540c998330e660f1c7506f6b08cristy          *pixels++=(*compact_pixels >> 6) & 0x03;
510618a96665a51cb540c998330e660f1c7506f6b08cristy          *pixels++=(*compact_pixels >> 4) & 0x03;
511618a96665a51cb540c998330e660f1c7506f6b08cristy          *pixels++=(*compact_pixels >> 2) & 0x03;
512618a96665a51cb540c998330e660f1c7506f6b08cristy          *pixels++=(*compact_pixels & 0x03) & 0x03;
513891df41d828a641db63d8bae45ca027d0e28341ddirk          break;
514891df41d828a641db63d8bae45ca027d0e28341ddirk        }
515891df41d828a641db63d8bae45ca027d0e28341ddirk        case 4:
516891df41d828a641db63d8bae45ca027d0e28341ddirk        {
517891df41d828a641db63d8bae45ca027d0e28341ddirk          CheckNumberPixels(2);
518891df41d828a641db63d8bae45ca027d0e28341ddirk          *pixels++=(*compact_pixels >> 4) & 0xff;
519891df41d828a641db63d8bae45ca027d0e28341ddirk          *pixels++=(*compact_pixels & 0x0f) & 0xff;
520cd0817764b65f779425ef95dfd90abbcf76d0a46cristy          break;
521cd0817764b65f779425ef95dfd90abbcf76d0a46cristy        }
522cd0817764b65f779425ef95dfd90abbcf76d0a46cristy        default:
523cd0817764b65f779425ef95dfd90abbcf76d0a46cristy        {
524891df41d828a641db63d8bae45ca027d0e28341ddirk          CheckNumberPixels(1);
525cd0817764b65f779425ef95dfd90abbcf76d0a46cristy          *pixels++=(*compact_pixels);
526cd0817764b65f779425ef95dfd90abbcf76d0a46cristy          break;
527cd0817764b65f779425ef95dfd90abbcf76d0a46cristy        }
528cd0817764b65f779425ef95dfd90abbcf76d0a46cristy      }
529cd0817764b65f779425ef95dfd90abbcf76d0a46cristy      compact_pixels++;
530cd0817764b65f779425ef95dfd90abbcf76d0a46cristy    }
531cd0817764b65f779425ef95dfd90abbcf76d0a46cristy  }
532cd0817764b65f779425ef95dfd90abbcf76d0a46cristy  return(i);
533cd0817764b65f779425ef95dfd90abbcf76d0a46cristy}
534cd0817764b65f779425ef95dfd90abbcf76d0a46cristy
535bd8bd8572e272ce0bc730bfa0296b8f048ea2da1dirkstatic inline LayerInfo *DestroyLayerInfo(LayerInfo *layer_info,
536bd8bd8572e272ce0bc730bfa0296b8f048ea2da1dirk  const ssize_t number_layers)
537bd8bd8572e272ce0bc730bfa0296b8f048ea2da1dirk{
538bd8bd8572e272ce0bc730bfa0296b8f048ea2da1dirk  ssize_t
539bd8bd8572e272ce0bc730bfa0296b8f048ea2da1dirk    i;
540bd8bd8572e272ce0bc730bfa0296b8f048ea2da1dirk
541bd8bd8572e272ce0bc730bfa0296b8f048ea2da1dirk  for (i=0; i<number_layers; i++)
542bd8bd8572e272ce0bc730bfa0296b8f048ea2da1dirk  {
543bd8bd8572e272ce0bc730bfa0296b8f048ea2da1dirk    if (layer_info[i].image != (Image *) NULL)
544bd8bd8572e272ce0bc730bfa0296b8f048ea2da1dirk      layer_info[i].image=DestroyImage(layer_info[i].image);
545a41d97fa7de942f144af6cfcceba24c523775c54dirk    if (layer_info[i].mask.image != (Image *) NULL)
546a41d97fa7de942f144af6cfcceba24c523775c54dirk      layer_info[i].mask.image=DestroyImage(layer_info[i].mask.image);
547bd8bd8572e272ce0bc730bfa0296b8f048ea2da1dirk  }
548bd8bd8572e272ce0bc730bfa0296b8f048ea2da1dirk
549bd8bd8572e272ce0bc730bfa0296b8f048ea2da1dirk  return (LayerInfo *) RelinquishMagickMemory(layer_info);
550bd8bd8572e272ce0bc730bfa0296b8f048ea2da1dirk}
551bd8bd8572e272ce0bc730bfa0296b8f048ea2da1dirk
552b41f080d52a5ff2d9c235cffac1419b84028bd31dirkstatic inline size_t GetPSDPacketSize(Image *image)
5532d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy{
554b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  if (image->storage_class == PseudoClass)
555b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    {
556b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      if (image->colors > 256)
557b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        return(2);
558b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      else if (image->depth > 8)
559b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        return(2);
560b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    }
561b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  else
562b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    if (image->depth > 8)
563b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      return(2);
564b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
565b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  return(1);
5662d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy}
5672d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy
5684d9863ca77e690fdde8653d1f3db0721bd25978edirkstatic inline MagickSizeType GetPSDSize(const PSDInfo *psd_info,Image *image)
5692d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy{
5702d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy  if (psd_info->version == 1)
57187038d5d4cc04fb99d6560ae95f3f07a87563323dirk    return((MagickSizeType) ReadBlobLong(image));
57287038d5d4cc04fb99d6560ae95f3f07a87563323dirk  return((MagickSizeType) ReadBlobLongLong(image));
5732d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy}
5742d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy
575b41f080d52a5ff2d9c235cffac1419b84028bd31dirkstatic inline size_t GetPSDRowSize(Image *image)
576b41f080d52a5ff2d9c235cffac1419b84028bd31dirk{
577b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  if (image->depth == 1)
5785f16640725b1225e6337c62526e6577f0f88edb8dirk    return(((image->columns+7)/8)*GetPSDPacketSize(image));
579b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  else
580b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    return(image->columns*GetPSDPacketSize(image));
581b41f080d52a5ff2d9c235cffac1419b84028bd31dirk}
582b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
583cd0817764b65f779425ef95dfd90abbcf76d0a46cristystatic const char *ModeToString(PSDImageType type)
5843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
585cd0817764b65f779425ef95dfd90abbcf76d0a46cristy  switch (type)
5863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
5873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case BitmapMode: return "Bitmap";
5883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case GrayscaleMode: return "Grayscale";
5893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case IndexedMode: return "Indexed";
5903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case RGBMode: return "RGB";
5913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case CMYKMode:  return "CMYK";
5923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case MultichannelMode: return "Multichannel";
5933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case DuotoneMode: return "Duotone";
5943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case LabMode: return "L*A*B";
5953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    default: return "unknown";
5963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
5973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
5983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
599b20a1794de28edf28c46f2268914c15781482530dirkstatic MagickBooleanType NegateCMYK(Image *image,ExceptionInfo *exception)
600d9795a19984ae1bae9205b7c0fe5de75461978b3dirk{
601d9795a19984ae1bae9205b7c0fe5de75461978b3dirk  ChannelType
602d9795a19984ae1bae9205b7c0fe5de75461978b3dirk    channel_mask;
603d9795a19984ae1bae9205b7c0fe5de75461978b3dirk
604b20a1794de28edf28c46f2268914c15781482530dirk  MagickBooleanType
605b20a1794de28edf28c46f2268914c15781482530dirk    status;
606b20a1794de28edf28c46f2268914c15781482530dirk
607d9795a19984ae1bae9205b7c0fe5de75461978b3dirk  channel_mask=SetImageChannelMask(image,(ChannelType)(AllChannels &~
608d9795a19984ae1bae9205b7c0fe5de75461978b3dirk    AlphaChannel));
609b20a1794de28edf28c46f2268914c15781482530dirk  status=NegateImage(image,MagickFalse,exception);
610d9795a19984ae1bae9205b7c0fe5de75461978b3dirk  (void) SetImageChannelMask(image,channel_mask);
611b20a1794de28edf28c46f2268914c15781482530dirk  return(status);
612d9795a19984ae1bae9205b7c0fe5de75461978b3dirk}
613d9795a19984ae1bae9205b7c0fe5de75461978b3dirk
6147ec893210d13a7424e5a7c3200568f1bf5317040dirkstatic void ParseImageResourceBlocks(Image *image,
61518c0e4dff391a0a98e7f478d0d86bbd08f7708d0dirk  const unsigned char *blocks,size_t length,
61618c0e4dff391a0a98e7f478d0d86bbd08f7708d0dirk  MagickBooleanType *has_merged_image,ExceptionInfo *exception)
6173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
6183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  const unsigned char
6193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *p;
6203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  StringInfo
6223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *profile;
6233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6246befb0f8f253ef359d1e14d1e569c1a848d02daccristy  unsigned int
6253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    count,
6266befb0f8f253ef359d1e14d1e569c1a848d02daccristy    long_sans;
6273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  unsigned short
6293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    id,
6303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    short_sans;
6313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (length < 16)
6337ec893210d13a7424e5a7c3200568f1bf5317040dirk    return;
634b3f97ae45019a91b30792a6fa42d81a2689a7025cristy  profile=BlobToStringInfo((const unsigned char *) NULL,length);
6353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  SetStringInfoDatum(profile,blocks);
636d15e65928aec551b7388c2863de3e3e628e2e0ddcristy  (void) SetImageProfile(image,"8bim",profile,exception);
6373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  profile=DestroyStringInfo(profile);
6383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  for (p=blocks; (p >= blocks) && (p < (blocks+length-16)); )
6393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
6403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
6413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
6426befb0f8f253ef359d1e14d1e569c1a848d02daccristy    p=PushLongPixel(MSBEndian,p,&long_sans);
643f11065e08c32a2c6a82e67ade789e83936724a8ecristy    p=PushShortPixel(MSBEndian,p,&id);
644f11065e08c32a2c6a82e67ade789e83936724a8ecristy    p=PushShortPixel(MSBEndian,p,&short_sans);
645f11065e08c32a2c6a82e67ade789e83936724a8ecristy    p=PushLongPixel(MSBEndian,p,&count);
64615dd190dfd7e7a3341bdc378f4f0daba9873322cCristy    if ((p+count) > (blocks+length-16))
6477ec893210d13a7424e5a7c3200568f1bf5317040dirk      return;
6483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    switch (id)
6493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
6503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      case 0x03ed:
6513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
6521e4a80b77c1443fc8d04ed0e1abd9942598533decristy        char
653151b66dffc9e3c2e8c4f8cdaca37ff987ca0f497cristy          value[MagickPathExtent];
6541e4a80b77c1443fc8d04ed0e1abd9942598533decristy
6553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        unsigned short
6563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          resolution;
6573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        /*
6593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          Resolution info.
6603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        */
661f11065e08c32a2c6a82e67ade789e83936724a8ecristy        p=PushShortPixel(MSBEndian,p,&resolution);
6622a11befa48257796843468409d77bb8cfb129cdccristy        image->resolution.x=(double) resolution;
663151b66dffc9e3c2e8c4f8cdaca37ff987ca0f497cristy        (void) FormatLocaleString(value,MagickPathExtent,"%g",image->resolution.x);
664d15e65928aec551b7388c2863de3e3e628e2e0ddcristy        (void) SetImageProperty(image,"tiff:XResolution",value,exception);
665f11065e08c32a2c6a82e67ade789e83936724a8ecristy        p=PushShortPixel(MSBEndian,p,&short_sans);
666f11065e08c32a2c6a82e67ade789e83936724a8ecristy        p=PushShortPixel(MSBEndian,p,&short_sans);
667f11065e08c32a2c6a82e67ade789e83936724a8ecristy        p=PushShortPixel(MSBEndian,p,&short_sans);
668f11065e08c32a2c6a82e67ade789e83936724a8ecristy        p=PushShortPixel(MSBEndian,p,&resolution);
6692a11befa48257796843468409d77bb8cfb129cdccristy        image->resolution.y=(double) resolution;
670151b66dffc9e3c2e8c4f8cdaca37ff987ca0f497cristy        (void) FormatLocaleString(value,MagickPathExtent,"%g",image->resolution.y);
671d15e65928aec551b7388c2863de3e3e628e2e0ddcristy        (void) SetImageProperty(image,"tiff:YResolution",value,exception);
672f11065e08c32a2c6a82e67ade789e83936724a8ecristy        p=PushShortPixel(MSBEndian,p,&short_sans);
673f11065e08c32a2c6a82e67ade789e83936724a8ecristy        p=PushShortPixel(MSBEndian,p,&short_sans);
674f11065e08c32a2c6a82e67ade789e83936724a8ecristy        p=PushShortPixel(MSBEndian,p,&short_sans);
67515893bd52474061ede50d7b38b38788d4bd66b36cristy        image->units=PixelsPerInchResolution;
6763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
6773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
67818c0e4dff391a0a98e7f478d0d86bbd08f7708d0dirk      case 0x0421:
67918c0e4dff391a0a98e7f478d0d86bbd08f7708d0dirk      {
68018c0e4dff391a0a98e7f478d0d86bbd08f7708d0dirk        if (*(p+4) == 0)
68118c0e4dff391a0a98e7f478d0d86bbd08f7708d0dirk          *has_merged_image=MagickFalse;
682c337843935542dbc968a24bfe1c7a25bf264836cdirk        p+=count;
683c337843935542dbc968a24bfe1c7a25bf264836cdirk        break;
68418c0e4dff391a0a98e7f478d0d86bbd08f7708d0dirk      }
6853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      default:
6863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
6873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        p+=count;
6883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
6893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
6903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
6913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if ((count & 0x01) != 0)
6923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      p++;
6933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
6947ec893210d13a7424e5a7c3200568f1bf5317040dirk  return;
6953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
6963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
697cd0817764b65f779425ef95dfd90abbcf76d0a46cristystatic CompositeOperator PSDBlendModeToCompositeOperator(const char *mode)
69856ed31cc763800a9fb1f0df96104c354b40d2cbccristy{
699cd0817764b65f779425ef95dfd90abbcf76d0a46cristy  if (mode == (const char *) NULL)
700cd0817764b65f779425ef95dfd90abbcf76d0a46cristy    return(OverCompositeOp);
701cd0817764b65f779425ef95dfd90abbcf76d0a46cristy  if (LocaleNCompare(mode,"norm",4) == 0)
702cd0817764b65f779425ef95dfd90abbcf76d0a46cristy    return(OverCompositeOp);
703cd0817764b65f779425ef95dfd90abbcf76d0a46cristy  if (LocaleNCompare(mode,"mul ",4) == 0)
704cd0817764b65f779425ef95dfd90abbcf76d0a46cristy    return(MultiplyCompositeOp);
705cd0817764b65f779425ef95dfd90abbcf76d0a46cristy  if (LocaleNCompare(mode,"diss",4) == 0)
706cd0817764b65f779425ef95dfd90abbcf76d0a46cristy    return(DissolveCompositeOp);
707cd0817764b65f779425ef95dfd90abbcf76d0a46cristy  if (LocaleNCompare(mode,"diff",4) == 0)
708cd0817764b65f779425ef95dfd90abbcf76d0a46cristy    return(DifferenceCompositeOp);
709cd0817764b65f779425ef95dfd90abbcf76d0a46cristy  if (LocaleNCompare(mode,"dark",4) == 0)
710cd0817764b65f779425ef95dfd90abbcf76d0a46cristy    return(DarkenCompositeOp);
711cd0817764b65f779425ef95dfd90abbcf76d0a46cristy  if (LocaleNCompare(mode,"lite",4) == 0)
712cd0817764b65f779425ef95dfd90abbcf76d0a46cristy    return(LightenCompositeOp);
713cd0817764b65f779425ef95dfd90abbcf76d0a46cristy  if (LocaleNCompare(mode,"hue ",4) == 0)
714cd0817764b65f779425ef95dfd90abbcf76d0a46cristy    return(HueCompositeOp);
715cd0817764b65f779425ef95dfd90abbcf76d0a46cristy  if (LocaleNCompare(mode,"sat ",4) == 0)
716cd0817764b65f779425ef95dfd90abbcf76d0a46cristy    return(SaturateCompositeOp);
717cd0817764b65f779425ef95dfd90abbcf76d0a46cristy  if (LocaleNCompare(mode,"colr",4) == 0)
718cd0817764b65f779425ef95dfd90abbcf76d0a46cristy    return(ColorizeCompositeOp);
719cd0817764b65f779425ef95dfd90abbcf76d0a46cristy  if (LocaleNCompare(mode,"lum ",4) == 0)
720cd0817764b65f779425ef95dfd90abbcf76d0a46cristy    return(LuminizeCompositeOp);
721cd0817764b65f779425ef95dfd90abbcf76d0a46cristy  if (LocaleNCompare(mode,"scrn",4) == 0)
722cd0817764b65f779425ef95dfd90abbcf76d0a46cristy    return(ScreenCompositeOp);
723cd0817764b65f779425ef95dfd90abbcf76d0a46cristy  if (LocaleNCompare(mode,"over",4) == 0)
724cd0817764b65f779425ef95dfd90abbcf76d0a46cristy    return(OverlayCompositeOp);
725cd0817764b65f779425ef95dfd90abbcf76d0a46cristy  if (LocaleNCompare(mode,"hLit",4) == 0)
726216b90f9cd72e8dbcc34653fe1e040ab4f876a5ecristy    return(HardLightCompositeOp);
727cd0817764b65f779425ef95dfd90abbcf76d0a46cristy  if (LocaleNCompare(mode,"sLit",4) == 0)
728216b90f9cd72e8dbcc34653fe1e040ab4f876a5ecristy    return(SoftLightCompositeOp);
729cd0817764b65f779425ef95dfd90abbcf76d0a46cristy  if (LocaleNCompare(mode,"smud",4) == 0)
730fdc035a228cf5dbcefcb3e86f57dfbfbfd77ee13cristy    return(ExclusionCompositeOp);
731cd0817764b65f779425ef95dfd90abbcf76d0a46cristy  if (LocaleNCompare(mode,"div ",4) == 0)
732fdc035a228cf5dbcefcb3e86f57dfbfbfd77ee13cristy    return(ColorDodgeCompositeOp);
733cd0817764b65f779425ef95dfd90abbcf76d0a46cristy  if (LocaleNCompare(mode,"idiv",4) == 0)
734fdc035a228cf5dbcefcb3e86f57dfbfbfd77ee13cristy    return(ColorBurnCompositeOp);
735fdc035a228cf5dbcefcb3e86f57dfbfbfd77ee13cristy  if (LocaleNCompare(mode,"lbrn",4) == 0)
736fdc035a228cf5dbcefcb3e86f57dfbfbfd77ee13cristy    return(LinearBurnCompositeOp);
737fdc035a228cf5dbcefcb3e86f57dfbfbfd77ee13cristy  if (LocaleNCompare(mode,"lddg",4) == 0)
738fdc035a228cf5dbcefcb3e86f57dfbfbfd77ee13cristy    return(LinearDodgeCompositeOp);
739fdc035a228cf5dbcefcb3e86f57dfbfbfd77ee13cristy  if (LocaleNCompare(mode,"lLit",4) == 0)
740fdc035a228cf5dbcefcb3e86f57dfbfbfd77ee13cristy    return(LinearLightCompositeOp);
741fdc035a228cf5dbcefcb3e86f57dfbfbfd77ee13cristy  if (LocaleNCompare(mode,"vLit",4) == 0)
742fdc035a228cf5dbcefcb3e86f57dfbfbfd77ee13cristy    return(VividLightCompositeOp);
743fdc035a228cf5dbcefcb3e86f57dfbfbfd77ee13cristy  if (LocaleNCompare(mode,"pLit",4) == 0)
744fdc035a228cf5dbcefcb3e86f57dfbfbfd77ee13cristy    return(PinLightCompositeOp);
745fdc035a228cf5dbcefcb3e86f57dfbfbfd77ee13cristy  if (LocaleNCompare(mode,"hMix",4) == 0)
746fdc035a228cf5dbcefcb3e86f57dfbfbfd77ee13cristy    return(HardMixCompositeOp);
747cd0817764b65f779425ef95dfd90abbcf76d0a46cristy  return(OverCompositeOp);
74856ed31cc763800a9fb1f0df96104c354b40d2cbccristy}
74956ed31cc763800a9fb1f0df96104c354b40d2cbccristy
75087038d5d4cc04fb99d6560ae95f3f07a87563323dirkstatic inline void ReversePSDString(Image *image,char *p,size_t length)
75187038d5d4cc04fb99d6560ae95f3f07a87563323dirk{
75287038d5d4cc04fb99d6560ae95f3f07a87563323dirk  char
75387038d5d4cc04fb99d6560ae95f3f07a87563323dirk    *q;
75487038d5d4cc04fb99d6560ae95f3f07a87563323dirk
75587038d5d4cc04fb99d6560ae95f3f07a87563323dirk  if (image->endian == MSBEndian)
75687038d5d4cc04fb99d6560ae95f3f07a87563323dirk    return;
75787038d5d4cc04fb99d6560ae95f3f07a87563323dirk
75887038d5d4cc04fb99d6560ae95f3f07a87563323dirk  q=p+length;
75987038d5d4cc04fb99d6560ae95f3f07a87563323dirk  for(--q; p < q; ++p, --q)
76087038d5d4cc04fb99d6560ae95f3f07a87563323dirk  {
76187038d5d4cc04fb99d6560ae95f3f07a87563323dirk    *p = *p ^ *q,
76287038d5d4cc04fb99d6560ae95f3f07a87563323dirk    *q = *p ^ *q,
76387038d5d4cc04fb99d6560ae95f3f07a87563323dirk    *p = *p ^ *q;
76487038d5d4cc04fb99d6560ae95f3f07a87563323dirk  }
76587038d5d4cc04fb99d6560ae95f3f07a87563323dirk}
76687038d5d4cc04fb99d6560ae95f3f07a87563323dirk
767280215b9936d145dd5ee91403738ccce1333cab1dirkstatic inline void SetPSDPixel(Image *image,const size_t channels,
768280215b9936d145dd5ee91403738ccce1333cab1dirk  const ssize_t type,const size_t packet_size,const Quantum pixel,Quantum *q,
769280215b9936d145dd5ee91403738ccce1333cab1dirk  ExceptionInfo *exception)
770280215b9936d145dd5ee91403738ccce1333cab1dirk{
771280215b9936d145dd5ee91403738ccce1333cab1dirk  if (image->storage_class == PseudoClass)
772280215b9936d145dd5ee91403738ccce1333cab1dirk    {
773280215b9936d145dd5ee91403738ccce1333cab1dirk      if (packet_size == 1)
774280215b9936d145dd5ee91403738ccce1333cab1dirk        SetPixelIndex(image,ScaleQuantumToChar(pixel),q);
775280215b9936d145dd5ee91403738ccce1333cab1dirk      else
776280215b9936d145dd5ee91403738ccce1333cab1dirk        SetPixelIndex(image,ScaleQuantumToShort(pixel),q);
777280215b9936d145dd5ee91403738ccce1333cab1dirk      SetPixelViaPixelInfo(image,image->colormap+(ssize_t)
778280215b9936d145dd5ee91403738ccce1333cab1dirk        ConstrainColormapIndex(image,GetPixelIndex(image,q),exception),q);
779280215b9936d145dd5ee91403738ccce1333cab1dirk      return;
780280215b9936d145dd5ee91403738ccce1333cab1dirk    }
781280215b9936d145dd5ee91403738ccce1333cab1dirk  switch (type)
782280215b9936d145dd5ee91403738ccce1333cab1dirk  {
783280215b9936d145dd5ee91403738ccce1333cab1dirk    case -1:
784280215b9936d145dd5ee91403738ccce1333cab1dirk    {
785280215b9936d145dd5ee91403738ccce1333cab1dirk      SetPixelAlpha(image, pixel,q);
786280215b9936d145dd5ee91403738ccce1333cab1dirk      break;
787280215b9936d145dd5ee91403738ccce1333cab1dirk    }
788280215b9936d145dd5ee91403738ccce1333cab1dirk    case -2:
789280215b9936d145dd5ee91403738ccce1333cab1dirk    case 0:
790280215b9936d145dd5ee91403738ccce1333cab1dirk    {
791280215b9936d145dd5ee91403738ccce1333cab1dirk      SetPixelRed(image,pixel,q);
792280215b9936d145dd5ee91403738ccce1333cab1dirk      if (channels == 1 || type == -2)
793280215b9936d145dd5ee91403738ccce1333cab1dirk        SetPixelGray(image,pixel,q);
794280215b9936d145dd5ee91403738ccce1333cab1dirk      break;
795280215b9936d145dd5ee91403738ccce1333cab1dirk    }
796280215b9936d145dd5ee91403738ccce1333cab1dirk    case 1:
797280215b9936d145dd5ee91403738ccce1333cab1dirk    {
798280215b9936d145dd5ee91403738ccce1333cab1dirk      if (image->storage_class == PseudoClass)
799280215b9936d145dd5ee91403738ccce1333cab1dirk        SetPixelAlpha(image,pixel,q);
800280215b9936d145dd5ee91403738ccce1333cab1dirk      else
801280215b9936d145dd5ee91403738ccce1333cab1dirk        SetPixelGreen(image,pixel,q);
802280215b9936d145dd5ee91403738ccce1333cab1dirk      break;
803280215b9936d145dd5ee91403738ccce1333cab1dirk    }
804280215b9936d145dd5ee91403738ccce1333cab1dirk    case 2:
805280215b9936d145dd5ee91403738ccce1333cab1dirk    {
806280215b9936d145dd5ee91403738ccce1333cab1dirk      if (image->storage_class == PseudoClass)
807280215b9936d145dd5ee91403738ccce1333cab1dirk        SetPixelAlpha(image,pixel,q);
808280215b9936d145dd5ee91403738ccce1333cab1dirk      else
809280215b9936d145dd5ee91403738ccce1333cab1dirk        SetPixelBlue(image,pixel,q);
810280215b9936d145dd5ee91403738ccce1333cab1dirk      break;
811280215b9936d145dd5ee91403738ccce1333cab1dirk    }
812280215b9936d145dd5ee91403738ccce1333cab1dirk    case 3:
813280215b9936d145dd5ee91403738ccce1333cab1dirk    {
814280215b9936d145dd5ee91403738ccce1333cab1dirk      if (image->colorspace == CMYKColorspace)
815280215b9936d145dd5ee91403738ccce1333cab1dirk        SetPixelBlack(image,pixel,q);
816280215b9936d145dd5ee91403738ccce1333cab1dirk      else
817280215b9936d145dd5ee91403738ccce1333cab1dirk        if (image->alpha_trait != UndefinedPixelTrait)
818280215b9936d145dd5ee91403738ccce1333cab1dirk          SetPixelAlpha(image,pixel,q);
819280215b9936d145dd5ee91403738ccce1333cab1dirk      break;
820280215b9936d145dd5ee91403738ccce1333cab1dirk    }
821280215b9936d145dd5ee91403738ccce1333cab1dirk    case 4:
822280215b9936d145dd5ee91403738ccce1333cab1dirk    {
823280215b9936d145dd5ee91403738ccce1333cab1dirk      if ((IssRGBCompatibleColorspace(image->colorspace) != MagickFalse) &&
824280215b9936d145dd5ee91403738ccce1333cab1dirk          (channels > 3))
825280215b9936d145dd5ee91403738ccce1333cab1dirk        break;
826280215b9936d145dd5ee91403738ccce1333cab1dirk      if (image->alpha_trait != UndefinedPixelTrait)
827280215b9936d145dd5ee91403738ccce1333cab1dirk        SetPixelAlpha(image,pixel,q);
828280215b9936d145dd5ee91403738ccce1333cab1dirk      break;
829280215b9936d145dd5ee91403738ccce1333cab1dirk    }
830280215b9936d145dd5ee91403738ccce1333cab1dirk  }
831280215b9936d145dd5ee91403738ccce1333cab1dirk}
832280215b9936d145dd5ee91403738ccce1333cab1dirk
833b20a1794de28edf28c46f2268914c15781482530dirkstatic MagickBooleanType ReadPSDChannelPixels(Image *image,
834b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  const size_t channels,const size_t row,const ssize_t type,
835b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  const unsigned char *pixels,ExceptionInfo *exception)
83656ed31cc763800a9fb1f0df96104c354b40d2cbccristy{
83756ed31cc763800a9fb1f0df96104c354b40d2cbccristy  Quantum
83856ed31cc763800a9fb1f0df96104c354b40d2cbccristy    pixel;
83956ed31cc763800a9fb1f0df96104c354b40d2cbccristy
8407753b2aa64ed48fc1f9d155cf43493373fa6d0bbcristy  register const unsigned char
8417753b2aa64ed48fc1f9d155cf43493373fa6d0bbcristy    *p;
8427753b2aa64ed48fc1f9d155cf43493373fa6d0bbcristy
8434c08aed51c5899665ade97263692328eea4af106cristy  register Quantum
84456ed31cc763800a9fb1f0df96104c354b40d2cbccristy    *q;
84556ed31cc763800a9fb1f0df96104c354b40d2cbccristy
8467753b2aa64ed48fc1f9d155cf43493373fa6d0bbcristy  register ssize_t
8477753b2aa64ed48fc1f9d155cf43493373fa6d0bbcristy    x;
84856ed31cc763800a9fb1f0df96104c354b40d2cbccristy
84956ed31cc763800a9fb1f0df96104c354b40d2cbccristy  size_t
85056ed31cc763800a9fb1f0df96104c354b40d2cbccristy    packet_size;
85156ed31cc763800a9fb1f0df96104c354b40d2cbccristy
85256ed31cc763800a9fb1f0df96104c354b40d2cbccristy  unsigned short
85356ed31cc763800a9fb1f0df96104c354b40d2cbccristy    nibble;
85456ed31cc763800a9fb1f0df96104c354b40d2cbccristy
855b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  p=pixels;
856b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  q=GetAuthenticPixels(image,0,row,image->columns,1,exception);
857b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  if (q == (Quantum *) NULL)
858b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    return MagickFalse;
859b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  packet_size=GetPSDPacketSize(image);
860b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  for (x=0; x < (ssize_t) image->columns; x++)
86156ed31cc763800a9fb1f0df96104c354b40d2cbccristy  {
862b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    if (packet_size == 1)
863b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      pixel=ScaleCharToQuantum(*p++);
864b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    else
865b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      {
866b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        p=PushShortPixel(MSBEndian,p,&nibble);
867b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        pixel=ScaleShortToQuantum(nibble);
868b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      }
869280215b9936d145dd5ee91403738ccce1333cab1dirk    if (image->depth > 1)
87056ed31cc763800a9fb1f0df96104c354b40d2cbccristy      {
871280215b9936d145dd5ee91403738ccce1333cab1dirk        SetPSDPixel(image,channels,type,packet_size,pixel,q,exception);
872280215b9936d145dd5ee91403738ccce1333cab1dirk        q+=GetPixelChannels(image);
873b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      }
874280215b9936d145dd5ee91403738ccce1333cab1dirk    else
875b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      {
876280215b9936d145dd5ee91403738ccce1333cab1dirk        ssize_t
877280215b9936d145dd5ee91403738ccce1333cab1dirk          bit,
878280215b9936d145dd5ee91403738ccce1333cab1dirk          number_bits;
879280215b9936d145dd5ee91403738ccce1333cab1dirk
880280215b9936d145dd5ee91403738ccce1333cab1dirk        number_bits=image->columns-x;
881280215b9936d145dd5ee91403738ccce1333cab1dirk        if (number_bits > 8)
882280215b9936d145dd5ee91403738ccce1333cab1dirk          number_bits=8;
883280215b9936d145dd5ee91403738ccce1333cab1dirk        for (bit = 0; bit < number_bits; bit++)
884280215b9936d145dd5ee91403738ccce1333cab1dirk        {
885280215b9936d145dd5ee91403738ccce1333cab1dirk          SetPSDPixel(image,channels,type,packet_size,(((unsigned char) pixel)
886c6e0187105ab20b12bbc661f01b54e4894e92a5bdirk            & (0x01 << (7-bit))) != 0 ? 0 : QuantumRange,q,exception);
887280215b9936d145dd5ee91403738ccce1333cab1dirk          q+=GetPixelChannels(image);
888280215b9936d145dd5ee91403738ccce1333cab1dirk          x++;
889280215b9936d145dd5ee91403738ccce1333cab1dirk        }
89062cf71319382faa2dced95488ab838ce8b796146dirk        if (x != (ssize_t) image->columns)
891280215b9936d145dd5ee91403738ccce1333cab1dirk          x--;
892280215b9936d145dd5ee91403738ccce1333cab1dirk        continue;
89356ed31cc763800a9fb1f0df96104c354b40d2cbccristy      }
89456ed31cc763800a9fb1f0df96104c354b40d2cbccristy  }
895b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  return(SyncAuthenticPixels(image,exception));
89656ed31cc763800a9fb1f0df96104c354b40d2cbccristy}
89756ed31cc763800a9fb1f0df96104c354b40d2cbccristy
898b20a1794de28edf28c46f2268914c15781482530dirkstatic MagickBooleanType ReadPSDChannelRaw(Image *image,const size_t channels,
899b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  const ssize_t type,ExceptionInfo *exception)
9003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
901b20a1794de28edf28c46f2268914c15781482530dirk  MagickBooleanType
902b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    status;
9033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
904b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  size_t
905b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    count,
906b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    row_size;
9073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
908b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  ssize_t
909b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    y;
9103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
911b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  unsigned char
912b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    *pixels;
913b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
914b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  if (image->debug != MagickFalse)
915b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
916b41f080d52a5ff2d9c235cffac1419b84028bd31dirk       "      layer data is RAW");
917b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
918b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  row_size=GetPSDRowSize(image);
919891df41d828a641db63d8bae45ca027d0e28341ddirk  pixels=(unsigned char *) AcquireQuantumMemory(row_size,sizeof(*pixels));
920b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  if (pixels == (unsigned char *) NULL)
921b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
922b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      image->filename);
923b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
924b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  status=MagickTrue;
925b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  for (y=0; y < (ssize_t) image->rows; y++)
926b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  {
927b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    status=MagickFalse;
928b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
929b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    count=ReadBlob(image,row_size,pixels);
930b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    if (count != row_size)
931b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      break;
932b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
933b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    status=ReadPSDChannelPixels(image,channels,y,type,pixels,exception);
934b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    if (status == MagickFalse)
935b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      break;
936b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  }
937b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
938b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  pixels=(unsigned char *) RelinquishMagickMemory(pixels);
939b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  return(status);
940b41f080d52a5ff2d9c235cffac1419b84028bd31dirk}
94156ed31cc763800a9fb1f0df96104c354b40d2cbccristy
942b41f080d52a5ff2d9c235cffac1419b84028bd31dirkstatic inline MagickOffsetType *ReadPSDRLEOffsets(Image *image,
9434d9863ca77e690fdde8653d1f3db0721bd25978edirk  const PSDInfo *psd_info,const size_t size)
944b41f080d52a5ff2d9c235cffac1419b84028bd31dirk{
94556ed31cc763800a9fb1f0df96104c354b40d2cbccristy  MagickOffsetType
94656ed31cc763800a9fb1f0df96104c354b40d2cbccristy    *offsets;
94756ed31cc763800a9fb1f0df96104c354b40d2cbccristy
948b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  ssize_t
949b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    y;
9503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
951b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  offsets=(MagickOffsetType *) AcquireQuantumMemory(size,sizeof(*offsets));
952b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  if(offsets != (MagickOffsetType *) NULL)
953b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    {
954b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      for (y=0; y < (ssize_t) size; y++)
955b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      {
956b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        if (psd_info->version == 1)
95787038d5d4cc04fb99d6560ae95f3f07a87563323dirk          offsets[y]=(MagickOffsetType) ReadBlobShort(image);
958b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        else
95987038d5d4cc04fb99d6560ae95f3f07a87563323dirk          offsets[y]=(MagickOffsetType) ReadBlobLong(image);
960b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      }
961b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    }
962b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  return offsets;
963b41f080d52a5ff2d9c235cffac1419b84028bd31dirk}
964dede49f1361cdf0a7aa29aa281b6f6e9a565f0facristy
965b20a1794de28edf28c46f2268914c15781482530dirkstatic MagickBooleanType ReadPSDChannelRLE(Image *image,const PSDInfo *psd_info,
966b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  const ssize_t type,MagickOffsetType *offsets,ExceptionInfo *exception)
967b41f080d52a5ff2d9c235cffac1419b84028bd31dirk{
968b20a1794de28edf28c46f2268914c15781482530dirk  MagickBooleanType
969b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    status;
9703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
971dc05fc25727367020d3b64c4e5831cc36632691acristy  size_t
972b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    length,
973b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    row_size;
974dc05fc25727367020d3b64c4e5831cc36632691acristy
9753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ssize_t
976dc05fc25727367020d3b64c4e5831cc36632691acristy    count,
977dc05fc25727367020d3b64c4e5831cc36632691acristy    y;
9783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
9793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  unsigned char
980b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    *compact_pixels,
981b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    *pixels;
9823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
983b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  if (image->debug != MagickFalse)
984b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
985b41f080d52a5ff2d9c235cffac1419b84028bd31dirk       "      layer data is RLE compressed");
9863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
987b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  row_size=GetPSDRowSize(image);
988891df41d828a641db63d8bae45ca027d0e28341ddirk  pixels=(unsigned char *) AcquireQuantumMemory(row_size,sizeof(*pixels));
989b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  if (pixels == (unsigned char *) NULL)
990b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
991b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      image->filename);
992b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
993b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  length=0;
994b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  for (y=0; y < (ssize_t) image->rows; y++)
995b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    if ((MagickOffsetType) length < offsets[y])
996b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      length=(size_t) offsets[y];
997b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
998b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  if (length > row_size + 256) // arbitrary number
9993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
1000b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1001b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      ThrowBinaryException(ResourceLimitError,"InvalidLength",
1002b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        image->filename);
10033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
1004b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1005891df41d828a641db63d8bae45ca027d0e28341ddirk  compact_pixels=(unsigned char *) AcquireQuantumMemory(length,sizeof(*pixels));
1006b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  if (compact_pixels == (unsigned char *) NULL)
1007b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    {
1008b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1009b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1010b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        image->filename);
1011b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    }
1012b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1013b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  (void) ResetMagickMemory(compact_pixels,0,length*sizeof(*compact_pixels));
1014b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1015b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  status=MagickTrue;
1016b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  for (y=0; y < (ssize_t) image->rows; y++)
1017b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  {
1018b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    status=MagickFalse;
1019b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1020b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    count=ReadBlob(image,(size_t) offsets[y],compact_pixels);
1021b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    if (count != (ssize_t) offsets[y])
1022b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      break;
1023b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1024b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    count=DecodePSDPixels((size_t) offsets[y],compact_pixels,
1025b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      (ssize_t) (image->depth == 1 ? 123456 : image->depth),row_size,pixels);
1026b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    if (count != (ssize_t) row_size)
1027b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      break;
1028b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1029b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    status=ReadPSDChannelPixels(image,psd_info->channels,y,type,pixels,
1030b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      exception);
1031b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    if (status == MagickFalse)
1032b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      break;
1033b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  }
1034b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1035b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
1036b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1037b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  return(status);
1038b41f080d52a5ff2d9c235cffac1419b84028bd31dirk}
1039b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1040b41f080d52a5ff2d9c235cffac1419b84028bd31dirk#ifdef MAGICKCORE_ZLIB_DELEGATE
1041b20a1794de28edf28c46f2268914c15781482530dirkstatic MagickBooleanType ReadPSDChannelZip(Image *image,const size_t channels,
1042ff30f83b51982c82b05cab57de8093dd52396b7bcristy  const ssize_t type,const PSDCompressionType compression,
1043ff30f83b51982c82b05cab57de8093dd52396b7bcristy  const size_t compact_size,ExceptionInfo *exception)
1044ff30f83b51982c82b05cab57de8093dd52396b7bcristy{
1045b20a1794de28edf28c46f2268914c15781482530dirk  MagickBooleanType
1046b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    status;
1047b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1048b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  register unsigned char
1049b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    *p;
1050b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1051b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  size_t
1052b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    count,
1053b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    length,
1054b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    packet_size,
1055b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    row_size;
1056b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1057b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  ssize_t
1058b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    y;
1059b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1060b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  unsigned char
1061b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    *compact_pixels,
1062b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    *pixels;
1063b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1064b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  z_stream
1065b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    stream;
1066b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1067b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  if (image->debug != MagickFalse)
1068b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1069245cc757e4d673ce07b090b09064951f3d029896dirk       "      layer data is ZIP compressed");
1070b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1071b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  compact_pixels=(unsigned char *) AcquireQuantumMemory(compact_size,
1072b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    sizeof(*compact_pixels));
1073b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  if (compact_pixels == (unsigned char *) NULL)
1074b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1075b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      image->filename);
1076b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1077b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  packet_size=GetPSDPacketSize(image);
1078b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  row_size=image->columns*packet_size;
1079b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  count=image->rows*row_size;
1080b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1081b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  pixels=(unsigned char *) AcquireQuantumMemory(count,sizeof(*pixels));
1082b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  if (pixels == (unsigned char *) NULL)
1083b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    {
1084b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
1085b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1086b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        image->filename);
1087b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    }
1088b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1089b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  ResetMagickMemory(&stream, 0, sizeof(z_stream));
1090b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  stream.data_type=Z_BINARY;
1091b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  (void) ReadBlob(image,compact_size,compact_pixels);
1092b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1093b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  stream.next_in=(Bytef *)compact_pixels;
10940e274112f2ad0a61de63adfc11e3e78038d55231cristy  stream.avail_in=(unsigned int) compact_size;
1095b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  stream.next_out=(Bytef *)pixels;
10960e274112f2ad0a61de63adfc11e3e78038d55231cristy  stream.avail_out=(unsigned int) count;
1097b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1098b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  if(inflateInit(&stream) == Z_OK)
1099b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    {
1100b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      int
1101b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        ret;
1102b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1103b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      while (stream.avail_out > 0)
1104b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      {
1105b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        ret=inflate(&stream, Z_SYNC_FLUSH);
1106b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        if (ret != Z_OK && ret != Z_STREAM_END)
1107b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        {
1108b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          compact_pixels=(unsigned char *) RelinquishMagickMemory(
1109b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            compact_pixels);
1110b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1111b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          return(MagickFalse);
1112b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        }
1113b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      }
1114b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    }
1115b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1116b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  if (compression == ZipWithPrediction)
1117b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  {
1118b41f080d52a5ff2d9c235cffac1419b84028bd31dirk     p=pixels;
1119b41f080d52a5ff2d9c235cffac1419b84028bd31dirk     while(count > 0)
1120b41f080d52a5ff2d9c235cffac1419b84028bd31dirk     {
1121b41f080d52a5ff2d9c235cffac1419b84028bd31dirk       length=image->columns;
1122b41f080d52a5ff2d9c235cffac1419b84028bd31dirk       while(--length)
1123b41f080d52a5ff2d9c235cffac1419b84028bd31dirk       {
1124b41f080d52a5ff2d9c235cffac1419b84028bd31dirk         if (packet_size == 2)
1125b41f080d52a5ff2d9c235cffac1419b84028bd31dirk           {
1126b41f080d52a5ff2d9c235cffac1419b84028bd31dirk             p[2]+=p[0]+((p[1]+p[3]) >> 8);
1127b41f080d52a5ff2d9c235cffac1419b84028bd31dirk             p[3]+=p[1];
1128b41f080d52a5ff2d9c235cffac1419b84028bd31dirk           }
1129b41f080d52a5ff2d9c235cffac1419b84028bd31dirk         else
1130b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          *(p+1)+=*p;
1131b41f080d52a5ff2d9c235cffac1419b84028bd31dirk         p+=packet_size;
1132b41f080d52a5ff2d9c235cffac1419b84028bd31dirk       }
1133b41f080d52a5ff2d9c235cffac1419b84028bd31dirk       p+=packet_size;
1134b41f080d52a5ff2d9c235cffac1419b84028bd31dirk       count-=row_size;
1135b41f080d52a5ff2d9c235cffac1419b84028bd31dirk     }
1136b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  }
1137b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1138b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  status=MagickTrue;
1139b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  p=pixels;
1140b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  for (y=0; y < (ssize_t) image->rows; y++)
1141b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  {
1142b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    status=ReadPSDChannelPixels(image,channels,y,type,p,exception);
1143b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    if (status == MagickFalse)
1144b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      break;
1145b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1146b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    p+=row_size;
1147b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  }
1148b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1149b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
1150b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1151b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  return(status);
1152b41f080d52a5ff2d9c235cffac1419b84028bd31dirk}
11530d67b92d9e50a025e13e4658113b31b4d3dd72cecristy#endif
1154b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1155b20a1794de28edf28c46f2268914c15781482530dirkstatic MagickBooleanType ReadPSDChannel(Image *image,const PSDInfo *psd_info,
1156a41d97fa7de942f144af6cfcceba24c523775c54dirk  LayerInfo* layer_info,const size_t channel,
1157b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  const PSDCompressionType compression,ExceptionInfo *exception)
1158b41f080d52a5ff2d9c235cffac1419b84028bd31dirk{
1159a41d97fa7de942f144af6cfcceba24c523775c54dirk  Image
1160a41d97fa7de942f144af6cfcceba24c523775c54dirk    *channel_image,
1161a41d97fa7de942f144af6cfcceba24c523775c54dirk    *mask;
1162a41d97fa7de942f144af6cfcceba24c523775c54dirk
1163b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  MagickOffsetType
1164b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    offset;
1165b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1166b20a1794de28edf28c46f2268914c15781482530dirk  MagickBooleanType
1167b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    status;
1168b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1169a41d97fa7de942f144af6cfcceba24c523775c54dirk  channel_image=image;
1170a41d97fa7de942f144af6cfcceba24c523775c54dirk  mask=(Image *) NULL;
1171245cc757e4d673ce07b090b09064951f3d029896dirk  if (layer_info->channel_info[channel].type < -1)
1172245cc757e4d673ce07b090b09064951f3d029896dirk  {
1173a41d97fa7de942f144af6cfcceba24c523775c54dirk    /*
1174a41d97fa7de942f144af6cfcceba24c523775c54dirk      Ignore mask that is not a user supplied layer mask, if the mask is
1175a41d97fa7de942f144af6cfcceba24c523775c54dirk      disabled or if the flags have unsupported values.
1176a41d97fa7de942f144af6cfcceba24c523775c54dirk    */
1177a41d97fa7de942f144af6cfcceba24c523775c54dirk    if (layer_info->channel_info[channel].type != -2 ||
1178a41d97fa7de942f144af6cfcceba24c523775c54dirk        (layer_info->mask.flags > 3) || (layer_info->mask.flags & 0x02))
1179a41d97fa7de942f144af6cfcceba24c523775c54dirk    {
1180a41d97fa7de942f144af6cfcceba24c523775c54dirk      SeekBlob(image,layer_info->channel_info[channel].size-2,SEEK_CUR);
1181a41d97fa7de942f144af6cfcceba24c523775c54dirk      return(MagickTrue);
1182a41d97fa7de942f144af6cfcceba24c523775c54dirk    }
1183a41d97fa7de942f144af6cfcceba24c523775c54dirk    mask=CloneImage(image,layer_info->mask.page.width,
1184a41d97fa7de942f144af6cfcceba24c523775c54dirk      layer_info->mask.page.height,MagickFalse,exception);
1185a41d97fa7de942f144af6cfcceba24c523775c54dirk    SetImageType(mask,GrayscaleType,exception);
1186a41d97fa7de942f144af6cfcceba24c523775c54dirk    channel_image=mask;
1187245cc757e4d673ce07b090b09064951f3d029896dirk  }
1188245cc757e4d673ce07b090b09064951f3d029896dirk
118955851db5384887e1bb46255bbfd1d55fa7408316dirk  offset=TellBlob(image);
1190b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  status=MagickTrue;
1191b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  switch(compression)
1192b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  {
1193b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    case Raw:
1194fe3a57e5b12c38f455ae6dd3bb47dc7cb054cc43dirk      status=ReadPSDChannelRaw(channel_image,psd_info->channels,
1195fe3a57e5b12c38f455ae6dd3bb47dc7cb054cc43dirk        layer_info->channel_info[channel].type,exception);
1196fe3a57e5b12c38f455ae6dd3bb47dc7cb054cc43dirk      break;
1197b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    case RLE:
1198b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      {
1199b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        MagickOffsetType
1200b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          *offsets;
1201b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1202a41d97fa7de942f144af6cfcceba24c523775c54dirk        offsets=ReadPSDRLEOffsets(channel_image,psd_info,channel_image->rows);
1203b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        if (offsets == (MagickOffsetType *) NULL)
1204b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1205b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            image->filename);
1206a41d97fa7de942f144af6cfcceba24c523775c54dirk        status=ReadPSDChannelRLE(channel_image,psd_info,
1207a41d97fa7de942f144af6cfcceba24c523775c54dirk          layer_info->channel_info[channel].type,offsets,exception);
1208b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        offsets=(MagickOffsetType *) RelinquishMagickMemory(offsets);
1209b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      }
1210b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      break;
1211b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    case ZipWithPrediction:
1212b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    case ZipWithoutPrediction:
1213b41f080d52a5ff2d9c235cffac1419b84028bd31dirk#ifdef MAGICKCORE_ZLIB_DELEGATE
1214a41d97fa7de942f144af6cfcceba24c523775c54dirk      status=ReadPSDChannelZip(channel_image,layer_info->channels,
1215b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        layer_info->channel_info[channel].type,compression,
1216b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        layer_info->channel_info[channel].size-2,exception);
1217b41f080d52a5ff2d9c235cffac1419b84028bd31dirk#else
1218b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      (void) ThrowMagickException(exception,GetMagickModule(),
1219b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn",
1220b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            "'%s' (ZLIB)",image->filename);
1221b41f080d52a5ff2d9c235cffac1419b84028bd31dirk#endif
1222b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      break;
1223b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    default:
1224b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      (void) ThrowMagickException(exception,GetMagickModule(),TypeWarning,
1225b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        "CompressionNotSupported","'%.20g'",(double) compression);
1226b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      break;
1227b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  }
1228b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
122955851db5384887e1bb46255bbfd1d55fa7408316dirk  SeekBlob(image,offset+layer_info->channel_info[channel].size-2,SEEK_SET);
1230b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  if (status == MagickFalse)
1231d5a9132f28f00226b38417cfaee9b4938f4a1cd6dirk    {
1232d5a9132f28f00226b38417cfaee9b4938f4a1cd6dirk      if (mask != (Image *) NULL)
1233d5a9132f28f00226b38417cfaee9b4938f4a1cd6dirk        DestroyImage(mask);
1234d5a9132f28f00226b38417cfaee9b4938f4a1cd6dirk      ThrowBinaryException(CoderError,"UnableToDecompressImage",
1235d5a9132f28f00226b38417cfaee9b4938f4a1cd6dirk        image->filename);
1236d5a9132f28f00226b38417cfaee9b4938f4a1cd6dirk    }
1237a41d97fa7de942f144af6cfcceba24c523775c54dirk  if (mask != (Image *) NULL)
1238a41d97fa7de942f144af6cfcceba24c523775c54dirk  {
1239a41d97fa7de942f144af6cfcceba24c523775c54dirk    if (status != MagickFalse)
1240a41d97fa7de942f144af6cfcceba24c523775c54dirk      {
1241a41d97fa7de942f144af6cfcceba24c523775c54dirk        PixelInfo
1242a41d97fa7de942f144af6cfcceba24c523775c54dirk          color;
1243a41d97fa7de942f144af6cfcceba24c523775c54dirk
1244a41d97fa7de942f144af6cfcceba24c523775c54dirk        layer_info->mask.image=CloneImage(image,image->columns,image->rows,
1245a41d97fa7de942f144af6cfcceba24c523775c54dirk          MagickTrue,exception);
1246a41d97fa7de942f144af6cfcceba24c523775c54dirk        layer_info->mask.image->alpha_trait=UndefinedPixelTrait;
1247a41d97fa7de942f144af6cfcceba24c523775c54dirk        GetPixelInfo(layer_info->mask.image,&color);
1248a41d97fa7de942f144af6cfcceba24c523775c54dirk        color.red=layer_info->mask.background == 0 ? 0 : QuantumRange;
1249a41d97fa7de942f144af6cfcceba24c523775c54dirk        SetImageColor(layer_info->mask.image,&color,exception);
1250a41d97fa7de942f144af6cfcceba24c523775c54dirk        (void) CompositeImage(layer_info->mask.image,mask,OverCompositeOp,
1251a41d97fa7de942f144af6cfcceba24c523775c54dirk          MagickTrue,layer_info->mask.page.x,layer_info->mask.page.y,
1252a41d97fa7de942f144af6cfcceba24c523775c54dirk          exception);
1253a41d97fa7de942f144af6cfcceba24c523775c54dirk      }
1254a41d97fa7de942f144af6cfcceba24c523775c54dirk    DestroyImage(mask);
1255a41d97fa7de942f144af6cfcceba24c523775c54dirk  }
1256b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1257b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  return(status);
1258b41f080d52a5ff2d9c235cffac1419b84028bd31dirk}
1259b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1260b20a1794de28edf28c46f2268914c15781482530dirkstatic MagickBooleanType ReadPSDLayer(Image *image,const PSDInfo *psd_info,
1261b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  LayerInfo* layer_info,ExceptionInfo *exception)
1262b41f080d52a5ff2d9c235cffac1419b84028bd31dirk{
1263b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  char
1264151b66dffc9e3c2e8c4f8cdaca37ff987ca0f497cristy    message[MagickPathExtent];
1265b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1266b20a1794de28edf28c46f2268914c15781482530dirk  MagickBooleanType
1267b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    status;
1268b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1269b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  PSDCompressionType
1270b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    compression;
1271b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1272b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  ssize_t
1273b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    j;
1274b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1275b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  if (image->debug != MagickFalse)
1276b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1277b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      "    setting up new layer image");
1278b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  (void) SetImageBackgroundColor(layer_info->image,exception);
1279b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  layer_info->image->compose=PSDBlendModeToCompositeOperator(
1280b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    layer_info->blendkey);
1281b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  if (layer_info->visible == MagickFalse)
1282b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    layer_info->image->compose=NoCompositeOp;
1283b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  if (psd_info->mode == CMYKMode)
1284b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    SetImageColorspace(layer_info->image,CMYKColorspace,exception);
1285d8083a693bea157df66921cb7570880bb081dcd1cristy  if ((psd_info->mode == BitmapMode) || (psd_info->mode == GrayscaleMode) ||
1286b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      (psd_info->mode == DuotoneMode))
1287b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    SetImageColorspace(layer_info->image,GRAYColorspace,exception);
1288b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  /*
1289b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    Set up some hidden attributes for folks that need them.
1290b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  */
1291a41d97fa7de942f144af6cfcceba24c523775c54dirk  (void) FormatLocaleString(message,MagickPathExtent,"%.20g",
1292b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    (double) layer_info->page.x);
1293b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  (void) SetImageArtifact(layer_info->image,"psd:layer.x",message);
1294151b66dffc9e3c2e8c4f8cdaca37ff987ca0f497cristy  (void) FormatLocaleString(message,MagickPathExtent,"%.20g",
1295b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    (double) layer_info->page.y);
1296b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  (void) SetImageArtifact(layer_info->image,"psd:layer.y",message);
1297151b66dffc9e3c2e8c4f8cdaca37ff987ca0f497cristy  (void) FormatLocaleString(message,MagickPathExtent,"%.20g",(double)
1298b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    layer_info->opacity);
1299b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  (void) SetImageArtifact(layer_info->image,"psd:layer.opacity",message);
1300b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  (void) SetImageProperty(layer_info->image,"label",(char *) layer_info->name,
1301b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    exception);
1302b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1303b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  status=MagickTrue;
1304b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  for (j=0; j < (ssize_t) layer_info->channels; j++)
1305b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  {
1306b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    if (image->debug != MagickFalse)
1307b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1308b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        "    reading data for channel %.20g",(double) j);
1309b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
131087038d5d4cc04fb99d6560ae95f3f07a87563323dirk    compression=(PSDCompressionType) ReadBlobShort(layer_info->image);
1311b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    layer_info->image->compression=ConvertPSDCompression(compression);
13126f20531b06ddc2852ec30506e13798363f534e53dirk    if (layer_info->channel_info[j].type == -1)
13136f20531b06ddc2852ec30506e13798363f534e53dirk      layer_info->image->alpha_trait=BlendPixelTrait;
1314d9795a19984ae1bae9205b7c0fe5de75461978b3dirk
13156f20531b06ddc2852ec30506e13798363f534e53dirk    status=ReadPSDChannel(layer_info->image,psd_info,layer_info,j,
13166f20531b06ddc2852ec30506e13798363f534e53dirk      compression,exception);
1317b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1318b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    if (status == MagickFalse)
1319b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      break;
1320b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  }
1321b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
13226f20531b06ddc2852ec30506e13798363f534e53dirk  if (status != MagickFalse)
1323b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    status=CorrectPSDOpacity(layer_info,exception);
1324b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1325b20a1794de28edf28c46f2268914c15781482530dirk  if ((status != MagickFalse) &&
1326b20a1794de28edf28c46f2268914c15781482530dirk      (layer_info->image->colorspace == CMYKColorspace))
1327b20a1794de28edf28c46f2268914c15781482530dirk    status=NegateCMYK(layer_info->image,exception);
1328b20a1794de28edf28c46f2268914c15781482530dirk
1329b20a1794de28edf28c46f2268914c15781482530dirk  if ((status != MagickFalse) && (layer_info->mask.image != (Image *) NULL))
1330a41d97fa7de942f144af6cfcceba24c523775c54dirk    {
1331b20a1794de28edf28c46f2268914c15781482530dirk      status=CompositeImage(layer_info->image,layer_info->mask.image,
1332b20a1794de28edf28c46f2268914c15781482530dirk        CopyAlphaCompositeOp,MagickTrue,0,0,exception);
1333b20a1794de28edf28c46f2268914c15781482530dirk      layer_info->mask.image=DestroyImage(layer_info->mask.image);
1334a41d97fa7de942f144af6cfcceba24c523775c54dirk    }
1335b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1336b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  return(status);
1337b41f080d52a5ff2d9c235cffac1419b84028bd31dirk}
1338b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1339b20a1794de28edf28c46f2268914c15781482530dirkModuleExport MagickBooleanType ReadPSDLayers(Image *image,
134014c08dcd1910ecd8360f51d13885b2c9c39b655ddirk  const ImageInfo *image_info,const PSDInfo *psd_info,
134114c08dcd1910ecd8360f51d13885b2c9c39b655ddirk  const MagickBooleanType skip_layers,ExceptionInfo *exception)
1342b41f080d52a5ff2d9c235cffac1419b84028bd31dirk{
1343b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  char
1344b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    type[4];
1345b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1346b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  LayerInfo
1347b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    *layer_info;
1348b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1349b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  MagickSizeType
1350b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    size;
1351b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1352b20a1794de28edf28c46f2268914c15781482530dirk  MagickBooleanType
1353b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    status;
1354b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1355b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  register ssize_t
1356b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    i;
1357b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1358b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  ssize_t
1359b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    count,
1360b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    j,
1361b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    number_layers;
1362b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1363b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  size=GetPSDSize(psd_info,image);
1364b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  if (size == 0)
1365b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    {
1366b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      /*
1367b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        Skip layers & masks.
1368b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      */
136987038d5d4cc04fb99d6560ae95f3f07a87563323dirk      (void) ReadBlobLong(image);
1370b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      count=ReadBlob(image,4,(unsigned char *) type);
137187038d5d4cc04fb99d6560ae95f3f07a87563323dirk      ReversePSDString(image,type,4);
1372908a35b19a313486d17de504738fc427595918d2cristy      status=MagickFalse;
1373b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      if ((count == 0) || (LocaleNCompare(type,"8BIM",4) != 0))
1374f308152b28249d599fa01dd41b1518c4ddfc5e60dirk        return(MagickTrue);
1375b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      else
1376b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        {
1377b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          count=ReadBlob(image,4,(unsigned char *) type);
137887038d5d4cc04fb99d6560ae95f3f07a87563323dirk          ReversePSDString(image,type,4);
1379b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          if ((count != 0) && (LocaleNCompare(type,"Lr16",4) == 0))
1380b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            size=GetPSDSize(psd_info,image);
1381b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          else
1382f308152b28249d599fa01dd41b1518c4ddfc5e60dirk            return(MagickTrue);
1383b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        }
1384b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    }
1385b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  status=MagickTrue;
1386b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  if (size != 0)
1387b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    {
1388b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      layer_info=(LayerInfo *) NULL;
138987038d5d4cc04fb99d6560ae95f3f07a87563323dirk      number_layers=(short) ReadBlobShort(image);
1390b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1391b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      if (number_layers < 0)
1392b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        {
1393b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          /*
13946f20531b06ddc2852ec30506e13798363f534e53dirk            The first alpha channel in the merged result contains the
13956f20531b06ddc2852ec30506e13798363f534e53dirk            transparency data for the merged result.
1396b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          */
1397b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          number_layers=MagickAbsoluteValue(number_layers);
1398b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          if (image->debug != MagickFalse)
1399b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1400b41f080d52a5ff2d9c235cffac1419b84028bd31dirk              "  negative layer count corrected for");
14016f20531b06ddc2852ec30506e13798363f534e53dirk          image->alpha_trait=BlendPixelTrait;
1402b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        }
1403b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1404f308152b28249d599fa01dd41b1518c4ddfc5e60dirk      /*
1405f308152b28249d599fa01dd41b1518c4ddfc5e60dirk        We only need to know if the image has an alpha channel
1406f308152b28249d599fa01dd41b1518c4ddfc5e60dirk      */
1407fcaec62bc681e372b60f8a31681671653bc907f2dirk      if (skip_layers != MagickFalse)
1408fcaec62bc681e372b60f8a31681671653bc907f2dirk        return(MagickTrue);
1409fcaec62bc681e372b60f8a31681671653bc907f2dirk
1410b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      if (image->debug != MagickFalse)
1411b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1412b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          "  image contains %.20g layers",(double) number_layers);
1413b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1414b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      if (number_layers == 0)
1415419e5adbecfc7375751e7ac2ba30be0b1d35690fdirk        ThrowBinaryException(CorruptImageError,"InvalidNumberOfLayers",
1416419e5adbecfc7375751e7ac2ba30be0b1d35690fdirk          image->filename);
1417b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1418b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      layer_info=(LayerInfo *) AcquireQuantumMemory((size_t) number_layers,
1419b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        sizeof(*layer_info));
1420b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      if (layer_info == (LayerInfo *) NULL)
1421b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        {
1422b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          if (image->debug != MagickFalse)
1423b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1424b41f080d52a5ff2d9c235cffac1419b84028bd31dirk              "  allocation of LayerInfo failed");
1425b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1426b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            image->filename);
1427b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        }
1428b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      (void) ResetMagickMemory(layer_info,0,(size_t) number_layers*
1429b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        sizeof(*layer_info));
1430b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1431b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      for (i=0; i < number_layers; i++)
1432b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      {
143387038d5d4cc04fb99d6560ae95f3f07a87563323dirk        ssize_t
1434b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          x,
1435b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          y;
1436b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1437b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        if (image->debug != MagickFalse)
1438b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1439b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            "  reading layer #%.20g",(double) i+1);
14401fe0b879964fa7797e3d68574d297922a47c4034Cristy        layer_info[i].page.y=ReadBlobSignedLong(image);
14411fe0b879964fa7797e3d68574d297922a47c4034Cristy        layer_info[i].page.x=ReadBlobSignedLong(image);
14421fe0b879964fa7797e3d68574d297922a47c4034Cristy        y=ReadBlobSignedLong(image);
14431fe0b879964fa7797e3d68574d297922a47c4034Cristy        x=ReadBlobSignedLong(image);
1444ca41d6217207703b616165002c165b1e1d85a2a7dirk        layer_info[i].page.width=(size_t) (x-layer_info[i].page.x);
1445ca41d6217207703b616165002c165b1e1d85a2a7dirk        layer_info[i].page.height=(size_t) (y-layer_info[i].page.y);
144687038d5d4cc04fb99d6560ae95f3f07a87563323dirk        layer_info[i].channels=ReadBlobShort(image);
1447b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        if (layer_info[i].channels > MaxPSDChannels)
1448b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          {
1449bd8bd8572e272ce0bc730bfa0296b8f048ea2da1dirk            layer_info=DestroyLayerInfo(layer_info,number_layers);
1450b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            ThrowBinaryException(CorruptImageError,"MaximumChannelsExceeded",
1451419e5adbecfc7375751e7ac2ba30be0b1d35690fdirk              image->filename);
1452b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          }
1453b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        if (image->debug != MagickFalse)
1454b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1455b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            "    offset(%.20g,%.20g), size(%.20g,%.20g), channels=%.20g",
1456b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            (double) layer_info[i].page.x,(double) layer_info[i].page.y,
1457b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            (double) layer_info[i].page.height,(double)
1458b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            layer_info[i].page.width,(double) layer_info[i].channels);
1459b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        for (j=0; j < (ssize_t) layer_info[i].channels; j++)
1460b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        {
146187038d5d4cc04fb99d6560ae95f3f07a87563323dirk          layer_info[i].channel_info[j].type=(short) ReadBlobShort(image);
1462b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          layer_info[i].channel_info[j].size=(size_t) GetPSDSize(psd_info,
1463b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            image);
1464b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          if (image->debug != MagickFalse)
1465b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1466b41f080d52a5ff2d9c235cffac1419b84028bd31dirk              "    channel[%.20g]: type=%.20g, size=%.20g",(double) j,
1467b41f080d52a5ff2d9c235cffac1419b84028bd31dirk              (double) layer_info[i].channel_info[j].type,
1468b41f080d52a5ff2d9c235cffac1419b84028bd31dirk              (double) layer_info[i].channel_info[j].size);
1469b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        }
1470b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        count=ReadBlob(image,4,(unsigned char *) type);
147187038d5d4cc04fb99d6560ae95f3f07a87563323dirk        ReversePSDString(image,type,4);
1472b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        if ((count == 0) || (LocaleNCompare(type,"8BIM",4) != 0))
1473b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          {
1474b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            if (image->debug != MagickFalse)
1475b41f080d52a5ff2d9c235cffac1419b84028bd31dirk              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1476b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                "  layer type was %.4s instead of 8BIM", type);
1477bd8bd8572e272ce0bc730bfa0296b8f048ea2da1dirk            layer_info=DestroyLayerInfo(layer_info,number_layers);
1478b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            ThrowBinaryException(CorruptImageError,"ImproperImageHeader",
1479b41f080d52a5ff2d9c235cffac1419b84028bd31dirk              image->filename);
1480b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          }
1481b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        count=ReadBlob(image,4,(unsigned char *) layer_info[i].blendkey);
148287038d5d4cc04fb99d6560ae95f3f07a87563323dirk        ReversePSDString(image,layer_info[i].blendkey,4);
1483b52a4b752ce10edce4c5ddb441480635ff7c7283dirk        layer_info[i].opacity=(Quantum) ScaleCharToQuantum((unsigned char)
1484d8083a693bea157df66921cb7570880bb081dcd1cristy          ReadBlobByte(image));
1485b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        layer_info[i].clipping=(unsigned char) ReadBlobByte(image);
1486b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        layer_info[i].flags=(unsigned char) ReadBlobByte(image);
1487b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        layer_info[i].visible=!(layer_info[i].flags & 0x02);
1488b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        if (image->debug != MagickFalse)
1489b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1490b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            "   blend=%.4s, opacity=%.20g, clipping=%s, flags=%d, visible=%s",
1491b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            layer_info[i].blendkey,(double) layer_info[i].opacity,
1492b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            layer_info[i].clipping ? "true" : "false",layer_info[i].flags,
1493b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            layer_info[i].visible ? "true" : "false");
1494b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        (void) ReadBlobByte(image);  /* filler */
1495b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
149687038d5d4cc04fb99d6560ae95f3f07a87563323dirk        size=ReadBlobLong(image);
1497b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        if (size != 0)
1498b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          {
1499b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            MagickSizeType
1500b41f080d52a5ff2d9c235cffac1419b84028bd31dirk              combined_length,
1501b41f080d52a5ff2d9c235cffac1419b84028bd31dirk              length;
1502b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1503b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            if (image->debug != MagickFalse)
1504b41f080d52a5ff2d9c235cffac1419b84028bd31dirk              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1505b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                "    layer contains additional info");
150687038d5d4cc04fb99d6560ae95f3f07a87563323dirk            length=ReadBlobLong(image);
1507b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            combined_length=length+4;
1508b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            if (length != 0)
1509b41f080d52a5ff2d9c235cffac1419b84028bd31dirk              {
1510b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                /*
1511b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                  Layer mask info.
1512b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                */
15131fe0b879964fa7797e3d68574d297922a47c4034Cristy                layer_info[i].mask.page.y=ReadBlobSignedLong(image);
15141fe0b879964fa7797e3d68574d297922a47c4034Cristy                layer_info[i].mask.page.x=ReadBlobSignedLong(image);
151587038d5d4cc04fb99d6560ae95f3f07a87563323dirk                layer_info[i].mask.page.height=(size_t) (ReadBlobLong(image)-
151687038d5d4cc04fb99d6560ae95f3f07a87563323dirk                  layer_info[i].mask.page.y);
151787038d5d4cc04fb99d6560ae95f3f07a87563323dirk                layer_info[i].mask.page.width=(size_t) (ReadBlobLong(image)-
151887038d5d4cc04fb99d6560ae95f3f07a87563323dirk                  layer_info[i].mask.page.x);
1519a41d97fa7de942f144af6cfcceba24c523775c54dirk                layer_info[i].mask.background=(unsigned char) ReadBlobByte(
1520a41d97fa7de942f144af6cfcceba24c523775c54dirk                  image);
1521a41d97fa7de942f144af6cfcceba24c523775c54dirk                layer_info[i].mask.flags=(unsigned char) ReadBlobByte(image);
1522a41d97fa7de942f144af6cfcceba24c523775c54dirk                if (!(layer_info[i].mask.flags & 0x01))
1523a41d97fa7de942f144af6cfcceba24c523775c54dirk                  {
1524a41d97fa7de942f144af6cfcceba24c523775c54dirk                    layer_info[i].mask.page.y=layer_info[i].mask.page.y-
1525a41d97fa7de942f144af6cfcceba24c523775c54dirk                      layer_info[i].page.y;
1526a41d97fa7de942f144af6cfcceba24c523775c54dirk                    layer_info[i].mask.page.x=layer_info[i].mask.page.x-
1527a41d97fa7de942f144af6cfcceba24c523775c54dirk                      layer_info[i].page.x;
1528a41d97fa7de942f144af6cfcceba24c523775c54dirk                  }
1529b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                if (image->debug != MagickFalse)
1530b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1531b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                    "      layer mask: offset(%.20g,%.20g), size(%.20g,%.20g), length=%.20g",
1532a41d97fa7de942f144af6cfcceba24c523775c54dirk                    (double) layer_info[i].mask.page.x,(double)
1533a41d97fa7de942f144af6cfcceba24c523775c54dirk                    layer_info[i].mask.page.y,(double) layer_info[i].mask.page.width,
1534a41d97fa7de942f144af6cfcceba24c523775c54dirk                    (double) layer_info[i].mask.page.height,(double)
1535a41d97fa7de942f144af6cfcceba24c523775c54dirk                    ((MagickOffsetType) length)-18);
1536b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                /*
1537b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                  Skip over the rest of the layer mask information.
1538b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                */
1539a41d97fa7de942f144af6cfcceba24c523775c54dirk                if (DiscardBlobBytes(image,(MagickSizeType) (length-18)) == MagickFalse)
1540b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                  {
1541bd8bd8572e272ce0bc730bfa0296b8f048ea2da1dirk                    layer_info=DestroyLayerInfo(layer_info,number_layers);
1542419e5adbecfc7375751e7ac2ba30be0b1d35690fdirk                    ThrowBinaryException(CorruptImageError,"UnexpectedEndOfFile",
1543419e5adbecfc7375751e7ac2ba30be0b1d35690fdirk                      image->filename);
1544b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                  }
1545b41f080d52a5ff2d9c235cffac1419b84028bd31dirk              }
154687038d5d4cc04fb99d6560ae95f3f07a87563323dirk            length=ReadBlobLong(image);
1547b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            combined_length+=length+4;
1548b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            if (length != 0)
1549b41f080d52a5ff2d9c235cffac1419b84028bd31dirk              {
1550b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                /*
1551b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                  Layer blending ranges info.
1552b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                */
1553b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                if (image->debug != MagickFalse)
1554b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1555b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                    "      layer blending ranges: length=%.20g",(double)
1556b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                    ((MagickOffsetType) length));
1557b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                /*
1558b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                  We read it, but don't use it...
1559b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                */
1560b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                for (j=0; j < (ssize_t) (length); j+=8)
1561b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                {
156287038d5d4cc04fb99d6560ae95f3f07a87563323dirk                  size_t blend_source=ReadBlobLong(image);
156387038d5d4cc04fb99d6560ae95f3f07a87563323dirk                  size_t blend_dest=ReadBlobLong(image);
1564b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                  if (image->debug != MagickFalse)
1565b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1566b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                      "        source(%x), dest(%x)",(unsigned int)
1567b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                      blend_source,(unsigned int) blend_dest);
1568b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                }
1569b41f080d52a5ff2d9c235cffac1419b84028bd31dirk              }
1570b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            /*
1571b41f080d52a5ff2d9c235cffac1419b84028bd31dirk              Layer name.
1572b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            */
1573b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            length=(size_t) ReadBlobByte(image);
1574b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            combined_length+=length+1;
1575f084319814dd6d347d596618a528c44d26e4a34adirk            if (length > 0)
1576a41d97fa7de942f144af6cfcceba24c523775c54dirk              (void) ReadBlob(image,(size_t) length++,layer_info[i].name);
1577a41d97fa7de942f144af6cfcceba24c523775c54dirk            layer_info[i].name[length]='\0';
1578b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            if (image->debug != MagickFalse)
1579b41f080d52a5ff2d9c235cffac1419b84028bd31dirk              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1580b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                "      layer name: %s",layer_info[i].name);
1581b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            /*
1582b41f080d52a5ff2d9c235cffac1419b84028bd31dirk               Skip the rest of the variable data until we support it.
1583b41f080d52a5ff2d9c235cffac1419b84028bd31dirk             */
1584b41f080d52a5ff2d9c235cffac1419b84028bd31dirk             if (image->debug != MagickFalse)
1585b41f080d52a5ff2d9c235cffac1419b84028bd31dirk               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1586b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                 "      unsupported data: length=%.20g",(double)
1587b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                 ((MagickOffsetType) (size-combined_length)));
15881b875d28a6423d6314bc1da914ade6d086cfe252cristy             if (DiscardBlobBytes(image,(MagickSizeType) (size-combined_length)) == MagickFalse)
1589b41f080d52a5ff2d9c235cffac1419b84028bd31dirk               {
1590bd8bd8572e272ce0bc730bfa0296b8f048ea2da1dirk                 layer_info=DestroyLayerInfo(layer_info,number_layers);
1591b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                 ThrowBinaryException(CorruptImageError,
1592b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                   "UnexpectedEndOfFile",image->filename);
1593b41f080d52a5ff2d9c235cffac1419b84028bd31dirk               }
1594b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          }
1595b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      }
1596b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1597b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      for (i=0; i < number_layers; i++)
1598b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      {
1599b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        if ((layer_info[i].page.width == 0) ||
1600b41f080d52a5ff2d9c235cffac1419b84028bd31dirk              (layer_info[i].page.height == 0))
1601b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          {
1602b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            if (image->debug != MagickFalse)
1603b41f080d52a5ff2d9c235cffac1419b84028bd31dirk              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1604b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                "      layer data is empty");
1605b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            continue;
1606b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          }
1607b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1608b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        /*
1609b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          Allocate layered image.
1610b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        */
1611b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        layer_info[i].image=CloneImage(image,layer_info[i].page.width,
1612b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          layer_info[i].page.height,MagickFalse,exception);
1613b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        if (layer_info[i].image == (Image *) NULL)
1614b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          {
1615bd8bd8572e272ce0bc730bfa0296b8f048ea2da1dirk            layer_info=DestroyLayerInfo(layer_info,number_layers);
1616b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            if (image->debug != MagickFalse)
1617b41f080d52a5ff2d9c235cffac1419b84028bd31dirk              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1618b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                "  allocation of image for layer %.20g failed",(double) i);
1619b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1620b41f080d52a5ff2d9c235cffac1419b84028bd31dirk              image->filename);
1621b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          }
1622b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      }
1623b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
16244d9863ca77e690fdde8653d1f3db0721bd25978edirk      if (image_info->ping == MagickFalse)
1625b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        {
16264d9863ca77e690fdde8653d1f3db0721bd25978edirk          for (i=0; i < number_layers; i++)
1627b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          {
16284d9863ca77e690fdde8653d1f3db0721bd25978edirk            if (layer_info[i].image == (Image *) NULL)
1629b41f080d52a5ff2d9c235cffac1419b84028bd31dirk              {
16304d9863ca77e690fdde8653d1f3db0721bd25978edirk                for (j=0; j < layer_info[i].channels; j++)
16314d9863ca77e690fdde8653d1f3db0721bd25978edirk                {
16321b875d28a6423d6314bc1da914ade6d086cfe252cristy                  if (DiscardBlobBytes(image,(MagickSizeType)
16334d9863ca77e690fdde8653d1f3db0721bd25978edirk                      layer_info[i].channel_info[j].size) == MagickFalse)
16344d9863ca77e690fdde8653d1f3db0721bd25978edirk                    {
16354d9863ca77e690fdde8653d1f3db0721bd25978edirk                      layer_info=DestroyLayerInfo(layer_info,number_layers);
16364d9863ca77e690fdde8653d1f3db0721bd25978edirk                      ThrowBinaryException(CorruptImageError,
16374d9863ca77e690fdde8653d1f3db0721bd25978edirk                        "UnexpectedEndOfFile",image->filename);
16384d9863ca77e690fdde8653d1f3db0721bd25978edirk                    }
16394d9863ca77e690fdde8653d1f3db0721bd25978edirk                }
16404d9863ca77e690fdde8653d1f3db0721bd25978edirk                continue;
1641b41f080d52a5ff2d9c235cffac1419b84028bd31dirk              }
1642b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
16434d9863ca77e690fdde8653d1f3db0721bd25978edirk            if (image->debug != MagickFalse)
16444d9863ca77e690fdde8653d1f3db0721bd25978edirk              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
16454d9863ca77e690fdde8653d1f3db0721bd25978edirk                "  reading data for layer %.20g",(double) i);
1646b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
16474d9863ca77e690fdde8653d1f3db0721bd25978edirk            status=ReadPSDLayer(image,psd_info,&layer_info[i],exception);
16484d9863ca77e690fdde8653d1f3db0721bd25978edirk            if (status == MagickFalse)
16494d9863ca77e690fdde8653d1f3db0721bd25978edirk              break;
1650b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
16514d9863ca77e690fdde8653d1f3db0721bd25978edirk            status=SetImageProgress(image,LoadImagesTag,i,(MagickSizeType)
16524d9863ca77e690fdde8653d1f3db0721bd25978edirk              number_layers);
16534d9863ca77e690fdde8653d1f3db0721bd25978edirk            if (status == MagickFalse)
16544d9863ca77e690fdde8653d1f3db0721bd25978edirk              break;
16554d9863ca77e690fdde8653d1f3db0721bd25978edirk          }
16564d9863ca77e690fdde8653d1f3db0721bd25978edirk        }
1657b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1658b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      if (status != MagickFalse)
1659b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      {
1660b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        for (i=0; i < number_layers; i++)
1661b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        {
1662b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          if (layer_info[i].image == (Image *) NULL)
1663b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          {
1664b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            for (j=i; j < number_layers - 1; j++)
1665b41f080d52a5ff2d9c235cffac1419b84028bd31dirk              layer_info[j] = layer_info[j+1];
1666b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            number_layers--;
1667b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            i--;
1668b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          }
1669b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        }
1670b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1671b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        if (number_layers > 0)
1672b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          {
1673b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            for (i=0; i < number_layers; i++)
1674b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            {
1675b41f080d52a5ff2d9c235cffac1419b84028bd31dirk              if (i > 0)
1676b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                layer_info[i].image->previous=layer_info[i-1].image;
1677b41f080d52a5ff2d9c235cffac1419b84028bd31dirk              if (i < (number_layers-1))
1678b41f080d52a5ff2d9c235cffac1419b84028bd31dirk                layer_info[i].image->next=layer_info[i+1].image;
1679b41f080d52a5ff2d9c235cffac1419b84028bd31dirk              layer_info[i].image->page=layer_info[i].page;
1680b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            }
1681b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            image->next=layer_info[0].image;
1682b41f080d52a5ff2d9c235cffac1419b84028bd31dirk            layer_info[0].image->previous=image;
1683b41f080d52a5ff2d9c235cffac1419b84028bd31dirk          }
1684bd9f1e7d1bd2c8e2cf7895d133c5c5b5cd3526b6dirk        layer_info=(LayerInfo *) RelinquishMagickMemory(layer_info);
1685b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      }
1686bd9f1e7d1bd2c8e2cf7895d133c5c5b5cd3526b6dirk      else
1687bd9f1e7d1bd2c8e2cf7895d133c5c5b5cd3526b6dirk        layer_info=DestroyLayerInfo(layer_info,number_layers);
1688b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    }
1689b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1690b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  return(status);
1691b41f080d52a5ff2d9c235cffac1419b84028bd31dirk}
1692b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1693b20a1794de28edf28c46f2268914c15781482530dirkstatic MagickBooleanType ReadPSDMergedImage(const ImageInfo *image_info,
1694b20a1794de28edf28c46f2268914c15781482530dirk  Image *image,const PSDInfo *psd_info,ExceptionInfo *exception)
1695b41f080d52a5ff2d9c235cffac1419b84028bd31dirk{
1696b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  MagickOffsetType
1697b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    *offsets;
1698b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1699b20a1794de28edf28c46f2268914c15781482530dirk  MagickBooleanType
1700b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    status;
1701b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1702b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  PSDCompressionType
1703b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    compression;
1704b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1705b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  register ssize_t
1706b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    i;
1707b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1708b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  compression=(PSDCompressionType) ReadBlobMSBShort(image);
1709b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  image->compression=ConvertPSDCompression(compression);
1710b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1711b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  if (compression != Raw && compression != RLE)
1712b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    {
1713b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      (void) ThrowMagickException(exception,GetMagickModule(),
1714b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        TypeWarning,"CompressionNotSupported","'%.20g'",(double) compression);
1715b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      return(MagickFalse);
1716b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    }
1717b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1718b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  offsets=(MagickOffsetType *) NULL;
1719b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  if (compression == RLE)
1720b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  {
1721b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    offsets=ReadPSDRLEOffsets(image,psd_info,image->rows*psd_info->channels);
1722b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    if (offsets == (MagickOffsetType *) NULL)
1723b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1724b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        image->filename);
1725b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  }
1726b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1727b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  status=MagickTrue;
1728b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  for (i=0; i < (ssize_t) psd_info->channels; i++)
1729b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  {
1730b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    if (compression == RLE)
1731b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      status=ReadPSDChannelRLE(image,psd_info,i,offsets+(i*image->rows),
1732b41f080d52a5ff2d9c235cffac1419b84028bd31dirk        exception);
1733b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    else
1734b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      status=ReadPSDChannelRaw(image,psd_info->channels,i,exception);
1735b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1736b20a1794de28edf28c46f2268914c15781482530dirk    if (status != MagickFalse)
1737b20a1794de28edf28c46f2268914c15781482530dirk      status=SetImageProgress(image,LoadImagesTag,i,psd_info->channels);
1738b20a1794de28edf28c46f2268914c15781482530dirk
1739b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    if (status == MagickFalse)
1740b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      break;
1741b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  }
1742b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1743b20a1794de28edf28c46f2268914c15781482530dirk  if ((status != MagickFalse) && (image->colorspace == CMYKColorspace))
1744b20a1794de28edf28c46f2268914c15781482530dirk    status=NegateCMYK(image,exception);
1745b20a1794de28edf28c46f2268914c15781482530dirk
1746b20a1794de28edf28c46f2268914c15781482530dirk  if (status != MagickFalse)
1747b20a1794de28edf28c46f2268914c15781482530dirk    status=CorrectPSDAlphaBlend(image_info,image,exception);
1748b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1749b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  if (offsets != (MagickOffsetType *) NULL)
1750b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    offsets=(MagickOffsetType *) RelinquishMagickMemory(offsets);
1751b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1752b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  return(status);
1753b41f080d52a5ff2d9c235cffac1419b84028bd31dirk}
1754b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
175590de83d3fe5221a8896ab53556c2e7992078a96ccristystatic Image *ReadPSDImage(const ImageInfo *image_info,ExceptionInfo *exception)
1756b41f080d52a5ff2d9c235cffac1419b84028bd31dirk{
1757b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  Image
1758b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    *image;
1759b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1760b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  MagickBooleanType
176118c0e4dff391a0a98e7f478d0d86bbd08f7708d0dirk    has_merged_image,
1762a41d97fa7de942f144af6cfcceba24c523775c54dirk    skip_layers;
1763b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1764b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  MagickOffsetType
1765b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    offset;
1766b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1767b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  MagickSizeType
1768b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    length;
1769b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1770b20a1794de28edf28c46f2268914c15781482530dirk  MagickBooleanType
1771a41d97fa7de942f144af6cfcceba24c523775c54dirk    status;
1772a41d97fa7de942f144af6cfcceba24c523775c54dirk
1773b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  PSDInfo
1774b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    psd_info;
1775b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1776b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  register ssize_t
1777b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    i;
1778b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1779b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  ssize_t
1780b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    count;
1781b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1782b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  unsigned char
1783b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    *data;
1784b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1785b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  /*
1786b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    Open image file.
1787b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  */
1788b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  assert(image_info != (const ImageInfo *) NULL);
1789e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(image_info->signature == MagickCoreSignature);
1790b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  if (image_info->debug != MagickFalse)
1791b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1792b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      image_info->filename);
1793b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  assert(exception != (ExceptionInfo *) NULL);
1794e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(exception->signature == MagickCoreSignature);
1795b41f080d52a5ff2d9c235cffac1419b84028bd31dirk
1796b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  image=AcquireImage(image_info,exception);
1797b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1798b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  if (status == MagickFalse)
1799b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    {
1800b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      image=DestroyImageList(image);
1801b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      return((Image *) NULL);
1802b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    }
1803b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  /*
1804b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    Read image header.
1805b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  */
1806fc16b54cdf77910dd5014ce819440662ced29d09dirk  image->endian=MSBEndian;
1807b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  count=ReadBlob(image,4,(unsigned char *) psd_info.signature);
1808b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  psd_info.version=ReadBlobMSBShort(image);
1809b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  if ((count == 0) || (LocaleNCompare(psd_info.signature,"8BPS",4) != 0) ||
1810b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      ((psd_info.version != 1) && (psd_info.version != 2)))
1811b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1812f308152b28249d599fa01dd41b1518c4ddfc5e60dirk  (void) ReadBlob(image,6,psd_info.reserved);
1813b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  psd_info.channels=ReadBlobMSBShort(image);
1814b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  if (psd_info.channels > MaxPSDChannels)
1815b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    ThrowReaderException(CorruptImageError,"MaximumChannelsExceeded");
1816b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  psd_info.rows=ReadBlobMSBLong(image);
1817b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  psd_info.columns=ReadBlobMSBLong(image);
1818b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  if ((psd_info.version == 1) && ((psd_info.rows > 30000) ||
1819b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      (psd_info.columns > 30000)))
1820b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1821b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  psd_info.depth=ReadBlobMSBShort(image);
1822b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  if ((psd_info.depth != 1) && (psd_info.depth != 8) && (psd_info.depth != 16))
1823b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1824b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  psd_info.mode=ReadBlobMSBShort(image);
1825b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  if (image->debug != MagickFalse)
18263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1827e8c25f9b4c9fb72cad6db08eeda58c7c5784014ecristy      "  Image is %.20g x %.20g with channels=%.20g, depth=%.20g, mode=%s",
1828e8c25f9b4c9fb72cad6db08eeda58c7c5784014ecristy      (double) psd_info.columns,(double) psd_info.rows,(double)
1829e8c25f9b4c9fb72cad6db08eeda58c7c5784014ecristy      psd_info.channels,(double) psd_info.depth,ModeToString((PSDImageType)
1830e8c25f9b4c9fb72cad6db08eeda58c7c5784014ecristy      psd_info.mode));
18313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
18323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Initialize image.
18333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
18343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  image->depth=psd_info.depth;
18353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  image->columns=psd_info.columns;
18363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  image->rows=psd_info.rows;
1837acabb847a592ca5e430c1c0949d03acfc0b78bb9cristy  status=SetImageExtent(image,image->columns,image->rows,exception);
1838acabb847a592ca5e430c1c0949d03acfc0b78bb9cristy  if (status == MagickFalse)
1839acabb847a592ca5e430c1c0949d03acfc0b78bb9cristy    return(DestroyImageList(image));
1840ea1a8aa04a9fe1500104284407c1cc06d20da699cristy  if (SetImageBackgroundColor(image,exception) == MagickFalse)
184195524f92fc346f548f202d36ffc6a17fdbd1b1cbcristy    {
184295524f92fc346f548f202d36ffc6a17fdbd1b1cbcristy      image=DestroyImageList(image);
184395524f92fc346f548f202d36ffc6a17fdbd1b1cbcristy      return((Image *) NULL);
184495524f92fc346f548f202d36ffc6a17fdbd1b1cbcristy    }
18453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (psd_info.mode == LabMode)
1846e2c4f18a7274c0c5c6231a2f3d73741a87d583facristy    SetImageColorspace(image,LabColorspace,exception);
18473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (psd_info.mode == CMYKMode)
184884affaa1fd31c85f2c323db093508352c1df05abdirk    {
184984affaa1fd31c85f2c323db093508352c1df05abdirk      SetImageColorspace(image,CMYKColorspace,exception);
1850deca4044d29506bb0d54806e44bdbe3c802eb430dirk      image->alpha_trait=psd_info.channels > 4 ? BlendPixelTrait :
185184affaa1fd31c85f2c323db093508352c1df05abdirk        UndefinedPixelTrait;
185284affaa1fd31c85f2c323db093508352c1df05abdirk    }
185384affaa1fd31c85f2c323db093508352c1df05abdirk  else if ((psd_info.mode == BitmapMode) || (psd_info.mode == GrayscaleMode) ||
18543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (psd_info.mode == DuotoneMode))
18553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
1856afd0fd11c04ff6716f320206eba3a64a2ca95a09cristy      status=AcquireImageColormap(image,psd_info.depth != 16 ? 256 : 65536,
1857afd0fd11c04ff6716f320206eba3a64a2ca95a09cristy        exception);
1858afd0fd11c04ff6716f320206eba3a64a2ca95a09cristy      if (status == MagickFalse)
185952cf7f1d54f12223fd4ca0c2a428811c003f81ddcristy        ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
18603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (image->debug != MagickFalse)
18613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1862dede49f1361cdf0a7aa29aa281b6f6e9a565f0facristy          "  Image colormap allocated");
1863e2c4f18a7274c0c5c6231a2f3d73741a87d583facristy      SetImageColorspace(image,GRAYColorspace,exception);
1864deca4044d29506bb0d54806e44bdbe3c802eb430dirk      image->alpha_trait=psd_info.channels > 1 ? BlendPixelTrait :
186584affaa1fd31c85f2c323db093508352c1df05abdirk        UndefinedPixelTrait;
18663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
186784affaa1fd31c85f2c323db093508352c1df05abdirk  else
1868deca4044d29506bb0d54806e44bdbe3c802eb430dirk    image->alpha_trait=psd_info.channels > 3 ? BlendPixelTrait :
186984affaa1fd31c85f2c323db093508352c1df05abdirk      UndefinedPixelTrait;
18703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
18713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Read PSD raster colormap only present for indexed and duotone images.
18723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
18733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  length=ReadBlobMSBLong(image);
18743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (length != 0)
18753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
18763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (image->debug != MagickFalse)
18773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
18783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          "  reading colormap");
18793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (psd_info.mode == DuotoneMode)
18803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
18813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          /*
18823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            Duotone image data;  the format of this data is undocumented.
18833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          */
188456ed31cc763800a9fb1f0df96104c354b40d2cbccristy          data=(unsigned char *) AcquireQuantumMemory((size_t) length,
188556ed31cc763800a9fb1f0df96104c354b40d2cbccristy            sizeof(*data));
18863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          if (data == (unsigned char *) NULL)
18873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1888f308152b28249d599fa01dd41b1518c4ddfc5e60dirk          (void) ReadBlob(image,(size_t) length,data);
18893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          data=(unsigned char *) RelinquishMagickMemory(data);
18903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
18913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      else
18923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
189318a9b97ccf4867621620ac1d81c38f5d81e1f4c9cristy          size_t
189418a9b97ccf4867621620ac1d81c38f5d81e1f4c9cristy            number_colors;
189518a9b97ccf4867621620ac1d81c38f5d81e1f4c9cristy
18963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          /*
18973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            Read PSD raster colormap.
18983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          */
189918a9b97ccf4867621620ac1d81c38f5d81e1f4c9cristy          number_colors=length/3;
190018a9b97ccf4867621620ac1d81c38f5d81e1f4c9cristy          if (number_colors > 65536)
190118a9b97ccf4867621620ac1d81c38f5d81e1f4c9cristy            ThrowReaderException(CorruptImageError,"ImproperImageHeader");
190218a9b97ccf4867621620ac1d81c38f5d81e1f4c9cristy          if (AcquireImageColormap(image,number_colors,exception) == MagickFalse)
19033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1904bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy          for (i=0; i < (ssize_t) image->colors; i++)
19053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            image->colormap[i].red=ScaleCharToQuantum((unsigned char)
19063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              ReadBlobByte(image));
1907bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy          for (i=0; i < (ssize_t) image->colors; i++)
19083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            image->colormap[i].green=ScaleCharToQuantum((unsigned char)
19093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              ReadBlobByte(image));
1910bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy          for (i=0; i < (ssize_t) image->colors; i++)
19113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            image->colormap[i].blue=ScaleCharToQuantum((unsigned char)
19123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy              ReadBlobByte(image));
19138a46d827a124555f0c48fb2368ec1bba8e079ab6cristy          image->alpha_trait=UndefinedPixelTrait;
19143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
19153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
1916198fffab4daf8aea88badd9c629350e5b26ec32fdirk  if ((image->depth == 1) && (image->storage_class != PseudoClass))
1917198fffab4daf8aea88badd9c629350e5b26ec32fdirk    ThrowReaderException(CorruptImageError, "ImproperImageHeader");
191818c0e4dff391a0a98e7f478d0d86bbd08f7708d0dirk  has_merged_image=MagickTrue;
19193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  length=ReadBlobMSBLong(image);
19203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (length != 0)
19213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
19223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      unsigned char
19233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        *blocks;
19243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
19253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /*
19263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        Image resources block.
19273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      */
19283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (image->debug != MagickFalse)
19293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
19302b9582a27910c7baaeb04b7e969638328fa70095cristy          "  reading image resource blocks - %.20g bytes",(double)
19312b9582a27910c7baaeb04b7e969638328fa70095cristy          ((MagickOffsetType) length));
19327ec893210d13a7424e5a7c3200568f1bf5317040dirk      blocks=(unsigned char *) AcquireQuantumMemory((size_t) length,
193356ed31cc763800a9fb1f0df96104c354b40d2cbccristy        sizeof(*blocks));
19343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (blocks == (unsigned char *) NULL)
19353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
193656ed31cc763800a9fb1f0df96104c354b40d2cbccristy      count=ReadBlob(image,(size_t) length,blocks);
19374b1b9c0522628887195bad3a6723f7000b0c9a58dirk      if ((count != (ssize_t) length) || (length < 4) ||
19383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          (LocaleNCompare((char *) blocks,"8BIM",4) != 0))
19393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
19403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          blocks=(unsigned char *) RelinquishMagickMemory(blocks);
19413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          ThrowReaderException(CorruptImageError,"ImproperImageHeader");
19423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
19437ec893210d13a7424e5a7c3200568f1bf5317040dirk      ParseImageResourceBlocks(image,blocks,(size_t) length,&has_merged_image,
19447ec893210d13a7424e5a7c3200568f1bf5317040dirk        exception);
19453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      blocks=(unsigned char *) RelinquishMagickMemory(blocks);
19463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
19473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
19483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Layer and mask block.
19493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
19502d3d87fbdee6704f11aad6e75d00847fe10f4d0ecristy  length=GetPSDSize(&psd_info,image);
19513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (length == 8)
19523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
19533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      length=ReadBlobMSBLong(image);
19543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      length=ReadBlobMSBLong(image);
19553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
1956b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  offset=TellBlob(image);
1957b41f080d52a5ff2d9c235cffac1419b84028bd31dirk  skip_layers=MagickFalse;
195818c0e4dff391a0a98e7f478d0d86bbd08f7708d0dirk  if ((image_info->number_scenes == 1) && (image_info->scene == 0) &&
195918c0e4dff391a0a98e7f478d0d86bbd08f7708d0dirk      (has_merged_image != MagickFalse))
1960d4297029a6faeb030aa4da519db921992dda664fcristy    {
1961374b8ad2958410591db2e8c42e9b65ef89655e00cristy      if (image->debug != MagickFalse)
1962374b8ad2958410591db2e8c42e9b65ef89655e00cristy        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1963374b8ad2958410591db2e8c42e9b65ef89655e00cristy          "  read composite only");
1964b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      skip_layers=MagickTrue;
1965d4297029a6faeb030aa4da519db921992dda664fcristy    }
19663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (length == 0)
19673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
19683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (image->debug != MagickFalse)
19693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
19703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          "  image has no layers");
19713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
19723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  else
19733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
19744d9863ca77e690fdde8653d1f3db0721bd25978edirk      if (ReadPSDLayers(image,image_info,&psd_info,skip_layers,exception) !=
19754d9863ca77e690fdde8653d1f3db0721bd25978edirk          MagickTrue)
19766f20531b06ddc2852ec30506e13798363f534e53dirk        {
19776f20531b06ddc2852ec30506e13798363f534e53dirk          (void) CloseBlob(image);
1978419e5adbecfc7375751e7ac2ba30be0b1d35690fdirk          image=DestroyImageList(image);
19796f20531b06ddc2852ec30506e13798363f534e53dirk          return((Image *) NULL);
19806f20531b06ddc2852ec30506e13798363f534e53dirk        }
19813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1982b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      /*
1983b41f080d52a5ff2d9c235cffac1419b84028bd31dirk         Skip the rest of the layer and mask information.
1984b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      */
1985b41f080d52a5ff2d9c235cffac1419b84028bd31dirk      SeekBlob(image,offset+length,SEEK_SET);
19863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
19874d9863ca77e690fdde8653d1f3db0721bd25978edirk  /*
198889e226084238a1611a572467a330e6e7145059becristy    If we are only "pinging" the image, then we're done - so return.
198989e226084238a1611a572467a330e6e7145059becristy  */
199089e226084238a1611a572467a330e6e7145059becristy  if (image_info->ping != MagickFalse)
199189e226084238a1611a572467a330e6e7145059becristy    {
199289e226084238a1611a572467a330e6e7145059becristy      (void) CloseBlob(image);
199389e226084238a1611a572467a330e6e7145059becristy      return(GetFirstImageInList(image));
199489e226084238a1611a572467a330e6e7145059becristy    }
199589e226084238a1611a572467a330e6e7145059becristy  /*
1996b41f080d52a5ff2d9c235cffac1419b84028bd31dirk    Read the precombined layer, present for PSD < 4 compatibility.
19973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
19983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (image->debug != MagickFalse)
19993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
20003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      "  reading the precombined layer");
200190de83d3fe5221a8896ab53556c2e7992078a96ccristy  if ((has_merged_image != MagickFalse) || (GetImageListLength(image) == 1))
2002b20a1794de28edf28c46f2268914c15781482530dirk    has_merged_image=(MagickBooleanType) ReadPSDMergedImage(image_info,image,
2003b20a1794de28edf28c46f2268914c15781482530dirk      &psd_info,exception);
200490de83d3fe5221a8896ab53556c2e7992078a96ccristy  if ((has_merged_image == MagickFalse) && (GetImageListLength(image) == 1) &&
200590de83d3fe5221a8896ab53556c2e7992078a96ccristy      (length != 0))
20062de94f5ff88944751b5d625aed674d56b59237afdirk    {
20072de94f5ff88944751b5d625aed674d56b59237afdirk      SeekBlob(image,offset,SEEK_SET);
200890de83d3fe5221a8896ab53556c2e7992078a96ccristy      status=ReadPSDLayers(image,image_info,&psd_info,MagickFalse,exception);
200990de83d3fe5221a8896ab53556c2e7992078a96ccristy      if (status != MagickTrue)
20102de94f5ff88944751b5d625aed674d56b59237afdirk        {
20112de94f5ff88944751b5d625aed674d56b59237afdirk          (void) CloseBlob(image);
2012b9ed408ffc0401e23dfd98b843dd4ae4313c0255dirk          image=DestroyImageList(image);
20132de94f5ff88944751b5d625aed674d56b59237afdirk          return((Image *) NULL);
20142de94f5ff88944751b5d625aed674d56b59237afdirk        }
20152de94f5ff88944751b5d625aed674d56b59237afdirk    }
201690de83d3fe5221a8896ab53556c2e7992078a96ccristy  if ((has_merged_image == MagickFalse) && (GetImageListLength(image) > 1))
201718c0e4dff391a0a98e7f478d0d86bbd08f7708d0dirk    {
201818c0e4dff391a0a98e7f478d0d86bbd08f7708d0dirk      Image
201918c0e4dff391a0a98e7f478d0d86bbd08f7708d0dirk        *merged;
202018c0e4dff391a0a98e7f478d0d86bbd08f7708d0dirk
202118c0e4dff391a0a98e7f478d0d86bbd08f7708d0dirk      SetImageAlphaChannel(image,TransparentAlphaChannel,exception);
202218c0e4dff391a0a98e7f478d0d86bbd08f7708d0dirk      image->background_color.alpha=TransparentAlpha;
20237b5a0d558aa402f0d0a853c97866c14856a10be9dirk      image->background_color.alpha_trait=BlendPixelTrait;
202418c0e4dff391a0a98e7f478d0d86bbd08f7708d0dirk      merged=MergeImageLayers(image,FlattenLayer,exception);
202518c0e4dff391a0a98e7f478d0d86bbd08f7708d0dirk      ReplaceImageInList(&image,merged);
202618c0e4dff391a0a98e7f478d0d86bbd08f7708d0dirk    }
20273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) CloseBlob(image);
20283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(GetFirstImageInList(image));
20293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
20303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
20313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
20323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
20333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
20343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
20353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
20363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   R e g i s t e r P S D I m a g e                                           %
20373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
20383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
20393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
20403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
20413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
20423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  RegisterPSDImage() adds properties for the PSD image format to
20433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  the list of supported formats.  The properties include the image format
20443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  tag, a method to read and/or write the format, whether the format
20453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  supports the saving of more than one frame to the same file or blob,
20463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  whether the format supports native in-memory I/O, and a brief
20473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  description of the format.
20483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
20493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the RegisterPSDImage method is:
20503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2051bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy%      size_t RegisterPSDImage(void)
20523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
20533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
2054bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristyModuleExport size_t RegisterPSDImage(void)
20553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
20563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickInfo
20573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *entry;
20583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
205906b627a07ff44e1ff93ef1288c9f428066ded10ddirk  entry=AcquireMagickInfo("PSD","PSB","Adobe Large Document Format");
2060b42330138c186026c567ffb0cce21aa06137b730cristy  entry->decoder=(DecodeImageHandler *) ReadPSDImage;
2061b42330138c186026c567ffb0cce21aa06137b730cristy  entry->encoder=(EncodeImageHandler *) WritePSDImage;
2062b42330138c186026c567ffb0cce21aa06137b730cristy  entry->magick=(IsImageFormatHandler *) IsPSD;
206308e9a113db499034abb5ad8d59b42f8eca3c641cdirk  entry->flags|=CoderSeekableStreamFlag;
2064b42330138c186026c567ffb0cce21aa06137b730cristy  (void) RegisterMagickInfo(entry);
206506b627a07ff44e1ff93ef1288c9f428066ded10ddirk  entry=AcquireMagickInfo("PSD","PSD","Adobe Photoshop bitmap");
20663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  entry->decoder=(DecodeImageHandler *) ReadPSDImage;
20673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  entry->encoder=(EncodeImageHandler *) WritePSDImage;
20683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  entry->magick=(IsImageFormatHandler *) IsPSD;
206908e9a113db499034abb5ad8d59b42f8eca3c641cdirk  entry->flags|=CoderSeekableStreamFlag;
20703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) RegisterMagickInfo(entry);
20713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(MagickImageCoderSignature);
20723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
20733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
20743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
20753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
20763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
20773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
20783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
20793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   U n r e g i s t e r P S D I m a g e                                       %
20803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
20813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
20823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
20833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
20843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
20853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  UnregisterPSDImage() removes format registrations made by the
20863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  PSD module from the list of supported formats.
20873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
20883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the UnregisterPSDImage method is:
20893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
20903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      UnregisterPSDImage(void)
20913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
20923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
20933ed852eea50f9d4cd633efb8c2b054b8e33c253cristyModuleExport void UnregisterPSDImage(void)
20943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
2095b42330138c186026c567ffb0cce21aa06137b730cristy  (void) UnregisterMagickInfo("PSB");
20963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) UnregisterMagickInfo("PSD");
20973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
20983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
20993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
21003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
21013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
21023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
21033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
21043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   W r i t e P S D I m a g e                                                 %
21053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
21063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
21073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
21083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
21093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
2110b1459bce38004e27d61bef953617d25747264ff4cristy%  WritePSDImage() writes an image in the Adobe Photoshop encoded image format.
21113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
21123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the WritePSDImage method is:
21133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
21141ab941fc759aa277e7f3a6050d149edfa4b29446dirk%      MagickBooleanType WritePSDImage(const ImageInfo *image_info,Image *image,
21151ab941fc759aa277e7f3a6050d149edfa4b29446dirk%        ExceptionInfo *exception)
21163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
21173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows.
21183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
21193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image_info: the image info.
21203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
21213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image:  The image.
21223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
21233a37efd7ece979e9c63dc8f2f2d3816bab8b1156cristy%    o exception: return any errors or warnings in this structure.
21243a37efd7ece979e9c63dc8f2f2d3816bab8b1156cristy%
21253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
21263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
212750aea4a7536abc82a6877cd256987666d14d54d0cristystatic inline ssize_t SetPSDOffset(const PSDInfo *psd_info,Image *image,
2128f0460eee0be6e6f31666d8eb784eb002399ff39fcristy  const size_t offset)
2129f0460eee0be6e6f31666d8eb784eb002399ff39fcristy{
2130f0460eee0be6e6f31666d8eb784eb002399ff39fcristy  if (psd_info->version == 1)
213156ed31cc763800a9fb1f0df96104c354b40d2cbccristy    return(WriteBlobMSBShort(image,(unsigned short) offset));
213256ed31cc763800a9fb1f0df96104c354b40d2cbccristy  return(WriteBlobMSBLong(image,(unsigned short) offset));
2133f0460eee0be6e6f31666d8eb784eb002399ff39fcristy}
2134f0460eee0be6e6f31666d8eb784eb002399ff39fcristy
213550aea4a7536abc82a6877cd256987666d14d54d0cristystatic inline ssize_t SetPSDSize(const PSDInfo *psd_info,Image *image,
2136f0460eee0be6e6f31666d8eb784eb002399ff39fcristy  const MagickSizeType size)
2137f0460eee0be6e6f31666d8eb784eb002399ff39fcristy{
2138f0460eee0be6e6f31666d8eb784eb002399ff39fcristy  if (psd_info->version == 1)
213956ed31cc763800a9fb1f0df96104c354b40d2cbccristy    return(WriteBlobMSBLong(image,(unsigned int) size));
2140f0460eee0be6e6f31666d8eb784eb002399ff39fcristy  return(WriteBlobMSBLongLong(image,size));
2141f0460eee0be6e6f31666d8eb784eb002399ff39fcristy}
2142f0460eee0be6e6f31666d8eb784eb002399ff39fcristy
21434aff1576adab1eae438d2d5b3ac2dde8418ccba8cristystatic size_t PSDPackbitsEncodeImage(Image *image,const size_t length,
2144018f07f7333b25743d0afff892450cebdb905c1acristy  const unsigned char *pixels,unsigned char *compact_pixels,
2145018f07f7333b25743d0afff892450cebdb905c1acristy  ExceptionInfo *exception)
21464aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy{
21474aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy  int
21484aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy    count;
21494aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy
2150bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  register ssize_t
21514aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy    i,
21524aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy    j;
21534aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy
21544aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy  register unsigned char
21554aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy    *q;
21564aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy
21574aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy  unsigned char
21584aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy    *packbits;
21594aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy
21604aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy  /*
21614aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy    Compress pixels with Packbits encoding.
21624aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy  */
21634aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy  assert(image != (Image *) NULL);
2164e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(image->signature == MagickCoreSignature);
21654aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy  if (image->debug != MagickFalse)
21664aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
21674aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy  assert(pixels != (unsigned char *) NULL);
21684aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy  packbits=(unsigned char *) AcquireQuantumMemory(128UL,sizeof(*packbits));
21694aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy  if (packbits == (unsigned char *) NULL)
21704aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
21714aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy      image->filename);
2172b1459bce38004e27d61bef953617d25747264ff4cristy  q=compact_pixels;
2173bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (i=(ssize_t) length; i != 0; )
21744aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy  {
21754aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy    switch (i)
21764aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy    {
21774aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy      case 1:
21784aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy      {
21794aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy        i--;
21804aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy        *q++=(unsigned char) 0;
21814aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy        *q++=(*pixels);
21824aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy        break;
21834aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy      }
21844aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy      case 2:
21854aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy      {
21864aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy        i-=2;
21874aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy        *q++=(unsigned char) 1;
21884aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy        *q++=(*pixels);
21894aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy        *q++=pixels[1];
21904aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy        break;
21914aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy      }
21924aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy      case 3:
21934aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy      {
21944aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy        i-=3;
21954aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy        if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2)))
21964aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy          {
21974aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy            *q++=(unsigned char) ((256-3)+1);
21984aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy            *q++=(*pixels);
21994aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy            break;
22004aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy          }
22014aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy        *q++=(unsigned char) 2;
22024aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy        *q++=(*pixels);
22034aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy        *q++=pixels[1];
22044aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy        *q++=pixels[2];
22054aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy        break;
22064aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy      }
22074aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy      default:
22084aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy      {
22094aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy        if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2)))
22104aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy          {
22114aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy            /*
22124aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy              Packed run.
22134aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy            */
22144aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy            count=3;
2215bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy            while (((ssize_t) count < i) && (*pixels == *(pixels+count)))
22164aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy            {
22174aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy              count++;
22184aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy              if (count >= 127)
22194aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy                break;
22204aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy            }
22214aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy            i-=count;
22224aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy            *q++=(unsigned char) ((256-count)+1);
22234aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy            *q++=(*pixels);
22244aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy            pixels+=count;
22254aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy            break;
22264aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy          }
22274aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy        /*
22284aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy          Literal run.
22294aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy        */
22304aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy        count=0;
22314aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy        while ((*(pixels+count) != *(pixels+count+1)) ||
22324aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy               (*(pixels+count+1) != *(pixels+count+2)))
22334aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy        {
22344aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy          packbits[count+1]=pixels[count];
22354aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy          count++;
2236bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy          if (((ssize_t) count >= (i-3)) || (count >= 127))
22374aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy            break;
22384aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy        }
22394aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy        i-=count;
22404aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy        *packbits=(unsigned char) (count-1);
2241bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy        for (j=0; j <= (ssize_t) count; j++)
22424aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy          *q++=packbits[j];
22434aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy        pixels+=count;
22444aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy        break;
22454aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy      }
22464aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy    }
22474aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy  }
22484aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy  *q++=(unsigned char) 128;  /* EOD marker */
22494aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy  packbits=(unsigned char *) RelinquishMagickMemory(packbits);
2250b1459bce38004e27d61bef953617d25747264ff4cristy  return((size_t) (q-compact_pixels));
22514aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy}
22524aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy
2253875e28af6da774727babef3e455b967d02a146f5cristystatic void WritePackbitsLength(const PSDInfo *psd_info,
2254a20214eef4b9c5e1797527b0a6273899a9062f9ccristy  const ImageInfo *image_info,Image *image,Image *next_image,
2255018f07f7333b25743d0afff892450cebdb905c1acristy  unsigned char *compact_pixels,const QuantumType quantum_type,
2256018f07f7333b25743d0afff892450cebdb905c1acristy  ExceptionInfo *exception)
22573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
22583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  QuantumInfo
22593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *quantum_info;
22603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
22614c08aed51c5899665ade97263692328eea4af106cristy  register const Quantum
22623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *p;
22633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
22643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  size_t
22654aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy    length,
22663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    packet_size;
22673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
226875f85ae6350dcd7d4f771f8fc1b7da27027ac50dcristy  ssize_t
226975f85ae6350dcd7d4f771f8fc1b7da27027ac50dcristy    y;
227075f85ae6350dcd7d4f771f8fc1b7da27027ac50dcristy
2271a20214eef4b9c5e1797527b0a6273899a9062f9ccristy  unsigned char
2272a20214eef4b9c5e1797527b0a6273899a9062f9ccristy    *pixels;
2273a20214eef4b9c5e1797527b0a6273899a9062f9ccristy
2274a20214eef4b9c5e1797527b0a6273899a9062f9ccristy  if (next_image->depth > 8)
2275a20214eef4b9c5e1797527b0a6273899a9062f9ccristy    next_image->depth=16;
2276a20214eef4b9c5e1797527b0a6273899a9062f9ccristy  packet_size=next_image->depth > 8UL ? 2UL : 1UL;
2277da16f16767eb31921af855f17bda465fffc4e000cristy  (void) packet_size;
22785f766ef8b0cd9906c2c3a56d845828380a251073cristy  quantum_info=AcquireQuantumInfo(image_info,image);
2279b3f97ae45019a91b30792a6fa42d81a2689a7025cristy  pixels=(unsigned char *) GetQuantumPixels(quantum_info);
2280a20214eef4b9c5e1797527b0a6273899a9062f9ccristy  for (y=0; y < (ssize_t) next_image->rows; y++)
22814aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy  {
2282c82a27bb8e3138ff9bbf0f696663bdf3e704cedecristy    p=GetVirtualPixels(next_image,0,y,next_image->columns,1,exception);
22834c08aed51c5899665ade97263692328eea4af106cristy    if (p == (const Quantum *) NULL)
22844aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy      break;
2285a20214eef4b9c5e1797527b0a6273899a9062f9ccristy    length=ExportQuantumPixels(next_image,(CacheView *) NULL,quantum_info,
2286c82a27bb8e3138ff9bbf0f696663bdf3e704cedecristy      quantum_type,pixels,exception);
2287018f07f7333b25743d0afff892450cebdb905c1acristy    length=PSDPackbitsEncodeImage(image,length,pixels,compact_pixels,
2288018f07f7333b25743d0afff892450cebdb905c1acristy      exception);
2289875e28af6da774727babef3e455b967d02a146f5cristy    (void) SetPSDOffset(psd_info,image,length);
22904aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy  }
22914aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy  quantum_info=DestroyQuantumInfo(quantum_info);
22924aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy}
22934aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy
2294875e28af6da774727babef3e455b967d02a146f5cristystatic void WriteOneChannel(const PSDInfo *psd_info,const ImageInfo *image_info,
2295a20214eef4b9c5e1797527b0a6273899a9062f9ccristy  Image *image,Image *next_image,unsigned char *compact_pixels,
2296018f07f7333b25743d0afff892450cebdb905c1acristy  const QuantumType quantum_type,const MagickBooleanType compression_flag,
2297018f07f7333b25743d0afff892450cebdb905c1acristy  ExceptionInfo *exception)
22984aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy{
22994aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy  int
23004aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy    y;
23014aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy
23020910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy  MagickBooleanType
23030910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy    monochrome;
23040910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy
23054aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy  QuantumInfo
23064aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy    *quantum_info;
23074aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy
23084c08aed51c5899665ade97263692328eea4af106cristy  register const Quantum
23094aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy    *p;
23104aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy
2311bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  register ssize_t
23120910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy    i;
23130910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy
23144aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy  size_t
23154aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy    length,
23164aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy    packet_size;
23174aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy
2318a20214eef4b9c5e1797527b0a6273899a9062f9ccristy  unsigned char
2319a20214eef4b9c5e1797527b0a6273899a9062f9ccristy    *pixels;
2320a20214eef4b9c5e1797527b0a6273899a9062f9ccristy
232150aea4a7536abc82a6877cd256987666d14d54d0cristy  (void) psd_info;
23224aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy  if ((compression_flag != MagickFalse) &&
2323a20214eef4b9c5e1797527b0a6273899a9062f9ccristy      (next_image->compression != RLECompression))
23244aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy    (void) WriteBlobMSBShort(image,0);
2325a20214eef4b9c5e1797527b0a6273899a9062f9ccristy  if (next_image->depth > 8)
2326a20214eef4b9c5e1797527b0a6273899a9062f9ccristy    next_image->depth=16;
2327a7014c80705e61fe66ccd14bfca87bfe9cffe87fdirk  monochrome=IsImageMonochrome(image) && (image->depth == 1) ?
2328c82a27bb8e3138ff9bbf0f696663bdf3e704cedecristy    MagickTrue : MagickFalse;
2329a20214eef4b9c5e1797527b0a6273899a9062f9ccristy  packet_size=next_image->depth > 8UL ? 2UL : 1UL;
2330da16f16767eb31921af855f17bda465fffc4e000cristy  (void) packet_size;
23315f766ef8b0cd9906c2c3a56d845828380a251073cristy  quantum_info=AcquireQuantumInfo(image_info,image);
2332b3f97ae45019a91b30792a6fa42d81a2689a7025cristy  pixels=(unsigned char *) GetQuantumPixels(quantum_info);
2333a20214eef4b9c5e1797527b0a6273899a9062f9ccristy  for (y=0; y < (ssize_t) next_image->rows; y++)
23343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
2335c82a27bb8e3138ff9bbf0f696663bdf3e704cedecristy    p=GetVirtualPixels(next_image,0,y,next_image->columns,1,exception);
23364c08aed51c5899665ade97263692328eea4af106cristy    if (p == (const Quantum *) NULL)
23374aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy      break;
2338a20214eef4b9c5e1797527b0a6273899a9062f9ccristy    length=ExportQuantumPixels(next_image,(CacheView *) NULL,quantum_info,
2339c82a27bb8e3138ff9bbf0f696663bdf3e704cedecristy      quantum_type,pixels,exception);
23400910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy    if (monochrome != MagickFalse)
2341bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      for (i=0; i < (ssize_t) length; i++)
23420910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy        pixels[i]=(~pixels[i]);
2343a20214eef4b9c5e1797527b0a6273899a9062f9ccristy    if (next_image->compression != RLECompression)
23444aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy      (void) WriteBlob(image,length,pixels);
23454aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy    else
23464aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy      {
2347018f07f7333b25743d0afff892450cebdb905c1acristy        length=PSDPackbitsEncodeImage(image,length,pixels,compact_pixels,
2348018f07f7333b25743d0afff892450cebdb905c1acristy          exception);
2349b1459bce38004e27d61bef953617d25747264ff4cristy        (void) WriteBlob(image,length,compact_pixels);
23504aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy      }
23513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
23523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  quantum_info=DestroyQuantumInfo(quantum_info);
23533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
23543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2355875e28af6da774727babef3e455b967d02a146f5cristystatic MagickBooleanType WriteImageChannels(const PSDInfo *psd_info,
2356a20214eef4b9c5e1797527b0a6273899a9062f9ccristy  const ImageInfo *image_info,Image *image,Image *next_image,
2357018f07f7333b25743d0afff892450cebdb905c1acristy  const MagickBooleanType separate,ExceptionInfo *exception)
23583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
23593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  size_t
23603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    channels,
23613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    packet_size;
23623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
23633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  unsigned char
2364a20214eef4b9c5e1797527b0a6273899a9062f9ccristy    *compact_pixels;
23653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
23663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
2367875e28af6da774727babef3e455b967d02a146f5cristy    Write uncompressed pixels as separate planes.
23683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
23693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  channels=1;
2370a20214eef4b9c5e1797527b0a6273899a9062f9ccristy  packet_size=next_image->depth > 8UL ? 2UL : 1UL;
2371a20214eef4b9c5e1797527b0a6273899a9062f9ccristy  compact_pixels=(unsigned char *) NULL;
2372a20214eef4b9c5e1797527b0a6273899a9062f9ccristy  if (next_image->compression == RLECompression)
23734aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy    {
2374533ea3b9047c67f9af49703de672f6c2e443f747Cristy      compact_pixels=(unsigned char *) AcquireQuantumMemory((9*channels*
23756f1879d498bcc5cce12fe0c5decb8dbc0f608e5ddirk        next_image->columns)+1,packet_size*sizeof(*compact_pixels));
2376a20214eef4b9c5e1797527b0a6273899a9062f9ccristy      if (compact_pixels == (unsigned char *) NULL)
2377a20214eef4b9c5e1797527b0a6273899a9062f9ccristy        ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
23784aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy    }
2379a7014c80705e61fe66ccd14bfca87bfe9cffe87fdirk  if (IsImageGray(next_image) != MagickFalse)
23803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
2381a20214eef4b9c5e1797527b0a6273899a9062f9ccristy      if (next_image->compression == RLECompression)
23824aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy        {
23834aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy          /*
23844aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy            Packbits compression.
23854aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy          */
23864aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy          (void) WriteBlobMSBShort(image,1);
2387a20214eef4b9c5e1797527b0a6273899a9062f9ccristy          WritePackbitsLength(psd_info,image_info,image,next_image,
2388018f07f7333b25743d0afff892450cebdb905c1acristy            compact_pixels,GrayQuantum,exception);
238917f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy          if (next_image->alpha_trait != UndefinedPixelTrait)
2390a20214eef4b9c5e1797527b0a6273899a9062f9ccristy            WritePackbitsLength(psd_info,image_info,image,next_image,
2391018f07f7333b25743d0afff892450cebdb905c1acristy              compact_pixels,AlphaQuantum,exception);
23924aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy        }
2393a20214eef4b9c5e1797527b0a6273899a9062f9ccristy      WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
2394c9e9ea32a13414a2574a54089c9b2facb6f8ea13dirk        GrayQuantum,MagickTrue,exception);
239517f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy      if (next_image->alpha_trait != UndefinedPixelTrait)
2396a20214eef4b9c5e1797527b0a6273899a9062f9ccristy        WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
2397c9e9ea32a13414a2574a54089c9b2facb6f8ea13dirk          AlphaQuantum,separate,exception);
23986886a7561ce8dffd35ccc6803665933f4e66c2d7cristy      (void) SetImageProgress(image,SaveImagesTag,0,1);
23990910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy    }
24000910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy  else
2401a20214eef4b9c5e1797527b0a6273899a9062f9ccristy    if (next_image->storage_class == PseudoClass)
24020910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy      {
2403a20214eef4b9c5e1797527b0a6273899a9062f9ccristy        if (next_image->compression == RLECompression)
24040910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy          {
24050910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy            /*
24060910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy              Packbits compression.
24070910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy            */
24080910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy            (void) WriteBlobMSBShort(image,1);
2409a20214eef4b9c5e1797527b0a6273899a9062f9ccristy            WritePackbitsLength(psd_info,image_info,image,next_image,
2410018f07f7333b25743d0afff892450cebdb905c1acristy              compact_pixels,IndexQuantum,exception);
241117f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy            if (next_image->alpha_trait != UndefinedPixelTrait)
2412a20214eef4b9c5e1797527b0a6273899a9062f9ccristy              WritePackbitsLength(psd_info,image_info,image,next_image,
2413018f07f7333b25743d0afff892450cebdb905c1acristy                compact_pixels,AlphaQuantum,exception);
24140910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy          }
2415a20214eef4b9c5e1797527b0a6273899a9062f9ccristy        WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
2416c9e9ea32a13414a2574a54089c9b2facb6f8ea13dirk          IndexQuantum,MagickTrue,exception);
241717f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy        if (next_image->alpha_trait != UndefinedPixelTrait)
2418a20214eef4b9c5e1797527b0a6273899a9062f9ccristy          WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
2419c9e9ea32a13414a2574a54089c9b2facb6f8ea13dirk            AlphaQuantum,separate,exception);
24200910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy        (void) SetImageProgress(image,SaveImagesTag,0,1);
24210910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy      }
24220910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy    else
24230910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy      {
2424a20214eef4b9c5e1797527b0a6273899a9062f9ccristy        if (next_image->colorspace == CMYKColorspace)
2425d9795a19984ae1bae9205b7c0fe5de75461978b3dirk          (void) NegateCMYK(next_image,exception);
2426a20214eef4b9c5e1797527b0a6273899a9062f9ccristy        if (next_image->compression == RLECompression)
24270910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy          {
24280910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy            /*
24290910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy              Packbits compression.
24300910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy            */
24310910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy            (void) WriteBlobMSBShort(image,1);
2432a20214eef4b9c5e1797527b0a6273899a9062f9ccristy            WritePackbitsLength(psd_info,image_info,image,next_image,
2433018f07f7333b25743d0afff892450cebdb905c1acristy              compact_pixels,RedQuantum,exception);
2434a20214eef4b9c5e1797527b0a6273899a9062f9ccristy            WritePackbitsLength(psd_info,image_info,image,next_image,
2435018f07f7333b25743d0afff892450cebdb905c1acristy              compact_pixels,GreenQuantum,exception);
2436a20214eef4b9c5e1797527b0a6273899a9062f9ccristy            WritePackbitsLength(psd_info,image_info,image,next_image,
2437018f07f7333b25743d0afff892450cebdb905c1acristy              compact_pixels,BlueQuantum,exception);
2438a20214eef4b9c5e1797527b0a6273899a9062f9ccristy            if (next_image->colorspace == CMYKColorspace)
2439a20214eef4b9c5e1797527b0a6273899a9062f9ccristy              WritePackbitsLength(psd_info,image_info,image,next_image,
2440018f07f7333b25743d0afff892450cebdb905c1acristy                compact_pixels,BlackQuantum,exception);
244117f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy            if (next_image->alpha_trait != UndefinedPixelTrait)
2442a20214eef4b9c5e1797527b0a6273899a9062f9ccristy              WritePackbitsLength(psd_info,image_info,image,next_image,
2443018f07f7333b25743d0afff892450cebdb905c1acristy                compact_pixels,AlphaQuantum,exception);
24440910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy          }
24450910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy        (void) SetImageProgress(image,SaveImagesTag,0,6);
2446a20214eef4b9c5e1797527b0a6273899a9062f9ccristy        WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
2447c9e9ea32a13414a2574a54089c9b2facb6f8ea13dirk          RedQuantum,MagickTrue,exception);
2448860cc73bed4db1b0d7e3913dabb8236a50d14e82cristy        (void) SetImageProgress(image,SaveImagesTag,1,6);
2449a20214eef4b9c5e1797527b0a6273899a9062f9ccristy        WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
2450c9e9ea32a13414a2574a54089c9b2facb6f8ea13dirk          GreenQuantum,separate,exception);
2451860cc73bed4db1b0d7e3913dabb8236a50d14e82cristy        (void) SetImageProgress(image,SaveImagesTag,2,6);
2452a20214eef4b9c5e1797527b0a6273899a9062f9ccristy        WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
2453c9e9ea32a13414a2574a54089c9b2facb6f8ea13dirk          BlueQuantum,separate,exception);
2454860cc73bed4db1b0d7e3913dabb8236a50d14e82cristy        (void) SetImageProgress(image,SaveImagesTag,3,6);
2455a20214eef4b9c5e1797527b0a6273899a9062f9ccristy        if (next_image->colorspace == CMYKColorspace)
2456a20214eef4b9c5e1797527b0a6273899a9062f9ccristy          WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
2457c9e9ea32a13414a2574a54089c9b2facb6f8ea13dirk            BlackQuantum,separate,exception);
2458860cc73bed4db1b0d7e3913dabb8236a50d14e82cristy        (void) SetImageProgress(image,SaveImagesTag,4,6);
245917f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy        if (next_image->alpha_trait != UndefinedPixelTrait)
2460a20214eef4b9c5e1797527b0a6273899a9062f9ccristy          WriteOneChannel(psd_info,image_info,image,next_image,compact_pixels,
2461c9e9ea32a13414a2574a54089c9b2facb6f8ea13dirk            AlphaQuantum,separate,exception);
24620910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy        (void) SetImageProgress(image,SaveImagesTag,5,6);
2463a20214eef4b9c5e1797527b0a6273899a9062f9ccristy        if (next_image->colorspace == CMYKColorspace)
2464d9795a19984ae1bae9205b7c0fe5de75461978b3dirk          (void) NegateCMYK(next_image,exception);
24650910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy      }
2466a20214eef4b9c5e1797527b0a6273899a9062f9ccristy  if (next_image->compression == RLECompression)
2467a20214eef4b9c5e1797527b0a6273899a9062f9ccristy    compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
24683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(MagickTrue);
24693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
24703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
24713ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic void WritePascalString(Image* inImage,const char *inString,int inPad)
24723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
24733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  size_t
2474a20214eef4b9c5e1797527b0a6273899a9062f9ccristy    length;
24753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2476a20214eef4b9c5e1797527b0a6273899a9062f9ccristy  register ssize_t
2477a20214eef4b9c5e1797527b0a6273899a9062f9ccristy    i;
24783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2479a20214eef4b9c5e1797527b0a6273899a9062f9ccristy  /*
2480a20214eef4b9c5e1797527b0a6273899a9062f9ccristy    Max length is 255.
2481a20214eef4b9c5e1797527b0a6273899a9062f9ccristy  */
2482a20214eef4b9c5e1797527b0a6273899a9062f9ccristy  length=(strlen(inString) > 255UL ) ? 255UL : strlen(inString);
2483a20214eef4b9c5e1797527b0a6273899a9062f9ccristy  if (length ==  0)
2484a20214eef4b9c5e1797527b0a6273899a9062f9ccristy    (void) WriteBlobByte(inImage,0);
24853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  else
2486a20214eef4b9c5e1797527b0a6273899a9062f9ccristy    {
2487a20214eef4b9c5e1797527b0a6273899a9062f9ccristy      (void) WriteBlobByte(inImage,(unsigned char) length);
2488a20214eef4b9c5e1797527b0a6273899a9062f9ccristy      (void) WriteBlob(inImage, length, (const unsigned char *) inString);
2489a20214eef4b9c5e1797527b0a6273899a9062f9ccristy    }
2490a20214eef4b9c5e1797527b0a6273899a9062f9ccristy  length++;
2491a20214eef4b9c5e1797527b0a6273899a9062f9ccristy  if ((length % inPad) == 0)
24923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return;
2493a20214eef4b9c5e1797527b0a6273899a9062f9ccristy  for (i=0; i < (ssize_t) (inPad-(length % inPad)); i++)
24943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) WriteBlobByte(inImage,0);
24953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
24963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
24973ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic void WriteResolutionResourceBlock(Image *image)
24983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
249956ed31cc763800a9fb1f0df96104c354b40d2cbccristy  double
250056ed31cc763800a9fb1f0df96104c354b40d2cbccristy    x_resolution,
250156ed31cc763800a9fb1f0df96104c354b40d2cbccristy    y_resolution;
25023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
25033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  unsigned short
25043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    units;
25053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
25063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (image->units == PixelsPerCentimeterResolution)
25073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
250887dabf6eb2a2d342eb36a734809075fa19cb5778dirk      x_resolution=2.54*65536.0*image->resolution.x+0.5;
25092a11befa48257796843468409d77bb8cfb129cdccristy      y_resolution=2.54*65536.0*image->resolution.y+0.5;
25103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      units=2;
25113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
251287dabf6eb2a2d342eb36a734809075fa19cb5778dirk  else
251387dabf6eb2a2d342eb36a734809075fa19cb5778dirk    {
251487dabf6eb2a2d342eb36a734809075fa19cb5778dirk      x_resolution=65536.0*image->resolution.x+0.5;
251587dabf6eb2a2d342eb36a734809075fa19cb5778dirk      y_resolution=65536.0*image->resolution.y+0.5;
251687dabf6eb2a2d342eb36a734809075fa19cb5778dirk      units=1;
251787dabf6eb2a2d342eb36a734809075fa19cb5778dirk    }
25183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
25193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) WriteBlobMSBShort(image,0x03ED);
25203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) WriteBlobMSBShort(image,0);
25213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) WriteBlobMSBLong(image,16); /* resource size */
252256ed31cc763800a9fb1f0df96104c354b40d2cbccristy  (void) WriteBlobMSBLong(image,(unsigned int) (x_resolution+0.5));
25233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) WriteBlobMSBShort(image,units); /* horizontal resolution unit */
25243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) WriteBlobMSBShort(image,units); /* width unit */
252556ed31cc763800a9fb1f0df96104c354b40d2cbccristy  (void) WriteBlobMSBLong(image,(unsigned int) (y_resolution+0.5));
25263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) WriteBlobMSBShort(image,units); /* vertical resolution unit */
25273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) WriteBlobMSBShort(image,units); /* height unit */
25283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
25293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2530d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristystatic void RemoveICCProfileFromResourceBlock(StringInfo *bim_profile)
2531d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy{
25320b796e6c8c90cf5ec9e6a295504220d055c9e0a6cristy  register const unsigned char
2533d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy    *p;
2534d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy
2535d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy  size_t
2536d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy    length;
2537d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy
2538d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy  unsigned char
2539d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy    *datum;
2540d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy
25416befb0f8f253ef359d1e14d1e569c1a848d02daccristy  unsigned int
2542d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy    count,
25436befb0f8f253ef359d1e14d1e569c1a848d02daccristy    long_sans;
2544d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy
2545d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy  unsigned short
2546d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy    id,
2547d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy    short_sans;
2548d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy
2549d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy  length=GetStringInfoLength(bim_profile);
2550d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy  if (length < 16)
25510b796e6c8c90cf5ec9e6a295504220d055c9e0a6cristy    return;
2552d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy  datum=GetStringInfoDatum(bim_profile);
2553d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy  for (p=datum; (p >= datum) && (p < (datum+length-16)); )
2554d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy  {
25554176bb21071b87cc8a0d0867db402999db941569cristy    register unsigned char
25564176bb21071b87cc8a0d0867db402999db941569cristy      *q;
25574176bb21071b87cc8a0d0867db402999db941569cristy
25584176bb21071b87cc8a0d0867db402999db941569cristy    q=(unsigned char *) p;
2559d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy    if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
2560d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy      break;
25616befb0f8f253ef359d1e14d1e569c1a848d02daccristy    p=PushLongPixel(MSBEndian,p,&long_sans);
2562d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy    p=PushShortPixel(MSBEndian,p,&id);
2563d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy    p=PushShortPixel(MSBEndian,p,&short_sans);
2564d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy    p=PushLongPixel(MSBEndian,p,&count);
2565d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy    if (id == 0x0000040f)
2566d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy      {
25674812e816a9c3da93003aaea1d0b1db9ccf8ce40ddirk        ssize_t
25684812e816a9c3da93003aaea1d0b1db9ccf8ce40ddirk          quantum;
25694812e816a9c3da93003aaea1d0b1db9ccf8ce40ddirk
25704812e816a9c3da93003aaea1d0b1db9ccf8ce40ddirk        quantum=PSDQuantum(count)+12;
25714812e816a9c3da93003aaea1d0b1db9ccf8ce40ddirk        if ((quantum >= 12) && (q+quantum < (datum+length-16)))
257282e2049862a8b8a999e160734ad64fb6cc3b145fCristy          {
25734812e816a9c3da93003aaea1d0b1db9ccf8ce40ddirk            (void) CopyMagickMemory(q,q+quantum,length-quantum-(q-datum));
25744812e816a9c3da93003aaea1d0b1db9ccf8ce40ddirk            SetStringInfoLength(bim_profile,length-quantum);
257582e2049862a8b8a999e160734ad64fb6cc3b145fCristy          }
2576d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy        break;
2577d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy      }
2578d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy    p+=count;
2579d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy    if ((count & 0x01) != 0)
2580d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy      p++;
2581d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy  }
2582d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy}
2583d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy
2584f11065e08c32a2c6a82e67ade789e83936724a8ecristystatic void RemoveResolutionFromResourceBlock(StringInfo *bim_profile)
2585f11065e08c32a2c6a82e67ade789e83936724a8ecristy{
2586f11065e08c32a2c6a82e67ade789e83936724a8ecristy  register const unsigned char
2587f11065e08c32a2c6a82e67ade789e83936724a8ecristy    *p;
2588f11065e08c32a2c6a82e67ade789e83936724a8ecristy
2589f11065e08c32a2c6a82e67ade789e83936724a8ecristy  size_t
2590f11065e08c32a2c6a82e67ade789e83936724a8ecristy    length;
2591f11065e08c32a2c6a82e67ade789e83936724a8ecristy
2592f11065e08c32a2c6a82e67ade789e83936724a8ecristy  unsigned char
2593f11065e08c32a2c6a82e67ade789e83936724a8ecristy    *datum;
2594f11065e08c32a2c6a82e67ade789e83936724a8ecristy
25956befb0f8f253ef359d1e14d1e569c1a848d02daccristy  unsigned int
2596f11065e08c32a2c6a82e67ade789e83936724a8ecristy    count,
25976befb0f8f253ef359d1e14d1e569c1a848d02daccristy    long_sans;
2598f11065e08c32a2c6a82e67ade789e83936724a8ecristy
2599f11065e08c32a2c6a82e67ade789e83936724a8ecristy  unsigned short
2600f11065e08c32a2c6a82e67ade789e83936724a8ecristy    id,
2601f11065e08c32a2c6a82e67ade789e83936724a8ecristy    short_sans;
2602f11065e08c32a2c6a82e67ade789e83936724a8ecristy
2603f11065e08c32a2c6a82e67ade789e83936724a8ecristy  length=GetStringInfoLength(bim_profile);
2604f11065e08c32a2c6a82e67ade789e83936724a8ecristy  if (length < 16)
2605f11065e08c32a2c6a82e67ade789e83936724a8ecristy    return;
2606f11065e08c32a2c6a82e67ade789e83936724a8ecristy  datum=GetStringInfoDatum(bim_profile);
2607f11065e08c32a2c6a82e67ade789e83936724a8ecristy  for (p=datum; (p >= datum) && (p < (datum+length-16)); )
2608f11065e08c32a2c6a82e67ade789e83936724a8ecristy  {
2609f11065e08c32a2c6a82e67ade789e83936724a8ecristy    register unsigned char
2610f11065e08c32a2c6a82e67ade789e83936724a8ecristy      *q;
2611f11065e08c32a2c6a82e67ade789e83936724a8ecristy
26124f2c04ea6673863b87ac7f186cbb0d911f74085cdirk    ssize_t
26134f2c04ea6673863b87ac7f186cbb0d911f74085cdirk      cnt;
26144f2c04ea6673863b87ac7f186cbb0d911f74085cdirk
2615f11065e08c32a2c6a82e67ade789e83936724a8ecristy    q=(unsigned char *) p;
2616f11065e08c32a2c6a82e67ade789e83936724a8ecristy    if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
26174f2c04ea6673863b87ac7f186cbb0d911f74085cdirk      return;
26186befb0f8f253ef359d1e14d1e569c1a848d02daccristy    p=PushLongPixel(MSBEndian,p,&long_sans);
2619f11065e08c32a2c6a82e67ade789e83936724a8ecristy    p=PushShortPixel(MSBEndian,p,&id);
2620f11065e08c32a2c6a82e67ade789e83936724a8ecristy    p=PushShortPixel(MSBEndian,p,&short_sans);
2621f11065e08c32a2c6a82e67ade789e83936724a8ecristy    p=PushLongPixel(MSBEndian,p,&count);
26224f2c04ea6673863b87ac7f186cbb0d911f74085cdirk    cnt=PSDQuantum(count);
26234f2c04ea6673863b87ac7f186cbb0d911f74085cdirk    if (cnt < 0)
26244f2c04ea6673863b87ac7f186cbb0d911f74085cdirk      return;
26254f2c04ea6673863b87ac7f186cbb0d911f74085cdirk    if ((id == 0x000003ed) && (cnt < (ssize_t) (length-12)))
2626f11065e08c32a2c6a82e67ade789e83936724a8ecristy      {
26274f2c04ea6673863b87ac7f186cbb0d911f74085cdirk        (void) CopyMagickMemory(q,q+cnt+12,length-(cnt+12)-(q-datum));
26284f2c04ea6673863b87ac7f186cbb0d911f74085cdirk        SetStringInfoLength(bim_profile,length-(cnt+12));
2629f11065e08c32a2c6a82e67ade789e83936724a8ecristy        break;
2630f11065e08c32a2c6a82e67ade789e83936724a8ecristy      }
2631f11065e08c32a2c6a82e67ade789e83936724a8ecristy    p+=count;
2632f11065e08c32a2c6a82e67ade789e83936724a8ecristy    if ((count & 0x01) != 0)
2633f11065e08c32a2c6a82e67ade789e83936724a8ecristy      p++;
2634f11065e08c32a2c6a82e67ade789e83936724a8ecristy  }
2635f11065e08c32a2c6a82e67ade789e83936724a8ecristy}
2636f11065e08c32a2c6a82e67ade789e83936724a8ecristy
26374f2c04ea6673863b87ac7f186cbb0d911f74085cdirkstatic MagickBooleanType WritePSDImage(const ImageInfo *image_info,
26384f2c04ea6673863b87ac7f186cbb0d911f74085cdirk  Image *image,ExceptionInfo *exception)
26393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
26403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  const char
2641a20214eef4b9c5e1797527b0a6273899a9062f9ccristy    *property;
26423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
26433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  const StringInfo
2644749d215867cacb414d8d675c4fc532cc25b473aecristy    *icc_profile;
26453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2646a20214eef4b9c5e1797527b0a6273899a9062f9ccristy  Image
2647a20214eef4b9c5e1797527b0a6273899a9062f9ccristy    *base_image,
2648a20214eef4b9c5e1797527b0a6273899a9062f9ccristy    *next_image;
2649a20214eef4b9c5e1797527b0a6273899a9062f9ccristy
26503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
26513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status;
26523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2653875e28af6da774727babef3e455b967d02a146f5cristy  PSDInfo
2654875e28af6da774727babef3e455b967d02a146f5cristy    psd_info;
2655875e28af6da774727babef3e455b967d02a146f5cristy
2656bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  register ssize_t
26573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    i;
26583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
26593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  size_t
2660a20214eef4b9c5e1797527b0a6273899a9062f9ccristy    channel_size,
2661a20214eef4b9c5e1797527b0a6273899a9062f9ccristy    channelLength,
2662a20214eef4b9c5e1797527b0a6273899a9062f9ccristy    layer_count,
2663a20214eef4b9c5e1797527b0a6273899a9062f9ccristy    layer_info_size,
2664749d215867cacb414d8d675c4fc532cc25b473aecristy    length,
26653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    num_channels,
2666a20214eef4b9c5e1797527b0a6273899a9062f9ccristy    packet_size,
2667a20214eef4b9c5e1797527b0a6273899a9062f9ccristy    rounded_layer_info_size;
26683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
26690b796e6c8c90cf5ec9e6a295504220d055c9e0a6cristy  StringInfo
26700b796e6c8c90cf5ec9e6a295504220d055c9e0a6cristy    *bim_profile;
26710b796e6c8c90cf5ec9e6a295504220d055c9e0a6cristy
26723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
267356ed31cc763800a9fb1f0df96104c354b40d2cbccristy    Open image file.
26743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
26753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(image_info != (const ImageInfo *) NULL);
2676e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(image_info->signature == MagickCoreSignature);
26773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(image != (Image *) NULL);
2678e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(image->signature == MagickCoreSignature);
26793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (image->debug != MagickFalse)
26803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
26813a37efd7ece979e9c63dc8f2f2d3816bab8b1156cristy  assert(exception != (ExceptionInfo *) NULL);
2682e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(exception->signature == MagickCoreSignature);
26833a37efd7ece979e9c63dc8f2f2d3816bab8b1156cristy  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
26843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (status == MagickFalse)
26853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(status);
26863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  packet_size=(size_t) (image->depth > 8 ? 6 : 3);
268717f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy  if (image->alpha_trait != UndefinedPixelTrait)
26883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    packet_size+=image->depth > 8 ? 2 : 1;
2689875e28af6da774727babef3e455b967d02a146f5cristy  psd_info.version=1;
2690875e28af6da774727babef3e455b967d02a146f5cristy  if ((LocaleCompare(image_info->magick,"PSB") == 0) ||
2691875e28af6da774727babef3e455b967d02a146f5cristy      (image->columns > 30000) || (image->rows > 30000))
2692875e28af6da774727babef3e455b967d02a146f5cristy    psd_info.version=2;
269350aea4a7536abc82a6877cd256987666d14d54d0cristy  (void) WriteBlob(image,4,(const unsigned char *) "8BPS");
2694875e28af6da774727babef3e455b967d02a146f5cristy  (void) WriteBlobMSBShort(image,psd_info.version);  /* version */
2695875e28af6da774727babef3e455b967d02a146f5cristy  for (i=1; i <= 6; i++)
2696875e28af6da774727babef3e455b967d02a146f5cristy    (void) WriteBlobByte(image, 0);  /* 6 bytes of reserved */
2697f4be669d7182ed9b584a71897c0e05e98fe074d0dirk  if (SetImageGray(image,exception) != MagickFalse)
269817f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy    num_channels=(image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL);
26993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  else
2700e1f8f29cea243595203167f070a0f1a193e45c67dirk    if ((image_info->type != TrueColorType) && (image_info->type !=
2701e1f8f29cea243595203167f070a0f1a193e45c67dirk         TrueColorAlphaType) && (image->storage_class == PseudoClass))
270217f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy      num_channels=(image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL);
27030910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy    else
27040910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy      {
2705e1f8f29cea243595203167f070a0f1a193e45c67dirk        if (image->storage_class == PseudoClass)
2706e1f8f29cea243595203167f070a0f1a193e45c67dirk          (void) SetImageStorageClass(image,DirectClass,exception);
27070910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy        if (image->colorspace != CMYKColorspace)
270817f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy          num_channels=(image->alpha_trait != UndefinedPixelTrait ? 4UL : 3UL);
27090910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy        else
271017f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy          num_channels=(image->alpha_trait != UndefinedPixelTrait ? 5UL : 4UL);
27110910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy      }
27123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) WriteBlobMSBShort(image,(unsigned short) num_channels);
271356ed31cc763800a9fb1f0df96104c354b40d2cbccristy  (void) WriteBlobMSBLong(image,(unsigned int) image->rows);
271456ed31cc763800a9fb1f0df96104c354b40d2cbccristy  (void) WriteBlobMSBLong(image,(unsigned int) image->columns);
2715a7014c80705e61fe66ccd14bfca87bfe9cffe87fdirk  if (IsImageGray(image) != MagickFalse)
27163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
27172045da39100ca0b2ebba13a936c20cad331109a2cristy      MagickBooleanType
27182045da39100ca0b2ebba13a936c20cad331109a2cristy        monochrome;
27192045da39100ca0b2ebba13a936c20cad331109a2cristy
27200910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy      /*
27210910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy        Write depth & mode.
27220910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy      */
2723a7014c80705e61fe66ccd14bfca87bfe9cffe87fdirk      monochrome=IsImageMonochrome(image) && (image->depth == 1) ?
27243a37efd7ece979e9c63dc8f2f2d3816bab8b1156cristy        MagickTrue : MagickFalse;
2725284c7d8f94022fc8106d28e9659bd4e4ff2154ffcristy      (void) WriteBlobMSBShort(image,(unsigned short)
2726284c7d8f94022fc8106d28e9659bd4e4ff2154ffcristy        (monochrome != MagickFalse ? 1 : image->depth > 8 ? 16 : 8));
27272b9582a27910c7baaeb04b7e969638328fa70095cristy      (void) WriteBlobMSBShort(image,(unsigned short)
27282b9582a27910c7baaeb04b7e969638328fa70095cristy        (monochrome != MagickFalse ? BitmapMode : GrayscaleMode));
27293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
27303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  else
27313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
2732a20214eef4b9c5e1797527b0a6273899a9062f9ccristy      (void) WriteBlobMSBShort(image,(unsigned short) (image->storage_class ==
2733a20214eef4b9c5e1797527b0a6273899a9062f9ccristy        PseudoClass ? 8 : image->depth > 8 ? 16 : 8));
273487dabf6eb2a2d342eb36a734809075fa19cb5778dirk
27354884539133c16f7f3eba25e60eea5c92d4cecbdacristy      if (((image_info->colorspace != UndefinedColorspace) ||
27360910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy           (image->colorspace != CMYKColorspace)) &&
27374884539133c16f7f3eba25e60eea5c92d4cecbdacristy          (image_info->colorspace != CMYKColorspace))
27380910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy        {
2739af8d391906d11f0a1f2bbf4e2adbc4995c852d33cristy          (void) TransformImageColorspace(image,sRGBColorspace,exception);
27400910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy          (void) WriteBlobMSBShort(image,(unsigned short)
27412045da39100ca0b2ebba13a936c20cad331109a2cristy            (image->storage_class == PseudoClass ? IndexedMode : RGBMode));
27420910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy        }
27430910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy      else
27440910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy        {
27454884539133c16f7f3eba25e60eea5c92d4cecbdacristy          if (image->colorspace != CMYKColorspace)
2746e941a75fe8bf344bc5c06a7f74bb5173c87db115cristy            (void) TransformImageColorspace(image,CMYKColorspace,exception);
27472045da39100ca0b2ebba13a936c20cad331109a2cristy          (void) WriteBlobMSBShort(image,CMYKMode);
27480910f24d34e1f8b06dc47ed189a1dde40c6eac83cristy        }
27493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
2750a7014c80705e61fe66ccd14bfca87bfe9cffe87fdirk  if ((IsImageGray(image) != MagickFalse) ||
2751ca9ddb09fab00b5f9769a42eba261eca7974f2abcristy      (image->storage_class == DirectClass) || (image->colors > 256))
27523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) WriteBlobMSBLong(image,0);
27533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  else
27543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
27553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /*
27563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        Write PSD raster colormap.
27573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      */
27583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (void) WriteBlobMSBLong(image,768);
2759bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      for (i=0; i < (ssize_t) image->colors; i++)
27603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        (void) WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].red));
27613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      for ( ; i < 256; i++)
27623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        (void) WriteBlobByte(image,0);
2763bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      for (i=0; i < (ssize_t) image->colors; i++)
2764a20214eef4b9c5e1797527b0a6273899a9062f9ccristy        (void) WriteBlobByte(image,ScaleQuantumToChar(
2765a20214eef4b9c5e1797527b0a6273899a9062f9ccristy          image->colormap[i].green));
27663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      for ( ; i < 256; i++)
27673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        (void) WriteBlobByte(image,0);
2768bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      for (i=0; i < (ssize_t) image->colors; i++)
27693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        (void) WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].blue));
27703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      for ( ; i < 256; i++)
27713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        (void) WriteBlobByte(image,0);
27723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
27733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
27743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Image resource block.
27753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
2776749d215867cacb414d8d675c4fc532cc25b473aecristy  length=28; /* 0x03EB */
27770b796e6c8c90cf5ec9e6a295504220d055c9e0a6cristy  bim_profile=(StringInfo *) GetImageProfile(image,"8bim");
2778749d215867cacb414d8d675c4fc532cc25b473aecristy  icc_profile=GetImageProfile(image,"icc");
2779d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy  if (bim_profile != (StringInfo *) NULL)
2780416dbd5933171784acf1f262219d9fdc5bae2342cristy    {
27810b796e6c8c90cf5ec9e6a295504220d055c9e0a6cristy      bim_profile=CloneStringInfo(bim_profile);
2782d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy      if (icc_profile != (StringInfo *) NULL)
2783d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy        RemoveICCProfileFromResourceBlock(bim_profile);
2784f11065e08c32a2c6a82e67ade789e83936724a8ecristy      RemoveResolutionFromResourceBlock(bim_profile);
2785d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy      length+=PSDQuantum(GetStringInfoLength(bim_profile));
2786416dbd5933171784acf1f262219d9fdc5bae2342cristy    }
27870b796e6c8c90cf5ec9e6a295504220d055c9e0a6cristy  if (icc_profile != (const StringInfo *) NULL)
2788d4d3f74b0a58d6fcab96da6e943c4755810db3f5cristy    length+=PSDQuantum(GetStringInfoLength(icc_profile))+12;
2789284c7d8f94022fc8106d28e9659bd4e4ff2154ffcristy  (void) WriteBlobMSBLong(image,(unsigned int) length);
2790f11065e08c32a2c6a82e67ade789e83936724a8ecristy  WriteResolutionResourceBlock(image);
27914176bb21071b87cc8a0d0867db402999db941569cristy  if (bim_profile != (StringInfo *) NULL)
27924176bb21071b87cc8a0d0867db402999db941569cristy    {
27934176bb21071b87cc8a0d0867db402999db941569cristy      (void) WriteBlob(image,GetStringInfoLength(bim_profile),
27944176bb21071b87cc8a0d0867db402999db941569cristy        GetStringInfoDatum(bim_profile));
27954176bb21071b87cc8a0d0867db402999db941569cristy      bim_profile=DestroyStringInfo(bim_profile);
27964176bb21071b87cc8a0d0867db402999db941569cristy    }
2797749d215867cacb414d8d675c4fc532cc25b473aecristy  if (icc_profile != (StringInfo *) NULL)
2798e636559dfadfdb115cc93f223315052a1ee89238cristy    {
2799749d215867cacb414d8d675c4fc532cc25b473aecristy      (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
28004176bb21071b87cc8a0d0867db402999db941569cristy      (void) WriteBlobMSBShort(image,0x0000040F);
2801749d215867cacb414d8d675c4fc532cc25b473aecristy      (void) WriteBlobMSBShort(image,0);
2802284c7d8f94022fc8106d28e9659bd4e4ff2154ffcristy      (void) WriteBlobMSBLong(image,(unsigned int) GetStringInfoLength(
2803284c7d8f94022fc8106d28e9659bd4e4ff2154ffcristy        icc_profile));
2804749d215867cacb414d8d675c4fc532cc25b473aecristy      (void) WriteBlob(image,GetStringInfoLength(icc_profile),
2805749d215867cacb414d8d675c4fc532cc25b473aecristy        GetStringInfoDatum(icc_profile));
2806e195f269ded3cc73598398d43649ad5adca19e44cristy      if ((MagickOffsetType) GetStringInfoLength(icc_profile) !=
28072045da39100ca0b2ebba13a936c20cad331109a2cristy          PSDQuantum(GetStringInfoLength(icc_profile)))
2808749d215867cacb414d8d675c4fc532cc25b473aecristy        (void) WriteBlobByte(image,0);
2809e636559dfadfdb115cc93f223315052a1ee89238cristy    }
28104884539133c16f7f3eba25e60eea5c92d4cecbdacristy  layer_count=0;
28114884539133c16f7f3eba25e60eea5c92d4cecbdacristy  layer_info_size=2;
28122837bcc0d895233e6d0034f88c5e86c15564bd1acristy  base_image=GetNextImageInList(image);
2813332ee36cfe05c954c18d72184dc690a57b0c9c8bdirk  if (base_image == (Image *) NULL)
28142837bcc0d895233e6d0034f88c5e86c15564bd1acristy    base_image=image;
2815a20214eef4b9c5e1797527b0a6273899a9062f9ccristy  next_image=base_image;
2816332ee36cfe05c954c18d72184dc690a57b0c9c8bdirk  while (next_image != (Image *) NULL)
2817a20214eef4b9c5e1797527b0a6273899a9062f9ccristy  {
2818a20214eef4b9c5e1797527b0a6273899a9062f9ccristy    packet_size=next_image->depth > 8 ? 2UL : 1UL;
2819a7014c80705e61fe66ccd14bfca87bfe9cffe87fdirk    if (IsImageGray(next_image) != MagickFalse)
282017f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy      num_channels=next_image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL;
28213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    else
2822a20214eef4b9c5e1797527b0a6273899a9062f9ccristy      if (next_image->storage_class == PseudoClass)
282317f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy        num_channels=next_image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL;
28242045da39100ca0b2ebba13a936c20cad331109a2cristy      else
2825a20214eef4b9c5e1797527b0a6273899a9062f9ccristy        if (next_image->colorspace != CMYKColorspace)
282617f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy          num_channels=next_image->alpha_trait != UndefinedPixelTrait ? 4UL : 3UL;
28272045da39100ca0b2ebba13a936c20cad331109a2cristy        else
282817f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy          num_channels=next_image->alpha_trait != UndefinedPixelTrait ? 5UL : 4UL;
2829a20214eef4b9c5e1797527b0a6273899a9062f9ccristy    channelLength=(size_t) (next_image->columns*next_image->rows*packet_size+2);
28304884539133c16f7f3eba25e60eea5c92d4cecbdacristy    layer_info_size+=(size_t) (4*4+2+num_channels*6+(psd_info.version == 1 ? 8 :
28314884539133c16f7f3eba25e60eea5c92d4cecbdacristy      16)+4*1+4+num_channels*channelLength);
2832d15e65928aec551b7388c2863de3e3e628e2e0ddcristy    property=(const char *) GetImageProperty(next_image,"label",exception);
2833a20214eef4b9c5e1797527b0a6273899a9062f9ccristy    if (property == (const char *) NULL)
2834a20214eef4b9c5e1797527b0a6273899a9062f9ccristy      layer_info_size+=16;
2835de9b8f5fafbde437b76e3cc037ae5ad481b01906cristy    else
2836de9b8f5fafbde437b76e3cc037ae5ad481b01906cristy      {
2837a20214eef4b9c5e1797527b0a6273899a9062f9ccristy        size_t
2838c93932ae0fce511e693d0cf9b969af16a3e50175dirk          layer_length;
2839a20214eef4b9c5e1797527b0a6273899a9062f9ccristy
2840c93932ae0fce511e693d0cf9b969af16a3e50175dirk        layer_length=strlen(property);
2841c93932ae0fce511e693d0cf9b969af16a3e50175dirk        layer_info_size+=8+layer_length+(4-(layer_length % 4));
2842de9b8f5fafbde437b76e3cc037ae5ad481b01906cristy      }
28434aff1576adab1eae438d2d5b3ac2dde8418ccba8cristy    layer_count++;
2844a20214eef4b9c5e1797527b0a6273899a9062f9ccristy    next_image=GetNextImageInList(next_image);
28453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
2846144f1b6af9d28fe66ee98ffd9fd1233bd55a45dacristy  if (layer_count == 0)
2847875e28af6da774727babef3e455b967d02a146f5cristy    (void) SetPSDSize(&psd_info,image,0);
28483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  else
2849a20214eef4b9c5e1797527b0a6273899a9062f9ccristy    {
28508e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy      CompressionType
28518e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy        compression;
28528e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy
28538e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy      (void) SetPSDSize(&psd_info,image,layer_info_size+
28548e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy        (psd_info.version == 1 ? 8 : 16));
28558e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy      if ((layer_info_size/2) != ((layer_info_size+1)/2))
28568e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy        rounded_layer_info_size=layer_info_size+1;
28578e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy      else
28588e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy        rounded_layer_info_size=layer_info_size;
28598e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy      (void) SetPSDSize(&psd_info,image,rounded_layer_info_size);
28601730317bbf49f1aea1dea206578f9f319ad98f8edirk      if (image->alpha_trait != UndefinedPixelTrait)
28618fb7ed503852cf10e782ef6b8bf24436ca83e3bbdirk        (void) WriteBlobMSBShort(image,-(unsigned short) layer_count);
28628fb7ed503852cf10e782ef6b8bf24436ca83e3bbdirk      else
28638fb7ed503852cf10e782ef6b8bf24436ca83e3bbdirk        (void) WriteBlobMSBShort(image,(unsigned short) layer_count);
28648e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy      layer_count=1;
28658e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy      compression=base_image->compression;
2866f2a82ee6e25411cb280db708ff26ab55cece1945cristy      for (next_image=base_image; next_image != NULL; )
28678e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy      {
28688e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy        next_image->compression=NoCompression;
2869a4e5f47ec63e62952af27cc1f0d4ece75e2db3a6cristy        (void) WriteBlobMSBLong(image,(unsigned int) next_image->page.y);
2870a4e5f47ec63e62952af27cc1f0d4ece75e2db3a6cristy        (void) WriteBlobMSBLong(image,(unsigned int) next_image->page.x);
28710e274112f2ad0a61de63adfc11e3e78038d55231cristy        (void) WriteBlobMSBLong(image,(unsigned int) (next_image->page.y+
28720e274112f2ad0a61de63adfc11e3e78038d55231cristy          next_image->rows));
28730e274112f2ad0a61de63adfc11e3e78038d55231cristy        (void) WriteBlobMSBLong(image,(unsigned int) (next_image->page.x+
28740e274112f2ad0a61de63adfc11e3e78038d55231cristy          next_image->columns));
28758e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy        packet_size=next_image->depth > 8 ? 2UL : 1UL;
28768e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy        channel_size=(unsigned int) ((packet_size*next_image->rows*
28778e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy          next_image->columns)+2);
2878a7014c80705e61fe66ccd14bfca87bfe9cffe87fdirk        if ((IsImageGray(next_image) != MagickFalse) ||
28798e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy            (next_image->storage_class == PseudoClass))
28808e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy          {
2881a20214eef4b9c5e1797527b0a6273899a9062f9ccristy             (void) WriteBlobMSBShort(image,(unsigned short)
288217f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy               (next_image->alpha_trait != UndefinedPixelTrait ? 2 : 1));
2883a20214eef4b9c5e1797527b0a6273899a9062f9ccristy             (void) WriteBlobMSBShort(image,0);
2884a20214eef4b9c5e1797527b0a6273899a9062f9ccristy             (void) SetPSDSize(&psd_info,image,channel_size);
288517f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy             if (next_image->alpha_trait != UndefinedPixelTrait)
2886a20214eef4b9c5e1797527b0a6273899a9062f9ccristy               {
2887a20214eef4b9c5e1797527b0a6273899a9062f9ccristy                 (void) WriteBlobMSBShort(image,(unsigned short) -1);
2888a20214eef4b9c5e1797527b0a6273899a9062f9ccristy                 (void) SetPSDSize(&psd_info,image,channel_size);
2889a20214eef4b9c5e1797527b0a6273899a9062f9ccristy               }
2890a20214eef4b9c5e1797527b0a6273899a9062f9ccristy           }
28918e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy          else
28928e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy            if (next_image->colorspace != CMYKColorspace)
28938e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy              {
28948e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy                (void) WriteBlobMSBShort(image,(unsigned short)
289517f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy                  (next_image->alpha_trait != UndefinedPixelTrait ? 4 : 3));
28968e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy               (void) WriteBlobMSBShort(image,0);
28978e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy               (void) SetPSDSize(&psd_info,image,channel_size);
28988e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy               (void) WriteBlobMSBShort(image,1);
28998e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy               (void) SetPSDSize(&psd_info,image,channel_size);
29008e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy               (void) WriteBlobMSBShort(image,2);
29018e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy               (void) SetPSDSize(&psd_info,image,channel_size);
290217f11b056210f082a6d0e54ac5d68e6d72fa76b2cristy               if (next_image->alpha_trait != UndefinedPixelTrait)
29038e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy                 {
29048e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy                   (void) WriteBlobMSBShort(image,(unsigned short) -1);
29058e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy                   (void) SetPSDSize(&psd_info,image,channel_size);
29068e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy                 }
29078e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy             }
29088e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy           else
29098e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy             {
29108e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy               (void) WriteBlobMSBShort(image,(unsigned short)
29118a46d827a124555f0c48fb2368ec1bba8e079ab6cristy                 (next_image->alpha_trait ? 5 : 4));
29128e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy               (void) WriteBlobMSBShort(image,0);
29138e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy               (void) SetPSDSize(&psd_info,image,channel_size);
29148e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy               (void) WriteBlobMSBShort(image,1);
29158e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy               (void) SetPSDSize(&psd_info,image,channel_size);
29168e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy               (void) WriteBlobMSBShort(image,2);
29178e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy               (void) SetPSDSize(&psd_info,image,channel_size);
29188e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy               (void) WriteBlobMSBShort(image,3);
29198e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy               (void) SetPSDSize(&psd_info,image,channel_size);
29208a46d827a124555f0c48fb2368ec1bba8e079ab6cristy               if (next_image->alpha_trait)
29218e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy                 {
29228e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy                   (void) WriteBlobMSBShort(image,(unsigned short) -1);
29238e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy                   (void) SetPSDSize(&psd_info,image,channel_size);
29248e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy                 }
29258e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy             }
29268e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy        (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
29278e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy        (void) WriteBlob(image,4,(const unsigned char *)
29288e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy          CompositeOperatorToPSDBlendMode(next_image->compose));
29298e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy        (void) WriteBlobByte(image,255); /* layer opacity */
29308e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy        (void) WriteBlobByte(image,0);
293148febd6e7503d789df337420cf150dfbb49726b5dirk        (void) WriteBlobByte(image,next_image->compose==NoCompositeOp ?
293248febd6e7503d789df337420cf150dfbb49726b5dirk          1 << 0x02 : 1); /* layer properties - visible, etc. */
29338e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy        (void) WriteBlobByte(image,0);
2934d15e65928aec551b7388c2863de3e3e628e2e0ddcristy        property=(const char *) GetImageProperty(next_image,"label",exception);
29358e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy        if (property == (const char *) NULL)
29368e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy          {
293793b02b797c4127ce2b06dbd3b2d75ecc33fca759dirk            char
2938151b66dffc9e3c2e8c4f8cdaca37ff987ca0f497cristy              layer_name[MagickPathExtent];
29397a1ce136b85a452a6c38798bd7ece426eb48f2f9cristy
29408e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy            (void) WriteBlobMSBLong(image,16);
29418e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy            (void) WriteBlobMSBLong(image,0);
29428e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy            (void) WriteBlobMSBLong(image,0);
2943151b66dffc9e3c2e8c4f8cdaca37ff987ca0f497cristy            (void) FormatLocaleString(layer_name,MagickPathExtent,"L%04ld",(long)
29447a1ce136b85a452a6c38798bd7ece426eb48f2f9cristy              layer_count++);
29457a1ce136b85a452a6c38798bd7ece426eb48f2f9cristy            WritePascalString(image,layer_name,4);
29468e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy          }
29478e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy        else
29488e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy          {
29498e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy            size_t
2950c93932ae0fce511e693d0cf9b969af16a3e50175dirk              label_length;
29518e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy
2952c93932ae0fce511e693d0cf9b969af16a3e50175dirk            label_length=strlen(property);
2953c93932ae0fce511e693d0cf9b969af16a3e50175dirk            (void) WriteBlobMSBLong(image,(unsigned int) (label_length+(4-
2954c93932ae0fce511e693d0cf9b969af16a3e50175dirk              (label_length % 4))+8));
29558e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy            (void) WriteBlobMSBLong(image,0);
29568e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy            (void) WriteBlobMSBLong(image,0);
29578e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy            WritePascalString(image,property,4);
29588e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy          }
29598e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy        next_image=GetNextImageInList(next_image);
29608e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy      }
29618e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy      /*
29628e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy        Now the image data!
29638e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy      */
29648e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy      next_image=base_image;
29658e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy      while (next_image != NULL)
29668e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy      {
29678e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy        status=WriteImageChannels(&psd_info,image_info,image,next_image,
2968018f07f7333b25743d0afff892450cebdb905c1acristy          MagickTrue,exception);
29698e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy        next_image=GetNextImageInList(next_image);
29708e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy      }
29718e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy      (void) WriteBlobMSBLong(image,0);  /* user mask data */
29728e9bd3e0de0cb1d12ed15b95b74bd616d3721eefcristy      base_image->compression=compression;
2973144f1b6af9d28fe66ee98ffd9fd1233bd55a45dacristy    }
2974144f1b6af9d28fe66ee98ffd9fd1233bd55a45dacristy  /*
2975144f1b6af9d28fe66ee98ffd9fd1233bd55a45dacristy    Write composite image.
2976144f1b6af9d28fe66ee98ffd9fd1233bd55a45dacristy  */
2977f308152b28249d599fa01dd41b1518c4ddfc5e60dirk  if (status != MagickFalse)
2978f308152b28249d599fa01dd41b1518c4ddfc5e60dirk    status=WriteImageChannels(&psd_info,image_info,image,image,MagickFalse,
2979f308152b28249d599fa01dd41b1518c4ddfc5e60dirk      exception);
29803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) CloseBlob(image);
29813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(status);
29823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
2983