Coverage Report

Created: 2025-11-14 07:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/imagemagick/coders/psd.c
Line
Count
Source
1
/*
2
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3
%                                                                             %
4
%                                                                             %
5
%                                                                             %
6
%                            PPPP   SSSSS  DDDD                               %
7
%                            P   P  SS     D   D                              %
8
%                            PPPP    SSS   D   D                              %
9
%                            P         SS  D   D                              %
10
%                            P      SSSSS  DDDD                               %
11
%                                                                             %
12
%                                                                             %
13
%                   Read/Write Adobe Photoshop Image Format                   %
14
%                                                                             %
15
%                              Software Design                                %
16
%                                   Cristy                                    %
17
%                              Leonard Rosenthol                              %
18
%                                 July 1992                                   %
19
%                                Dirk Lemstra                                 %
20
%                                December 2013                                %
21
%                                                                             %
22
%                                                                             %
23
%  Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization         %
24
%  dedicated to making software imaging solutions freely available.           %
25
%                                                                             %
26
%  You may not use this file except in compliance with the License.  You may  %
27
%  obtain a copy of the License at                                            %
28
%                                                                             %
29
%    https://imagemagick.org/script/license.php                               %
30
%                                                                             %
31
%  Unless required by applicable law or agreed to in writing, software        %
32
%  distributed under the License is distributed on an "AS IS" BASIS,          %
33
%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
34
%  See the License for the specific language governing permissions and        %
35
%  limitations under the License.                                             %
36
%                                                                             %
37
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
38
%
39
% Photoshop spec @ https://www.adobe.com/devnet-apps/photoshop/fileformatashtml
40
%
41
*/
42

43
/*
44
  Include declarations.
45
*/
46
#include "MagickCore/studio.h"
47
#include "MagickCore/artifact.h"
48
#include "MagickCore/attribute.h"
49
#include "MagickCore/blob.h"
50
#include "MagickCore/blob-private.h"
51
#include "MagickCore/cache.h"
52
#include "MagickCore/channel.h"
53
#include "MagickCore/colormap.h"
54
#include "MagickCore/colormap-private.h"
55
#include "MagickCore/colorspace.h"
56
#include "MagickCore/colorspace-private.h"
57
#include "MagickCore/constitute.h"
58
#include "MagickCore/enhance.h"
59
#include "MagickCore/exception.h"
60
#include "MagickCore/exception-private.h"
61
#include "MagickCore/image.h"
62
#include "MagickCore/image-private.h"
63
#include "MagickCore/list.h"
64
#include "MagickCore/log.h"
65
#include "MagickCore/magick.h"
66
#include "MagickCore/memory_.h"
67
#include "MagickCore/module.h"
68
#include "MagickCore/monitor-private.h"
69
#include "MagickCore/option.h"
70
#include "MagickCore/pixel.h"
71
#include "MagickCore/pixel-accessor.h"
72
#include "MagickCore/pixel-private.h"
73
#include "MagickCore/policy.h"
74
#include "MagickCore/profile-private.h"
75
#include "MagickCore/property.h"
76
#include "MagickCore/registry.h"
77
#include "MagickCore/quantum-private.h"
78
#include "MagickCore/static.h"
79
#include "MagickCore/string_.h"
80
#include "MagickCore/string-private.h"
81
#include "MagickCore/thread-private.h"
82
#include "coders/coders-private.h"
83
#ifdef MAGICKCORE_ZLIB_DELEGATE
84
#include <zlib.h>
85
#endif
86
#include "psd-private.h"
87
88
/*
89
  Define declarations.
90
*/
91
1.11k
#define MaxPSDChannels  56
92
0
#define PSDQuantum(x) (((ssize_t) (x)+1) & -2)
93

94
/*
95
  Enumerated declarations.
96
*/
97
typedef enum
98
{
99
  Raw = 0,
100
  RLE = 1,
101
  ZipWithoutPrediction = 2,
102
  ZipWithPrediction = 3
103
} PSDCompressionType;
104
105
typedef enum
106
{
107
  BitmapMode = 0,
108
  GrayscaleMode = 1,
109
  IndexedMode = 2,
110
  RGBMode = 3,
111
  CMYKMode = 4,
112
  MultichannelMode = 7,
113
  DuotoneMode = 8,
114
  LabMode = 9
115
} PSDImageType;
116

117
/*
118
  Typedef declarations.
119
*/
120
typedef struct _ChannelInfo
121
{
122
  MagickBooleanType
123
    supported;
124
125
  PixelChannel
126
    channel;
127
128
  size_t
129
    size;
130
} ChannelInfo;
131
132
typedef struct _MaskInfo
133
{
134
  Image
135
    *image;
136
137
  RectangleInfo
138
    page;
139
140
  unsigned char
141
    background,
142
    flags;
143
} MaskInfo;
144
145
typedef struct _LayerInfo
146
{
147
  ChannelInfo
148
    channel_info[MaxPSDChannels];
149
150
  char
151
    blendkey[4];
152
153
  Image
154
    *image;
155
156
  MaskInfo
157
    mask;
158
159
  Quantum
160
    opacity;
161
162
  RectangleInfo
163
    page;
164
165
  size_t
166
    offset_x,
167
    offset_y;
168
169
  unsigned char
170
    clipping,
171
    flags,
172
    name[257],
173
    visible;
174
175
  unsigned short
176
    channels;
177
178
  StringInfo
179
    *info;
180
} LayerInfo;
181
182
/*
183
  Forward declarations.
184
*/
185
static MagickBooleanType
186
  WritePSDImage(const ImageInfo *,Image *,ExceptionInfo *);
187

188
/*
189
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
190
%                                                                             %
191
%                                                                             %
192
%                                                                             %
193
%   I s P S D                                                                 %
194
%                                                                             %
195
%                                                                             %
196
%                                                                             %
197
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
198
%
199
%  IsPSD()() returns MagickTrue if the image format type, identified by the
200
%  magick string, is PSD.
201
%
202
%  The format of the IsPSD method is:
203
%
204
%      MagickBooleanType IsPSD(const unsigned char *magick,const size_t length)
205
%
206
%  A description of each parameter follows:
207
%
208
%    o magick: compare image format pattern against these bytes.
209
%
210
%    o length: Specifies the length of the magick string.
211
%
212
*/
213
static MagickBooleanType IsPSD(const unsigned char *magick,const size_t length)
214
0
{
215
0
  if (length < 4)
216
0
    return(MagickFalse);
217
0
  if (LocaleNCompare((const char *) magick,"8BPS",4) == 0)
218
0
    return(MagickTrue);
219
0
  return(MagickFalse);
220
0
}
221

222
/*
223
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
224
%                                                                             %
225
%                                                                             %
226
%                                                                             %
227
%   R e a d P S D I m a g e                                                   %
228
%                                                                             %
229
%                                                                             %
230
%                                                                             %
231
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
232
%
233
%  ReadPSDImage() reads an Adobe Photoshop image file and returns it.  It
234
%  allocates the memory necessary for the new Image structure and returns a
235
%  pointer to the new image.
236
%
237
%  The format of the ReadPSDImage method is:
238
%
239
%      Image *ReadPSDImage(image_info,ExceptionInfo *exception)
240
%
241
%  A description of each parameter follows:
242
%
243
%    o image_info: the image info.
244
%
245
%    o exception: return any errors or warnings in this structure.
246
%
247
*/
248
249
static const char *CompositeOperatorToPSDBlendMode(const Image *image)
250
0
{
251
0
  switch (image->compose)
252
0
  {
253
0
    case ColorBurnCompositeOp:
254
0
      return(image->endian == LSBEndian ? "vidi" : "idiv");
255
0
    case ColorDodgeCompositeOp:
256
0
      return(image->endian == LSBEndian ? " vid" : "div ");
257
0
    case ColorizeCompositeOp:
258
0
      return(image->endian == LSBEndian ? "rloc" : "colr");
259
0
    case DarkenCompositeOp:
260
0
      return(image->endian == LSBEndian ? "krad" : "dark");
261
0
    case DifferenceCompositeOp:
262
0
      return(image->endian == LSBEndian ? "ffid" : "diff");
263
0
    case DissolveCompositeOp:
264
0
      return(image->endian == LSBEndian ? "ssid" : "diss");
265
0
    case ExclusionCompositeOp:
266
0
      return(image->endian == LSBEndian ? "dums" : "smud");
267
0
    case HardLightCompositeOp:
268
0
      return(image->endian == LSBEndian ? "tiLh" : "hLit");
269
0
    case HardMixCompositeOp:
270
0
      return(image->endian == LSBEndian ? "xiMh" : "hMix");
271
0
    case HueCompositeOp:
272
0
      return(image->endian == LSBEndian ? " euh" : "hue ");
273
0
    case LightenCompositeOp:
274
0
      return(image->endian == LSBEndian ? "etil" : "lite");
275
0
    case LinearBurnCompositeOp:
276
0
      return(image->endian == LSBEndian ? "nrbl" : "lbrn");
277
0
    case LinearDodgeCompositeOp:
278
0
      return(image->endian == LSBEndian ? "gddl" : "lddg");
279
0
    case LinearLightCompositeOp:
280
0
      return(image->endian == LSBEndian ? "tiLl" : "lLit");
281
0
    case LuminizeCompositeOp:
282
0
      return(image->endian == LSBEndian ? " mul" : "lum ");
283
0
    case MultiplyCompositeOp:
284
0
      return(image->endian == LSBEndian ? " lum" : "mul ");
285
0
    case OverlayCompositeOp:
286
0
      return(image->endian == LSBEndian ? "revo" : "over");
287
0
    case PinLightCompositeOp:
288
0
      return(image->endian == LSBEndian ? "tiLp" : "pLit");
289
0
    case SaturateCompositeOp:
290
0
      return(image->endian == LSBEndian ? " tas" : "sat ");
291
0
    case ScreenCompositeOp:
292
0
      return(image->endian == LSBEndian ? "nrcs" : "scrn");
293
0
    case SoftLightCompositeOp:
294
0
      return(image->endian == LSBEndian ? "tiLs" : "sLit");
295
0
    case VividLightCompositeOp:
296
0
      return(image->endian == LSBEndian ? "tiLv" : "vLit");
297
0
    case OverCompositeOp:
298
0
    default:
299
0
      return(image->endian == LSBEndian ? "mron" : "norm");
300
0
  }
301
0
}
302
303
/*
304
  For some reason Photoshop seems to blend semi-transparent pixels with white.
305
  This method reverts the blending. This can be disabled by setting the
306
  option 'psd:alpha-unblend' to off.
307
*/
308
static MagickBooleanType CorrectPSDAlphaBlend(const ImageInfo *image_info,
309
  Image *image,ExceptionInfo* exception)
310
0
{
311
0
  const char
312
0
    *option;
313
314
0
  MagickBooleanType
315
0
    status;
316
317
0
  ssize_t
318
0
    y;
319
320
0
  if ((image->alpha_trait != BlendPixelTrait) ||
321
0
      (image->colorspace != sRGBColorspace))
322
0
    return(MagickTrue);
323
0
  option=GetImageOption(image_info,"psd:alpha-unblend");
324
0
  if (IsStringFalse(option) != MagickFalse)
325
0
    return(MagickTrue);
326
0
  status=MagickTrue;
327
#if defined(MAGICKCORE_OPENMP_SUPPORT)
328
#pragma omp parallel for schedule(static) shared(status) \
329
  magick_number_threads(image,image,image->rows,1)
330
#endif
331
0
  for (y=0; y < (ssize_t) image->rows; y++)
332
0
  {
333
0
    Quantum
334
0
      *magick_restrict q;
335
336
0
    ssize_t
337
0
      x;
338
339
0
    if (status == MagickFalse)
340
0
      continue;
341
0
    q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
342
0
    if (q == (Quantum *) NULL)
343
0
      {
344
0
        status=MagickFalse;
345
0
        continue;
346
0
      }
347
0
    for (x=0; x < (ssize_t) image->columns; x++)
348
0
    {
349
0
      double
350
0
        gamma;
351
352
0
      ssize_t
353
0
        i;
354
355
0
      gamma=QuantumScale*(double) GetPixelAlpha(image, q);
356
0
      if (gamma != 0.0 && gamma != 1.0)
357
0
        {
358
0
          for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
359
0
          {
360
0
            PixelChannel channel = GetPixelChannelChannel(image,i);
361
0
            if (channel != AlphaPixelChannel)
362
0
              q[i]=ClampToQuantum(((double) q[i]-((1.0-gamma)*(double)
363
0
                QuantumRange))/gamma);
364
0
          }
365
0
        }
366
0
      q+=(ptrdiff_t) GetPixelChannels(image);
367
0
    }
368
0
    if (SyncAuthenticPixels(image,exception) == MagickFalse)
369
0
      status=MagickFalse;
370
0
  }
371
372
0
  return(status);
373
0
}
374
375
static inline CompressionType ConvertPSDCompression(
376
  const PSDCompressionType compression)
377
3.20k
{
378
3.20k
  switch (compression)
379
3.20k
  {
380
571
    case RLE:
381
571
      return RLECompression;
382
64
    case ZipWithPrediction:
383
84
    case ZipWithoutPrediction:
384
84
      return ZipCompression;
385
2.55k
    default:
386
2.55k
      return NoCompression;
387
3.20k
  }
388
3.20k
}
389
390
static MagickBooleanType ApplyPSDLayerOpacity(Image *image,
391
  const Quantum opacity,const MagickBooleanType revert,ExceptionInfo *exception)
392
110
{
393
110
  MagickBooleanType
394
110
    status;
395
396
110
  ssize_t
397
110
    y;
398
399
110
  if (image->debug != MagickFalse)
400
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
401
0
      "  applying layer opacity %.20g", (double) opacity);
402
110
  if (opacity == OpaqueAlpha)
403
17
    return(MagickTrue);
404
93
  if (image->alpha_trait != BlendPixelTrait)
405
38
    (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
406
93
  status=MagickTrue;
407
#if defined(MAGICKCORE_OPENMP_SUPPORT)
408
#pragma omp parallel for schedule(static) shared(status) \
409
  magick_number_threads(image,image,image->rows,1)
410
#endif
411
1.03k
  for (y=0; y < (ssize_t) image->rows; y++)
412
943
  {
413
943
    Quantum
414
943
      *magick_restrict q;
415
416
943
    ssize_t
417
943
      x;
418
419
943
    if (status == MagickFalse)
420
0
      continue;
421
943
    q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
422
943
    if (q == (Quantum *) NULL)
423
0
      {
424
0
        status=MagickFalse;
425
0
        continue;
426
0
      }
427
35.7k
    for (x=0; x < (ssize_t) image->columns; x++)
428
34.7k
    {
429
34.7k
      if (revert == MagickFalse)
430
34.7k
        SetPixelAlpha(image,ClampToQuantum(QuantumScale*(double)
431
34.7k
          GetPixelAlpha(image,q)*(double) opacity),q);
432
0
      else if (opacity > 0)
433
0
        SetPixelAlpha(image,ClampToQuantum((double) QuantumRange*(double)
434
0
          GetPixelAlpha(image,q)/(double) opacity),q);
435
34.7k
      q+=(ptrdiff_t) GetPixelChannels(image);
436
34.7k
    }
437
943
    if (SyncAuthenticPixels(image,exception) == MagickFalse)
438
0
      status=MagickFalse;
439
943
  }
440
441
93
  return(status);
442
110
}
443
444
static MagickBooleanType ApplyPSDOpacityMask(Image *image,const Image *mask,
445
  const Quantum background,const MagickBooleanType revert,
446
  ExceptionInfo *exception)
447
52
{
448
52
  Image
449
52
    *complete_mask;
450
451
52
  MagickBooleanType
452
52
    status;
453
454
52
  PixelInfo
455
52
    color;
456
457
52
  ssize_t
458
52
    y;
459
460
52
  if ((image->alpha_trait & BlendPixelTrait) == 0)
461
1
    return(MagickTrue);
462
51
  if (image->debug != MagickFalse)
463
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
464
0
      "  applying opacity mask");
465
51
  complete_mask=CloneImage(image,0,0,MagickTrue,exception);
466
51
  if (complete_mask == (Image *) NULL)
467
0
    return(MagickFalse);
468
51
  complete_mask->alpha_trait=BlendPixelTrait;
469
51
  GetPixelInfo(complete_mask,&color);
470
51
  color.red=(MagickRealType) background;
471
51
  (void) SetImageColor(complete_mask,&color,exception);
472
51
  status=CompositeImage(complete_mask,mask,OverCompositeOp,MagickTrue,
473
51
    mask->page.x-image->page.x,mask->page.y-image->page.y,exception);
474
51
  if (status == MagickFalse)
475
0
    {
476
0
      complete_mask=DestroyImage(complete_mask);
477
0
      return(status);
478
0
    }
479
480
#if defined(MAGICKCORE_OPENMP_SUPPORT)
481
#pragma omp parallel for schedule(static) shared(status) \
482
  magick_number_threads(image,image,image->rows,1)
483
#endif
484
786
  for (y=0; y < (ssize_t) image->rows; y++)
485
735
  {
486
735
    Quantum
487
735
      *magick_restrict q;
488
489
735
    Quantum
490
735
      *p;
491
492
735
    ssize_t
493
735
      x;
494
495
735
    if (status == MagickFalse)
496
0
      continue;
497
735
    q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
498
735
    p=GetAuthenticPixels(complete_mask,0,y,complete_mask->columns,1,exception);
499
735
    if ((q == (Quantum *) NULL) || (p == (Quantum *) NULL))
500
0
      {
501
0
        status=MagickFalse;
502
0
        continue;
503
0
      }
504
26.7k
    for (x=0; x < (ssize_t) image->columns; x++)
505
26.0k
    {
506
26.0k
      MagickRealType
507
26.0k
        alpha,
508
26.0k
        intensity;
509
510
26.0k
      alpha=(MagickRealType) GetPixelAlpha(image,q);
511
26.0k
      intensity=GetPixelIntensity(complete_mask,p);
512
26.0k
      if (revert == MagickFalse)
513
26.0k
        SetPixelAlpha(image,ClampToQuantum(intensity*(QuantumScale*alpha)),q);
514
0
      else
515
0
        if (intensity > 0)
516
0
          SetPixelAlpha(image,ClampToQuantum((alpha/intensity)*(double)
517
0
            QuantumRange),q);
518
26.0k
      q+=(ptrdiff_t) GetPixelChannels(image);
519
26.0k
      p+=(ptrdiff_t) GetPixelChannels(complete_mask);
520
26.0k
    }
521
735
    if (SyncAuthenticPixels(image,exception) == MagickFalse)
522
0
      status=MagickFalse;
523
735
  }
524
51
  complete_mask=DestroyImage(complete_mask);
525
51
  return(status);
526
51
}
527
528
static void PreservePSDOpacityMask(Image *image,LayerInfo *layer_info,
529
  ExceptionInfo *exception)
530
0
{
531
0
  char
532
0
    *key;
533
534
0
  RandomInfo
535
0
    *random_info;
536
537
0
  StringInfo
538
0
    *key_info;
539
540
0
  if (image->debug != MagickFalse)
541
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
542
0
      "  preserving opacity mask");
543
0
  random_info=AcquireRandomInfo();
544
0
  key_info=GetRandomKey(random_info,2+1);
545
0
  key=(char *) GetStringInfoDatum(key_info);
546
0
  key[8]=(char) layer_info->mask.background;
547
0
  key[9]='\0';
548
0
  layer_info->mask.image->page.x+=layer_info->page.x;
549
0
  layer_info->mask.image->page.y+=layer_info->page.y;
550
0
  (void) SetImageRegistry(ImageRegistryType,(const char *) key,
551
0
    layer_info->mask.image,exception);
552
0
  (void) SetImageArtifact(layer_info->image,"psd:opacity-mask",
553
0
    (const char *) key);
554
0
  key_info=DestroyStringInfo(key_info);
555
0
  random_info=DestroyRandomInfo(random_info);
556
0
}
557
558
static ssize_t DecodePSDPixels(const size_t number_compact_pixels,
559
  const unsigned char *compact_pixels,const ssize_t depth,
560
  const size_t number_pixels,unsigned char *pixels)
