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