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