561
508
{
562
508
#define CheckNumberCompactPixels \
563
52.4k
  if (packets == 0) \
564
52.4k
    return(i); \
565
52.4k
  packets--
566
567
508
#define CheckNumberPixels(count) \
568
82.3k
  if (((ssize_t) i + count) > (ssize_t) number_pixels) \
569
82.3k
    return(i); \
570
82.3k
  i+=count
571
572
508
  int
573
508
    pixel;
574
575
508
  ssize_t
576
508
    i,
577
508
    j;
578
579
508
  size_t
580
508
    length;
581
582
508
  ssize_t
583
508
    packets;
584
585
508
  packets=(ssize_t) number_compact_pixels;
586
10.0k
  for (i=0; (packets > 1) && (i < (ssize_t) number_pixels); )
587
9.99k
  {
588
9.99k
    packets--;
589
9.99k
    length=(size_t) (*compact_pixels++);
590
9.99k
    if (length == 128)
591
1.11k
      continue;
592
8.88k
    if (length > 128)
593
2.44k
      {
594
2.44k
        length=256-length+1;
595
2.44k
        CheckNumberCompactPixels;
596
2.44k
        pixel=(*compact_pixels++);
597
34.5k
        for (j=0; j < (ssize_t) length; j++)
598
32.3k
        {
599
32.3k
          switch (depth)
600
32.3k
          {
601
0
            case 1:
602
0
            {
603
0
              CheckNumberPixels(8);
604
0
              *pixels++=(pixel >> 7) & 0x01 ? 0U : 255U;
605
0
              *pixels++=(pixel >> 6) & 0x01 ? 0U : 255U;
606
0
              *pixels++=(pixel >> 5) & 0x01 ? 0U : 255U;
607
0
              *pixels++=(pixel >> 4) & 0x01 ? 0U : 255U;
608
0
              *pixels++=(pixel >> 3) & 0x01 ? 0U : 255U;
609
0
              *pixels++=(pixel >> 2) & 0x01 ? 0U : 255U;
610
0
              *pixels++=(pixel >> 1) & 0x01 ? 0U : 255U;
611
0
              *pixels++=(pixel >> 0) & 0x01 ? 0U : 255U;
612
0
              break;
613
0
            }
614
1.42k
            case 2:
615
1.42k
            {
616
1.42k
              CheckNumberPixels(4);
617
1.38k
              *pixels++=(unsigned char) ((pixel >> 6) & 0x03);
618
1.38k
              *pixels++=(unsigned char) ((pixel >> 4) & 0x03);
619
1.38k
              *pixels++=(unsigned char) ((pixel >> 2) & 0x03);
620
1.38k
              *pixels++=(unsigned char) ((pixel & 0x03) & 0x03);
621
1.38k
              break;
622
1.42k
            }
623
25.1k
            case 4:
624
25.1k
            {
625
25.1k
              CheckNumberPixels(2);
626
25.0k
              *pixels++=(unsigned char) ((pixel >> 4) & 0xff);
627
25.0k
              *pixels++=(unsigned char) ((pixel & 0x0f) & 0xff);
628
25.0k
              break;
629
25.1k
            }
630
5.76k
            default:
631
5.76k
            {
632
5.76k
              CheckNumberPixels(1);
633
5.68k
              *pixels++=(unsigned char) pixel;
634
5.68k
              break;
635
5.76k
            }
636
32.3k
          }
637
32.3k
        }
638
2.24k
        continue;
639
2.44k
      }
640
6.44k
    length++;
641
56.2k
    for (j=0; j < (ssize_t) length; j++)
642
50.0k
    {
643
50.0k
      CheckNumberCompactPixels;
644
50.0k
      switch (depth)
645
50.0k
      {
646
0
        case 1:
647
0
        {
648
0
          CheckNumberPixels(8);
649
0
          *pixels++=(*compact_pixels >> 7) & 0x01 ? 0U : 255U;
650
0
          *pixels++=(*compact_pixels >> 6) & 0x01 ? 0U : 255U;
651
0
          *pixels++=(*compact_pixels >> 5) & 0x01 ? 0U : 255U;
652
0
          *pixels++=(*compact_pixels >> 4) & 0x01 ? 0U : 255U;
653
0
          *pixels++=(*compact_pixels >> 3) & 0x01 ? 0U : 255U;
654
0
          *pixels++=(*compact_pixels >> 2) & 0x01 ? 0U : 255U;
655
0
          *pixels++=(*compact_pixels >> 1) & 0x01 ? 0U : 255U;
656
0
          *pixels++=(*compact_pixels >> 0) & 0x01 ? 0U : 255U;
657
0
          break;
658
0
        }
659
8.07k
        case 2:
660
8.07k
        {
661
8.07k
          CheckNumberPixels(4);
662
8.03k
          *pixels++=(*compact_pixels >> 6) & 0x03;
663
8.03k
          *pixels++=(*compact_pixels >> 4) & 0x03;
664
8.03k
          *pixels++=(*compact_pixels >> 2) & 0x03;
665
8.03k
          *pixels++=(*compact_pixels & 0x03) & 0x03;
666
8.03k
          break;
667
8.07k
        }
668
34.4k
        case 4:
669
34.4k
        {
670
34.4k
          CheckNumberPixels(2);
671
34.3k
          *pixels++=(*compact_pixels >> 4) & 0xff;
672
34.3k
          *pixels++=(*compact_pixels & 0x0f) & 0xff;
673
34.3k
          break;
674
34.4k
        }
675
7.48k
        default:
676
7.48k
        {
677
7.48k
          CheckNumberPixels(1);
678
7.42k
          *pixels++=(*compact_pixels);
679
7.42k
          break;
680
7.48k
        }
681
50.0k
      }
682
49.8k
      compact_pixels++;
683
49.8k
    }
684
6.44k
  }
685
86
  return(i);
686
508
}
687
688
static inline LayerInfo *DestroyLayerInfo(LayerInfo *layer_info,
689
  const ssize_t number_layers)
690
697
{
691
697
  ssize_t
692
697
    i;
693
694
1.42M
  for (i=0; i<number_layers; i++)
695
1.42M
  {
696
1.42M
    if (layer_info[i].image != (Image *) NULL)
697
295
      layer_info[i].image=DestroyImage(layer_info[i].image);
698
1.42M
    if (layer_info[i].mask.image != (Image *) NULL)
699
39
      layer_info[i].mask.image=DestroyImage(layer_info[i].mask.image);
700
1.42M
    if (layer_info[i].info != (StringInfo *) NULL)
701
104
      layer_info[i].info=DestroyStringInfo(layer_info[i].info);
702
1.42M
  }
703
697
  return((LayerInfo *) RelinquishMagickMemory(layer_info));
704
697
}
705
706
static inline size_t GetPSDPacketSize(const Image *image)
707
18.3k
{
708
18.3k
  if (image->storage_class == PseudoClass)
709
0
    {
710
0
      if (image->colors > 256)
711
0
        return(2);
712
0
    }
713
18.3k
  if (image->depth > 16)
714
222
    return(4);
715
18.1k
  if (image->depth > 8)
716
350
    return(2);
717
718
17.8k
  return(1);
719
18.1k
}
720
721
static inline MagickSizeType GetPSDSize(const PSDInfo *psd_info,Image *image)
722
12.9k
{
723
12.9k
  if (psd_info->version == 1)
724
12.3k
    return((MagickSizeType) ReadBlobLong(image));
725
653
  return((MagickSizeType) ReadBlobLongLong(image));
726
12.9k
}
727
728
static inline size_t GetPSDRowSize(const Image *image)
729
1.55k
{
730
1.55k
  if (image->depth == 1)
731
1.18k
    return(((image->columns+7)/8)*GetPSDPacketSize(image));
732
369
  else
733
369
    return(image->columns*GetPSDPacketSize(image));
734
1.55k
}
735
736
static const char *ModeToString(const PSDImageType type)
737
0
{
738
0
  switch (type)
739
0
  {
740
0
    case BitmapMode: return "Bitmap";
741
0
    case GrayscaleMode: return "Grayscale";
742
0
    case IndexedMode: return "Indexed";
743
0
    case RGBMode: return "RGB";
744
0
    case CMYKMode:  return "CMYK";
745
0
    case MultichannelMode: return "Multichannel";
746
0
    case DuotoneMode: return "Duotone";
747
0
    case LabMode: return "L*A*B";
748
0
    default: return "unknown";
749
0
  }
750
0
}
751
752
static MagickBooleanType NegateCMYK(Image *image,ExceptionInfo *exception)
753
35
{
754
35
  ChannelType
755
35
    channel_mask;
756
757
35
  MagickBooleanType
758
35
    status;
759
760
35
  channel_mask=SetImageChannelMask(image,(ChannelType)(AllChannels &~
761
35
    AlphaChannel));
762
35
  status=NegateImage(image,MagickFalse,exception);
763
35
  (void) SetImageChannelMask(image,channel_mask);
764
35
  return(status);
765
35
}
766
767
static StringInfo *ParseImageResourceBlocks(PSDInfo *psd_info,Image *image,
768
  const unsigned char *blocks,size_t length)
769
15
{
770
15
  const unsigned char
771
15
    *p;
772
773
15
  ssize_t
774
15
    offset;
775
776
15
  StringInfo
777
15
    *profile;
778
779
15
  unsigned char
780
15
    name_length;
781
782
15
  unsigned int
783
15
    count;
784
785
15
  unsigned short
786
15
    id,
787
15
    short_sans;
788
789
15
  if (length < 16)
790
1
    return((StringInfo *) NULL);
791
14
  profile=BlobToStringInfo((const unsigned char *) NULL,length);
792
14
  SetStringInfoDatum(profile,blocks);
793
14
  SetStringInfoName(profile,"8bim");
794
33
  for (p=blocks; (p >= blocks) && (p < (blocks+length-7)); )
795
29
  {
796
29
    if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
797
6
      break;
798
23
    p+=(ptrdiff_t) 4;
799
23
    p=PushShortPixel(MSBEndian,p,&id);
800
23
    p=PushCharPixel(p,&name_length);
801
23
    if ((name_length % 2) == 0)
802
22
      name_length++;
803
23
    p+=(ptrdiff_t) name_length;
804
23
    if (p > (blocks+length-4))
805
1
      break;
806
22
    p=PushLongPixel(MSBEndian,p,&count);
807
22
    offset=(ssize_t) count;
808
22
    if (((p+offset) < blocks) || ((p+offset) > (blocks+length)))
809
3
      break;
810
19
    switch (id)
811
19
    {
812
10
      case 0x03ed:
813
10
      {
814
10
        unsigned short
815
10
          resolution;
816
817
        /*
818
          Resolution info.
819
        */
820
10
        if (offset < 16)
821
1
          break;
822
9
        p=PushShortPixel(MSBEndian,p,&resolution);
823
9
        image->resolution.x=(double) resolution;
824
9
        (void) FormatImageProperty(image,"tiff:XResolution","%*g",
825
9
          GetMagickPrecision(),image->resolution.x);
826
9
        p=PushShortPixel(MSBEndian,p,&short_sans);
827
9
        p=PushShortPixel(MSBEndian,p,&short_sans);
828
9
        p=PushShortPixel(MSBEndian,p,&short_sans);
829
9
        p=PushShortPixel(MSBEndian,p,&resolution);
830
9
        image->resolution.y=(double) resolution;
831
9
        (void) FormatImageProperty(image,"tiff:YResolution","%*g",
832
9
          GetMagickPrecision(),image->resolution.y);
833
9
        p=PushShortPixel(MSBEndian,p,&short_sans);
834
9
        p=PushShortPixel(MSBEndian,p,&short_sans);
835
9
        p=PushShortPixel(MSBEndian,p,&short_sans);
836
9
        image->units=PixelsPerInchResolution;
837
9
        break;
838
10
      }
839
0
      case 0x0421:
840
0
      {
841
0
        if ((offset > 4) && (*(p+4) == 0))
842
0
          psd_info->has_merged_image=MagickFalse;
843
0
        p+=(ptrdiff_t) offset;
844
0
        break;
845
10
      }
846
9
      default:
847
9
      {
848
9
        p+=(ptrdiff_t) offset;
849
9
        break;
850
10
      }
851
19
    }
852
19
    if ((offset & 0x01) != 0)
853
7
      p++;
854
19
  }
855
14
  return(profile);
856
14
}
857
858
static CompositeOperator PSDBlendModeToCompositeOperator(const char *mode)
859
400
{
860
400
  if (mode == (const char *) NULL)
861
0
    return(OverCompositeOp);
862
400
  if (LocaleNCompare(mode,"norm",4) == 0)
863
0
    return(OverCompositeOp);
864
400
  if (LocaleNCompare(mode,"mul ",4) == 0)
865
0
    return(MultiplyCompositeOp);
866
400
  if (LocaleNCompare(mode,"diss",4) == 0)
867
0
    return(DissolveCompositeOp);
868
400
  if (LocaleNCompare(mode,"diff",4) == 0)
869
0
    return(DifferenceCompositeOp);
870
400
  if (LocaleNCompare(mode,"dark",4) == 0)
871
0
    return(DarkenCompositeOp);
872
400
  if (LocaleNCompare(mode,"lite",4) == 0)
873
0
    return(LightenCompositeOp);
874
400
  if (LocaleNCompare(mode,"hue ",4) == 0)
875
0
    return(HueCompositeOp);
876
400
  if (LocaleNCompare(mode,"sat ",4) == 0)
877
0
    return(SaturateCompositeOp);
878
400
  if (LocaleNCompare(mode,"colr",4) == 0)
879
0
    return(ColorizeCompositeOp);
880
400
  if (LocaleNCompare(mode,"lum ",4) == 0)
881
0
    return(LuminizeCompositeOp);
882
400
  if (LocaleNCompare(mode,"scrn",4) == 0)
883
0
    return(ScreenCompositeOp);
884
400
  if (LocaleNCompare(mode,"over",4) == 0)
885
0
    return(OverlayCompositeOp);
886
400
  if (LocaleNCompare(mode,"hLit",4) == 0)
887
0
    return(HardLightCompositeOp);
888
400
  if (LocaleNCompare(mode,"sLit",4) == 0)
889
0
    return(SoftLightCompositeOp);
890
400
  if (LocaleNCompare(mode,"smud",4) == 0)
891
0
    return(ExclusionCompositeOp);
892
400
  if (LocaleNCompare(mode,"div ",4) == 0)
893
0
    return(ColorDodgeCompositeOp);
894
400
  if (LocaleNCompare(mode,"idiv",4) == 0)
895
0
    return(ColorBurnCompositeOp);
896
400
  if (LocaleNCompare(mode,"lbrn",4) == 0)
897
0
    return(LinearBurnCompositeOp);
898
400
  if (LocaleNCompare(mode,"lddg",4) == 0)
899
0
    return(LinearDodgeCompositeOp);
900
400
  if (LocaleNCompare(mode,"lLit",4) == 0)
901
0
    return(LinearLightCompositeOp);
902
400
  if (LocaleNCompare(mode,"vLit",4) == 0)
903
0
    return(VividLightCompositeOp);
904
400
  if (LocaleNCompare(mode,"pLit",4) == 0)
905
0
    return(PinLightCompositeOp);
906
400
  if (LocaleNCompare(mode,"hMix",4) == 0)
907
0
    return(HardMixCompositeOp);
908
400
  return(OverCompositeOp);
909
400
}
910
911
static inline ssize_t ReadPSDString(Image *image,char *p,const size_t length)
912
1.32k
{
913
1.32k
  ssize_t
914
1.32k
    count;
915
916
1.32k
  count=ReadBlob(image,length,(unsigned char *) p);
917
1.32k
  if ((count == (ssize_t) length) && (image->endian != MSBEndian))
918
0
    {
919
0
      char
920
0
        *q;
921
922
0
      q=p+length;
923
0
      for(--q; p < q; ++p, --q)
924
0
      {
925
0
        *p = *p ^ *q,
926
0
        *q = *p ^ *q,
927
0
        *p = *p ^ *q;
928
0
      }
929
0
    }
930
1.32k
  return(count);
931
1.32k
}
932
933
static inline void SetPSDPixel(Image *image,const PixelChannel channel,
934
  const size_t packet_size,const Quantum pixel,Quantum *q,
935
  ExceptionInfo *exception)
936
608k
{
937
608k
  if (image->storage_class == PseudoClass)
938
0
    {
939
0
      PixelInfo
940
0
        *color;
941
942
0
      ssize_t
943
0
        index;
944
945
0
      if (channel == GrayPixelChannel)
946
0
        {
947
0
          index=(ssize_t) pixel;
948
0
          if (packet_size == 1)
949
0
            index=(ssize_t) ScaleQuantumToChar((Quantum) index);
950
0
          index=ConstrainColormapIndex(image,index,exception);
951
0
          SetPixelIndex(image,(Quantum) index,q);
952
0
        }
953
0
      else
954
0
        {
955
0
          index=(ssize_t) GetPixelIndex(image,q);
956
0
          index=ConstrainColormapIndex(image,index,exception);
957
0
        }
958
0
      color=image->colormap+index;
959
0
      if (channel == AlphaPixelChannel)
960
0
        color->alpha=(MagickRealType) pixel;
961
0
      SetPixelViaPixelInfo(image,color,q);
962
0
    }
963
608k
  else
964
608k
    SetPixelChannel(image,channel,pixel,q);
965
608k
}
966
967
static MagickBooleanType ReadPSDChannelPixels(Image *image,const ssize_t row,
968
  const PixelChannel channel,const unsigned char *pixels,
969
  ExceptionInfo *exception)
970
16.7k
{
971
16.7k
  Quantum
972
16.7k
    pixel;
973
974
16.7k
  const unsigned char
975
16.7k
    *p;
976
977
16.7k
  Quantum
978
16.7k
    *q;
979
980
16.7k
  ssize_t
981
16.7k
    x;
982
983
16.7k
  size_t
984
16.7k
    packet_size;
985
986
16.7k
  p=pixels;
987
16.7k
  q=GetAuthenticPixels(image,0,row,image->columns,1,exception);
988
16.7k
  if (q == (Quantum *) NULL)
989
0
    return MagickFalse;
990
16.7k
  packet_size=GetPSDPacketSize(image);
991
248k
  for (x=0; x < (ssize_t) image->columns; x++)
992
232k
  {
993
232k
    if (packet_size == 1)
994
229k
      pixel=ScaleCharToQuantum(*p++);
995
2.99k
    else
996
2.99k
      if (packet_size == 2)
997
1.42k
        {
998
1.42k
          unsigned short
999
1.42k
            nibble;
1000
1001
1.42k
          p=PushShortPixel(MSBEndian,p,&nibble);
1002
1.42k
          pixel=ScaleShortToQuantum(nibble);
1003
1.42k
        }
1004
1.56k
      else
1005
1.56k
        {
1006
1.56k
          MagickFloatType
1007
1.56k
            nibble;
1008
1009
1.56k
          p=PushFloatPixel(MSBEndian,p,&nibble);
1010
1.56k
          pixel=ClampToQuantum((double) QuantumRange*(double) nibble);
1011
1.56k
        }
1012
232k
    if (image->depth > 1)
1013
164k
      {
1014
164k
        SetPSDPixel(image,channel,packet_size,pixel,q,exception);
1015
164k
        q+=(ptrdiff_t) GetPixelChannels(image);
1016
164k
      }
1017
67.3k
    else
1018
67.3k
      {
1019
67.3k
        ssize_t
1020
67.3k
          bit,
1021
67.3k
          number_bits;
1022
1023
67.3k
        number_bits=(ssize_t) image->columns-x;
1024
67.3k
        if (number_bits > 8)
1025
51.3k
          number_bits=8;
1026
510k
        for (bit = 0; bit < (ssize_t) number_bits; bit++)
1027
443k
        {
1028
443k
          SetPSDPixel(image,channel,packet_size,(((unsigned char)
1029
443k
            ((ssize_t) pixel)) & (0x01 << (7-bit))) != 0 ? 0 :
1030
443k
            QuantumRange,q,exception);
1031
443k
          q+=(ptrdiff_t) GetPixelChannels(image);
1032
443k
          x++;
1033
443k
        }
1034
67.3k
        if (x != (ssize_t) image->columns)
1035
51.3k
          x--;
1036
67.3k
        continue;
1037
67.3k
      }
1038
232k
  }
1039
16.7k
  return(SyncAuthenticPixels(image,exception));
1040
16.7k
}
1041
1042
static MagickBooleanType ReadPSDChannelRaw(Image *image,
1043
  const PixelChannel channel,ExceptionInfo *exception)
1044
1.19k
{
1045
1.19k
  MagickBooleanType
1046
1.19k
    status;
1047
1048
1.19k
  size_t
1049
1.19k
    row_size;
1050
1051
1.19k
  ssize_t
1052
1.19k
    count,
1053
1.19k
    y;
1054
1055
1.19k
  unsigned char
1056
1.19k
    *pixels;
1057
1058
1.19k
  if (image->debug != MagickFalse)
1059
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1060
0
       "      layer data is RAW");
1061
1062
1.19k
  row_size=GetPSDRowSize(image);
1063
1.19k
  pixels=(unsigned char *) AcquireQuantumMemory(row_size,sizeof(*pixels));
1064
1.19k
  if (pixels == (unsigned char *) NULL)
1065
0
    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1066
1.19k
      image->filename);
1067
1.19k
  (void) memset(pixels,0,row_size*sizeof(*pixels));
1068
1069
1.19k
  status=MagickTrue;
1070
17.0k
  for (y=0; y < (ssize_t) image->rows; y++)
1071
15.9k
  {
1072
15.9k
    status=MagickFalse;
1073
1074
15.9k
    count=ReadBlob(image,row_size,pixels);
1075
15.9k
    if (count != (ssize_t) row_size)
1076
81
      break;
1077
1078
15.8k
    status=ReadPSDChannelPixels(image,y,channel,pixels,exception);
1079
15.8k
    if (status == MagickFalse)
1080
0
      break;
1081
15.8k
  }
