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