]> granicus.if.org Git - imagemagick/blob - coders/tiff.c
(no commit message)
[imagemagick] / coders / tiff.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                        TTTTT  IIIII  FFFFF  FFFFF                           %
7 %                          T      I    F      F                               %
8 %                          T      I    FFF    FFF                             %
9 %                          T      I    F      F                               %
10 %                          T    IIIII  F      F                               %
11 %                                                                             %
12 %                                                                             %
13 %                        Read/Write TIFF Image Format                         %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                John Cristy                                  %
17 %                                 July 1992                                   %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2012 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 %    http://www.imagemagick.org/script/license.php                            %
27 %                                                                             %
28 %  Unless required by applicable law or agreed to in writing, software        %
29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31 %  See the License for the specific language governing permissions and        %
32 %  limitations under the License.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38 \f
39 /*
40   Include declarations.
41 */
42 #include "MagickCore/studio.h"
43 #include "MagickCore/artifact.h"
44 #include "MagickCore/attribute.h"
45 #include "MagickCore/blob.h"
46 #include "MagickCore/blob-private.h"
47 #include "MagickCore/cache.h"
48 #include "MagickCore/color.h"
49 #include "MagickCore/color-private.h"
50 #include "MagickCore/colormap.h"
51 #include "MagickCore/colorspace.h"
52 #include "MagickCore/colorspace-private.h"
53 #include "MagickCore/constitute.h"
54 #include "MagickCore/enhance.h"
55 #include "MagickCore/exception.h"
56 #include "MagickCore/exception-private.h"
57 #include "MagickCore/geometry.h"
58 #include "MagickCore/image.h"
59 #include "MagickCore/image-private.h"
60 #include "MagickCore/list.h"
61 #include "MagickCore/log.h"
62 #include "MagickCore/magick.h"
63 #include "MagickCore/memory_.h"
64 #include "MagickCore/module.h"
65 #include "MagickCore/monitor.h"
66 #include "MagickCore/monitor-private.h"
67 #include "MagickCore/option.h"
68 #include "MagickCore/pixel-accessor.h"
69 #include "MagickCore/property.h"
70 #include "MagickCore/quantum.h"
71 #include "MagickCore/quantum-private.h"
72 #include "MagickCore/profile.h"
73 #include "MagickCore/resize.h"
74 #include "MagickCore/resource_.h"
75 #include "MagickCore/semaphore.h"
76 #include "MagickCore/splay-tree.h"
77 #include "MagickCore/static.h"
78 #include "MagickCore/statistic.h"
79 #include "MagickCore/string_.h"
80 #include "MagickCore/string-private.h"
81 #include "MagickCore/thread_.h"
82 #include "MagickCore/utility.h"
83 #if defined(MAGICKCORE_TIFF_DELEGATE)
84 # if defined(MAGICKCORE_HAVE_TIFFCONF_H)
85 #  include "tiffconf.h"
86 # endif
87 # include "tiff.h"
88 # include "tiffio.h"
89 # if !defined(COMPRESSION_ADOBE_DEFLATE)
90 #  define COMPRESSION_ADOBE_DEFLATE  8
91 # endif
92 # if !defined(PREDICTOR_HORIZONTAL)
93 # define PREDICTOR_HORIZONTAL  2
94 # endif
95 # if !defined(TIFFTAG_COPYRIGHT)
96 #  define TIFFTAG_COPYRIGHT  33432
97 # endif
98 # if !defined(TIFFTAG_OPIIMAGEID)
99 #  define TIFF_OPIIMAGEID  32781
100 # endif
101 \f
102 /*
103   Typedef declarations.
104 */
105 #if defined(MAGICKCORE_HAVE_TIFFREADEXIFDIRECTORY)
106 typedef struct _ExifInfo
107 {
108   unsigned int
109     tag,
110     type;
111
112   const char
113     *property;
114 } ExifInfo;
115
116 static const ExifInfo
117   exif_info[] = {
118     { EXIFTAG_EXPOSURETIME, TIFF_RATIONAL, "exif:ExposureTime" },
119     { EXIFTAG_FNUMBER, TIFF_RATIONAL, "exif:FNumber" },
120     { EXIFTAG_EXPOSUREPROGRAM, TIFF_SHORT, "exif:ExposureProgram" },
121     { EXIFTAG_SPECTRALSENSITIVITY, TIFF_ASCII, "exif:SpectralSensitivity" },
122     { EXIFTAG_ISOSPEEDRATINGS, TIFF_SHORT, "exif:ISOSpeedRatings" },
123     { EXIFTAG_OECF, TIFF_NOTYPE, "exif:OptoelectricConversionFactor" },
124     { EXIFTAG_EXIFVERSION, TIFF_NOTYPE, "exif:ExifVersion" },
125     { EXIFTAG_DATETIMEORIGINAL, TIFF_ASCII, "exif:DateTimeOriginal" },
126     { EXIFTAG_DATETIMEDIGITIZED, TIFF_ASCII, "exif:DateTimeDigitized" },
127     { EXIFTAG_COMPONENTSCONFIGURATION, TIFF_NOTYPE, "exif:ComponentsConfiguration" },
128     { EXIFTAG_COMPRESSEDBITSPERPIXEL, TIFF_RATIONAL, "exif:CompressedBitsPerPixel" },
129     { EXIFTAG_SHUTTERSPEEDVALUE, TIFF_SRATIONAL, "exif:ShutterSpeedValue" },
130     { EXIFTAG_APERTUREVALUE, TIFF_RATIONAL, "exif:ApertureValue" },
131     { EXIFTAG_BRIGHTNESSVALUE, TIFF_SRATIONAL, "exif:BrightnessValue" },
132     { EXIFTAG_EXPOSUREBIASVALUE, TIFF_SRATIONAL, "exif:ExposureBiasValue" },
133     { EXIFTAG_MAXAPERTUREVALUE, TIFF_RATIONAL, "exif:MaxApertureValue" },
134     { EXIFTAG_SUBJECTDISTANCE, TIFF_RATIONAL, "exif:SubjectDistance" },
135     { EXIFTAG_METERINGMODE, TIFF_SHORT, "exif:MeteringMode" },
136     { EXIFTAG_LIGHTSOURCE, TIFF_SHORT, "exif:LightSource" },
137     { EXIFTAG_FLASH, TIFF_SHORT, "exif:Flash" },
138     { EXIFTAG_FOCALLENGTH, TIFF_RATIONAL, "exif:FocalLength" },
139     { EXIFTAG_SUBJECTAREA, TIFF_NOTYPE, "exif:SubjectArea" },
140     { EXIFTAG_MAKERNOTE, TIFF_NOTYPE, "exif:MakerNote" },
141     { EXIFTAG_USERCOMMENT, TIFF_NOTYPE, "exif:UserComment" },
142     { EXIFTAG_SUBSECTIME, TIFF_ASCII, "exif:SubSecTime" },
143     { EXIFTAG_SUBSECTIMEORIGINAL, TIFF_ASCII, "exif:SubSecTimeOriginal" },
144     { EXIFTAG_SUBSECTIMEDIGITIZED, TIFF_ASCII, "exif:SubSecTimeDigitized" },
145     { EXIFTAG_FLASHPIXVERSION, TIFF_NOTYPE, "exif:FlashpixVersion" },
146     { EXIFTAG_PIXELXDIMENSION, TIFF_LONG, "exif:PixelXDimension" },
147     { EXIFTAG_PIXELXDIMENSION, TIFF_SHORT, "exif:PixelXDimension" },
148     { EXIFTAG_PIXELYDIMENSION, TIFF_LONG, "exif:PixelYDimension" },
149     { EXIFTAG_PIXELYDIMENSION, TIFF_SHORT, "exif:PixelYDimension" },
150     { EXIFTAG_RELATEDSOUNDFILE, TIFF_ASCII, "exif:RelatedSoundFile" },
151     { EXIFTAG_FLASHENERGY, TIFF_RATIONAL, "exif:FlashEnergy" },
152     { EXIFTAG_SPATIALFREQUENCYRESPONSE, TIFF_NOTYPE, "exif:SpatialFrequencyResponse" },
153     { EXIFTAG_FOCALPLANEXRESOLUTION, TIFF_RATIONAL, "exif:FocalPlaneXResolution" },
154     { EXIFTAG_FOCALPLANEYRESOLUTION, TIFF_RATIONAL, "exif:FocalPlaneYResolution" },
155     { EXIFTAG_FOCALPLANERESOLUTIONUNIT, TIFF_SHORT, "exif:FocalPlaneResolutionUnit" },
156     { EXIFTAG_SUBJECTLOCATION, TIFF_SHORT, "exif:SubjectLocation" },
157     { EXIFTAG_EXPOSUREINDEX, TIFF_RATIONAL, "exif:ExposureIndex" },
158     { EXIFTAG_SENSINGMETHOD, TIFF_SHORT, "exif:SensingMethod" },
159     { EXIFTAG_FILESOURCE, TIFF_NOTYPE, "exif:FileSource" },
160     { EXIFTAG_SCENETYPE, TIFF_NOTYPE, "exif:SceneType" },
161     { EXIFTAG_CFAPATTERN, TIFF_NOTYPE, "exif:CFAPattern" },
162     { EXIFTAG_CUSTOMRENDERED, TIFF_SHORT, "exif:CustomRendered" },
163     { EXIFTAG_EXPOSUREMODE, TIFF_SHORT, "exif:ExposureMode" },
164     { EXIFTAG_WHITEBALANCE, TIFF_SHORT, "exif:WhiteBalance" },
165     { EXIFTAG_DIGITALZOOMRATIO, TIFF_RATIONAL, "exif:DigitalZoomRatio" },
166     { EXIFTAG_FOCALLENGTHIN35MMFILM, TIFF_SHORT, "exif:FocalLengthIn35mmFilm" },
167     { EXIFTAG_SCENECAPTURETYPE, TIFF_SHORT, "exif:SceneCaptureType" },
168     { EXIFTAG_GAINCONTROL, TIFF_RATIONAL, "exif:GainControl" },
169     { EXIFTAG_CONTRAST, TIFF_SHORT, "exif:Contrast" },
170     { EXIFTAG_SATURATION, TIFF_SHORT, "exif:Saturation" },
171     { EXIFTAG_SHARPNESS, TIFF_SHORT, "exif:Sharpness" },
172     { EXIFTAG_DEVICESETTINGDESCRIPTION, TIFF_NOTYPE, "exif:DeviceSettingDescription" },
173     { EXIFTAG_SUBJECTDISTANCERANGE, TIFF_SHORT, "exif:SubjectDistanceRange" },
174     { EXIFTAG_IMAGEUNIQUEID, TIFF_ASCII, "exif:ImageUniqueID" },
175     { 0, 0, (char *) NULL }
176 };
177 #endif
178 #endif  /* MAGICKCORE_TIFF_DELEGATE */
179 \f
180 /*
181   Global declarations.
182 */
183 static MagickThreadKey
184   tiff_exception;
185
186 static SemaphoreInfo
187   *tiff_semaphore = (SemaphoreInfo *) NULL;
188
189 static volatile MagickBooleanType
190   instantiate_key = MagickFalse;
191 \f
192 /*
193   Forward declarations.
194 */
195 #if defined(MAGICKCORE_TIFF_DELEGATE)
196 static Image *
197   ReadTIFFImage(const ImageInfo *,ExceptionInfo *);
198
199 static MagickBooleanType
200   WriteGROUP4Image(const ImageInfo *,Image *,ExceptionInfo *),
201   WritePTIFImage(const ImageInfo *,Image *,ExceptionInfo *),
202   WriteTIFFImage(const ImageInfo *,Image *,ExceptionInfo *);
203 #endif
204 \f
205 /*
206 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
207 %                                                                             %
208 %                                                                             %
209 %                                                                             %
210 %   I s T I F F                                                               %
211 %                                                                             %
212 %                                                                             %
213 %                                                                             %
214 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
215 %
216 %  IsTIFF() returns MagickTrue if the image format type, identified by the
217 %  magick string, is TIFF.
218 %
219 %  The format of the IsTIFF method is:
220 %
221 %      MagickBooleanType IsTIFF(const unsigned char *magick,const size_t length)
222 %
223 %  A description of each parameter follows:
224 %
225 %    o magick: compare image format pattern against these bytes.
226 %
227 %    o length: Specifies the length of the magick string.
228 %
229 */
230 static MagickBooleanType IsTIFF(const unsigned char *magick,const size_t length)
231 {
232   if (length < 4)
233     return(MagickFalse);
234   if (memcmp(magick,"\115\115\000\052",4) == 0)
235     return(MagickTrue);
236   if (memcmp(magick,"\111\111\052\000",4) == 0)
237     return(MagickTrue);
238 #if defined(TIFF_VERSION_BIG)
239   if (length < 8)
240     return(MagickFalse);
241   if (memcmp(magick,"\115\115\000\053\000\010\000\000",8) == 0)
242     return(MagickTrue);
243   if (memcmp(magick,"\111\111\053\000\010\000\000\000",8) == 0)
244     return(MagickTrue);
245 #endif
246   return(MagickFalse);
247 }
248 \f
249 #if defined(MAGICKCORE_TIFF_DELEGATE)
250 /*
251 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
252 %                                                                             %
253 %                                                                             %
254 %                                                                             %
255 %   R e a d G R O U P 4 I m a g e                                             %
256 %                                                                             %
257 %                                                                             %
258 %                                                                             %
259 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
260 %
261 %  ReadGROUP4Image() reads a raw CCITT Group 4 image file and returns it.  It
262 %  allocates the memory necessary for the new Image structure and returns a
263 %  pointer to the new image.
264 %
265 %  The format of the ReadGROUP4Image method is:
266 %
267 %      Image *ReadGROUP4Image(const ImageInfo *image_info,
268 %        ExceptionInfo *exception)
269 %
270 %  A description of each parameter follows:
271 %
272 %    o image_info: the image info.
273 %
274 %    o exception: return any errors or warnings in this structure.
275 %
276 */
277
278 static inline size_t WriteLSBLong(FILE *file,const size_t value)
279 {
280   unsigned char
281     buffer[4];
282
283   buffer[0]=(unsigned char) value;
284   buffer[1]=(unsigned char) (value >> 8);
285   buffer[2]=(unsigned char) (value >> 16);
286   buffer[3]=(unsigned char) (value >> 24);
287   return(fwrite(buffer,1,4,file));
288 }
289
290 static Image *ReadGROUP4Image(const ImageInfo *image_info,
291   ExceptionInfo *exception)
292 {
293   char
294     filename[MaxTextExtent];
295
296   FILE
297     *file;
298
299   Image
300     *image;
301
302   ImageInfo
303     *read_info;
304
305   int
306     c,
307     unique_file;
308
309   MagickBooleanType
310     status;
311
312   size_t
313     length;
314
315   ssize_t
316     offset,
317     strip_offset;
318
319   /*
320     Open image file.
321   */
322   assert(image_info != (const ImageInfo *) NULL);
323   assert(image_info->signature == MagickSignature);
324   if (image_info->debug != MagickFalse)
325     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
326       image_info->filename);
327   assert(exception != (ExceptionInfo *) NULL);
328   assert(exception->signature == MagickSignature);
329   image=AcquireImage(image_info,exception);
330   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
331   if (status == MagickFalse)
332     {
333       image=DestroyImageList(image);
334       return((Image *) NULL);
335     }
336   /*
337     Write raw CCITT Group 4 wrapped as a TIFF image file.
338   */
339   file=(FILE *) NULL;
340   unique_file=AcquireUniqueFileResource(filename);
341   if (unique_file != -1)
342     file=fdopen(unique_file,"wb");
343   if ((unique_file == -1) || (file == (FILE *) NULL))
344     ThrowImageException(FileOpenError,"UnableToCreateTemporaryFile");
345   length=fwrite("\111\111\052\000\010\000\000\000\016\000",1,10,file);
346   length=fwrite("\376\000\003\000\001\000\000\000\000\000\000\000",1,12,file);
347   length=fwrite("\000\001\004\000\001\000\000\000",1,8,file);
348   length=WriteLSBLong(file,image->columns);
349   length=fwrite("\001\001\004\000\001\000\000\000",1,8,file);
350   length=WriteLSBLong(file,image->rows);
351   length=fwrite("\002\001\003\000\001\000\000\000\001\000\000\000",1,12,file);
352   length=fwrite("\003\001\003\000\001\000\000\000\004\000\000\000",1,12,file);
353   length=fwrite("\006\001\003\000\001\000\000\000\000\000\000\000",1,12,file);
354   length=fwrite("\021\001\003\000\001\000\000\000",1,8,file);
355   strip_offset=10+(12*14)+4+8;
356   length=WriteLSBLong(file,(size_t) strip_offset);
357   length=fwrite("\022\001\003\000\001\000\000\000",1,8,file);
358   length=WriteLSBLong(file,(size_t) image_info->orientation);
359   length=fwrite("\025\001\003\000\001\000\000\000\001\000\000\000",1,12,file);
360   length=fwrite("\026\001\004\000\001\000\000\000",1,8,file);
361   length=WriteLSBLong(file,image->rows);
362   length=fwrite("\027\001\004\000\001\000\000\000\000\000\000\000",1,12,file);
363   offset=(ssize_t) ftell(file)-4;
364   length=fwrite("\032\001\005\000\001\000\000\000",1,8,file);
365   length=WriteLSBLong(file,(size_t) (strip_offset-8));
366   length=fwrite("\033\001\005\000\001\000\000\000",1,8,file);
367   length=WriteLSBLong(file,(size_t) (strip_offset-8));
368   length=fwrite("\050\001\003\000\001\000\000\000\002\000\000\000",1,12,file);
369   length=fwrite("\000\000\000\000",1,4,file);
370   length=WriteLSBLong(file,(long) image->resolution.x);
371   length=WriteLSBLong(file,1);
372   for (length=0; (c=ReadBlobByte(image)) != EOF; length++)
373     (void) fputc(c,file);
374   offset=(ssize_t) fseek(file,(ssize_t) offset,SEEK_SET);
375   length=WriteLSBLong(file,(unsigned int) length);
376   (void) fclose(file);
377   (void) CloseBlob(image);
378   image=DestroyImage(image);
379   /*
380     Read TIFF image.
381   */
382   read_info=CloneImageInfo((ImageInfo *) NULL);
383   (void) FormatLocaleString(read_info->filename,MaxTextExtent,"%s",filename);
384   image=ReadTIFFImage(read_info,exception);
385   read_info=DestroyImageInfo(read_info);
386   if (image != (Image *) NULL)
387     {
388       (void) CopyMagickString(image->filename,image_info->filename,
389         MaxTextExtent);
390       (void) CopyMagickString(image->magick_filename,image_info->filename,
391         MaxTextExtent);
392       (void) CopyMagickString(image->magick,"GROUP4",MaxTextExtent);
393     }
394   (void) RelinquishUniqueFileResource(filename);
395   return(image);
396 }
397 #endif
398 \f
399 #if defined(MAGICKCORE_TIFF_DELEGATE)
400 /*
401 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
402 %                                                                             %
403 %                                                                             %
404 %                                                                             %
405 %   R e a d T I F F I m a g e                                                 %
406 %                                                                             %
407 %                                                                             %
408 %                                                                             %
409 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
410 %
411 %  ReadTIFFImage() reads a Tagged image file and returns it.  It allocates the
412 %  memory necessary for the new Image structure and returns a pointer to the
413 %  new image.
414 %
415 %  The format of the ReadTIFFImage method is:
416 %
417 %      Image *ReadTIFFImage(const ImageInfo *image_info,
418 %        ExceptionInfo *exception)
419 %
420 %  A description of each parameter follows:
421 %
422 %    o image_info: the image info.
423 %
424 %    o exception: return any errors or warnings in this structure.
425 %
426 */
427
428 static inline size_t MagickMax(const size_t x,const size_t y)
429 {
430   if (x > y)
431     return(x);
432   return(y);
433 }
434
435 static inline ssize_t MagickMin(const ssize_t x,const ssize_t y)
436 {
437   if (x < y)
438     return(x);
439   return(y);
440 }
441
442 static MagickBooleanType ReadProfile(Image *image,const char *name,
443   unsigned char *datum,ssize_t length,ExceptionInfo *exception)
444 {
445   MagickBooleanType
446     status;
447
448   register ssize_t
449     i;
450
451   StringInfo
452     *profile;
453
454   if (length < 4)
455     return(MagickFalse);
456   i=0;
457   if ((LocaleCompare(name,"icc") != 0) && (LocaleCompare(name,"xmp") != 0))
458     {
459       for (i=0; i < (length-4); i+=2)
460         if (LocaleNCompare((char *) (datum+i),"8BIM",4) == 0)
461           break;
462       if (i == length)
463         length-=i;
464       else
465         i=0;
466       if (length < 4)
467         return(MagickFalse);
468     }
469   profile=BlobToStringInfo(datum+i,(size_t) length);
470   if (profile == (StringInfo *) NULL)
471     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
472       image->filename);
473   status=SetImageProfile(image,name,profile,exception);
474   profile=DestroyStringInfo(profile);
475   if (status == MagickFalse)
476     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
477       image->filename);
478   return(MagickTrue);
479 }
480
481 #if defined(__cplusplus) || defined(c_plusplus)
482 extern "C" {
483 #endif
484
485 static int TIFFCloseBlob(thandle_t image)
486 {
487   (void) CloseBlob((Image *) image);
488   return(0);
489 }
490
491 static void TIFFErrors(const char *module,const char *format,va_list error)
492 {
493   char
494     message[MaxTextExtent];
495
496   ExceptionInfo
497     *exception;
498
499 #if defined(MAGICKCORE_HAVE_VSNPRINTF)
500   (void) vsnprintf(message,MaxTextExtent,format,error);
501 #else
502   (void) vsprintf(message,format,error);
503 #endif
504   (void) ConcatenateMagickString(message,".",MaxTextExtent);
505   exception=(ExceptionInfo *) MagickGetThreadValue(tiff_exception);
506   if (exception != (ExceptionInfo *) NULL)
507     (void) ThrowMagickException(exception,GetMagickModule(),CoderError,message,
508       "`%s'",module);
509 }
510
511 static toff_t TIFFGetBlobSize(thandle_t image)
512 {
513   return((toff_t) GetBlobSize((Image *) image));
514 }
515
516 static void TIFFGetProfiles(TIFF *tiff,Image *image,ExceptionInfo *exception)
517 {
518   uint32
519     length;
520
521   unsigned char
522     *profile;
523
524 #if defined(TIFFTAG_ICCPROFILE)
525   length=0;
526   if (TIFFGetField(tiff,TIFFTAG_ICCPROFILE,&length,&profile) == 1)
527     (void) ReadProfile(image,"icc",profile,(ssize_t) length,exception);
528 #endif
529 #if defined(TIFFTAG_PHOTOSHOP)
530   length=0;
531   if (TIFFGetField(tiff,TIFFTAG_PHOTOSHOP,&length,&profile) == 1)
532     (void) ReadProfile(image,"8bim",profile,(ssize_t) length,exception);
533 #endif
534 #if defined(TIFFTAG_RICHTIFFIPTC)
535   length=0;
536   if (TIFFGetField(tiff,TIFFTAG_RICHTIFFIPTC,&length,&profile) == 1)
537     {
538       if (TIFFIsByteSwapped(tiff) != 0)
539         TIFFSwabArrayOfLong((uint32 *) profile,(size_t) length);
540       (void) ReadProfile(image,"iptc",profile,4L*length,exception);
541     }
542 #endif
543 #if defined(TIFFTAG_XMLPACKET)
544   length=0;
545   if (TIFFGetField(tiff,TIFFTAG_XMLPACKET,&length,&profile) == 1)
546     (void) ReadProfile(image,"xmp",profile,(ssize_t) length,exception);
547 #endif
548   length=0;
549   if (TIFFGetField(tiff,37724,&length,&profile) == 1)
550     (void) ReadProfile(image,"tiff:37724",profile,(ssize_t) length,exception);
551 }
552
553 static void TIFFGetProperties(TIFF *tiff,Image *image,ExceptionInfo *exception)
554 {
555   char
556     message[MaxTextExtent],
557     *text;
558
559   uint32
560     count;
561
562   if (TIFFGetField(tiff,TIFFTAG_ARTIST,&text) == 1)
563     (void) SetImageProperty(image,"tiff:artist",text,exception);
564   if (TIFFGetField(tiff,TIFFTAG_COPYRIGHT,&text) == 1)
565     (void) SetImageProperty(image,"tiff:copyright",text,exception);
566   if (TIFFGetField(tiff,TIFFTAG_DATETIME,&text) == 1)
567     (void) SetImageProperty(image,"tiff:timestamp",text,exception);
568   if (TIFFGetField(tiff,TIFFTAG_DOCUMENTNAME,&text) == 1)
569     (void) SetImageProperty(image,"tiff:document",text,exception);
570   if (TIFFGetField(tiff,TIFFTAG_HOSTCOMPUTER,&text) == 1)
571     (void) SetImageProperty(image,"tiff:hostcomputer",text,exception);
572   if (TIFFGetField(tiff,TIFFTAG_IMAGEDESCRIPTION,&text) == 1)
573     (void) SetImageProperty(image,"comment",text,exception);
574   if (TIFFGetField(tiff,TIFFTAG_MAKE,&text) == 1)
575     (void) SetImageProperty(image,"tiff:make",text,exception);
576   if (TIFFGetField(tiff,TIFFTAG_MODEL,&text) == 1)
577     (void) SetImageProperty(image,"tiff:model",text,exception);
578   if (TIFFGetField(tiff,TIFFTAG_OPIIMAGEID,&count,&text) == 1)
579     {
580       if (count >= MaxTextExtent)
581         count=MaxTextExtent-1;
582       (void) CopyMagickString(message,text,count+1);
583       (void) SetImageProperty(image,"tiff:image-id",message,exception);
584     }
585   if (TIFFGetField(tiff,TIFFTAG_PAGENAME,&text) == 1)
586     (void) SetImageProperty(image,"label",text,exception);
587   if (TIFFGetField(tiff,TIFFTAG_SOFTWARE,&text) == 1)
588     (void) SetImageProperty(image,"tiff:software",text,exception);
589   if (TIFFGetField(tiff,33423,&count,&text) == 1)
590     {
591       if (count >= MaxTextExtent)
592         count=MaxTextExtent-1;
593       (void) CopyMagickString(message,text,count+1);
594       (void) SetImageProperty(image,"tiff:kodak-33423",message,exception);
595     }
596   if (TIFFGetField(tiff,36867,&count,&text) == 1)
597     {
598       if (count >= MaxTextExtent)
599         count=MaxTextExtent-1;
600       (void) CopyMagickString(message,text,count+1);
601       (void) SetImageProperty(image,"tiff:kodak-36867",message,exception);
602     }
603 }
604
605 static void TIFFGetEXIFProperties(TIFF *tiff,Image *image,
606   ExceptionInfo *exception)
607 {
608 #if defined(MAGICKCORE_HAVE_TIFFREADEXIFDIRECTORY)
609   char
610     value[MaxTextExtent];
611
612   register ssize_t
613     i;
614
615   tdir_t
616     directory;
617
618 #if defined(TIFF_VERSION_BIG)
619   uint64
620 #else
621   uint32
622 #endif
623     offset;
624
625   void
626     *sans;
627
628   /*
629     Read EXIF properties.
630   */
631   offset=0;
632   if (TIFFGetField(tiff,TIFFTAG_EXIFIFD,&offset) == 0)
633     return;
634   directory=TIFFCurrentDirectory(tiff);
635   if (TIFFReadEXIFDirectory(tiff,offset) == 0)
636     return;
637   sans=NULL;
638   for (i=0; exif_info[i].tag != 0; i++)
639   {
640     *value='\0';
641     switch (exif_info[i].type)
642     {
643       case TIFF_ASCII:
644       {
645         char
646           *ascii;
647
648         ascii=(char *) NULL;
649         if ((TIFFGetField(tiff,exif_info[i].tag,&ascii,&sans,&sans) != 0) &&
650             (ascii != (char *) NULL) && (*ascii != '\0'))
651           (void) CopyMagickMemory(value,ascii,MaxTextExtent);
652         break;
653       }
654       case TIFF_SHORT:
655       {
656         uint16
657           shorty[2] = { 0, 0};
658
659         if (TIFFGetField(tiff,exif_info[i].tag,&shorty,&sans,&sans) != 0)
660           (void) FormatLocaleString(value,MaxTextExtent,"%d",(int) shorty[0]);
661         break;
662       }
663       case TIFF_LONG:
664       {
665         uint32
666           longy;
667
668         if (TIFFGetField(tiff,exif_info[i].tag,&longy,&sans,&sans) != 0)
669           (void) FormatLocaleString(value,MaxTextExtent,"%d",longy);
670         break;
671       }
672 #if defined(TIFF_VERSION_BIG)
673       case TIFF_LONG8:
674       {
675         uint64
676           longy;
677
678         if (TIFFGetField(tiff,exif_info[i].tag,&longy,&sans,&sans) != 0)
679           (void) FormatLocaleString(value,MaxTextExtent,"%lld",longy);
680         break;
681       }
682 #endif
683       case TIFF_RATIONAL:
684       case TIFF_SRATIONAL:
685       case TIFF_FLOAT:
686       case TIFF_DOUBLE:
687       {
688         float
689           rational[16];
690
691         if (TIFFGetField(tiff,exif_info[i].tag,&rational,&sans,&sans) != 0)
692           (void) FormatLocaleString(value,MaxTextExtent,"%g",rational[0]);
693         break;
694       }
695       default:
696         break;
697     }
698     if (*value != '\0')
699       (void) SetImageProperty(image,exif_info[i].property,value,exception);
700   }
701   TIFFSetDirectory(tiff,directory);
702 #else
703   (void) tiff;
704   (void) image;
705 #endif
706 }
707
708 static int TIFFMapBlob(thandle_t image,tdata_t *base,toff_t *size)
709 {
710   *base=(tdata_t *) GetBlobStreamData((Image *) image);
711   if (*base != (tdata_t *) NULL)
712     *size=(toff_t) GetBlobSize((Image *) image);
713   if (*base != (tdata_t *) NULL)
714     return(1);
715   return(0);
716 }
717
718 static tsize_t TIFFReadBlob(thandle_t image,tdata_t data,tsize_t size)
719 {
720   tsize_t
721     count;
722
723   count=(tsize_t) ReadBlob((Image *) image,(size_t) size,
724     (unsigned char *) data);
725   return(count);
726 }
727
728 static int32 TIFFReadPixels(TIFF *tiff,size_t bits_per_sample,
729   tsample_t sample,ssize_t row,tdata_t scanline)
730 {
731   int32
732     status;
733
734   (void) bits_per_sample;
735   status=TIFFReadScanline(tiff,scanline,(uint32) row,sample);
736   return(status);
737 }
738
739 static toff_t TIFFSeekBlob(thandle_t image,toff_t offset,int whence)
740 {
741   return((toff_t) SeekBlob((Image *) image,(MagickOffsetType) offset,whence));
742 }
743
744 static void TIFFUnmapBlob(thandle_t image,tdata_t base,toff_t size)
745 {
746   (void) image;
747   (void) base;
748   (void) size;
749 }
750
751 static void TIFFWarnings(const char *module,const char *format,va_list warning)
752 {
753   char
754     message[MaxTextExtent];
755
756   ExceptionInfo
757     *exception;
758
759 #if defined(MAGICKCORE_HAVE_VSNPRINTF)
760   (void) vsnprintf(message,MaxTextExtent,format,warning);
761 #else
762   (void) vsprintf(message,format,warning);
763 #endif
764   (void) ConcatenateMagickString(message,".",MaxTextExtent);
765   exception=(ExceptionInfo *) MagickGetThreadValue(tiff_exception);
766   if (exception != (ExceptionInfo *) NULL)
767     (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
768       message,"`%s'",module);
769 }
770
771 static tsize_t TIFFWriteBlob(thandle_t image,tdata_t data,tsize_t size)
772 {
773   tsize_t
774     count;
775
776   count=(tsize_t) WriteBlob((Image *) image,(size_t) size,
777     (unsigned char *) data);
778   return(count);
779 }
780
781 #if defined(__cplusplus) || defined(c_plusplus)
782 }
783 #endif
784
785 static Image *ReadTIFFImage(const ImageInfo *image_info,
786   ExceptionInfo *exception)
787 {
788   typedef enum
789   {
790     ReadSingleSampleMethod,
791     ReadRGBAMethod,
792     ReadCMYKAMethod,
793     ReadStripMethod,
794     ReadTileMethod,
795     ReadGenericMethod
796   } TIFFMethodType;
797
798   const char
799     *option;
800
801   float
802     *chromaticity,
803     x_position,
804     y_position,
805     x_resolution,
806     y_resolution;
807
808   Image
809     *image;
810
811   MagickBooleanType
812     associated_alpha,
813     debug,
814     status;
815
816   MagickSizeType
817     number_pixels;
818
819   QuantumInfo
820     *quantum_info;
821
822   QuantumType
823     quantum_type;
824
825   register ssize_t
826     i;
827
828   size_t
829     length,
830     pad;
831
832   ssize_t
833     y;
834
835   TIFF
836     *tiff;
837
838   TIFFErrorHandler
839     error_handler,
840     warning_handler;
841
842   TIFFMethodType
843     method;
844
845   uint16
846     compress_tag,
847     bits_per_sample,
848     endian,
849     extra_samples,
850     interlace,
851     max_sample_value,
852     min_sample_value,
853     orientation,
854     pages,
855     photometric,
856     *sample_info,
857     sample_format,
858     samples_per_pixel,
859     units,
860     value;
861
862   uint32
863     height,
864     rows_per_strip,
865     width;
866
867   unsigned char
868     *pixels;
869
870   /*
871     Open image.
872   */
873   assert(image_info != (const ImageInfo *) NULL);
874   assert(image_info->signature == MagickSignature);
875   if (image_info->debug != MagickFalse)
876     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
877       image_info->filename);
878   assert(exception != (ExceptionInfo *) NULL);
879   assert(exception->signature == MagickSignature);
880   image=AcquireImage(image_info,exception);
881   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
882   if (status == MagickFalse)
883     {
884       image=DestroyImageList(image);
885       return((Image *) NULL);
886     }
887   (void) MagickSetThreadValue(tiff_exception,exception);
888   error_handler=TIFFSetErrorHandler(TIFFErrors);
889   warning_handler=TIFFSetWarningHandler(TIFFWarnings);
890   tiff=TIFFClientOpen(image->filename,"rb",(thandle_t) image,TIFFReadBlob,
891     TIFFWriteBlob,TIFFSeekBlob,TIFFCloseBlob,TIFFGetBlobSize,TIFFMapBlob,
892     TIFFUnmapBlob);
893   if (tiff == (TIFF *) NULL)
894     {
895       (void) TIFFSetWarningHandler(warning_handler);
896       (void) TIFFSetErrorHandler(error_handler);
897       image=DestroyImageList(image);
898       return((Image *) NULL);
899     }
900   debug=IsEventLogging();
901   (void) debug;
902   if (image_info->number_scenes != 0)
903     {
904       /*
905         Generate blank images for subimage specification (e.g. image.tif[4].
906       */
907       for (i=0; i < (ssize_t) image_info->scene; i++)
908       {
909         (void) TIFFReadDirectory(tiff);
910         AcquireNextImage(image_info,image,exception);
911         if (GetNextImageInList(image) == (Image *) NULL)
912           {
913             image=DestroyImageList(image);
914             return((Image *) NULL);
915           }
916         image=SyncNextImageInList(image);
917       }
918     }
919   do
920   {
921     if (0 && (image_info->verbose != MagickFalse))
922       TIFFPrintDirectory(tiff,stdout,MagickFalse);
923 #if defined(MAGICKCORE_HAVE_TIFFISBIGENDIAN)
924     (void) SetImageProperty(image,"tiff:endian",TIFFIsBigEndian(tiff) == 0 ?
925       "lsb" : "msb",exception);
926 #endif
927     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_COMPRESSION,&compress_tag);
928     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_ORIENTATION,&orientation);
929     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_IMAGEWIDTH,&width);
930     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_IMAGELENGTH,&height);
931     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_FILLORDER,&endian);
932     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_PLANARCONFIG,&interlace);
933     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_BITSPERSAMPLE,&bits_per_sample);
934     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_SAMPLEFORMAT,&sample_format);
935     if (sample_format == SAMPLEFORMAT_IEEEFP)
936       (void) SetImageProperty(image,"quantum:format","floating-point",
937         exception);
938     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_MINSAMPLEVALUE,&min_sample_value);
939     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_MAXSAMPLEVALUE,&max_sample_value);
940     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_PHOTOMETRIC,&photometric);
941     switch (photometric)
942     {
943       case PHOTOMETRIC_MINISBLACK:
944       {
945         (void) SetImageProperty(image,"tiff:photometric","min-is-black",
946           exception);
947         break;
948       }
949       case PHOTOMETRIC_MINISWHITE:
950       {
951         (void) SetImageProperty(image,"tiff:photometric","min-is-white",
952           exception);
953         break;
954       }
955       case PHOTOMETRIC_PALETTE:
956       {
957         (void) SetImageProperty(image,"tiff:photometric","palette",exception);
958         break;
959       }
960       case PHOTOMETRIC_RGB:
961       {
962         (void) SetImageProperty(image,"tiff:photometric","RGB",exception);
963         break;
964       }
965       case PHOTOMETRIC_CIELAB:
966       {
967         (void) SetImageProperty(image,"tiff:photometric","CIELAB",exception);
968         break;
969       }
970       case PHOTOMETRIC_SEPARATED:
971       {
972         (void) SetImageProperty(image,"tiff:photometric","separated",exception);
973         break;
974       }
975       case PHOTOMETRIC_YCBCR:
976       {
977         (void) SetImageProperty(image,"tiff:photometric","YCBCR",exception);
978         break;
979       }
980       default:
981       {
982         (void) SetImageProperty(image,"tiff:photometric","unknown",exception);
983         break;
984       }
985     }
986     if (image->debug != MagickFalse)
987       {
988         (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %ux%u",
989           (unsigned int) width,(unsigned int) height);
990         (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Interlace: %u",
991           interlace);
992         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
993           "Bits per sample: %u",bits_per_sample);
994         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
995           "Min sample value: %u",min_sample_value);
996         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
997           "Max sample value: %u",max_sample_value);
998         (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Photometric "
999           "interpretation: %s",GetImageProperty(image,"tiff:photometric",
1000           exception));
1001       }
1002     image->columns=(size_t) width;
1003     image->rows=(size_t) height;
1004     image->depth=(size_t) bits_per_sample;
1005     if (image->debug != MagickFalse)
1006       (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Image depth: %.20g",
1007         (double) image->depth);
1008     image->endian=MSBEndian;
1009     if (endian == FILLORDER_LSB2MSB)
1010       image->endian=LSBEndian;
1011     if ((photometric == PHOTOMETRIC_MINISBLACK) ||
1012         (photometric == PHOTOMETRIC_MINISWHITE))
1013       image->colorspace=GRAYColorspace;
1014     if (photometric == PHOTOMETRIC_SEPARATED)
1015       image->colorspace=CMYKColorspace;
1016     if (photometric == PHOTOMETRIC_CIELAB)
1017       image->colorspace=LabColorspace;
1018     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_SAMPLESPERPIXEL,
1019       &samples_per_pixel);
1020     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_RESOLUTIONUNIT,&units);
1021     x_resolution=(float) image->resolution.x;
1022     y_resolution=(float) image->resolution.y;
1023     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_XRESOLUTION,&x_resolution);
1024     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_YRESOLUTION,&y_resolution);
1025     image->resolution.x=x_resolution;
1026     image->resolution.y=y_resolution;
1027     x_position=(float) image->page.x/x_resolution;
1028     y_position=(float) image->page.y/y_resolution;
1029     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_XPOSITION,&x_position);
1030     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_YPOSITION,&y_position);
1031     image->page.x=(ssize_t) ceil(x_position*x_resolution-0.5);
1032     image->page.y=(ssize_t) ceil(y_position*y_resolution-0.5);
1033     image->orientation=(OrientationType) orientation;
1034     chromaticity=(float *) NULL;
1035     (void) TIFFGetField(tiff,TIFFTAG_WHITEPOINT,&chromaticity);
1036     if (chromaticity != (float *) NULL)
1037       {
1038         image->chromaticity.white_point.x=chromaticity[0];
1039         image->chromaticity.white_point.y=chromaticity[1];
1040       }
1041     chromaticity=(float *) NULL;
1042     (void) TIFFGetField(tiff,TIFFTAG_PRIMARYCHROMATICITIES,&chromaticity);
1043     if (chromaticity != (float *) NULL)
1044       {
1045         image->chromaticity.red_primary.x=chromaticity[0];
1046         image->chromaticity.red_primary.y=chromaticity[1];
1047         image->chromaticity.green_primary.x=chromaticity[2];
1048         image->chromaticity.green_primary.y=chromaticity[3];
1049         image->chromaticity.blue_primary.x=chromaticity[4];
1050         image->chromaticity.blue_primary.y=chromaticity[5];
1051       }
1052 #if defined(MAGICKCORE_HAVE_TIFFISCODECCONFIGURED) || (TIFFLIB_VERSION > 20040919)
1053     if ((compress_tag != COMPRESSION_NONE) &&
1054         (TIFFIsCODECConfigured(compress_tag) == 0))
1055       {
1056         TIFFClose(tiff);
1057         ThrowReaderException(CoderError,"CompressNotSupported");
1058       }
1059 #endif
1060     switch (compress_tag)
1061     {
1062       case COMPRESSION_NONE: image->compression=NoCompression; break;
1063       case COMPRESSION_CCITTFAX3: image->compression=FaxCompression; break;
1064       case COMPRESSION_CCITTFAX4: image->compression=Group4Compression; break;
1065       case COMPRESSION_JPEG:
1066       {
1067          image->compression=JPEGCompression;
1068 #if defined(JPEG_SUPPORT)
1069          {
1070            char
1071              sampling_factor[MaxTextExtent];
1072
1073            uint16
1074              horizontal,
1075              vertical;
1076
1077            (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_YCBCRSUBSAMPLING,
1078              &horizontal,&vertical);
1079            (void) FormatLocaleString(sampling_factor,MaxTextExtent,"%dx%d",
1080              horizontal,vertical);
1081            (void) SetImageProperty(image,"jpeg:sampling-factor",
1082              sampling_factor,exception);
1083            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1084              "Sampling Factors: %s",sampling_factor);
1085            if ((samples_per_pixel > 1) && (photometric == PHOTOMETRIC_YCBCR))
1086              {
1087                (void) TIFFSetField(tiff,TIFFTAG_JPEGCOLORMODE,
1088                  JPEGCOLORMODE_RGB);
1089                photometric=PHOTOMETRIC_RGB;
1090              }
1091          }
1092 #endif
1093         break;
1094       }
1095       case COMPRESSION_OJPEG: image->compression=JPEGCompression; break;
1096 #if defined(COMPRESSION_LZMA)
1097       case COMPRESSION_LZMA: image->compression=LZMACompression; break;
1098 #endif
1099       case COMPRESSION_LZW: image->compression=LZWCompression; break;
1100       case COMPRESSION_DEFLATE: image->compression=ZipCompression; break;
1101       case COMPRESSION_ADOBE_DEFLATE: image->compression=ZipCompression; break;
1102       default: image->compression=RLECompression; break;
1103     }
1104     TIFFGetProfiles(tiff,image,exception);
1105     TIFFGetProperties(tiff,image,exception);
1106     option=GetImageOption(image_info,"tiff:exif-properties");
1107     if ((option == (const char *) NULL) ||
1108         (IsMagickTrue(option) != MagickFalse))
1109       TIFFGetEXIFProperties(tiff,image,exception);
1110     /*
1111       Allocate memory for the image and pixel buffer.
1112     */
1113     quantum_info=AcquireQuantumInfo(image_info,image);
1114     if (quantum_info == (QuantumInfo *) NULL)
1115       {
1116         TIFFClose(tiff);
1117         ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1118       }
1119     if (sample_format == SAMPLEFORMAT_UINT)
1120       status=SetQuantumFormat(image,quantum_info,UnsignedQuantumFormat);
1121     if (sample_format == SAMPLEFORMAT_INT)
1122       status=SetQuantumFormat(image,quantum_info,SignedQuantumFormat);
1123     if (sample_format == SAMPLEFORMAT_IEEEFP)
1124       status=SetQuantumFormat(image,quantum_info,FloatingPointQuantumFormat);
1125     if (status == MagickFalse)
1126       {
1127         quantum_info=DestroyQuantumInfo(quantum_info);
1128         TIFFClose(tiff);
1129         ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1130       }
1131     status=MagickTrue;
1132     switch (photometric)
1133     {
1134       case PHOTOMETRIC_MINISBLACK:
1135       {
1136         quantum_info->min_is_white=MagickFalse;
1137         break;
1138       }
1139       case PHOTOMETRIC_MINISWHITE:
1140       {
1141         quantum_info->min_is_white=MagickTrue;
1142         break;
1143       }
1144       default:
1145         break;
1146     }
1147     associated_alpha=MagickFalse;
1148     extra_samples=0;
1149     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_EXTRASAMPLES,&extra_samples,
1150       &sample_info);
1151     if (extra_samples == 0)
1152       {
1153         if ((samples_per_pixel == 4) && (photometric == PHOTOMETRIC_RGB))
1154           image->matte=MagickTrue;
1155       }
1156     else
1157       for (i=0; i < extra_samples; i++)
1158       {
1159         image->matte=MagickTrue;
1160         if (sample_info[i] == EXTRASAMPLE_ASSOCALPHA)
1161           SetQuantumAlphaType(quantum_info,DisassociatedQuantumAlpha);
1162       }
1163     option=GetImageOption(image_info,"tiff:alpha");
1164     if (option != (const char *) NULL)
1165       associated_alpha=LocaleCompare(option,"associated") == 0 ? MagickTrue :
1166         MagickFalse;
1167     if (image->matte != MagickFalse)
1168       (void) SetImageProperty(image,"tiff:alpha",
1169         associated_alpha != MagickFalse ? "associated" : "unassociated",
1170         exception);
1171     if ((photometric == PHOTOMETRIC_PALETTE) &&
1172         (pow(2.0,1.0*bits_per_sample) <= MaxColormapSize))
1173       {
1174         size_t
1175           colors;
1176
1177         colors=(size_t) GetQuantumRange(bits_per_sample)+1;
1178         if (AcquireImageColormap(image,colors,exception) == MagickFalse)
1179           {
1180             TIFFClose(tiff);
1181             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1182           }
1183       }
1184     if (units == RESUNIT_INCH)
1185       image->units=PixelsPerInchResolution;
1186     if (units == RESUNIT_CENTIMETER)
1187       image->units=PixelsPerCentimeterResolution;
1188     value=(unsigned short) image->scene;
1189     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_PAGENUMBER,&value,&pages);
1190     image->scene=value;
1191     if (image_info->ping != MagickFalse)
1192       {
1193         if (image_info->number_scenes != 0)
1194           if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1195             break;
1196         goto next_tiff_frame;
1197       }
1198     method=ReadGenericMethod;
1199     if (TIFFGetField(tiff,TIFFTAG_ROWSPERSTRIP,&rows_per_strip) != 0)
1200       {
1201         char
1202           value[MaxTextExtent];
1203
1204         method=ReadStripMethod;
1205         (void) FormatLocaleString(value,MaxTextExtent,"%u",
1206           (unsigned int) rows_per_strip);
1207         (void) SetImageProperty(image,"tiff:rows-per-strip",value,exception);
1208       }
1209     if ((samples_per_pixel >= 2) && (interlace == PLANARCONFIG_CONTIG))
1210       method=ReadRGBAMethod;
1211     if ((samples_per_pixel >= 2) && (interlace == PLANARCONFIG_SEPARATE))
1212       method=ReadCMYKAMethod;
1213     if ((photometric != PHOTOMETRIC_RGB) &&
1214         (photometric != PHOTOMETRIC_CIELAB) &&
1215         (photometric != PHOTOMETRIC_SEPARATED))
1216       method=ReadGenericMethod;
1217     if (image->storage_class == PseudoClass)
1218       method=ReadSingleSampleMethod;
1219     if ((photometric == PHOTOMETRIC_MINISBLACK) ||
1220         (photometric == PHOTOMETRIC_MINISWHITE))
1221       method=ReadSingleSampleMethod;
1222     if ((photometric != PHOTOMETRIC_SEPARATED) &&
1223         (interlace == PLANARCONFIG_SEPARATE) && (bits_per_sample < 64))
1224       method=ReadGenericMethod;
1225     if (image->compression == JPEGCompression)
1226       method=ReadGenericMethod;
1227     if (TIFFIsTiled(tiff) != MagickFalse)
1228       method=ReadTileMethod;
1229     quantum_info->endian=LSBEndian;
1230     quantum_type=RGBQuantum;
1231     pixels=GetQuantumPixels(quantum_info);
1232     switch (method)
1233     {
1234       case ReadSingleSampleMethod:
1235       {
1236         /*
1237           Convert TIFF image to PseudoClass MIFF image.
1238         */
1239         if ((image->storage_class == PseudoClass) &&
1240             (photometric == PHOTOMETRIC_PALETTE))
1241           {
1242             size_t
1243               range;
1244
1245             uint16
1246               *blue_colormap,
1247               *green_colormap,
1248               *red_colormap;
1249
1250             /*
1251               Initialize colormap.
1252             */
1253             (void) TIFFGetField(tiff,TIFFTAG_COLORMAP,&red_colormap,
1254               &green_colormap,&blue_colormap);
1255             range=255;  /* might be old style 8-bit colormap */
1256             for (i=0; i < (ssize_t) image->colors; i++)
1257               if ((red_colormap[i] >= 256) || (green_colormap[i] >= 256) ||
1258                   (blue_colormap[i] >= 256))
1259                 {
1260                   range=65535;
1261                   break;
1262                 }
1263             for (i=0; i < (ssize_t) image->colors; i++)
1264             {
1265               image->colormap[i].red=ClampToQuantum(((double) QuantumRange*
1266                 red_colormap[i])/range);
1267               image->colormap[i].green=ClampToQuantum(((double) QuantumRange*
1268                 green_colormap[i])/range);
1269               image->colormap[i].blue=ClampToQuantum(((double) QuantumRange*
1270                 blue_colormap[i])/range);
1271             }
1272           }
1273         quantum_type=IndexQuantum;
1274         pad=(size_t) MagickMax((size_t) samples_per_pixel-1,0);
1275         if (image->matte != MagickFalse)
1276           {
1277             if (image->storage_class != PseudoClass)
1278               {
1279                 quantum_type=samples_per_pixel == 1 ? AlphaQuantum :
1280                   GrayAlphaQuantum;
1281                 pad=(size_t) MagickMax((size_t) samples_per_pixel-2,0);
1282               }
1283             else
1284               {
1285                 quantum_type=IndexAlphaQuantum;
1286                 pad=(size_t) MagickMax((size_t) samples_per_pixel-2,0);
1287               }
1288           }
1289         else
1290           if (image->storage_class != PseudoClass)
1291             {
1292               quantum_type=GrayQuantum;
1293               pad=(size_t) MagickMax((size_t) samples_per_pixel-1,0);
1294             }
1295         status=SetQuantumPad(image,quantum_info,pad*((bits_per_sample+7) >> 3));
1296         if (status == MagickFalse)
1297           {
1298             TIFFClose(tiff);
1299             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1300           }
1301         pixels=GetQuantumPixels(quantum_info);
1302         for (y=0; y < (ssize_t) image->rows; y++)
1303         {
1304           int
1305             status;
1306
1307           register Quantum
1308             *restrict q;
1309
1310           status=TIFFReadPixels(tiff,bits_per_sample,0,y,(char *) pixels);
1311           if (status == -1)
1312             break;
1313           q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1314           if (q == (Quantum *) NULL)
1315             break;
1316           length=ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1317             quantum_type,pixels,exception);
1318           (void) length;
1319           if (SyncAuthenticPixels(image,exception) == MagickFalse)
1320             break;
1321           if (image->previous == (Image *) NULL)
1322             {
1323               status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1324                 image->rows);
1325               if (status == MagickFalse)
1326                 break;
1327             }
1328         }
1329         break;
1330       }
1331       case ReadRGBAMethod:
1332       {
1333         /*
1334           Convert TIFF image to DirectClass MIFF image.
1335         */
1336         pad=(size_t) MagickMax((size_t) samples_per_pixel-3,0);
1337         quantum_type=RGBQuantum;
1338         if (image->matte != MagickFalse)
1339           {
1340             quantum_type=RGBAQuantum;
1341             pad=(size_t) MagickMax((size_t) samples_per_pixel-4,0);
1342           }
1343         if (image->colorspace == CMYKColorspace)
1344           {
1345             pad=(size_t) MagickMax((size_t) samples_per_pixel-4,0);
1346             quantum_type=CMYKQuantum;
1347             if (image->matte != MagickFalse)
1348               {
1349                 quantum_type=CMYKAQuantum;
1350                 pad=(size_t) MagickMax((size_t) samples_per_pixel-5,0);
1351               }
1352           }
1353         status=SetQuantumPad(image,quantum_info,pad*((bits_per_sample+7) >> 3));
1354         if (status == MagickFalse)
1355           {
1356             TIFFClose(tiff);
1357             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1358           }
1359         pixels=GetQuantumPixels(quantum_info);
1360         for (y=0; y < (ssize_t) image->rows; y++)
1361         {
1362           int
1363             status;
1364
1365           register Quantum
1366             *restrict q;
1367
1368           status=TIFFReadPixels(tiff,bits_per_sample,0,y,(char *) pixels);
1369           if (status == -1)
1370             break;
1371           q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1372           if (q == (Quantum *) NULL)
1373             break;
1374           length=ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1375             quantum_type,pixels,exception);
1376           if (SyncAuthenticPixels(image,exception) == MagickFalse)
1377             break;
1378           if (image->previous == (Image *) NULL)
1379             {
1380               status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1381                 image->rows);
1382               if (status == MagickFalse)
1383                 break;
1384             }
1385         }
1386         break;
1387       }
1388       case ReadCMYKAMethod:
1389       {
1390         /*
1391           Convert TIFF image to DirectClass MIFF image.
1392         */
1393         for (i=0; i < (ssize_t) samples_per_pixel; i++)
1394         {
1395           for (y=0; y < (ssize_t) image->rows; y++)
1396           {
1397             register Quantum
1398               *restrict q;
1399
1400             int
1401               status;
1402
1403             status=TIFFReadPixels(tiff,bits_per_sample,(tsample_t) i,y,(char *)
1404               pixels);
1405             if (status == -1)
1406               break;
1407             q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
1408             if (q == (Quantum *) NULL)
1409               break;
1410             if (image->colorspace != CMYKColorspace)
1411               switch (i)
1412               {
1413                 case 0: quantum_type=RedQuantum; break;
1414                 case 1: quantum_type=GreenQuantum; break;
1415                 case 2: quantum_type=BlueQuantum; break;
1416                 case 3: quantum_type=AlphaQuantum; break;
1417                 default: quantum_type=UndefinedQuantum; break;
1418               }
1419             else
1420               switch (i)
1421               {
1422                 case 0: quantum_type=CyanQuantum; break;
1423                 case 1: quantum_type=MagentaQuantum; break;
1424                 case 2: quantum_type=YellowQuantum; break;
1425                 case 3: quantum_type=BlackQuantum; break;
1426                 case 4: quantum_type=AlphaQuantum; break;
1427                 default: quantum_type=UndefinedQuantum; break;
1428               }
1429             length=ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1430               quantum_type,pixels,exception);
1431             if (SyncAuthenticPixels(image,exception) == MagickFalse)
1432               break;
1433           }
1434           if (image->previous == (Image *) NULL)
1435             {
1436               status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1437                 image->rows);
1438               if (status == MagickFalse)
1439                 break;
1440             }
1441         }
1442         break;
1443       }
1444       case ReadStripMethod:
1445       {
1446         register unsigned char
1447           *p;
1448
1449         /*
1450           Convert stripped TIFF image to DirectClass MIFF image.
1451         */
1452         i=0;
1453         p=(unsigned char *) NULL;
1454         for (y=0; y < (ssize_t) image->rows; y++)
1455         {
1456           register ssize_t
1457             x;
1458
1459           register Quantum
1460             *restrict q;
1461
1462           q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1463           if (q == (Quantum *) NULL)
1464             break;
1465           if (i == 0)
1466             {
1467               if (TIFFReadRGBAStrip(tiff,(tstrip_t) y,(uint32 *) pixels) == 0)
1468                 break;
1469               i=(ssize_t) MagickMin((ssize_t) rows_per_strip,(ssize_t)
1470                 image->rows-y);
1471             }
1472           i--;
1473           p=(unsigned char *) (((uint32 *) pixels)+image->columns*i);
1474           for (x=0; x < (ssize_t) image->columns; x++)
1475           {
1476             SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1477               (TIFFGetR(*p))),q);
1478             SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1479               (TIFFGetG(*p))),q);
1480             SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1481               (TIFFGetB(*p))),q);
1482             if (image->matte != MagickFalse)
1483               SetPixelAlpha(image,ScaleCharToQuantum((unsigned char)
1484                 (TIFFGetA(*p))),q);
1485             p++;
1486             q+=GetPixelChannels(image);
1487           }
1488           if (SyncAuthenticPixels(image,exception) == MagickFalse)
1489             break;
1490           if (image->previous == (Image *) NULL)
1491             {
1492               status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1493                 image->rows);
1494               if (status == MagickFalse)
1495                 break;
1496             }
1497         }
1498         break;
1499       }
1500       case ReadTileMethod:
1501       {
1502         register uint32
1503           *p;
1504
1505         uint32
1506           *tile_pixels,
1507           columns,
1508           rows;
1509
1510         size_t
1511           number_pixels;
1512
1513         /*
1514           Convert tiled TIFF image to DirectClass MIFF image.
1515         */
1516         if ((TIFFGetField(tiff,TIFFTAG_TILEWIDTH,&columns) == 0) ||
1517             (TIFFGetField(tiff,TIFFTAG_TILELENGTH,&rows) == 0))
1518           {
1519             TIFFClose(tiff);
1520             ThrowReaderException(CoderError,"ImageIsNotTiled");
1521           }
1522         (void) SetImageStorageClass(image,DirectClass,exception);
1523         number_pixels=columns*rows;
1524         tile_pixels=(uint32 *) AcquireQuantumMemory(number_pixels,
1525           sizeof(*tile_pixels));
1526         if (tile_pixels == (uint32 *) NULL)
1527           {
1528             TIFFClose(tiff);
1529             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1530           }
1531         for (y=0; y < (ssize_t) image->rows; y+=rows)
1532         {
1533           register ssize_t
1534             x;
1535
1536           register Quantum
1537             *restrict q,
1538             *restrict tile;
1539
1540           size_t
1541             columns_remaining,
1542             rows_remaining;
1543
1544           rows_remaining=image->rows-y;
1545           if ((ssize_t) (y+rows) < (ssize_t) image->rows)
1546             rows_remaining=rows;
1547           tile=QueueAuthenticPixels(image,0,y,image->columns,rows_remaining,
1548             exception);
1549           if (tile == (Quantum *) NULL)
1550             break;
1551           for (x=0; x < (ssize_t) image->columns; x+=columns)
1552           {
1553             size_t
1554               column,
1555               row;
1556
1557             if (TIFFReadRGBATile(tiff,(uint32) x,(uint32) y,tile_pixels) == 0)
1558               break;
1559             columns_remaining=image->columns-x;
1560             if ((ssize_t) (x+columns) < (ssize_t) image->columns)
1561               columns_remaining=columns;
1562             p=tile_pixels+(rows-rows_remaining)*columns;
1563             q=tile+GetPixelChannels(image)*(image->columns*(rows_remaining-1)+
1564               x);
1565             for (row=rows_remaining; row > 0; row--)
1566             {
1567               if (image->matte != MagickFalse)
1568                 for (column=columns_remaining; column > 0; column--)
1569                 {
1570                   SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1571                     TIFFGetR(*p)),q);
1572                   SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1573                     TIFFGetG(*p)),q);
1574                   SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1575                     TIFFGetB(*p)),q);
1576                   SetPixelAlpha(image,ScaleCharToQuantum((unsigned char)
1577                     TIFFGetA(*p)),q);
1578                   p++;
1579                   q+=GetPixelChannels(image);
1580                 }
1581               else
1582                 for (column=columns_remaining; column > 0; column--)
1583                 {
1584                   SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1585                     TIFFGetR(*p)),q);
1586                   SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1587                     TIFFGetG(*p)),q);
1588                   SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1589                     TIFFGetB(*p)),q);
1590                   p++;
1591                   q+=GetPixelChannels(image);
1592                 }
1593               p+=columns-columns_remaining;
1594               q-=GetPixelChannels(image)*(image->columns+columns_remaining);
1595             }
1596           }
1597           if (SyncAuthenticPixels(image,exception) == MagickFalse)
1598             break;
1599           if (image->previous == (Image *) NULL)
1600             {
1601               status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1602                 image->rows);
1603               if (status == MagickFalse)
1604                 break;
1605             }
1606         }
1607         tile_pixels=(uint32 *) RelinquishMagickMemory(tile_pixels);
1608         break;
1609       }
1610       case ReadGenericMethod:
1611       default:
1612       {
1613         register uint32
1614           *p;
1615
1616         uint32
1617           *pixels;
1618
1619         /*
1620           Convert TIFF image to DirectClass MIFF image.
1621         */
1622         number_pixels=(MagickSizeType) image->columns*image->rows;
1623         if ((number_pixels*sizeof(uint32)) != (MagickSizeType) ((size_t)
1624             (number_pixels*sizeof(uint32))))
1625           {
1626             TIFFClose(tiff);
1627             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1628           }
1629         pixels=(uint32 *) AcquireQuantumMemory(image->columns,image->rows*
1630           sizeof(uint32));
1631         if (pixels == (uint32 *) NULL)
1632           {
1633             TIFFClose(tiff);
1634             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1635           }
1636         (void) TIFFReadRGBAImage(tiff,(uint32) image->columns,
1637           (uint32) image->rows,(uint32 *) pixels,0);
1638         /*
1639           Convert image to DirectClass pixel packets.
1640         */
1641         p=pixels+number_pixels-1;
1642         for (y=0; y < (ssize_t) image->rows; y++)
1643         {
1644           register ssize_t
1645             x;
1646
1647           register Quantum
1648             *restrict q;
1649
1650           q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1651           if (q == (Quantum *) NULL)
1652             break;
1653           q+=GetPixelChannels(image)*(image->columns-1);
1654           for (x=0; x < (ssize_t) image->columns; x++)
1655           {
1656             SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1657               TIFFGetR(*p)),q);
1658             SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1659               TIFFGetG(*p)),q);
1660             SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1661               TIFFGetB(*p)),q);
1662             if (image->matte != MagickFalse)
1663               SetPixelAlpha(image,ScaleCharToQuantum((unsigned char)
1664                 TIFFGetA(*p)),q);
1665             p--;
1666             q-=GetPixelChannels(image);;
1667           }
1668           if (SyncAuthenticPixels(image,exception) == MagickFalse)
1669             break;
1670           if (image->previous == (Image *) NULL)
1671             {
1672               status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1673                 image->rows);
1674               if (status == MagickFalse)
1675                 break;
1676             }
1677         }
1678         pixels=(uint32 *) RelinquishMagickMemory(pixels);
1679         break;
1680       }
1681     }
1682     SetQuantumImageType(image,quantum_type);
1683   next_tiff_frame:
1684     quantum_info=DestroyQuantumInfo(quantum_info);
1685     if ((photometric == PHOTOMETRIC_LOGL) ||
1686         (photometric == PHOTOMETRIC_MINISBLACK) ||
1687         (photometric == PHOTOMETRIC_MINISWHITE))
1688       {
1689         image->type=GrayscaleType;
1690         if (bits_per_sample == 1)
1691           image->type=BilevelType;
1692       }
1693     if (image->storage_class == PseudoClass)
1694       image->depth=GetImageDepth(image,exception);
1695     if ((photometric == PHOTOMETRIC_LOGL) ||
1696         (photometric == PHOTOMETRIC_MINISBLACK) ||
1697         (photometric == PHOTOMETRIC_MINISWHITE))
1698       {
1699          image->type=GrayscaleType;
1700          if (bits_per_sample == 1)
1701            image->type=BilevelType;
1702       }
1703     /*
1704       Proceed to next image.
1705     */
1706     if (image_info->number_scenes != 0)
1707       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1708         break;
1709     status=TIFFReadDirectory(tiff) != 0 ? MagickTrue : MagickFalse;
1710     if (status == MagickTrue)
1711       {
1712         /*
1713           Allocate next image structure.
1714         */
1715         AcquireNextImage(image_info,image,exception);
1716         if (GetNextImageInList(image) == (Image *) NULL)
1717           {
1718             image=DestroyImageList(image);
1719             return((Image *) NULL);
1720           }
1721         image=SyncNextImageInList(image);
1722         status=SetImageProgress(image,LoadImagesTag,image->scene-1,
1723           image->scene);
1724         if (status == MagickFalse)
1725           break;
1726       }
1727   } while (status == MagickTrue);
1728   (void) TIFFSetWarningHandler(warning_handler);
1729   (void) TIFFSetErrorHandler(error_handler);
1730   TIFFClose(tiff);
1731   return(GetFirstImageInList(image));
1732 }
1733 #endif
1734 \f
1735 /*
1736 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1737 %                                                                             %
1738 %                                                                             %
1739 %                                                                             %
1740 %   R e g i s t e r T I F F I m a g e                                         %
1741 %                                                                             %
1742 %                                                                             %
1743 %                                                                             %
1744 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1745 %
1746 %  RegisterTIFFImage() adds properties for the TIFF image format to
1747 %  the list of supported formats.  The properties include the image format
1748 %  tag, a method to read and/or write the format, whether the format
1749 %  supports the saving of more than one frame to the same file or blob,
1750 %  whether the format supports native in-memory I/O, and a brief
1751 %  description of the format.
1752 %
1753 %  The format of the RegisterTIFFImage method is:
1754 %
1755 %      size_t RegisterTIFFImage(void)
1756 %
1757 */
1758
1759 #if defined(MAGICKCORE_HAVE_TIFFMERGEFIELDINFO) && defined(MAGICKCORE_HAVE_TIFFSETTAGEXTENDER)
1760 static TIFFExtendProc
1761   tag_extender = (TIFFExtendProc) NULL;
1762
1763 static void TIFFTagExtender(TIFF *tiff)
1764 {
1765   static const TIFFFieldInfo
1766     TIFFExtensions[] =
1767     {
1768       {
1769         37724, -3, -3, TIFF_UNDEFINED, FIELD_CUSTOM, 1, 1,
1770           (char *) "PhotoshopLayerData"
1771       }
1772     };
1773
1774   TIFFMergeFieldInfo(tiff,TIFFExtensions,sizeof(TIFFExtensions)/
1775     sizeof(*TIFFExtensions));
1776   if (tag_extender != (TIFFExtendProc) NULL)
1777     (*tag_extender)(tiff);
1778 }
1779 #endif
1780
1781 ModuleExport size_t RegisterTIFFImage(void)
1782 {
1783 #define TIFFDescription  "Tagged Image File Format"
1784
1785   char
1786     version[MaxTextExtent];
1787
1788   MagickInfo
1789     *entry;
1790
1791   if (tiff_semaphore == (SemaphoreInfo *) NULL)
1792     tiff_semaphore=AllocateSemaphoreInfo();
1793   LockSemaphoreInfo(tiff_semaphore);
1794   if (instantiate_key == MagickFalse)
1795     {
1796       if (MagickCreateThreadKey(&tiff_exception) == MagickFalse)
1797         ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1798 #if defined(MAGICKCORE_HAVE_TIFFMERGEFIELDINFO) && defined(MAGICKCORE_HAVE_TIFFSETTAGEXTENDER)
1799       if (tag_extender == (TIFFExtendProc) NULL)
1800         tag_extender=TIFFSetTagExtender(TIFFTagExtender);
1801 #endif
1802       instantiate_key=MagickTrue;
1803     }
1804   UnlockSemaphoreInfo(tiff_semaphore);
1805   *version='\0';
1806 #if defined(TIFF_VERSION)
1807   (void) FormatLocaleString(version,MaxTextExtent,"%d",TIFF_VERSION);
1808 #endif
1809 #if defined(MAGICKCORE_TIFF_DELEGATE)
1810   {
1811     const char
1812       *p;
1813
1814     register ssize_t
1815       i;
1816
1817     p=TIFFGetVersion();
1818     for (i=0; (i < (MaxTextExtent-1)) && (*p != 0) && (*p != '\n'); i++)
1819       version[i]=(*p++);
1820     version[i]='\0';
1821   }
1822 #endif
1823
1824   entry=SetMagickInfo("GROUP4");
1825 #if defined(MAGICKCORE_TIFF_DELEGATE)
1826   entry->decoder=(DecodeImageHandler *) ReadGROUP4Image;
1827   entry->encoder=(EncodeImageHandler *) WriteGROUP4Image;
1828 #endif
1829   entry->raw=MagickTrue;
1830   entry->endian_support=MagickTrue;
1831   entry->adjoin=MagickFalse;
1832   entry->format_type=ImplicitFormatType;
1833   entry->seekable_stream=MagickTrue;
1834   entry->thread_support=NoThreadSupport;
1835   entry->description=ConstantString("Raw CCITT Group4");
1836   entry->module=ConstantString("TIFF");
1837   (void) RegisterMagickInfo(entry);
1838   entry=SetMagickInfo("PTIF");
1839 #if defined(MAGICKCORE_TIFF_DELEGATE)
1840   entry->decoder=(DecodeImageHandler *) ReadTIFFImage;
1841   entry->encoder=(EncodeImageHandler *) WritePTIFImage;
1842 #endif
1843   entry->endian_support=MagickTrue;
1844   entry->seekable_stream=MagickTrue;
1845   entry->thread_support=NoThreadSupport;
1846   entry->description=ConstantString("Pyramid encoded TIFF");
1847   entry->module=ConstantString("TIFF");
1848   (void) RegisterMagickInfo(entry);
1849   entry=SetMagickInfo("TIF");
1850 #if defined(MAGICKCORE_TIFF_DELEGATE)
1851   entry->decoder=(DecodeImageHandler *) ReadTIFFImage;
1852   entry->encoder=(EncodeImageHandler *) WriteTIFFImage;
1853 #endif
1854   entry->endian_support=MagickTrue;
1855   entry->seekable_stream=MagickTrue;
1856   entry->stealth=MagickTrue;
1857   entry->thread_support=NoThreadSupport;
1858   entry->description=ConstantString(TIFFDescription);
1859   if (*version != '\0')
1860     entry->version=ConstantString(version);
1861   entry->module=ConstantString("TIFF");
1862   (void) RegisterMagickInfo(entry);
1863   entry=SetMagickInfo("TIFF");
1864 #if defined(MAGICKCORE_TIFF_DELEGATE)
1865   entry->decoder=(DecodeImageHandler *) ReadTIFFImage;
1866   entry->encoder=(EncodeImageHandler *) WriteTIFFImage;
1867 #endif
1868   entry->magick=(IsImageFormatHandler *) IsTIFF;
1869   entry->endian_support=MagickTrue;
1870   entry->seekable_stream=MagickTrue;
1871   entry->thread_support=NoThreadSupport;
1872   entry->description=ConstantString(TIFFDescription);
1873   if (*version != '\0')
1874     entry->version=ConstantString(version);
1875   entry->module=ConstantString("TIFF");
1876   (void) RegisterMagickInfo(entry);
1877   entry=SetMagickInfo("TIFF64");
1878 #if defined(TIFF_VERSION_BIG)
1879   entry->decoder=(DecodeImageHandler *) ReadTIFFImage;
1880   entry->encoder=(EncodeImageHandler *) WriteTIFFImage;
1881 #endif
1882   entry->adjoin=MagickFalse;
1883   entry->endian_support=MagickTrue;
1884   entry->seekable_stream=MagickTrue;
1885   entry->thread_support=NoThreadSupport;
1886   entry->description=ConstantString("Tagged Image File Format (64-bit)");
1887   if (*version != '\0')
1888     entry->version=ConstantString(version);
1889   entry->module=ConstantString("TIFF");
1890   (void) RegisterMagickInfo(entry);
1891   return(MagickImageCoderSignature);
1892 }
1893 \f
1894 /*
1895 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1896 %                                                                             %
1897 %                                                                             %
1898 %                                                                             %
1899 %   U n r e g i s t e r T I F F I m a g e                                     %
1900 %                                                                             %
1901 %                                                                             %
1902 %                                                                             %
1903 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1904 %
1905 %  UnregisterTIFFImage() removes format registrations made by the TIFF module
1906 %  from the list of supported formats.
1907 %
1908 %  The format of the UnregisterTIFFImage method is:
1909 %
1910 %      UnregisterTIFFImage(void)
1911 %
1912 */
1913 ModuleExport void UnregisterTIFFImage(void)
1914 {
1915   (void) UnregisterMagickInfo("TIFF64");
1916   (void) UnregisterMagickInfo("TIFF");
1917   (void) UnregisterMagickInfo("TIF");
1918   (void) UnregisterMagickInfo("PTIF");
1919   if (tiff_semaphore == (SemaphoreInfo *) NULL)
1920     tiff_semaphore=AllocateSemaphoreInfo();
1921   LockSemaphoreInfo(tiff_semaphore);
1922   if (instantiate_key != MagickFalse)
1923     {
1924 #if defined(MAGICKCORE_HAVE_TIFFMERGEFIELDINFO) && defined(MAGICKCORE_HAVE_TIFFSETTAGEXTENDER)
1925       if (tag_extender == (TIFFExtendProc) NULL)
1926         (void) TIFFSetTagExtender(tag_extender);
1927 #endif
1928       if (MagickDeleteThreadKey(tiff_exception) == MagickFalse)
1929         ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1930       instantiate_key=MagickFalse;
1931     }
1932   UnlockSemaphoreInfo(tiff_semaphore);
1933   DestroySemaphoreInfo(&tiff_semaphore);
1934 }
1935 \f
1936 #if defined(MAGICKCORE_TIFF_DELEGATE)
1937 /*
1938 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1939 %                                                                             %
1940 %                                                                             %
1941 %                                                                             %
1942 %   W r i t e G R O U P 4 I m a g e                                           %
1943 %                                                                             %
1944 %                                                                             %
1945 %                                                                             %
1946 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1947 %
1948 %  WriteGROUP4Image() writes an image in the raw CCITT Group 4 image format.
1949 %
1950 %  The format of the WriteGROUP4Image method is:
1951 %
1952 %      MagickBooleanType WriteGROUP4Image(const ImageInfo *image_info,
1953 %        Image *image,ExceptionInfo *)
1954 %
1955 %  A description of each parameter follows:
1956 %
1957 %    o image_info: the image info.
1958 %
1959 %    o image:  The image.
1960 %
1961 %    o exception: return any errors or warnings in this structure.
1962 %
1963 */
1964 static MagickBooleanType WriteGROUP4Image(const ImageInfo *image_info,
1965   Image *image,ExceptionInfo *exception)
1966 {
1967   char
1968     filename[MaxTextExtent];
1969
1970   FILE
1971     *file;
1972
1973   Image
1974     *huffman_image;
1975
1976   ImageInfo
1977     *write_info;
1978
1979   int
1980     unique_file;
1981
1982   MagickBooleanType
1983     status;
1984
1985   register ssize_t
1986     i;
1987
1988   ssize_t
1989     count;
1990
1991   TIFF
1992     *tiff;
1993
1994   toff_t
1995     *byte_count,
1996     strip_size;
1997
1998   unsigned char
1999     *buffer;
2000
2001   /*
2002     Write image as CCITT Group4 TIFF image to a temporary file.
2003   */
2004   assert(image_info != (const ImageInfo *) NULL);
2005   assert(image_info->signature == MagickSignature);
2006   assert(image != (Image *) NULL);
2007   assert(image->signature == MagickSignature);
2008   if (image->debug != MagickFalse)
2009     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2010   assert(exception != (ExceptionInfo *) NULL);
2011   assert(exception->signature == MagickSignature);
2012   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2013   if (status == MagickFalse)
2014     return(status);
2015   huffman_image=CloneImage(image,0,0,MagickTrue,exception);
2016   if (huffman_image == (Image *) NULL)
2017     {
2018       (void) CloseBlob(image);
2019       return(MagickFalse);
2020     }
2021   huffman_image->endian=MSBEndian;
2022   file=(FILE *) NULL;
2023   unique_file=AcquireUniqueFileResource(filename);
2024   if (unique_file != -1)
2025     file=fdopen(unique_file,"wb");
2026   if ((unique_file == -1) || (file == (FILE *) NULL))
2027     {
2028       ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
2029         filename);
2030       return(MagickFalse);
2031     }
2032   (void) FormatLocaleString(huffman_image->filename,MaxTextExtent,"tiff:%s",
2033     filename);
2034   (void) SetImageType(huffman_image,BilevelType,exception);
2035   write_info=CloneImageInfo((ImageInfo *) NULL);
2036   SetImageInfoFile(write_info,file);
2037   write_info->compression=Group4Compression;
2038   write_info->type=BilevelType;
2039   (void) SetImageOption(write_info,"quantum:polarity","min-is-white");
2040   status=WriteTIFFImage(write_info,huffman_image,exception);
2041   (void) fflush(file);
2042   write_info=DestroyImageInfo(write_info);
2043   if (status == MagickFalse)
2044     {
2045       huffman_image=DestroyImage(huffman_image);
2046       (void) fclose(file);
2047       (void) RelinquishUniqueFileResource(filename);
2048       return(MagickFalse);
2049     }
2050   tiff=TIFFOpen(filename,"rb");
2051   if (tiff == (TIFF *) NULL)
2052     {
2053       huffman_image=DestroyImage(huffman_image);
2054       (void) fclose(file);
2055       (void) RelinquishUniqueFileResource(filename);
2056       ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
2057         image_info->filename);
2058       return(MagickFalse);
2059     }
2060   /*
2061     Allocate raw strip buffer.
2062   */
2063   if (TIFFGetField(tiff,TIFFTAG_STRIPBYTECOUNTS,&byte_count) != 1)
2064     {
2065       TIFFClose(tiff);
2066       huffman_image=DestroyImage(huffman_image);
2067       (void) fclose(file);
2068       (void) RelinquishUniqueFileResource(filename);
2069       return(MagickFalse);
2070     }
2071   strip_size=byte_count[0];
2072   for (i=1; i < (ssize_t) TIFFNumberOfStrips(tiff); i++)
2073     if (byte_count[i] > strip_size)
2074       strip_size=byte_count[i];
2075   buffer=(unsigned char *) AcquireQuantumMemory((size_t) strip_size,
2076     sizeof(*buffer));
2077   if (buffer == (unsigned char *) NULL)
2078     {
2079       TIFFClose(tiff);
2080       huffman_image=DestroyImage(huffman_image);
2081       (void) fclose(file);
2082       (void) RelinquishUniqueFileResource(filename);
2083       ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
2084         image_info->filename);
2085     }
2086   /*
2087     Compress runlength encoded to 2D Huffman pixels.
2088   */
2089   for (i=0; i < (ssize_t) TIFFNumberOfStrips(tiff); i++)
2090   {
2091     count=(ssize_t) TIFFReadRawStrip(tiff,(uint32) i,buffer,strip_size);
2092     if (WriteBlob(image,(size_t) count,buffer) != count)
2093       status=MagickFalse;
2094   }
2095   buffer=(unsigned char *) RelinquishMagickMemory(buffer);
2096   TIFFClose(tiff);
2097   huffman_image=DestroyImage(huffman_image);
2098   (void) fclose(file);
2099   (void) RelinquishUniqueFileResource(filename);
2100   (void) CloseBlob(image);
2101   return(status);
2102 }
2103 #endif
2104 \f
2105 #if defined(MAGICKCORE_TIFF_DELEGATE)
2106 /*
2107 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2108 %                                                                             %
2109 %                                                                             %
2110 %                                                                             %
2111 %   W r i t e P T I F I m a g e                                               %
2112 %                                                                             %
2113 %                                                                             %
2114 %                                                                             %
2115 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2116 %
2117 %  WritePTIFImage() writes an image in the pyrimid-encoded Tagged image file
2118 %  format.
2119 %
2120 %  The format of the WritePTIFImage method is:
2121 %
2122 %      MagickBooleanType WritePTIFImage(const ImageInfo *image_info,
2123 %        Image *image,ExceptionInfo *exception)
2124 %
2125 %  A description of each parameter follows:
2126 %
2127 %    o image_info: the image info.
2128 %
2129 %    o image:  The image.
2130 %
2131 %    o exception: return any errors or warnings in this structure.
2132 %
2133 */
2134 static MagickBooleanType WritePTIFImage(const ImageInfo *image_info,
2135   Image *image,ExceptionInfo *exception)
2136 {
2137   Image
2138     *images,
2139     *next,
2140     *pyramid_image;
2141
2142   ImageInfo
2143     *write_info;
2144
2145   MagickBooleanType
2146     status;
2147
2148   PointInfo
2149     resolution;
2150
2151   size_t
2152     columns,
2153     rows;
2154
2155   /*
2156     Create pyramid-encoded TIFF image.
2157   */
2158   images=NewImageList();
2159   for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
2160   {
2161     AppendImageToList(&images,CloneImage(next,0,0,MagickFalse,exception));
2162     columns=next->columns;
2163     rows=next->rows;
2164     resolution=next->resolution;
2165     while ((columns > 64) && (rows > 64))
2166     {
2167       columns/=2;
2168       rows/=2;
2169       resolution.x/=2;
2170       resolution.y/=2;
2171       pyramid_image=ResizeImage(next,columns,rows,image->filter,image->blur,
2172         exception);
2173       if (pyramid_image == (Image *) NULL)
2174         break;
2175       pyramid_image->resolution=resolution;
2176       AppendImageToList(&images,pyramid_image);
2177     }
2178   }
2179   images=GetFirstImageInList(images);
2180   /*
2181     Write pyramid-encoded TIFF image.
2182   */
2183   write_info=CloneImageInfo(image_info);
2184   write_info->adjoin=MagickTrue;
2185   (void) CopyMagickString(write_info->magick,"TIFF",MaxTextExtent);
2186   (void) CopyMagickString(images->magick,"TIFF",MaxTextExtent);
2187   status=WriteTIFFImage(write_info,images,exception);
2188   images=DestroyImageList(images);
2189   write_info=DestroyImageInfo(write_info);
2190   return(status);
2191 }
2192 #endif
2193 \f
2194 #if defined(MAGICKCORE_TIFF_DELEGATE)
2195 /*
2196 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2197 %                                                                             %
2198 %                                                                             %
2199 %   W r i t e T I F F I m a g e                                               %
2200 %                                                                             %
2201 %                                                                             %
2202 %                                                                             %
2203 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2204 %
2205 %  WriteTIFFImage() writes an image in the Tagged image file format.
2206 %
2207 %  The format of the WriteTIFFImage method is:
2208 %
2209 %      MagickBooleanType WriteTIFFImage(const ImageInfo *image_info,
2210 %        Image *image,ExceptionInfo *exception)
2211 %
2212 %  A description of each parameter follows:
2213 %
2214 %    o image_info: the image info.
2215 %
2216 %    o image:  The image.
2217 %
2218 %    o exception: return any errors or warnings in this structure.
2219 %
2220 */
2221
2222 typedef struct _TIFFInfo
2223 {
2224   RectangleInfo
2225     tile_geometry;
2226
2227   unsigned char
2228     *scanline,
2229     *scanlines,
2230     *pixels;
2231 } TIFFInfo;
2232
2233 static void DestroyTIFFInfo(TIFFInfo *tiff_info)
2234 {
2235   assert(tiff_info != (TIFFInfo *) NULL);
2236   if (tiff_info->scanlines != (unsigned char *) NULL)
2237     tiff_info->scanlines=(unsigned char *) RelinquishMagickMemory(
2238       tiff_info->scanlines);
2239   if (tiff_info->pixels != (unsigned char *) NULL)
2240     tiff_info->pixels=(unsigned char *) RelinquishMagickMemory(
2241       tiff_info->pixels);
2242 }
2243
2244 static MagickBooleanType GetTIFFInfo(const ImageInfo *image_info,TIFF *tiff,
2245   TIFFInfo *tiff_info)
2246 {
2247   const char
2248     *option;
2249
2250   MagickStatusType
2251     flags;
2252
2253   uint32
2254     tile_columns,
2255     tile_rows;
2256
2257   assert(tiff_info != (TIFFInfo *) NULL);
2258   (void) ResetMagickMemory(tiff_info,0,sizeof(*tiff_info));
2259   option=GetImageOption(image_info,"tiff:tile-geometry");
2260   if (option == (const char *) NULL)
2261     return(MagickTrue);
2262   flags=ParseAbsoluteGeometry(option,&tiff_info->tile_geometry);
2263   if ((flags & HeightValue) == 0)
2264     tiff_info->tile_geometry.height=tiff_info->tile_geometry.width;
2265   tile_columns=(uint32) tiff_info->tile_geometry.width;
2266   tile_rows=(uint32) tiff_info->tile_geometry.height;
2267   TIFFDefaultTileSize(tiff,&tile_columns,&tile_rows);
2268   (void) TIFFSetField(tiff,TIFFTAG_TILEWIDTH,tile_columns);
2269   (void) TIFFSetField(tiff,TIFFTAG_TILELENGTH,tile_rows);
2270   tiff_info->tile_geometry.width=tile_columns;
2271   tiff_info->tile_geometry.height=tile_rows;
2272   tiff_info->scanlines=(unsigned char *) AcquireQuantumMemory((size_t)
2273     tile_rows*TIFFScanlineSize(tiff),sizeof(*tiff_info->scanlines));
2274   tiff_info->pixels=(unsigned char *) AcquireQuantumMemory((size_t)
2275     tile_rows*TIFFTileSize(tiff),sizeof(*tiff_info->scanlines));
2276   if ((tiff_info->scanlines == (unsigned char *) NULL) ||
2277       (tiff_info->pixels == (unsigned char *) NULL))
2278     {
2279       DestroyTIFFInfo(tiff_info);
2280       return(MagickFalse);
2281     }
2282   return(MagickTrue);
2283 }
2284
2285 static int32 TIFFWritePixels(TIFF *tiff,TIFFInfo *tiff_info,ssize_t row,
2286   tsample_t sample,Image *image)
2287 {
2288   int32
2289     status;
2290
2291   register ssize_t
2292     i;
2293
2294   register unsigned char
2295     *p,
2296     *q;
2297
2298   size_t
2299     number_tiles,
2300     tile_width;
2301
2302   ssize_t
2303     bytes_per_pixel,
2304     j,
2305     k,
2306     l;
2307
2308   if (TIFFIsTiled(tiff) == 0)
2309     return(TIFFWriteScanline(tiff,tiff_info->scanline,(uint32) row,sample));
2310   /*
2311     Fill scanlines to tile height.
2312   */
2313   i=(ssize_t) (row % tiff_info->tile_geometry.height)*TIFFScanlineSize(tiff);
2314   (void) CopyMagickMemory(tiff_info->scanlines+i,(char *) tiff_info->scanline,
2315     (size_t) TIFFScanlineSize(tiff));
2316   if (((size_t) (row % tiff_info->tile_geometry.height) !=
2317       (tiff_info->tile_geometry.height-1)) &&
2318       (row != (ssize_t) (image->rows-1)))
2319     return(0);
2320   /*
2321     Write tile to TIFF image.
2322   */
2323   status=0;
2324   bytes_per_pixel=TIFFTileSize(tiff)/(ssize_t) (
2325     tiff_info->tile_geometry.height*tiff_info->tile_geometry.width);
2326   number_tiles=(image->columns+tiff_info->tile_geometry.width)/
2327     tiff_info->tile_geometry.width;
2328   for (i=0; i < (ssize_t) number_tiles; i++)
2329   {
2330     tile_width=(i == (ssize_t) (number_tiles-1)) ? image->columns-(i*
2331       tiff_info->tile_geometry.width) : tiff_info->tile_geometry.width;
2332     for (j=0; j < (ssize_t) ((row % tiff_info->tile_geometry.height)+1); j++)
2333       for (k=0; k < (ssize_t) tile_width; k++)
2334       {
2335         if (bytes_per_pixel == 0)
2336           {
2337             p=tiff_info->scanlines+(j*TIFFScanlineSize(tiff)+(i*
2338               tiff_info->tile_geometry.width+k)/8);
2339             q=tiff_info->pixels+(j*TIFFTileRowSize(tiff)+k/8);
2340             *q++=(*p++);
2341             continue;
2342           }
2343         p=tiff_info->scanlines+(j*TIFFScanlineSize(tiff)+(i*
2344           tiff_info->tile_geometry.width+k)*bytes_per_pixel);
2345         q=tiff_info->pixels+(j*TIFFTileRowSize(tiff)+k*bytes_per_pixel);
2346         for (l=0; l < bytes_per_pixel; l++)
2347           *q++=(*p++);
2348       }
2349     if ((i*tiff_info->tile_geometry.width) != image->columns)
2350       status=TIFFWriteTile(tiff,tiff_info->pixels,(uint32) (i*
2351         tiff_info->tile_geometry.width),(uint32) ((row/
2352         tiff_info->tile_geometry.height)*tiff_info->tile_geometry.height),0,
2353         sample);
2354     if (status < 0)
2355       break;
2356   }
2357   return(status);
2358 }
2359
2360 static void TIFFSetProfiles(TIFF *tiff,Image *image)
2361 {
2362   const char
2363     *name;
2364
2365   const StringInfo
2366     *profile;
2367
2368   if (image->profiles == (void *) NULL)
2369     return;
2370   ResetImageProfileIterator(image);
2371   for (name=GetNextImageProfile(image); name != (const char *) NULL; )
2372   {
2373     profile=GetImageProfile(image,name);
2374 #if defined(TIFFTAG_XMLPACKET)
2375     if (LocaleCompare(name,"xmp") == 0)
2376       (void) TIFFSetField(tiff,TIFFTAG_XMLPACKET,(uint32) GetStringInfoLength(
2377         profile),GetStringInfoDatum(profile));
2378 #endif
2379 #if defined(TIFFTAG_ICCPROFILE)
2380     if (LocaleCompare(name,"icc") == 0)
2381       (void) TIFFSetField(tiff,TIFFTAG_ICCPROFILE,(uint32) GetStringInfoLength(
2382         profile),GetStringInfoDatum(profile));
2383 #endif
2384     if (LocaleCompare(name,"iptc") == 0)
2385       {
2386         size_t
2387           length;
2388
2389         StringInfo
2390           *iptc_profile;
2391
2392         iptc_profile=CloneStringInfo(profile);
2393         length=GetStringInfoLength(profile)+4-(GetStringInfoLength(profile) &
2394           0x03);
2395         SetStringInfoLength(iptc_profile,length);
2396         if (TIFFIsByteSwapped(tiff))
2397           TIFFSwabArrayOfLong((uint32 *) GetStringInfoDatum(iptc_profile),
2398             (unsigned long) (length/4));
2399         (void) TIFFSetField(tiff,TIFFTAG_RICHTIFFIPTC,(uint32)
2400           GetStringInfoLength(iptc_profile)/4,GetStringInfoDatum(iptc_profile));
2401         iptc_profile=DestroyStringInfo(iptc_profile);
2402       }
2403 #if defined(TIFFTAG_PHOTOSHOP)
2404     if (LocaleCompare(name,"8bim") == 0)
2405       (void) TIFFSetField(tiff,TIFFTAG_PHOTOSHOP,(uint32)
2406         GetStringInfoLength(profile),GetStringInfoDatum(profile));
2407 #endif
2408     if (LocaleCompare(name,"tiff:37724") == 0)
2409       (void) TIFFSetField(tiff,37724,(uint32) GetStringInfoLength(profile),
2410         GetStringInfoDatum(profile));
2411     name=GetNextImageProfile(image);
2412   }
2413 }
2414
2415 static void TIFFSetProperties(TIFF *tiff,Image *image,ExceptionInfo *exception)
2416 {
2417   const char
2418     *value;
2419
2420   (void) TIFFSetField(tiff,TIFFTAG_DOCUMENTNAME,image->filename);
2421   value=GetImageProperty(image,"tiff:hostcomputer",exception);
2422   if (value != (const char *) NULL)
2423     (void) TIFFSetField(tiff,TIFFTAG_HOSTCOMPUTER,value);
2424   value=GetImageProperty(image,"tiff:artist",exception);
2425   if (value != (const char *) NULL)
2426     (void) TIFFSetField(tiff,TIFFTAG_ARTIST,value);
2427   value=GetImageProperty(image,"tiff:timestamp",exception);
2428   if (value != (const char *) NULL)
2429     (void) TIFFSetField(tiff,TIFFTAG_DATETIME,value);
2430   value=GetImageProperty(image,"tiff:make",exception);
2431   if (value != (const char *) NULL)
2432     (void) TIFFSetField(tiff,TIFFTAG_MAKE,value);
2433   value=GetImageProperty(image,"tiff:model",exception);
2434   if (value != (const char *) NULL)
2435     (void) TIFFSetField(tiff,TIFFTAG_MODEL,value);
2436   value=GetImageProperty(image,"tiff:software",exception);
2437   if (value != (const char *) NULL)
2438     (void) TIFFSetField(tiff,TIFFTAG_SOFTWARE,value);
2439   value=GetImageProperty(image,"tiff:copyright",exception);
2440   if (value != (const char *) NULL)
2441     (void) TIFFSetField(tiff,TIFFTAG_COPYRIGHT,value);
2442   value=GetImageProperty(image,"kodak-33423",exception);
2443   if (value != (const char *) NULL)
2444     (void) TIFFSetField(tiff,33423,value);
2445   value=GetImageProperty(image,"kodak-36867",exception);
2446   if (value != (const char *) NULL)
2447     (void) TIFFSetField(tiff,36867,value);
2448   value=GetImageProperty(image,"label",exception);
2449   if (value != (const char *) NULL)
2450     (void) TIFFSetField(tiff,TIFFTAG_PAGENAME,value);
2451   value=GetImageProperty(image,"comment",exception);
2452   if (value != (const char *) NULL)
2453     (void) TIFFSetField(tiff,TIFFTAG_IMAGEDESCRIPTION,value);
2454 }
2455
2456 static void TIFFSetEXIFProperties(TIFF *tiff,Image *image,
2457   ExceptionInfo *exception)
2458 {
2459 #if defined(MAGICKCORE_HAVE_TIFFREADEXIFDIRECTORY)
2460   const char
2461     *value;
2462
2463   register ssize_t
2464     i;
2465
2466   uint32
2467     offset;
2468
2469   /*
2470     Write EXIF properties.
2471   */
2472   offset=0;
2473   (void) TIFFSetField(tiff,TIFFTAG_SUBIFD,1,&offset);
2474   for (i=0; exif_info[i].tag != 0; i++)
2475   {
2476     value=GetImageProperty(image,exif_info[i].property,exception);
2477     if (value == (const char *) NULL)
2478       continue;
2479     switch (exif_info[i].type)
2480     {
2481       case TIFF_ASCII:
2482       {
2483         (void) TIFFSetField(tiff,exif_info[i].tag,value);
2484         break;
2485       }
2486       case TIFF_SHORT:
2487       {
2488         uint16
2489           shorty;
2490
2491         shorty=(uint16) StringToLong(value);
2492         (void) TIFFSetField(tiff,exif_info[i].tag,shorty);
2493         break;
2494       }
2495       case TIFF_LONG:
2496       {
2497         uint16
2498           ssize_ty;
2499
2500         ssize_ty=(uint16) StringToLong(value);
2501         (void) TIFFSetField(tiff,exif_info[i].tag,ssize_ty);
2502         break;
2503       }
2504       case TIFF_RATIONAL:
2505       case TIFF_SRATIONAL:
2506       {
2507         float
2508           rational;
2509
2510         rational=StringToDouble(value,(char **) NULL);
2511         (void) TIFFSetField(tiff,exif_info[i].tag,rational);
2512         break;
2513       }
2514       default:
2515         break;
2516     }
2517   }
2518   /* (void) TIFFSetField(tiff,TIFFTAG_EXIFIFD,offset); */
2519 #else
2520   (void) tiff;
2521   (void) image;
2522 #endif
2523 }
2524
2525 static MagickBooleanType WriteTIFFImage(const ImageInfo *image_info,
2526   Image *image,ExceptionInfo *exception)
2527 {
2528 #if !defined(TIFFDefaultStripSize)
2529 #define TIFFDefaultStripSize(tiff,request)  (8192UL/TIFFScanlineSize(tiff))
2530 #endif
2531
2532   const char
2533     *mode,
2534     *option;
2535
2536   CompressionType
2537     compression;
2538
2539   EndianType
2540     endian_type;
2541
2542   MagickBooleanType
2543     debug,
2544     status;
2545
2546   MagickOffsetType
2547     scene;
2548
2549   QuantumInfo
2550     *quantum_info;
2551
2552   QuantumType
2553     quantum_type;
2554
2555   register ssize_t
2556     i;
2557
2558   size_t
2559     length;
2560
2561   ssize_t
2562     y;
2563
2564   TIFF
2565     *tiff;
2566
2567   TIFFErrorHandler
2568     error_handler,
2569     warning_handler;
2570
2571   TIFFInfo
2572     tiff_info;
2573
2574   uint16
2575     bits_per_sample,
2576     compress_tag,
2577     endian,
2578     photometric;
2579
2580   uint32
2581     rows_per_strip;
2582
2583   unsigned char
2584     *pixels;
2585
2586   /*
2587     Open TIFF file.
2588   */
2589   assert(image_info != (const ImageInfo *) NULL);
2590   assert(image_info->signature == MagickSignature);
2591   assert(image != (Image *) NULL);
2592   assert(image->signature == MagickSignature);
2593   if (image->debug != MagickFalse)
2594     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2595   assert(exception != (ExceptionInfo *) NULL);
2596   assert(exception->signature == MagickSignature);
2597   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2598   if (status == MagickFalse)
2599     return(status);
2600   (void) MagickSetThreadValue(tiff_exception,exception);
2601   error_handler=TIFFSetErrorHandler((TIFFErrorHandler) TIFFErrors);
2602   warning_handler=TIFFSetWarningHandler((TIFFErrorHandler) TIFFWarnings);
2603   endian_type=UndefinedEndian;
2604   option=GetImageArtifact(image,"tiff:endian");
2605   if (option != (const char *) NULL)
2606     {
2607       if (LocaleNCompare(option,"msb",3) == 0)
2608         endian_type=MSBEndian;
2609       if (LocaleNCompare(option,"lsb",3) == 0)
2610         endian_type=LSBEndian;;
2611     }
2612   switch (endian_type)
2613   {
2614     case LSBEndian: mode="wl"; break;
2615     case MSBEndian: mode="wb"; break;
2616     default: mode="w"; break;
2617   }
2618 #if defined(TIFF_VERSION_BIG)
2619   if (LocaleCompare(image_info->magick,"TIFF64") == 0)
2620     switch (endian_type)
2621     {
2622       case LSBEndian: mode="wl8"; break;
2623       case MSBEndian: mode="wb8"; break;
2624       default: mode="w8"; break;
2625     }
2626 #endif
2627   tiff=TIFFClientOpen(image->filename,mode,(thandle_t) image,TIFFReadBlob,
2628     TIFFWriteBlob,TIFFSeekBlob,TIFFCloseBlob,TIFFGetBlobSize,TIFFMapBlob,
2629     TIFFUnmapBlob);
2630   if (tiff == (TIFF *) NULL)
2631     {
2632       (void) TIFFSetWarningHandler(warning_handler);
2633       (void) TIFFSetErrorHandler(error_handler);
2634       return(MagickFalse);
2635     }
2636   scene=0;
2637   debug=IsEventLogging();
2638   (void) debug;
2639   do
2640   {
2641     /*
2642       Initialize TIFF fields.
2643     */
2644     if ((image_info->type != UndefinedType) &&
2645         (image_info->type != OptimizeType))
2646       (void) SetImageType(image,image_info->type,exception);
2647     quantum_info=AcquireQuantumInfo(image_info,image);
2648     if (quantum_info == (QuantumInfo *) NULL)
2649       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2650     if ((image->storage_class != PseudoClass) && (image->depth >= 32) &&
2651         (quantum_info->format == UndefinedQuantumFormat) &&
2652         (IsHighDynamicRangeImage(image,exception) != MagickFalse))
2653       {
2654         status=SetQuantumFormat(image,quantum_info,FloatingPointQuantumFormat);
2655         if (status == MagickFalse)
2656           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2657       }
2658     if ((LocaleCompare(image_info->magick,"PTIF") == 0) &&
2659         (GetPreviousImageInList(image) != (Image *) NULL))
2660       (void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_REDUCEDIMAGE);
2661     if ((image->columns != (uint32) image->columns) ||
2662         (image->rows != (uint32) image->rows))
2663       ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
2664     (void) TIFFSetField(tiff,TIFFTAG_IMAGELENGTH,(uint32) image->rows);
2665     (void) TIFFSetField(tiff,TIFFTAG_IMAGEWIDTH,(uint32) image->columns);
2666     compression=image->compression;
2667     if (image_info->compression != UndefinedCompression)
2668       compression=image_info->compression;
2669     switch (compression)
2670     {
2671       case FaxCompression:
2672       {
2673         compress_tag=COMPRESSION_CCITTFAX3;
2674         SetQuantumMinIsWhite(quantum_info,MagickTrue);
2675         break;
2676       }
2677       case Group4Compression:
2678       {
2679         compress_tag=COMPRESSION_CCITTFAX4;
2680         SetQuantumMinIsWhite(quantum_info,MagickTrue);
2681         break;
2682       }
2683 #if defined(COMPRESSION_JBIG)
2684       case JBIG1Compression:
2685       {
2686         compress_tag=COMPRESSION_JBIG;
2687         break;
2688       }
2689 #endif
2690       case JPEGCompression:
2691       {
2692         compress_tag=COMPRESSION_JPEG;
2693         break;
2694       }
2695 #if defined(COMPRESSION_LZMA)
2696       case LZMACompression:
2697       {
2698         compress_tag=COMPRESSION_LZMA;
2699         break;
2700       }
2701 #endif
2702       case LZWCompression:
2703       {
2704         compress_tag=COMPRESSION_LZW;
2705         break;
2706       }
2707       case RLECompression:
2708       {
2709         compress_tag=COMPRESSION_PACKBITS;
2710         break;
2711       }
2712       case ZipCompression:
2713       {
2714         compress_tag=COMPRESSION_ADOBE_DEFLATE;
2715         break;
2716       }
2717       case NoCompression:
2718       default:
2719       {
2720         compress_tag=COMPRESSION_NONE;
2721         break;
2722       }
2723     }
2724 #if defined(MAGICKCORE_HAVE_TIFFISCODECCONFIGURED) || (TIFFLIB_VERSION > 20040919)
2725     if ((compress_tag != COMPRESSION_NONE) &&
2726         (TIFFIsCODECConfigured(compress_tag) == 0))
2727       {
2728         (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
2729           "CompressionNotSupported","`%s'",CommandOptionToMnemonic(
2730           MagickCompressOptions,(ssize_t) compression));
2731         compress_tag=COMPRESSION_NONE;
2732         compression=NoCompression;
2733       }
2734 #else
2735       switch (compress_tag)
2736       {
2737 #if defined(CCITT_SUPPORT)
2738         case COMPRESSION_CCITTFAX3:
2739         case COMPRESSION_CCITTFAX4:
2740 #endif
2741 #if defined(YCBCR_SUPPORT) && defined(JPEG_SUPPORT)
2742         case COMPRESSION_JPEG:
2743 #endif
2744 #if defined(LZMA_SUPPORT) && defined(COMPRESSION_LZMA)
2745         case COMPRESSION_LZMA:
2746 #endif
2747 #if defined(LZW_SUPPORT)
2748         case COMPRESSION_LZW:
2749 #endif
2750 #if defined(PACKBITS_SUPPORT)
2751         case COMPRESSION_PACKBITS:
2752 #endif
2753 #if defined(ZIP_SUPPORT)
2754         case COMPRESSION_ADOBE_DEFLATE:
2755 #endif
2756         case COMPRESSION_NONE:
2757           break;
2758         default:
2759         {
2760           (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
2761             "CompressionNotSupported","`%s'",CommandOptionToMnemonic(
2762               MagickCompressOptions,(ssize_t) compression));
2763           compress_tag=COMPRESSION_NONE;
2764           compression=NoCompression;
2765           break;
2766         }
2767       }
2768 #endif
2769     switch (compression)
2770     {
2771       case FaxCompression:
2772       case Group4Compression:
2773       {
2774         (void) SetImageType(image,BilevelType,exception);
2775         break;
2776       }
2777       case JPEGCompression:
2778       {
2779         (void) SetImageStorageClass(image,DirectClass,exception);
2780         (void) SetImageDepth(image,8,exception);
2781         break;
2782       }
2783       default:
2784         break;
2785     }
2786     if (image->colorspace == CMYKColorspace)
2787       {
2788         photometric=PHOTOMETRIC_SEPARATED;
2789         (void) TIFFSetField(tiff,TIFFTAG_SAMPLESPERPIXEL,4);
2790         (void) TIFFSetField(tiff,TIFFTAG_INKSET,INKSET_CMYK);
2791       }
2792     else
2793       {
2794         /*
2795           Full color TIFF raster.
2796         */
2797         if (image->colorspace == LabColorspace)
2798           photometric=PHOTOMETRIC_CIELAB;
2799         else
2800           if (image->colorspace == YCbCrColorspace)
2801             {
2802               photometric=PHOTOMETRIC_YCBCR;
2803               (void) TIFFSetField(tiff,TIFFTAG_YCBCRSUBSAMPLING,1,1);
2804               (void) SetImageStorageClass(image,DirectClass,exception);
2805               (void) SetImageDepth(image,8,exception);
2806             }
2807           else
2808             {
2809               if (IsRGBColorspace(image->colorspace) == MagickFalse)
2810                 (void) TransformImageColorspace(image,sRGBColorspace,exception);
2811               photometric=PHOTOMETRIC_RGB;
2812             }
2813         (void) TIFFSetField(tiff,TIFFTAG_SAMPLESPERPIXEL,3);
2814         if ((image_info->type != TrueColorType) &&
2815             (image_info->type != TrueColorMatteType))
2816           {
2817             if ((image_info->type != PaletteType) &&
2818                 (IsImageGray(image,exception) != MagickFalse))
2819               {
2820                 photometric=(uint16) (quantum_info->min_is_white !=
2821                   MagickFalse ? PHOTOMETRIC_MINISWHITE :
2822                   PHOTOMETRIC_MINISBLACK);
2823                 (void) TIFFSetField(tiff,TIFFTAG_SAMPLESPERPIXEL,1);
2824                 if ((image_info->depth == 0) && (image->matte == MagickFalse) &&
2825                     (IsImageMonochrome(image,exception) != MagickFalse))
2826                   {
2827                     status=SetQuantumDepth(image,quantum_info,1);
2828                     if (status == MagickFalse)
2829                       ThrowWriterException(ResourceLimitError,
2830                         "MemoryAllocationFailed");
2831                   }
2832               }
2833             else
2834               if (image->storage_class == PseudoClass)
2835                 {
2836                   size_t
2837                     depth;
2838
2839                   /*
2840                     Colormapped TIFF raster.
2841                   */
2842                   (void) TIFFSetField(tiff,TIFFTAG_SAMPLESPERPIXEL,1);
2843                   photometric=PHOTOMETRIC_PALETTE;
2844                   depth=1;
2845                   while ((GetQuantumRange(depth)+1) < image->colors)
2846                     depth<<=1;
2847                   status=SetQuantumDepth(image,quantum_info,depth);
2848                   if (status == MagickFalse)
2849                     ThrowWriterException(ResourceLimitError,
2850                       "MemoryAllocationFailed");
2851                 }
2852           }
2853       }
2854     switch (image->endian)
2855     {
2856       case LSBEndian:
2857       {
2858         endian=FILLORDER_LSB2MSB;
2859         break;
2860       }
2861       case MSBEndian:
2862       {
2863         endian=FILLORDER_MSB2LSB;
2864         break;
2865       }
2866       case UndefinedEndian:
2867       default:
2868       {
2869         (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_FILLORDER,&endian);
2870         break;
2871       }
2872     }
2873     if ((compress_tag == COMPRESSION_CCITTFAX3) &&
2874         (photometric != PHOTOMETRIC_MINISWHITE))
2875       {
2876         compress_tag=COMPRESSION_NONE;
2877         endian=FILLORDER_MSB2LSB;
2878       }
2879     else
2880       if ((compress_tag == COMPRESSION_CCITTFAX4) &&
2881          (photometric != PHOTOMETRIC_MINISWHITE))
2882        {
2883          compress_tag=COMPRESSION_NONE;
2884          endian=FILLORDER_MSB2LSB;
2885        }
2886     option=GetImageArtifact(image,"tiff:fill-order");
2887     if (option != (const char *) NULL)
2888       {
2889         if (LocaleNCompare(option,"msb",3) == 0)
2890           endian=FILLORDER_MSB2LSB;
2891         if (LocaleNCompare(option,"lsb",3) == 0)
2892           endian=FILLORDER_LSB2MSB;
2893       }
2894     (void) TIFFSetField(tiff,TIFFTAG_COMPRESSION,compress_tag);
2895     (void) TIFFSetField(tiff,TIFFTAG_FILLORDER,endian);
2896     (void) TIFFSetField(tiff,TIFFTAG_BITSPERSAMPLE,quantum_info->depth);
2897     if (image->matte != MagickFalse)
2898       {
2899         uint16
2900           extra_samples,
2901           sample_info[1],
2902           samples_per_pixel;
2903
2904         /*
2905           TIFF has a matte channel.
2906         */
2907         extra_samples=1;
2908         sample_info[0]=EXTRASAMPLE_UNASSALPHA;
2909         option=GetImageArtifact(image,"tiff:alpha");
2910         if ((option != (const char *) NULL) &&
2911             (LocaleCompare(option,"associated") == 0))
2912           sample_info[0]=EXTRASAMPLE_ASSOCALPHA;
2913         (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_SAMPLESPERPIXEL,
2914           &samples_per_pixel);
2915         (void) TIFFSetField(tiff,TIFFTAG_SAMPLESPERPIXEL,samples_per_pixel+1);
2916         (void) TIFFSetField(tiff,TIFFTAG_EXTRASAMPLES,extra_samples,
2917           &sample_info);
2918         if (sample_info[0] == EXTRASAMPLE_ASSOCALPHA)
2919           SetQuantumAlphaType(quantum_info,AssociatedQuantumAlpha);
2920       }
2921     (void) TIFFSetField(tiff,TIFFTAG_PHOTOMETRIC,photometric);
2922     switch (quantum_info->format)
2923     {
2924       case FloatingPointQuantumFormat:
2925       {
2926         (void) TIFFSetField(tiff,TIFFTAG_SAMPLEFORMAT,SAMPLEFORMAT_IEEEFP);
2927         (void) TIFFSetField(tiff,TIFFTAG_SMINSAMPLEVALUE,quantum_info->minimum);
2928         (void) TIFFSetField(tiff,TIFFTAG_SMAXSAMPLEVALUE,quantum_info->maximum);
2929         break;
2930       }
2931       case SignedQuantumFormat:
2932       {
2933         (void) TIFFSetField(tiff,TIFFTAG_SAMPLEFORMAT,SAMPLEFORMAT_INT);
2934         break;
2935       }
2936       case UnsignedQuantumFormat:
2937       {
2938         (void) TIFFSetField(tiff,TIFFTAG_SAMPLEFORMAT,SAMPLEFORMAT_UINT);
2939         break;
2940       }
2941       default:
2942         break;
2943     }
2944     (void) TIFFSetField(tiff,TIFFTAG_ORIENTATION,ORIENTATION_TOPLEFT);
2945     (void) TIFFSetField(tiff,TIFFTAG_PLANARCONFIG,PLANARCONFIG_CONTIG);
2946     if (photometric == PHOTOMETRIC_RGB)
2947       if ((image_info->interlace == PlaneInterlace) ||
2948           (image_info->interlace == PartitionInterlace))
2949         (void) TIFFSetField(tiff,TIFFTAG_PLANARCONFIG,PLANARCONFIG_SEPARATE);
2950     rows_per_strip=1;
2951     if (TIFFScanlineSize(tiff) != 0)
2952       rows_per_strip=(uint32) MagickMax((size_t) TIFFDefaultStripSize(tiff,0),
2953         1);
2954     option=GetImageArtifact(image,"tiff:rows-per-strip");
2955     if (option != (const char *) NULL)
2956       rows_per_strip=(size_t) strtol(option,(char **) NULL,10);
2957     switch (compress_tag)
2958     {
2959       case COMPRESSION_JPEG:
2960       {
2961 #if defined(JPEG_SUPPORT)
2962         const char
2963           *sampling_factor;
2964
2965         GeometryInfo
2966           geometry_info;
2967
2968         MagickStatusType
2969           flags;
2970
2971         rows_per_strip+=(16-(rows_per_strip % 16));
2972         if (image->quality != 0)
2973           (void) TIFFSetField(tiff,TIFFTAG_JPEGQUALITY,image->quality);
2974         if (image_info->quality != UndefinedCompressionQuality)
2975           (void) TIFFSetField(tiff,TIFFTAG_JPEGQUALITY,image_info->quality);
2976         (void) TIFFSetField(tiff,TIFFTAG_JPEGCOLORMODE,JPEGCOLORMODE_RAW);
2977         if (IsRGBColorspace(image->colorspace) == MagickTrue)
2978           {
2979             const char
2980               *value;
2981
2982             (void) TIFFSetField(tiff,TIFFTAG_JPEGCOLORMODE,JPEGCOLORMODE_RGB);
2983             sampling_factor=(const char *) NULL;
2984             value=GetImageProperty(image,"jpeg:sampling-factor",exception);
2985             if (value != (char *) NULL)
2986               {
2987                 sampling_factor=value;
2988                 if (image->debug != MagickFalse)
2989                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2990                     "  Input sampling-factors=%s",sampling_factor);
2991               }
2992             if (image_info->sampling_factor != (char *) NULL)
2993               sampling_factor=image_info->sampling_factor;
2994             if (sampling_factor != (const char *) NULL)
2995               {
2996                 flags=ParseGeometry(sampling_factor,&geometry_info);
2997                 if ((flags & SigmaValue) == 0)
2998                   geometry_info.sigma=geometry_info.rho;
2999                 if (image->colorspace == YCbCrColorspace)
3000                   (void) TIFFSetField(tiff,TIFFTAG_YCBCRSUBSAMPLING,(uint16)
3001                     geometry_info.rho,(uint16) geometry_info.sigma);
3002               }
3003           }
3004         if (bits_per_sample == 12)
3005           (void) TIFFSetField(tiff,TIFFTAG_JPEGTABLESMODE,JPEGTABLESMODE_QUANT);
3006 #endif
3007         break;
3008       }
3009       case COMPRESSION_ADOBE_DEFLATE:
3010       {
3011         rows_per_strip=(uint32) image->rows;
3012         (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_BITSPERSAMPLE,
3013           &bits_per_sample);
3014         if (((photometric == PHOTOMETRIC_RGB) ||
3015              (photometric == PHOTOMETRIC_MINISBLACK)) &&
3016             ((bits_per_sample == 8) || (bits_per_sample == 16)))
3017           (void) TIFFSetField(tiff,TIFFTAG_PREDICTOR,PREDICTOR_HORIZONTAL);
3018         (void) TIFFSetField(tiff,TIFFTAG_ZIPQUALITY,(long) (
3019           image_info->quality == UndefinedCompressionQuality ? 7 :
3020           MagickMin((ssize_t) image_info->quality/10,9)));
3021         break;
3022       }
3023       case COMPRESSION_CCITTFAX3:
3024       {
3025         /*
3026           Byte-aligned EOL.
3027         */
3028         rows_per_strip=(uint32) image->rows;
3029         (void) TIFFSetField(tiff,TIFFTAG_GROUP3OPTIONS,4);
3030         break;
3031       }
3032       case COMPRESSION_CCITTFAX4:
3033       {
3034         rows_per_strip=(uint32) image->rows;
3035         break;
3036       }
3037 #if defined(LZMA_SUPPORT) && defined(COMPRESSION_LZMA)
3038       case COMPRESSION_LZMA:
3039       {
3040         if (((photometric == PHOTOMETRIC_RGB) ||
3041              (photometric == PHOTOMETRIC_MINISBLACK)) &&
3042             ((bits_per_sample == 8) || (bits_per_sample == 16)))
3043           (void) TIFFSetField(tiff,TIFFTAG_PREDICTOR,PREDICTOR_HORIZONTAL);
3044         (void) TIFFSetField(tiff,TIFFTAG_LZMAPRESET,(long) (
3045           image_info->quality == UndefinedCompressionQuality ? 7 :
3046           MagickMin((ssize_t) image_info->quality/10,9)));
3047         break;
3048       }
3049 #endif
3050       case COMPRESSION_LZW:
3051       {
3052         (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_BITSPERSAMPLE,
3053           &bits_per_sample);
3054         if (((photometric == PHOTOMETRIC_RGB) ||
3055              (photometric == PHOTOMETRIC_MINISBLACK)) &&
3056             ((bits_per_sample == 8) || (bits_per_sample == 16)))
3057           (void) TIFFSetField(tiff,TIFFTAG_PREDICTOR,PREDICTOR_HORIZONTAL);
3058         break;
3059       }
3060       default:
3061         break;
3062     }
3063     option=GetImageArtifact(image,"tiff:rows-per-strip");
3064     if (option == (const char *) NULL)
3065       (void) TIFFSetField(tiff,TIFFTAG_ROWSPERSTRIP,rows_per_strip);
3066     if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
3067       {
3068         unsigned short
3069           units;
3070
3071         /*
3072           Set image resolution.
3073         */
3074         units=RESUNIT_NONE;
3075         if (image->units == PixelsPerInchResolution)
3076           units=RESUNIT_INCH;
3077         if (image->units == PixelsPerCentimeterResolution)
3078           units=RESUNIT_CENTIMETER;
3079         (void) TIFFSetField(tiff,TIFFTAG_RESOLUTIONUNIT,(uint16) units);
3080         (void) TIFFSetField(tiff,TIFFTAG_XRESOLUTION,image->resolution.x);
3081         (void) TIFFSetField(tiff,TIFFTAG_YRESOLUTION,image->resolution.y);
3082         if ((image->page.x != 0) || (image->page.y != 0))
3083           {
3084             /*
3085               Set image position.
3086             */
3087             (void) TIFFSetField(tiff,TIFFTAG_XPOSITION,(float) image->page.x/
3088               image->resolution.x);
3089             (void) TIFFSetField(tiff,TIFFTAG_YPOSITION,(float) image->page.y/
3090               image->resolution.y);
3091           }
3092       }
3093     if (image->chromaticity.white_point.x != 0.0)
3094       {
3095         float
3096           chromaticity[6];
3097
3098         /*
3099           Set image chromaticity.
3100         */
3101         chromaticity[0]=(float) image->chromaticity.red_primary.x;
3102         chromaticity[1]=(float) image->chromaticity.red_primary.y;
3103         chromaticity[2]=(float) image->chromaticity.green_primary.x;
3104         chromaticity[3]=(float) image->chromaticity.green_primary.y;
3105         chromaticity[4]=(float) image->chromaticity.blue_primary.x;
3106         chromaticity[5]=(float) image->chromaticity.blue_primary.y;
3107         (void) TIFFSetField(tiff,TIFFTAG_PRIMARYCHROMATICITIES,chromaticity);
3108         chromaticity[0]=(float) image->chromaticity.white_point.x;
3109         chromaticity[1]=(float) image->chromaticity.white_point.y;
3110         (void) TIFFSetField(tiff,TIFFTAG_WHITEPOINT,chromaticity);
3111       }
3112     if ((LocaleCompare(image_info->magick,"PTIF") != 0) &&
3113         (image_info->adjoin != MagickFalse) && (GetImageListLength(image) > 1))
3114       {
3115         (void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_PAGE);
3116         if (image->scene != 0)
3117           (void) TIFFSetField(tiff,TIFFTAG_PAGENUMBER,(uint16) image->scene,
3118             GetImageListLength(image));
3119       }
3120     if (image->orientation != UndefinedOrientation)
3121       (void) TIFFSetField(tiff,TIFFTAG_ORIENTATION,(uint16) image->orientation);
3122     (void) TIFFSetProfiles(tiff,image);
3123     {
3124       uint16
3125         page,
3126         pages;
3127
3128       page=(uint16) scene;
3129       pages=(uint16) GetImageListLength(image);
3130       if ((LocaleCompare(image_info->magick,"PTIF") != 0) &&
3131           (image_info->adjoin != MagickFalse) && (pages > 1))
3132         (void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_PAGE);
3133       (void) TIFFSetField(tiff,TIFFTAG_PAGENUMBER,page,pages);
3134     }
3135     (void) TIFFSetProperties(tiff,image,exception);
3136     if (0)
3137       (void) TIFFSetEXIFProperties(tiff,image,exception);
3138     /*
3139       Write image scanlines.
3140     */
3141     if (GetTIFFInfo(image_info,tiff,&tiff_info) == MagickFalse)
3142       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3143     quantum_info->endian=LSBEndian;
3144     pixels=GetQuantumPixels(quantum_info);
3145     tiff_info.scanline=GetQuantumPixels(quantum_info);
3146     switch (photometric)
3147     {
3148       case PHOTOMETRIC_CIELAB:
3149       case PHOTOMETRIC_YCBCR:
3150       case PHOTOMETRIC_RGB:
3151       {
3152         /*
3153           RGB TIFF image.
3154         */
3155         switch (image_info->interlace)
3156         {
3157           case NoInterlace:
3158           default:
3159           {
3160             quantum_type=RGBQuantum;
3161             if (image->matte != MagickFalse)
3162               quantum_type=RGBAQuantum;
3163             for (y=0; y < (ssize_t) image->rows; y++)
3164             {
3165               register const Quantum
3166                 *restrict p;
3167
3168               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3169               if (p == (const Quantum *) NULL)
3170                 break;
3171               length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3172                 quantum_type,pixels,exception);
3173               (void) length;
3174               if (TIFFWritePixels(tiff,&tiff_info,y,0,image) == -1)
3175                 break;
3176               if (image->previous == (Image *) NULL)
3177                 {
3178                   status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
3179                     y,image->rows);
3180                   if (status == MagickFalse)
3181                     break;
3182                 }
3183             }
3184             break;
3185           }
3186           case PlaneInterlace:
3187           case PartitionInterlace:
3188           {
3189             /*
3190               Plane interlacing:  RRRRRR...GGGGGG...BBBBBB...
3191             */
3192             for (y=0; y < (ssize_t) image->rows; y++)
3193             {
3194               register const Quantum
3195                 *restrict p;
3196
3197               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3198               if (p == (const Quantum *) NULL)
3199                 break;
3200               length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3201                 RedQuantum,pixels,exception);
3202               if (TIFFWritePixels(tiff,&tiff_info,y,0,image) == -1)
3203                 break;
3204             }
3205             if (image->previous == (Image *) NULL)
3206               {
3207                 status=SetImageProgress(image,SaveImageTag,100,400);
3208                 if (status == MagickFalse)
3209                   break;
3210               }
3211             for (y=0; y < (ssize_t) image->rows; y++)
3212             {
3213               register const Quantum
3214                 *restrict p;
3215
3216               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3217               if (p == (const Quantum *) NULL)
3218                 break;
3219               length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3220                 GreenQuantum,pixels,exception);
3221               if (TIFFWritePixels(tiff,&tiff_info,y,1,image) == -1)
3222                 break;
3223             }
3224             if (image->previous == (Image *) NULL)
3225               {
3226                 status=SetImageProgress(image,SaveImageTag,200,400);
3227                 if (status == MagickFalse)
3228                   break;
3229               }
3230             for (y=0; y < (ssize_t) image->rows; y++)
3231             {
3232               register const Quantum
3233                 *restrict p;
3234
3235               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3236               if (p == (const Quantum *) NULL)
3237                 break;
3238               length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3239                 BlueQuantum,pixels,exception);
3240               if (TIFFWritePixels(tiff,&tiff_info,y,2,image) == -1)
3241                 break;
3242             }
3243             if (image->previous == (Image *) NULL)
3244               {
3245                 status=SetImageProgress(image,SaveImageTag,300,400);
3246                 if (status == MagickFalse)
3247                   break;
3248               }
3249             if (image->matte != MagickFalse)
3250               for (y=0; y < (ssize_t) image->rows; y++)
3251               {
3252                 register const Quantum
3253                   *restrict p;
3254
3255                 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3256                 if (p == (const Quantum *) NULL)
3257                   break;
3258                 length=ExportQuantumPixels(image,(CacheView *) NULL,
3259                   quantum_info,AlphaQuantum,pixels,exception);
3260                 if (TIFFWritePixels(tiff,&tiff_info,y,3,image) == -1)
3261                   break;
3262               }
3263             if (image->previous == (Image *) NULL)
3264               {
3265                 status=SetImageProgress(image,SaveImageTag,400,400);
3266                 if (status == MagickFalse)
3267                   break;
3268               }
3269             break;
3270           }
3271         }
3272         break;
3273       }
3274       case PHOTOMETRIC_SEPARATED:
3275       {
3276         /*
3277           CMYK TIFF image.
3278         */
3279         quantum_type=CMYKQuantum;
3280         if (image->matte != MagickFalse)
3281           quantum_type=CMYKAQuantum;
3282         if (image->colorspace != CMYKColorspace)
3283           (void) TransformImageColorspace(image,CMYKColorspace,exception);
3284         for (y=0; y < (ssize_t) image->rows; y++)
3285         {
3286           register const Quantum
3287             *restrict p;
3288
3289           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3290           if (p == (const Quantum *) NULL)
3291             break;
3292           length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3293             quantum_type,pixels,exception);
3294           if (TIFFWritePixels(tiff,&tiff_info,y,0,image) == -1)
3295             break;
3296           if (image->previous == (Image *) NULL)
3297             {
3298               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
3299                 image->rows);
3300               if (status == MagickFalse)
3301                 break;
3302             }
3303         }
3304         break;
3305       }
3306       case PHOTOMETRIC_PALETTE:
3307       {
3308         uint16
3309           *blue,
3310           *green,
3311           *red;
3312
3313         /*
3314           Colormapped TIFF image.
3315         */
3316         red=(uint16 *) AcquireQuantumMemory(65536,sizeof(*red));
3317         green=(uint16 *) AcquireQuantumMemory(65536,sizeof(*green));
3318         blue=(uint16 *) AcquireQuantumMemory(65536,sizeof(*blue));
3319         if ((red == (uint16 *) NULL) || (green == (uint16 *) NULL) ||
3320             (blue == (uint16 *) NULL))
3321           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3322         /*
3323           Initialize TIFF colormap.
3324         */
3325         (void) ResetMagickMemory(red,0,65536*sizeof(*red));
3326         (void) ResetMagickMemory(green,0,65536*sizeof(*green));
3327         (void) ResetMagickMemory(blue,0,65536*sizeof(*blue));
3328         for (i=0; i < (ssize_t) image->colors; i++)
3329         {
3330           red[i]=ScaleQuantumToShort(image->colormap[i].red);
3331           green[i]=ScaleQuantumToShort(image->colormap[i].green);
3332           blue[i]=ScaleQuantumToShort(image->colormap[i].blue);
3333         }
3334         (void) TIFFSetField(tiff,TIFFTAG_COLORMAP,red,green,blue);
3335         red=(uint16 *) RelinquishMagickMemory(red);
3336         green=(uint16 *) RelinquishMagickMemory(green);
3337         blue=(uint16 *) RelinquishMagickMemory(blue);
3338       }
3339       default:
3340       {
3341         /*
3342           Convert PseudoClass packets to contiguous grayscale scanlines.
3343         */
3344         quantum_type=IndexQuantum;
3345         if (image->matte != MagickFalse)
3346           {
3347             if (photometric != PHOTOMETRIC_PALETTE)
3348               quantum_type=GrayAlphaQuantum;
3349             else
3350               quantum_type=IndexAlphaQuantum;
3351            }
3352          else
3353            if (photometric != PHOTOMETRIC_PALETTE)
3354              quantum_type=GrayQuantum;
3355         for (y=0; y < (ssize_t) image->rows; y++)
3356         {
3357           register const Quantum
3358             *restrict p;
3359
3360           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3361           if (p == (const Quantum *) NULL)
3362             break;
3363           length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3364             quantum_type,pixels,exception);
3365           if (TIFFWritePixels(tiff,&tiff_info,y,0,image) == -1)
3366             break;
3367           if (image->previous == (Image *) NULL)
3368             {
3369               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
3370                 image->rows);
3371               if (status == MagickFalse)
3372                 break;
3373             }
3374         }
3375         break;
3376       }
3377     }
3378     quantum_info=DestroyQuantumInfo(quantum_info);
3379     DestroyTIFFInfo(&tiff_info);
3380     if (0 && (image_info->verbose == MagickTrue))
3381       TIFFPrintDirectory(tiff,stdout,MagickFalse);
3382     (void) TIFFWriteDirectory(tiff);
3383     image=SyncNextImageInList(image);
3384     if (image == (Image *) NULL)
3385       break;
3386     status=SetImageProgress(image,SaveImagesTag,scene++,
3387       GetImageListLength(image));
3388     if (status == MagickFalse)
3389       break;
3390   } while (image_info->adjoin != MagickFalse);
3391   (void) TIFFSetWarningHandler(warning_handler);
3392   (void) TIFFSetErrorHandler(error_handler);
3393   TIFFClose(tiff);
3394   return(MagickTrue);
3395 }
3396 #endif