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