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