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