1082
1083
1.19k
  pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1084
1.19k
  return(status);
1085
1.19k
}
1086
1087
static inline MagickOffsetType *ReadPSDRLESizes(Image *image,
1088
  const PSDInfo *psd_info,const size_t size)
1089
365
{
1090
365
  MagickOffsetType
1091
365
    *sizes;
1092
1093
365
  ssize_t
1094
365
    y;
1095
1096
365
  sizes=(MagickOffsetType *) AcquireQuantumMemory(size,sizeof(*sizes));
1097
365
  if(sizes != (MagickOffsetType *) NULL)
1098
365
    {
1099
1.94k
      for (y=0; y < (ssize_t) size; y++)
1100
1.57k
      {
1101
1.57k
        if (psd_info->version == 1)
1102
1.57k
          sizes[y]=(MagickOffsetType) ReadBlobShort(image);
1103
0
        else
1104
0
          sizes[y]=(MagickOffsetType) ReadBlobLong(image);
1105
1.57k
      }
1106
365
    }
1107
365
  return sizes;
1108
365
}
1109
1110
static MagickBooleanType ReadPSDChannelRLE(Image *image,
1111
  const PixelChannel channel,MagickOffsetType *sizes,
1112
  ExceptionInfo *exception)
1113
365
{
1114
365
  MagickBooleanType
1115
365
    status;
1116
1117
365
  size_t
1118
365
    length,
1119
365
    row_size;
1120
1121
365
  ssize_t
1122
365
    count,
1123
365
    y;
1124
1125
365
  unsigned char
1126
365
    *compact_pixels,
1127
365
    *pixels;
1128
1129
365
  if (image->debug != MagickFalse)
1130
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1131
0
       "      layer data is RLE compressed");
1132
1133
365
  row_size=GetPSDRowSize(image);
1134
365
  pixels=(unsigned char *) AcquireQuantumMemory(row_size,sizeof(*pixels));
1135
365
  if (pixels == (unsigned char *) NULL)
1136
0
    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1137
365
      image->filename);
1138
1139
365
  length=0;
1140
1.94k
  for (y=0; y < (ssize_t) image->rows; y++)
1141
1.57k
    if ((MagickOffsetType) length < sizes[y])
1142
540
      length=(size_t) sizes[y];
1143
1144
365
  if (length > (row_size+2048)) /* arbitrary number */
1145
22
    {
1146
22
      pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1147
22
      ThrowBinaryException(ResourceLimitError,"InvalidLength",image->filename);
1148
0
    }
1149
1150
343
  compact_pixels=(unsigned char *) AcquireQuantumMemory(length,sizeof(*pixels));
1151
343
  if (compact_pixels == (unsigned char *) NULL)
1152
4
    {
1153
4
      pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1154
4
      ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1155
4
        image->filename);
1156
0
    }
1157
1158
339
  (void) memset(compact_pixels,0,length*sizeof(*compact_pixels));
1159
1160
339
  status=MagickTrue;
1161
828
  for (y=0; y < (ssize_t) image->rows; y++)
1162
511
  {
1163
511
    status=MagickFalse;
1164
1165
511
    count=ReadBlob(image,(size_t) sizes[y],compact_pixels);
1166
511
    if (count != (ssize_t) sizes[y])
1167
3
      break;
1168
1169
508
    count=DecodePSDPixels((size_t) sizes[y],compact_pixels,
1170
508
      (ssize_t) (image->depth == 1 ? 123456 : image->depth),row_size,pixels);
1171
508
    if (count != (ssize_t) row_size)
1172
19
      break;
1173
1174
489
    status=ReadPSDChannelPixels(image,y,channel,pixels,exception);
1175
489
    if (status == MagickFalse)
1176
0
      break;
1177
489
  }
1178
1179
339
  compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
1180
339
  pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1181
339
  return(status);
1182
343
}
1183
1184
#ifdef MAGICKCORE_ZLIB_DELEGATE
1185
static void Unpredict8Bit(const Image *image,unsigned char *pixels,
1186
  const size_t count,const size_t row_size)
1187
19
{
1188
19
  unsigned char
1189
19
    *p;
1190
1191
19
  size_t
1192
19
    length,
1193
19
    remaining;
1194
1195
19
  p=pixels;
1196
19
  remaining=count;
1197
426
  while (remaining > 0)
1198
407
  {
1199
407
    length=image->columns;
1200
1.89k
    while (--length)
1201
1.49k
    {
1202
1.49k
      *(p+1)+=*p;
1203
1.49k
      p++;
1204
1.49k
    }
1205
407
    p++;
1206
407
    remaining-=row_size;
1207
407
  }
1208
19
}
1209
1210
static void Unpredict16Bit(const Image *image,unsigned char *pixels,
1211
  const size_t count,const size_t row_size)
1212
8
{
1213
8
  unsigned char
1214
8
    *p;
1215
1216
8
  size_t
1217
8
    length,
1218
8
    remaining;
1219
1220
8
  p=pixels;
1221
8
  remaining=count;
1222
26
  while (remaining > 0)
1223
18
  {
1224
18
    length=image->columns;
1225
67
    while (--length)
1226
49
    {
1227
49
      p[2]+=p[0]+((p[1]+p[3]) >> 8);
1228
49
      p[3]+=p[1];
1229
49
      p+=(ptrdiff_t) 2;
1230
49
    }
1231
18
    p+=(ptrdiff_t) 2;
1232
18
    remaining-=row_size;
1233
18
  }
1234
8
}
1235
1236
static void Unpredict32Bit(const Image *image,unsigned char *pixels,
1237
  unsigned char *output_pixels,const size_t row_size)
1238
8
{
1239
8
  unsigned char
1240
8
    *p,
1241
8
    *q;
1242
1243
8
  ssize_t
1244
8
    y;
1245
1246
8
  size_t
1247
8
    offset1,
1248
8
    offset2,
1249
8
    offset3,
1250
8
    remaining;
1251
1252
8
  unsigned char
1253
8
    *start;
1254
1255
8
  offset1=image->columns;
1256
8
  offset2=2*offset1;
1257
8
  offset3=3*offset1;
1258
8
  p=pixels;
1259
8
  q=output_pixels;
1260
19
  for (y=0; y < (ssize_t) image->rows; y++)
1261
11
  {
1262
11
    start=p;
1263
11
    remaining=row_size;
1264
96
    while (--remaining)
1265
85
    {
1266
85
      *(p+1)+=*p;
1267
85
      p++;
1268
85
    }
1269
1270
11
    p=start;
1271
11
    remaining=image->columns;
1272
35
    while (remaining--)
1273
24
    {
1274
24
      *(q++)=*p;
1275
24
      *(q++)=*(p+offset1);
1276
24
      *(q++)=*(p+offset2);
1277
24
      *(q++)=*(p+offset3);
1278
1279
24
      p++;
1280
24
    }
1281
11
    p=start+row_size;
1282
11
  }
1283
8
}
1284
1285
static MagickBooleanType ReadPSDChannelZip(Image *image,
1286
  const PixelChannel channel,const PSDCompressionType compression,
1287
  const size_t compact_size,ExceptionInfo *exception)
1288
63
{
1289
63
  MagickBooleanType
1290
63
    status;
1291
1292
63
  unsigned char
1293
63
    *p;
1294
1295
63
  size_t
1296
63
    count,
1297
63
    packet_size,
1298
63
    row_size;
1299
1300
63
  ssize_t
1301
63
    y;
1302
1303
63
  unsigned char
1304
63
    *compact_pixels,
1305
63
    *pixels;
1306
1307
63
  z_stream
1308
63
    stream;
1309
1310
63
  if (image->debug != MagickFalse)
1311
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1312
0
       "      layer data is ZIP compressed");
1313
1314
63
  if ((MagickSizeType) compact_size > GetBlobSize(image))
1315
7
    ThrowBinaryException(CorruptImageError,"UnexpectedEndOfFile",
1316
63
      image->filename);
1317
56
  compact_pixels=(unsigned char *) AcquireQuantumMemory(compact_size,
1318
56
    sizeof(*compact_pixels));
1319
56
  if (compact_pixels == (unsigned char *) NULL)
1320
2
    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1321
56
      image->filename);
1322
1323
54
  packet_size=GetPSDPacketSize(image);
1324
54
  row_size=image->columns*packet_size;
1325
54
  count=image->rows*row_size;
1326
1327
54
  pixels=(unsigned char *) AcquireQuantumMemory(count,sizeof(*pixels));
1328
54
  if (pixels == (unsigned char *) NULL)
1329
0
    {
1330
0
      compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
1331
0
      ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1332
0
        image->filename);
1333
0
    }
1334
54
  if (ReadBlob(image,compact_size,compact_pixels) != (ssize_t) compact_size)
1335
7
    {
1336
7
      pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1337
7
      compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
1338
7
      ThrowBinaryException(CorruptImageError,"UnexpectedEndOfFile",
1339
7
        image->filename);
1340
0
    }
1341
1342
47
  memset(&stream,0,sizeof(stream));
1343
47
  stream.data_type=Z_BINARY;
1344
47
  stream.next_in=(Bytef *)compact_pixels;
1345
47
  stream.avail_in=(uInt) compact_size;
1346
47
  stream.next_out=(Bytef *)pixels;
1347
47
  stream.avail_out=(uInt) count;
1348
1349
47
  if (inflateInit(&stream) == Z_OK)
1350
47
    {
1351
47
      int
1352
47
        ret;
1353
1354
86
      while (stream.avail_out > 0)
1355
49
      {
1356
49
        ret=inflate(&stream,Z_SYNC_FLUSH);
1357
49
        if ((ret != Z_OK) && (ret != Z_STREAM_END))
1358
10
          {
1359
10
            (void) inflateEnd(&stream);
1360
10
            compact_pixels=(unsigned char *) RelinquishMagickMemory(
1361
10
              compact_pixels);
1362
10
            pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1363
10
            return(MagickFalse);
1364
10
          }
1365
39
        if (ret == Z_STREAM_END)
1366
0
          break;
1367
39
      }
1368
37
      (void) inflateEnd(&stream);
1369
37
    }
1370
1371
37
  if (compression == ZipWithPrediction)
1372
35
    {
1373
35
      if (packet_size == 1)
1374
19
        Unpredict8Bit(image,pixels,count,row_size);
1375
16
      else if (packet_size == 2)
1376
8
        Unpredict16Bit(image,pixels,count,row_size);
1377
8
      else if (packet_size == 4)
1378
8
      {
1379
8
        unsigned char
1380
8
          *output_pixels;
1381
1382
8
        output_pixels=(unsigned char *) AcquireQuantumMemory(count,
1383
8
          sizeof(*output_pixels));
1384
8
        if (output_pixels == (unsigned char *) NULL)
1385
0
          {
1386
0
            compact_pixels=(unsigned char *) RelinquishMagickMemory(
1387
0
              compact_pixels);
1388
0
            pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1389
0
            ThrowBinaryException(ResourceLimitError,
1390
0
              "MemoryAllocationFailed",image->filename);
1391
0
          }
1392
8
        Unpredict32Bit(image,pixels,output_pixels,row_size);
1393
8
        pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1394
8
        pixels=output_pixels;
1395
8
      }
1396
35
    }
1397
1398
37
  status=MagickTrue;
1399
37
  p=pixels;
1400
475
  for (y=0; y < (ssize_t) image->rows; y++)
1401
438
  {
1402
438
    status=ReadPSDChannelPixels(image,y,channel,p,exception);
1403
438
    if (status == MagickFalse)
1404
0
      break;
1405
1406
438
    p+=(ptrdiff_t) row_size;
1407
438
  }
1408
1409
37
  compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
1410
37
  pixels=(unsigned char *) RelinquishMagickMemory(pixels);
1411
37
  return(status);
1412
37
}
1413
#endif
1414
1415
static MagickBooleanType ReadPSDChannel(Image *image,
1416
  const ImageInfo *image_info,const PSDInfo *psd_info,LayerInfo* layer_info,
1417
  const size_t channel_index,const PSDCompressionType compression,
1418
  ExceptionInfo *exception)
1419
3.20k
{
1420
3.20k
  Image
1421
3.20k
    *channel_image,
1422
3.20k
    *mask;
1423
1424
3.20k
  MagickOffsetType
1425
3.20k
    end_offset,
1426
3.20k
    offset;
1427
1428
3.20k
  MagickBooleanType
1429
3.20k
    status;
1430
1431
3.20k
  PixelChannel
1432
3.20k
    channel;
1433
1434
3.20k
  end_offset=(MagickOffsetType) layer_info->channel_info[channel_index].size-2;
1435
3.20k
  if (layer_info->channel_info[channel_index].supported == MagickFalse)
1436
1.18k
    {
1437
1.18k
      (void) SeekBlob(image,end_offset,SEEK_CUR);
1438
1.18k
      return(MagickTrue);
1439
1.18k
    }
1440
2.02k
  channel_image=image;
1441
2.02k
  channel=layer_info->channel_info[channel_index].channel;
1442
2.02k
  mask=(Image *) NULL;
1443
2.02k
  if (channel == ReadMaskPixelChannel)
1444
770
    {
1445
770
      const char
1446
770
        *option;
1447
1448
      /*
1449
        Ignore mask that is not a user supplied layer mask, if the mask is
1450
        disabled or if the flags have unsupported values.
1451
      */
1452
770
      option=GetImageOption(image_info,"psd:preserve-opacity-mask");
1453
770
      if ((layer_info->mask.flags > 2) || ((layer_info->mask.flags & 0x02) &&
1454
21
           (IsStringTrue(option) == MagickFalse)) ||
1455
726
           (layer_info->mask.page.width < 1) ||
1456
515
           (layer_info->mask.page.height < 1))
1457
274
        {
1458
274
          (void) SeekBlob(image,end_offset,SEEK_CUR);
1459
274
          return(MagickTrue);
1460
274
        }
1461
496
      mask=CloneImage(image,layer_info->mask.page.width,
1462
496
        layer_info->mask.page.height,MagickFalse,exception);
1463
496
      if (mask != (Image *) NULL)
1464
336
        {
1465
336
          (void) ResetImagePixels(mask,exception);
1466
336
          (void) SetImageType(mask,GrayscaleType,exception);
1467
336
          channel_image=mask;
1468
336
          channel=GrayPixelChannel;
1469
336
        }
1470
496
    }
1471
1472
1.75k
  offset=TellBlob(image);
1473
1.75k
  status=MagickFalse;
1474
1.75k
  switch(compression)
1475
1.75k
  {
1476
1.19k
    case Raw:
1477
1.19k
      status=ReadPSDChannelRaw(channel_image,channel,exception);
1478
1.19k
      break;
1479
365
    case RLE:
1480
365
      {
1481
365
        MagickOffsetType
1482
365
          *sizes;
1483
1484
365
        sizes=ReadPSDRLESizes(channel_image,psd_info,channel_image->rows);
1485
365
        if (sizes == (MagickOffsetType *) NULL)
1486
0
          ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1487
365
            image->filename);
1488
365
        status=ReadPSDChannelRLE(channel_image,channel,sizes,exception);
1489
365
        sizes=(MagickOffsetType *) RelinquishMagickMemory(sizes);
1490
365
      }
1491
0
      break;
1492
51
    case ZipWithPrediction:
1493
63
    case ZipWithoutPrediction:
1494
63
#ifdef MAGICKCORE_ZLIB_DELEGATE
1495
63
      status=ReadPSDChannelZip(channel_image,channel,compression,(size_t)
1496
63
        end_offset,exception);
1497
#else
1498
      (void) ThrowMagickException(exception,GetMagickModule(),
1499
          MissingDelegateWarning,"DelegateLibrarySupportNotBuiltIn",
1500
            "'%s' (ZLIB)",image->filename);
1501
#endif
1502
63
      break;
1503
135
    default:
1504
135
      (void) ThrowMagickException(exception,GetMagickModule(),TypeWarning,
1505
135
        "CompressionNotSupported","'%.20g'",(double) compression);
1506
135
      break;
1507
1.75k
  }
1508
1509
1.75k
  (void) SeekBlob(image,offset+end_offset,SEEK_SET);
1510
1.75k
  if (status == MagickFalse)
1511
290
    {
1512
290
      if (mask != (Image *) NULL)
1513
38
        (void) DestroyImage(mask);
1514
290
      ThrowBinaryException(CoderError,"UnableToDecompressImage",
1515
290
        image->filename);
1516
0
    }
1517
1.46k
  if (mask != (Image *) NULL)
1518
298
    {
1519
298
      if (layer_info->mask.image != (Image *) NULL)
1520
207
        layer_info->mask.image=DestroyImage(layer_info->mask.image);
1521
298
      layer_info->mask.image=mask;
1522
298
    }
1523
1.46k
  return(status);
1524
1.75k
}
1525
1526
static MagickBooleanType GetPixelChannelFromPSDIndex(const PSDInfo *psd_info,
1527
  ssize_t index,PixelChannel *channel)
1528
11.9k
{
1529
11.9k
  *channel=RedPixelChannel;
1530
11.9k
  switch (psd_info->mode)
1531
11.9k
  {
1532
494
    case BitmapMode:
1533
494
    case IndexedMode:
1534
873
    case GrayscaleMode:
1535
873
    {
1536
873
      if (index == 1)
1537
10
        index=-1;
1538
863
      else if (index > 1)
1539
134
        index=MetaPixelChannels+index-2;
1540
873
      break;
1541
494
    }
1542
93
    case LabMode:
1543
237
    case MultichannelMode:
1544
768
    case RGBMode:
1545
768
    {
1546
768
      if (index == 3)
1547
6
        index=-1;
1548
762
      else if (index > 3)
1549
136
        index=MetaPixelChannels+index-4;
1550
768
      break;
1551
237
    }
1552
450
    case CMYKMode:
1553
450
    {
1554
450
      if (index == 4)
1555
15
        index=-1;
1556
435
      else if (index > 4)
1557
128
        index=MetaPixelChannels+index-5;
1558
450
      break;
1559
237
    }
1560
11.9k
  }
1561
11.9k
  if ((index < -2) || (index >= MaxPixelChannels))
1562
4.12k
    return(MagickFalse);
1563
7.79k
  if (index == -1)
1564
340
    *channel=AlphaPixelChannel;
1565
7.45k
  else if (index == -2)
1566
247
    *channel=ReadMaskPixelChannel;
1567
7.20k
  else
1568
7.20k
    *channel=(PixelChannel) index;
1569
7.79k
  return(MagickTrue);
1570
11.9k
}
1571
1572
static MagickBooleanType SetPSDMetaChannels(Image *image,const PSDInfo *psd_info,
1573
  const unsigned short channels,ExceptionInfo *exception)
1574
400
{
1575
400
  ssize_t
1576
400
    number_meta_channels;
1577
1578
400
  number_meta_channels=(ssize_t) channels-psd_info->min_channels;
1579
400
  if ((image->alpha_trait & BlendPixelTrait) != 0)
1580
250
    number_meta_channels--;
1581
400
  if (number_meta_channels > 0)
1582
400
    return(SetPixelMetaChannels(image,(size_t) number_meta_channels,exception));
1583
0
  return(MagickTrue);
1584
400
}
1585
1586
static MagickBooleanType ReadPSDLayer(Image *image,const ImageInfo *image_info,
1587
  const PSDInfo *psd_info,LayerInfo* layer_info,ExceptionInfo *exception)
1588
400
{
1589
400
  char
1590
400
    message[MagickPathExtent];
1591
1592
400
  MagickBooleanType
1593
400
    status;
1594
1595
400
  PSDCompressionType
1596
400
    compression;
1597
1598
400
  ssize_t
1599
400
    j;
1600
1601
400
  if (image->debug != MagickFalse)
1602
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1603
0
      "    setting up new layer image");
1604
400
  if (psd_info->mode != IndexedMode)
1605
400
    (void) SetImageBackgroundColor(layer_info->image,exception);
1606
400
  layer_info->image->compose=PSDBlendModeToCompositeOperator(
1607
400
    layer_info->blendkey);
1608
400
  if (layer_info->visible == MagickFalse)
1609
219
    layer_info->image->compose=NoCompositeOp;
1610
  /*
1611
    Set up some hidden attributes for folks that need them.
1612
  */
1613
400
  (void) FormatLocaleString(message,MagickPathExtent,"%.20g",
1614
400
    (double) layer_info->page.x);
1615
400
  (void) SetImageArtifact(layer_info->image,"psd:layer.x",message);
1616
400
  (void) FormatLocaleString(message,MagickPathExtent,"%.20g",
1617
400
    (double) layer_info->page.y);
1618
400
  (void) SetImageArtifact(layer_info->image,"psd:layer.y",message);
1619
400
  (void) FormatLocaleString(message,MagickPathExtent,"%.20g",(double)
1620
400
    layer_info->opacity);
1621
400
  (void) SetImageArtifact(layer_info->image,"psd:layer.opacity",message);
1622
400
  (void) FormatLocaleString(message,MagickPathExtent,"%.20g",(double)
1623
400
    layer_info->visible);
