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