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