1624
400
  (void) SetImageArtifact(layer_info->image,"psd:layer.visible",message);
1625
400
  (void) SetImageProperty(layer_info->image,"label",(char *) layer_info->name,
1626
400
    exception);
1627
1628
400
  status=SetPSDMetaChannels(layer_info->image,psd_info,layer_info->channels,
1629
400
    exception);
1630
400
  if (status != MagickFalse)
1631
400
    {
1632
3.31k
      for (j=0; j < (ssize_t) layer_info->channels; j++)
1633
3.20k
      {
1634
3.20k
        if (image->debug != MagickFalse)
1635
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1636
0
            "    reading data for channel %.20g",(double) j);
1637
1638
3.20k
        compression=(PSDCompressionType) ReadBlobShort(layer_info->image);
1639
3.20k
        layer_info->image->compression=ConvertPSDCompression(compression);
1640
1641
3.20k
        status=ReadPSDChannel(layer_info->image,image_info,psd_info,layer_info,
1642
3.20k
          (size_t) j,compression,exception);
1643
1644
3.20k
        if (status == MagickFalse)
1645
290
          break;
1646
3.20k
      }
1647
400
    }
1648
1649
400
  if (status != MagickFalse)
1650
110
    status=ApplyPSDLayerOpacity(layer_info->image,layer_info->opacity,
1651
110
      MagickFalse,exception);
1652
1653
400
  if ((status != MagickFalse) &&
1654
110
      (layer_info->image->colorspace == CMYKColorspace))
1655
35
    status=NegateCMYK(layer_info->image,exception);
1656
1657
400
  if ((status != MagickFalse) && (layer_info->mask.image != (Image *) NULL))
1658
52
    {
1659
52
      const char
1660
52
        *option;
1661
1662
52
      layer_info->mask.image->page.x=layer_info->mask.page.x;
1663
52
      layer_info->mask.image->page.y=layer_info->mask.page.y;
1664
      /* Do not composite the mask when it is disabled */
1665
52
      if ((layer_info->mask.flags & 0x02) == 0x02)
1666
0
        layer_info->mask.image->compose=NoCompositeOp;
1667
52
      else
1668
52
        status=ApplyPSDOpacityMask(layer_info->image,layer_info->mask.image,
1669
52
          layer_info->mask.background == 0 ? 0 : QuantumRange,MagickFalse,
1670
52
          exception);
1671
52
      option=GetImageOption(image_info,"psd:preserve-opacity-mask");
1672
52
      if (IsStringTrue(option) != MagickFalse)
1673
0
        PreservePSDOpacityMask(image,layer_info,exception);
1674
52
      layer_info->mask.image=DestroyImage(layer_info->mask.image);
1675
52
    }
1676
1677
400
  return(status);
1678
400
}
1679
1680
static MagickBooleanType IsEmptyPSDLayer(LayerInfo *layer_info)
1681
1.30k
{
1682
1.30k
  if ((layer_info->page.width == 0) || (layer_info->page.height == 0))
1683
108
    return(MagickTrue);
1684
1.19k
  return(MagickFalse);
1685
1.30k
}
1686
1687
static MagickBooleanType CheckPSDChannels(const Image *image,
1688
  const PSDInfo *psd_info,LayerInfo *layer_info)
1689
850
{
1690
850
  int
1691
850
    channel_type;
1692
1693
850
  size_t
1694
850
    blob_size;
1695
1696
850
  ssize_t
1697
850
    i;
1698
1699
850
  if (IsEmptyPSDLayer(layer_info) != MagickFalse)
1700
88
    return(MagickTrue);
1701
762
  if (layer_info->channels < psd_info->min_channels)
1702
33
    return(MagickFalse);
1703
729
  channel_type=RedChannel;
1704
729
  if (psd_info->min_channels >= 3)
1705
490
    channel_type|=(GreenChannel | BlueChannel);
1706
729
  if (psd_info->min_channels >= 4)
1707
20
    channel_type|=BlackChannel;
1708
729
  if (psd_info->mode == IndexedMode)
1709
0
    channel_type|=IndexChannel;
1710
729
  blob_size=(size_t) GetBlobSize(image);
1711
9.49k
  for (i=0; i < (ssize_t) layer_info->channels; i++)
1712
8.88k
  {
1713
8.88k
    PixelChannel
1714
8.88k
      channel;
1715
1716
8.88k
    if (layer_info->channel_info[i].size >= blob_size)
1717
121
      return(MagickFalse);
1718
8.76k
    if (layer_info->channel_info[i].supported == MagickFalse)
1719
3.10k
      continue;
1720
5.66k
    channel=layer_info->channel_info[i].channel;
1721
5.66k
    if ((i == 0) && (psd_info->mode == IndexedMode))
1722
0
      {
1723
0
        if (channel != RedPixelChannel)
1724
0
          return(MagickFalse);
1725
0
        channel_type&=~IndexChannel;
1726
0
      }
1727
5.66k
    if (channel == AlphaPixelChannel)
1728
257
      {
1729
257
        channel_type|=AlphaChannel;
1730
257
        continue;
1731
257
      }
1732
5.40k
    if (channel == RedPixelChannel)
1733
1.93k
      channel_type&=~RedChannel;
1734
3.46k
    else if (channel == GreenPixelChannel)
1735
555
      channel_type&=~GreenChannel;
1736
2.91k
    else if (channel == BluePixelChannel)
1737
542
      channel_type&=~BlueChannel;
1738
2.37k
    else if (channel == BlackPixelChannel)
1739
12
      channel_type&=~BlackChannel;
1740
5.40k
  }
1741
608
  if (channel_type == 0)
1742
345
    return(MagickTrue);
1743
263
  if ((channel_type == AlphaChannel) &&
1744
246
      (layer_info->channels >= psd_info->min_channels + 1))
1745
246
    return(MagickTrue);
1746
17
  return(MagickFalse);
1747
263
}
1748
1749
static void AttachPSDLayers(Image *image,LayerInfo *layer_info,
1750
  ssize_t number_layers)
1751
112
{
1752
112
  ssize_t
1753
112
    i;
1754
1755
112
  ssize_t
1756
112
    j;
1757
1758
224
  for (i=0; i < number_layers; i++)
1759
112
  {
1760
112
    if (layer_info[i].image == (Image *) NULL)
1761
2
      {
1762
2
        for (j=i; j < number_layers - 1; j++)
1763
0
          layer_info[j] = layer_info[j+1];
1764
2
        number_layers--;
1765
2
        i--;
1766
2
      }
1767
112
  }
1768
112
  if (number_layers == 0)
1769
2
    {
1770
2
      layer_info=(LayerInfo *) RelinquishMagickMemory(layer_info);
1771
2
      return;
1772
2
    }
1773
220
  for (i=0; i < number_layers; i++)
1774
110
  {
1775
110
    if (i > 0)
1776
0
      layer_info[i].image->previous=layer_info[i-1].image;
1777
110
    if (i < (number_layers-1))
1778
0
      layer_info[i].image->next=layer_info[i+1].image;
1779
110
    layer_info[i].image->page=layer_info[i].page;
1780
110
  }
1781
110
  image->next=layer_info[0].image;
1782
110
  layer_info[0].image->previous=image;
1783
110
  layer_info=(LayerInfo *) RelinquishMagickMemory(layer_info);
1784
110
}
1785
1786
static inline MagickBooleanType PSDSkipImage(const PSDInfo *psd_info,
1787
  const ImageInfo *image_info,const size_t index)
1788
400
{
1789
400
  if (psd_info->has_merged_image == MagickFalse)
1790
400
    return(MagickFalse);
1791
0
  if (image_info->number_scenes == 0)
1792
0
    return(MagickFalse);
1793
0
  if (index < image_info->scene)
1794
0
    return(MagickTrue);
1795
0
  if (index > image_info->scene+image_info->number_scenes-1)
1796
0
    return(MagickTrue);
1797
0
  return(MagickFalse);
1798
0
}
1799
1800
static inline void CheckMergedImageAlpha(const PSDInfo *psd_info,Image *image)
1801
24
{
1802
  /*
1803
    The number of layers cannot be used to determine if the merged image
1804
    contains an alpha channel. So we enable it when we think we should.
1805
  */
1806
24
  if (((psd_info->mode == GrayscaleMode) && (psd_info->channels > 1)) ||
1807
23
      ((psd_info->mode == RGBMode) && (psd_info->channels > 3)) ||
1808
22
      ((psd_info->mode == CMYKMode) && (psd_info->channels > 4)))
1809
7
    image->alpha_trait=BlendPixelTrait;
1810
24
}
1811
1812
static void ParseAdditionalInfo(LayerInfo *layer_info)
1813
290
{
1814
290
  char
1815
290
    key[5];
1816
1817
290
  size_t
1818
290
    remaining_length;
1819
1820
290
  unsigned char
1821
290
    *p;
1822
1823
290
  unsigned int
1824
290
    size;
1825
1826
290
  p=GetStringInfoDatum(layer_info->info);
1827
290
  remaining_length=GetStringInfoLength(layer_info->info);
1828
800
  while (remaining_length >= 12)
1829
659
  {
1830
    /* skip over signature */
1831
659
    p+=(ptrdiff_t) 4;
1832
659
    key[0]=(char) (*p++);
1833
659
    key[1]=(char) (*p++);
1834
659
    key[2]=(char) (*p++);
1835
659
    key[3]=(char) (*p++);
1836
659
    key[4]='\0';
1837
659
    size=(unsigned int) (*p++) << 24;
1838
659
    size|=(unsigned int) (*p++) << 16;
1839
659
    size|=(unsigned int) (*p++) << 8;
1840
659
    size|=(unsigned int) (*p++);
1841
659
    size=size & 0xffffffff;
1842
659
    remaining_length-=12;
1843
659
    if ((size_t) size > remaining_length)
1844
149
      break;
1845
510
    if (LocaleNCompare(key,"luni",sizeof(key)) == 0)
1846
0
      {
1847
0
        unsigned char
1848
0
          *name;
1849
1850
0
        unsigned int
1851
0
          length;
1852
1853
0
        length=(unsigned int) (*p++) << 24;
1854
0
        length|=(unsigned int) (*p++) << 16;
1855
0
        length|=(unsigned int) (*p++) << 8;
1856
0
        length|=(unsigned int) (*p++);
1857
0
        if (length * 2 > size - 4)
1858
0
          break;
1859
0
        if (sizeof(layer_info->name) <= length)
1860
0
          break;
1861
0
        name=layer_info->name;
1862
0
        while (length > 0)
1863
0
        {
1864
          /* Only ASCII strings are supported */
1865
0
          if (*p++ != '\0')
1866
0
            break;
1867
0
          *name++=*p++;
1868
0
          length--;
1869
0
        }
1870
0
        if (length == 0)
1871
0
          *name='\0';
1872
0
        break;
1873
0
      }
1874
510
    else
1875
510
      p+=(ptrdiff_t) size;
1876
510
    remaining_length-=(size_t) size;
1877
510
  }
1878
290
}
1879
1880
static MagickSizeType GetLayerInfoSize(const PSDInfo *psd_info,Image *image)
1881
838
{
1882
838
  char
1883
838
    type[4];
1884
1885
838
  MagickSizeType
1886
838
    size;
1887
1888
838
  ssize_t
1889
838
    count;
1890
1891
838
  size=GetPSDSize(psd_info,image);
1892
838
  if (size != 0)
1893
814
    return(size);
1894
24
  (void) ReadBlobLong(image);
1895
24
  count=ReadPSDString(image,type,4);
1896
24
  if ((count != 4) || (LocaleNCompare(type,"8BIM",4) != 0))
1897
23
    return(0);
1898
1
  count=ReadPSDString(image,type,4);
1899
1
  if ((count == 4) && ((LocaleNCompare(type,"Mt16",4) == 0) ||
1900
1
      (LocaleNCompare(type,"Mt32",4) == 0) ||
1901
1
      (LocaleNCompare(type,"Mtrn",4) == 0)))
1902
0
    {
1903
0
      size=GetPSDSize(psd_info,image);
1904
0
      if (size != 0)
1905
0
        return(0);
1906
0
      image->alpha_trait=BlendPixelTrait;
1907
0
      count=ReadPSDString(image,type,4);
1908
0
      if ((count != 4) || (LocaleNCompare(type,"8BIM",4) != 0))
1909
0
        return(0);
1910
0
      count=ReadPSDString(image,type,4);
1911
0
    }
1912
1
  if ((count == 4) && ((LocaleNCompare(type,"Lr16",4) == 0) ||
1913
1
      (LocaleNCompare(type,"Lr32",4) == 0)))
1914
0
    size=GetPSDSize(psd_info,image);
1915
1
  return(size);
1916
1
}
1917
1918
static MagickBooleanType ReadPSDLayersInternal(Image *image,
1919
  const ImageInfo *image_info,const PSDInfo *psd_info,
1920
  const MagickBooleanType skip_layers,ExceptionInfo *exception)
1921
838
{
1922
838
  char
1923
838
    type[4];
1924
1925
838
  LayerInfo
1926
838
    *layer_info;
1927
1928
838
  MagickSizeType
1929
838
    size;
1930
1931
838
  MagickBooleanType
1932
838
    status;
1933
1934
838
  ssize_t
1935
838
    count,
1936
838
    index,
1937
838
    i,
1938
838
    j,
1939
838
    number_layers;
1940
1941
838
  size=GetLayerInfoSize(psd_info,image);
1942
838
  if (size == 0)
1943
24
    {
1944
24
      CheckMergedImageAlpha(psd_info,image);
1945
24
      return(MagickTrue);
1946
24
    }
1947
1948
814
  layer_info=(LayerInfo *) NULL;
1949
814
  number_layers=(ssize_t) ReadBlobSignedShort(image);
1950
1951
814
  if (number_layers < 0)
1952
314
    {
1953
      /*
1954
        The first alpha channel in the merged result contains the
1955
        transparency data for the merged result.
1956
      */
1957
314
      number_layers=MagickAbsoluteValue(number_layers);
1958
314
      if (image->debug != MagickFalse)
1959
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1960
0
          "  negative layer count corrected for");
1961
314
      image->alpha_trait=BlendPixelTrait;
1962
314
    }
1963
1964
  /*
1965
    We only need to know if the image has an alpha channel
1966
  */
1967
814
  if (skip_layers != MagickFalse)
1968
0
    return(MagickTrue);
1969
1970
814
  if (image->debug != MagickFalse)
1971
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1972
0
      "  image contains %.20g layers",(double) number_layers);
1973
1974
814
  if (number_layers == 0)
1975
5
    ThrowBinaryException(CorruptImageError,"InvalidNumberOfLayers",
1976
814
      image->filename);
1977
1978
809
  layer_info=(LayerInfo *) AcquireQuantumMemory((size_t) number_layers,
1979
809
    sizeof(*layer_info));
1980
809
  if (layer_info == (LayerInfo *) NULL)
1981
0
    {
1982
0
      if (image->debug != MagickFalse)
1983
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1984
0
          "  allocation of LayerInfo failed");
1985
0
      ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1986
0
        image->filename);
1987
0
    }
1988
809
  (void) memset(layer_info,0,(size_t) number_layers*sizeof(*layer_info));
1989
1990
1.35k
  for (i=0; i < number_layers; i++)
1991
910
  {
1992
910
    ssize_t
1993
910
      top,
1994
910
      left,
1995
910
      bottom,
1996
910
      right;
1997
1998
910
    if (image->debug != MagickFalse)
1999
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2000
0
        "  reading layer #%.20g",(double) i+1);
2001
910
    top=(ssize_t) ReadBlobSignedLong(image);
2002
910
    left=(ssize_t) ReadBlobSignedLong(image);
2003
910
    bottom=(ssize_t) ReadBlobSignedLong(image);
2004
910
    right=(ssize_t) ReadBlobSignedLong(image);
2005
910
    if ((right < left) || (bottom < top))
2006
34
      {
2007
34
        layer_info=DestroyLayerInfo(layer_info,number_layers);
2008
34
        ThrowBinaryException(CorruptImageError,"ImproperImageHeader",
2009
34
          image->filename);
2010
0
      }
2011
876
    layer_info[i].page.y=top;
2012
876
    layer_info[i].page.x=left;
2013
876
    layer_info[i].page.width=(size_t) (right-left);
2014
876
    layer_info[i].page.height=(size_t) (bottom-top);
2015
876
    layer_info[i].channels=ReadBlobShort(image);
2016
876
    if (layer_info[i].channels > (unsigned short) MaxPSDChannels)
2017
26
      {
2018
26
        layer_info=DestroyLayerInfo(layer_info,number_layers);
2019
26
        ThrowBinaryException(CorruptImageError,"MaximumChannelsExceeded",
2020
26
          image->filename);
2021
0
      }
2022
850
    if (image->debug != MagickFalse)
2023
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2024
0
        "    offset(%.20g,%.20g), size(%.20g,%.20g), channels=%.20g",
2025
0
        (double) layer_info[i].page.x,(double) layer_info[i].page.y,
2026
0
        (double) layer_info[i].page.height,(double)
2027
0
        layer_info[i].page.width,(double) layer_info[i].channels);
2028
12.7k
    for (j=0; j < (ssize_t) layer_info[i].channels; j++)
2029
11.9k
    {
2030
11.9k
      layer_info[i].channel_info[j].supported=GetPixelChannelFromPSDIndex(
2031
11.9k
        psd_info,(ssize_t) ReadBlobSignedShort(image),
2032
11.9k
        &layer_info[i].channel_info[j].channel);
2033
11.9k
      layer_info[i].channel_info[j].size=(size_t) GetPSDSize(psd_info,
2034
11.9k
        image);
2035
11.9k
      if (image->debug != MagickFalse)
2036
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2037
0
          "    channel[%.20g]: type=%.20g, size=%.20g",(double) j,
2038
0
          (double) layer_info[i].channel_info[j].channel,
2039
0
          (double) layer_info[i].channel_info[j].size);
2040
11.9k
    }
2041
850
    if (CheckPSDChannels(image,psd_info,&layer_info[i]) == MagickFalse)
2042
171
      {
2043
171
        layer_info=DestroyLayerInfo(layer_info,number_layers);
2044
171
        ThrowBinaryException(CorruptImageError,"ImproperImageHeader",
2045
171
          image->filename);
2046
0
      }
2047
679
    count=ReadPSDString(image,type,4);
2048
679
    if ((count != 4) || (LocaleNCompare(type,"8BIM",4) != 0))
2049
56
      {
2050
56
        if (image->debug != MagickFalse)
2051
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2052
0
            "  layer type was %.4s instead of 8BIM", type);
2053
56
        layer_info=DestroyLayerInfo(layer_info,number_layers);
2054
56
        ThrowBinaryException(CorruptImageError,"ImproperImageHeader",
2055
56
          image->filename);
2056
0
      }
2057
623
    count=ReadPSDString(image,layer_info[i].blendkey,4);
2058
623
    if (count != 4)
2059
2
      {
2060
2
        layer_info=DestroyLayerInfo(layer_info,number_layers);
2061
2
        ThrowBinaryException(CorruptImageError,"ImproperImageHeader",
2062
2
          image->filename);
2063
0
      }
2064
621
    layer_info[i].opacity=(Quantum) ScaleCharToQuantum((unsigned char)
2065
621
      ReadBlobByte(image));
2066
621
    layer_info[i].clipping=(unsigned char) ReadBlobByte(image);
2067
621
    layer_info[i].flags=(unsigned char) ReadBlobByte(image);
2068
621
    layer_info[i].visible=!(layer_info[i].flags & 0x02);
2069
621
    if (image->debug != MagickFalse)
2070
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2071
0
        "   blend=%.4s, opacity=%.20g, clipping=%s, flags=%d, visible=%s",
2072
0
        layer_info[i].blendkey,(double) layer_info[i].opacity,
2073
0
        layer_info[i].clipping ? "true" : "false",layer_info[i].flags,
2074
0
        layer_info[i].visible ? "true" : "false");
2075
621
    (void) ReadBlobByte(image);  /* filler */
2076
2077
621
    size=ReadBlobLong(image);
2078
621
    if (size != 0)
2079
391
      {
2080
391
        MagickSizeType
2081
391
          combined_length,
2082
391
          length;
2083
2084
391
        if (image->debug != MagickFalse)
2085
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2086
0
            "    layer contains additional info");
2087
391
        length=ReadBlobLong(image);
2088
391
        combined_length=length+4;
2089
391
        if (length != 0)
