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