Coverage Report

Created: 2026-07-20 07:19

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