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