2090
276
          {
2091
            /*
2092
              Layer mask info.
2093
            */
2094
276
            layer_info[i].mask.page.y=(ssize_t) ReadBlobSignedLong(image);
2095
276
            layer_info[i].mask.page.x=(ssize_t) ReadBlobSignedLong(image);
2096
276
            layer_info[i].mask.page.height=(size_t)
2097
276
              (ReadBlobSignedLong(image)-layer_info[i].mask.page.y);
2098
276
            layer_info[i].mask.page.width=(size_t) (
2099
276
              ReadBlobSignedLong(image)-layer_info[i].mask.page.x);
2100
276
            layer_info[i].mask.background=(unsigned char) ReadBlobByte(
2101
276
              image);
2102
276
            layer_info[i].mask.flags=(unsigned char) ReadBlobByte(image);
2103
276
            if (!(layer_info[i].mask.flags & 0x01))
2104
168
              {
2105
168
                layer_info[i].mask.page.y=layer_info[i].mask.page.y-
2106
168
                  layer_info[i].page.y;
2107
168
                layer_info[i].mask.page.x=layer_info[i].mask.page.x-
2108
168
                  layer_info[i].page.x;
2109
168
              }
2110
276
            if (image->debug != MagickFalse)
2111
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2112
0
                "      layer mask: offset(%.20g,%.20g), size(%.20g,%.20g), length=%.20g",
2113
0
                (double) layer_info[i].mask.page.x,(double)
2114
0
                layer_info[i].mask.page.y,(double)
2115
0
                layer_info[i].mask.page.width,(double)
2116
0
                layer_info[i].mask.page.height,(double) ((MagickOffsetType)
2117
0
                length)-18);
2118
            /*
2119
              Skip over the rest of the layer mask information.
2120
            */
2121
276
            if (DiscardBlobBytes(image,(MagickSizeType) (length-18)) == MagickFalse)
2122
32
              {
2123
32
                layer_info=DestroyLayerInfo(layer_info,number_layers);
2124
32
                ThrowBinaryException(CorruptImageError,
2125
32
                  "UnexpectedEndOfFile",image->filename);
2126
0
              }
2127
276
          }
2128
359
        length=ReadBlobLong(image);
2129
359
        combined_length+=length+4;
2130
359
        if (length != 0)
2131
76
          {
2132
            /*
2133
              Layer blending ranges info.
2134
            */
2135
76
            if (image->debug != MagickFalse)
2136
0
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2137
0
                "      layer blending ranges: length=%.20g",(double)
2138
0
                ((MagickOffsetType) length));
2139
76
            if (DiscardBlobBytes(image,length) == MagickFalse)
2140
9
              {
2141
9
                layer_info=DestroyLayerInfo(layer_info,number_layers);
2142
9
                ThrowBinaryException(CorruptImageError,
2143
9
                  "UnexpectedEndOfFile",image->filename);
2144
0
              }
2145
76
          }
2146
        /*
2147
          Layer name.
2148
        */
2149
350
        length=(MagickSizeType) ((unsigned char) ReadBlobByte(image));
2150
350
        combined_length+=length+1;
2151
350
        if (length > 0)
2152
51
          (void) ReadBlob(image,(size_t) length++,layer_info[i].name);
2153
350
        layer_info[i].name[length]='\0';
2154
350
        if (image->debug != MagickFalse)
2155
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2156
0
            "      layer name: %s",layer_info[i].name);
2157
350
        if ((length % 4) != 0)
2158
39
          {
2159
39
            length=4-(length % 4);
2160
39
            combined_length+=length;
2161
            /* Skip over the padding of the layer name */
2162
39
            if (DiscardBlobBytes(image,length) == MagickFalse)
2163
4
              {
2164
4
                layer_info=DestroyLayerInfo(layer_info,number_layers);
2165
4
                ThrowBinaryException(CorruptImageError,
2166
4
                  "UnexpectedEndOfFile",image->filename);
2167
0
              }
2168
39
          }
2169
346
        length=(MagickSizeType) size-combined_length;
2170
346
        if (length > 0)
2171
325
          {
2172
325
            unsigned char
2173
325
              *info;
2174
2175
325
            if (length > GetBlobSize(image))
2176
35
              {
2177
35
                layer_info=DestroyLayerInfo(layer_info,number_layers);
2178
35
                ThrowBinaryException(CorruptImageError,
2179
35
                  "InsufficientImageDataInFile",image->filename);
2180
0
              }
2181
290
            layer_info[i].info=AcquireProfileStringInfo("psd:additional-info",
2182
290
              (size_t) length,exception);
2183
290
            if (layer_info[i].info == (StringInfo*) NULL)
2184
0
              (void) SeekBlob(image,(MagickOffsetType)length,SEEK_CUR);
2185
290
            else
2186
290
              {
2187
290
                info=GetStringInfoDatum(layer_info[i].info);
2188
290
                (void) ReadBlob(image,(size_t) length,info);
2189
290
                ParseAdditionalInfo(&layer_info[i]);
2190
290
              }
2191
290
          }
2192
346
      }
2193
621
  }
2194
2195
865
  for (i=0; i < number_layers; i++)
2196
450
  {
2197
450
    if (IsEmptyPSDLayer(&layer_info[i]) != MagickFalse)
2198
20
      {
2199
20
        if (image->debug != MagickFalse)
2200
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2201
0
            "      layer data is empty");
2202
20
        if (layer_info[i].info != (StringInfo *) NULL)
2203
7
          layer_info[i].info=DestroyStringInfo(layer_info[i].info);
2204
20
        continue;
2205
20
      }
2206
2207
    /*
2208
      Allocate layered image.
2209
    */
2210
430
    layer_info[i].image=CloneImage(image,layer_info[i].page.width,
2211
430
      layer_info[i].page.height,MagickFalse,exception);
2212
430
    if (layer_info[i].image == (Image *) NULL)
2213
25
      {
2214
25
        layer_info=DestroyLayerInfo(layer_info,number_layers);
2215
25
        if (image->debug != MagickFalse)
2216
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2217
0
            "  allocation of image for layer %.20g failed",(double) i);
2218
25
        ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
2219
25
          image->filename);
2220
0
      }
2221
4.52k
    for (j=0; j < (ssize_t) layer_info[i].channels; j++)
2222
4.28k
    {
2223
4.28k
      if (layer_info[i].channel_info[j].channel == AlphaPixelChannel)
2224
164
        {
2225
164
          layer_info[i].image->alpha_trait=BlendPixelTrait;
2226
164
          break;
2227
164
        }
2228
4.28k
    }
2229
405
    if (layer_info[i].info != (StringInfo *) NULL)
2230
179
      {
2231
179
        (void) SetImageProfilePrivate(layer_info[i].image,layer_info[i].info,
2232
179
          exception);
2233
179
        layer_info[i].info=(StringInfo *) NULL;
2234
179
      }
2235
405
  }
2236
415
  if (image_info->ping != MagickFalse)
2237
1
    {
2238
1
      AttachPSDLayers(image,layer_info,number_layers);
2239
1
      return(MagickTrue);
2240
1
    }
2241
414
  status=MagickTrue;
2242
414
  index=0;
2243
525
  for (i=0; i < number_layers; i++)
2244
414
  {
2245
414
    if ((layer_info[i].image == (Image *) NULL) ||
2246
400
        (PSDSkipImage(psd_info, image_info,(size_t) ++index) != MagickFalse))
2247
14
      {
2248
102
        for (j=0; j < (ssize_t) layer_info[i].channels; j++)
2249
101
        {
2250
101
          if (DiscardBlobBytes(image,(MagickSizeType)
2251
101
              layer_info[i].channel_info[j].size) == MagickFalse)
2252
13
            {
2253
13
              layer_info=DestroyLayerInfo(layer_info,number_layers);
2254
13
              ThrowBinaryException(CorruptImageError,
2255
13
                "UnexpectedEndOfFile",image->filename);
2256
0
            }
2257
101
        }
2258
1
        continue;
2259
14
      }
2260
2261
400
    if (image->debug != MagickFalse)
2262
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2263
0
        "  reading data for layer %.20g",(double) i);
2264
2265
400
    status=ReadPSDLayer(image,image_info,psd_info,&layer_info[i],
2266
400
      exception);
2267
400
    if (status == MagickFalse)
2268
290
      break;
2269
2270
110
    status=SetImageProgress(image,LoadImagesTag,(MagickOffsetType) i,
2271
110
      (MagickSizeType) number_layers);
2272
110
    if (status == MagickFalse)
2273
0
      break;
2274
110
  }
2275
2276
401
  if (status != MagickFalse)
2277
111
    AttachPSDLayers(image,layer_info,number_layers);
2278
290
  else
2279
290
    layer_info=DestroyLayerInfo(layer_info,number_layers);
2280
2281
401
  return(status);
2282
414
}
2283
2284
ModuleExport MagickBooleanType ReadPSDLayers(Image *image,
2285
  const ImageInfo *image_info,const PSDInfo *psd_info,ExceptionInfo *exception)
2286
654
{
2287
654
  MagickBooleanType
2288
654
    status;
2289
2290
654
  status=IsRightsAuthorized(CoderPolicyDomain,ReadPolicyRights,"PSD");
2291
654
  if (status == MagickFalse)
2292
0
    return(MagickTrue);
2293
654
  return(ReadPSDLayersInternal(image,image_info,psd_info,MagickFalse,
2294
654
    exception));
2295
654
}
2296
2297
static MagickBooleanType ReadPSDMergedImage(const ImageInfo *image_info,
2298
  Image *image,const PSDInfo *psd_info,ExceptionInfo *exception)
2299
0
{
2300
0
  MagickOffsetType
2301
0
    *sizes;
2302
2303
0
  MagickBooleanType
2304
0
    status;
2305
2306
0
  PSDCompressionType
2307
0
    compression;
2308
2309
0
  ssize_t
2310
0
    i;
2311
2312
0
  if ((image_info->number_scenes != 0) && (image_info->scene != 0))
2313
0
    return(MagickTrue);
2314
0
  compression=(PSDCompressionType) ReadBlobMSBShort(image);
2315
0
  image->compression=ConvertPSDCompression(compression);
2316
2317
0
  if (compression != Raw && compression != RLE)
2318
0
    {
2319
0
      (void) ThrowMagickException(exception,GetMagickModule(),
2320
0
        TypeWarning,"CompressionNotSupported","'%.20g'",(double) compression);
2321
0
      return(MagickFalse);
2322
0
    }
2323
2324
0
  sizes=(MagickOffsetType *) NULL;
2325
0
  if (compression == RLE)
2326
0
    {
2327
0
      sizes=ReadPSDRLESizes(image,psd_info,image->rows*psd_info->channels);
2328
0
      if (sizes == (MagickOffsetType *) NULL)
2329
0
        ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
2330
0
          image->filename);
2331
0
    }
2332
2333
0
  status=SetPSDMetaChannels(image,psd_info,psd_info->channels,exception);
2334
0
  if (status != MagickFalse)
2335
0
    {
2336
0
      for (i=0; i < (ssize_t) psd_info->channels; i++)
2337
0
      {
2338
0
        PixelChannel
2339
0
          channel;
2340
2341
0
        status=GetPixelChannelFromPSDIndex(psd_info,i,&channel);
2342
0
        if (status == MagickFalse)
2343
0
          {
2344
0
            (void) ThrowMagickException(exception,GetMagickModule(),
2345
0
              CorruptImageError,"MaximumChannelsExceeded","'%.20g'",(double) i);
2346
0
            break;
2347
0
          }
2348
2349
0
        if (compression == RLE)
2350
0
          status=ReadPSDChannelRLE(image,channel,sizes+(i*(ssize_t) image->rows),
2351
0
            exception);
2352
0
        else
2353
0
          status=ReadPSDChannelRaw(image,channel,exception);
2354
2355
0
        if (status != MagickFalse)
2356
0
          status=SetImageProgress(image,LoadImagesTag,(MagickOffsetType) i,
2357
0
            psd_info->channels);
2358
2359
0
        if (status == MagickFalse)
2360
0
          break;
2361
0
      }
2362
0
    }
2363
2364
0
  if ((status != MagickFalse) && (image->colorspace == CMYKColorspace))
2365
0
    status=NegateCMYK(image,exception);
2366
2367
0
  if (status != MagickFalse)
2368
0
    status=CorrectPSDAlphaBlend(image_info,image,exception);
2369
2370
0
  sizes=(MagickOffsetType *) RelinquishMagickMemory(sizes);
2371
2372
0
  return(status);
2373
0
}
2374
2375
static Image *ReadPSDImage(const ImageInfo *image_info,ExceptionInfo *exception)
2376
272
{
2377
272
  Image
2378
272
    *image;
2379
2380
272
  MagickBooleanType
2381
272
    skip_layers;
2382
2383
272
  MagickOffsetType
2384
272
    offset;
2385
2386
272
  MagickSizeType
2387
272
    length;
2388
2389
272
  MagickBooleanType
2390
272
    status;
2391
2392
272
  PSDInfo
2393
272
    psd_info;
2394
2395
272
  ssize_t
2396
272
    i;
2397
2398
272
  size_t
2399
272
    image_list_length;
2400
2401
272
  ssize_t
2402
272
    count;
2403
2404
272
  StringInfo
2405
272
    *profile;
2406
2407
  /*
2408
    Open image file.
2409
  */
2410
272
  assert(image_info != (const ImageInfo *) NULL);
2411
272
  assert(image_info->signature == MagickCoreSignature);
2412
272
  assert(exception != (ExceptionInfo *) NULL);
2413
272
  assert(exception->signature == MagickCoreSignature);
2414
272
  if (IsEventLogging() != MagickFalse)
2415
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2416
0
      image_info->filename);
2417
272
  image=AcquireImage(image_info,exception);
2418
272
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2419
272
  if (status == MagickFalse)
2420
0
    {
2421
0
      image=DestroyImageList(image);
2422
0
      return((Image *) NULL);
2423
0
    }
2424
  /*
2425
    Read image header.
2426
  */
2427
272
  image->endian=MSBEndian;
2428
272
  count=ReadBlob(image,4,(unsigned char *) psd_info.signature);
2429
272
  psd_info.version=ReadBlobMSBShort(image);
2430
272
  if ((count != 4) || (LocaleNCompare(psd_info.signature,"8BPS",4) != 0) ||
2431
238
      ((psd_info.version != 1) && (psd_info.version != 2)))
2432
236
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2433
236
  (void) ReadBlob(image,6,psd_info.reserved);
2434
236
  psd_info.channels=ReadBlobMSBShort(image);
2435
236
  if (psd_info.channels < 1)
2436
234
    ThrowReaderException(CorruptImageError,"MissingImageChannel");
2437
234
  if (psd_info.channels > MaxPSDChannels)
2438
233
    ThrowReaderException(CorruptImageError,"MaximumChannelsExceeded");
2439
233
  psd_info.rows=ReadBlobMSBLong(image);
2440
233
  psd_info.columns=ReadBlobMSBLong(image);
2441
233
  if ((psd_info.version == 1) && ((psd_info.rows > 30000) ||
2442
146
      (psd_info.columns > 30000)))
2443
229
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2444
229
  psd_info.depth=ReadBlobMSBShort(image);
2445
229
  if ((psd_info.depth != 1) && (psd_info.depth != 8) &&
2446
21
      (psd_info.depth != 16) && (psd_info.depth != 32))
2447
224
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2448
224
  psd_info.mode=ReadBlobMSBShort(image);
2449
224
  if ((psd_info.mode == IndexedMode) && (psd_info.channels > 3))
2450
223
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2451
223
  if (image->debug != MagickFalse)
2452
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2453
0
      "  Image is %.20g x %.20g with channels=%.20g, depth=%.20g, mode=%s",
2454
0
      (double) psd_info.columns,(double) psd_info.rows,(double)
2455
0
      psd_info.channels,(double) psd_info.depth,ModeToString((PSDImageType)
2456
0
      psd_info.mode));
2457
223
  if (EOFBlob(image) != MagickFalse)
2458
222
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2459
  /*
2460
    Initialize image.
2461
  */
2462
222
  image->depth=psd_info.depth;
2463
222
  image->columns=psd_info.columns;
2464
222
  image->rows=psd_info.rows;
2465
222
  status=SetImageExtent(image,image->columns,image->rows,exception);
2466
222
  if (status == MagickFalse)
2467
1
    return(DestroyImageList(image));
2468
221
  status=ResetImagePixels(image,exception);
2469
221
  if (status == MagickFalse)
2470
0
    return(DestroyImageList(image));
2471
221
  psd_info.min_channels=3;
2472
221
  switch (psd_info.mode)
2473
221
  {
2474
9
    case LabMode:
2475
9
    {
2476
9
      (void) SetImageColorspace(image,LabColorspace,exception);
2477
9
      break;
2478
0
    }
2479
48
    case CMYKMode:
2480
48
    {
2481
48
      psd_info.min_channels=4;
2482
48
      (void) SetImageColorspace(image,CMYKColorspace,exception);
2483
48
      break;
2484
0
    }
2485
41
    case BitmapMode:
2486
92
    case GrayscaleMode:
2487
99
    case DuotoneMode:
2488
99
    {
2489
99
      if (psd_info.depth != 32)
2490
98
        {
2491
98
          status=AcquireImageColormap(image,MagickMin((size_t)
2492
98
            (psd_info.depth < 16 ? 256 : 65536), MaxColormapSize),exception);
2493
98
          if (status == MagickFalse)
2494
98
            ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2495
98
          if (image->debug != MagickFalse)
2496
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2497
0
              "  Image colormap allocated");
2498
98
        }
2499
99
      psd_info.min_channels=1;
2500
99
      (void) SetImageColorspace(image,GRAYColorspace,exception);
2501
99
      break;
2502
99
    }
2503
1
    case IndexedMode:
2504
1
    {
2505
1
      psd_info.min_channels=1;
2506
1
      break;
2507
99
    }
2508
14
    case MultichannelMode:
2509
14
    {
2510
14
      if ((psd_info.channels > 0) && (psd_info.channels < 3))
2511
8
        {
2512
8
          psd_info.min_channels=psd_info.channels;
2513
8
          (void) SetImageColorspace(image,GRAYColorspace,exception);
2514
8
        }
2515
14
      break;
2516
99
    }
2517
221
  }
2518
221
  if (psd_info.channels < psd_info.min_channels)
2519
220
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2520
  /*
2521
    Read PSD raster colormap only present for indexed and duotone images.
2522
  */
2523
220
  length=ReadBlobMSBLong(image);
2524
220
  if ((psd_info.mode == IndexedMode) && (length < 3))
2525
220
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2526
220
  if (length != 0)
2527
37
    {
2528
37
      if (image->debug != MagickFalse)
2529
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2530
0
          "  reading colormap");
2531
37
      if ((psd_info.mode == DuotoneMode) || (psd_info.depth == 32))
2532
7
        {
2533
          /*
2534
            Duotone image data;  the format of this data is undocumented.
2535
            32 bits per pixel;  the colormap is ignored.
2536
          */
2537
7
          (void) SeekBlob(image,(MagickOffsetType) length,SEEK_CUR);
2538
7
        }
2539
30
      else
2540
30
        {
2541
30
          size_t
2542
30
            number_colors;
2543
2544
          /*
2545
            Read PSD raster colormap.
2546
          */
2547
30
          number_colors=(size_t) length/3;
2548
30
          if (number_colors > 65536)
2549
28
            ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2550
28
          if (AcquireImageColormap(image,number_colors,exception) == MagickFalse)
2551
28
            ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2552
114k
          for (i=0; i < (ssize_t) image->colors; i++)
2553
114k
            image->colormap[i].red=(MagickRealType) ScaleCharToQuantum(
2554
114k
              (unsigned char) ReadBlobByte(image));
2555
114k
          for (i=0; i < (ssize_t) image->colors; i++)
2556
114k
            image->colormap[i].green=(MagickRealType) ScaleCharToQuantum(
2557
114k
              (unsigned char) ReadBlobByte(image));
2558
114k
          for (i=0; i < (ssize_t) image->colors; i++)
2559
114k
            image->colormap[i].blue=(MagickRealType) ScaleCharToQuantum(
2560
114k
              (unsigned char) ReadBlobByte(image));
2561
28
          image->alpha_trait=UndefinedPixelTrait;
2562
28
        }
2563
37
    }
2564
218
  if ((image->depth == 1) && (image->storage_class != PseudoClass))
2565
216
    ThrowReaderException(CorruptImageError, "ImproperImageHeader");
2566
216
  psd_info.has_merged_image=MagickTrue;
2567
216
  profile=(StringInfo *) NULL;
2568
216
  length=ReadBlobMSBLong(image);
2569
216
  if (length != 0)
2570
22
    {
2571
22
      unsigned char
2572
22
        *blocks;
2573
2574
      /*
2575
        Image resources block.
2576
      */
2577
22
      if (image->debug != MagickFalse)
2578
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2579
0
          "  reading image resource blocks - %.20g bytes",(double)
2580
0
          ((MagickOffsetType) length));
2581
22
      if (length > GetBlobSize(image))
2582
18
        ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
2583
18
      blocks=(unsigned char *) AcquireQuantumMemory((size_t) length,
2584
18
        sizeof(*blocks));
2585
18
      if (blocks == (unsigned char *) NULL)
2586
18
        ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2587
18
      count=ReadBlob(image,(size_t) length,blocks);
2588
18
      if ((count != (ssize_t) length) || (length < 4) ||
2589
16
          (LocaleNCompare((char *) blocks,"8BIM",4) != 0))
