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