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