2590
3
        {
2591
3
          blocks=(unsigned char *) RelinquishMagickMemory(blocks);
2592
3
          ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2593
0
        }
2594
15
      profile=ParseImageResourceBlocks(&psd_info,image,blocks,(size_t) length);
2595
15
      blocks=(unsigned char *) RelinquishMagickMemory(blocks);
2596
15
    }
2597
  /*
2598
    Layer and mask block.
2599
  */
2600
209
  length=GetPSDSize(&psd_info,image);
2601
209
  if (length == 8)
2602
2
    {
2603
2
      length=ReadBlobMSBLong(image);
2604
2
      length=ReadBlobMSBLong(image);
2605
2
    }
2606
209
  offset=TellBlob(image);
2607
209
  skip_layers=MagickFalse;
2608
209
  if ((image_info->number_scenes == 1) && (image_info->scene == 0) &&
2609
0
      (psd_info.has_merged_image != MagickFalse))
2610
0
    {
2611
0
      if (image->debug != MagickFalse)
2612
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2613
0
          "  read composite only");
2614
0
      skip_layers=MagickTrue;
2615
0
    }
2616
209
  if (length == 0)
2617
25
    {
2618
25
      if (image->debug != MagickFalse)
2619
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2620
0
          "  image has no layers");
2621
25
    }
2622
184
  else
2623
184
    {
2624
184
      if (ReadPSDLayersInternal(image,image_info,&psd_info,skip_layers,exception) != MagickTrue)
2625
161
        {
2626
161
          if (profile != (StringInfo *) NULL)
2627
5
            profile=DestroyStringInfo(profile);
2628
161
          (void) CloseBlob(image);
2629
161
          image=DestroyImageList(image);
2630
161
          return((Image *) NULL);
2631
161
        }
2632
2633
      /*
2634
         Skip the rest of the layer and mask information.
2635
      */
2636
23
      (void) SeekBlob(image,offset+(MagickOffsetType) length,SEEK_SET);
2637
23
    }
2638
  /*
2639
    If we are only "pinging" the image, then we're done - so return.
2640
  */
2641
48
  if (EOFBlob(image) != MagickFalse)
2642
38
    {
2643
38
      if (profile != (StringInfo *) NULL)
2644
4
        profile=DestroyStringInfo(profile);
2645
38
      ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
2646
0
    }
2647
10
  if (image_info->ping != MagickFalse)
2648
10
    {
2649
10
      if (profile != (StringInfo *) NULL)
2650
5
        profile=DestroyStringInfo(profile);
2651
10
      (void) CloseBlob(image);
2652
10
      return(GetFirstImageInList(image));
2653
10
    }
2654
  /*
2655
    Read the precombined layer, present for PSD < 4 compatibility.
2656
  */
2657
0
  if (image->debug != MagickFalse)
2658
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2659
0
      "  reading the precombined layer");
2660
0
  image_list_length=GetImageListLength(image);
2661
0
  if ((psd_info.has_merged_image != MagickFalse) || (image_list_length == 1))
2662
0
    psd_info.has_merged_image=(MagickBooleanType) ReadPSDMergedImage(
2663
0
      image_info,image,&psd_info,exception);
2664
0
  if ((psd_info.has_merged_image == MagickFalse) && (image_list_length == 1) &&
2665
0
      (length != 0))
2666
0
    {
2667
0
      (void) SeekBlob(image,offset,SEEK_SET);
2668
0
      status=ReadPSDLayersInternal(image,image_info,&psd_info,MagickFalse,
2669
0
        exception);
2670
0
      if (status != MagickTrue)
2671
0
        {
2672
0
          if (profile != (StringInfo *) NULL)
2673
0
            profile=DestroyStringInfo(profile);
2674
0
          (void) CloseBlob(image);
2675
0
          image=DestroyImageList(image);
2676
0
          return((Image *) NULL);
2677
0
        }
2678
0
      image_list_length=GetImageListLength(image);
2679
0
    }
2680
0
  if (psd_info.has_merged_image == MagickFalse)
2681
0
    {
2682
0
      Image
2683
0
        *merged;
2684
2685
0
      if (image_list_length == 1)
2686
0
        {
2687
0
          if (profile != (StringInfo *) NULL)
2688
0
            profile=DestroyStringInfo(profile);
2689
0
          ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
2690
0
        }
2691
0
      image->background_color.alpha=(MagickRealType) TransparentAlpha;
2692
0
      image->background_color.alpha_trait=BlendPixelTrait;
2693
0
      (void) SetImageBackgroundColor(image,exception);
2694
0
      merged=MergeImageLayers(image,FlattenLayer,exception);
2695
0
      if (merged == (Image *) NULL)
2696
0
        {
2697
0
          if (profile != (StringInfo *) NULL)
2698
0
            profile=DestroyStringInfo(profile);
2699
0
          (void) CloseBlob(image);
2700
0
          image=DestroyImageList(image);
2701
0
          return((Image *) NULL);
2702
0
        }
2703
0
      ReplaceImageInList(&image,merged);
2704
0
    }
2705
0
  if (profile != (StringInfo *) NULL)
2706
0
    {
2707
0
      const char
2708
0
        *option;
2709
2710
0
      Image
2711
0
        *next;
2712
2713
0
      MagickBooleanType
2714
0
        replicate_profile;
2715
2716
0
      option=GetImageOption(image_info,"psd:replicate-profile");
2717
0
      replicate_profile=IsStringTrue(option);
2718
0
      i=0;
2719
0
      next=image;
2720
0
      while (next != (Image *) NULL)
2721
0
      {
2722
0
        if (PSDSkipImage(&psd_info,image_info,(size_t) i++) == MagickFalse)
2723
0
          {
2724
0
            (void) SetImageProfile(next,GetStringInfoName(profile),profile,
2725
0
              exception);
2726
0
            if (replicate_profile == MagickFalse)
2727
0
              break;
2728
0
          }
2729
0
        next=next->next;
2730
0
      }
2731
0
      profile=DestroyStringInfo(profile);
2732
      /*
2733
        Always replicate the color profile to all images.
2734
      */
2735
0
      if ((replicate_profile == MagickFalse) &&
2736
0
          (image->next != (Image *) NULL))
2737
0
        {
2738
0
          const StringInfo
2739
0
            *icc_profile;
2740
2741
0
          icc_profile=GetImageProfile(image,"icc");
2742
0
          if (icc_profile != (const StringInfo *) NULL)
2743
0
            {
2744
0
              next=image->next;
2745
0
              while (next != (Image *) NULL)
2746
0
              {          
2747
0
                (void) SetImageProfile(next,"icc",icc_profile,exception);
2748
0
                next=next->next;
2749
0
              }
2750
0
            }
2751
0
        }
2752
0
    }
2753
0
  if (CloseBlob(image) == MagickFalse)
2754
0
    status=MagickFalse;
2755
0
  if (status == MagickFalse)
2756
0
    return(DestroyImageList(image));
2757
0
  return(GetFirstImageInList(image));
2758
0
}
2759

2760
/*
2761
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2762
%                                                                             %
2763
%                                                                             %
2764
%                                                                             %
2765
%   R e g i s t e r P S D I m a g e                                           %
2766
%                                                                             %
2767
%                                                                             %
2768
%                                                                             %
2769
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2770
%
2771
%  RegisterPSDImage() adds properties for the PSD image format to
2772
%  the list of supported formats.  The properties include the image format
2773
%  tag, a method to read and/or write the format, whether the format
2774
%  supports the saving of more than one frame to the same file or blob,
2775
%  whether the format supports native in-memory I/O, and a brief
2776
%  description of the format.
2777
%
2778
%  The format of the RegisterPSDImage method is:
2779
%
2780
%      size_t RegisterPSDImage(void)
2781
%
2782
*/
2783
ModuleExport size_t RegisterPSDImage(void)
2784
8
{
2785
8
  MagickInfo
2786
8
    *entry;
2787
2788
8
  entry=AcquireMagickInfo("PSD","PSB","Adobe Large Document Format");
2789
8
  entry->decoder=(DecodeImageHandler *) ReadPSDImage;
2790
8
  entry->encoder=(EncodeImageHandler *) WritePSDImage;
2791
8
  entry->magick=(IsImageFormatHandler *) IsPSD;
2792
8
  entry->flags|=CoderDecoderSeekableStreamFlag;
2793
8
  entry->flags|=CoderEncoderSeekableStreamFlag;
2794
8
  (void) RegisterMagickInfo(entry);
2795
8
  entry=AcquireMagickInfo("PSD","PSD","Adobe Photoshop bitmap");
2796
8
  entry->decoder=(DecodeImageHandler *) ReadPSDImage;
2797
8
  entry->encoder=(EncodeImageHandler *) WritePSDImage;
2798
8
  entry->magick=(IsImageFormatHandler *) IsPSD;
2799
8
  entry->flags|=CoderDecoderSeekableStreamFlag;
2800
8
  entry->flags|=CoderEncoderSeekableStreamFlag;
2801
8
  (void) RegisterMagickInfo(entry);
2802
8
  return(MagickImageCoderSignature);
2803
8
}
2804

2805
/*
2806
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2807
%                                                                             %
2808
%                                                                             %
2809
%                                                                             %
2810
%   U n r e g i s t e r P S D I m a g e                                       %
2811
%                                                                             %
2812
%                                                                             %
2813
%                                                                             %
2814
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2815
%
2816
%  UnregisterPSDImage() removes format registrations made by the
2817
%  PSD module from the list of supported formats.
2818
%
2819
%  The format of the UnregisterPSDImage method is:
2820
%
2821
%      UnregisterPSDImage(void)
2822
%
2823
*/
2824
ModuleExport void UnregisterPSDImage(void)
2825
0
{
2826
0
  (void) UnregisterMagickInfo("PSB");
2827
0
  (void) UnregisterMagickInfo("PSD");
2828
0
}
2829

2830
/*
2831
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2832
%                                                                             %
2833
%                                                                             %
2834
%                                                                             %
2835
%   W r i t e P S D I m a g e                                                 %
2836
%                                                                             %
2837
%                                                                             %
2838
%                                                                             %
2839
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2840
%
2841
%  WritePSDImage() writes an image in the Adobe Photoshop encoded image format.
2842
%
2843
%  The format of the WritePSDImage method is:
2844
%
2845
%      MagickBooleanType WritePSDImage(const ImageInfo *image_info,Image *image,
2846
%        ExceptionInfo *exception)
2847
%
2848
%  A description of each parameter follows.
2849
%
2850
%    o image_info: the image info.
2851
%
2852
%    o image:  The image.
2853
%
2854
%    o exception: return any errors or warnings in this structure.
2855
%
2856
*/
2857
2858
static inline ssize_t SetPSDOffset(const PSDInfo *psd_info,Image *image,
2859
  const size_t offset)
2860
0
{
2861
0
  if (psd_info->version == 1)
2862
0
    return(WriteBlobMSBShort(image,(unsigned short) offset));
2863
0
  return(WriteBlobMSBLong(image,(unsigned int) offset));
2864
0
}
2865
2866
static inline ssize_t WritePSDOffset(const PSDInfo *psd_info,Image *image,
2867
  const MagickSizeType size,const MagickOffsetType offset)
2868
0
{
2869
0
  MagickOffsetType
2870
0
    current_offset;
2871
2872
0
  ssize_t
2873
0
    result;
2874
2875
0
  current_offset=TellBlob(image);
2876
0
  (void) SeekBlob(image,offset,SEEK_SET);
2877
0
  if (psd_info->version == 1)
2878
0
    result=WriteBlobMSBShort(image,(unsigned short) size);
2879
0
  else
2880
0
    result=WriteBlobMSBLong(image,(unsigned int) size);
2881
0
  (void) SeekBlob(image,current_offset,SEEK_SET);
2882
0
  return(result);
2883
0
}
2884
2885
static inline ssize_t SetPSDSize(const PSDInfo *psd_info,Image *image,
2886
  const MagickSizeType size)
2887
0
{
2888
0
  if (psd_info->version == 1)
2889
0
    return(WriteBlobLong(image,(unsigned int) size));
2890
0
  return(WriteBlobLongLong(image,size));
2891
0
}
2892
2893
static inline ssize_t WritePSDSize(const PSDInfo *psd_info,Image *image,
2894
  const MagickSizeType size,const MagickOffsetType offset)
2895
0
{
2896
0
  MagickOffsetType
2897
0
    current_offset;
2898
2899
0
  ssize_t
2900
0
    result;
2901
2902
0
  current_offset=TellBlob(image);
2903
0
  (void) SeekBlob(image,offset,SEEK_SET);
2904
0
  result=SetPSDSize(psd_info,image,size);
2905
0
  (void) SeekBlob(image,current_offset,SEEK_SET);
2906
0
  return(result);
2907
0
}
2908
2909
static size_t PSDPackbitsEncodeImage(Image *image,const size_t length,
2910
  const unsigned char *pixels,unsigned char *compact_pixels,
2911
  ExceptionInfo *exception)
2912
0
{
2913
0
  int
2914
0
    count;
2915
2916
0
  ssize_t
2917
0
    i,
2918
0
    j;
2919
2920
0
  unsigned char
2921
0
    *q;
2922
2923
0
  unsigned char
2924
0
    *packbits;
2925
2926
  /*
2927
    Compress pixels with Packbits encoding.
2928
  */
2929
0
  assert(image != (Image *) NULL);
2930
0
  assert(image->signature == MagickCoreSignature);
2931
0
  assert(pixels != (unsigned char *) NULL);
2932
0
  assert(compact_pixels != (unsigned char *) NULL);
2933
0
  if (IsEventLogging() != MagickFalse)
2934
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2935
0
  packbits=(unsigned char *) AcquireQuantumMemory(128UL,sizeof(*packbits));
2936
0
  if (packbits == (unsigned char *) NULL)
2937
0
    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
2938
0
      image->filename);
2939
0
  q=compact_pixels;
2940
0
  for (i=(ssize_t) length; i != 0; )
2941
0
  {
2942
0
    switch (i)
2943
0
    {
2944
0
      case 1:
2945
0
      {
2946
0
        i--;
2947
0
        *q++=(unsigned char) 0;
2948
0
        *q++=(*pixels);
2949
0
        break;
2950
0
      }
2951
0
      case 2:
2952
0
      {
2953
0
        i-=2;
2954
0
        *q++=(unsigned char) 1;
2955
0
        *q++=(*pixels);
2956
0
        *q++=pixels[1];
2957
0
        break;
2958
0
      }
2959
0
      case 3:
2960
0
      {
2961
0
        i-=3;
2962
0
        if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2)))
2963
0
          {
2964
0
            *q++=(unsigned char) ((256-3)+1);
2965
0
            *q++=(*pixels);
2966
0
            break;
2967
0
          }
2968
0
        *q++=(unsigned char) 2;
2969
0
        *q++=(*pixels);
2970
0
        *q++=pixels[1];
2971
0
        *q++=pixels[2];
2972
0
        break;
2973
0
      }
2974
0
      default:
2975
0
      {
2976
0
        if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2)))
2977
0
          {
2978
            /*
2979
              Packed run.
2980
            */
2981
0
            count=3;
2982
0
            while (((ssize_t) count < i) && (*pixels == *(pixels+count)))
2983
0
            {
2984
0
              count++;
2985
0
              if (count >= 127)
2986
0
                break;
2987
0
            }
2988
0
            i-=count;
2989
0
            *q++=(unsigned char) ((256-count)+1);
2990
0
            *q++=(*pixels);
2991
0
            pixels+=count;
2992
0
            break;
2993
0
          }
2994
        /*
2995
          Literal run.
2996
        */
2997
0
        count=0;
2998
0
        while ((*(pixels+count) != *(pixels+count+1)) ||
2999
0
               (*(pixels+count+1) != *(pixels+count+2)))
3000
0
        {
3001
0
          packbits[count+1]=pixels[count];
3002
0
          count++;
3003
0
          if (((ssize_t) count >= (i-3)) || (count >= 127))
3004
0
            break;
3005
0
        }
3006
0
        i-=count;
3007
0
        *packbits=(unsigned char) (count-1);
3008
0
        for (j=0; j <= (ssize_t) count; j++)
3009
0
          *q++=packbits[j];
3010
0
        pixels+=count;
3011
0
        break;
3012
0
      }
3013
0
    }
3014
0
  }
3015
0
  *q++=(unsigned char) 128;  /* EOD marker */
3016
0
  packbits=(unsigned char *) RelinquishMagickMemory(packbits);
3017
0
  return((size_t) (q-compact_pixels));
3018
0
}
3019
3020
static size_t WriteCompressionStart(const PSDInfo *psd_info,Image *image,
3021
  const Image *layer,const CompressionType compression,const ssize_t channels)
3022
0
{
3023
0
  size_t
3024
0
    length;
3025
3026
0
  ssize_t
3027
0
    i,
3028
0
    y;
3029
3030
0
  if (compression == RLECompression)
3031
0
    {
3032
0
      length=(size_t) WriteBlobShort(image,RLE);
3033
0
      for (i=0; i < channels; i++)
3034
0
        for (y=0; y < (ssize_t) layer->rows; y++)
3035
0
          length=(size_t) ((ssize_t) length+SetPSDOffset(psd_info,image,0));
3036
0
    }
3037
0
#ifdef MAGICKCORE_ZLIB_DELEGATE
3038
0
  else if (compression == ZipCompression)
3039
0
    length=(size_t) WriteBlobShort(image,ZipWithoutPrediction);
3040
0
#endif
3041
0
  else
3042
0
    length=(size_t) WriteBlobShort(image,Raw);
3043
0
  return(length);
3044
0
}
3045
3046
static size_t WritePSDChannel(const PSDInfo *psd_info,
3047
  const ImageInfo *image_info,Image *image,Image *layer,
3048
  const QuantumType quantum_type, unsigned char *compact_pixels,
3049
  MagickOffsetType size_offset,const MagickBooleanType separate,
3050
  const CompressionType compression,ExceptionInfo *exception)
3051
0
{
3052
0
  const Quantum
3053
0
    *p;
3054
3055
0
  MagickBooleanType
3056
0
    monochrome;
3057
3058
0
  QuantumInfo
3059
0
    *quantum_info;
3060
3061
0
  size_t
3062
0
    length;
3063
3064
0
  ssize_t
3065
0
    count,
3066
0
    i,
3067
0
    y;
3068
3069
0
  unsigned char
3070
0
    *pixels;
3071
3072
0
#ifdef MAGICKCORE_ZLIB_DELEGATE
3073
3074
0
  int
3075
0
    flush,
3076
0
    level;
3077
3078
0
  unsigned char
3079
0
    *compressed_pixels;
3080
3081
0
  z_stream
3082
0
    stream;
3083
3084
0
  compressed_pixels=(unsigned char *) NULL;
3085
0
  flush=Z_NO_FLUSH;
3086
0
#endif
3087
0
  count=0;
3088
0
  if (separate != MagickFalse)
3089
0
    {
3090
0
      size_offset=TellBlob(image)+2;
3091
0
      count+=(ssize_t) WriteCompressionStart(psd_info,image,layer,
3092
0
        compression,1);
3093
0
    }
3094
0
  if (layer->depth > 8)
3095
0
    layer->depth=16;
3096
0
  monochrome=IsImageMonochrome(image) && (image->depth == 1) ?
3097
0
    MagickTrue : MagickFalse;
3098
0
  quantum_info=AcquireQuantumInfo(image_info,layer);
3099
0
  if (quantum_info == (QuantumInfo *) NULL)
3100
0
    return(0);
3101
0
  pixels=(unsigned char *) GetQuantumPixels(quantum_info);
3102
0
#ifdef MAGICKCORE_ZLIB_DELEGATE
3103
0
  if (compression == ZipCompression)
3104
0
    {
3105
0
      compressed_pixels=(unsigned char *) AcquireQuantumMemory(
3106
0
        MagickMinBufferExtent,sizeof(*compressed_pixels));
3107
0
      if (compressed_pixels == (unsigned char *) NULL)
3108
0
        {
3109
0
          quantum_info=DestroyQuantumInfo(quantum_info);
3110
0
          return(0);
3111
0
        }
3112
0
      memset(&stream,0,sizeof(stream));
3113
0
      stream.data_type=Z_BINARY;
3114
0
      level=Z_DEFAULT_COMPRESSION;
3115
0
      if ((image_info->quality > 0 && image_info->quality < 10))
3116
0
        level=(int) image_info->quality;
3117
0
      if (deflateInit(&stream,level) != Z_OK)
3118
0
        {
3119
0
          quantum_info=DestroyQuantumInfo(quantum_info);
3120
0
          compressed_pixels=(unsigned char *) RelinquishMagickMemory(
3121
0
            compressed_pixels);
3122
0
          return(0);
3123
0
        }
3124
0
    }
3125
0
#endif
3126
0
  for (y=0; y < (ssize_t) layer->rows; y++)
3127
0
  {
3128
0
    p=GetVirtualPixels(layer,0,y,layer->columns,1,exception);
3129
0
    if (p == (const Quantum *) NULL)
3130
0
      break;
3131
0
    length=ExportQuantumPixels(layer,(CacheView *) NULL,quantum_info,
3132
0
      quantum_type,pixels,exception);
3133
0
    if (monochrome != MagickFalse)
3134
0
      for (i=0; i < (ssize_t) length; i++)
3135
0
        pixels[i]=(~pixels[i]);
3136
0
    if (compression == RLECompression)
3137
0
      {
3138
0
        length=PSDPackbitsEncodeImage(image,length,pixels,compact_pixels,
3139
0
          exception);
3140
0
        count+=WriteBlob(image,length,compact_pixels);
3141
0
        size_offset+=WritePSDOffset(psd_info,image,length,size_offset);
3142
0
      }
3143
0
#ifdef MAGICKCORE_ZLIB_DELEGATE
3144
0
    else if (compression == ZipCompression)
3145
0
      {
3146
0
        stream.avail_in=(uInt) length;
3147
0
        stream.next_in=(Bytef *) pixels;
3148
0
        if (y == (ssize_t) layer->rows-1)
3149
0
          flush=Z_FINISH;
3150
0
        do {
3151
0
            stream.avail_out=(uInt) MagickMinBufferExtent;
3152
0
            stream.next_out=(Bytef *) compressed_pixels;
3153
0
            if (deflate(&stream,flush) == Z_STREAM_ERROR)
3154
0
              break;
3155
0
            length=(size_t) MagickMinBufferExtent-stream.avail_out;
3156
0
            if (length > 0)
3157
0
              count+=WriteBlob(image,length,compressed_pixels);
3158
0
        } while (stream.avail_out == 0);
3159
0
      }
3160
0
#endif
3161
0
    else
3162
0
      count+=WriteBlob(image,length,pixels);
3163
0
  }
3164
0
#ifdef MAGICKCORE_ZLIB_DELEGATE
3165
0
  if (compression == ZipCompression)
3166
0
    {
3167
0
      (void) deflateEnd(&stream);
3168
0
      compressed_pixels=(unsigned char *) RelinquishMagickMemory(
3169
0
        compressed_pixels);
3170
0
    }
3171
0
#endif
3172
0
  quantum_info=DestroyQuantumInfo(quantum_info);
3173
0
  return((size_t) count);
3174
0
}
3175
3176
static unsigned char *AcquireCompactPixels(const Image *image,
3177
  ExceptionInfo *exception)
