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