• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                        TTTTT  IIIII  FFFFF  FFFFF                           %
7 %                          T      I    F      F                               %
8 %                          T      I    FFF    FFF                             %
9 %                          T      I    F      F                               %
10 %                          T    IIIII  F      F                               %
11 %                                                                             %
12 %                                                                             %
13 %                        Read/Write TIFF Image Format                         %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                   Cristy                                    %
17 %                                 July 1992                                   %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    https://imagemagick.org/script/license.php                               %
27 %                                                                             %
28 %  Unless required by applicable law or agreed to in writing, software        %
29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31 %  See the License for the specific language governing permissions and        %
32 %  limitations under the License.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38 
39 /*
40   Include declarations.
41 */
42 #ifdef __VMS
43 #define JPEG_SUPPORT 1
44 #endif
45 #include "MagickCore/studio.h"
46 #include "MagickCore/artifact.h"
47 #include "MagickCore/attribute.h"
48 #include "MagickCore/blob.h"
49 #include "MagickCore/blob-private.h"
50 #include "MagickCore/cache.h"
51 #include "MagickCore/channel.h"
52 #include "MagickCore/color.h"
53 #include "MagickCore/color-private.h"
54 #include "MagickCore/colormap.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/geometry.h"
62 #include "MagickCore/image.h"
63 #include "MagickCore/image-private.h"
64 #include "MagickCore/list.h"
65 #include "MagickCore/log.h"
66 #include "MagickCore/magick.h"
67 #include "MagickCore/memory_.h"
68 #include "MagickCore/memory-private.h"
69 #include "MagickCore/module.h"
70 #include "MagickCore/monitor.h"
71 #include "MagickCore/monitor-private.h"
72 #include "MagickCore/option.h"
73 #include "MagickCore/pixel-accessor.h"
74 #include "MagickCore/pixel-private.h"
75 #include "MagickCore/property.h"
76 #include "MagickCore/quantum.h"
77 #include "MagickCore/quantum-private.h"
78 #include "MagickCore/profile.h"
79 #include "MagickCore/resize.h"
80 #include "MagickCore/resource_.h"
81 #include "MagickCore/semaphore.h"
82 #include "MagickCore/splay-tree.h"
83 #include "MagickCore/static.h"
84 #include "MagickCore/statistic.h"
85 #include "MagickCore/string_.h"
86 #include "MagickCore/string-private.h"
87 #include "MagickCore/thread_.h"
88 #include "MagickCore/token.h"
89 #include "MagickCore/utility.h"
90 #include "psd-private.h"
91 #if defined(MAGICKCORE_TIFF_DELEGATE)
92 # if defined(MAGICKCORE_HAVE_TIFFCONF_H)
93 #  include <tiffconf.h>
94 # endif
95 # include <tiff.h>
96 # include <tiffio.h>
97 # if !defined(COMPRESSION_ADOBE_DEFLATE)
98 #  define COMPRESSION_ADOBE_DEFLATE  8
99 # endif
100 # if !defined(PREDICTOR_HORIZONTAL)
101 # define PREDICTOR_HORIZONTAL  2
102 # endif
103 # if !defined(TIFFTAG_COPYRIGHT)
104 #  define TIFFTAG_COPYRIGHT  33432
105 # endif
106 # if !defined(TIFFTAG_OPIIMAGEID)
107 #  define TIFFTAG_OPIIMAGEID  32781
108 # endif
109 # if defined(COMPRESSION_ZSTD) && defined(MAGICKCORE_ZSTD_DELEGATE)
110 #   include <zstd.h>
111 # endif
112 
113 #if defined(MAGICKCORE_HAVE_STDINT_H) && (TIFFLIB_VERSION >= 20201219)
114 #  undef uint16
115 #  define uint16  uint16_t
116 #  undef uint32
117 #  define uint32  uint32_t
118 #endif
119 
120 /*
121   Typedef declarations.
122 */
123 typedef enum
124 {
125   ReadYCCKMethod,
126   ReadStripMethod,
127   ReadTileMethod,
128   ReadGenericMethod
129 } TIFFMethodType;
130 
131 typedef struct _PhotoshopProfile
132 {
133   StringInfo
134     *data;
135 
136   MagickOffsetType
137     offset;
138 
139   size_t
140     length,
141     extent,
142     quantum;
143 } PhotoshopProfile;
144 
145 /*
146   Global declarations.
147 */
148 static MagickThreadKey
149   tiff_exception;
150 
151 static SemaphoreInfo
152   *tiff_semaphore = (SemaphoreInfo *) NULL;
153 
154 static TIFFErrorHandler
155   error_handler,
156   warning_handler;
157 
158 static volatile MagickBooleanType
159   instantiate_key = MagickFalse;
160 
161 /*
162   Forward declarations.
163 */
164 static Image *
165   ReadTIFFImage(const ImageInfo *,ExceptionInfo *);
166 
167 static MagickBooleanType
168   WriteGROUP4Image(const ImageInfo *,Image *,ExceptionInfo *),
169   WritePTIFImage(const ImageInfo *,Image *,ExceptionInfo *),
170   WriteTIFFImage(const ImageInfo *,Image *,ExceptionInfo *);
171 
TIFFSeekCustomStream(const MagickOffsetType offset,const int whence,void * user_data)172 static MagickOffsetType TIFFSeekCustomStream(const MagickOffsetType offset,
173   const int whence,void *user_data)
174 {
175   PhotoshopProfile
176     *profile;
177 
178   profile=(PhotoshopProfile *) user_data;
179   switch (whence)
180   {
181     case SEEK_SET:
182     default:
183     {
184       if (offset < 0)
185         return(-1);
186       profile->offset=offset;
187       break;
188     }
189     case SEEK_CUR:
190     {
191       if (((offset > 0) && (profile->offset > (MAGICK_SSIZE_MAX-offset))) ||
192           ((offset < 0) && (profile->offset < (MAGICK_SSIZE_MIN-offset))))
193         {
194           errno=EOVERFLOW;
195           return(-1);
196         }
197       if ((profile->offset+offset) < 0)
198         return(-1);
199       profile->offset+=offset;
200       break;
201     }
202     case SEEK_END:
203     {
204       if (((MagickOffsetType) profile->length+offset) < 0)
205         return(-1);
206       profile->offset=profile->length+offset;
207       break;
208     }
209   }
210 
211   return(profile->offset);
212 }
213 
TIFFTellCustomStream(void * user_data)214 static MagickOffsetType TIFFTellCustomStream(void *user_data)
215 {
216   PhotoshopProfile
217     *profile;
218 
219   profile=(PhotoshopProfile *) user_data;
220   return(profile->offset);
221 }
222 
InitPSDInfo(const Image * image,PSDInfo * info)223 static void InitPSDInfo(const Image *image,PSDInfo *info)
224 {
225   (void) memset(info,0,sizeof(*info));
226   info->version=1;
227   info->columns=image->columns;
228   info->rows=image->rows;
229   info->mode=10; /* Set the mode to a value that won't change the colorspace */
230   info->channels=1U;
231   info->min_channels=1U;
232   info->has_merged_image=MagickFalse;
233   if (image->storage_class == PseudoClass)
234     info->mode=2; /* indexed mode */
235   else
236     {
237       info->channels=(unsigned short) image->number_channels;
238       info->min_channels=info->channels;
239       if (image->alpha_trait == BlendPixelTrait)
240         info->min_channels--;
241     }
242 }
243 #endif
244 
245 /*
246 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
247 %                                                                             %
248 %                                                                             %
249 %                                                                             %
250 %   I s T I F F                                                               %
251 %                                                                             %
252 %                                                                             %
253 %                                                                             %
254 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
255 %
256 %  IsTIFF() returns MagickTrue if the image format type, identified by the
257 %  magick string, is TIFF.
258 %
259 %  The format of the IsTIFF method is:
260 %
261 %      MagickBooleanType IsTIFF(const unsigned char *magick,const size_t length)
262 %
263 %  A description of each parameter follows:
264 %
265 %    o magick: compare image format pattern against these bytes.
266 %
267 %    o length: Specifies the length of the magick string.
268 %
269 */
IsTIFF(const unsigned char * magick,const size_t length)270 static MagickBooleanType IsTIFF(const unsigned char *magick,const size_t length)
271 {
272   if (length < 4)
273     return(MagickFalse);
274   if (memcmp(magick,"\115\115\000\052",4) == 0)
275     return(MagickTrue);
276   if (memcmp(magick,"\111\111\052\000",4) == 0)
277     return(MagickTrue);
278 #if defined(TIFF_VERSION_BIG)
279   if (length < 8)
280     return(MagickFalse);
281   if (memcmp(magick,"\115\115\000\053\000\010\000\000",8) == 0)
282     return(MagickTrue);
283   if (memcmp(magick,"\111\111\053\000\010\000\000\000",8) == 0)
284     return(MagickTrue);
285 #endif
286   return(MagickFalse);
287 }
288 
289 #if defined(MAGICKCORE_TIFF_DELEGATE)
290 /*
291 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
292 %                                                                             %
293 %                                                                             %
294 %                                                                             %
295 %   R e a d G R O U P 4 I m a g e                                             %
296 %                                                                             %
297 %                                                                             %
298 %                                                                             %
299 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
300 %
301 %  ReadGROUP4Image() reads a raw CCITT Group 4 image file and returns it.  It
302 %  allocates the memory necessary for the new Image structure and returns a
303 %  pointer to the new image.
304 %
305 %  The format of the ReadGROUP4Image method is:
306 %
307 %      Image *ReadGROUP4Image(const ImageInfo *image_info,
308 %        ExceptionInfo *exception)
309 %
310 %  A description of each parameter follows:
311 %
312 %    o image_info: the image info.
313 %
314 %    o exception: return any errors or warnings in this structure.
315 %
316 */
317 
WriteLSBLong(FILE * file,const unsigned int value)318 static inline size_t WriteLSBLong(FILE *file,const unsigned int value)
319 {
320   unsigned char
321     buffer[4];
322 
323   buffer[0]=(unsigned char) value;
324   buffer[1]=(unsigned char) (value >> 8);
325   buffer[2]=(unsigned char) (value >> 16);
326   buffer[3]=(unsigned char) (value >> 24);
327   return(fwrite(buffer,1,4,file));
328 }
329 
ReadGROUP4Image(const ImageInfo * image_info,ExceptionInfo * exception)330 static Image *ReadGROUP4Image(const ImageInfo *image_info,
331   ExceptionInfo *exception)
332 {
333   char
334     filename[MagickPathExtent];
335 
336   FILE
337     *file;
338 
339   Image
340     *image;
341 
342   ImageInfo
343     *read_info;
344 
345   int
346     c,
347     unique_file;
348 
349   MagickBooleanType
350     status;
351 
352   size_t
353     length;
354 
355   ssize_t
356     offset,
357     strip_offset;
358 
359   /*
360     Open image file.
361   */
362   assert(image_info != (const ImageInfo *) NULL);
363   assert(image_info->signature == MagickCoreSignature);
364   if (image_info->debug != MagickFalse)
365     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
366       image_info->filename);
367   assert(exception != (ExceptionInfo *) NULL);
368   assert(exception->signature == MagickCoreSignature);
369   image=AcquireImage(image_info,exception);
370   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
371   if (status == MagickFalse)
372     {
373       image=DestroyImageList(image);
374       return((Image *) NULL);
375     }
376   /*
377     Write raw CCITT Group 4 wrapped as a TIFF image file.
378   */
379   file=(FILE *) NULL;
380   unique_file=AcquireUniqueFileResource(filename);
381   if (unique_file != -1)
382     file=fdopen(unique_file,"wb");
383   if ((unique_file == -1) || (file == (FILE *) NULL))
384     ThrowImageException(FileOpenError,"UnableToCreateTemporaryFile");
385   length=fwrite("\111\111\052\000\010\000\000\000\016\000",1,10,file);
386   if (length != 10)
387     ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
388   length=fwrite("\376\000\003\000\001\000\000\000\000\000\000\000",1,12,file);
389   length=fwrite("\000\001\004\000\001\000\000\000",1,8,file);
390   length=WriteLSBLong(file,(unsigned int) image->columns);
391   length=fwrite("\001\001\004\000\001\000\000\000",1,8,file);
392   length=WriteLSBLong(file,(unsigned int) image->rows);
393   length=fwrite("\002\001\003\000\001\000\000\000\001\000\000\000",1,12,file);
394   length=fwrite("\003\001\003\000\001\000\000\000\004\000\000\000",1,12,file);
395   length=fwrite("\006\001\003\000\001\000\000\000\000\000\000\000",1,12,file);
396   length=fwrite("\021\001\003\000\001\000\000\000",1,8,file);
397   strip_offset=10+(12*14)+4+8;
398   length=WriteLSBLong(file,(unsigned int) strip_offset);
399   length=fwrite("\022\001\003\000\001\000\000\000",1,8,file);
400   length=WriteLSBLong(file,(unsigned int) image_info->orientation);
401   length=fwrite("\025\001\003\000\001\000\000\000\001\000\000\000",1,12,file);
402   length=fwrite("\026\001\004\000\001\000\000\000",1,8,file);
403   length=WriteLSBLong(file,(unsigned int) image->rows);
404   length=fwrite("\027\001\004\000\001\000\000\000\000\000\000\000",1,12,file);
405   offset=(ssize_t) ftell(file)-4;
406   length=fwrite("\032\001\005\000\001\000\000\000",1,8,file);
407   length=WriteLSBLong(file,(unsigned int) (strip_offset-8));
408   length=fwrite("\033\001\005\000\001\000\000\000",1,8,file);
409   length=WriteLSBLong(file,(unsigned int) (strip_offset-8));
410   length=fwrite("\050\001\003\000\001\000\000\000\002\000\000\000",1,12,file);
411   length=fwrite("\000\000\000\000",1,4,file);
412   length=WriteLSBLong(file,(unsigned int) image->resolution.x);
413   length=WriteLSBLong(file,1);
414   status=MagickTrue;
415   for (length=0; (c=ReadBlobByte(image)) != EOF; length++)
416     if (fputc(c,file) != c)
417       status=MagickFalse;
418   offset=(ssize_t) fseek(file,(ssize_t) offset,SEEK_SET);
419   length=WriteLSBLong(file,(unsigned int) length);
420   if (ferror(file) != 0)
421     {
422       (void) fclose(file);
423       ThrowImageException(FileOpenError,"UnableToCreateTemporaryFile");
424     }
425   (void) fclose(file);
426   (void) CloseBlob(image);
427   image=DestroyImage(image);
428   /*
429     Read TIFF image.
430   */
431   read_info=CloneImageInfo((ImageInfo *) NULL);
432   (void) FormatLocaleString(read_info->filename,MagickPathExtent,"%s",filename);
433   image=ReadTIFFImage(read_info,exception);
434   read_info=DestroyImageInfo(read_info);
435   if (image != (Image *) NULL)
436     {
437       (void) CopyMagickString(image->filename,image_info->filename,
438         MagickPathExtent);
439       (void) CopyMagickString(image->magick_filename,image_info->filename,
440         MagickPathExtent);
441       (void) CopyMagickString(image->magick,"GROUP4",MagickPathExtent);
442     }
443   (void) RelinquishUniqueFileResource(filename);
444   if (status == MagickFalse)
445     image=DestroyImage(image);
446   return(image);
447 }
448 #endif
449 
450 #if defined(MAGICKCORE_TIFF_DELEGATE)
451 /*
452 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
453 %                                                                             %
454 %                                                                             %
455 %                                                                             %
456 %   R e a d T I F F I m a g e                                                 %
457 %                                                                             %
458 %                                                                             %
459 %                                                                             %
460 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
461 %
462 %  ReadTIFFImage() reads a Tagged image file and returns it.  It allocates the
463 %  memory necessary for the new Image structure and returns a pointer to the
464 %  new image.
465 %
466 %  The format of the ReadTIFFImage method is:
467 %
468 %      Image *ReadTIFFImage(const ImageInfo *image_info,
469 %        ExceptionInfo *exception)
470 %
471 %  A description of each parameter follows:
472 %
473 %    o image_info: the image info.
474 %
475 %    o exception: return any errors or warnings in this structure.
476 %
477 */
478 
ClampYCC(double value)479 static inline unsigned char ClampYCC(double value)
480 {
481   value=255.0-value;
482   if (value < 0.0)
483     return((unsigned char)0);
484   if (value > 255.0)
485     return((unsigned char)255);
486   return((unsigned char)(value));
487 }
488 
DecodeLabImage(Image * image,ExceptionInfo * exception)489 static MagickBooleanType DecodeLabImage(Image *image,ExceptionInfo *exception)
490 {
491   CacheView
492     *image_view;
493 
494   MagickBooleanType
495     status;
496 
497   ssize_t
498     y;
499 
500   status=MagickTrue;
501   image_view=AcquireAuthenticCacheView(image,exception);
502   for (y=0; y < (ssize_t) image->rows; y++)
503   {
504     Quantum
505       *magick_restrict q;
506 
507     ssize_t
508       x;
509 
510     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
511     if (q == (Quantum *) NULL)
512       {
513         status=MagickFalse;
514         break;
515       }
516     for (x=0; x < (ssize_t) image->columns; x++)
517     {
518       double
519         a,
520         b;
521 
522       a=QuantumScale*GetPixela(image,q)+0.5;
523       if (a > 1.0)
524         a-=1.0;
525       b=QuantumScale*GetPixelb(image,q)+0.5;
526       if (b > 1.0)
527         b-=1.0;
528       SetPixela(image,QuantumRange*a,q);
529       SetPixelb(image,QuantumRange*b,q);
530       q+=GetPixelChannels(image);
531     }
532     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
533       {
534         status=MagickFalse;
535         break;
536       }
537   }
538   image_view=DestroyCacheView(image_view);
539   return(status);
540 }
541 
ReadProfile(Image * image,const char * name,const unsigned char * datum,ssize_t length,ExceptionInfo * exception)542 static MagickBooleanType ReadProfile(Image *image,const char *name,
543   const unsigned char *datum,ssize_t length,ExceptionInfo *exception)
544 {
545   MagickBooleanType
546     status;
547 
548   StringInfo
549     *profile;
550 
551   if (length < 4)
552     return(MagickFalse);
553   profile=BlobToStringInfo(datum,(size_t) length);
554   if (profile == (StringInfo *) NULL)
555     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
556       image->filename);
557   status=SetImageProfile(image,name,profile,exception);
558   profile=DestroyStringInfo(profile);
559   if (status == MagickFalse)
560     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
561       image->filename);
562   return(MagickTrue);
563 }
564 
565 #if defined(__cplusplus) || defined(c_plusplus)
566 extern "C" {
567 #endif
568 
TIFFCloseBlob(thandle_t image)569 static int TIFFCloseBlob(thandle_t image)
570 {
571   (void) CloseBlob((Image *) image);
572   return(0);
573 }
574 
575 static void TIFFErrors(const char *,const char *,va_list)
576   magick_attribute((__format__ (__printf__,2,0)));
577 
TIFFErrors(const char * module,const char * format,va_list error)578 static void TIFFErrors(const char *module,const char *format,va_list error)
579 {
580   char
581     message[MagickPathExtent];
582 
583   ExceptionInfo
584     *exception;
585 
586 #if defined(MAGICKCORE_HAVE_VSNPRINTF)
587   (void) vsnprintf(message,MagickPathExtent-2,format,error);
588 #else
589   (void) vsprintf(message,format,error);
590 #endif
591   message[MagickPathExtent-2]='\0';
592   (void) ConcatenateMagickString(message,".",MagickPathExtent);
593   exception=(ExceptionInfo *) GetMagickThreadValue(tiff_exception);
594   if (exception != (ExceptionInfo *) NULL)
595     (void) ThrowMagickException(exception,GetMagickModule(),CoderError,message,
596       "`%s'",module);
597 }
598 
TIFFGetBlobSize(thandle_t image)599 static toff_t TIFFGetBlobSize(thandle_t image)
600 {
601   return((toff_t) GetBlobSize((Image *) image));
602 }
603 
TIFFGetProfiles(TIFF * tiff,Image * image,ExceptionInfo * exception)604 static MagickBooleanType TIFFGetProfiles(TIFF *tiff,Image *image,
605   ExceptionInfo *exception)
606 {
607   MagickBooleanType
608     status;
609 
610   uint32
611     length = 0;
612 
613   unsigned char
614     *profile = (unsigned char *) NULL;
615 
616   status=MagickTrue;
617 #if defined(TIFFTAG_ICCPROFILE)
618   if ((TIFFGetField(tiff,TIFFTAG_ICCPROFILE,&length,&profile) == 1) &&
619       (profile != (unsigned char *) NULL))
620     status=ReadProfile(image,"icc",profile,(ssize_t) length,exception);
621 #endif
622 #if defined(TIFFTAG_PHOTOSHOP)
623   if ((TIFFGetField(tiff,TIFFTAG_PHOTOSHOP,&length,&profile) == 1) &&
624       (profile != (unsigned char *) NULL))
625     status=ReadProfile(image,"8bim",profile,(ssize_t) length,exception);
626 #endif
627 #if defined(TIFFTAG_RICHTIFFIPTC) && (TIFFLIB_VERSION >= 20191103)
628   if ((TIFFGetField(tiff,TIFFTAG_RICHTIFFIPTC,&length,&profile) == 1) &&
629       (profile != (unsigned char *) NULL))
630     {
631       const TIFFField
632         *field;
633 
634       field=TIFFFieldWithTag(tiff,TIFFTAG_RICHTIFFIPTC);
635       if (TIFFFieldDataType(field) == TIFF_LONG)
636         {
637           if (TIFFIsByteSwapped(tiff) != 0)
638             TIFFSwabArrayOfLong((uint32 *) profile,(size_t) length);
639           status=ReadProfile(image,"iptc",profile,4L*length,exception);
640         }
641       else
642         status=ReadProfile(image,"iptc",profile,length,exception);
643     }
644 #endif
645 #if defined(TIFFTAG_XMLPACKET)
646   if ((TIFFGetField(tiff,TIFFTAG_XMLPACKET,&length,&profile) == 1) &&
647       (profile != (unsigned char *) NULL))
648     {
649       StringInfo
650         *dng;
651 
652       status=ReadProfile(image,"xmp",profile,(ssize_t) length,exception);
653       dng=BlobToStringInfo(profile,length);
654       if (dng != (StringInfo *) NULL)
655         {
656           const char
657             *target = "dc:format=\"image/dng\"";
658 
659           if (strstr((char *) GetStringInfoDatum(dng),target) != (char *) NULL)
660             (void) CopyMagickString(image->magick,"DNG",MagickPathExtent);
661           dng=DestroyStringInfo(dng);
662         }
663     }
664 #endif
665   if ((TIFFGetField(tiff,34118,&length,&profile) == 1) &&
666       (profile != (unsigned char *) NULL))
667     status=ReadProfile(image,"tiff:34118",profile,(ssize_t) length,
668       exception);
669   if ((TIFFGetField(tiff,37724,&length,&profile) == 1) &&
670       (profile != (unsigned char *) NULL))
671     status=ReadProfile(image,"tiff:37724",profile,(ssize_t) length,exception);
672   return(status);
673 }
674 
TIFFGetProperties(TIFF * tiff,Image * image,ExceptionInfo * exception)675 static MagickBooleanType TIFFGetProperties(TIFF *tiff,Image *image,
676   ExceptionInfo *exception)
677 {
678   char
679     message[MagickPathExtent],
680     *text;
681 
682   MagickBooleanType
683     status;
684 
685   uint32
686     count,
687     type;
688 
689   text=(char *) NULL;
690   status=MagickTrue;
691   if ((TIFFGetField(tiff,TIFFTAG_ARTIST,&text) == 1) &&
692       (text != (char *) NULL))
693     status=SetImageProperty(image,"tiff:artist",text,exception);
694   if ((TIFFGetField(tiff,TIFFTAG_COPYRIGHT,&text) == 1) &&
695       (text != (char *) NULL))
696     status=SetImageProperty(image,"tiff:copyright",text,exception);
697   if ((TIFFGetField(tiff,TIFFTAG_DATETIME,&text) == 1) &&
698       (text != (char *) NULL))
699     status=SetImageProperty(image,"tiff:timestamp",text,exception);
700   if ((TIFFGetField(tiff,TIFFTAG_DOCUMENTNAME,&text) == 1) &&
701       (text != (char *) NULL))
702     status=SetImageProperty(image,"tiff:document",text,exception);
703   if ((TIFFGetField(tiff,TIFFTAG_HOSTCOMPUTER,&text) == 1) &&
704       (text != (char *) NULL))
705     status=SetImageProperty(image,"tiff:hostcomputer",text,exception);
706   if ((TIFFGetField(tiff,TIFFTAG_IMAGEDESCRIPTION,&text) == 1) &&
707       (text != (char *) NULL))
708     status=SetImageProperty(image,"comment",text,exception);
709   if ((TIFFGetField(tiff,TIFFTAG_MAKE,&text) == 1) &&
710       (text != (char *) NULL))
711     status=SetImageProperty(image,"tiff:make",text,exception);
712   if ((TIFFGetField(tiff,TIFFTAG_MODEL,&text) == 1) &&
713       (text != (char *) NULL))
714     status=SetImageProperty(image,"tiff:model",text,exception);
715   if ((TIFFGetField(tiff,TIFFTAG_OPIIMAGEID,&count,&text) == 1) &&
716       (text != (char *) NULL))
717     {
718       if (count >= MagickPathExtent)
719         count=MagickPathExtent-1;
720       (void) CopyMagickString(message,text,count+1);
721       status=SetImageProperty(image,"tiff:image-id",message,exception);
722     }
723   if ((TIFFGetField(tiff,TIFFTAG_PAGENAME,&text) == 1) &&
724       (text != (char *) NULL))
725     status=SetImageProperty(image,"label",text,exception);
726   if ((TIFFGetField(tiff,TIFFTAG_SOFTWARE,&text) == 1) &&
727       (text != (char *) NULL))
728     status=SetImageProperty(image,"tiff:software",text,exception);
729   if ((TIFFGetField(tiff,33423,&count,&text) == 1) && (text != (char *) NULL))
730     {
731       if (count >= MagickPathExtent)
732         count=MagickPathExtent-1;
733       (void) CopyMagickString(message,text,count+1);
734       status=SetImageProperty(image,"tiff:kodak-33423",message,exception);
735     }
736   if ((TIFFGetField(tiff,36867,&count,&text) == 1) && (text != (char *) NULL))
737     {
738       if (count >= MagickPathExtent)
739         count=MagickPathExtent-1;
740       (void) CopyMagickString(message,text,count+1);
741       status=SetImageProperty(image,"tiff:kodak-36867",message,exception);
742     }
743   if (TIFFGetField(tiff,TIFFTAG_SUBFILETYPE,&type) == 1)
744     switch (type)
745     {
746       case 0x01:
747       {
748         status=SetImageProperty(image,"tiff:subfiletype","REDUCEDIMAGE",
749           exception);
750         break;
751       }
752       case 0x02:
753       {
754         status=SetImageProperty(image,"tiff:subfiletype","PAGE",exception);
755         break;
756       }
757       case 0x04:
758       {
759         status=SetImageProperty(image,"tiff:subfiletype","MASK",exception);
760         break;
761       }
762       default:
763         break;
764     }
765   return(status);
766 }
767 
TIFFSetImageProperties(TIFF * tiff,Image * image,const char * tag,ExceptionInfo * exception)768 static MagickBooleanType TIFFSetImageProperties(TIFF *tiff,Image *image,
769   const char *tag,ExceptionInfo *exception)
770 {
771   char
772     buffer[MagickPathExtent],
773     filename[MagickPathExtent];
774 
775   FILE
776     *file;
777 
778   int
779     unique_file;
780 
781   /*
782     Set EXIF or GPS image properties.
783   */
784   unique_file=AcquireUniqueFileResource(filename);
785   file=(FILE *) NULL;
786   if (unique_file != -1)
787     file=fdopen(unique_file,"rb+");
788   if ((unique_file == -1) || (file == (FILE *) NULL))
789     {
790       (void) RelinquishUniqueFileResource(filename);
791       (void) ThrowMagickException(exception,GetMagickModule(),WandError,
792         "UnableToCreateTemporaryFile","`%s'",filename);
793       return(MagickFalse);
794     }
795   TIFFPrintDirectory(tiff,file,0);
796   (void) fseek(file,0,SEEK_SET);
797   while (fgets(buffer,(int) sizeof(buffer),file) != NULL)
798   {
799     char
800       *p,
801       property[MagickPathExtent],
802       value[MagickPathExtent];
803 
804     StripString(buffer);
805     p=strchr(buffer,':');
806     if (p == (char *) NULL)
807       continue;
808     *p='\0';
809     (void) sprintf(property,"%s%.1024s",tag,buffer);
810     (void) sprintf(value,"%s",p+1);
811     StripString(value);
812     (void) SetImageProperty(image,property,value,exception);
813   }
814   (void) fclose(file);
815   (void) RelinquishUniqueFileResource(filename);
816   return(MagickTrue);
817 }
818 
TIFFGetEXIFProperties(TIFF * tiff,Image * image,ExceptionInfo * exception)819 static MagickBooleanType TIFFGetEXIFProperties(TIFF *tiff,Image *image,
820   ExceptionInfo *exception)
821 {
822 #if defined(MAGICKCORE_HAVE_TIFFREADEXIFDIRECTORY)
823   MagickBooleanType
824     status;
825 
826   tdir_t
827     directory;
828 
829 #if defined(TIFF_VERSION_BIG)
830   uint64
831 #else
832   uint32
833 #endif
834     offset;
835 
836   /*
837     Read EXIF properties.
838   */
839   offset=0;
840   if (TIFFGetField(tiff,TIFFTAG_EXIFIFD,&offset) != 1)
841     return(MagickFalse);
842   directory=TIFFCurrentDirectory(tiff);
843   if (TIFFReadEXIFDirectory(tiff,offset) != 1)
844     {
845       TIFFSetDirectory(tiff,directory);
846       return(MagickFalse);
847     }
848   status=TIFFSetImageProperties(tiff,image,"exif:",exception);
849   TIFFSetDirectory(tiff,directory);
850   return(status);
851 #else
852   (void) tiff;
853   (void) image;
854   return(MagickTrue);
855 #endif
856 }
857 
TIFFGetGPSProperties(TIFF * tiff,Image * image,ExceptionInfo * exception)858 static MagickBooleanType TIFFGetGPSProperties(TIFF *tiff,Image *image,
859   ExceptionInfo *exception)
860 {
861 #if defined(MAGICKCORE_HAVE_TIFFREADGPSDIRECTORY)
862   MagickBooleanType
863     status;
864 
865   tdir_t
866     directory;
867 
868 #if defined(TIFF_VERSION_BIG)
869   uint64
870 #else
871   uint32
872 #endif
873     offset;
874 
875   /*
876     Read GPS properties.
877   */
878   offset=0;
879   if (TIFFGetField(tiff,TIFFTAG_GPSIFD,&offset) != 1)
880     return(MagickFalse);
881   directory=TIFFCurrentDirectory(tiff);
882   if (TIFFReadGPSDirectory(tiff,offset) != 1)
883     {
884       TIFFSetDirectory(tiff,directory);
885       return(MagickFalse);
886     }
887   status=TIFFSetImageProperties(tiff,image,"exif:GPS",exception);
888   TIFFSetDirectory(tiff,directory);
889   return(status);
890 #else
891   magick_unreferenced(tiff);
892   magick_unreferenced(image);
893   magick_unreferenced(exception);
894   return(MagickTrue);
895 #endif
896 }
897 
TIFFMapBlob(thandle_t image,tdata_t * base,toff_t * size)898 static int TIFFMapBlob(thandle_t image,tdata_t *base,toff_t *size)
899 {
900   *base=(tdata_t *) GetBlobStreamData((Image *) image);
901   if (*base != (tdata_t *) NULL)
902     *size=(toff_t) GetBlobSize((Image *) image);
903   if (*base != (tdata_t *) NULL)
904     return(1);
905   return(0);
906 }
907 
TIFFReadBlob(thandle_t image,tdata_t data,tsize_t size)908 static tsize_t TIFFReadBlob(thandle_t image,tdata_t data,tsize_t size)
909 {
910   tsize_t
911     count;
912 
913   count=(tsize_t) ReadBlob((Image *) image,(size_t) size,
914     (unsigned char *) data);
915   return(count);
916 }
917 
TIFFReadPixels(TIFF * tiff,const tsample_t sample,const ssize_t row,tdata_t scanline)918 static int32 TIFFReadPixels(TIFF *tiff,const tsample_t sample,const ssize_t row,
919   tdata_t scanline)
920 {
921   int32
922     status;
923 
924   status=TIFFReadScanline(tiff,scanline,(uint32) row,sample);
925   return(status);
926 }
927 
TIFFSeekBlob(thandle_t image,toff_t offset,int whence)928 static toff_t TIFFSeekBlob(thandle_t image,toff_t offset,int whence)
929 {
930   return((toff_t) SeekBlob((Image *) image,(MagickOffsetType) offset,whence));
931 }
932 
TIFFUnmapBlob(thandle_t image,tdata_t base,toff_t size)933 static void TIFFUnmapBlob(thandle_t image,tdata_t base,toff_t size)
934 {
935   (void) image;
936   (void) base;
937   (void) size;
938 }
939 
940 static void TIFFWarnings(const char *,const char *,va_list)
941   magick_attribute((__format__ (__printf__,2,0)));
942 
TIFFWarnings(const char * module,const char * format,va_list warning)943 static void TIFFWarnings(const char *module,const char *format,va_list warning)
944 {
945   char
946     message[MagickPathExtent];
947 
948   ExceptionInfo
949     *exception;
950 
951 #if defined(MAGICKCORE_HAVE_VSNPRINTF)
952   (void) vsnprintf(message,MagickPathExtent-2,format,warning);
953 #else
954   (void) vsprintf(message,format,warning);
955 #endif
956   message[MagickPathExtent-2]='\0';
957   (void) ConcatenateMagickString(message,".",MagickPathExtent);
958   exception=(ExceptionInfo *) GetMagickThreadValue(tiff_exception);
959   if (exception != (ExceptionInfo *) NULL)
960     (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
961       message,"`%s'",module);
962 }
963 
TIFFWriteBlob(thandle_t image,tdata_t data,tsize_t size)964 static tsize_t TIFFWriteBlob(thandle_t image,tdata_t data,tsize_t size)
965 {
966   tsize_t
967     count;
968 
969   count=(tsize_t) WriteBlob((Image *) image,(size_t) size,
970     (unsigned char *) data);
971   return(count);
972 }
973 
GetJPEGMethod(Image * image,TIFF * tiff,uint16 photometric,uint16 bits_per_sample,uint16 samples_per_pixel)974 static TIFFMethodType GetJPEGMethod(Image* image,TIFF *tiff,uint16 photometric,
975   uint16 bits_per_sample,uint16 samples_per_pixel)
976 {
977 #define BUFFER_SIZE 2048
978 
979   MagickOffsetType
980     position,
981     offset;
982 
983   size_t
984     i;
985 
986   TIFFMethodType
987     method;
988 
989 #if defined(TIFF_VERSION_BIG)
990   uint64
991 #else
992   uint32
993 #endif
994     *value;
995 
996   unsigned char
997     buffer[BUFFER_SIZE+32];
998 
999   unsigned short
1000     length;
1001 
1002   /*
1003     Only support 8 bit for now.
1004   */
1005   if ((photometric != PHOTOMETRIC_SEPARATED) || (bits_per_sample != 8) ||
1006       (samples_per_pixel != 4))
1007     return(ReadGenericMethod);
1008   /*
1009     Search for Adobe APP14 JPEG marker.
1010   */
1011   value=NULL;
1012   if (!TIFFGetField(tiff,TIFFTAG_STRIPOFFSETS,&value) || (value == NULL))
1013     return(ReadStripMethod);
1014   position=TellBlob(image);
1015   offset=(MagickOffsetType) (value[0]);
1016   if (SeekBlob(image,offset,SEEK_SET) != offset)
1017     return(ReadStripMethod);
1018   method=ReadStripMethod;
1019   if (ReadBlob(image,BUFFER_SIZE,buffer) == BUFFER_SIZE)
1020     {
1021       for (i=0; i < BUFFER_SIZE; i++)
1022       {
1023         while (i < BUFFER_SIZE)
1024         {
1025           if (buffer[i++] == 255)
1026            break;
1027         }
1028         while (i < BUFFER_SIZE)
1029         {
1030           if (buffer[++i] != 255)
1031            break;
1032         }
1033         if (buffer[i++] == 216) /* JPEG_MARKER_SOI */
1034           continue;
1035         length=(unsigned short) (((unsigned int) (buffer[i] << 8) |
1036           (unsigned int) buffer[i+1]) & 0xffff);
1037         if (i+(size_t) length >= BUFFER_SIZE)
1038           break;
1039         if (buffer[i-1] == 238) /* JPEG_MARKER_APP0+14 */
1040           {
1041             if (length != 14)
1042               break;
1043             /* 0 == CMYK, 1 == YCbCr, 2 = YCCK */
1044             if (buffer[i+13] == 2)
1045               method=ReadYCCKMethod;
1046             break;
1047           }
1048         i+=(size_t) length;
1049       }
1050     }
1051   (void) SeekBlob(image,position,SEEK_SET);
1052   return(method);
1053 }
1054 
TIFFReadCustomStream(unsigned char * data,const size_t count,void * user_data)1055 static ssize_t TIFFReadCustomStream(unsigned char *data,const size_t count,
1056   void *user_data)
1057 {
1058   PhotoshopProfile
1059     *profile;
1060 
1061   size_t
1062     total;
1063 
1064   MagickOffsetType
1065     remaining;
1066 
1067   if (count == 0)
1068     return(0);
1069   profile=(PhotoshopProfile *) user_data;
1070   remaining=(MagickOffsetType) profile->length-profile->offset;
1071   if (remaining <= 0)
1072     return(-1);
1073   total=MagickMin(count, (size_t) remaining);
1074   (void) memcpy(data,profile->data->datum+profile->offset,total);
1075   profile->offset+=total;
1076   return(total);
1077 }
1078 
TIFFAcquireCustomStreamForReading(PhotoshopProfile * profile,ExceptionInfo * exception)1079 static CustomStreamInfo *TIFFAcquireCustomStreamForReading(
1080   PhotoshopProfile *profile,ExceptionInfo *exception)
1081 {
1082   CustomStreamInfo
1083     *custom_stream;
1084 
1085   custom_stream=AcquireCustomStreamInfo(exception);
1086   if (custom_stream == (CustomStreamInfo *) NULL)
1087     return(custom_stream);
1088   SetCustomStreamData(custom_stream,(void *) profile);
1089   SetCustomStreamReader(custom_stream,TIFFReadCustomStream);
1090   SetCustomStreamSeeker(custom_stream,TIFFSeekCustomStream);
1091   SetCustomStreamTeller(custom_stream,TIFFTellCustomStream);
1092   return(custom_stream);
1093 }
1094 
TIFFReadPhotoshopLayers(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)1095 static void TIFFReadPhotoshopLayers(const ImageInfo *image_info,Image *image,
1096   ExceptionInfo *exception)
1097 {
1098   const char
1099     *option;
1100 
1101   const StringInfo
1102     *profile;
1103 
1104   CustomStreamInfo
1105     *custom_stream;
1106 
1107   Image
1108     *layers;
1109 
1110   ImageInfo
1111     *clone_info;
1112 
1113   PhotoshopProfile
1114     photoshop_profile;
1115 
1116   PSDInfo
1117     info;
1118 
1119   ssize_t
1120     i;
1121 
1122   if (GetImageListLength(image) != 1)
1123     return;
1124   if ((image_info->number_scenes == 1) && (image_info->scene == 0))
1125     return;
1126   option=GetImageOption(image_info,"tiff:ignore-layers");
1127   if (option != (const char * ) NULL)
1128     return;
1129   profile=GetImageProfile(image,"tiff:37724");
1130   if (profile == (const StringInfo *) NULL)
1131     return;
1132   for (i=0; i < (ssize_t) profile->length-8; i++)
1133   {
1134     if (LocaleNCompare((const char *) (profile->datum+i),
1135         image->endian == MSBEndian ? "8BIM" : "MIB8",4) != 0)
1136       continue;
1137     i+=4;
1138     if ((LocaleNCompare((const char *) (profile->datum+i),
1139          image->endian == MSBEndian ? "Layr" : "ryaL",4) == 0) ||
1140         (LocaleNCompare((const char *) (profile->datum+i),
1141          image->endian == MSBEndian ? "LMsk" : "ksML",4) == 0) ||
1142         (LocaleNCompare((const char *) (profile->datum+i),
1143          image->endian == MSBEndian ? "Lr16" : "61rL",4) == 0) ||
1144         (LocaleNCompare((const char *) (profile->datum+i),
1145          image->endian == MSBEndian ? "Lr32" : "23rL",4) == 0))
1146       break;
1147   }
1148   i+=4;
1149   if (i >= (ssize_t) (profile->length-8))
1150     return;
1151   photoshop_profile.data=(StringInfo *) profile;
1152   photoshop_profile.length=profile->length;
1153   custom_stream=TIFFAcquireCustomStreamForReading(&photoshop_profile,exception);
1154   if (custom_stream == (CustomStreamInfo *) NULL)
1155     return;
1156   layers=CloneImage(image,0,0,MagickTrue,exception);
1157   if (layers == (Image *) NULL)
1158     {
1159       custom_stream=DestroyCustomStreamInfo(custom_stream);
1160       return;
1161     }
1162   (void) DeleteImageProfile(layers,"tiff:37724");
1163   AttachCustomStream(layers->blob,custom_stream);
1164   SeekBlob(layers,(MagickOffsetType) i,SEEK_SET);
1165   InitPSDInfo(layers,&info);
1166   clone_info=CloneImageInfo(image_info);
1167   clone_info->number_scenes=0;
1168   (void) ReadPSDLayers(layers,clone_info,&info,exception);
1169   clone_info=DestroyImageInfo(clone_info);
1170   DeleteImageFromList(&layers);
1171   if (layers != (Image *) NULL)
1172     {
1173       SetImageArtifact(image,"tiff:has-layers","true");
1174       AppendImageToList(&image,layers);
1175       while (layers != (Image *) NULL)
1176       {
1177         SetImageArtifact(layers,"tiff:has-layers","true");
1178         DetachBlob(layers->blob);
1179         layers=GetNextImageInList(layers);
1180       }
1181     }
1182   custom_stream=DestroyCustomStreamInfo(custom_stream);
1183 }
1184 
1185 #if defined(__cplusplus) || defined(c_plusplus)
1186 }
1187 #endif
1188 
ReadTIFFImage(const ImageInfo * image_info,ExceptionInfo * exception)1189 static Image *ReadTIFFImage(const ImageInfo *image_info,
1190   ExceptionInfo *exception)
1191 {
1192 #define ThrowTIFFException(severity,message) \
1193 { \
1194   if (pixel_info != (MemoryInfo *) NULL) \
1195     pixel_info=RelinquishVirtualMemory(pixel_info); \
1196   if (quantum_info != (QuantumInfo *) NULL) \
1197     quantum_info=DestroyQuantumInfo(quantum_info); \
1198   TIFFClose(tiff); \
1199   ThrowReaderException(severity,message); \
1200 }
1201 
1202   const char
1203     *option;
1204 
1205   float
1206     *chromaticity,
1207     x_position,
1208     y_position,
1209     x_resolution,
1210     y_resolution;
1211 
1212   Image
1213     *image;
1214 
1215   int
1216     tiff_status;
1217 
1218   MagickBooleanType
1219     more_frames;
1220 
1221   MagickSizeType
1222     number_pixels;
1223 
1224   MagickStatusType
1225     status;
1226 
1227   MemoryInfo
1228     *pixel_info = (MemoryInfo *) NULL;
1229 
1230   QuantumInfo
1231     *quantum_info;
1232 
1233   QuantumType
1234     quantum_type;
1235 
1236   ssize_t
1237     i;
1238 
1239   ssize_t
1240     y;
1241 
1242   TIFF
1243     *tiff;
1244 
1245   TIFFMethodType
1246     method;
1247 
1248   uint16
1249     compress_tag,
1250     bits_per_sample,
1251     endian,
1252     extra_samples,
1253     interlace,
1254     max_sample_value,
1255     min_sample_value,
1256     orientation,
1257     pages,
1258     photometric,
1259     *sample_info,
1260     sample_format,
1261     samples_per_pixel,
1262     units,
1263     value;
1264 
1265   uint32
1266     height,
1267     rows_per_strip,
1268     width;
1269 
1270   unsigned char
1271     *pixels;
1272 
1273   void
1274     *sans[4] = { NULL, NULL, NULL, NULL };
1275 
1276   /*
1277     Open image.
1278   */
1279   assert(image_info != (const ImageInfo *) NULL);
1280   assert(image_info->signature == MagickCoreSignature);
1281   if (image_info->debug != MagickFalse)
1282     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1283       image_info->filename);
1284   assert(exception != (ExceptionInfo *) NULL);
1285   assert(exception->signature == MagickCoreSignature);
1286   image=AcquireImage(image_info,exception);
1287   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1288   if (status == MagickFalse)
1289     {
1290       image=DestroyImageList(image);
1291       return((Image *) NULL);
1292     }
1293   (void) SetMagickThreadValue(tiff_exception,exception);
1294   tiff=TIFFClientOpen(image->filename,"rb",(thandle_t) image,TIFFReadBlob,
1295     TIFFWriteBlob,TIFFSeekBlob,TIFFCloseBlob,TIFFGetBlobSize,TIFFMapBlob,
1296     TIFFUnmapBlob);
1297   if (tiff == (TIFF *) NULL)
1298     {
1299       image=DestroyImageList(image);
1300       return((Image *) NULL);
1301     }
1302   if (exception->severity > ErrorException)
1303     {
1304       TIFFClose(tiff);
1305       image=DestroyImageList(image);
1306       return((Image *) NULL);
1307     }
1308   if (image_info->number_scenes != 0)
1309     {
1310       /*
1311         Generate blank images for subimage specification (e.g. image.tif[4].
1312         We need to check the number of directores because it is possible that
1313         the subimage(s) are stored in the photoshop profile.
1314       */
1315       if (image_info->scene < (size_t) TIFFNumberOfDirectories(tiff))
1316         {
1317           for (i=0; i < (ssize_t) image_info->scene; i++)
1318           {
1319             status=TIFFReadDirectory(tiff) != 0 ? MagickTrue : MagickFalse;
1320             if (status == MagickFalse)
1321               {
1322                 TIFFClose(tiff);
1323                 image=DestroyImageList(image);
1324                 return((Image *) NULL);
1325               }
1326             AcquireNextImage(image_info,image,exception);
1327             if (GetNextImageInList(image) == (Image *) NULL)
1328               {
1329                 TIFFClose(tiff);
1330                 image=DestroyImageList(image);
1331                 return((Image *) NULL);
1332               }
1333             image=SyncNextImageInList(image);
1334           }
1335       }
1336   }
1337   more_frames=MagickTrue;
1338   do
1339   {
1340     /* TIFFPrintDirectory(tiff,stdout,MagickFalse); */
1341     photometric=PHOTOMETRIC_RGB;
1342     if ((TIFFGetField(tiff,TIFFTAG_IMAGEWIDTH,&width) != 1) ||
1343         (TIFFGetField(tiff,TIFFTAG_IMAGELENGTH,&height) != 1) ||
1344         (TIFFGetFieldDefaulted(tiff,TIFFTAG_PHOTOMETRIC,&photometric,sans) != 1) ||
1345         (TIFFGetFieldDefaulted(tiff,TIFFTAG_COMPRESSION,&compress_tag,sans) != 1) ||
1346         (TIFFGetFieldDefaulted(tiff,TIFFTAG_FILLORDER,&endian,sans) != 1) ||
1347         (TIFFGetFieldDefaulted(tiff,TIFFTAG_PLANARCONFIG,&interlace,sans) != 1) ||
1348         (TIFFGetFieldDefaulted(tiff,TIFFTAG_SAMPLESPERPIXEL,&samples_per_pixel,sans) != 1) ||
1349         (TIFFGetFieldDefaulted(tiff,TIFFTAG_BITSPERSAMPLE,&bits_per_sample,sans) != 1) ||
1350         (TIFFGetFieldDefaulted(tiff,TIFFTAG_SAMPLEFORMAT,&sample_format,sans) != 1) ||
1351         (TIFFGetFieldDefaulted(tiff,TIFFTAG_MINSAMPLEVALUE,&min_sample_value,sans) != 1) ||
1352         (TIFFGetFieldDefaulted(tiff,TIFFTAG_MAXSAMPLEVALUE,&max_sample_value,sans) != 1))
1353       {
1354         TIFFClose(tiff);
1355         ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1356       }
1357     if (((sample_format != SAMPLEFORMAT_IEEEFP) || (bits_per_sample != 64)) &&
1358         ((bits_per_sample <= 0) || (bits_per_sample > 32)))
1359       {
1360         TIFFClose(tiff);
1361         ThrowReaderException(CorruptImageError,"UnsupportedBitsPerPixel");
1362       }
1363     if (sample_format == SAMPLEFORMAT_IEEEFP)
1364       (void) SetImageProperty(image,"quantum:format","floating-point",
1365         exception);
1366     switch (photometric)
1367     {
1368       case PHOTOMETRIC_MINISBLACK:
1369       {
1370         (void) SetImageProperty(image,"tiff:photometric","min-is-black",
1371           exception);
1372         break;
1373       }
1374       case PHOTOMETRIC_MINISWHITE:
1375       {
1376         (void) SetImageProperty(image,"tiff:photometric","min-is-white",
1377           exception);
1378         break;
1379       }
1380       case PHOTOMETRIC_PALETTE:
1381       {
1382         (void) SetImageProperty(image,"tiff:photometric","palette",exception);
1383         break;
1384       }
1385       case PHOTOMETRIC_RGB:
1386       {
1387         (void) SetImageProperty(image,"tiff:photometric","RGB",exception);
1388         break;
1389       }
1390       case PHOTOMETRIC_CIELAB:
1391       {
1392         (void) SetImageProperty(image,"tiff:photometric","CIELAB",exception);
1393         break;
1394       }
1395       case PHOTOMETRIC_LOGL:
1396       {
1397         (void) SetImageProperty(image,"tiff:photometric","CIE Log2(L)",
1398           exception);
1399         break;
1400       }
1401       case PHOTOMETRIC_LOGLUV:
1402       {
1403         (void) SetImageProperty(image,"tiff:photometric","LOGLUV",exception);
1404         break;
1405       }
1406 #if defined(PHOTOMETRIC_MASK)
1407       case PHOTOMETRIC_MASK:
1408       {
1409         (void) SetImageProperty(image,"tiff:photometric","MASK",exception);
1410         break;
1411       }
1412 #endif
1413       case PHOTOMETRIC_SEPARATED:
1414       {
1415         (void) SetImageProperty(image,"tiff:photometric","separated",exception);
1416         break;
1417       }
1418       case PHOTOMETRIC_YCBCR:
1419       {
1420         (void) SetImageProperty(image,"tiff:photometric","YCBCR",exception);
1421         break;
1422       }
1423       default:
1424       {
1425         (void) SetImageProperty(image,"tiff:photometric","unknown",exception);
1426         break;
1427       }
1428     }
1429     if (image->debug != MagickFalse)
1430       {
1431         (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %ux%u",
1432           (unsigned int) width,(unsigned int) height);
1433         (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Interlace: %u",
1434           interlace);
1435         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1436           "Bits per sample: %u",bits_per_sample);
1437         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1438           "Min sample value: %u",min_sample_value);
1439         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1440           "Max sample value: %u",max_sample_value);
1441         (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Photometric "
1442           "interpretation: %s",GetImageProperty(image,"tiff:photometric",
1443           exception));
1444       }
1445     image->columns=(size_t) width;
1446     image->rows=(size_t) height;
1447     image->depth=(size_t) bits_per_sample;
1448     if (image->debug != MagickFalse)
1449       (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Image depth: %.20g",
1450         (double) image->depth);
1451     image->endian=MSBEndian;
1452     if (endian == FILLORDER_LSB2MSB)
1453       image->endian=LSBEndian;
1454 #if defined(MAGICKCORE_HAVE_TIFFISBIGENDIAN)
1455     if (TIFFIsBigEndian(tiff) == 0)
1456       {
1457         (void) SetImageProperty(image,"tiff:endian","lsb",exception);
1458         image->endian=LSBEndian;
1459       }
1460     else
1461       {
1462         (void) SetImageProperty(image,"tiff:endian","msb",exception);
1463         image->endian=MSBEndian;
1464       }
1465 #endif
1466     if ((photometric == PHOTOMETRIC_MINISBLACK) ||
1467         (photometric == PHOTOMETRIC_MINISWHITE))
1468       image->colorspace=GRAYColorspace;
1469     if (photometric == PHOTOMETRIC_SEPARATED)
1470       image->colorspace=CMYKColorspace;
1471     if (photometric == PHOTOMETRIC_CIELAB)
1472       image->colorspace=LabColorspace;
1473     if ((photometric == PHOTOMETRIC_YCBCR) && (compress_tag != COMPRESSION_JPEG))
1474       image->colorspace=YCbCrColorspace;
1475     status=TIFFGetProfiles(tiff,image,exception);
1476     if (status == MagickFalse)
1477       {
1478         TIFFClose(tiff);
1479         return(DestroyImageList(image));
1480       }
1481     status=TIFFGetProperties(tiff,image,exception);
1482     if (status == MagickFalse)
1483       {
1484         TIFFClose(tiff);
1485         return(DestroyImageList(image));
1486       }
1487     option=GetImageOption(image_info,"tiff:exif-properties");
1488     if (IsStringFalse(option) == MagickFalse) /* enabled by default */
1489       (void) TIFFGetEXIFProperties(tiff,image,exception);
1490     option=GetImageOption(image_info,"tiff:gps-properties");
1491     if (IsStringFalse(option) == MagickFalse) /* enabled by default */
1492       (void) TIFFGetGPSProperties(tiff,image,exception);
1493     if ((TIFFGetFieldDefaulted(tiff,TIFFTAG_XRESOLUTION,&x_resolution,sans) == 1) &&
1494         (TIFFGetFieldDefaulted(tiff,TIFFTAG_YRESOLUTION,&y_resolution,sans) == 1))
1495       {
1496         image->resolution.x=x_resolution;
1497         image->resolution.y=y_resolution;
1498       }
1499     if (TIFFGetFieldDefaulted(tiff,TIFFTAG_RESOLUTIONUNIT,&units,sans,sans) == 1)
1500       {
1501         if (units == RESUNIT_INCH)
1502           image->units=PixelsPerInchResolution;
1503         if (units == RESUNIT_CENTIMETER)
1504           image->units=PixelsPerCentimeterResolution;
1505       }
1506     if ((TIFFGetFieldDefaulted(tiff,TIFFTAG_XPOSITION,&x_position,sans) == 1) &&
1507         (TIFFGetFieldDefaulted(tiff,TIFFTAG_YPOSITION,&y_position,sans) == 1))
1508       {
1509         image->page.x=CastDoubleToLong(ceil(x_position*
1510           image->resolution.x-0.5));
1511         image->page.y=CastDoubleToLong(ceil(y_position*
1512           image->resolution.y-0.5));
1513       }
1514     if (TIFFGetFieldDefaulted(tiff,TIFFTAG_ORIENTATION,&orientation,sans) == 1)
1515       image->orientation=(OrientationType) orientation;
1516     if (TIFFGetField(tiff,TIFFTAG_WHITEPOINT,&chromaticity) == 1)
1517       {
1518         if ((chromaticity != (float *) NULL) && (*chromaticity != 0.0))
1519           {
1520             image->chromaticity.white_point.x=chromaticity[0];
1521             image->chromaticity.white_point.y=chromaticity[1];
1522           }
1523       }
1524     if (TIFFGetField(tiff,TIFFTAG_PRIMARYCHROMATICITIES,&chromaticity) == 1)
1525       {
1526         if ((chromaticity != (float *) NULL) && (*chromaticity != 0.0))
1527           {
1528             image->chromaticity.red_primary.x=chromaticity[0];
1529             image->chromaticity.red_primary.y=chromaticity[1];
1530             image->chromaticity.green_primary.x=chromaticity[2];
1531             image->chromaticity.green_primary.y=chromaticity[3];
1532             image->chromaticity.blue_primary.x=chromaticity[4];
1533             image->chromaticity.blue_primary.y=chromaticity[5];
1534           }
1535       }
1536 #if defined(MAGICKCORE_HAVE_TIFFISCODECCONFIGURED) || (TIFFLIB_VERSION > 20040919)
1537     if ((compress_tag != COMPRESSION_NONE) &&
1538         (TIFFIsCODECConfigured(compress_tag) == 0))
1539       {
1540         TIFFClose(tiff);
1541         ThrowReaderException(CoderError,"CompressNotSupported");
1542       }
1543 #endif
1544     switch (compress_tag)
1545     {
1546       case COMPRESSION_NONE: image->compression=NoCompression; break;
1547       case COMPRESSION_CCITTFAX3: image->compression=FaxCompression; break;
1548       case COMPRESSION_CCITTFAX4: image->compression=Group4Compression; break;
1549       case COMPRESSION_JPEG:
1550       {
1551          image->compression=JPEGCompression;
1552 #if defined(JPEG_SUPPORT)
1553          {
1554            char
1555              sampling_factor[MagickPathExtent];
1556 
1557            uint16
1558              horizontal,
1559              vertical;
1560 
1561            tiff_status=TIFFGetField(tiff,TIFFTAG_YCBCRSUBSAMPLING,&horizontal,
1562              &vertical);
1563            if (tiff_status == 1)
1564              {
1565                (void) FormatLocaleString(sampling_factor,MagickPathExtent,
1566                  "%dx%d",horizontal,vertical);
1567                (void) SetImageProperty(image,"jpeg:sampling-factor",
1568                  sampling_factor,exception);
1569                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1570                  "Sampling Factors: %s",sampling_factor);
1571              }
1572          }
1573 #endif
1574         break;
1575       }
1576       case COMPRESSION_OJPEG: image->compression=JPEGCompression; break;
1577 #if defined(COMPRESSION_LZMA)
1578       case COMPRESSION_LZMA: image->compression=LZMACompression; break;
1579 #endif
1580       case COMPRESSION_LZW: image->compression=LZWCompression; break;
1581       case COMPRESSION_DEFLATE: image->compression=ZipCompression; break;
1582       case COMPRESSION_ADOBE_DEFLATE: image->compression=ZipCompression; break;
1583 #if defined(COMPRESSION_WEBP)
1584       case COMPRESSION_WEBP: image->compression=WebPCompression; break;
1585 #endif
1586 #if defined(COMPRESSION_ZSTD)
1587       case COMPRESSION_ZSTD: image->compression=ZstdCompression; break;
1588 #endif
1589       default: image->compression=RLECompression; break;
1590     }
1591     quantum_info=(QuantumInfo *) NULL;
1592     if ((photometric == PHOTOMETRIC_PALETTE) &&
1593         (pow(2.0,1.0*bits_per_sample) <= MaxColormapSize))
1594       {
1595         size_t
1596           colors;
1597 
1598         colors=(size_t) GetQuantumRange(bits_per_sample)+1;
1599         if (AcquireImageColormap(image,colors,exception) == MagickFalse)
1600           {
1601             TIFFClose(tiff);
1602             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1603           }
1604       }
1605     value=(unsigned short) image->scene;
1606     if (TIFFGetFieldDefaulted(tiff,TIFFTAG_PAGENUMBER,&value,&pages,sans) == 1)
1607       image->scene=value;
1608     if (image->storage_class == PseudoClass)
1609       {
1610         size_t
1611           range;
1612 
1613         uint16
1614           *blue_colormap,
1615           *green_colormap,
1616           *red_colormap;
1617 
1618         /*
1619           Initialize colormap.
1620         */
1621         tiff_status=TIFFGetField(tiff,TIFFTAG_COLORMAP,&red_colormap,
1622           &green_colormap,&blue_colormap);
1623         if (tiff_status == 1)
1624           {
1625             if ((red_colormap != (uint16 *) NULL) &&
1626                 (green_colormap != (uint16 *) NULL) &&
1627                 (blue_colormap != (uint16 *) NULL))
1628               {
1629                 range=255;  /* might be old style 8-bit colormap */
1630                 for (i=0; i < (ssize_t) image->colors; i++)
1631                   if ((red_colormap[i] >= 256) || (green_colormap[i] >= 256) ||
1632                       (blue_colormap[i] >= 256))
1633                     {
1634                       range=65535;
1635                       break;
1636                     }
1637                 for (i=0; i < (ssize_t) image->colors; i++)
1638                 {
1639                   image->colormap[i].red=ClampToQuantum(((double)
1640                     QuantumRange*red_colormap[i])/range);
1641                   image->colormap[i].green=ClampToQuantum(((double)
1642                     QuantumRange*green_colormap[i])/range);
1643                   image->colormap[i].blue=ClampToQuantum(((double)
1644                     QuantumRange*blue_colormap[i])/range);
1645                 }
1646               }
1647           }
1648       }
1649     if (image_info->ping != MagickFalse)
1650       {
1651         if (image_info->number_scenes != 0)
1652           if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1653             break;
1654         goto next_tiff_frame;
1655       }
1656     status=SetImageExtent(image,image->columns,image->rows,exception);
1657     if (status == MagickFalse)
1658       {
1659         TIFFClose(tiff);
1660         return(DestroyImageList(image));
1661       }
1662     status=SetImageColorspace(image,image->colorspace,exception);
1663     status&=ResetImagePixels(image,exception);
1664     if (status == MagickFalse)
1665       {
1666         TIFFClose(tiff);
1667         return(DestroyImageList(image));
1668       }
1669     /*
1670       Allocate memory for the image and pixel buffer.
1671     */
1672     quantum_info=AcquireQuantumInfo(image_info,image);
1673     if (quantum_info == (QuantumInfo *) NULL)
1674       ThrowTIFFException(ResourceLimitError,"MemoryAllocationFailed");
1675     if (sample_format == SAMPLEFORMAT_UINT)
1676       status=SetQuantumFormat(image,quantum_info,UnsignedQuantumFormat);
1677     if (sample_format == SAMPLEFORMAT_INT)
1678       status=SetQuantumFormat(image,quantum_info,SignedQuantumFormat);
1679     if (sample_format == SAMPLEFORMAT_IEEEFP)
1680       status=SetQuantumFormat(image,quantum_info,FloatingPointQuantumFormat);
1681     if (status == MagickFalse)
1682       ThrowTIFFException(ResourceLimitError,"MemoryAllocationFailed");
1683     status=MagickTrue;
1684     switch (photometric)
1685     {
1686       case PHOTOMETRIC_MINISBLACK:
1687       {
1688         quantum_info->min_is_white=MagickFalse;
1689         break;
1690       }
1691       case PHOTOMETRIC_MINISWHITE:
1692       {
1693         quantum_info->min_is_white=MagickTrue;
1694         break;
1695       }
1696       default:
1697         break;
1698     }
1699     extra_samples=0;
1700     tiff_status=TIFFGetFieldDefaulted(tiff,TIFFTAG_EXTRASAMPLES,&extra_samples,
1701       &sample_info,sans);
1702     if (tiff_status == 1)
1703       {
1704         (void) SetImageProperty(image,"tiff:alpha","unspecified",exception);
1705         if (extra_samples == 0)
1706           {
1707             if ((samples_per_pixel == 4) && (photometric == PHOTOMETRIC_RGB))
1708               image->alpha_trait=BlendPixelTrait;
1709           }
1710         else
1711           for (i=0; i < extra_samples; i++)
1712           {
1713             image->alpha_trait=BlendPixelTrait;
1714             if (sample_info[i] == EXTRASAMPLE_ASSOCALPHA)
1715               {
1716                 SetQuantumAlphaType(quantum_info,AssociatedQuantumAlpha);
1717                 (void) SetImageProperty(image,"tiff:alpha","associated",
1718                   exception);
1719               }
1720             else
1721               if (sample_info[i] == EXTRASAMPLE_UNASSALPHA)
1722                 {
1723                   SetQuantumAlphaType(quantum_info,DisassociatedQuantumAlpha);
1724                   (void) SetImageProperty(image,"tiff:alpha","unassociated",
1725                     exception);
1726                 }
1727           }
1728       }
1729     if (image->alpha_trait != UndefinedPixelTrait)
1730       (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1731     if (samples_per_pixel > MaxPixelChannels)
1732       {
1733         TIFFClose(tiff);
1734         ThrowReaderException(CorruptImageError,"MaximumChannelsExceeded");
1735       }
1736     method=ReadGenericMethod;
1737     rows_per_strip=(uint32) image->rows;
1738     if (TIFFGetField(tiff,TIFFTAG_ROWSPERSTRIP,&rows_per_strip) == 1)
1739       {
1740         char
1741           buffer[MagickPathExtent];
1742 
1743         (void) FormatLocaleString(buffer,MagickPathExtent,"%u",
1744           (unsigned int) rows_per_strip);
1745         (void) SetImageProperty(image,"tiff:rows-per-strip",buffer,exception);
1746         method=ReadStripMethod;
1747         if (rows_per_strip > (uint32) image->rows)
1748           rows_per_strip=(uint32) image->rows;
1749       }
1750     if (TIFFIsTiled(tiff) != MagickFalse)
1751       {
1752         uint32
1753           columns,
1754           rows;
1755 
1756         if ((TIFFGetField(tiff,TIFFTAG_TILEWIDTH,&columns) != 1) ||
1757             (TIFFGetField(tiff,TIFFTAG_TILELENGTH,&rows) != 1))
1758           ThrowTIFFException(CoderError,"ImageIsNotTiled");
1759         if ((AcquireMagickResource(WidthResource,columns) == MagickFalse) ||
1760             (AcquireMagickResource(HeightResource,rows) == MagickFalse))
1761           ThrowTIFFException(ImageError,"WidthOrHeightExceedsLimit");
1762         method=ReadTileMethod;
1763       }
1764     if ((photometric == PHOTOMETRIC_LOGLUV) ||
1765         (compress_tag == COMPRESSION_CCITTFAX3))
1766       method=ReadGenericMethod;
1767     if (image->compression == JPEGCompression)
1768       method=GetJPEGMethod(image,tiff,photometric,bits_per_sample,
1769         samples_per_pixel);
1770     quantum_info->endian=LSBEndian;
1771     if (TIFFScanlineSize(tiff) <= 0)
1772       ThrowTIFFException(ResourceLimitError,"MemoryAllocationFailed");
1773     if ((1.0*TIFFScanlineSize(tiff)) > (2.53*GetBlobSize(image)))
1774       ThrowTIFFException(CorruptImageError,"InsufficientImageDataInFile");
1775     number_pixels=MagickMax(TIFFScanlineSize(tiff),MagickMax((ssize_t)
1776       image->columns*samples_per_pixel*pow(2.0,ceil(log(bits_per_sample)/
1777       log(2.0))),image->columns*rows_per_strip));
1778     pixel_info=AcquireVirtualMemory(number_pixels,sizeof(uint32));
1779     if (pixel_info == (MemoryInfo *) NULL)
1780       ThrowTIFFException(ResourceLimitError,"MemoryAllocationFailed");
1781     pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);
1782     (void) memset(pixels,0,number_pixels*sizeof(uint32));
1783     quantum_type=GrayQuantum;
1784     if (image->storage_class == PseudoClass)
1785       quantum_type=IndexQuantum;
1786     if (interlace != PLANARCONFIG_SEPARATE)
1787       {
1788         size_t
1789           pad;
1790 
1791         pad=(size_t) MagickMax((ssize_t) samples_per_pixel-1,0);
1792         if (image->alpha_trait != UndefinedPixelTrait)
1793           {
1794             if (image->storage_class == PseudoClass)
1795               quantum_type=IndexAlphaQuantum;
1796             else
1797               quantum_type=samples_per_pixel == 1 ? AlphaQuantum :
1798                 GrayAlphaQuantum;
1799           }
1800         if ((samples_per_pixel > 2) && (interlace != PLANARCONFIG_SEPARATE))
1801           {
1802             quantum_type=RGBQuantum;
1803             pad=(size_t) MagickMax((size_t) samples_per_pixel-3,0);
1804             if (image->alpha_trait != UndefinedPixelTrait)
1805               {
1806                 quantum_type=RGBAQuantum;
1807                 pad=(size_t) MagickMax((size_t) samples_per_pixel-4,0);
1808               }
1809             if (image->colorspace == CMYKColorspace)
1810               {
1811                 quantum_type=CMYKQuantum;
1812                 pad=(size_t) MagickMax((size_t) samples_per_pixel-4,0);
1813                 if (image->alpha_trait != UndefinedPixelTrait)
1814                   {
1815                     quantum_type=CMYKAQuantum;
1816                     pad=(size_t) MagickMax((size_t) samples_per_pixel-5,0);
1817                   }
1818               }
1819             status=SetQuantumPad(image,quantum_info,pad*((bits_per_sample+7) >>
1820               3));
1821             if (status == MagickFalse)
1822               ThrowTIFFException(ResourceLimitError,"MemoryAllocationFailed");
1823           }
1824       }
1825     switch (method)
1826     {
1827       case ReadYCCKMethod:
1828       {
1829         /*
1830           Convert YCC TIFF image.
1831         */
1832         for (y=0; y < (ssize_t) image->rows; y++)
1833         {
1834           Quantum
1835             *magick_restrict q;
1836 
1837           ssize_t
1838             x;
1839 
1840           unsigned char
1841             *p;
1842 
1843           tiff_status=TIFFReadPixels(tiff,0,y,(char *) pixels);
1844           if (tiff_status == -1)
1845             break;
1846           q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1847           if (q == (Quantum *) NULL)
1848             break;
1849           p=pixels;
1850           for (x=0; x < (ssize_t) image->columns; x++)
1851           {
1852             SetPixelCyan(image,ScaleCharToQuantum(ClampYCC((double) *p+
1853               (1.402*(double) *(p+2))-179.456)),q);
1854             SetPixelMagenta(image,ScaleCharToQuantum(ClampYCC((double) *p-
1855               (0.34414*(double) *(p+1))-(0.71414*(double ) *(p+2))+
1856               135.45984)),q);
1857             SetPixelYellow(image,ScaleCharToQuantum(ClampYCC((double) *p+
1858               (1.772*(double) *(p+1))-226.816)),q);
1859             SetPixelBlack(image,ScaleCharToQuantum((unsigned char) *(p+3)),q);
1860             q+=GetPixelChannels(image);
1861             p+=4;
1862           }
1863           if (SyncAuthenticPixels(image,exception) == MagickFalse)
1864             break;
1865           if (image->previous == (Image *) NULL)
1866             {
1867               status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1868                 image->rows);
1869               if (status == MagickFalse)
1870                 break;
1871             }
1872         }
1873         break;
1874       }
1875       case ReadStripMethod:
1876       {
1877         unsigned char
1878           *p;
1879 
1880         size_t
1881           extent;
1882 
1883         ssize_t
1884           stride,
1885           strip_id;
1886 
1887         tsize_t
1888           strip_size;
1889 
1890         unsigned char
1891           *strip_pixels;
1892 
1893         /*
1894           Convert stripped TIFF image.
1895         */
1896         extent=2*TIFFStripSize(tiff);
1897 #if defined(TIFF_VERSION_BIG)
1898         extent+=image->columns*sizeof(uint64);
1899 #else
1900         extent+=image->columns*sizeof(uint32);
1901 #endif
1902         strip_pixels=(unsigned char *) AcquireQuantumMemory(extent,
1903           sizeof(*strip_pixels));
1904         if (strip_pixels == (unsigned char *) NULL)
1905           ThrowTIFFException(ResourceLimitError,"MemoryAllocationFailed");
1906         (void) memset(strip_pixels,0,extent*sizeof(*strip_pixels));
1907         stride=TIFFVStripSize(tiff,1);
1908         strip_id=0;
1909         p=strip_pixels;
1910         for (i=0; i < (ssize_t) samples_per_pixel; i++)
1911         {
1912           size_t
1913             rows_remaining;
1914 
1915           switch (i)
1916           {
1917             case 0: break;
1918             case 1: quantum_type=GreenQuantum; break;
1919             case 2: quantum_type=BlueQuantum; break;
1920             case 3:
1921             {
1922               quantum_type=AlphaQuantum;
1923               if (image->colorspace == CMYKColorspace)
1924                 quantum_type=BlackQuantum;
1925               break;
1926             }
1927             case 4: quantum_type=AlphaQuantum; break;
1928             default: break;
1929           }
1930           rows_remaining=0;
1931           for (y=0; y < (ssize_t) image->rows; y++)
1932           {
1933             Quantum
1934               *magick_restrict q;
1935 
1936             q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
1937             if (q == (Quantum *) NULL)
1938               break;
1939             if (rows_remaining == 0)
1940               {
1941                 strip_size=TIFFReadEncodedStrip(tiff,strip_id,strip_pixels,
1942                   TIFFStripSize(tiff));
1943                 if (strip_size == -1)
1944                   break;
1945                 rows_remaining=rows_per_strip;
1946                 if ((y+rows_per_strip) > (ssize_t) image->rows)
1947                   rows_remaining=(rows_per_strip-(y+rows_per_strip-
1948                     image->rows));
1949                 p=strip_pixels;
1950                 strip_id++;
1951               }
1952             (void) ImportQuantumPixels(image,(CacheView *) NULL,
1953               quantum_info,quantum_type,p,exception);
1954             p+=stride;
1955             rows_remaining--;
1956             if (SyncAuthenticPixels(image,exception) == MagickFalse)
1957               break;
1958             if (image->previous == (Image *) NULL)
1959               {
1960                 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1961                   image->rows);
1962                 if (status == MagickFalse)
1963                   break;
1964               }
1965           }
1966           if ((samples_per_pixel > 1) && (interlace != PLANARCONFIG_SEPARATE))
1967             break;
1968         }
1969         strip_pixels=(unsigned char *) RelinquishMagickMemory(strip_pixels);
1970         break;
1971       }
1972       case ReadTileMethod:
1973       {
1974         unsigned char
1975           *p;
1976 
1977         size_t
1978           extent;
1979 
1980         uint32
1981           columns,
1982           rows;
1983 
1984         unsigned char
1985           *tile_pixels;
1986 
1987         /*
1988           Convert tiled TIFF image.
1989         */
1990         if ((TIFFGetField(tiff,TIFFTAG_TILEWIDTH,&columns) != 1) ||
1991             (TIFFGetField(tiff,TIFFTAG_TILELENGTH,&rows) != 1))
1992           ThrowTIFFException(CoderError,"ImageIsNotTiled");
1993         number_pixels=(MagickSizeType) columns*rows;
1994         if (HeapOverflowSanityCheck(rows,sizeof(*tile_pixels)) != MagickFalse)
1995           ThrowTIFFException(ResourceLimitError,"MemoryAllocationFailed");
1996         extent=TIFFTileSize(tiff);
1997 #if defined(TIFF_VERSION_BIG)
1998         extent+=columns*sizeof(uint64);
1999 #else
2000         extent+=columns*sizeof(uint32);
2001 #endif
2002         tile_pixels=(unsigned char *) AcquireQuantumMemory(extent,
2003           sizeof(*tile_pixels));
2004         if (tile_pixels == (unsigned char *) NULL)
2005           ThrowTIFFException(ResourceLimitError,"MemoryAllocationFailed");
2006         (void) memset(tile_pixels,0,extent*sizeof(*tile_pixels));
2007         for (i=0; i < (ssize_t) samples_per_pixel; i++)
2008         {
2009           switch (i)
2010           {
2011             case 0: break;
2012             case 1: quantum_type=GreenQuantum; break;
2013             case 2: quantum_type=BlueQuantum; break;
2014             case 3:
2015             {
2016               quantum_type=AlphaQuantum;
2017               if (image->colorspace == CMYKColorspace)
2018                 quantum_type=BlackQuantum;
2019               break;
2020             }
2021             case 4: quantum_type=AlphaQuantum; break;
2022             default: break;
2023           }
2024           for (y=0; y < (ssize_t) image->rows; y+=rows)
2025           {
2026             ssize_t
2027               x;
2028 
2029             size_t
2030               rows_remaining;
2031 
2032             rows_remaining=image->rows-y;
2033             if ((ssize_t) (y+rows) < (ssize_t) image->rows)
2034               rows_remaining=rows;
2035             for (x=0; x < (ssize_t) image->columns; x+=columns)
2036             {
2037               size_t
2038                 columns_remaining,
2039                 row;
2040 
2041               columns_remaining=image->columns-x;
2042               if ((ssize_t) (x+columns) < (ssize_t) image->columns)
2043                 columns_remaining=columns;
2044               if (TIFFReadTile(tiff,tile_pixels,(uint32) x,(uint32) y,0,i) == 0)
2045                 break;
2046               p=tile_pixels;
2047               for (row=0; row < rows_remaining; row++)
2048               {
2049                 Quantum
2050                   *magick_restrict q;
2051 
2052                 q=GetAuthenticPixels(image,x,y+row,columns_remaining,1,
2053                   exception);
2054                 if (q == (Quantum *) NULL)
2055                   break;
2056                 (void) ImportQuantumPixels(image,(CacheView *) NULL,
2057                   quantum_info,quantum_type,p,exception);
2058                 p+=TIFFTileRowSize(tiff);
2059                 if (SyncAuthenticPixels(image,exception) == MagickFalse)
2060                   break;
2061               }
2062             }
2063           }
2064           if ((samples_per_pixel > 1) && (interlace != PLANARCONFIG_SEPARATE))
2065             break;
2066           if (image->previous == (Image *) NULL)
2067             {
2068               status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) i,
2069                 samples_per_pixel);
2070               if (status == MagickFalse)
2071                 break;
2072             }
2073         }
2074         tile_pixels=(unsigned char *) RelinquishMagickMemory(tile_pixels);
2075         break;
2076       }
2077       case ReadGenericMethod:
2078       default:
2079       {
2080         MemoryInfo
2081           *generic_info = (MemoryInfo * ) NULL;
2082 
2083         uint32
2084           *p;
2085 
2086         uint32
2087           *pixels;
2088 
2089         /*
2090           Convert generic TIFF image.
2091         */
2092         if (HeapOverflowSanityCheck(image->rows,sizeof(*pixels)) != MagickFalse)
2093           ThrowTIFFException(ResourceLimitError,"MemoryAllocationFailed");
2094         number_pixels=(MagickSizeType) image->columns*image->rows;
2095 #if defined(TIFF_VERSION_BIG)
2096         number_pixels+=image->columns*sizeof(uint64);
2097 #else
2098         number_pixels+=image->columns*sizeof(uint32);
2099 #endif
2100         generic_info=AcquireVirtualMemory(number_pixels,sizeof(uint32));
2101         if (generic_info == (MemoryInfo *) NULL)
2102           ThrowTIFFException(ResourceLimitError,"MemoryAllocationFailed");
2103         pixels=(uint32 *) GetVirtualMemoryBlob(generic_info);
2104         (void) TIFFReadRGBAImage(tiff,(uint32) image->columns,(uint32)
2105           image->rows,(uint32 *) pixels,0);
2106         p=pixels+(image->columns*image->rows)-1;
2107         for (y=0; y < (ssize_t) image->rows; y++)
2108         {
2109           ssize_t
2110             x;
2111 
2112           Quantum
2113             *magick_restrict q;
2114 
2115           q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
2116           if (q == (Quantum *) NULL)
2117             break;
2118           q+=GetPixelChannels(image)*(image->columns-1);
2119           for (x=0; x < (ssize_t) image->columns; x++)
2120           {
2121             SetPixelRed(image,ScaleCharToQuantum((unsigned char)
2122               TIFFGetR(*p)),q);
2123             SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
2124               TIFFGetG(*p)),q);
2125             SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
2126               TIFFGetB(*p)),q);
2127             if (image->alpha_trait != UndefinedPixelTrait)
2128               SetPixelAlpha(image,ScaleCharToQuantum((unsigned char)
2129                 TIFFGetA(*p)),q);
2130             p--;
2131             q-=GetPixelChannels(image);
2132           }
2133           if (SyncAuthenticPixels(image,exception) == MagickFalse)
2134             break;
2135           if (image->previous == (Image *) NULL)
2136             {
2137               status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
2138                 image->rows);
2139               if (status == MagickFalse)
2140                 break;
2141             }
2142         }
2143         generic_info=RelinquishVirtualMemory(generic_info);
2144         break;
2145       }
2146     }
2147     pixel_info=RelinquishVirtualMemory(pixel_info);
2148     SetQuantumImageType(image,quantum_type);
2149   next_tiff_frame:
2150     if (quantum_info != (QuantumInfo *) NULL)
2151       quantum_info=DestroyQuantumInfo(quantum_info);
2152     if (photometric == PHOTOMETRIC_CIELAB)
2153       DecodeLabImage(image,exception);
2154     if ((photometric == PHOTOMETRIC_LOGL) ||
2155         (photometric == PHOTOMETRIC_MINISBLACK) ||
2156         (photometric == PHOTOMETRIC_MINISWHITE))
2157       {
2158         image->type=GrayscaleType;
2159         if (bits_per_sample == 1)
2160           image->type=BilevelType;
2161       }
2162     /*
2163       Proceed to next image.
2164     */
2165     if (image_info->number_scenes != 0)
2166       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
2167         break;
2168     more_frames=TIFFReadDirectory(tiff) != 0 ? MagickTrue : MagickFalse;
2169     if (more_frames != MagickFalse)
2170       {
2171         /*
2172           Allocate next image structure.
2173         */
2174         AcquireNextImage(image_info,image,exception);
2175         if (GetNextImageInList(image) == (Image *) NULL)
2176           {
2177             status=MagickFalse;
2178             break;
2179           }
2180         image=SyncNextImageInList(image);
2181         status=SetImageProgress(image,LoadImagesTag,image->scene-1,
2182           image->scene);
2183         if (status == MagickFalse)
2184           break;
2185       }
2186   } while ((status != MagickFalse) && (more_frames != MagickFalse));
2187   TIFFClose(tiff);
2188   if (status != MagickFalse)
2189     TIFFReadPhotoshopLayers(image_info,image,exception);
2190   if ((image_info->number_scenes != 0) &&
2191       (image_info->scene >= GetImageListLength(image)))
2192     status=MagickFalse;
2193   if (status == MagickFalse)
2194     return(DestroyImageList(image));
2195   return(GetFirstImageInList(image));
2196 }
2197 #endif
2198 
2199 /*
2200 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2201 %                                                                             %
2202 %                                                                             %
2203 %                                                                             %
2204 %   R e g i s t e r T I F F I m a g e                                         %
2205 %                                                                             %
2206 %                                                                             %
2207 %                                                                             %
2208 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2209 %
2210 %  RegisterTIFFImage() adds properties for the TIFF image format to
2211 %  the list of supported formats.  The properties include the image format
2212 %  tag, a method to read and/or write the format, whether the format
2213 %  supports the saving of more than one frame to the same file or blob,
2214 %  whether the format supports native in-memory I/O, and a brief
2215 %  description of the format.
2216 %
2217 %  The format of the RegisterTIFFImage method is:
2218 %
2219 %      size_t RegisterTIFFImage(void)
2220 %
2221 */
2222 
2223 #if defined(MAGICKCORE_TIFF_DELEGATE)
2224 #if defined(MAGICKCORE_HAVE_TIFFMERGEFIELDINFO) && defined(MAGICKCORE_HAVE_TIFFSETTAGEXTENDER)
2225 static TIFFExtendProc
2226   tag_extender = (TIFFExtendProc) NULL;
2227 
TIFFIgnoreTags(TIFF * tiff)2228 static void TIFFIgnoreTags(TIFF *tiff)
2229 {
2230   char
2231     *q;
2232 
2233   const char
2234     *p,
2235     *tags;
2236 
2237   Image
2238    *image;
2239 
2240   ssize_t
2241     i;
2242 
2243   size_t
2244     count;
2245 
2246   TIFFFieldInfo
2247     *ignore;
2248 
2249   if (TIFFGetReadProc(tiff) != TIFFReadBlob)
2250     return;
2251   image=(Image *)TIFFClientdata(tiff);
2252   tags=GetImageArtifact(image,"tiff:ignore-tags");
2253   if (tags == (const char *) NULL)
2254     return;
2255   count=0;
2256   p=tags;
2257   while (*p != '\0')
2258   {
2259     while ((isspace((int) ((unsigned char) *p)) != 0))
2260       p++;
2261 
2262     (void) strtol(p,&q,10);
2263     if (p == q)
2264       return;
2265 
2266     p=q;
2267     count++;
2268 
2269     while ((isspace((int) ((unsigned char) *p)) != 0) || (*p == ','))
2270       p++;
2271   }
2272   if (count == 0)
2273     return;
2274   i=0;
2275   p=tags;
2276   ignore=(TIFFFieldInfo *) AcquireQuantumMemory(count,sizeof(*ignore));
2277   if (ignore == (TIFFFieldInfo *) NULL)
2278     return;
2279   /*
2280     This also sets field_bit to 0 (FIELD_IGNORE).
2281   */
2282   (void) memset(ignore,0,count*sizeof(*ignore));
2283   while (*p != '\0')
2284   {
2285     while ((isspace((int) ((unsigned char) *p)) != 0))
2286       p++;
2287 
2288     ignore[i].field_tag=(ttag_t) strtol(p,&q,10);
2289 
2290     p=q;
2291     i++;
2292 
2293     while ((isspace((int) ((unsigned char) *p)) != 0) || (*p == ','))
2294       p++;
2295   }
2296   (void) TIFFMergeFieldInfo(tiff,ignore,(uint32) count);
2297   ignore=(TIFFFieldInfo *) RelinquishMagickMemory(ignore);
2298 }
2299 
TIFFTagExtender(TIFF * tiff)2300 static void TIFFTagExtender(TIFF *tiff)
2301 {
2302   static const TIFFFieldInfo
2303     TIFFExtensions[] =
2304     {
2305       { 37724, -3, -3, TIFF_UNDEFINED, FIELD_CUSTOM, 1, 1,
2306         (char *) "PhotoshopLayerData" },
2307       { 34118, -3, -3, TIFF_UNDEFINED, FIELD_CUSTOM, 1, 1,
2308         (char *) "Microscope" }
2309     };
2310 
2311   TIFFMergeFieldInfo(tiff,TIFFExtensions,sizeof(TIFFExtensions)/
2312     sizeof(*TIFFExtensions));
2313   if (tag_extender != (TIFFExtendProc) NULL)
2314     (*tag_extender)(tiff);
2315   TIFFIgnoreTags(tiff);
2316 }
2317 #endif
2318 #endif
2319 
RegisterTIFFImage(void)2320 ModuleExport size_t RegisterTIFFImage(void)
2321 {
2322 #define TIFFDescription  "Tagged Image File Format"
2323 
2324   char
2325     version[MagickPathExtent];
2326 
2327   MagickInfo
2328     *entry;
2329 
2330 #if defined(MAGICKCORE_TIFF_DELEGATE)
2331   if (tiff_semaphore == (SemaphoreInfo *) NULL)
2332     ActivateSemaphoreInfo(&tiff_semaphore);
2333   LockSemaphoreInfo(tiff_semaphore);
2334   if (instantiate_key == MagickFalse)
2335     {
2336       if (CreateMagickThreadKey(&tiff_exception,NULL) == MagickFalse)
2337         ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
2338       error_handler=TIFFSetErrorHandler(TIFFErrors);
2339       warning_handler=TIFFSetWarningHandler(TIFFWarnings);
2340 #if defined(MAGICKCORE_HAVE_TIFFMERGEFIELDINFO) && defined(MAGICKCORE_HAVE_TIFFSETTAGEXTENDER)
2341       if (tag_extender == (TIFFExtendProc) NULL)
2342         tag_extender=TIFFSetTagExtender(TIFFTagExtender);
2343 #endif
2344       instantiate_key=MagickTrue;
2345     }
2346   UnlockSemaphoreInfo(tiff_semaphore);
2347 #endif
2348   *version='\0';
2349 #if defined(TIFF_VERSION)
2350   (void) FormatLocaleString(version,MagickPathExtent,"%d",TIFF_VERSION);
2351 #endif
2352 #if defined(MAGICKCORE_TIFF_DELEGATE)
2353   {
2354     const char
2355       *p;
2356 
2357     ssize_t
2358       i;
2359 
2360     p=TIFFGetVersion();
2361     for (i=0; (i < (MagickPathExtent-1)) && (*p != 0) && (*p != '\n'); i++)
2362       version[i]=(*p++);
2363     version[i]='\0';
2364   }
2365 #endif
2366 
2367   entry=AcquireMagickInfo("TIFF","GROUP4","Raw CCITT Group4");
2368 #if defined(MAGICKCORE_TIFF_DELEGATE)
2369   entry->decoder=(DecodeImageHandler *) ReadGROUP4Image;
2370   entry->encoder=(EncodeImageHandler *) WriteGROUP4Image;
2371 #endif
2372   entry->flags|=CoderRawSupportFlag;
2373   entry->flags|=CoderEndianSupportFlag;
2374   entry->flags|=CoderDecoderSeekableStreamFlag;
2375   entry->flags|=CoderEncoderSeekableStreamFlag;
2376   entry->flags^=CoderAdjoinFlag;
2377   entry->flags^=CoderUseExtensionFlag;
2378   entry->format_type=ImplicitFormatType;
2379   entry->mime_type=ConstantString("image/tiff");
2380   (void) RegisterMagickInfo(entry);
2381   entry=AcquireMagickInfo("TIFF","PTIF","Pyramid encoded TIFF");
2382 #if defined(MAGICKCORE_TIFF_DELEGATE)
2383   entry->decoder=(DecodeImageHandler *) ReadTIFFImage;
2384   entry->encoder=(EncodeImageHandler *) WritePTIFImage;
2385 #endif
2386   entry->flags|=CoderEndianSupportFlag;
2387   entry->flags|=CoderDecoderSeekableStreamFlag;
2388   entry->flags|=CoderEncoderSeekableStreamFlag;
2389   entry->flags^=CoderUseExtensionFlag;
2390   entry->mime_type=ConstantString("image/tiff");
2391   (void) RegisterMagickInfo(entry);
2392   entry=AcquireMagickInfo("TIFF","TIF",TIFFDescription);
2393 #if defined(MAGICKCORE_TIFF_DELEGATE)
2394   entry->decoder=(DecodeImageHandler *) ReadTIFFImage;
2395   entry->encoder=(EncodeImageHandler *) WriteTIFFImage;
2396 #endif
2397   entry->flags|=CoderEndianSupportFlag;
2398   entry->flags|=CoderDecoderSeekableStreamFlag;
2399   entry->flags|=CoderEncoderSeekableStreamFlag;
2400   entry->flags|=CoderStealthFlag;
2401   entry->flags^=CoderUseExtensionFlag;
2402   if (*version != '\0')
2403     entry->version=ConstantString(version);
2404   entry->mime_type=ConstantString("image/tiff");
2405   (void) RegisterMagickInfo(entry);
2406   entry=AcquireMagickInfo("TIFF","TIFF",TIFFDescription);
2407 #if defined(MAGICKCORE_TIFF_DELEGATE)
2408   entry->decoder=(DecodeImageHandler *) ReadTIFFImage;
2409   entry->encoder=(EncodeImageHandler *) WriteTIFFImage;
2410 #endif
2411   entry->magick=(IsImageFormatHandler *) IsTIFF;
2412   entry->flags|=CoderEndianSupportFlag;
2413   entry->flags|=CoderDecoderSeekableStreamFlag;
2414   entry->flags|=CoderEncoderSeekableStreamFlag;
2415   entry->flags^=CoderUseExtensionFlag;
2416   if (*version != '\0')
2417     entry->version=ConstantString(version);
2418   entry->mime_type=ConstantString("image/tiff");
2419   (void) RegisterMagickInfo(entry);
2420   entry=AcquireMagickInfo("TIFF","TIFF64","Tagged Image File Format (64-bit)");
2421 #if defined(TIFF_VERSION_BIG)
2422   entry->decoder=(DecodeImageHandler *) ReadTIFFImage;
2423   entry->encoder=(EncodeImageHandler *) WriteTIFFImage;
2424 #endif
2425   entry->flags|=CoderEndianSupportFlag;
2426   entry->flags|=CoderDecoderSeekableStreamFlag;
2427   entry->flags|=CoderEncoderSeekableStreamFlag;
2428   entry->flags^=CoderUseExtensionFlag;
2429   if (*version != '\0')
2430     entry->version=ConstantString(version);
2431   entry->mime_type=ConstantString("image/tiff");
2432   (void) RegisterMagickInfo(entry);
2433   return(MagickImageCoderSignature);
2434 }
2435 
2436 /*
2437 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2438 %                                                                             %
2439 %                                                                             %
2440 %                                                                             %
2441 %   U n r e g i s t e r T I F F I m a g e                                     %
2442 %                                                                             %
2443 %                                                                             %
2444 %                                                                             %
2445 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2446 %
2447 %  UnregisterTIFFImage() removes format registrations made by the TIFF module
2448 %  from the list of supported formats.
2449 %
2450 %  The format of the UnregisterTIFFImage method is:
2451 %
2452 %      UnregisterTIFFImage(void)
2453 %
2454 */
UnregisterTIFFImage(void)2455 ModuleExport void UnregisterTIFFImage(void)
2456 {
2457   (void) UnregisterMagickInfo("TIFF64");
2458   (void) UnregisterMagickInfo("TIFF");
2459   (void) UnregisterMagickInfo("TIF");
2460   (void) UnregisterMagickInfo("PTIF");
2461 #if defined(MAGICKCORE_TIFF_DELEGATE)
2462   if (tiff_semaphore == (SemaphoreInfo *) NULL)
2463     ActivateSemaphoreInfo(&tiff_semaphore);
2464   LockSemaphoreInfo(tiff_semaphore);
2465   if (instantiate_key != MagickFalse)
2466     {
2467 #if defined(MAGICKCORE_HAVE_TIFFMERGEFIELDINFO) && defined(MAGICKCORE_HAVE_TIFFSETTAGEXTENDER)
2468       if (tag_extender == (TIFFExtendProc) NULL)
2469         (void) TIFFSetTagExtender(tag_extender);
2470 #endif
2471       if (DeleteMagickThreadKey(tiff_exception) == MagickFalse)
2472         ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
2473       (void) TIFFSetWarningHandler(warning_handler);
2474       (void) TIFFSetErrorHandler(error_handler);
2475       instantiate_key=MagickFalse;
2476     }
2477   UnlockSemaphoreInfo(tiff_semaphore);
2478   RelinquishSemaphoreInfo(&tiff_semaphore);
2479 #endif
2480 }
2481 
2482 #if defined(MAGICKCORE_TIFF_DELEGATE)
2483 /*
2484 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2485 %                                                                             %
2486 %                                                                             %
2487 %                                                                             %
2488 %   W r i t e G R O U P 4 I m a g e                                           %
2489 %                                                                             %
2490 %                                                                             %
2491 %                                                                             %
2492 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2493 %
2494 %  WriteGROUP4Image() writes an image in the raw CCITT Group 4 image format.
2495 %
2496 %  The format of the WriteGROUP4Image method is:
2497 %
2498 %      MagickBooleanType WriteGROUP4Image(const ImageInfo *image_info,
2499 %        Image *image,ExceptionInfo *)
2500 %
2501 %  A description of each parameter follows:
2502 %
2503 %    o image_info: the image info.
2504 %
2505 %    o image:  The image.
2506 %
2507 %    o exception: return any errors or warnings in this structure.
2508 %
2509 */
WriteGROUP4Image(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)2510 static MagickBooleanType WriteGROUP4Image(const ImageInfo *image_info,
2511   Image *image,ExceptionInfo *exception)
2512 {
2513   char
2514     filename[MagickPathExtent];
2515 
2516   FILE
2517     *file;
2518 
2519   Image
2520     *huffman_image;
2521 
2522   ImageInfo
2523     *write_info;
2524 
2525   int
2526     unique_file;
2527 
2528   MagickBooleanType
2529     status;
2530 
2531   ssize_t
2532     i;
2533 
2534   ssize_t
2535     count;
2536 
2537   TIFF
2538     *tiff;
2539 
2540   toff_t
2541     *byte_count,
2542     strip_size;
2543 
2544   unsigned char
2545     *buffer;
2546 
2547   /*
2548     Write image as CCITT Group4 TIFF image to a temporary file.
2549   */
2550   assert(image_info != (const ImageInfo *) NULL);
2551   assert(image_info->signature == MagickCoreSignature);
2552   assert(image != (Image *) NULL);
2553   assert(image->signature == MagickCoreSignature);
2554   if (image->debug != MagickFalse)
2555     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2556   assert(exception != (ExceptionInfo *) NULL);
2557   assert(exception->signature == MagickCoreSignature);
2558   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2559   if (status == MagickFalse)
2560     return(status);
2561   huffman_image=CloneImage(image,0,0,MagickTrue,exception);
2562   if (huffman_image == (Image *) NULL)
2563     {
2564       (void) CloseBlob(image);
2565       return(MagickFalse);
2566     }
2567   huffman_image->endian=MSBEndian;
2568   file=(FILE *) NULL;
2569   unique_file=AcquireUniqueFileResource(filename);
2570   if (unique_file != -1)
2571     file=fdopen(unique_file,"wb");
2572   if ((unique_file == -1) || (file == (FILE *) NULL))
2573     {
2574       ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
2575         filename);
2576       return(MagickFalse);
2577     }
2578   (void) FormatLocaleString(huffman_image->filename,MagickPathExtent,"tiff:%s",
2579     filename);
2580   if (IsImageMonochrome(image) == MagickFalse)
2581     (void) SetImageType(huffman_image,BilevelType,exception);
2582   write_info=CloneImageInfo((ImageInfo *) NULL);
2583   SetImageInfoFile(write_info,file);
2584   if (IsImageMonochrome(image) == MagickFalse)
2585     (void) SetImageType(image,BilevelType,exception);
2586   (void) SetImageDepth(image,1,exception);
2587   write_info->compression=Group4Compression;
2588   write_info->type=BilevelType;
2589   status=WriteTIFFImage(write_info,huffman_image,exception);
2590   (void) fflush(file);
2591   write_info=DestroyImageInfo(write_info);
2592   if (status == MagickFalse)
2593     {
2594       huffman_image=DestroyImage(huffman_image);
2595       (void) fclose(file);
2596       (void) RelinquishUniqueFileResource(filename);
2597       return(MagickFalse);
2598     }
2599   tiff=TIFFOpen(filename,"rb");
2600   if (tiff == (TIFF *) NULL)
2601     {
2602       huffman_image=DestroyImage(huffman_image);
2603       (void) fclose(file);
2604       (void) RelinquishUniqueFileResource(filename);
2605       ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
2606         image_info->filename);
2607       return(MagickFalse);
2608     }
2609   /*
2610     Allocate raw strip buffer.
2611   */
2612   if (TIFFGetField(tiff,TIFFTAG_STRIPBYTECOUNTS,&byte_count) != 1)
2613     {
2614       TIFFClose(tiff);
2615       huffman_image=DestroyImage(huffman_image);
2616       (void) fclose(file);
2617       (void) RelinquishUniqueFileResource(filename);
2618       return(MagickFalse);
2619     }
2620   strip_size=byte_count[0];
2621   for (i=1; i < (ssize_t) TIFFNumberOfStrips(tiff); i++)
2622     if (byte_count[i] > strip_size)
2623       strip_size=byte_count[i];
2624   buffer=(unsigned char *) AcquireQuantumMemory((size_t) strip_size,
2625     sizeof(*buffer));
2626   if (buffer == (unsigned char *) NULL)
2627     {
2628       TIFFClose(tiff);
2629       huffman_image=DestroyImage(huffman_image);
2630       (void) fclose(file);
2631       (void) RelinquishUniqueFileResource(filename);
2632       ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
2633         image_info->filename);
2634     }
2635   /*
2636     Compress runlength encoded to 2D Huffman pixels.
2637   */
2638   for (i=0; i < (ssize_t) TIFFNumberOfStrips(tiff); i++)
2639   {
2640     count=(ssize_t) TIFFReadRawStrip(tiff,(uint32) i,buffer,strip_size);
2641     if (WriteBlob(image,(size_t) count,buffer) != count)
2642       status=MagickFalse;
2643   }
2644   buffer=(unsigned char *) RelinquishMagickMemory(buffer);
2645   TIFFClose(tiff);
2646   huffman_image=DestroyImage(huffman_image);
2647   (void) fclose(file);
2648   (void) RelinquishUniqueFileResource(filename);
2649   (void) CloseBlob(image);
2650   return(status);
2651 }
2652 #endif
2653 
2654 #if defined(MAGICKCORE_TIFF_DELEGATE)
2655 /*
2656 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2657 %                                                                             %
2658 %                                                                             %
2659 %                                                                             %
2660 %   W r i t e P T I F I m a g e                                               %
2661 %                                                                             %
2662 %                                                                             %
2663 %                                                                             %
2664 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2665 %
2666 %  WritePTIFImage() writes an image in the pyrimid-encoded Tagged image file
2667 %  format.
2668 %
2669 %  The format of the WritePTIFImage method is:
2670 %
2671 %      MagickBooleanType WritePTIFImage(const ImageInfo *image_info,
2672 %        Image *image,ExceptionInfo *exception)
2673 %
2674 %  A description of each parameter follows:
2675 %
2676 %    o image_info: the image info.
2677 %
2678 %    o image:  The image.
2679 %
2680 %    o exception: return any errors or warnings in this structure.
2681 %
2682 */
WritePTIFImage(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)2683 static MagickBooleanType WritePTIFImage(const ImageInfo *image_info,
2684   Image *image,ExceptionInfo *exception)
2685 {
2686   Image
2687     *images,
2688     *next,
2689     *pyramid_image;
2690 
2691   ImageInfo
2692     *write_info;
2693 
2694   MagickBooleanType
2695     status;
2696 
2697   PointInfo
2698     resolution;
2699 
2700   size_t
2701     columns,
2702     rows;
2703 
2704   /*
2705     Create pyramid-encoded TIFF image.
2706   */
2707   images=NewImageList();
2708   for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
2709   {
2710     Image
2711       *clone_image;
2712 
2713     clone_image=CloneImage(next,0,0,MagickFalse,exception);
2714     if (clone_image == (Image *) NULL)
2715       break;
2716     clone_image->previous=NewImageList();
2717     clone_image->next=NewImageList();
2718     (void) SetImageProperty(clone_image,"tiff:subfiletype","none",exception);
2719     AppendImageToList(&images,clone_image);
2720     columns=next->columns;
2721     rows=next->rows;
2722     resolution=next->resolution;
2723     while ((columns > 64) && (rows > 64))
2724     {
2725       columns/=2;
2726       rows/=2;
2727       resolution.x/=2;
2728       resolution.y/=2;
2729       pyramid_image=ResizeImage(next,columns,rows,image->filter,exception);
2730       if (pyramid_image == (Image *) NULL)
2731         break;
2732       DestroyBlob(pyramid_image);
2733       pyramid_image->blob=ReferenceBlob(next->blob);
2734       pyramid_image->resolution=resolution;
2735       (void) SetImageProperty(pyramid_image,"tiff:subfiletype","REDUCEDIMAGE",
2736         exception);
2737       AppendImageToList(&images,pyramid_image);
2738     }
2739   }
2740   status=MagickFalse;
2741   if (images != (Image *) NULL)
2742     {
2743       /*
2744         Write pyramid-encoded TIFF image.
2745       */
2746       images=GetFirstImageInList(images);
2747       write_info=CloneImageInfo(image_info);
2748       write_info->adjoin=MagickTrue;
2749       (void) CopyMagickString(write_info->magick,"TIFF",MagickPathExtent);
2750       (void) CopyMagickString(images->magick,"TIFF",MagickPathExtent);
2751       status=WriteTIFFImage(write_info,images,exception);
2752       images=DestroyImageList(images);
2753       write_info=DestroyImageInfo(write_info);
2754     }
2755   return(status);
2756 }
2757 #endif
2758 
2759 #if defined(MAGICKCORE_TIFF_DELEGATE)
2760 /*
2761 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2762 %                                                                             %
2763 %                                                                             %
2764 %                                                                             %
2765 %   W r i t e T I F F I m a g e                                               %
2766 %                                                                             %
2767 %                                                                             %
2768 %                                                                             %
2769 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2770 %
2771 %  WriteTIFFImage() writes an image in the Tagged image file format.
2772 %
2773 %  The format of the WriteTIFFImage method is:
2774 %
2775 %      MagickBooleanType WriteTIFFImage(const ImageInfo *image_info,
2776 %        Image *image,ExceptionInfo *exception)
2777 %
2778 %  A description of each parameter follows:
2779 %
2780 %    o image_info: the image info.
2781 %
2782 %    o image:  The image.
2783 %
2784 %    o exception: return any errors or warnings in this structure.
2785 %
2786 */
2787 
2788 typedef struct _TIFFInfo
2789 {
2790   RectangleInfo
2791     tile_geometry;
2792 
2793   unsigned char
2794     *scanline,
2795     *scanlines,
2796     *pixels;
2797 } TIFFInfo;
2798 
DestroyTIFFInfo(TIFFInfo * tiff_info)2799 static void DestroyTIFFInfo(TIFFInfo *tiff_info)
2800 {
2801   assert(tiff_info != (TIFFInfo *) NULL);
2802   if (tiff_info->scanlines != (unsigned char *) NULL)
2803     tiff_info->scanlines=(unsigned char *) RelinquishMagickMemory(
2804       tiff_info->scanlines);
2805   if (tiff_info->pixels != (unsigned char *) NULL)
2806     tiff_info->pixels=(unsigned char *) RelinquishMagickMemory(
2807       tiff_info->pixels);
2808 }
2809 
EncodeLabImage(Image * image,ExceptionInfo * exception)2810 static MagickBooleanType EncodeLabImage(Image *image,ExceptionInfo *exception)
2811 {
2812   CacheView
2813     *image_view;
2814 
2815   MagickBooleanType
2816     status;
2817 
2818   ssize_t
2819     y;
2820 
2821   status=MagickTrue;
2822   image_view=AcquireAuthenticCacheView(image,exception);
2823   for (y=0; y < (ssize_t) image->rows; y++)
2824   {
2825     Quantum
2826       *magick_restrict q;
2827 
2828     ssize_t
2829       x;
2830 
2831     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2832     if (q == (Quantum *) NULL)
2833       {
2834         status=MagickFalse;
2835         break;
2836       }
2837     for (x=0; x < (ssize_t) image->columns; x++)
2838     {
2839       double
2840         a,
2841         b;
2842 
2843       a=QuantumScale*GetPixela(image,q)-0.5;
2844       if (a < 0.0)
2845         a+=1.0;
2846       b=QuantumScale*GetPixelb(image,q)-0.5;
2847       if (b < 0.0)
2848         b+=1.0;
2849       SetPixela(image,QuantumRange*a,q);
2850       SetPixelb(image,QuantumRange*b,q);
2851       q+=GetPixelChannels(image);
2852     }
2853     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2854       {
2855         status=MagickFalse;
2856         break;
2857       }
2858   }
2859   image_view=DestroyCacheView(image_view);
2860   return(status);
2861 }
2862 
GetTIFFInfo(const ImageInfo * image_info,TIFF * tiff,TIFFInfo * tiff_info)2863 static MagickBooleanType GetTIFFInfo(const ImageInfo *image_info,
2864   TIFF *tiff,TIFFInfo *tiff_info)
2865 {
2866 #define TIFFStripSizeDefault  1048576
2867 
2868   const char
2869     *option;
2870 
2871   MagickStatusType
2872     flags;
2873 
2874   uint32
2875     tile_columns,
2876     tile_rows;
2877 
2878   assert(tiff_info != (TIFFInfo *) NULL);
2879   (void) memset(tiff_info,0,sizeof(*tiff_info));
2880   option=GetImageOption(image_info,"tiff:tile-geometry");
2881   if (option == (const char *) NULL)
2882     {
2883       size_t
2884         extent;
2885 
2886       uint32
2887         rows,
2888         rows_per_strip;
2889 
2890       extent=TIFFScanlineSize(tiff);
2891       rows_per_strip=TIFFStripSizeDefault/(extent == 0 ? 1 : (uint32) extent);
2892       rows_per_strip=16*(((rows_per_strip < 16 ? 16 : rows_per_strip)+1)/16);
2893       TIFFGetField(tiff,TIFFTAG_IMAGELENGTH,&rows);
2894       if (rows_per_strip > rows)
2895         rows_per_strip=rows;
2896       option=GetImageOption(image_info,"tiff:rows-per-strip");
2897       if (option != (const char *) NULL)
2898         rows_per_strip=(uint32) strtoul(option,(char **) NULL,10);
2899       rows_per_strip=TIFFDefaultStripSize(tiff,rows_per_strip);
2900       (void) TIFFSetField(tiff,TIFFTAG_ROWSPERSTRIP,rows_per_strip);
2901       return(MagickTrue);
2902     }
2903   /*
2904     Create tiled TIFF, ignore "tiff:rows-per-strip".
2905   */
2906   flags=ParseAbsoluteGeometry(option,&tiff_info->tile_geometry);
2907   if ((flags & HeightValue) == 0)
2908     tiff_info->tile_geometry.height=tiff_info->tile_geometry.width;
2909   tile_columns=(uint32) tiff_info->tile_geometry.width;
2910   tile_rows=(uint32) tiff_info->tile_geometry.height;
2911   TIFFDefaultTileSize(tiff,&tile_columns,&tile_rows);
2912   (void) TIFFSetField(tiff,TIFFTAG_TILEWIDTH,tile_columns);
2913   (void) TIFFSetField(tiff,TIFFTAG_TILELENGTH,tile_rows);
2914   tiff_info->tile_geometry.width=tile_columns;
2915   tiff_info->tile_geometry.height=tile_rows;
2916   if ((TIFFScanlineSize(tiff) <= 0) || (TIFFTileSize(tiff) <= 0))
2917     {
2918       DestroyTIFFInfo(tiff_info);
2919       return(MagickFalse);
2920     }
2921   tiff_info->scanlines=(unsigned char *) AcquireQuantumMemory((size_t)
2922     tile_rows*TIFFScanlineSize(tiff),sizeof(*tiff_info->scanlines));
2923   tiff_info->pixels=(unsigned char *) AcquireQuantumMemory((size_t)
2924     tile_rows*TIFFTileSize(tiff),sizeof(*tiff_info->scanlines));
2925   if ((tiff_info->scanlines == (unsigned char *) NULL) ||
2926       (tiff_info->pixels == (unsigned char *) NULL))
2927     {
2928       DestroyTIFFInfo(tiff_info);
2929       return(MagickFalse);
2930     }
2931   return(MagickTrue);
2932 }
2933 
TIFFWritePixels(TIFF * tiff,TIFFInfo * tiff_info,ssize_t row,tsample_t sample,Image * image)2934 static int32 TIFFWritePixels(TIFF *tiff,TIFFInfo *tiff_info,ssize_t row,
2935   tsample_t sample,Image *image)
2936 {
2937   int32
2938     status;
2939 
2940   ssize_t
2941     i;
2942 
2943   unsigned char
2944     *p,
2945     *q;
2946 
2947   size_t
2948     number_tiles,
2949     tile_width;
2950 
2951   ssize_t
2952     bytes_per_pixel,
2953     j,
2954     k,
2955     l;
2956 
2957   if (TIFFIsTiled(tiff) == 0)
2958     return(TIFFWriteScanline(tiff,tiff_info->scanline,(uint32) row,sample));
2959   /*
2960     Fill scanlines to tile height.
2961   */
2962   i=(ssize_t) (row % tiff_info->tile_geometry.height)*TIFFScanlineSize(tiff);
2963   (void) memcpy(tiff_info->scanlines+i,(char *) tiff_info->scanline,
2964     (size_t) TIFFScanlineSize(tiff));
2965   if (((size_t) (row % tiff_info->tile_geometry.height) !=
2966       (tiff_info->tile_geometry.height-1)) &&
2967       (row != (ssize_t) (image->rows-1)))
2968     return(0);
2969   /*
2970     Write tile to TIFF image.
2971   */
2972   status=0;
2973   bytes_per_pixel=TIFFTileSize(tiff)/(ssize_t) (
2974     tiff_info->tile_geometry.height*tiff_info->tile_geometry.width);
2975   number_tiles=(image->columns+tiff_info->tile_geometry.width)/
2976     tiff_info->tile_geometry.width;
2977   for (i=0; i < (ssize_t) number_tiles; i++)
2978   {
2979     tile_width=(i == (ssize_t) (number_tiles-1)) ? image->columns-(i*
2980       tiff_info->tile_geometry.width) : tiff_info->tile_geometry.width;
2981     for (j=0; j < (ssize_t) ((row % tiff_info->tile_geometry.height)+1); j++)
2982       for (k=0; k < (ssize_t) tile_width; k++)
2983       {
2984         if (bytes_per_pixel == 0)
2985           {
2986             p=tiff_info->scanlines+(j*TIFFScanlineSize(tiff)+(i*
2987               tiff_info->tile_geometry.width+k)/8);
2988             q=tiff_info->pixels+(j*TIFFTileRowSize(tiff)+k/8);
2989             *q++=(*p++);
2990             continue;
2991           }
2992         p=tiff_info->scanlines+(j*TIFFScanlineSize(tiff)+(i*
2993           tiff_info->tile_geometry.width+k)*bytes_per_pixel);
2994         q=tiff_info->pixels+(j*TIFFTileRowSize(tiff)+k*bytes_per_pixel);
2995         for (l=0; l < bytes_per_pixel; l++)
2996           *q++=(*p++);
2997       }
2998     if ((i*tiff_info->tile_geometry.width) != image->columns)
2999       status=TIFFWriteTile(tiff,tiff_info->pixels,(uint32) (i*
3000         tiff_info->tile_geometry.width),(uint32) ((row/
3001         tiff_info->tile_geometry.height)*tiff_info->tile_geometry.height),0,
3002         sample);
3003     if (status < 0)
3004       break;
3005   }
3006   return(status);
3007 }
3008 
TIFFWriteCustomStream(unsigned char * data,const size_t count,void * user_data)3009 static ssize_t TIFFWriteCustomStream(unsigned char *data,const size_t count,
3010   void *user_data)
3011 {
3012   PhotoshopProfile
3013     *profile;
3014 
3015   if (count == 0)
3016     return(0);
3017   profile=(PhotoshopProfile *) user_data;
3018   if ((profile->offset+(MagickOffsetType) count) >=
3019         (MagickOffsetType) profile->extent)
3020     {
3021       profile->extent+=count+profile->quantum;
3022       profile->quantum<<=1;
3023       SetStringInfoLength(profile->data,profile->extent);
3024     }
3025   (void) memcpy(profile->data->datum+profile->offset,data,count);
3026   profile->offset+=count;
3027   return(count);
3028 }
3029 
TIFFAcquireCustomStreamForWriting(PhotoshopProfile * profile,ExceptionInfo * exception)3030 static CustomStreamInfo *TIFFAcquireCustomStreamForWriting(
3031   PhotoshopProfile *profile,ExceptionInfo *exception)
3032 {
3033   CustomStreamInfo
3034     *custom_stream;
3035 
3036   custom_stream=AcquireCustomStreamInfo(exception);
3037   if (custom_stream == (CustomStreamInfo *) NULL)
3038     return(custom_stream);
3039   SetCustomStreamData(custom_stream,(void *) profile);
3040   SetCustomStreamWriter(custom_stream,TIFFWriteCustomStream);
3041   SetCustomStreamSeeker(custom_stream,TIFFSeekCustomStream);
3042   SetCustomStreamTeller(custom_stream,TIFFTellCustomStream);
3043   return(custom_stream);
3044 }
3045 
TIFFWritePhotoshopLayers(Image * image,const ImageInfo * image_info,EndianType endian,ExceptionInfo * exception)3046 static MagickBooleanType TIFFWritePhotoshopLayers(Image* image,
3047   const ImageInfo *image_info,EndianType endian,ExceptionInfo *exception)
3048 {
3049   BlobInfo
3050     *blob;
3051 
3052   CustomStreamInfo
3053     *custom_stream;
3054 
3055   Image
3056     *base_image,
3057     *next;
3058 
3059   ImageInfo
3060     *clone_info;
3061 
3062   MagickBooleanType
3063     status;
3064 
3065   PhotoshopProfile
3066     profile;
3067 
3068   PSDInfo
3069     info;
3070 
3071   StringInfo
3072     *layers;
3073 
3074   base_image=CloneImage(image,0,0,MagickFalse,exception);
3075   if (base_image == (Image *) NULL)
3076     return(MagickTrue);
3077   clone_info=CloneImageInfo(image_info);
3078   if (clone_info == (ImageInfo *) NULL)
3079     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
3080       image->filename);
3081   profile.offset=0;
3082   profile.quantum=MagickMinBlobExtent;
3083   layers=AcquireStringInfo(profile.quantum);
3084   if (layers == (StringInfo *) NULL)
3085     {
3086       base_image=DestroyImage(base_image);
3087       clone_info=DestroyImageInfo(clone_info);
3088       ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
3089         image->filename);
3090     }
3091   profile.data=layers;
3092   profile.extent=layers->length;
3093   custom_stream=TIFFAcquireCustomStreamForWriting(&profile,exception);
3094   if (custom_stream == (CustomStreamInfo *) NULL)
3095     {
3096       base_image=DestroyImage(base_image);
3097       clone_info=DestroyImageInfo(clone_info);
3098       layers=DestroyStringInfo(layers);
3099       ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
3100         image->filename);
3101     }
3102   blob=CloneBlobInfo((BlobInfo *) NULL);
3103   if (blob == (BlobInfo *) NULL)
3104     {
3105       base_image=DestroyImage(base_image);
3106       clone_info=DestroyImageInfo(clone_info);
3107       layers=DestroyStringInfo(layers);
3108       custom_stream=DestroyCustomStreamInfo(custom_stream);
3109       ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
3110         image->filename);
3111     }
3112   DestroyBlob(base_image);
3113   base_image->blob=blob;
3114   next=base_image;
3115   while (next != (Image *) NULL)
3116     next=SyncNextImageInList(next);
3117   AttachCustomStream(base_image->blob,custom_stream);
3118   InitPSDInfo(image,&info);
3119   base_image->endian=endian;
3120   WriteBlobString(base_image,"Adobe Photoshop Document Data Block");
3121   WriteBlobByte(base_image,0);
3122   WriteBlobString(base_image,base_image->endian == LSBEndian ? "MIB8ryaL" :
3123     "8BIMLayr");
3124   status=WritePSDLayers(base_image,clone_info,&info,exception);
3125   if (status != MagickFalse)
3126     {
3127       SetStringInfoLength(layers,(size_t) profile.offset);
3128       status=SetImageProfile(image,"tiff:37724",layers,exception);
3129     }
3130   next=base_image;
3131   while (next != (Image *) NULL)
3132   {
3133     CloseBlob(next);
3134     next=next->next;
3135   }
3136   layers=DestroyStringInfo(layers);
3137   clone_info=DestroyImageInfo(clone_info);
3138   custom_stream=DestroyCustomStreamInfo(custom_stream);
3139   return(status);
3140 }
3141 
TIFFSetProfiles(TIFF * tiff,Image * image)3142 static void TIFFSetProfiles(TIFF *tiff,Image *image)
3143 {
3144   const char
3145     *name;
3146 
3147   const StringInfo
3148     *profile;
3149 
3150   if (image->profiles == (void *) NULL)
3151     return;
3152   ResetImageProfileIterator(image);
3153   for (name=GetNextImageProfile(image); name != (const char *) NULL; )
3154   {
3155     profile=GetImageProfile(image,name);
3156     if (GetStringInfoLength(profile) == 0)
3157       {
3158         name=GetNextImageProfile(image);
3159         continue;
3160       }
3161 #if defined(TIFFTAG_XMLPACKET)
3162     if (LocaleCompare(name,"xmp") == 0)
3163       (void) TIFFSetField(tiff,TIFFTAG_XMLPACKET,(uint32) GetStringInfoLength(
3164         profile),GetStringInfoDatum(profile));
3165 #endif
3166 #if defined(TIFFTAG_ICCPROFILE)
3167     if (LocaleCompare(name,"icc") == 0)
3168       (void) TIFFSetField(tiff,TIFFTAG_ICCPROFILE,(uint32) GetStringInfoLength(
3169         profile),GetStringInfoDatum(profile));
3170 #endif
3171     if (LocaleCompare(name,"iptc") == 0)
3172       {
3173         size_t
3174           length;
3175 
3176         StringInfo
3177           *iptc_profile;
3178 
3179         iptc_profile=CloneStringInfo(profile);
3180         length=GetStringInfoLength(profile)+4-(GetStringInfoLength(profile) &
3181           0x03);
3182         SetStringInfoLength(iptc_profile,length);
3183         if (TIFFIsByteSwapped(tiff))
3184           TIFFSwabArrayOfLong((uint32 *) GetStringInfoDatum(iptc_profile),
3185             (unsigned long) (length/4));
3186         (void) TIFFSetField(tiff,TIFFTAG_RICHTIFFIPTC,(uint32)
3187           GetStringInfoLength(iptc_profile)/4,GetStringInfoDatum(iptc_profile));
3188         iptc_profile=DestroyStringInfo(iptc_profile);
3189       }
3190 #if defined(TIFFTAG_PHOTOSHOP)
3191     if (LocaleCompare(name,"8bim") == 0)
3192       (void) TIFFSetField(tiff,TIFFTAG_PHOTOSHOP,(uint32)
3193         GetStringInfoLength(profile),GetStringInfoDatum(profile));
3194 #endif
3195     if (LocaleCompare(name,"tiff:37724") == 0)
3196       (void) TIFFSetField(tiff,37724,(uint32) GetStringInfoLength(profile),
3197         GetStringInfoDatum(profile));
3198     if (LocaleCompare(name,"tiff:34118") == 0)
3199       (void) TIFFSetField(tiff,34118,(uint32) GetStringInfoLength(profile),
3200         GetStringInfoDatum(profile));
3201     name=GetNextImageProfile(image);
3202   }
3203 }
3204 
TIFFSetProperties(TIFF * tiff,const MagickBooleanType adjoin,Image * image,ExceptionInfo * exception)3205 static void TIFFSetProperties(TIFF *tiff,const MagickBooleanType adjoin,
3206   Image *image,ExceptionInfo *exception)
3207 {
3208   const char
3209     *value;
3210 
3211   value=GetImageArtifact(image,"tiff:document");
3212   if (value != (const char *) NULL)
3213     (void) TIFFSetField(tiff,TIFFTAG_DOCUMENTNAME,value);
3214   value=GetImageArtifact(image,"tiff:hostcomputer");
3215   if (value != (const char *) NULL)
3216     (void) TIFFSetField(tiff,TIFFTAG_HOSTCOMPUTER,value);
3217   value=GetImageArtifact(image,"tiff:artist");
3218   if (value != (const char *) NULL)
3219     (void) TIFFSetField(tiff,TIFFTAG_ARTIST,value);
3220   value=GetImageArtifact(image,"tiff:timestamp");
3221   if (value != (const char *) NULL)
3222     (void) TIFFSetField(tiff,TIFFTAG_DATETIME,value);
3223   value=GetImageArtifact(image,"tiff:make");
3224   if (value != (const char *) NULL)
3225     (void) TIFFSetField(tiff,TIFFTAG_MAKE,value);
3226   value=GetImageArtifact(image,"tiff:model");
3227   if (value != (const char *) NULL)
3228     (void) TIFFSetField(tiff,TIFFTAG_MODEL,value);
3229   value=GetImageArtifact(image,"tiff:software");
3230   if (value != (const char *) NULL)
3231     (void) TIFFSetField(tiff,TIFFTAG_SOFTWARE,value);
3232   value=GetImageArtifact(image,"tiff:copyright");
3233   if (value != (const char *) NULL)
3234     (void) TIFFSetField(tiff,TIFFTAG_COPYRIGHT,value);
3235   value=GetImageArtifact(image,"kodak-33423");
3236   if (value != (const char *) NULL)
3237     (void) TIFFSetField(tiff,33423,value);
3238   value=GetImageArtifact(image,"kodak-36867");
3239   if (value != (const char *) NULL)
3240     (void) TIFFSetField(tiff,36867,value);
3241   value=GetImageProperty(image,"label",exception);
3242   if (value != (const char *) NULL)
3243     (void) TIFFSetField(tiff,TIFFTAG_PAGENAME,value);
3244   value=GetImageProperty(image,"comment",exception);
3245   if (value != (const char *) NULL)
3246     (void) TIFFSetField(tiff,TIFFTAG_IMAGEDESCRIPTION,value);
3247   value=GetImageArtifact(image,"tiff:subfiletype");
3248   if (value != (const char *) NULL)
3249     {
3250       if (LocaleCompare(value,"REDUCEDIMAGE") == 0)
3251         (void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_REDUCEDIMAGE);
3252       else
3253         if (LocaleCompare(value,"PAGE") == 0)
3254           (void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_PAGE);
3255         else
3256           if (LocaleCompare(value,"MASK") == 0)
3257             (void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_MASK);
3258     }
3259   else
3260     {
3261       uint16
3262         page,
3263         pages;
3264 
3265       page=(uint16) image->scene;
3266       pages=(uint16) GetImageListLength(image);
3267       if ((adjoin != MagickFalse) && (pages > 1))
3268         (void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_PAGE);
3269       (void) TIFFSetField(tiff,TIFFTAG_PAGENUMBER,page,pages);
3270     }
3271 }
3272 
WriteTIFFImage(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)3273 static MagickBooleanType WriteTIFFImage(const ImageInfo *image_info,
3274   Image *image,ExceptionInfo *exception)
3275 {
3276   const char
3277     *mode,
3278     *option;
3279 
3280   CompressionType
3281     compression;
3282 
3283   EndianType
3284     endian_type;
3285 
3286   MagickBooleanType
3287     adjoin,
3288     preserve_compression,
3289     status;
3290 
3291   MagickOffsetType
3292     scene;
3293 
3294   QuantumInfo
3295     *quantum_info;
3296 
3297   QuantumType
3298     quantum_type;
3299 
3300   ssize_t
3301     i;
3302 
3303   size_t
3304     imageListLength,
3305     length;
3306 
3307   ssize_t
3308     y;
3309 
3310   TIFF
3311     *tiff;
3312 
3313   TIFFInfo
3314     tiff_info;
3315 
3316   uint16
3317     bits_per_sample,
3318     compress_tag,
3319     endian,
3320     photometric,
3321     predictor;
3322 
3323   unsigned char
3324     *pixels;
3325 
3326   void
3327     *sans[2] = { NULL, NULL };
3328 
3329   /*
3330     Open TIFF file.
3331   */
3332   assert(image_info != (const ImageInfo *) NULL);
3333   assert(image_info->signature == MagickCoreSignature);
3334   assert(image != (Image *) NULL);
3335   assert(image->signature == MagickCoreSignature);
3336   if (image->debug != MagickFalse)
3337     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3338   assert(exception != (ExceptionInfo *) NULL);
3339   assert(exception->signature == MagickCoreSignature);
3340   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
3341   if (status == MagickFalse)
3342     return(status);
3343   (void) SetMagickThreadValue(tiff_exception,exception);
3344   endian_type=(HOST_FILLORDER == FILLORDER_LSB2MSB) ? LSBEndian : MSBEndian;
3345   option=GetImageOption(image_info,"tiff:endian");
3346   if (option != (const char *) NULL)
3347     {
3348       if (LocaleNCompare(option,"msb",3) == 0)
3349         endian_type=MSBEndian;
3350       if (LocaleNCompare(option,"lsb",3) == 0)
3351         endian_type=LSBEndian;
3352     }
3353   mode=endian_type == LSBEndian ? "wl" : "wb";
3354 #if defined(TIFF_VERSION_BIG)
3355   if (LocaleCompare(image_info->magick,"TIFF64") == 0)
3356     mode=endian_type == LSBEndian ? "wl8" : "wb8";
3357 #endif
3358   tiff=TIFFClientOpen(image->filename,mode,(thandle_t) image,TIFFReadBlob,
3359     TIFFWriteBlob,TIFFSeekBlob,TIFFCloseBlob,TIFFGetBlobSize,TIFFMapBlob,
3360     TIFFUnmapBlob);
3361   if (tiff == (TIFF *) NULL)
3362     return(MagickFalse);
3363   if (exception->severity > ErrorException)
3364     {
3365       TIFFClose(tiff);
3366       return(MagickFalse);
3367     }
3368   (void) DeleteImageProfile(image,"tiff:37724");
3369   scene=0;
3370   adjoin=image_info->adjoin;
3371   imageListLength=GetImageListLength(image);
3372   option=GetImageOption(image_info,"tiff:preserve-compression");
3373   preserve_compression=IsStringTrue(option);
3374   do
3375   {
3376     /*
3377       Initialize TIFF fields.
3378     */
3379     if ((image_info->type != UndefinedType) &&
3380         (image_info->type != OptimizeType))
3381       (void) SetImageType(image,image_info->type,exception);
3382     compression=image_info->compression;
3383     if (preserve_compression != MagickFalse)
3384       compression=image->compression;
3385     switch (compression)
3386     {
3387       case FaxCompression:
3388       case Group4Compression:
3389       {
3390         if (IsImageMonochrome(image) == MagickFalse)
3391           {
3392             if (IsImageGray(image) == MagickFalse)
3393               (void) SetImageType(image,BilevelType,exception);
3394             else
3395               (void) SetImageDepth(image,1,exception);
3396           }
3397         image->depth=1;
3398         break;
3399       }
3400       case JPEGCompression:
3401       {
3402         (void) SetImageStorageClass(image,DirectClass,exception);
3403         (void) SetImageDepth(image,8,exception);
3404         break;
3405       }
3406       default:
3407         break;
3408     }
3409     quantum_info=AcquireQuantumInfo(image_info,image);
3410     if (quantum_info == (QuantumInfo *) NULL)
3411       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3412     if ((image->storage_class != PseudoClass) && (image->depth >= 32) &&
3413         (quantum_info->format == UndefinedQuantumFormat) &&
3414         (IsHighDynamicRangeImage(image,exception) != MagickFalse))
3415       {
3416         status=SetQuantumFormat(image,quantum_info,FloatingPointQuantumFormat);
3417         if (status == MagickFalse)
3418           {
3419             quantum_info=DestroyQuantumInfo(quantum_info);
3420             ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3421           }
3422       }
3423     if ((LocaleCompare(image_info->magick,"PTIF") == 0) &&
3424         (GetPreviousImageInList(image) != (Image *) NULL))
3425       (void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_REDUCEDIMAGE);
3426     if ((image->columns != (uint32) image->columns) ||
3427         (image->rows != (uint32) image->rows))
3428       ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
3429     (void) TIFFSetField(tiff,TIFFTAG_IMAGELENGTH,(uint32) image->rows);
3430     (void) TIFFSetField(tiff,TIFFTAG_IMAGEWIDTH,(uint32) image->columns);
3431     switch (compression)
3432     {
3433       case FaxCompression:
3434       {
3435         compress_tag=COMPRESSION_CCITTFAX3;
3436         option=GetImageOption(image_info,"quantum:polarity");
3437         if (option == (const char *) NULL)
3438           SetQuantumMinIsWhite(quantum_info,MagickTrue);
3439         break;
3440       }
3441       case Group4Compression:
3442       {
3443         compress_tag=COMPRESSION_CCITTFAX4;
3444         option=GetImageOption(image_info,"quantum:polarity");
3445         if (option == (const char *) NULL)
3446           SetQuantumMinIsWhite(quantum_info,MagickTrue);
3447         break;
3448       }
3449 #if defined(COMPRESSION_JBIG)
3450       case JBIG1Compression:
3451       {
3452         compress_tag=COMPRESSION_JBIG;
3453         break;
3454       }
3455 #endif
3456       case JPEGCompression:
3457       {
3458         compress_tag=COMPRESSION_JPEG;
3459         break;
3460       }
3461 #if defined(COMPRESSION_LZMA)
3462       case LZMACompression:
3463       {
3464         compress_tag=COMPRESSION_LZMA;
3465         break;
3466       }
3467 #endif
3468       case LZWCompression:
3469       {
3470         compress_tag=COMPRESSION_LZW;
3471         break;
3472       }
3473       case RLECompression:
3474       {
3475         compress_tag=COMPRESSION_PACKBITS;
3476         break;
3477       }
3478       case ZipCompression:
3479       {
3480         compress_tag=COMPRESSION_ADOBE_DEFLATE;
3481         break;
3482       }
3483 #if defined(COMPRESSION_ZSTD)
3484       case ZstdCompression:
3485       {
3486         compress_tag=COMPRESSION_ZSTD;
3487         break;
3488       }
3489 #endif
3490       case NoCompression:
3491       default:
3492       {
3493         compress_tag=COMPRESSION_NONE;
3494         break;
3495       }
3496     }
3497 #if defined(MAGICKCORE_HAVE_TIFFISCODECCONFIGURED) || (TIFFLIB_VERSION > 20040919)
3498     if ((compress_tag != COMPRESSION_NONE) &&
3499         (TIFFIsCODECConfigured(compress_tag) == 0))
3500       {
3501         (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
3502           "CompressionNotSupported","`%s'",CommandOptionToMnemonic(
3503           MagickCompressOptions,(ssize_t) compression));
3504         compress_tag=COMPRESSION_NONE;
3505         compression=NoCompression;
3506       }
3507 #else
3508       switch (compress_tag)
3509       {
3510 #if defined(CCITT_SUPPORT)
3511         case COMPRESSION_CCITTFAX3:
3512         case COMPRESSION_CCITTFAX4:
3513 #endif
3514 #if defined(YCBCR_SUPPORT) && defined(JPEG_SUPPORT)
3515         case COMPRESSION_JPEG:
3516 #endif
3517 #if defined(LZMA_SUPPORT) && defined(COMPRESSION_LZMA)
3518         case COMPRESSION_LZMA:
3519 #endif
3520 #if defined(LZW_SUPPORT)
3521         case COMPRESSION_LZW:
3522 #endif
3523 #if defined(PACKBITS_SUPPORT)
3524         case COMPRESSION_PACKBITS:
3525 #endif
3526 #if defined(ZIP_SUPPORT)
3527         case COMPRESSION_ADOBE_DEFLATE:
3528 #endif
3529         case COMPRESSION_NONE:
3530           break;
3531         default:
3532         {
3533           (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
3534             "CompressionNotSupported","`%s'",CommandOptionToMnemonic(
3535             MagickCompressOptions,(ssize_t) compression));
3536           compress_tag=COMPRESSION_NONE;
3537           compression=NoCompression;
3538           break;
3539         }
3540       }
3541 #endif
3542     if (image->colorspace == CMYKColorspace)
3543       {
3544         photometric=PHOTOMETRIC_SEPARATED;
3545         (void) TIFFSetField(tiff,TIFFTAG_SAMPLESPERPIXEL,4);
3546         (void) TIFFSetField(tiff,TIFFTAG_INKSET,INKSET_CMYK);
3547       }
3548     else
3549       {
3550         /*
3551           Full color TIFF raster.
3552         */
3553         if (image->colorspace == LabColorspace)
3554           {
3555             photometric=PHOTOMETRIC_CIELAB;
3556             EncodeLabImage(image,exception);
3557           }
3558         else
3559           if (IsYCbCrCompatibleColorspace(image->colorspace) != MagickFalse)
3560             {
3561               photometric=PHOTOMETRIC_YCBCR;
3562               (void) TIFFSetField(tiff,TIFFTAG_YCBCRSUBSAMPLING,1,1);
3563               (void) SetImageStorageClass(image,DirectClass,exception);
3564               status=SetQuantumDepth(image,quantum_info,8);
3565               if (status == MagickFalse)
3566                 ThrowWriterException(ResourceLimitError,
3567                   "MemoryAllocationFailed");
3568             }
3569           else
3570             photometric=PHOTOMETRIC_RGB;
3571         (void) TIFFSetField(tiff,TIFFTAG_SAMPLESPERPIXEL,3);
3572         if ((image_info->type != TrueColorType) &&
3573             (image_info->type != TrueColorAlphaType))
3574           {
3575             if ((image_info->type != PaletteType) &&
3576                 (SetImageGray(image,exception) != MagickFalse))
3577               {
3578                 photometric=(uint16) (quantum_info->min_is_white !=
3579                   MagickFalse ? PHOTOMETRIC_MINISWHITE :
3580                   PHOTOMETRIC_MINISBLACK);
3581                 (void) TIFFSetField(tiff,TIFFTAG_SAMPLESPERPIXEL,1);
3582                 if ((image->depth == 1) &&
3583                     (image->alpha_trait == UndefinedPixelTrait))
3584                   SetImageMonochrome(image,exception);
3585               }
3586             else
3587               if (image->storage_class == PseudoClass)
3588                 {
3589                   size_t
3590                     depth;
3591 
3592                   /*
3593                     Colormapped TIFF raster.
3594                   */
3595                   (void) TIFFSetField(tiff,TIFFTAG_SAMPLESPERPIXEL,1);
3596                   photometric=PHOTOMETRIC_PALETTE;
3597                   depth=1;
3598                   while ((GetQuantumRange(depth)+1) < image->colors)
3599                     depth<<=1;
3600                   status=SetQuantumDepth(image,quantum_info,depth);
3601                   if (status == MagickFalse)
3602                     ThrowWriterException(ResourceLimitError,
3603                       "MemoryAllocationFailed");
3604                 }
3605           }
3606       }
3607     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_FILLORDER,&endian,sans);
3608     if ((compress_tag == COMPRESSION_CCITTFAX3) ||
3609         (compress_tag == COMPRESSION_CCITTFAX4))
3610       {
3611          if ((photometric != PHOTOMETRIC_MINISWHITE) &&
3612              (photometric != PHOTOMETRIC_MINISBLACK))
3613           {
3614             compress_tag=COMPRESSION_NONE;
3615             endian=FILLORDER_MSB2LSB;
3616           }
3617       }
3618     option=GetImageOption(image_info,"tiff:fill-order");
3619     if (option != (const char *) NULL)
3620       {
3621         if (LocaleNCompare(option,"msb",3) == 0)
3622           endian=FILLORDER_MSB2LSB;
3623         if (LocaleNCompare(option,"lsb",3) == 0)
3624           endian=FILLORDER_LSB2MSB;
3625       }
3626     (void) TIFFSetField(tiff,TIFFTAG_COMPRESSION,compress_tag);
3627     (void) TIFFSetField(tiff,TIFFTAG_FILLORDER,endian);
3628     (void) TIFFSetField(tiff,TIFFTAG_BITSPERSAMPLE,quantum_info->depth);
3629     if (image->alpha_trait != UndefinedPixelTrait)
3630       {
3631         uint16
3632           extra_samples,
3633           sample_info[1],
3634           samples_per_pixel;
3635 
3636         /*
3637           TIFF has a matte channel.
3638         */
3639         extra_samples=1;
3640         sample_info[0]=EXTRASAMPLE_UNASSALPHA;
3641         option=GetImageOption(image_info,"tiff:alpha");
3642         if (option != (const char *) NULL)
3643           {
3644             if (LocaleCompare(option,"associated") == 0)
3645               sample_info[0]=EXTRASAMPLE_ASSOCALPHA;
3646             else
3647               if (LocaleCompare(option,"unspecified") == 0)
3648                 sample_info[0]=EXTRASAMPLE_UNSPECIFIED;
3649           }
3650         (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_SAMPLESPERPIXEL,
3651           &samples_per_pixel,sans);
3652         (void) TIFFSetField(tiff,TIFFTAG_SAMPLESPERPIXEL,samples_per_pixel+1);
3653         (void) TIFFSetField(tiff,TIFFTAG_EXTRASAMPLES,extra_samples,
3654           &sample_info);
3655         if (sample_info[0] == EXTRASAMPLE_ASSOCALPHA)
3656           SetQuantumAlphaType(quantum_info,AssociatedQuantumAlpha);
3657       }
3658     (void) TIFFSetField(tiff,TIFFTAG_PHOTOMETRIC,photometric);
3659     switch (quantum_info->format)
3660     {
3661       case FloatingPointQuantumFormat:
3662       {
3663         (void) TIFFSetField(tiff,TIFFTAG_SAMPLEFORMAT,SAMPLEFORMAT_IEEEFP);
3664         (void) TIFFSetField(tiff,TIFFTAG_SMINSAMPLEVALUE,quantum_info->minimum);
3665         (void) TIFFSetField(tiff,TIFFTAG_SMAXSAMPLEVALUE,quantum_info->maximum);
3666         break;
3667       }
3668       case SignedQuantumFormat:
3669       {
3670         (void) TIFFSetField(tiff,TIFFTAG_SAMPLEFORMAT,SAMPLEFORMAT_INT);
3671         break;
3672       }
3673       case UnsignedQuantumFormat:
3674       {
3675         (void) TIFFSetField(tiff,TIFFTAG_SAMPLEFORMAT,SAMPLEFORMAT_UINT);
3676         break;
3677       }
3678       default:
3679         break;
3680     }
3681     (void) TIFFSetField(tiff,TIFFTAG_PLANARCONFIG,PLANARCONFIG_CONTIG);
3682     if (photometric == PHOTOMETRIC_RGB)
3683       if ((image_info->interlace == PlaneInterlace) ||
3684           (image_info->interlace == PartitionInterlace))
3685         (void) TIFFSetField(tiff,TIFFTAG_PLANARCONFIG,PLANARCONFIG_SEPARATE);
3686     predictor=0;
3687     switch (compress_tag)
3688     {
3689       case COMPRESSION_JPEG:
3690       {
3691 #if defined(JPEG_SUPPORT)
3692         if (image_info->quality != UndefinedCompressionQuality)
3693           (void) TIFFSetField(tiff,TIFFTAG_JPEGQUALITY,image_info->quality);
3694         (void) TIFFSetField(tiff,TIFFTAG_JPEGCOLORMODE,JPEGCOLORMODE_RAW);
3695         if (IssRGBCompatibleColorspace(image->colorspace) != MagickFalse)
3696           {
3697             const char
3698               *value;
3699 
3700             (void) TIFFSetField(tiff,TIFFTAG_JPEGCOLORMODE,JPEGCOLORMODE_RGB);
3701             if (IsYCbCrCompatibleColorspace(image->colorspace) != MagickFalse)
3702               {
3703                 const char
3704                   *sampling_factor;
3705 
3706                 GeometryInfo
3707                   geometry_info;
3708 
3709                 MagickStatusType
3710                   flags;
3711 
3712                 sampling_factor=(const char *) NULL;
3713                 value=GetImageProperty(image,"jpeg:sampling-factor",exception);
3714                 if (value != (char *) NULL)
3715                   {
3716                     sampling_factor=value;
3717                     if (image->debug != MagickFalse)
3718                       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3719                         "  Input sampling-factors=%s",sampling_factor);
3720                   }
3721                 if (image_info->sampling_factor != (char *) NULL)
3722                   sampling_factor=image_info->sampling_factor;
3723                 if (sampling_factor != (const char *) NULL)
3724                   {
3725                     flags=ParseGeometry(sampling_factor,&geometry_info);
3726                     if ((flags & SigmaValue) == 0)
3727                       geometry_info.sigma=geometry_info.rho;
3728                     (void) TIFFSetField(tiff,TIFFTAG_YCBCRSUBSAMPLING,(uint16)
3729                       geometry_info.rho,(uint16) geometry_info.sigma);
3730                   }
3731                 }
3732           }
3733         (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_BITSPERSAMPLE,
3734           &bits_per_sample,sans);
3735         if (bits_per_sample == 12)
3736           (void) TIFFSetField(tiff,TIFFTAG_JPEGTABLESMODE,JPEGTABLESMODE_QUANT);
3737 #endif
3738         break;
3739       }
3740       case COMPRESSION_ADOBE_DEFLATE:
3741       {
3742         (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_BITSPERSAMPLE,
3743           &bits_per_sample,sans);
3744         if (((photometric == PHOTOMETRIC_RGB) ||
3745              (photometric == PHOTOMETRIC_SEPARATED) ||
3746              (photometric == PHOTOMETRIC_MINISBLACK)) &&
3747             ((bits_per_sample == 8) || (bits_per_sample == 16)))
3748           predictor=PREDICTOR_HORIZONTAL;
3749         (void) TIFFSetField(tiff,TIFFTAG_ZIPQUALITY,(long) (
3750           image_info->quality == UndefinedCompressionQuality ? 7 :
3751           MagickMin((ssize_t) image_info->quality/10,9)));
3752         break;
3753       }
3754       case COMPRESSION_CCITTFAX3:
3755       {
3756         /*
3757           Byte-aligned EOL.
3758         */
3759         (void) TIFFSetField(tiff,TIFFTAG_GROUP3OPTIONS,4);
3760         break;
3761       }
3762       case COMPRESSION_CCITTFAX4:
3763         break;
3764 #if defined(LZMA_SUPPORT) && defined(COMPRESSION_LZMA)
3765       case COMPRESSION_LZMA:
3766       {
3767         if (((photometric == PHOTOMETRIC_RGB) ||
3768              (photometric == PHOTOMETRIC_SEPARATED) ||
3769              (photometric == PHOTOMETRIC_MINISBLACK)) &&
3770             ((bits_per_sample == 8) || (bits_per_sample == 16)))
3771           predictor=PREDICTOR_HORIZONTAL;
3772         (void) TIFFSetField(tiff,TIFFTAG_LZMAPRESET,(long) (
3773           image_info->quality == UndefinedCompressionQuality ? 7 :
3774           MagickMin((ssize_t) image_info->quality/10,9)));
3775         break;
3776       }
3777 #endif
3778       case COMPRESSION_LZW:
3779       {
3780         (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_BITSPERSAMPLE,
3781           &bits_per_sample,sans);
3782         if (((photometric == PHOTOMETRIC_RGB) ||
3783              (photometric == PHOTOMETRIC_SEPARATED) ||
3784              (photometric == PHOTOMETRIC_MINISBLACK)) &&
3785             ((bits_per_sample == 8) || (bits_per_sample == 16)))
3786           predictor=PREDICTOR_HORIZONTAL;
3787         break;
3788       }
3789 #if defined(WEBP_SUPPORT) && defined(COMPRESSION_WEBP)
3790       case COMPRESSION_WEBP:
3791       {
3792         (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_BITSPERSAMPLE,
3793           &bits_per_sample,sans);
3794         if (((photometric == PHOTOMETRIC_RGB) ||
3795              (photometric == PHOTOMETRIC_SEPARATED) ||
3796              (photometric == PHOTOMETRIC_MINISBLACK)) &&
3797             ((bits_per_sample == 8) || (bits_per_sample == 16)))
3798           predictor=PREDICTOR_HORIZONTAL;
3799         (void) TIFFSetField(tiff,TIFFTAG_WEBP_LEVEL,image_info->quality);
3800         if (image_info->quality >= 100)
3801           (void) TIFFSetField(tiff,TIFFTAG_WEBP_LOSSLESS,1);
3802         break;
3803       }
3804 #endif
3805 #if defined(ZSTD_SUPPORT) && defined(COMPRESSION_ZSTD)
3806       case COMPRESSION_ZSTD:
3807       {
3808         (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_BITSPERSAMPLE,
3809           &bits_per_sample,sans);
3810         if (((photometric == PHOTOMETRIC_RGB) ||
3811              (photometric == PHOTOMETRIC_SEPARATED) ||
3812              (photometric == PHOTOMETRIC_MINISBLACK)) &&
3813             ((bits_per_sample == 8) || (bits_per_sample == 16)))
3814           predictor=PREDICTOR_HORIZONTAL;
3815         (void) TIFFSetField(tiff,TIFFTAG_ZSTD_LEVEL,22*image_info->quality/
3816           100.0);
3817         break;
3818       }
3819 #endif
3820       default:
3821         break;
3822     }
3823     if (quantum_info->format == FloatingPointQuantumFormat)
3824       predictor=PREDICTOR_FLOATINGPOINT;
3825     option=GetImageOption(image_info,"tiff:predictor");
3826     if (option != (const char * ) NULL)
3827       predictor=(uint16) strtol(option,(char **) NULL,10);
3828     if (predictor != 0)
3829       (void) TIFFSetField(tiff,TIFFTAG_PREDICTOR,predictor);
3830     if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
3831       {
3832         unsigned short
3833           units;
3834 
3835         /*
3836           Set image resolution.
3837         */
3838         units=RESUNIT_NONE;
3839         if (image->units == PixelsPerInchResolution)
3840           units=RESUNIT_INCH;
3841         if (image->units == PixelsPerCentimeterResolution)
3842           units=RESUNIT_CENTIMETER;
3843         (void) TIFFSetField(tiff,TIFFTAG_RESOLUTIONUNIT,(uint16) units);
3844         (void) TIFFSetField(tiff,TIFFTAG_XRESOLUTION,image->resolution.x);
3845         (void) TIFFSetField(tiff,TIFFTAG_YRESOLUTION,image->resolution.y);
3846         if ((image->page.x < 0) || (image->page.y < 0))
3847           (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
3848             "TIFF: negative image positions unsupported","%s",image->filename);
3849         if ((image->page.x > 0) && (image->resolution.x > 0.0))
3850           {
3851             /*
3852               Set horizontal image position.
3853             */
3854             (void) TIFFSetField(tiff,TIFFTAG_XPOSITION,(float) image->page.x/
3855               image->resolution.x);
3856           }
3857         if ((image->page.y > 0) && (image->resolution.y > 0.0))
3858           {
3859             /*
3860               Set vertical image position.
3861             */
3862             (void) TIFFSetField(tiff,TIFFTAG_YPOSITION,(float) image->page.y/
3863               image->resolution.y);
3864           }
3865       }
3866     if (image->chromaticity.white_point.x != 0.0)
3867       {
3868         float
3869           chromaticity[6];
3870 
3871         /*
3872           Set image chromaticity.
3873         */
3874         chromaticity[0]=(float) image->chromaticity.red_primary.x;
3875         chromaticity[1]=(float) image->chromaticity.red_primary.y;
3876         chromaticity[2]=(float) image->chromaticity.green_primary.x;
3877         chromaticity[3]=(float) image->chromaticity.green_primary.y;
3878         chromaticity[4]=(float) image->chromaticity.blue_primary.x;
3879         chromaticity[5]=(float) image->chromaticity.blue_primary.y;
3880         (void) TIFFSetField(tiff,TIFFTAG_PRIMARYCHROMATICITIES,chromaticity);
3881         chromaticity[0]=(float) image->chromaticity.white_point.x;
3882         chromaticity[1]=(float) image->chromaticity.white_point.y;
3883         (void) TIFFSetField(tiff,TIFFTAG_WHITEPOINT,chromaticity);
3884       }
3885     option=GetImageOption(image_info,"tiff:write-layers");
3886     if (IsStringTrue(option) != MagickFalse)
3887       {
3888         (void) TIFFWritePhotoshopLayers(image,image_info,endian_type,exception);
3889         adjoin=MagickFalse;
3890       }
3891     if ((LocaleCompare(image_info->magick,"PTIF") != 0) &&
3892         (adjoin != MagickFalse) && (imageListLength > 1))
3893       {
3894         (void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_PAGE);
3895         if (image->scene != 0)
3896           (void) TIFFSetField(tiff,TIFFTAG_PAGENUMBER,(uint16) image->scene,
3897             imageListLength);
3898       }
3899     if (image->orientation != UndefinedOrientation)
3900       (void) TIFFSetField(tiff,TIFFTAG_ORIENTATION,(uint16) image->orientation);
3901     else
3902       (void) TIFFSetField(tiff,TIFFTAG_ORIENTATION,ORIENTATION_TOPLEFT);
3903     TIFFSetProfiles(tiff,image);
3904     {
3905       uint16
3906         page,
3907         pages;
3908 
3909       page=(uint16) scene;
3910       pages=(uint16) imageListLength;
3911       if ((LocaleCompare(image_info->magick,"PTIF") != 0) &&
3912           (adjoin != MagickFalse) && (pages > 1))
3913         (void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_PAGE);
3914       (void) TIFFSetField(tiff,TIFFTAG_PAGENUMBER,page,pages);
3915     }
3916     (void) TIFFSetProperties(tiff,adjoin,image,exception);
3917     /*
3918       Write image scanlines.
3919     */
3920     if (GetTIFFInfo(image_info,tiff,&tiff_info) == MagickFalse)
3921       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3922     if (compress_tag == COMPRESSION_CCITTFAX4)
3923       (void) TIFFSetField(tiff,TIFFTAG_ROWSPERSTRIP,(uint32) image->rows);
3924     quantum_info->endian=LSBEndian;
3925     pixels=(unsigned char *) GetQuantumPixels(quantum_info);
3926     tiff_info.scanline=(unsigned char *) GetQuantumPixels(quantum_info);
3927     switch (photometric)
3928     {
3929       case PHOTOMETRIC_CIELAB:
3930       case PHOTOMETRIC_YCBCR:
3931       case PHOTOMETRIC_RGB:
3932       {
3933         /*
3934           RGB TIFF image.
3935         */
3936         switch (image_info->interlace)
3937         {
3938           case NoInterlace:
3939           default:
3940           {
3941             quantum_type=RGBQuantum;
3942             if (image->alpha_trait != UndefinedPixelTrait)
3943               quantum_type=RGBAQuantum;
3944             for (y=0; y < (ssize_t) image->rows; y++)
3945             {
3946               const Quantum
3947                 *magick_restrict p;
3948 
3949               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3950               if (p == (const Quantum *) NULL)
3951                 break;
3952               length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3953                 quantum_type,pixels,exception);
3954               (void) length;
3955               if (TIFFWritePixels(tiff,&tiff_info,y,0,image) == -1)
3956                 break;
3957               if (image->previous == (Image *) NULL)
3958                 {
3959                   status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
3960                     y,image->rows);
3961                   if (status == MagickFalse)
3962                     break;
3963                 }
3964             }
3965             break;
3966           }
3967           case PlaneInterlace:
3968           case PartitionInterlace:
3969           {
3970             /*
3971               Plane interlacing:  RRRRRR...GGGGGG...BBBBBB...
3972             */
3973             for (y=0; y < (ssize_t) image->rows; y++)
3974             {
3975               const Quantum
3976                 *magick_restrict p;
3977 
3978               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3979               if (p == (const Quantum *) NULL)
3980                 break;
3981               length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3982                 RedQuantum,pixels,exception);
3983               if (TIFFWritePixels(tiff,&tiff_info,y,0,image) == -1)
3984                 break;
3985             }
3986             if (image->previous == (Image *) NULL)
3987               {
3988                 status=SetImageProgress(image,SaveImageTag,100,400);
3989                 if (status == MagickFalse)
3990                   break;
3991               }
3992             for (y=0; y < (ssize_t) image->rows; y++)
3993             {
3994               const Quantum
3995                 *magick_restrict p;
3996 
3997               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3998               if (p == (const Quantum *) NULL)
3999                 break;
4000               length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
4001                 GreenQuantum,pixels,exception);
4002               if (TIFFWritePixels(tiff,&tiff_info,y,1,image) == -1)
4003                 break;
4004             }
4005             if (image->previous == (Image *) NULL)
4006               {
4007                 status=SetImageProgress(image,SaveImageTag,200,400);
4008                 if (status == MagickFalse)
4009                   break;
4010               }
4011             for (y=0; y < (ssize_t) image->rows; y++)
4012             {
4013               const Quantum
4014                 *magick_restrict p;
4015 
4016               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
4017               if (p == (const Quantum *) NULL)
4018                 break;
4019               length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
4020                 BlueQuantum,pixels,exception);
4021               if (TIFFWritePixels(tiff,&tiff_info,y,2,image) == -1)
4022                 break;
4023             }
4024             if (image->previous == (Image *) NULL)
4025               {
4026                 status=SetImageProgress(image,SaveImageTag,300,400);
4027                 if (status == MagickFalse)
4028                   break;
4029               }
4030             if (image->alpha_trait != UndefinedPixelTrait)
4031               for (y=0; y < (ssize_t) image->rows; y++)
4032               {
4033                 const Quantum
4034                   *magick_restrict p;
4035 
4036                 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
4037                 if (p == (const Quantum *) NULL)
4038                   break;
4039                 length=ExportQuantumPixels(image,(CacheView *) NULL,
4040                   quantum_info,AlphaQuantum,pixels,exception);
4041                 if (TIFFWritePixels(tiff,&tiff_info,y,3,image) == -1)
4042                   break;
4043               }
4044             if (image->previous == (Image *) NULL)
4045               {
4046                 status=SetImageProgress(image,SaveImageTag,400,400);
4047                 if (status == MagickFalse)
4048                   break;
4049               }
4050             break;
4051           }
4052         }
4053         break;
4054       }
4055       case PHOTOMETRIC_SEPARATED:
4056       {
4057         /*
4058           CMYK TIFF image.
4059         */
4060         quantum_type=CMYKQuantum;
4061         if (image->alpha_trait != UndefinedPixelTrait)
4062           quantum_type=CMYKAQuantum;
4063         if (image->colorspace != CMYKColorspace)
4064           (void) TransformImageColorspace(image,CMYKColorspace,exception);
4065         for (y=0; y < (ssize_t) image->rows; y++)
4066         {
4067           const Quantum
4068             *magick_restrict p;
4069 
4070           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
4071           if (p == (const Quantum *) NULL)
4072             break;
4073           length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
4074             quantum_type,pixels,exception);
4075           if (TIFFWritePixels(tiff,&tiff_info,y,0,image) == -1)
4076             break;
4077           if (image->previous == (Image *) NULL)
4078             {
4079               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
4080                 image->rows);
4081               if (status == MagickFalse)
4082                 break;
4083             }
4084         }
4085         break;
4086       }
4087       case PHOTOMETRIC_PALETTE:
4088       {
4089         uint16
4090           *blue,
4091           *green,
4092           *red;
4093 
4094         /*
4095           Colormapped TIFF image.
4096         */
4097         red=(uint16 *) AcquireQuantumMemory(65536,sizeof(*red));
4098         green=(uint16 *) AcquireQuantumMemory(65536,sizeof(*green));
4099         blue=(uint16 *) AcquireQuantumMemory(65536,sizeof(*blue));
4100         if ((red == (uint16 *) NULL) || (green == (uint16 *) NULL) ||
4101             (blue == (uint16 *) NULL))
4102           {
4103             if (red != (uint16 *) NULL)
4104               red=(uint16 *) RelinquishMagickMemory(red);
4105             if (green != (uint16 *) NULL)
4106               green=(uint16 *) RelinquishMagickMemory(green);
4107             if (blue != (uint16 *) NULL)
4108               blue=(uint16 *) RelinquishMagickMemory(blue);
4109             ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
4110           }
4111         /*
4112           Initialize TIFF colormap.
4113         */
4114         (void) memset(red,0,65536*sizeof(*red));
4115         (void) memset(green,0,65536*sizeof(*green));
4116         (void) memset(blue,0,65536*sizeof(*blue));
4117         for (i=0; i < (ssize_t) image->colors; i++)
4118         {
4119           red[i]=ScaleQuantumToShort(image->colormap[i].red);
4120           green[i]=ScaleQuantumToShort(image->colormap[i].green);
4121           blue[i]=ScaleQuantumToShort(image->colormap[i].blue);
4122         }
4123         (void) TIFFSetField(tiff,TIFFTAG_COLORMAP,red,green,blue);
4124         red=(uint16 *) RelinquishMagickMemory(red);
4125         green=(uint16 *) RelinquishMagickMemory(green);
4126         blue=(uint16 *) RelinquishMagickMemory(blue);
4127       }
4128       default:
4129       {
4130         /*
4131           Convert PseudoClass packets to contiguous grayscale scanlines.
4132         */
4133         quantum_type=IndexQuantum;
4134         if (image->alpha_trait != UndefinedPixelTrait)
4135           {
4136             if (photometric != PHOTOMETRIC_PALETTE)
4137               quantum_type=GrayAlphaQuantum;
4138             else
4139               quantum_type=IndexAlphaQuantum;
4140            }
4141          else
4142            if (photometric != PHOTOMETRIC_PALETTE)
4143              quantum_type=GrayQuantum;
4144         for (y=0; y < (ssize_t) image->rows; y++)
4145         {
4146           const Quantum
4147             *magick_restrict p;
4148 
4149           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
4150           if (p == (const Quantum *) NULL)
4151             break;
4152           length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
4153             quantum_type,pixels,exception);
4154           if (TIFFWritePixels(tiff,&tiff_info,y,0,image) == -1)
4155             break;
4156           if (image->previous == (Image *) NULL)
4157             {
4158               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
4159                 image->rows);
4160               if (status == MagickFalse)
4161                 break;
4162             }
4163         }
4164         break;
4165       }
4166     }
4167     quantum_info=DestroyQuantumInfo(quantum_info);
4168     if (image->colorspace == LabColorspace)
4169       DecodeLabImage(image,exception);
4170     DestroyTIFFInfo(&tiff_info);
4171     /* TIFFPrintDirectory(tiff,stdout,MagickFalse); */
4172     if (TIFFWriteDirectory(tiff) == 0)
4173       {
4174         status=MagickFalse;
4175         break;
4176       }
4177     image=SyncNextImageInList(image);
4178     if (image == (Image *) NULL)
4179       break;
4180     status=SetImageProgress(image,SaveImagesTag,scene++,imageListLength);
4181     if (status == MagickFalse)
4182       break;
4183   } while (adjoin != MagickFalse);
4184   TIFFClose(tiff);
4185   return(status);
4186 }
4187 #endif
4188