3178
0
{
3179
0
  size_t
3180
0
    packet_size;
3181
3182
0
  unsigned char
3183
0
    *compact_pixels;
3184
3185
0
  packet_size=image->depth > 8UL ? 2UL : 1UL;
3186
0
  compact_pixels=(unsigned char *) AcquireQuantumMemory((9*
3187
0
    image->columns)+1,packet_size*sizeof(*compact_pixels));
3188
0
  if (compact_pixels == (unsigned char *) NULL)
3189
0
    {
3190
0
      (void) ThrowMagickException(exception,GetMagickModule(),
3191
0
        ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
3192
0
    }
3193
0
  return(compact_pixels);
3194
0
}
3195
3196
static size_t WritePSDChannels(const PSDInfo *psd_info,
3197
  const ImageInfo *image_info,Image *image,Image *layer,
3198
  MagickOffsetType size_offset,const MagickBooleanType separate,
3199
  ExceptionInfo *exception)
3200
0
{
3201
0
  CompressionType
3202
0
    compression;
3203
3204
0
  Image
3205
0
    *mask;
3206
3207
0
  MagickOffsetType
3208
0
    rows_offset;
3209
3210
0
  size_t
3211
0
    channels,
3212
0
    length,
3213
0
    offset_length,
3214
0
    total_length;
3215
3216
0
  unsigned char
3217
0
    *compact_pixels;
3218
3219
0
  total_length=0;
3220
0
  offset_length=0;
3221
0
  rows_offset=0;
3222
0
  compact_pixels=(unsigned char *) NULL;
3223
0
  compression=layer->compression;
3224
0
  if (image_info->compression != UndefinedCompression)
3225
0
    compression=image_info->compression;
3226
0
  if (compression == RLECompression)
3227
0
    {
3228
0
      compact_pixels=AcquireCompactPixels(layer,exception);
3229
0
      if (compact_pixels == (unsigned char *) NULL)
3230
0
        return(0);
3231
0
    }
3232
0
  channels=1;
3233
0
  if (separate == MagickFalse)
3234
0
    {
3235
0
      if ((layer->storage_class != PseudoClass) ||
3236
0
          (IsImageGray(layer) != MagickFalse))
3237
0
        {
3238
0
          if (IsImageGray(layer) == MagickFalse)
3239
0
            channels=(size_t) (layer->colorspace == CMYKColorspace ? 4 :
3240
0
              3);
3241
0
          if (layer->alpha_trait != UndefinedPixelTrait)
3242
0
            channels++;
3243
0
        }
3244
0
      rows_offset=TellBlob(image)+2;
3245
0
      total_length+=WriteCompressionStart(psd_info,image,layer,compression,
3246
0
        (ssize_t) channels);
3247
0
      offset_length=(layer->rows*(psd_info->version == 1 ? 2 : 4));
3248
0
    }
3249
0
  size_offset+=2;
3250
0
  if ((layer->storage_class == PseudoClass) &&
3251
0
      (IsImageGray(layer) == MagickFalse))
3252
0
    {
3253
0
      length=WritePSDChannel(psd_info,image_info,image,layer,
3254
0
        IndexQuantum,compact_pixels,rows_offset,separate,compression,
3255
0
        exception);
3256
0
      if (separate != MagickFalse)
3257
0
        size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
3258
0
      else
3259
0
        rows_offset+=(MagickOffsetType) offset_length;
3260
0
      total_length+=length;
3261
0
    }
3262
0
  else
3263
0
    {
3264
0
      if (IsImageGray(layer) != MagickFalse)
3265
0
        {
3266
0
          length=WritePSDChannel(psd_info,image_info,image,layer,
3267
0
            GrayQuantum,compact_pixels,rows_offset,separate,compression,
3268
0
            exception);
3269
0
          if (separate != MagickFalse)
3270
0
            size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
3271
0
          else
3272
0
            rows_offset+=(MagickOffsetType) offset_length;
3273
0
          total_length+=length;
3274
0
        }
3275
0
      else
3276
0
        {
3277
0
          if (layer->colorspace == CMYKColorspace)
3278
0
            (void) NegateCMYK(layer,exception);
3279
3280
0
          length=WritePSDChannel(psd_info,image_info,image,layer,
3281
0
            RedQuantum,compact_pixels,rows_offset,separate,compression,
3282
0
            exception);
3283
0
          if (separate != MagickFalse)
3284
0
            size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
3285
0
          else
3286
0
            rows_offset+=(MagickOffsetType) offset_length;
3287
0
          total_length+=length;
3288
3289
0
          length=WritePSDChannel(psd_info,image_info,image,layer,
3290
0
            GreenQuantum,compact_pixels,rows_offset,separate,compression,
3291
0
            exception);
3292
0
          if (separate != MagickFalse)
3293
0
            size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
3294
0
          else
3295
0
            rows_offset+=(MagickOffsetType) offset_length;
3296
0
          total_length+=length;
3297
3298
0
          length=WritePSDChannel(psd_info,image_info,image,layer,
3299
0
            BlueQuantum,compact_pixels,rows_offset,separate,compression,
3300
0
            exception);
3301
0
          if (separate != MagickFalse)
3302
0
            size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
3303
0
          else
3304
0
            rows_offset+=(MagickOffsetType) offset_length;
3305
0
          total_length+=length;
3306
3307
0
          if (layer->colorspace == CMYKColorspace)
3308
0
            {
3309
0
              length=WritePSDChannel(psd_info,image_info,image,layer,
3310
0
                BlackQuantum,compact_pixels,rows_offset,separate,compression,
3311
0
                exception);
3312
0
              if (separate != MagickFalse)
3313
0
                size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
3314
0
              else
3315
0
                rows_offset+=(MagickOffsetType) offset_length;
3316
0
              total_length+=length;
3317
0
            }
3318
0
        }
3319
0
      if (layer->alpha_trait != UndefinedPixelTrait)
3320
0
        {
3321
0
          length=WritePSDChannel(psd_info,image_info,image,layer,
3322
0
            AlphaQuantum,compact_pixels,rows_offset,separate,compression,
3323
0
            exception);
3324
0
          if (separate != MagickFalse)
3325
0
            size_offset+=WritePSDSize(psd_info,image,length,size_offset)+2;
3326
0
          else
3327
0
            rows_offset+=(MagickOffsetType) offset_length;
3328
0
          total_length+=length;
3329
0
        }
3330
0
    }
3331
0
  compact_pixels=(unsigned char *) RelinquishMagickMemory(compact_pixels);
3332
0
  if (layer->colorspace == CMYKColorspace)
3333
0
    (void) NegateCMYK(layer,exception);
3334
0
  if (separate != MagickFalse)
3335
0
    {
3336
0
      const char
3337
0
        *property;
3338
3339
0
      property=GetImageArtifact(layer,"psd:opacity-mask");
3340
0
      if (property != (const char *) NULL)
3341
0
        {
3342
0
          mask=(Image *) GetImageRegistry(ImageRegistryType,property,
3343
0
            exception);
3344
0
          if (mask != (Image *) NULL)
3345
0
            {
3346
0
              if (compression == RLECompression)
3347
0
                {
3348
0
                  compact_pixels=AcquireCompactPixels(mask,exception);
3349
0
                  if (compact_pixels == (unsigned char *) NULL)
3350
0
                    return(0);
3351
0
                }
3352
0
              length=WritePSDChannel(psd_info,image_info,image,mask,
3353
0
                RedQuantum,compact_pixels,rows_offset,MagickTrue,compression,
3354
0
                exception);
3355
0
              (void) WritePSDSize(psd_info,image,length,size_offset);
3356
0
              total_length+=length;
3357
0
              compact_pixels=(unsigned char *) RelinquishMagickMemory(
3358
0
                compact_pixels);
3359
0
            }
3360
0
        }
3361
0
    }
3362
0
  return(total_length);
3363
0
}
3364
3365
static size_t WritePascalString(Image *image,const char *value,size_t padding)
3366
0
{
3367
0
  size_t
3368
0
    length;
3369
3370
0
  ssize_t
3371
0
    count,
3372
0
    i;
3373
3374
  /*
3375
    Max length is 255.
3376
  */
3377
0
  count=0;
3378
0
  length=(strlen(value) > 255UL ) ? 255UL : strlen(value);
3379
0
  if (length ==  0)
3380
0
    count+=WriteBlobByte(image,0);
3381
0
  else
3382
0
    {
3383
0
      count+=WriteBlobByte(image,(unsigned char) length);
3384
0
      count+=WriteBlob(image,length,(const unsigned char *) value);
3385
0
    }
3386
0
  length++;
3387
0
  if ((length % padding) == 0)
3388
0
    return((size_t) count);
3389
0
  for (i=0; i < (ssize_t) (padding-(length % padding)); i++)
3390
0
    count+=WriteBlobByte(image,0);
3391
0
  return((size_t) count);
3392
0
}
3393
3394
static void WriteResolutionResourceBlock(Image *image)
3395
0
{
3396
0
  double
3397
0
    x_resolution,
3398
0
    y_resolution;
3399
3400
0
  unsigned short
3401
0
    units;
3402
3403
0
  if (image->units == PixelsPerCentimeterResolution)
3404
0
    {
3405
0
      x_resolution=2.54*65536.0*image->resolution.x+0.5;
3406
0
      y_resolution=2.54*65536.0*image->resolution.y+0.5;
3407
0
      units=2;
3408
0
    }
3409
0
  else
3410
0
    {
3411
0
      x_resolution=65536.0*image->resolution.x+0.5;
3412
0
      y_resolution=65536.0*image->resolution.y+0.5;
3413
0
      units=1;
3414
0
    }
3415
0
  (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
3416
0
  (void) WriteBlobMSBShort(image,0x03ED);
3417
0
  (void) WriteBlobMSBShort(image,0);
3418
0
  (void) WriteBlobMSBLong(image,16); /* resource size */
3419
0
  (void) WriteBlobMSBLong(image,(unsigned int) (x_resolution+0.5));
3420
0
  (void) WriteBlobMSBShort(image,units); /* horizontal resolution unit */
3421
0
  (void) WriteBlobMSBShort(image,units); /* width unit */
3422
0
  (void) WriteBlobMSBLong(image,(unsigned int) (y_resolution+0.5));
3423
0
  (void) WriteBlobMSBShort(image,units); /* vertical resolution unit */
3424
0
  (void) WriteBlobMSBShort(image,units); /* height unit */
3425
0
}
3426
3427
static inline size_t WriteChannelSize(const PSDInfo *psd_info,Image *image,
3428
  const signed short channel)
3429
0
{
3430
0
  ssize_t
3431
0
    count;
3432
3433
0
  count=WriteBlobShort(image,(unsigned short) channel);
3434
0
  count+=SetPSDSize(psd_info,image,0);
3435
0
  return((size_t) count);
3436
0
}
3437
3438
static void RemoveICCProfileFromResourceBlock(StringInfo *bim_profile)
3439
0
{
3440
0
  const unsigned char
3441
0
    *p;
3442
3443
0
  size_t
3444
0
    length;
3445
3446
0
  unsigned char
3447
0
    *datum;
3448
3449
0
  unsigned int
3450
0
    count,
3451
0
    long_sans;
3452
3453
0
  unsigned short
3454
0
    id,
3455
0
    short_sans;
3456
3457
0
  length=GetStringInfoLength(bim_profile);
3458
0
  if (length < 16)
3459
0
    return;
3460
0
  datum=GetStringInfoDatum(bim_profile);
3461
0
  for (p=datum; (p >= datum) && (p < (datum+length-16)); )
3462
0
  {
3463
0
    unsigned char
3464
0
      *q;
3465
3466
0
    q=(unsigned char *) p;
3467
0
    if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
3468
0
      break;
3469
0
    p=PushLongPixel(MSBEndian,p,&long_sans);
3470
0
    p=PushShortPixel(MSBEndian,p,&id);
3471
0
    p=PushShortPixel(MSBEndian,p,&short_sans);
3472
0
    p=PushLongPixel(MSBEndian,p,&count);
3473
0
    if (id == 0x0000040f)
3474
0
      {
3475
0
        ssize_t
3476
0
          quantum;
3477
3478
0
        quantum=PSDQuantum(count)+12;
3479
0
        if ((quantum >= 12) && (quantum < (ssize_t) length))
3480
0
          {
3481
0
            if ((q+quantum < (datum+length-16)))
3482
0
              (void) memmove(q,q+quantum,(size_t) ((ssize_t) length-quantum-
3483
0
                (q-datum)));
3484
0
            SetStringInfoLength(bim_profile,(size_t) ((ssize_t) length-
3485
0
              quantum));
3486
0
          }
3487
0
        break;
3488
0
      }
3489
0
    p+=(ptrdiff_t) count;
3490
0
    if ((count & 0x01) != 0)
3491
0
      p++;
3492
0
  }
3493
0
}
3494
3495
static void RemoveResolutionFromResourceBlock(StringInfo *bim_profile)
3496
0
{
3497
0
  const unsigned char
3498
0
    *p;
3499
3500
0
  size_t
3501
0
    length;
3502
3503
0
  unsigned char
3504
0
    *datum;
3505
3506
0
  unsigned int
3507
0
    count,
3508
0
    long_sans;
3509
3510
0
  unsigned short
3511
0
    id,
3512
0
    short_sans;
3513
3514
0
  length=GetStringInfoLength(bim_profile);
3515
0
  if (length < 16)
3516
0
    return;
3517
0
  datum=GetStringInfoDatum(bim_profile);
3518
0
  for (p=datum; (p >= datum) && (p < (datum+length-16)); )
3519
0
  {
3520
0
    unsigned char
3521
0
      *q;
3522
3523
0
    ssize_t
3524
0
      cnt;
3525
3526
0
    q=(unsigned char *) p;
3527
0
    if (LocaleNCompare((const char *) p,"8BIM",4) != 0)
3528
0
      return;
3529
0
    p=PushLongPixel(MSBEndian,p,&long_sans);
3530
0
    p=PushShortPixel(MSBEndian,p,&id);
3531
0
    p=PushShortPixel(MSBEndian,p,&short_sans);
3532
0
    p=PushLongPixel(MSBEndian,p,&count);
3533
0
    cnt=PSDQuantum(count);
3534
0
    if (cnt < 0)
3535
0
      return;
3536
0
    if ((id == 0x000003ed) && (cnt < (ssize_t) (length-12)) &&
3537
0
        ((ssize_t) length-(cnt+12)-(q-datum)) > 0)
3538
0
      {
3539
0
        (void) memmove(q,q+cnt+12,(size_t) ((ssize_t) length-(cnt+12)-
3540
0
          (q-datum)));
3541
0
        SetStringInfoLength(bim_profile,(size_t) ((ssize_t) length-(cnt+12)));
3542
0
        break;
3543
0
      }
3544
0
    p+=(ptrdiff_t) count;
3545
0
    if ((count & 0x01) != 0)
3546
0
      p++;
3547
0
  }
3548
0
}
3549
3550
static const StringInfo *GetAdditionalInformation(const ImageInfo *image_info,
3551
  Image *image,ExceptionInfo *exception)
3552
0
{
3553
0
#define PSDKeySize 5
3554
0
#define PSDAllowedLength 36
3555
3556
0
  char
3557
0
    key[PSDKeySize];
3558
3559
  /* Whitelist of keys from: https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/ */
3560
0
  const char
3561
0
    allowed[PSDAllowedLength][PSDKeySize] = {
3562
0
      "blnc", "blwh", "brit", "brst", "clbl", "clrL", "curv", "expA", "FMsk",
3563
0
      "GdFl", "grdm", "hue ", "hue2", "infx", "knko", "lclr", "levl", "lnsr",
3564
0
      "lfx2", "luni", "lrFX", "lspf", "lyid", "lyvr", "mixr", "nvrt", "phfl",
3565
0
      "post", "PtFl", "selc", "shpa", "sn2P", "SoCo", "thrs", "tsly", "vibA"
3566
0
    },
3567
0
    *option;
3568
3569
0
  const StringInfo
3570
0
    *info;
3571
3572
0
  MagickBooleanType
3573
0
    found;
3574
3575
0
  size_t
3576
0
    i;
3577
3578
0
  size_t
3579
0
    remaining_length,
3580
0
    length;
3581
3582
0
  StringInfo
3583
0
    *profile;
3584
3585
0
  unsigned char
3586
0
    *p;
3587
3588
0
  unsigned int
3589
0
    size;
3590
3591
0
  info=GetImageProfile(image,"psd:additional-info");
3592
0
  if (info == (const StringInfo *) NULL)
3593
0
    return((const StringInfo *) NULL);
3594
0
  option=GetImageOption(image_info,"psd:additional-info");
3595
0
  if (LocaleCompare(option,"all") == 0)
3596
0
    return(info);
3597
0
  if (LocaleCompare(option,"selective") != 0)
3598
0
    {
3599
0
      profile=RemoveImageProfile(image,"psd:additional-info");
3600
0
      return(DestroyStringInfo(profile));
3601
0
    }
3602
0
  length=GetStringInfoLength(info);
3603
0
  p=GetStringInfoDatum(info);
3604
0
  remaining_length=length;
3605
0
  length=0;
3606
0
  while (remaining_length >= 12)
3607
0
  {
3608
    /* skip over signature */
3609
0
    p+=(ptrdiff_t) 4;
3610
0
    key[0]=(char) (*p++);
3611
0
    key[1]=(char) (*p++);
3612
0
    key[2]=(char) (*p++);
3613
0
    key[3]=(char) (*p++);
3614
0
    key[4]='\0';
3615
0
    size=(unsigned int) (*p++) << 24;
3616
0
    size|=(unsigned int) (*p++) << 16;
3617
0
    size|=(unsigned int) (*p++) << 8;
3618
0
    size|=(unsigned int) (*p++);
3619
0
    size=size & 0xffffffff;
3620
0
    remaining_length-=12;
3621
0
    if ((size_t) size > remaining_length)
3622
0
      return((const StringInfo *) NULL);
3623
0
    found=MagickFalse;
3624
0
    for (i=0; i < PSDAllowedLength; i++)
3625
0
    {
3626
0
      if (LocaleNCompare(key,allowed[i],PSDKeySize) != 0)
3627
0
        continue;
3628
3629
0
      found=MagickTrue;
3630
0
      break;
3631
0
    }
3632
0
    remaining_length-=(size_t) size;
3633
0
    if (found == MagickFalse)
3634
0
      {
3635
0
        if (remaining_length > 0)
3636
0
          p=(unsigned char *) memmove(p-12,p+size,remaining_length);
3637
0
        continue;
3638
0
      }
3639
0
    length+=(size_t) size+12;
3640
0
    p+=(ptrdiff_t) size;
3641
0
  }
3642
0
  profile=RemoveImageProfile(image,"psd:additional-info");
3643
0
  if (length == 0)
3644
0
    return(DestroyStringInfo(profile));
3645
0
  SetStringInfoLength(profile,(size_t) length);
3646
0
  (void) SetImageProfile(image,"psd:additional-info",info,exception);
3647
0
  return(profile);
3648
0
}
3649
3650
static MagickBooleanType WritePSDLayersInternal(Image *image,
3651
  const ImageInfo *image_info,const PSDInfo *psd_info,size_t *layers_size,
3652
  ExceptionInfo *exception)
3653
0
{
3654
0
  char
3655
0
    layer_name[MagickPathExtent];
3656
3657
0
  const char
3658
0
    *property;
3659
3660
0
  const StringInfo
3661
0
    *info;
3662
3663
0
  Image
3664
0
    *base_image,
3665
0
    *next_image;
3666
3667
0
  MagickBooleanType
3668
0
    status;
3669
3670
0
  MagickOffsetType
3671
0
    *layer_size_offsets,
3672
0
    size_offset;
3673
3674
0
  ssize_t
3675
0
    i;
3676
3677
0
  size_t
3678
0
    layer_count,
3679
0
    layer_index,
3680
0
    length,
3681
0
    name_length,
3682
0
    rounded_size,
3683
0
    size;
3684
3685
0
  assert(image != (Image *) NULL);
3686
0
  status=MagickTrue;
3687
0
  base_image=GetNextImageInList(image);
3688
0
  if (base_image == (Image *) NULL)
3689
0
    base_image=image;
3690
0
  size=0;
3691
0
  size_offset=TellBlob(image);
3692
0
  (void) SetPSDSize(psd_info,image,0);
3693
0
  layer_count=0;
3694
0
  for (next_image=base_image; next_image != NULL; )
3695
0
  {
3696
0
    layer_count++;
3697
0
    next_image=GetNextImageInList(next_image);
3698
0
  }
3699
0
  if (image->alpha_trait != UndefinedPixelTrait)
3700
0
    size+=(size_t) WriteBlobShort(image,-(unsigned short) layer_count);
3701
0
  else
3702
0
    size+=(size_t) WriteBlobShort(image,(unsigned short) layer_count);
3703
0
  layer_size_offsets=(MagickOffsetType *) AcquireQuantumMemory(
3704
0
    (size_t) layer_count,sizeof(MagickOffsetType));
3705
0
  if (layer_size_offsets == (MagickOffsetType *) NULL)
3706
0
    ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3707
0
  layer_index=0;
3708
0
  for (next_image=base_image; next_image != NULL; )
3709
0
  {
3710
0
    Image
3711
0
      *mask;
3712
3713
0
    unsigned char
3714
0
      default_color;
3715
3716
0
    unsigned short
3717
0
      channels,
3718
0
      total_channels;
3719
3720
0
    mask=(Image *) NULL;
3721
0
    property=GetImageArtifact(next_image,"psd:opacity-mask");
3722
0
    default_color=0;
3723
0
    if (property != (const char *) NULL)
3724
0
      {
3725
0
        mask=(Image *) GetImageRegistry(ImageRegistryType,property,exception);
3726
0
        default_color=(unsigned char) (strlen(property) == 9 ? 255 : 0);
3727
0
      }
3728
0
    size+=(size_t) WriteBlobSignedLong(image,(signed int) next_image->page.y);
3729
0
    size+=(size_t) WriteBlobSignedLong(image,(signed int) next_image->page.x);
3730
0
    size+=(size_t) WriteBlobSignedLong(image,(signed int) ((ssize_t)
3731
0
      next_image->page.y+(ssize_t) next_image->rows));
3732
0
    size+=(size_t) WriteBlobSignedLong(image,(signed int) ((ssize_t)
3733
0
      next_image->page.x+(ssize_t) next_image->columns));
3734
0
    channels=1;
3735
0
    if ((next_image->storage_class != PseudoClass) &&
3736
0
        (IsImageGray(next_image) == MagickFalse))
3737
0
      channels=(unsigned short) (next_image->colorspace == CMYKColorspace ? 4 :
3738
0
        3);
3739
0
    total_channels=channels;
3740
0
    if (next_image->alpha_trait != UndefinedPixelTrait)
3741
0
      total_channels++;
3742
0
    if (mask != (Image *) NULL)
3743
0
      total_channels++;
3744
0
    size+=(size_t) WriteBlobShort(image,total_channels);
3745
0
    layer_size_offsets[layer_index++]=TellBlob(image);
3746
0
    for (i=0; i < (ssize_t) channels; i++)
3747
0
      size+=(size_t) WriteChannelSize(psd_info,image,(signed short) i);
3748
0
    if (next_image->alpha_trait != UndefinedPixelTrait)
3749
0
      size+=(size_t) WriteChannelSize(psd_info,image,-1);
3750
0
    if (mask != (Image *) NULL)
3751
0
      size+=(size_t) WriteChannelSize(psd_info,image,-2);
3752
0
    size+=(size_t) WriteBlobString(image,image->endian == LSBEndian ? "MIB8" :
3753
0
      "8BIM");
3754
0
    size+=(size_t) WriteBlobString(image,
3755
0
      CompositeOperatorToPSDBlendMode(next_image));
3756
0
    property=GetImageArtifact(next_image,"psd:layer.opacity");
3757
0
    if (property != (const char *) NULL)
3758
0
      {
3759
0
        Quantum
3760
0
          opacity;
3761
3762
0
        opacity=(Quantum) StringToInteger(property);
3763
0
        size+=(size_t) WriteBlobByte(image,ScaleQuantumToChar(opacity));
3764
0
        (void) ApplyPSDLayerOpacity(next_image,opacity,MagickTrue,exception);
3765
0
      }
3766
0
    else
3767
0
      size+=(size_t) WriteBlobByte(image,255);
3768
0
    size+=(size_t) WriteBlobByte(image,0);
3769
0
    size+=(size_t) WriteBlobByte(image,(unsigned char) (next_image->compose ==
3770
0
      NoCompositeOp ? 0 : 1)); /* bit 1 = visible; */
3771
0
    size+=(size_t) WriteBlobByte(image,0);
3772
0
    info=GetAdditionalInformation(image_info,next_image,exception);
3773
0
    property=(const char *) GetImageProperty(next_image,"label",exception);
3774
0
    if (property == (const char *) NULL)
3775
0
      {
3776
0
        (void) FormatLocaleString(layer_name,MagickPathExtent,"L%.20g",
3777
0
          (double) layer_index);
3778
0
        property=layer_name;
3779
0
      }
3780
0
    name_length=strlen(property)+1;
3781
0
    if ((name_length % 4) != 0)
3782
0
      name_length+=(4-(name_length % 4));
3783
0
    if (info != (const StringInfo *) NULL)
3784
0
      name_length+=GetStringInfoLength(info);
3785
0
    name_length+=8;
3786
0
    if (mask != (Image *) NULL)
3787
0
      name_length+=20;
3788
0
    size+=(size_t) WriteBlobLong(image,(unsigned int) name_length);
3789
0
    if (mask == (Image *) NULL)
3790
0
      size+=(size_t) WriteBlobLong(image,0);
3791
0
    else
3792
0
      {
3793
0
        if (mask->compose != NoCompositeOp)
3794
0
          (void) ApplyPSDOpacityMask(next_image,mask,ScaleCharToQuantum(
3795
0
            default_color),MagickTrue,exception);
3796
0
        mask->page.y+=image->page.y;
3797
0
        mask->page.x+=image->page.x;
3798
0
        size+=(size_t) WriteBlobLong(image,20);
3799
0
        size+=(size_t) WriteBlobSignedLong(image,(signed int) mask->page.y);
3800
0
        size+=(size_t) WriteBlobSignedLong(image,(signed int) mask->page.x);
3801
0
        size+=(size_t) WriteBlobSignedLong(image,(signed int) ((ssize_t)
3802
0
          mask->rows+mask->page.y));
3803
0
        size+=(size_t) WriteBlobSignedLong(image,(signed int) ((ssize_t)
3804
0
          mask->columns+mask->page.x));
3805
0
        size+=(size_t) WriteBlobByte(image,default_color);
3806
0
        size+=(size_t) WriteBlobByte(image,(unsigned char) (mask->compose ==
3807
0
          NoCompositeOp ? 1 : 0)); /* bit 1 = layer mask disabled */
3808
0
        size+=(size_t) WriteBlobMSBShort(image,0);
3809
0
      }
3810
0
    size+=(size_t) WriteBlobLong(image,0);
3811
0
    size+=WritePascalString(image,property,4);
3812
0
    if (info != (const StringInfo *) NULL)
3813
0
      size+=(size_t) WriteBlob(image,GetStringInfoLength(info),
3814
0
        GetStringInfoDatum(info));
3815
0
    next_image=GetNextImageInList(next_image);
3816
0
  }
3817
  /*
3818
    Now the image data!
3819
  */
3820
0
  next_image=base_image;
3821
0
  layer_index=0;
3822
0
  while (next_image != NULL)
3823
0
  {
3824
0
    length=WritePSDChannels(psd_info,image_info,image,next_image,
3825
0
      layer_size_offsets[layer_index++],MagickTrue,exception);
3826
0
    if (length == 0)
3827
0
      {
3828
0
        status=MagickFalse;
3829
0
        break;
3830
0
      }
3831
0
    size+=length;
3832
0
    next_image=GetNextImageInList(next_image);
3833
0
  }
3834
  /*
3835
    Write the total size
3836
  */
3837
0
  if (layers_size != (size_t*) NULL)
3838
0
    *layers_size=size;
3839
0
  if ((size/2) != ((size+1)/2))
3840
0
    rounded_size=size+1;
3841
0
  else
3842
0
    rounded_size=size;
3843
0
  (void) WritePSDSize(psd_info,image,rounded_size,size_offset);
3844
0
  layer_size_offsets=(MagickOffsetType *) RelinquishMagickMemory(
3845
0
    layer_size_offsets);
3846
  /*
3847
    Remove the opacity mask from the registry
3848
  */
3849
0
  next_image=base_image;
3850
0
  while (next_image != (Image *) NULL)
3851
0
  {
3852
0
    property=GetImageArtifact(next_image,"psd:opacity-mask");
3853
0
    if (property != (const char *) NULL)
3854
0
      (void) DeleteImageRegistry(property);
3855
0
    next_image=GetNextImageInList(next_image);
3856
0
  }
3857
0
  return(status);
3858
0
}
3859
3860
ModuleExport MagickBooleanType WritePSDLayers(Image * image,
3861
  const ImageInfo *image_info,const PSDInfo *psd_info,ExceptionInfo *exception)
3862
0
{
3863
0
  MagickBooleanType
3864
0
    status;
3865
3866
0
  status=IsRightsAuthorized(CoderPolicyDomain,WritePolicyRights,"PSD");
3867
0
  if (status == MagickFalse)
3868
0
    return(MagickTrue);
3869
0
  return WritePSDLayersInternal(image,image_info,psd_info,(size_t*) NULL,
3870
0
    exception);
3871
0
}
3872
3873
static MagickBooleanType WritePSDImage(const ImageInfo *image_info,
3874
  Image *image,ExceptionInfo *exception)
3875
0
{
3876
0
  const StringInfo
3877
0
    *icc_profile;
3878
3879
0
  MagickBooleanType
3880
0
    status;
3881
3882
0
  PSDInfo
3883
0
    psd_info;
3884
3885
0
  ssize_t
3886
0
    i;
3887
3888
0
  size_t
3889
0
    length,
3890
0
    num_channels;
3891
3892
0
  StringInfo
3893
0
    *bim_profile;
3894
3895
  /*
3896
    Open image file.
3897
  */
3898
0
  assert(image_info != (const ImageInfo *) NULL);
3899
0
  assert(image_info->signature == MagickCoreSignature);
3900
0
  assert(image != (Image *) NULL);
3901
0
  assert(image->signature == MagickCoreSignature);
3902
0
  assert(exception != (ExceptionInfo *) NULL);
3903
0
  assert(exception->signature == MagickCoreSignature);
3904
0
  if (IsEventLogging() != MagickFalse)
3905
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3906
0
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
3907
0
  if (status == MagickFalse)
3908
0
    return(status);
3909
0
  psd_info.version=1;
3910
0
  if ((LocaleCompare(image_info->magick,"PSB") == 0) ||
3911
0
      (image->columns > 30000) || (image->rows > 30000))
3912
0
    psd_info.version=2;
3913
0
  (void) WriteBlob(image,4,(const unsigned char *) "8BPS");
3914
0
  (void) WriteBlobMSBShort(image,psd_info.version);  /* version */
3915
0
  for (i=1; i <= 6; i++)
3916
0
    (void) WriteBlobByte(image, 0);  /* 6 bytes of reserved */
3917
0
  if ((GetImageProfile(image,"icc") == (StringInfo *) NULL) &&
3918
0
      (SetImageGray(image,exception) != MagickFalse))
3919
0
    num_channels=(image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL);
3920
0
  else
3921
0
    if ((image_info->type != TrueColorType) &&
3922
0
        (image_info->type != TrueColorAlphaType) &&
3923
0
        (image->storage_class == PseudoClass))
3924
0
      num_channels=(image->alpha_trait != UndefinedPixelTrait ? 2UL : 1UL);
3925
0
    else
3926
0
      {
3927
0
        if (image->storage_class == PseudoClass)
3928
0
          (void) SetImageStorageClass(image,DirectClass,exception);
3929
0
        if (image->colorspace != CMYKColorspace)
3930
0
          num_channels=(image->alpha_trait != UndefinedPixelTrait ? 4UL : 3UL);
3931
0
        else
3932
0
          num_channels=(image->alpha_trait != UndefinedPixelTrait ? 5UL : 4UL);
3933
0
      }
3934
0
  (void) WriteBlobMSBShort(image,(unsigned short) num_channels);
3935
0
  (void) WriteBlobMSBLong(image,(unsigned int) image->rows);
3936
0
  (void) WriteBlobMSBLong(image,(unsigned int) image->columns);
3937
0
  if (IsImageGray(image) != MagickFalse)
3938
0
    {
3939
0
      MagickBooleanType
3940
0
        monochrome;
3941
3942
      /*
3943
        Write depth & mode.
3944
      */
3945
0
      monochrome=IsImageMonochrome(image) && (image->depth == 1) ?
3946
0
        MagickTrue : MagickFalse;
3947
0
      (void) WriteBlobMSBShort(image,(unsigned short)
3948
0
        (monochrome != MagickFalse ? 1 : image->depth > 8 ? 16 : 8));
3949
0
      (void) WriteBlobMSBShort(image,(unsigned short)
3950
0
        (monochrome != MagickFalse ? BitmapMode : GrayscaleMode));
3951
0
    }
3952
0
  else
3953
0
    {
3954
0
      (void) WriteBlobMSBShort(image,(unsigned short) (image->storage_class ==
3955
0
        PseudoClass ? 8 : image->depth > 8 ? 16 : 8));
3956
3957
0
      if (((image_info->colorspace != UndefinedColorspace) ||
3958
0
           (image->colorspace != CMYKColorspace)) &&
3959
0
          (image_info->colorspace != CMYKColorspace))
3960
0
        {
3961
0
          (void) TransformImageColorspace(image,sRGBColorspace,exception);
3962
0
          (void) WriteBlobMSBShort(image,(unsigned short)
3963
0
            (image->storage_class == PseudoClass ? IndexedMode : RGBMode));
3964
0
        }
3965
0
      else
3966
0
        {
3967
0
          if (image->colorspace != CMYKColorspace)
3968
0
            (void) TransformImageColorspace(image,CMYKColorspace,exception);
3969
0
          (void) WriteBlobMSBShort(image,CMYKMode);
3970
0
        }
3971
0
    }
3972
0
  if ((IsImageGray(image) != MagickFalse) ||
3973
0
      (image->storage_class == DirectClass) || (image->colors > 256))
3974
0
    (void) WriteBlobMSBLong(image,0);
3975
0
  else
3976
0
    {
3977
      /*
3978
        Write PSD raster colormap.
3979
      */
3980
0
      (void) WriteBlobMSBLong(image,768);
3981
0
      for (i=0; i < (ssize_t) image->colors; i++)
3982
0
        (void) WriteBlobByte(image,ScaleQuantumToChar(ClampToQuantum(
3983
0
          image->colormap[i].red)));
3984
0
      for ( ; i < 256; i++)
3985
0
        (void) WriteBlobByte(image,0);
3986
0
      for (i=0; i < (ssize_t) image->colors; i++)
3987
0
        (void) WriteBlobByte(image,ScaleQuantumToChar(ClampToQuantum(
3988
0
          image->colormap[i].green)));
3989
0
      for ( ; i < 256; i++)
3990
0
        (void) WriteBlobByte(image,0);
3991
0
      for (i=0; i < (ssize_t) image->colors; i++)
3992
0
        (void) WriteBlobByte(image,ScaleQuantumToChar(ClampToQuantum(
3993
0
          image->colormap[i].blue)));
3994
0
      for ( ; i < 256; i++)
3995
0
        (void) WriteBlobByte(image,0);
3996
0
    }
3997
  /*
3998
    Image resource block.
3999
  */
4000
0
  length=0;
4001
0
  bim_profile=(StringInfo *) GetImageProfile(image,"8bim");
4002
0
  icc_profile=GetImageProfile(image,"icc");
4003
0
  if (bim_profile != (StringInfo *) NULL)
4004
0
    {
4005
0
      bim_profile=CloneStringInfo(bim_profile);
4006
0
      if (icc_profile != (StringInfo *) NULL)
4007
0
        RemoveICCProfileFromResourceBlock(bim_profile);
4008
0
      RemoveResolutionFromResourceBlock(bim_profile);
4009
0
      length+=(size_t) PSDQuantum(GetStringInfoLength(bim_profile));
4010
0
    }
4011
0
  if (icc_profile != (const StringInfo *) NULL)
4012
0
    length+=(size_t) PSDQuantum(GetStringInfoLength(icc_profile))+12;
4013
0
  if ((image->resolution.x > 0.0) && (image->resolution.y > 0.0))
4014
0
    length+=28; /* size of WriteResolutionResourceBlock */
4015
0
  (void) WriteBlobMSBLong(image,(unsigned int) length);
4016
0
  if ((image->resolution.x > 0.0) && (image->resolution.y > 0.0))
4017
0
    WriteResolutionResourceBlock(image);
4018
0
  if (bim_profile != (StringInfo *) NULL)
4019
0
    {
4020
0
      (void) WriteBlob(image,GetStringInfoLength(bim_profile),
4021
0
        GetStringInfoDatum(bim_profile));
4022
0
      bim_profile=DestroyStringInfo(bim_profile);
4023
0
    }
4024
0
  if (icc_profile != (StringInfo *) NULL)
4025
0
    {
4026
0
      (void) WriteBlob(image,4,(const unsigned char *) "8BIM");
4027
0
      (void) WriteBlobMSBShort(image,0x0000040F);
4028
0
      (void) WriteBlobMSBShort(image,0);
4029
0
      (void) WriteBlobMSBLong(image,(unsigned int) GetStringInfoLength(
4030
0
        icc_profile));
4031
0
      (void) WriteBlob(image,GetStringInfoLength(icc_profile),
4032
0
        GetStringInfoDatum(icc_profile));
4033
0
      if ((ssize_t) GetStringInfoLength(icc_profile) != PSDQuantum(GetStringInfoLength(icc_profile)))
4034
0
        (void) WriteBlobByte(image,0);
4035
0
    }
4036
0
  if (status != MagickFalse)
4037
0
    {
4038
0
      const char
4039
0
        *option;
4040
4041
0
      CompressionType
4042
0
        compression;
4043
4044
0
      MagickOffsetType
4045
0
        size_offset;
4046
4047
0
      size_t
4048
0
        size = 0;
4049
4050
0
      size_offset=TellBlob(image);
4051
0
      (void) SetPSDSize(&psd_info,image,0);
4052
0
      option=GetImageOption(image_info,"psd:write-layers");
4053
0
      if (IsStringFalse(option) != MagickTrue)
4054
0
        {
4055
0
          status=WritePSDLayersInternal(image,image_info,&psd_info,&size,
4056
0
            exception);
4057
0
          (void) WritePSDSize(&psd_info,image,size+
4058
0
            (psd_info.version == 1 ? 8 : 12),size_offset);
4059
0
          (void) WriteBlobMSBLong(image,0);  /* user mask data */
4060
0
        }
4061
      /*
4062
        Write composite image.
4063
      */
4064
0
      compression=image->compression;
4065
0
      if (image_info->compression != UndefinedCompression)
4066
0
        image->compression=image_info->compression;
4067
0
      if (image->compression == ZipCompression)
4068
0
        image->compression=RLECompression;
4069
0
      if (WritePSDChannels(&psd_info,image_info,image,image,0,MagickFalse,
4070
0
          exception) == 0)
4071
0
        status=MagickFalse;
4072
0
      image->compression=compression;
4073
0
    }
4074
0
  if (CloseBlob(image) == MagickFalse)
4075
0
    status=MagickFalse;
4076
0
  return(status);
4077
0
}