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