]> 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 size_t 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,(size_t) strip_offset);
345   length=fwrite("\022\001\003\000\001\000\000\000",1,8,file);
346   length=WriteLSBLong(file,(size_t) 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,(size_t) (strip_offset-8));
354   length=fwrite("\033\001\005\000\001\000\000\000",1,8,file);
355   length=WriteLSBLong(file,(size_t) (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,(ssize_t) 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 ssize_t MagickMin(const ssize_t x,const ssize_t 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,ssize_t length)
433 {
434   MagickBooleanType
435     status;
436
437   register ssize_t
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(),CoderError,message,
495       "`%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,(ssize_t) 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,(ssize_t) 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,(size_t) 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,(ssize_t) length);
529 #endif
530   length=0;
531   if (TIFFGetField(tiff,37724,&length,&profile) == 1)
532     (void) ReadProfile(image,"tiff:37724",profile,(ssize_t) 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 ssize_t
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           ssize_ty;
612
613         if (TIFFGetField(tiff,exif_info[i].tag,&ssize_ty) != 0)
614           (void) FormatMagickString(value,MaxTextExtent,"%d",ssize_ty);
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,size_t bits_per_sample,
661   tsample_t sample,ssize_t 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   ssize_t
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 ssize_t
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   size_t
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 < (ssize_t) 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) SetImageProperty(image,"tiff:endian",TIFFIsBigEndian(tiff) == 0 ?
863       "lsb" : "msb");
864     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_COMPRESSION,&compress_tag);
865     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_ORIENTATION,&orientation);
866     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_IMAGEWIDTH,&width);
867     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_IMAGELENGTH,&height);
868     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_FILLORDER,&endian);
869     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_PLANARCONFIG,&interlace);
870     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_BITSPERSAMPLE,&bits_per_sample);
871     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_SAMPLEFORMAT,&sample_format);
872     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_MINSAMPLEVALUE,&min_sample_value);
873     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_MAXSAMPLEVALUE,&max_sample_value);
874     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_PHOTOMETRIC,&photometric);
875     switch (photometric)
876     {
877       case PHOTOMETRIC_MINISBLACK:
878       {
879         (void) SetImageProperty(image,"tiff:photometric","min-is-black");
880         break;
881       }
882       case PHOTOMETRIC_MINISWHITE:
883       {
884         (void) SetImageProperty(image,"tiff:photometric","min-is-white");
885         break;
886       }
887       case PHOTOMETRIC_PALETTE:
888       {
889         (void) SetImageProperty(image,"tiff:photometric","palette");
890         break;
891       }
892       case PHOTOMETRIC_RGB:
893       {
894         (void) SetImageProperty(image,"tiff:photometric","RGB");
895         break;
896       }
897       case PHOTOMETRIC_CIELAB:
898       {
899         (void) SetImageProperty(image,"tiff:photometric","CIELAB");
900         break;
901       }
902       case PHOTOMETRIC_SEPARATED:
903       {
904         (void) SetImageProperty(image,"tiff:photometric","separated");
905         break;
906       }
907       default:
908       {
909         (void) SetImageProperty(image,"tiff:photometric","unknown");
910         break;
911       }
912     }
913     if (image->debug != MagickFalse)
914       {
915         (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %ux%u",
916           (unsigned int) width,(unsigned int) height);
917         (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Interlace: %u",
918           interlace);
919         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
920           "Bits per sample: %u",bits_per_sample);
921         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
922           "Min sample value: %u",min_sample_value);
923         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
924           "Max sample value: %u",max_sample_value);
925         (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Photometric "
926           "interpretation: %s",GetImageProperty(image,"tiff:photometric"));
927       }
928     image->columns=(size_t) width;
929     image->rows=(size_t) height;
930     image->depth=(size_t) bits_per_sample;
931     if (image->debug != MagickFalse)
932       (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Image depth: %.20g",
933         (double) image->depth);
934     lsb_first=1;
935     image->endian=MSBEndian;
936     if ((int) (*(char *) &lsb_first) != 0)
937       image->endian=LSBEndian;
938     if (photometric == PHOTOMETRIC_SEPARATED)
939       image->colorspace=CMYKColorspace;
940     if (photometric == PHOTOMETRIC_CIELAB)
941       image->colorspace=LabColorspace;
942     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_SAMPLESPERPIXEL,
943       &samples_per_pixel);
944     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_RESOLUTIONUNIT,&units);
945     x_resolution=(float) image->x_resolution;
946     y_resolution=(float) image->y_resolution;
947     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_XRESOLUTION,&x_resolution);
948     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_YRESOLUTION,&y_resolution);
949     image->x_resolution=x_resolution;
950     image->y_resolution=y_resolution;
951     x_position=(float) image->page.x/x_resolution;
952     y_position=(float) image->page.y/y_resolution;
953     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_XPOSITION,&x_position);
954     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_YPOSITION,&y_position);
955     image->page.x=(ssize_t) ceil(x_position*x_resolution-0.5);
956     image->page.y=(ssize_t) ceil(y_position*y_resolution-0.5);
957     image->orientation=(OrientationType) orientation;
958     chromaticity=(float *) NULL;
959     (void) TIFFGetField(tiff,TIFFTAG_WHITEPOINT,&chromaticity);
960     if (chromaticity != (float *) NULL)
961       {
962         image->chromaticity.white_point.x=chromaticity[0];
963         image->chromaticity.white_point.y=chromaticity[1];
964       }
965     chromaticity=(float *) NULL;
966     (void) TIFFGetField(tiff,TIFFTAG_PRIMARYCHROMATICITIES,&chromaticity);
967     if (chromaticity != (float *) NULL)
968       {
969         image->chromaticity.red_primary.x=chromaticity[0];
970         image->chromaticity.red_primary.y=chromaticity[1];
971         image->chromaticity.green_primary.x=chromaticity[2];
972         image->chromaticity.green_primary.y=chromaticity[3];
973         image->chromaticity.blue_primary.x=chromaticity[4];
974         image->chromaticity.blue_primary.y=chromaticity[5];
975       }
976     TIFFGetProperties(tiff,image);
977     option=GetImageOption(image_info,"tiff:exif");
978     if ((option != (const char *) NULL) &&
979         (IsMagickTrue(option) != MagickFalse))
980       TIFFGetEXIFProperties(tiff,image);
981     TIFFGetProfiles(tiff,image);
982     /*
983       Allocate memory for the image and pixel buffer.
984     */
985 #if defined(MAGICKCORE_HAVE_TIFFISCODECCONFIGURED) || (TIFFLIB_VERSION > 20040919)
986     if ((compress_tag != COMPRESSION_NONE) &&
987         (TIFFIsCODECConfigured(compress_tag) == 0))
988       {
989         TIFFClose(tiff);
990         ThrowReaderException(CoderError,"CompressNotSupported");
991       }
992 #endif
993     switch (compress_tag)
994     {
995       case COMPRESSION_NONE: image->compression=NoCompression; break;
996       case COMPRESSION_CCITTFAX3: image->compression=FaxCompression; break;
997       case COMPRESSION_CCITTFAX4: image->compression=Group4Compression; break;
998       case COMPRESSION_JPEG:
999       {
1000          image->compression=JPEGCompression;
1001 #if defined(JPEG_SUPPORT)
1002          {
1003            char
1004              sampling_factor[MaxTextExtent];
1005
1006            uint16
1007              horizontal,
1008              vertical;
1009
1010            (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_YCBCRSUBSAMPLING,
1011              &horizontal,&vertical);
1012            (void) FormatMagickString(sampling_factor,MaxTextExtent,"%dx%d",
1013              horizontal,vertical);
1014            (void) SetImageProperty(image,"jpeg:sampling-factor",
1015              sampling_factor);
1016            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1017              "Sampling Factors: %s",sampling_factor);
1018            if ((samples_per_pixel > 1) && (photometric == PHOTOMETRIC_YCBCR))
1019              {
1020                (void) TIFFSetField(tiff,TIFFTAG_JPEGCOLORMODE,
1021                  JPEGCOLORMODE_RGB);
1022                photometric=PHOTOMETRIC_RGB;
1023              }
1024          }
1025 #endif
1026         break;
1027       }
1028       case COMPRESSION_OJPEG: image->compression=JPEGCompression; break;
1029       case COMPRESSION_LZW: image->compression=LZWCompression; break;
1030       case COMPRESSION_DEFLATE: image->compression=ZipCompression; break;
1031       case COMPRESSION_ADOBE_DEFLATE: image->compression=ZipCompression; break;
1032       default: image->compression=RLECompression; break;
1033     }
1034     quantum_info=AcquireQuantumInfo(image_info,image);
1035     if (quantum_info == (QuantumInfo *) NULL)
1036       {
1037         TIFFClose(tiff);
1038         ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1039       }
1040     if (sample_format == SAMPLEFORMAT_UINT)
1041       status=SetQuantumFormat(image,quantum_info,UnsignedQuantumFormat);
1042     if (sample_format == SAMPLEFORMAT_INT)
1043       status=SetQuantumFormat(image,quantum_info,SignedQuantumFormat);
1044     if (sample_format == SAMPLEFORMAT_IEEEFP)
1045       status=SetQuantumFormat(image,quantum_info,FloatingPointQuantumFormat);
1046     if (status == MagickFalse)
1047       {
1048         TIFFClose(tiff);
1049         ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1050       }
1051     status=MagickTrue;
1052     switch (photometric)
1053     {
1054       case PHOTOMETRIC_MINISBLACK:
1055       {
1056         quantum_info->min_is_white=MagickFalse;
1057         break;
1058       }
1059       case PHOTOMETRIC_MINISWHITE:
1060       {
1061         quantum_info->min_is_white=MagickTrue;
1062         break;
1063       }
1064       default:
1065         break;
1066     }
1067     associated_alpha=MagickFalse;
1068     extra_samples=0;
1069     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_EXTRASAMPLES,&extra_samples,
1070       &sample_info);
1071     if (extra_samples == 0)
1072       {
1073         if ((samples_per_pixel == 4) && (photometric == PHOTOMETRIC_RGB))
1074           image->matte=MagickTrue;
1075       }
1076     else
1077       for (i=0; i < extra_samples; i++)
1078       {
1079         image->matte=MagickTrue;
1080         if (sample_info[i] == EXTRASAMPLE_ASSOCALPHA)
1081           SetQuantumAlphaType(quantum_info,DisassociatedQuantumAlpha);
1082       }
1083     option=GetImageOption(image_info,"tiff:alpha");
1084     if (option != (const char *) NULL)
1085       associated_alpha=LocaleCompare(option,"associated") == 0 ? MagickTrue :
1086         MagickFalse;
1087     if (image->matte != MagickFalse)
1088       (void) SetImageProperty(image,"tiff:alpha",
1089         associated_alpha != MagickFalse ? "associated" : "unassociated");
1090     if ((photometric == PHOTOMETRIC_PALETTE) &&
1091         (pow(2.0,1.0*bits_per_sample) <= MaxColormapSize))
1092       {
1093         size_t
1094           colors;
1095
1096         colors=(size_t) GetQuantumRange(bits_per_sample)+1;
1097         if (AcquireImageColormap(image,colors) == MagickFalse)
1098           {
1099             TIFFClose(tiff);
1100             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1101           }
1102       }
1103     if (units == RESUNIT_INCH)
1104       image->units=PixelsPerInchResolution;
1105     if (units == RESUNIT_CENTIMETER)
1106       image->units=PixelsPerCentimeterResolution;
1107     value=(unsigned short) image->scene;
1108     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_PAGENUMBER,&value,&pages);
1109     image->scene=value;
1110     if (image_info->ping != MagickFalse)
1111       {
1112         if (image_info->number_scenes != 0)
1113           if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1114             break;
1115         goto next_tiff_frame;
1116       }
1117     method=ReadGenericMethod;
1118     if (TIFFGetField(tiff,TIFFTAG_ROWSPERSTRIP,&rows_per_strip) != 0)
1119       {
1120         char
1121           value[MaxTextExtent];
1122
1123         method=ReadStripMethod;
1124         (void) FormatMagickString(value,MaxTextExtent,"%u",
1125           (unsigned int) rows_per_strip);
1126         (void) SetImageProperty(image,"tiff:rows-per-strip",value);
1127       }
1128     if ((samples_per_pixel >= 2) && (interlace == PLANARCONFIG_CONTIG))
1129       method=ReadRGBAMethod;
1130     if ((samples_per_pixel >= 2) && (interlace == PLANARCONFIG_SEPARATE))
1131       method=ReadCMYKAMethod;
1132     if ((photometric != PHOTOMETRIC_RGB) &&
1133         (photometric != PHOTOMETRIC_CIELAB) &&
1134         (photometric != PHOTOMETRIC_SEPARATED))
1135       method=ReadGenericMethod;
1136     if (image->storage_class == PseudoClass)
1137       method=ReadSingleSampleMethod;
1138     if ((photometric == PHOTOMETRIC_MINISBLACK) ||
1139         (photometric == PHOTOMETRIC_MINISWHITE))
1140       method=ReadSingleSampleMethod;
1141     if ((photometric != PHOTOMETRIC_SEPARATED) &&
1142         (interlace == PLANARCONFIG_SEPARATE))
1143       method=ReadGenericMethod;
1144     if (TIFFIsTiled(tiff) != MagickFalse)
1145       method=ReadTileMethod;
1146     quantum_type=RGBQuantum;
1147     pixels=GetQuantumPixels(quantum_info);
1148     switch (method)
1149     {
1150       case ReadSingleSampleMethod:
1151       {
1152         /*
1153           Convert TIFF image to PseudoClass MIFF image.
1154         */
1155         if ((image->storage_class == PseudoClass) &&
1156             (photometric == PHOTOMETRIC_PALETTE))
1157           {
1158             size_t
1159               range;
1160
1161             uint16
1162               *blue_colormap,
1163               *green_colormap,
1164               *red_colormap;
1165
1166             /*
1167               Initialize colormap.
1168             */
1169             (void) TIFFGetField(tiff,TIFFTAG_COLORMAP,&red_colormap,
1170               &green_colormap,&blue_colormap);
1171             range=255;  /* might be old style 8-bit colormap */
1172             for (i=0; i < (ssize_t) image->colors; i++)
1173               if ((red_colormap[i] >= 256) || (green_colormap[i] >= 256) ||
1174                   (blue_colormap[i] >= 256))
1175                 {
1176                   range=65535;
1177                   break;
1178                 }
1179             for (i=0; i < (ssize_t) image->colors; i++)
1180             {
1181               image->colormap[i].red=ClampToQuantum(((double) QuantumRange*
1182                 red_colormap[i])/range);
1183               image->colormap[i].green=ClampToQuantum(((double) QuantumRange*
1184                 green_colormap[i])/range);
1185               image->colormap[i].blue=ClampToQuantum(((double) QuantumRange*
1186                 blue_colormap[i])/range);
1187             }
1188           }
1189         quantum_type=IndexQuantum;
1190         pad=(size_t) MagickMax((size_t) samples_per_pixel-1,0);
1191         if (image->matte != MagickFalse)
1192           {
1193             if (image->storage_class != PseudoClass)
1194               {
1195                 quantum_type=samples_per_pixel == 1 ? AlphaQuantum :
1196                   GrayAlphaQuantum;
1197                 pad=(size_t) MagickMax((size_t) samples_per_pixel-2,0);
1198               }
1199             else
1200               {
1201                 quantum_type=IndexAlphaQuantum;
1202                 pad=(size_t) MagickMax((size_t) samples_per_pixel-2,0);
1203               }
1204           }
1205         else
1206           if (image->storage_class != PseudoClass)
1207             {
1208               quantum_type=GrayQuantum;
1209               pad=(size_t) MagickMax((size_t) samples_per_pixel-1,0);
1210             }
1211         status=SetQuantumPad(image,quantum_info,pad*((bits_per_sample+7) >> 3));
1212         if (status == MagickFalse)
1213           {
1214             TIFFClose(tiff);
1215             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1216           }
1217         pixels=GetQuantumPixels(quantum_info);
1218         for (y=0; y < (ssize_t) image->rows; y++)
1219         {
1220           int
1221             status;
1222
1223           register PixelPacket
1224             *restrict q;
1225
1226           status=TIFFReadPixels(tiff,bits_per_sample,0,y,(char *) pixels);
1227           if (status == -1)
1228             break;
1229           q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1230           if (q == (PixelPacket *) NULL)
1231             break;
1232           length=ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1233             quantum_type,pixels,exception);
1234           if (SyncAuthenticPixels(image,exception) == MagickFalse)
1235             break;
1236           if (image->previous == (Image *) NULL)
1237             {
1238               status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1239                 image->rows);
1240               if (status == MagickFalse)
1241                 break;
1242             }
1243         }
1244         break;
1245       }
1246       case ReadRGBAMethod:
1247       {
1248         /*
1249           Convert TIFF image to DirectClass MIFF image.
1250         */
1251         pad=(size_t) MagickMax((size_t) samples_per_pixel-3,0);
1252         quantum_type=RGBQuantum;
1253         if (image->matte != MagickFalse)
1254           {
1255             quantum_type=RGBAQuantum;
1256             pad=(size_t) MagickMax((size_t) samples_per_pixel-4,0);
1257           }
1258         if (image->colorspace == CMYKColorspace)
1259           {
1260             pad=(size_t) MagickMax((size_t) samples_per_pixel-4,0);
1261             quantum_type=CMYKQuantum;
1262             if (image->matte != MagickFalse)
1263               {
1264                 quantum_type=CMYKAQuantum;
1265                 pad=(size_t) MagickMax((size_t) samples_per_pixel-5,0);
1266               }
1267           }
1268         status=SetQuantumPad(image,quantum_info,pad*((bits_per_sample+7) >> 3));
1269         if (status == MagickFalse)
1270           {
1271             TIFFClose(tiff);
1272             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1273           }
1274         pixels=GetQuantumPixels(quantum_info);
1275         for (y=0; y < (ssize_t) image->rows; y++)
1276         {
1277           int
1278             status;
1279
1280           register PixelPacket
1281             *restrict q;
1282
1283           status=TIFFReadPixels(tiff,bits_per_sample,0,y,(char *) pixels);
1284           if (status == -1)
1285             break;
1286           q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1287           if (q == (PixelPacket *) NULL)
1288             break;
1289           length=ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1290             quantum_type,pixels,exception);
1291           if (SyncAuthenticPixels(image,exception) == MagickFalse)
1292             break;
1293           if (image->previous == (Image *) NULL)
1294             {
1295               status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1296                 image->rows);
1297               if (status == MagickFalse)
1298                 break;
1299             }
1300         }
1301         break;
1302       }
1303       case ReadCMYKAMethod:
1304       {
1305         /*
1306           Convert TIFF image to DirectClass MIFF image.
1307         */
1308         for (i=0; i < (ssize_t) samples_per_pixel; i++)
1309         {
1310           for (y=0; y < (ssize_t) image->rows; y++)
1311           {
1312             register PixelPacket
1313               *restrict q;
1314
1315             int
1316               status;
1317
1318             status=TIFFReadPixels(tiff,bits_per_sample,(tsample_t) i,y,(char *)
1319               pixels);
1320             if (status == -1)
1321               break;
1322             q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
1323             if (q == (PixelPacket *) NULL)
1324               break;
1325             if (image->colorspace != CMYKColorspace)
1326               switch (i)
1327               {
1328                 case 0: quantum_type=RedQuantum; break;
1329                 case 1: quantum_type=GreenQuantum; break;
1330                 case 2: quantum_type=BlueQuantum; break;
1331                 case 3: quantum_type=AlphaQuantum; break;
1332                 default: quantum_type=UndefinedQuantum; break;
1333               }
1334             else
1335               switch (i)
1336               {
1337                 case 0: quantum_type=CyanQuantum; break;
1338                 case 1: quantum_type=MagentaQuantum; break;
1339                 case 2: quantum_type=YellowQuantum; break;
1340                 case 3: quantum_type=BlackQuantum; break;
1341                 case 4: quantum_type=AlphaQuantum; break;
1342                 default: quantum_type=UndefinedQuantum; break;
1343               }
1344             length=ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1345               quantum_type,pixels,exception);
1346             if (SyncAuthenticPixels(image,exception) == MagickFalse)
1347               break;
1348           }
1349           if (image->previous == (Image *) NULL)
1350             {
1351               status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1352                 image->rows);
1353               if (status == MagickFalse)
1354                 break;
1355             }
1356         }
1357         break;
1358       }
1359       case ReadStripMethod:
1360       {
1361         register unsigned char
1362           *p;
1363
1364         /*
1365           Convert stripped TIFF image to DirectClass MIFF image.
1366         */
1367         i=0;
1368         p=(unsigned char *) NULL;
1369         for (y=0; y < (ssize_t) image->rows; y++)
1370         {
1371           register ssize_t
1372             x;
1373
1374           register PixelPacket
1375             *restrict q;
1376
1377           q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1378           if (q == (PixelPacket *) NULL)
1379             break;
1380           if (i == 0)
1381             {
1382               if (TIFFReadRGBAStrip(tiff,(tstrip_t) y,(uint32 *) pixels) == 0)
1383                 break;
1384               i=(ssize_t) MagickMin((ssize_t) rows_per_strip,(ssize_t)
1385                 image->rows-y);
1386             }
1387           i--;
1388           p=pixels+image->columns*i;
1389           for (x=0; x < (ssize_t) image->columns; x++)
1390           {
1391             q->red=ScaleCharToQuantum((unsigned char) (TIFFGetR(*p)));
1392             q->green=ScaleCharToQuantum((unsigned char) (TIFFGetG(*p)));
1393             q->blue=ScaleCharToQuantum((unsigned char) (TIFFGetB(*p)));
1394             if (image->matte != MagickFalse)
1395               q->opacity=ScaleCharToQuantum((unsigned char) (TIFFGetA(*p)));
1396             p++;
1397             q++;
1398           }
1399           if (SyncAuthenticPixels(image,exception) == MagickFalse)
1400             break;
1401           if (image->previous == (Image *) NULL)
1402             {
1403               status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1404                 image->rows);
1405               if (status == MagickFalse)
1406                 break;
1407             }
1408         }
1409         break;
1410       }
1411       case ReadTileMethod:
1412       {
1413         register uint32
1414           *p;
1415
1416         uint32
1417           *tile_pixels,
1418           columns,
1419           rows;
1420
1421         size_t
1422           number_pixels;
1423
1424         /*
1425           Convert tiled TIFF image to DirectClass MIFF image.
1426         */
1427         if ((TIFFGetField(tiff,TIFFTAG_TILEWIDTH,&columns) == 0) ||
1428             (TIFFGetField(tiff,TIFFTAG_TILELENGTH,&rows) == 0))
1429           {
1430             TIFFClose(tiff);
1431             ThrowReaderException(CoderError,"ImageIsNotTiled");
1432           }
1433         (void) SetImageStorageClass(image,DirectClass);
1434         number_pixels=columns*rows;
1435         tile_pixels=(uint32 *) AcquireQuantumMemory((size_t) columns*rows,
1436           sizeof(*tile_pixels));
1437         if (tile_pixels == (uint32 *) NULL)
1438           {
1439             TIFFClose(tiff);
1440             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1441           }
1442         for (y=0; y < (ssize_t) image->rows; y+=rows)
1443         {
1444           PixelPacket
1445             *tile;
1446
1447           register ssize_t
1448             x;
1449
1450           register PixelPacket
1451             *restrict q;
1452
1453           size_t
1454             columns_remaining,
1455             rows_remaining;
1456
1457           rows_remaining=image->rows-y;
1458           if ((ssize_t) (y+rows) < (ssize_t) image->rows)
1459             rows_remaining=rows;
1460           tile=QueueAuthenticPixels(image,0,y,image->columns,rows_remaining,
1461             exception);
1462           if (tile == (PixelPacket *) NULL)
1463             break;
1464           for (x=0; x < (ssize_t) image->columns; x+=columns)
1465           {
1466             size_t
1467               column,
1468               row;
1469
1470             if (TIFFReadRGBATile(tiff,(uint32) x,(uint32) y,tile_pixels) == 0)
1471               break;
1472             columns_remaining=image->columns-x;
1473             if ((ssize_t) (x+columns) < (ssize_t) image->columns)
1474               columns_remaining=columns;
1475             p=tile_pixels+(rows-rows_remaining)*columns;
1476             q=tile+(image->columns*(rows_remaining-1)+x);
1477             for (row=rows_remaining; row > 0; row--)
1478             {
1479               if (image->matte != MagickFalse)
1480                 for (column=columns_remaining; column > 0; column--)
1481                 {
1482                   q->red=ScaleCharToQuantum((unsigned char) TIFFGetR(*p));
1483                   q->green=ScaleCharToQuantum((unsigned char) TIFFGetG(*p));
1484                   q->blue=ScaleCharToQuantum((unsigned char) TIFFGetB(*p));
1485                   q->opacity=(Quantum) (QuantumRange-ScaleCharToQuantum(
1486                     (unsigned char) TIFFGetA(*p)));
1487                   q++;
1488                   p++;
1489                 }
1490               else
1491                 for (column=columns_remaining; column > 0; column--)
1492                 {
1493                   q->red=ScaleCharToQuantum((unsigned char) TIFFGetR(*p));
1494                   q->green=ScaleCharToQuantum((unsigned char) TIFFGetG(*p));
1495                   q->blue=ScaleCharToQuantum((unsigned char) TIFFGetB(*p));
1496                   q++;
1497                   p++;
1498                 }
1499               p+=columns-columns_remaining;
1500               q-=(image->columns+columns_remaining);
1501             }
1502           }
1503           if (SyncAuthenticPixels(image,exception) == MagickFalse)
1504             break;
1505           if (image->previous == (Image *) NULL)
1506             {
1507               status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1508                 image->rows);
1509               if (status == MagickFalse)
1510                 break;
1511             }
1512         }
1513         tile_pixels=(uint32 *) RelinquishMagickMemory(tile_pixels);
1514         break;
1515       }
1516       case ReadGenericMethod:
1517       default:
1518       {
1519         register uint32
1520           *p;
1521
1522         uint32
1523           *pixels;
1524
1525         /*
1526           Convert TIFF image to DirectClass MIFF image.
1527         */
1528         number_pixels=(MagickSizeType) image->columns*image->rows;
1529         if ((number_pixels*sizeof(uint32)) != (MagickSizeType) ((size_t)
1530             (number_pixels*sizeof(uint32))))
1531           {
1532             TIFFClose(tiff);
1533             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1534           }
1535         pixels=(uint32 *) AcquireQuantumMemory(image->columns,image->rows*
1536           sizeof(uint32));
1537         if (pixels == (uint32 *) NULL)
1538           {
1539             TIFFClose(tiff);
1540             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1541           }
1542         (void) TIFFReadRGBAImage(tiff,(uint32) image->columns,
1543           (uint32) image->rows,(uint32 *) pixels,0);
1544         /*
1545           Convert image to DirectClass pixel packets.
1546         */
1547         p=pixels+number_pixels-1;
1548         for (y=0; y < (ssize_t) image->rows; y++)
1549         {
1550           register ssize_t
1551             x;
1552
1553           register PixelPacket
1554             *restrict q;
1555
1556           q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1557           if (q == (PixelPacket *) NULL)
1558             break;
1559           q+=image->columns-1;
1560           for (x=0; x < (ssize_t) image->columns; x++)
1561           {
1562             q->red=ScaleCharToQuantum((unsigned char) TIFFGetR(*p));
1563             q->green=ScaleCharToQuantum((unsigned char) TIFFGetG(*p));
1564             q->blue=ScaleCharToQuantum((unsigned char) TIFFGetB(*p));
1565             if (image->matte != MagickFalse)
1566               q->opacity=(Quantum) (QuantumRange-
1567                 ScaleCharToQuantum((unsigned char) TIFFGetA(*p)));
1568             p--;
1569             q--;
1570           }
1571           if (SyncAuthenticPixels(image,exception) == MagickFalse)
1572             break;
1573           if (image->previous == (Image *) NULL)
1574             {
1575               status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1576                 image->rows);
1577               if (status == MagickFalse)
1578                 break;
1579             }
1580         }
1581         pixels=(uint32 *) RelinquishMagickMemory(pixels);
1582         break;
1583       }
1584     }
1585     SetQuantumImageType(image,quantum_type);
1586   next_tiff_frame:
1587     if ((photometric == PHOTOMETRIC_LOGL) ||
1588         (photometric == PHOTOMETRIC_MINISBLACK) ||
1589         (photometric == PHOTOMETRIC_MINISWHITE))
1590       {
1591         image->type=GrayscaleType;
1592         if (bits_per_sample == 1)
1593           image->type=BilevelType;
1594       }
1595     if (image->storage_class == PseudoClass)
1596       image->depth=GetImageDepth(image,exception);
1597     image->endian=MSBEndian;
1598     if (endian == FILLORDER_LSB2MSB)
1599       image->endian=LSBEndian;
1600     if ((photometric == PHOTOMETRIC_LOGL) ||
1601         (photometric == PHOTOMETRIC_MINISBLACK) ||
1602         (photometric == PHOTOMETRIC_MINISWHITE))
1603       {
1604          image->type=GrayscaleType;
1605          if (bits_per_sample == 1)
1606            image->type=BilevelType;
1607       }
1608     /*
1609       Proceed to next image.
1610     */
1611     if (image_info->number_scenes != 0)
1612       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1613         break;
1614     status=TIFFReadDirectory(tiff) != 0 ? MagickTrue : MagickFalse;
1615     if (status == MagickTrue)
1616       {
1617         /*
1618           Allocate next image structure.
1619         */
1620         AcquireNextImage(image_info,image);
1621         if (GetNextImageInList(image) == (Image *) NULL)
1622           {
1623             image=DestroyImageList(image);
1624             return((Image *) NULL);
1625           }
1626         image=SyncNextImageInList(image);
1627         status=SetImageProgress(image,LoadImagesTag,image->scene-1,
1628           image->scene);
1629         if (status == MagickFalse)
1630           break;
1631       }
1632     quantum_info=DestroyQuantumInfo(quantum_info);
1633   } while (status == MagickTrue);
1634   (void) TIFFSetWarningHandler(warning_handler);
1635   (void) TIFFSetErrorHandler(error_handler);
1636   TIFFClose(tiff);
1637   return(GetFirstImageInList(image));
1638 }
1639 #endif
1640 \f
1641 /*
1642 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1643 %                                                                             %
1644 %                                                                             %
1645 %                                                                             %
1646 %   R e g i s t e r T I F F I m a g e                                         %
1647 %                                                                             %
1648 %                                                                             %
1649 %                                                                             %
1650 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1651 %
1652 %  RegisterTIFFImage() adds properties for the TIFF image format to
1653 %  the list of supported formats.  The properties include the image format
1654 %  tag, a method to read and/or write the format, whether the format
1655 %  supports the saving of more than one frame to the same file or blob,
1656 %  whether the format supports native in-memory I/O, and a brief
1657 %  description of the format.
1658 %
1659 %  The format of the RegisterTIFFImage method is:
1660 %
1661 %      size_t RegisterTIFFImage(void)
1662 %
1663 */
1664 ModuleExport size_t RegisterTIFFImage(void)
1665 {
1666 #define TIFFDescription  "Tagged Image File Format"
1667
1668   char
1669     version[MaxTextExtent];
1670
1671   MagickInfo
1672     *entry;
1673
1674   if (tiff_semaphore == (SemaphoreInfo *) NULL)
1675     tiff_semaphore=AllocateSemaphoreInfo();
1676   LockSemaphoreInfo(tiff_semaphore);
1677   if (instantiate_key == MagickFalse)
1678     {
1679       if (MagickCreateThreadKey(&tiff_exception) == MagickFalse)
1680         ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1681       instantiate_key=MagickTrue;
1682     }
1683   UnlockSemaphoreInfo(tiff_semaphore);
1684   *version='\0';
1685 #if defined(TIFF_VERSION)
1686   (void) FormatMagickString(version,MaxTextExtent,"%d",TIFF_VERSION);
1687 #endif
1688 #if defined(MAGICKCORE_TIFF_DELEGATE)
1689   {
1690     const char
1691       *p;
1692
1693     register ssize_t
1694       i;
1695
1696     p=TIFFGetVersion();
1697     for (i=0; (i < (MaxTextExtent-1)) && (*p != 0) && (*p != '\n'); i++)
1698       version[i]=(*p++);
1699     version[i]='\0';
1700   }
1701 #endif
1702
1703   entry=SetMagickInfo("GROUP4");
1704 #if defined(MAGICKCORE_TIFF_DELEGATE)
1705   entry->decoder=(DecodeImageHandler *) ReadGROUP4Image;
1706   entry->encoder=(EncodeImageHandler *) WriteGROUP4Image;
1707 #endif
1708   entry->raw=MagickTrue;
1709   entry->endian_support=MagickTrue;
1710   entry->adjoin=MagickFalse;
1711   entry->format_type=ImplicitFormatType;
1712   entry->seekable_stream=MagickTrue;
1713   entry->thread_support=NoThreadSupport;
1714   entry->description=ConstantString("Raw CCITT Group4");
1715   entry->module=ConstantString("TIFF");
1716   (void) RegisterMagickInfo(entry);
1717   entry=SetMagickInfo("PTIF");
1718 #if defined(MAGICKCORE_TIFF_DELEGATE)
1719   entry->decoder=(DecodeImageHandler *) ReadTIFFImage;
1720   entry->encoder=(EncodeImageHandler *) WritePTIFImage;
1721 #endif
1722   entry->endian_support=MagickTrue;
1723   entry->seekable_stream=MagickTrue;
1724   entry->thread_support=NoThreadSupport;
1725   entry->description=ConstantString("Pyramid encoded TIFF");
1726   entry->module=ConstantString("TIFF");
1727   (void) RegisterMagickInfo(entry);
1728   entry=SetMagickInfo("TIF");
1729 #if defined(MAGICKCORE_TIFF_DELEGATE)
1730   entry->decoder=(DecodeImageHandler *) ReadTIFFImage;
1731   entry->encoder=(EncodeImageHandler *) WriteTIFFImage;
1732 #endif
1733   entry->endian_support=MagickTrue;
1734   entry->seekable_stream=MagickTrue;
1735   entry->stealth=MagickTrue;
1736   entry->thread_support=NoThreadSupport;
1737   entry->description=ConstantString(TIFFDescription);
1738   if (*version != '\0')
1739     entry->version=ConstantString(version);
1740   entry->module=ConstantString("TIFF");
1741   (void) RegisterMagickInfo(entry);
1742   entry=SetMagickInfo("TIFF");
1743 #if defined(MAGICKCORE_TIFF_DELEGATE)
1744   entry->decoder=(DecodeImageHandler *) ReadTIFFImage;
1745   entry->encoder=(EncodeImageHandler *) WriteTIFFImage;
1746 #endif
1747   entry->magick=(IsImageFormatHandler *) IsTIFF;
1748   entry->endian_support=MagickTrue;
1749   entry->seekable_stream=MagickTrue;
1750   entry->thread_support=NoThreadSupport;
1751   entry->description=ConstantString(TIFFDescription);
1752   if (*version != '\0')
1753     entry->version=ConstantString(version);
1754   entry->module=ConstantString("TIFF");
1755   (void) RegisterMagickInfo(entry);
1756   entry=SetMagickInfo("TIFF64");
1757 #if defined(TIFF_VERSION_BIG)
1758   entry->decoder=(DecodeImageHandler *) ReadTIFFImage;
1759   entry->encoder=(EncodeImageHandler *) WritePTIFImage;
1760 #endif
1761   entry->adjoin=MagickFalse;
1762   entry->endian_support=MagickTrue;
1763   entry->seekable_stream=MagickTrue;
1764   entry->thread_support=NoThreadSupport;
1765   entry->description=ConstantString("Tagged Image File Format (64-bit)");
1766   if (*version != '\0')
1767     entry->version=ConstantString(version);
1768   entry->module=ConstantString("TIFF");
1769   (void) RegisterMagickInfo(entry);
1770   return(MagickImageCoderSignature);
1771 }
1772 \f
1773 /*
1774 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1775 %                                                                             %
1776 %                                                                             %
1777 %                                                                             %
1778 %   U n r e g i s t e r T I F F I m a g e                                     %
1779 %                                                                             %
1780 %                                                                             %
1781 %                                                                             %
1782 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1783 %
1784 %  UnregisterTIFFImage() removes format registrations made by the TIFF module
1785 %  from the list of supported formats.
1786 %
1787 %  The format of the UnregisterTIFFImage method is:
1788 %
1789 %      UnregisterTIFFImage(void)
1790 %
1791 */
1792 ModuleExport void UnregisterTIFFImage(void)
1793 {
1794   (void) UnregisterMagickInfo("RAWGROUP4");
1795   (void) UnregisterMagickInfo("PTIF");
1796   (void) UnregisterMagickInfo("TIF");
1797   (void) UnregisterMagickInfo("TIFF");
1798   (void) UnregisterMagickInfo("TIFF64");
1799   if (tiff_semaphore == (SemaphoreInfo *) NULL)
1800     tiff_semaphore=AllocateSemaphoreInfo();
1801   LockSemaphoreInfo(tiff_semaphore);
1802   if (instantiate_key != MagickFalse)
1803     if (MagickDeleteThreadKey(tiff_exception) == MagickFalse)
1804       ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1805   instantiate_key=MagickFalse;
1806   UnlockSemaphoreInfo(tiff_semaphore);
1807   DestroySemaphoreInfo(&tiff_semaphore);
1808 }
1809 \f
1810 #if defined(MAGICKCORE_TIFF_DELEGATE)
1811 /*
1812 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1813 %                                                                             %
1814 %                                                                             %
1815 %                                                                             %
1816 %   W r i t e G R O U P 4 I m a g e                                           %
1817 %                                                                             %
1818 %                                                                             %
1819 %                                                                             %
1820 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1821 %
1822 %  WriteGROUP4Image() writes an image in the raw CCITT Group 4 image format.
1823 %
1824 %  The format of the WriteGROUP4Image method is:
1825 %
1826 %      MagickBooleanType WriteGROUP4Image(const ImageInfo *image_info,
1827 %        Image *image)
1828 %
1829 %  A description of each parameter follows:
1830 %
1831 %    o image_info: the image info.
1832 %
1833 %    o image:  The image.
1834 %
1835 */
1836 static MagickBooleanType WriteGROUP4Image(const ImageInfo *image_info,
1837   Image *image)
1838 {
1839   char
1840     filename[MaxTextExtent];
1841
1842   FILE
1843     *file;
1844
1845   Image
1846     *huffman_image;
1847
1848   ImageInfo
1849     *write_info;
1850
1851   int
1852     unique_file;
1853
1854   MagickBooleanType
1855     status;
1856
1857   register ssize_t
1858     i;
1859
1860   ssize_t
1861     count;
1862
1863   TIFF
1864     *tiff;
1865
1866   toff_t
1867     *byte_count,
1868     strip_size;
1869
1870   unsigned char
1871     *buffer;
1872
1873   /*
1874     Write image as CCITT Group4 TIFF image to a temporary file.
1875   */
1876   assert(image_info != (const ImageInfo *) NULL);
1877   assert(image_info->signature == MagickSignature);
1878   assert(image != (Image *) NULL);
1879   assert(image->signature == MagickSignature);
1880   if (image->debug != MagickFalse)
1881     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1882   status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1883   if (status == MagickFalse)
1884     return(status);
1885   huffman_image=CloneImage(image,0,0,MagickTrue,&image->exception);
1886   if (huffman_image == (Image *) NULL)
1887     {
1888       (void) CloseBlob(image);
1889       return(MagickFalse);
1890     }
1891   huffman_image->endian=MSBEndian;
1892   file=(FILE *) NULL;
1893   unique_file=AcquireUniqueFileResource(filename);
1894   if (unique_file != -1)
1895     file=fdopen(unique_file,"wb");
1896   if ((unique_file == -1) || (file == (FILE *) NULL))
1897     {
1898       ThrowFileException(&image->exception,FileOpenError,
1899         "UnableToCreateTemporaryFile",filename);
1900       return(MagickFalse);
1901     }
1902   (void) FormatMagickString(huffman_image->filename,MaxTextExtent,"tiff:%s",
1903     filename);
1904   (void) SetImageType(huffman_image,BilevelType);
1905   write_info=CloneImageInfo((ImageInfo *) NULL);
1906   SetImageInfoFile(write_info,file);
1907   write_info->compression=Group4Compression;
1908   write_info->type=BilevelType;
1909   (void) SetImageOption(write_info,"quantum:polarity","min-is-white");
1910   status=WriteTIFFImage(write_info,huffman_image);
1911   (void) fflush(file);
1912   write_info=DestroyImageInfo(write_info);
1913   if (status == MagickFalse)
1914     {
1915       InheritException(&image->exception,&huffman_image->exception);
1916       huffman_image=DestroyImage(huffman_image);
1917       (void) fclose(file);
1918       (void) RelinquishUniqueFileResource(filename);
1919       return(MagickFalse);
1920     }
1921   tiff=TIFFOpen(filename,"rb");
1922   if (tiff == (TIFF *) NULL)
1923     {
1924       huffman_image=DestroyImage(huffman_image);
1925       (void) fclose(file);
1926       (void) RelinquishUniqueFileResource(filename);
1927       ThrowFileException(&image->exception,FileOpenError,"UnableToOpenFile",
1928         image_info->filename);
1929       return(MagickFalse);
1930     }
1931   /*
1932     Allocate raw strip buffer.
1933   */
1934   if (TIFFGetField(tiff,TIFFTAG_STRIPBYTECOUNTS,&byte_count) != 1)
1935     {
1936       TIFFClose(tiff);
1937       huffman_image=DestroyImage(huffman_image);
1938       (void) fclose(file);
1939       (void) RelinquishUniqueFileResource(filename);
1940       return(MagickFalse);
1941     }
1942   strip_size=byte_count[0];
1943   for (i=1; i < (ssize_t) TIFFNumberOfStrips(tiff); i++)
1944     if (byte_count[i] > strip_size)
1945       strip_size=byte_count[i];
1946   buffer=(unsigned char *) AcquireQuantumMemory((size_t) strip_size,
1947     sizeof(*buffer));
1948   if (buffer == (unsigned char *) NULL)
1949     {
1950       TIFFClose(tiff);
1951       huffman_image=DestroyImage(huffman_image);
1952       (void) fclose(file);
1953       (void) RelinquishUniqueFileResource(filename);
1954       ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1955         image_info->filename);
1956     }
1957   /*
1958     Compress runlength encoded to 2D Huffman pixels.
1959   */
1960   for (i=0; i < (ssize_t) TIFFNumberOfStrips(tiff); i++)
1961   {
1962     count=(ssize_t) TIFFReadRawStrip(tiff,(uint32) i,buffer,strip_size);
1963     if (WriteBlob(image,(size_t) count,buffer) != count)
1964       status=MagickFalse;
1965   }
1966   buffer=(unsigned char *) RelinquishMagickMemory(buffer);
1967   TIFFClose(tiff);
1968   huffman_image=DestroyImage(huffman_image);
1969   (void) fclose(file);
1970   (void) RelinquishUniqueFileResource(filename);
1971   (void) CloseBlob(image);
1972   return(status);
1973 }
1974 #endif
1975 \f
1976 #if defined(MAGICKCORE_TIFF_DELEGATE)
1977 /*
1978 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1979 %                                                                             %
1980 %                                                                             %
1981 %                                                                             %
1982 %   W r i t e P T I F I m a g e                                               %
1983 %                                                                             %
1984 %                                                                             %
1985 %                                                                             %
1986 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1987 %
1988 %  WritePTIFImage() writes an image in the pyrimid-encoded Tagged image file
1989 %  format.
1990 %
1991 %  The format of the WritePTIFImage method is:
1992 %
1993 %      MagickBooleanType WritePTIFImage(const ImageInfo *image_info,
1994 %        Image *image)
1995 %
1996 %  A description of each parameter follows:
1997 %
1998 %    o image_info: the image info.
1999 %
2000 %    o image:  The image.
2001 %
2002 */
2003 static MagickBooleanType WritePTIFImage(const ImageInfo *image_info,
2004   Image *image)
2005 {
2006   Image
2007     *images,
2008     *next,
2009     *pyramid_image;
2010
2011   ImageInfo
2012     *write_info;
2013
2014   MagickBooleanType
2015     status;
2016
2017   size_t
2018     columns,
2019     rows;
2020
2021   /*
2022     Create pyramid-encoded TIFF image.
2023   */
2024   images=NewImageList();
2025   for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
2026   {
2027     AppendImageToList(&images,CloneImage(next,0,0,MagickFalse,
2028       &image->exception));
2029     columns=next->columns;
2030     rows=next->rows;
2031     while ((columns > 64) && (rows > 64))
2032     {
2033       columns/=2;
2034       rows/=2;
2035       pyramid_image=ResizeImage(next,columns,rows,UndefinedFilter,image->blur,
2036         &image->exception);
2037       AppendImageToList(&images,pyramid_image);
2038     }
2039   }
2040   /*
2041     Write pyramid-encoded TIFF image.
2042   */
2043   write_info=CloneImageInfo(image_info);
2044   *write_info->magick='\0';
2045   write_info->adjoin=MagickTrue;
2046   status=WriteTIFFImage(write_info,GetFirstImageInList(images));
2047   images=DestroyImageList(images);
2048   write_info=DestroyImageInfo(write_info);
2049   return(status);
2050 }
2051 #endif
2052 \f
2053 #if defined(MAGICKCORE_TIFF_DELEGATE)
2054 /*
2055 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2056 %                                                                             %
2057 %                                                                             %
2058 %   W r i t e T I F F I m a g e                                               %
2059 %                                                                             %
2060 %                                                                             %
2061 %                                                                             %
2062 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2063 %
2064 %  WriteTIFFImage() writes an image in the Tagged image file format.
2065 %
2066 %  The format of the WriteTIFFImage method is:
2067 %
2068 %      MagickBooleanType WriteTIFFImage(const ImageInfo *image_info,
2069 %        Image *image)
2070 %
2071 %  A description of each parameter follows:
2072 %
2073 %    o image_info: the image info.
2074 %
2075 %    o image:  The image.
2076 %
2077 */
2078
2079 typedef struct _TIFFInfo
2080 {
2081   RectangleInfo
2082     tile_geometry;
2083
2084   unsigned char
2085     *scanline,
2086     *scanlines,
2087     *pixels;
2088 } TIFFInfo;
2089
2090 static void DestroyTIFFInfo(TIFFInfo *tiff_info)
2091 {
2092   assert(tiff_info != (TIFFInfo *) NULL);
2093   if (tiff_info->scanlines != (unsigned char *) NULL)
2094     tiff_info->scanlines=(unsigned char *) RelinquishMagickMemory(
2095       tiff_info->scanlines);
2096   if (tiff_info->pixels != (unsigned char *) NULL)
2097     tiff_info->pixels=(unsigned char *) RelinquishMagickMemory(
2098       tiff_info->pixels);
2099 }
2100
2101 static MagickBooleanType GetTIFFInfo(const ImageInfo *image_info,TIFF *tiff,
2102   TIFFInfo *tiff_info)
2103 {
2104   const char
2105     *option;
2106
2107   MagickStatusType
2108     flags;
2109
2110   assert(tiff_info != (TIFFInfo *) NULL);
2111   (void) ResetMagickMemory(tiff_info,0,sizeof(*tiff_info));
2112   option=GetImageOption(image_info,"tiff:tile-geometry");
2113   if (option == (const char *) NULL)
2114     return(MagickTrue);
2115   flags=ParseAbsoluteGeometry(option,&tiff_info->tile_geometry);
2116   if ((flags & HeightValue) == 0)
2117     tiff_info->tile_geometry.height=tiff_info->tile_geometry.width;
2118   (void) TIFFSetField(tiff,TIFFTAG_TILEWIDTH,(uint32)
2119     tiff_info->tile_geometry.width);
2120   (void) TIFFSetField(tiff,TIFFTAG_TILELENGTH,(uint32)
2121     tiff_info->tile_geometry.height);
2122   tiff_info->scanlines=(unsigned char *) AcquireQuantumMemory((size_t)
2123     tiff_info->tile_geometry.height*TIFFScanlineSize(tiff),
2124     sizeof(*tiff_info->scanlines));
2125   tiff_info->pixels=(unsigned char *) AcquireQuantumMemory((size_t)
2126     TIFFTileSize(tiff),sizeof(*tiff_info->scanlines));
2127   if ((tiff_info->scanlines == (unsigned char *) NULL) ||
2128       (tiff_info->pixels == (unsigned char *) NULL))
2129     {
2130       DestroyTIFFInfo(tiff_info);
2131       return(MagickFalse);
2132     }
2133   return(MagickTrue);
2134 }
2135
2136 static int32 TIFFWritePixels(TIFF *tiff,TIFFInfo *tiff_info,ssize_t row,
2137   tsample_t sample,Image *image)
2138 {
2139   int32
2140     status;
2141
2142   ssize_t
2143     bytes_per_pixel,
2144     j,
2145     k,
2146     l;
2147
2148   register ssize_t
2149     i;
2150
2151   register unsigned char
2152     *p,
2153     *q;
2154
2155   size_t
2156     number_tiles,
2157     tile_width;
2158
2159   if (TIFFIsTiled(tiff) == 0)
2160     return(TIFFWriteScanline(tiff,tiff_info->scanline,(uint32) row,sample));
2161   /*
2162     Fill scanlines to tile height.
2163   */
2164   i=(ssize_t) (row % tiff_info->tile_geometry.height)*TIFFScanlineSize(tiff);
2165   (void) CopyMagickMemory(tiff_info->scanlines+i,(char *) tiff_info->scanline,
2166     (size_t) TIFFScanlineSize(tiff));
2167   if (((size_t) (row % tiff_info->tile_geometry.height) !=
2168       (tiff_info->tile_geometry.height-1)) && (row != (ssize_t) (image->rows-1)))
2169     return(0);
2170   /*
2171     Write tile to TIFF image.
2172   */
2173   status=0;
2174   bytes_per_pixel=TIFFTileSize(tiff)/(ssize_t) (tiff_info->tile_geometry.height*
2175     tiff_info->tile_geometry.width);
2176   number_tiles=(image->columns+tiff_info->tile_geometry.width)/
2177     tiff_info->tile_geometry.width;
2178   for (i=0; i < (ssize_t) number_tiles; i++)
2179   {
2180     tile_width=(i == (ssize_t) (number_tiles-1)) ? image->columns-(i*
2181       tiff_info->tile_geometry.width) : tiff_info->tile_geometry.width;
2182     for (j=0; j < (ssize_t) ((row % tiff_info->tile_geometry.height)+1); j++)
2183       for (k=0; k < (ssize_t) tile_width; k++)
2184       {
2185         if (bytes_per_pixel == 0)
2186           {
2187             p=tiff_info->scanlines+(j*TIFFScanlineSize(tiff)+(i*
2188               tiff_info->tile_geometry.width+k)/8);
2189             q=tiff_info->pixels+(j*TIFFTileRowSize(tiff)+k/8);
2190             *q++=(*p++);
2191             continue;
2192           }
2193         p=tiff_info->scanlines+(j*TIFFScanlineSize(tiff)+(i*
2194           tiff_info->tile_geometry.width+k)*bytes_per_pixel);
2195         q=tiff_info->pixels+(j*TIFFTileRowSize(tiff)+k*bytes_per_pixel);
2196         for (l=0; l < bytes_per_pixel; l++)
2197           *q++=(*p++);
2198       }
2199     if ((i*tiff_info->tile_geometry.width) != image->columns)
2200       status=TIFFWriteTile(tiff,tiff_info->pixels,(uint32) (i*
2201         tiff_info->tile_geometry.width),(uint32) ((row/
2202         tiff_info->tile_geometry.height)*tiff_info->tile_geometry.height),0,
2203         sample);
2204     if (status < 0)
2205       break;
2206   }
2207   return(status);
2208 }
2209
2210 static void TIFFSetProfiles(TIFF *tiff,Image *image)
2211 {
2212   const char
2213     *name;
2214
2215   const StringInfo
2216     *profile;
2217
2218   if (image->profiles == (void *) NULL)
2219     return;
2220   ResetImageProfileIterator(image);
2221   for (name=GetNextImageProfile(image); name != (const char *) NULL; )
2222   {
2223     profile=GetImageProfile(image,name);
2224 #if defined(TIFFTAG_XMLPACKET)
2225     if (LocaleCompare(name,"xmp") == 0)
2226       (void) TIFFSetField(tiff,TIFFTAG_XMLPACKET,(uint32) GetStringInfoLength(
2227         profile),GetStringInfoDatum(profile));
2228 #endif
2229 #if defined(TIFFTAG_ICCPROFILE)
2230     if (LocaleCompare(name,"icc") == 0)
2231       (void) TIFFSetField(tiff,TIFFTAG_ICCPROFILE,(uint32) GetStringInfoLength(
2232         profile),GetStringInfoDatum(profile));
2233 #endif
2234     if (LocaleCompare(name,"iptc") == 0)
2235       {
2236         size_t
2237           length;
2238
2239         StringInfo
2240           *iptc_profile;
2241
2242         iptc_profile=CloneStringInfo(profile);
2243         length=GetStringInfoLength(profile)+4-(GetStringInfoLength(profile) &
2244           0x03);
2245         SetStringInfoLength(iptc_profile,length);
2246         if (TIFFIsByteSwapped(tiff))
2247           TIFFSwabArrayOfLong((uint32 *) GetStringInfoDatum(iptc_profile),
2248             (unsigned long) (length/4));
2249         (void) TIFFSetField(tiff,TIFFTAG_RICHTIFFIPTC,(uint32)
2250           GetStringInfoLength(iptc_profile)/4,GetStringInfoDatum(iptc_profile));
2251         iptc_profile=DestroyStringInfo(iptc_profile);
2252       }
2253 #if defined(TIFFTAG_PHOTOSHOP)
2254     if (LocaleCompare(name,"8bim") == 0)
2255       (void) TIFFSetField(tiff,TIFFTAG_PHOTOSHOP,(uint32)
2256         GetStringInfoLength(profile),GetStringInfoDatum(profile));
2257 #endif
2258     if (LocaleCompare(name,"tiff:37724") == 0)
2259       (void) TIFFSetField(tiff,37724,(uint32)GetStringInfoLength(profile),
2260         GetStringInfoDatum(profile));
2261     name=GetNextImageProfile(image);
2262   }
2263 }
2264
2265 static void TIFFSetProperties(TIFF *tiff,Image *image)
2266 {
2267   const char
2268     *value;
2269
2270   value=GetImageProperty(image,"tiff:hostcomputer");
2271   if (value != (const char *) NULL)
2272     (void) TIFFSetField(tiff,TIFFTAG_HOSTCOMPUTER,value);
2273   value=GetImageProperty(image,"tiff:artist");
2274   if (value != (const char *) NULL)
2275     (void) TIFFSetField(tiff,TIFFTAG_ARTIST,value);
2276   value=GetImageProperty(image,"tiff:timestamp");
2277   if (value != (const char *) NULL)
2278     (void) TIFFSetField(tiff,TIFFTAG_DATETIME,value);
2279   value=GetImageProperty(image,"tiff:make");
2280   if (value != (const char *) NULL)
2281     (void) TIFFSetField(tiff,TIFFTAG_MAKE,value);
2282   value=GetImageProperty(image,"tiff:model");
2283   if (value != (const char *) NULL)
2284     (void) TIFFSetField(tiff,TIFFTAG_MODEL,value);
2285   (void) TIFFSetField(tiff,TIFFTAG_SOFTWARE,
2286     GetMagickVersion((size_t *) NULL));
2287   (void) TIFFSetField(tiff,TIFFTAG_DOCUMENTNAME,image->filename);
2288   value=GetImageProperty(image,"tiff:copyright");
2289   if (value != (const char *) NULL)
2290     (void) TIFFSetField(tiff,33432,value);
2291   value=GetImageProperty(image,"kodak-33423");
2292   if (value != (const char *) NULL)
2293     (void) TIFFSetField(tiff,33423,value);
2294   value=GetImageProperty(image,"kodak-36867");
2295   if (value != (const char *) NULL)
2296     (void) TIFFSetField(tiff,36867,value);
2297   value=GetImageProperty(image,"label");
2298   if (value != (const char *) NULL)
2299     (void) TIFFSetField(tiff,TIFFTAG_PAGENAME,value);
2300   value=GetImageProperty(image,"comment");
2301   if (value != (const char *) NULL)
2302     (void) TIFFSetField(tiff,TIFFTAG_IMAGEDESCRIPTION,value);
2303 }
2304
2305 static void TIFFSetEXIFProperties(TIFF *tiff,Image *image)
2306 {
2307 #if defined(MAGICKCORE_HAVE_TIFFREADEXIFDIRECTORY)
2308   const char
2309     *value;
2310
2311   register ssize_t
2312     i;
2313
2314   uint32
2315     offset;
2316
2317   /*
2318     Write EXIF properties.
2319   */
2320   offset=0;
2321   (void) TIFFSetField(tiff,TIFFTAG_SUBIFD,1,&offset);
2322   for (i=0; exif_info[i].tag != 0; i++)
2323   {
2324     value=GetImageProperty(image,exif_info[i].property);
2325     if (value == (const char *) NULL)
2326       continue;
2327     switch (exif_info[i].type)
2328     {
2329       case TIFF_ASCII:
2330       {
2331         (void) TIFFSetField(tiff,exif_info[i].tag,value);
2332         break;
2333       }
2334       case TIFF_SHORT:
2335       {
2336         uint16
2337           shorty;
2338
2339         shorty=(uint16) StringToLong(value);
2340         (void) TIFFSetField(tiff,exif_info[i].tag,shorty);
2341         break;
2342       }
2343       case TIFF_LONG:
2344       {
2345         uint16
2346           ssize_ty;
2347
2348         ssize_ty=(uint16) StringToLong(value);
2349         (void) TIFFSetField(tiff,exif_info[i].tag,ssize_ty);
2350         break;
2351       }
2352       case TIFF_RATIONAL:
2353       case TIFF_SRATIONAL:
2354       {
2355         float
2356           rational;
2357
2358         rational=StringToDouble(value);
2359         (void) TIFFSetField(tiff,exif_info[i].tag,rational);
2360         break;
2361       }
2362       default:
2363         break;
2364     }
2365   }
2366   /* (void) TIFFSetField(tiff,TIFFTAG_EXIFIFD,offset); */
2367 #else
2368   (void) tiff;
2369   (void) image;
2370 #endif
2371 }
2372
2373 static MagickBooleanType WriteTIFFImage(const ImageInfo *image_info,
2374   Image *image)
2375 {
2376 #if !defined(TIFFDefaultStripSize)
2377 #define TIFFDefaultStripSize(tiff,request)  (8192UL/TIFFScanlineSize(tiff))
2378 #endif
2379
2380   const char
2381     *mode,
2382     *option;
2383
2384   CompressionType
2385     compression;
2386
2387   EndianType
2388     endian_type;
2389
2390   ssize_t
2391     y;
2392
2393   MagickBooleanType
2394     debug,
2395     status;
2396
2397   MagickOffsetType
2398     scene;
2399
2400   QuantumInfo
2401     *quantum_info;
2402
2403   QuantumType
2404     quantum_type;
2405
2406   register ssize_t
2407     i;
2408
2409   size_t
2410     length;
2411
2412   TIFF
2413     *tiff;
2414
2415   TIFFErrorHandler
2416     error_handler,
2417     warning_handler;
2418
2419   TIFFInfo
2420     tiff_info;
2421
2422   uint16
2423     bits_per_sample,
2424     compress_tag,
2425     endian,
2426     photometric;
2427
2428   uint32
2429     rows_per_strip;
2430
2431   unsigned char
2432     *pixels;
2433
2434   size_t
2435     lsb_first;
2436
2437   /*
2438     Open TIFF file.
2439   */
2440   assert(image_info != (const ImageInfo *) NULL);
2441   assert(image_info->signature == MagickSignature);
2442   assert(image != (Image *) NULL);
2443   assert(image->signature == MagickSignature);
2444   if (image->debug != MagickFalse)
2445     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2446   status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
2447   if (status == MagickFalse)
2448     return(status);
2449   (void) MagickSetThreadValue(tiff_exception,&image->exception);
2450   error_handler=TIFFSetErrorHandler((TIFFErrorHandler) TIFFErrors);
2451   warning_handler=TIFFSetWarningHandler((TIFFErrorHandler) TIFFWarnings);
2452   endian_type=UndefinedEndian;
2453   option=GetImageOption(image_info,"tiff:endian");
2454   if (option != (const char *) NULL)
2455     {
2456       if (LocaleNCompare(option,"msb",3) == 0)
2457         endian_type=MSBEndian;
2458       if (LocaleNCompare(option,"lsb",3) == 0)
2459         endian_type=LSBEndian;;
2460     }
2461   switch (endian_type)
2462   {
2463     case LSBEndian: mode="wl"; break;
2464     case MSBEndian: mode="wb"; break;
2465     default: mode="w"; break;
2466   }
2467 #if defined(TIFF_VERSION_BIG)
2468   if (LocaleCompare(image_info->magick,"TIFF64") == 0)
2469     switch (endian_type)
2470     {
2471       case LSBEndian: mode="wl8"; break;
2472       case MSBEndian: mode="wb8"; break;
2473       default: mode="w8"; break;
2474     }
2475 #endif
2476   tiff=TIFFClientOpen(image->filename,mode,(thandle_t) image,TIFFReadBlob,
2477     TIFFWriteBlob,TIFFSeekBlob,TIFFCloseBlob,TIFFGetBlobSize,TIFFMapBlob,
2478     TIFFUnmapBlob);
2479   if (tiff == (TIFF *) NULL)
2480     {
2481       (void) TIFFSetWarningHandler(warning_handler);
2482       (void) TIFFSetErrorHandler(error_handler);
2483       return(MagickFalse);
2484     }
2485   scene=0;
2486   debug=IsEventLogging();
2487   do
2488   {
2489     /*
2490       Initialize TIFF fields.
2491     */
2492     if ((image_info->type != UndefinedType) &&
2493         (image_info->type != OptimizeType))
2494       (void) SetImageType(image,image_info->type);
2495     quantum_info=AcquireQuantumInfo(image_info,image);
2496     if (quantum_info == (QuantumInfo *) NULL)
2497       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2498     if ((image->storage_class != PseudoClass) && (image->depth >= 32) &&
2499         (quantum_info->format == UndefinedQuantumFormat) &&
2500         (IsHighDynamicRangeImage(image,&image->exception) != MagickFalse))
2501       {
2502         status=SetQuantumFormat(image,quantum_info,FloatingPointQuantumFormat);
2503         if (status == MagickFalse)
2504           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2505       }
2506     if ((LocaleCompare(image_info->magick,"PTIF") == 0) &&
2507         (GetPreviousImageInList(image) != (Image *) NULL))
2508       (void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_REDUCEDIMAGE);
2509     if ((image->columns != (uint32) image->columns) ||
2510         (image->rows != (uint32) image->rows))
2511       ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
2512     (void) TIFFSetField(tiff,TIFFTAG_IMAGELENGTH,(uint32) image->rows);
2513     (void) TIFFSetField(tiff,TIFFTAG_IMAGEWIDTH,(uint32) image->columns);
2514     compression=image->compression;
2515     if (image_info->compression != UndefinedCompression)
2516       compression=image_info->compression;
2517     switch (compression)
2518     {
2519       case FaxCompression:
2520       {
2521         compress_tag=COMPRESSION_CCITTFAX3;
2522         SetQuantumMinIsWhite(quantum_info,MagickTrue);
2523         break;
2524       }
2525       case Group4Compression:
2526       {
2527         compress_tag=COMPRESSION_CCITTFAX4;
2528         SetQuantumMinIsWhite(quantum_info,MagickTrue);
2529         break;
2530       }
2531       case JPEGCompression:
2532       {
2533         compress_tag=COMPRESSION_JPEG;
2534         break;
2535       }
2536       case LZWCompression:
2537       {
2538         compress_tag=COMPRESSION_LZW;
2539         break;
2540       }
2541       case RLECompression:
2542       {
2543         compress_tag=COMPRESSION_PACKBITS;
2544         break;
2545       }
2546       case ZipCompression:
2547       {
2548         compress_tag=COMPRESSION_ADOBE_DEFLATE;
2549         break;
2550       }
2551       case NoCompression:
2552       default:
2553       {
2554         compress_tag=COMPRESSION_NONE;
2555         break;
2556       }
2557     }
2558 #if defined(MAGICKCORE_HAVE_TIFFISCODECCONFIGURED) || (TIFFLIB_VERSION > 20040919)
2559     if ((compress_tag != COMPRESSION_NONE) &&
2560         (TIFFIsCODECConfigured(compress_tag) == 0))
2561       {
2562         (void) ThrowMagickException(&image->exception,GetMagickModule(),
2563           CoderError,"CompressionNotSupported","`%s'",MagickOptionToMnemonic(
2564           MagickCompressOptions,(ssize_t) compression));
2565         compress_tag=COMPRESSION_NONE;
2566         compression=NoCompression;
2567       }
2568 #else
2569       switch (compress_tag)
2570       {
2571 #if defined(CCITT_SUPPORT)
2572         case COMPRESSION_CCITTFAX3:
2573         case COMPRESSION_CCITTFAX4:
2574 #endif
2575 #if defined(YCBCR_SUPPORT) && defined(JPEG_SUPPORT)
2576         case COMPRESSION_JPEG:
2577 #endif
2578 #if defined(LZW_SUPPORT)
2579         case COMPRESSION_LZW:
2580 #endif
2581 #if defined(PACKBITS_SUPPORT)
2582         case COMPRESSION_PACKBITS:
2583 #endif
2584 #if defined(ZIP_SUPPORT)
2585         case COMPRESSION_ADOBE_DEFLATE:
2586 #endif
2587         case COMPRESSION_NONE:
2588           break;
2589         default:
2590         {
2591           (void) ThrowMagickException(&image->exception,GetMagickModule(),
2592             CoderError,"CompressionNotSupported","`%s'",MagickOptionToMnemonic(
2593               MagickCompressOptions,(ssize_t) compression));
2594           compress_tag=COMPRESSION_NONE;
2595           compression=NoCompression;
2596           break;
2597         }
2598       }
2599 #endif
2600     switch (compression)
2601     {
2602       case FaxCompression:
2603       case Group4Compression:
2604       {
2605         (void) SetImageType(image,BilevelType);
2606         break;
2607       }
2608       case JPEGCompression:
2609       {
2610         (void) SetImageStorageClass(image,DirectClass);
2611         (void) SetImageDepth(image,8);
2612         break;
2613       }
2614       default:
2615         break;
2616     }
2617     if (image->colorspace == CMYKColorspace)
2618       {
2619         photometric=PHOTOMETRIC_SEPARATED;
2620         (void) TIFFSetField(tiff,TIFFTAG_SAMPLESPERPIXEL,4);
2621         (void) TIFFSetField(tiff,TIFFTAG_INKSET,INKSET_CMYK);
2622       }
2623     else
2624       {
2625         /*
2626           Full color TIFF raster.
2627         */
2628         if (image->colorspace == LabColorspace)
2629           photometric=PHOTOMETRIC_CIELAB;
2630         else
2631           if (image->colorspace == YCbCrColorspace)
2632             {
2633               photometric=PHOTOMETRIC_YCBCR;
2634               (void) TIFFSetField(tiff,TIFFTAG_YCBCRSUBSAMPLING,1,1);
2635               (void) SetImageDepth(image,8);
2636             }
2637           else
2638             {
2639               if (image->colorspace != RGBColorspace)
2640                 (void) TransformImageColorspace(image,RGBColorspace);
2641               photometric=PHOTOMETRIC_RGB;
2642             }
2643         (void) TIFFSetField(tiff,TIFFTAG_SAMPLESPERPIXEL,3);
2644         if ((image_info->type != TrueColorType) &&
2645             (image_info->type != TrueColorMatteType))
2646           {
2647             if ((image_info->type != PaletteType) &&
2648                 (IsGrayImage(image,&image->exception) != MagickFalse))
2649               {
2650                 photometric=(uint16) (quantum_info->min_is_white !=
2651                   MagickFalse ? PHOTOMETRIC_MINISWHITE :
2652                   PHOTOMETRIC_MINISBLACK);
2653                 (void) TIFFSetField(tiff,TIFFTAG_SAMPLESPERPIXEL,1);
2654                 if ((image_info->depth == 0) &&
2655                     (IsMonochromeImage(image,&image->exception) != MagickFalse))
2656                   {
2657                     status=SetQuantumDepth(image,quantum_info,1);
2658                     if (status == MagickFalse)
2659                       ThrowWriterException(ResourceLimitError,
2660                         "MemoryAllocationFailed");
2661                   }
2662               }
2663             else
2664               if (image->storage_class == PseudoClass)
2665                 {
2666                   size_t
2667                     depth;
2668
2669                   /*
2670                     Colormapped TIFF raster.
2671                   */
2672                   (void) TIFFSetField(tiff,TIFFTAG_SAMPLESPERPIXEL,1);
2673                   photometric=PHOTOMETRIC_PALETTE;
2674                   depth=1;
2675                   while ((GetQuantumRange(depth)+1) < image->colors)
2676                     depth<<=1;
2677                   status=SetQuantumDepth(image,quantum_info,depth);
2678                   if (status == MagickFalse)
2679                     ThrowWriterException(ResourceLimitError,
2680                       "MemoryAllocationFailed");
2681                 }
2682           }
2683       }
2684     switch (image->endian)
2685     {
2686       case LSBEndian:
2687       {
2688         endian=FILLORDER_LSB2MSB;
2689         break;
2690       }
2691       case MSBEndian:
2692       {
2693         endian=FILLORDER_MSB2LSB;
2694         break;
2695       }
2696       case UndefinedEndian:
2697       default:
2698       {
2699         (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_FILLORDER,&endian);
2700         break;
2701       }
2702     }
2703     lsb_first=1;
2704     image->endian=MSBEndian;
2705     if ((int) (*(char *) &lsb_first) != 0)
2706       image->endian=LSBEndian;
2707     if ((compress_tag == COMPRESSION_CCITTFAX3) &&
2708         (photometric != PHOTOMETRIC_MINISWHITE))
2709       {
2710         compress_tag=COMPRESSION_NONE;
2711         endian=FILLORDER_MSB2LSB;
2712       }
2713     else
2714       if ((compress_tag == COMPRESSION_CCITTFAX4) &&
2715          (photometric != PHOTOMETRIC_MINISWHITE))
2716        {
2717          compress_tag=COMPRESSION_NONE;
2718          endian=FILLORDER_MSB2LSB;
2719        }
2720     option=GetImageProperty(image,"tiff:fill-order");
2721     if (option != (const char *) NULL)
2722       {
2723         if (LocaleNCompare(option,"msb",3) == 0)
2724           endian=FILLORDER_MSB2LSB;
2725         if (LocaleNCompare(option,"lsb",3) == 0)
2726           endian=FILLORDER_LSB2MSB;
2727       }
2728     (void) TIFFSetField(tiff,TIFFTAG_COMPRESSION,compress_tag);
2729     (void) TIFFSetField(tiff,TIFFTAG_FILLORDER,endian);
2730     (void) TIFFSetField(tiff,TIFFTAG_BITSPERSAMPLE,quantum_info->depth);
2731     if (image->matte != MagickFalse)
2732       {
2733         uint16
2734           extra_samples,
2735           sample_info[1],
2736           samples_per_pixel;
2737
2738         /*
2739           TIFF has a matte channel.
2740         */
2741         extra_samples=1;
2742         sample_info[0]=EXTRASAMPLE_UNASSALPHA;
2743         option=GetImageProperty(image,"tiff:alpha");
2744         if ((option != (const char *) NULL) &&
2745             (LocaleCompare(option,"associated") == 0))
2746           sample_info[0]=EXTRASAMPLE_ASSOCALPHA;
2747         (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_SAMPLESPERPIXEL,
2748           &samples_per_pixel);
2749         (void) TIFFSetField(tiff,TIFFTAG_SAMPLESPERPIXEL,samples_per_pixel+1);
2750         (void) TIFFSetField(tiff,TIFFTAG_EXTRASAMPLES,extra_samples,
2751           &sample_info);
2752         if (sample_info[0] == EXTRASAMPLE_ASSOCALPHA)
2753           SetQuantumAlphaType(quantum_info,AssociatedQuantumAlpha);
2754       }
2755     (void) TIFFSetField(tiff,TIFFTAG_PHOTOMETRIC,photometric);
2756     switch (quantum_info->format)
2757     {
2758       case FloatingPointQuantumFormat:
2759       {
2760         (void) TIFFSetField(tiff,TIFFTAG_SAMPLEFORMAT,SAMPLEFORMAT_IEEEFP);
2761         (void) TIFFSetField(tiff,TIFFTAG_SMINSAMPLEVALUE,quantum_info->minimum);
2762         (void) TIFFSetField(tiff,TIFFTAG_SMAXSAMPLEVALUE,quantum_info->maximum);
2763         break;
2764       }
2765       case SignedQuantumFormat:
2766       {
2767         (void) TIFFSetField(tiff,TIFFTAG_SAMPLEFORMAT,SAMPLEFORMAT_INT);
2768         break;
2769       }
2770       case UnsignedQuantumFormat:
2771       {
2772         (void) TIFFSetField(tiff,TIFFTAG_SAMPLEFORMAT,SAMPLEFORMAT_UINT);
2773         break;
2774       }
2775       default:
2776         break;
2777     }
2778     (void) TIFFSetField(tiff,TIFFTAG_ORIENTATION,ORIENTATION_TOPLEFT);
2779     (void) TIFFSetField(tiff,TIFFTAG_PLANARCONFIG,PLANARCONFIG_CONTIG);
2780     if (photometric == PHOTOMETRIC_RGB)
2781       if ((image_info->interlace == PlaneInterlace) ||
2782           (image_info->interlace == PartitionInterlace))
2783         (void) TIFFSetField(tiff,TIFFTAG_PLANARCONFIG,PLANARCONFIG_SEPARATE);
2784     rows_per_strip=1;
2785     if (TIFFScanlineSize(tiff) != 0)
2786       rows_per_strip=(uint32) MagickMax((size_t) TIFFDefaultStripSize(tiff,0),
2787         1);
2788     option=GetImageOption(image_info,"tiff:rows-per-strip");
2789     if (option != (const char *) NULL)
2790       rows_per_strip=(size_t) strtol(option,(char **) NULL,10);
2791     switch (compress_tag)
2792     {
2793       case COMPRESSION_JPEG:
2794       {
2795 #if defined(JPEG_SUPPORT)
2796         const char
2797           *sampling_factor;
2798
2799         GeometryInfo
2800           geometry_info;
2801
2802         MagickStatusType
2803           flags;
2804
2805         rows_per_strip+=(16-(rows_per_strip % 16));
2806         if (image->quality != 0)
2807           (void) TIFFSetField(tiff,TIFFTAG_JPEGQUALITY,image->quality);
2808         if (image_info->quality != UndefinedCompressionQuality)
2809           (void) TIFFSetField(tiff,TIFFTAG_JPEGQUALITY,image_info->quality);
2810         (void) TIFFSetField(tiff,TIFFTAG_JPEGCOLORMODE,JPEGCOLORMODE_RAW);
2811         if (image->colorspace == RGBColorspace)
2812           {
2813             const char
2814               *value;
2815
2816             (void) TIFFSetField(tiff,TIFFTAG_JPEGCOLORMODE,JPEGCOLORMODE_RGB);
2817             sampling_factor=(const char *) NULL;
2818             value=GetImageProperty(image,"jpeg:sampling-factor");
2819             if (value != (char *) NULL)
2820               {
2821                 sampling_factor=value;
2822                 if (image->debug != MagickFalse)
2823                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2824                     "  Input sampling-factors=%s",sampling_factor);
2825               }
2826             if (image_info->sampling_factor != (char *) NULL)
2827               sampling_factor=image_info->sampling_factor;
2828             if (sampling_factor != (const char *) NULL)
2829               {
2830                 flags=ParseGeometry(sampling_factor,&geometry_info);
2831                 if ((flags & SigmaValue) == 0)
2832                   geometry_info.sigma=geometry_info.rho;
2833                 (void) TIFFSetField(tiff,TIFFTAG_YCBCRSUBSAMPLING,(uint16)
2834                   geometry_info.rho,(uint16) geometry_info.sigma);
2835               }
2836           }
2837         if (bits_per_sample == 12)
2838           (void) TIFFSetField(tiff,TIFFTAG_JPEGTABLESMODE,JPEGTABLESMODE_QUANT);
2839 #endif
2840         break;
2841       }
2842       case COMPRESSION_ADOBE_DEFLATE:
2843       {
2844         rows_per_strip=(uint32) image->rows;
2845         (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_BITSPERSAMPLE,
2846           &bits_per_sample);
2847         if (((photometric == PHOTOMETRIC_RGB) ||
2848              (photometric == PHOTOMETRIC_MINISBLACK)) &&
2849             ((bits_per_sample == 8) || (bits_per_sample == 16)))
2850           (void) TIFFSetField(tiff,TIFFTAG_PREDICTOR,2);
2851         (void) TIFFSetField(tiff,TIFFTAG_ZIPQUALITY,(long) (
2852           image_info->quality == UndefinedCompressionQuality ? 7 :
2853           MagickMin((ssize_t) image_info->quality/10,9)));
2854         break;
2855       }
2856       case COMPRESSION_CCITTFAX3:
2857       {
2858         /*
2859           Byte-aligned EOL.
2860         */
2861         rows_per_strip=(uint32) image->rows;
2862         (void) TIFFSetField(tiff,TIFFTAG_GROUP3OPTIONS,4);
2863         break;
2864       }
2865       case COMPRESSION_CCITTFAX4:
2866       {
2867         rows_per_strip=(uint32) image->rows;
2868         break;
2869       }
2870       case COMPRESSION_LZW:
2871       {
2872         (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_BITSPERSAMPLE,
2873           &bits_per_sample);
2874         if (((photometric == PHOTOMETRIC_RGB) ||
2875              (photometric == PHOTOMETRIC_MINISBLACK)) &&
2876             ((bits_per_sample == 8) || (bits_per_sample == 16)))
2877           (void) TIFFSetField(tiff,TIFFTAG_PREDICTOR,2);
2878         break;
2879       }
2880       default:
2881         break;
2882     }
2883     (void) TIFFSetField(tiff,TIFFTAG_ROWSPERSTRIP,rows_per_strip);
2884     if ((image->x_resolution != 0.0) && (image->y_resolution != 0.0))
2885       {
2886         unsigned short
2887           units;
2888
2889         /*
2890           Set image resolution.
2891         */
2892         units=RESUNIT_NONE;
2893         if (image->units == PixelsPerInchResolution)
2894           units=RESUNIT_INCH;
2895         if (image->units == PixelsPerCentimeterResolution)
2896           units=RESUNIT_CENTIMETER;
2897         (void) TIFFSetField(tiff,TIFFTAG_RESOLUTIONUNIT,(uint16) units);
2898         (void) TIFFSetField(tiff,TIFFTAG_XRESOLUTION,image->x_resolution);
2899         (void) TIFFSetField(tiff,TIFFTAG_YRESOLUTION,image->y_resolution);
2900         if ((image->page.x != 0) || (image->page.y != 0))
2901           {
2902             /*
2903               Set image position.
2904             */
2905             (void) TIFFSetField(tiff,TIFFTAG_XPOSITION,(float) image->page.x/
2906               image->x_resolution);
2907             (void) TIFFSetField(tiff,TIFFTAG_YPOSITION,(float) image->page.y/
2908               image->y_resolution);
2909           }
2910       }
2911     if (image->chromaticity.white_point.x != 0.0)
2912       {
2913         float
2914           chromaticity[6];
2915
2916         /*
2917           Set image chromaticity.
2918         */
2919         chromaticity[0]=(float) image->chromaticity.red_primary.x;
2920         chromaticity[1]=(float) image->chromaticity.red_primary.y;
2921         chromaticity[2]=(float) image->chromaticity.green_primary.x;
2922         chromaticity[3]=(float) image->chromaticity.green_primary.y;
2923         chromaticity[4]=(float) image->chromaticity.blue_primary.x;
2924         chromaticity[5]=(float) image->chromaticity.blue_primary.y;
2925         (void) TIFFSetField(tiff,TIFFTAG_PRIMARYCHROMATICITIES,chromaticity);
2926         chromaticity[0]=(float) image->chromaticity.white_point.x;
2927         chromaticity[1]=(float) image->chromaticity.white_point.y;
2928         (void) TIFFSetField(tiff,TIFFTAG_WHITEPOINT,chromaticity);
2929       }
2930     if ((image_info->adjoin != MagickFalse) && (GetImageListLength(image) > 1))
2931       {
2932         (void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_PAGE);
2933         if (image->scene != 0)
2934           (void) TIFFSetField(tiff,TIFFTAG_PAGENUMBER,(uint16) image->scene,
2935             GetImageListLength(image));
2936       }
2937     if (image->orientation != UndefinedOrientation)
2938       (void) TIFFSetField(tiff,TIFFTAG_ORIENTATION,(uint16) image->orientation);
2939     (void) TIFFSetProfiles(tiff,image);
2940     {
2941       uint16
2942         page,
2943         pages;
2944
2945       page=(uint16) scene;
2946       pages=(uint16) GetImageListLength(image);
2947       if ((image_info->adjoin != MagickFalse) && (pages > 1))
2948         (void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_PAGE);
2949       (void) TIFFSetField(tiff,TIFFTAG_PAGENUMBER,page,pages);
2950     }
2951     (void) TIFFSetProperties(tiff,image);
2952     if (0)
2953       (void) TIFFSetEXIFProperties(tiff,image);
2954     /*
2955       Write image scanlines.
2956     */
2957     if (GetTIFFInfo(image_info,tiff,&tiff_info) == MagickFalse)
2958       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2959     pixels=GetQuantumPixels(quantum_info);
2960     tiff_info.scanline=GetQuantumPixels(quantum_info);
2961     switch (photometric)
2962     {
2963       case PHOTOMETRIC_CIELAB:
2964       case PHOTOMETRIC_YCBCR:
2965       case PHOTOMETRIC_RGB:
2966       {
2967         /*
2968           RGB TIFF image.
2969         */
2970         switch (image_info->interlace)
2971         {
2972           case NoInterlace:
2973           default:
2974           {
2975             quantum_type=RGBQuantum;
2976             if (image->matte != MagickFalse)
2977               quantum_type=RGBAQuantum;
2978             for (y=0; y < (ssize_t) image->rows; y++)
2979             {
2980               register const PixelPacket
2981                 *restrict p;
2982
2983               p=GetVirtualPixels(image,0,y,image->columns,1,
2984                 &image->exception);
2985               if (p == (const PixelPacket *) NULL)
2986                 break;
2987               length=ExportQuantumPixels(image,(const CacheView *) NULL,
2988                 quantum_info,quantum_type,pixels,&image->exception);
2989               if (TIFFWritePixels(tiff,&tiff_info,y,0,image) == -1)
2990                 break;
2991               if (image->previous == (Image *) NULL)
2992                 {
2993                   status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
2994                     y,image->rows);
2995                   if (status == MagickFalse)
2996                     break;
2997                 }
2998             }
2999             break;
3000           }
3001           case PlaneInterlace:
3002           case PartitionInterlace:
3003           {
3004             /*
3005               Plane interlacing:  RRRRRR...GGGGGG...BBBBBB...
3006             */
3007             for (y=0; y < (ssize_t) image->rows; y++)
3008             {
3009               register const PixelPacket
3010                 *restrict p;
3011
3012               p=GetVirtualPixels(image,0,y,image->columns,1,
3013                 &image->exception);
3014               if (p == (const PixelPacket *) NULL)
3015                 break;
3016               length=ExportQuantumPixels(image,(const CacheView *) NULL,
3017                 quantum_info,RedQuantum,pixels,&image->exception);
3018               if (TIFFWritePixels(tiff,&tiff_info,y,0,image) == -1)
3019                 break;
3020             }
3021             if (image->previous == (Image *) NULL)
3022               {
3023                 status=SetImageProgress(image,SaveImageTag,100,400);
3024                 if (status == MagickFalse)
3025                   break;
3026               }
3027             for (y=0; y < (ssize_t) image->rows; y++)
3028             {
3029               register const PixelPacket
3030                 *restrict p;
3031
3032               p=GetVirtualPixels(image,0,y,image->columns,1,
3033                 &image->exception);
3034               if (p == (const PixelPacket *) NULL)
3035                 break;
3036               length=ExportQuantumPixels(image,(const CacheView *) NULL,
3037                 quantum_info,GreenQuantum,pixels,&image->exception);
3038               if (TIFFWritePixels(tiff,&tiff_info,y,1,image) == -1)
3039                 break;
3040             }
3041             if (image->previous == (Image *) NULL)
3042               {
3043                 status=SetImageProgress(image,SaveImageTag,200,400);
3044                 if (status == MagickFalse)
3045                   break;
3046               }
3047             for (y=0; y < (ssize_t) image->rows; y++)
3048             {
3049               register const PixelPacket
3050                 *restrict p;
3051
3052               p=GetVirtualPixels(image,0,y,image->columns,1,
3053                 &image->exception);
3054               if (p == (const PixelPacket *) NULL)
3055                 break;
3056               length=ExportQuantumPixels(image,(const CacheView *) NULL,
3057                 quantum_info,BlueQuantum,pixels,&image->exception);
3058               if (TIFFWritePixels(tiff,&tiff_info,y,2,image) == -1)
3059                 break;
3060             }
3061             if (image->previous == (Image *) NULL)
3062               {
3063                 status=SetImageProgress(image,SaveImageTag,300,400);
3064                 if (status == MagickFalse)
3065                   break;
3066               }
3067             if (image->matte != MagickFalse)
3068               for (y=0; y < (ssize_t) image->rows; y++)
3069               {
3070                 register const PixelPacket
3071                   *restrict p;
3072
3073                 p=GetVirtualPixels(image,0,y,image->columns,1,
3074                   &image->exception);
3075                 if (p == (const PixelPacket *) NULL)
3076                   break;
3077                 length=ExportQuantumPixels(image,(const CacheView *) NULL,
3078                   quantum_info,AlphaQuantum,pixels,&image->exception);
3079                 if (TIFFWritePixels(tiff,&tiff_info,y,3,image) == -1)
3080                   break;
3081               }
3082             if (image->previous == (Image *) NULL)
3083               {
3084                 status=SetImageProgress(image,SaveImageTag,400,400);
3085                 if (status == MagickFalse)
3086                   break;
3087               }
3088             break;
3089           }
3090         }
3091         break;
3092       }
3093       case PHOTOMETRIC_SEPARATED:
3094       {
3095         /*
3096           CMYK TIFF image.
3097         */
3098         quantum_type=CMYKQuantum;
3099         if (image->matte != MagickFalse)
3100           quantum_type=CMYKAQuantum;
3101         if (image->colorspace != CMYKColorspace)
3102           (void) TransformImageColorspace(image,CMYKColorspace);
3103         for (y=0; y < (ssize_t) image->rows; y++)
3104         {
3105           register const PixelPacket
3106             *restrict p;
3107
3108           p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
3109           if (p == (const PixelPacket *) NULL)
3110             break;
3111           length=ExportQuantumPixels(image,(const CacheView *) NULL,
3112             quantum_info,quantum_type,pixels,&image->exception);
3113           if (TIFFWritePixels(tiff,&tiff_info,y,0,image) == -1)
3114             break;
3115           if (image->previous == (Image *) NULL)
3116             {
3117               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
3118                 image->rows);
3119               if (status == MagickFalse)
3120                 break;
3121             }
3122         }
3123         break;
3124       }
3125       case PHOTOMETRIC_PALETTE:
3126       {
3127         uint16
3128           *blue,
3129           *green,
3130           *red;
3131
3132         /*
3133           Colormapped TIFF image.
3134         */
3135         red=(uint16 *) AcquireQuantumMemory(65536,sizeof(*red));
3136         green=(uint16 *) AcquireQuantumMemory(65536,sizeof(*green));
3137         blue=(uint16 *) AcquireQuantumMemory(65536,sizeof(*blue));
3138         if ((red == (uint16 *) NULL) || (green == (uint16 *) NULL) ||
3139             (blue == (uint16 *) NULL))
3140           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3141         /*
3142           Initialize TIFF colormap.
3143         */
3144         (void) ResetMagickMemory(red,0,65536*sizeof(*red));
3145         (void) ResetMagickMemory(green,0,65536*sizeof(*green));
3146         (void) ResetMagickMemory(blue,0,65536*sizeof(*blue));
3147         for (i=0; i < (ssize_t) image->colors; i++)
3148         {
3149           red[i]=ScaleQuantumToShort(image->colormap[i].red);
3150           green[i]=ScaleQuantumToShort(image->colormap[i].green);
3151           blue[i]=ScaleQuantumToShort(image->colormap[i].blue);
3152         }
3153         (void) TIFFSetField(tiff,TIFFTAG_COLORMAP,red,green,blue);
3154         red=(uint16 *) RelinquishMagickMemory(red);
3155         green=(uint16 *) RelinquishMagickMemory(green);
3156         blue=(uint16 *) RelinquishMagickMemory(blue);
3157       }
3158       default:
3159       {
3160         /*
3161           Convert PseudoClass packets to contiguous grayscale scanlines.
3162         */
3163         quantum_type=IndexQuantum;
3164         if (image->matte != MagickFalse)
3165           {
3166             if (photometric != PHOTOMETRIC_PALETTE)
3167               quantum_type=GrayAlphaQuantum;
3168             else
3169               quantum_type=IndexAlphaQuantum;
3170            }
3171          else
3172            if (photometric != PHOTOMETRIC_PALETTE)
3173              quantum_type=GrayQuantum;
3174         for (y=0; y < (ssize_t) image->rows; y++)
3175         {
3176           register const PixelPacket
3177             *restrict p;
3178
3179           p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
3180           if (p == (const PixelPacket *) NULL)
3181             break;
3182           length=ExportQuantumPixels(image,(const CacheView *) NULL,
3183             quantum_info,quantum_type,pixels,&image->exception);
3184           if (TIFFWritePixels(tiff,&tiff_info,y,0,image) == -1)
3185             break;
3186           if (image->previous == (Image *) NULL)
3187             {
3188               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
3189                 image->rows);
3190               if (status == MagickFalse)
3191                 break;
3192             }
3193         }
3194         break;
3195       }
3196     }
3197     quantum_info=DestroyQuantumInfo(quantum_info);
3198     DestroyTIFFInfo(&tiff_info);
3199     if (0 && (image_info->verbose == MagickTrue))
3200       TIFFPrintDirectory(tiff,stdout,MagickFalse);
3201     (void) TIFFWriteDirectory(tiff);
3202     image->endian=MSBEndian;
3203     if (endian == FILLORDER_LSB2MSB)
3204       image->endian=LSBEndian;
3205     image=SyncNextImageInList(image);
3206     if (image == (Image *) NULL)
3207       break;
3208     status=SetImageProgress(image,SaveImagesTag,scene++,
3209       GetImageListLength(image));
3210     if (status == MagickFalse)
3211       break;
3212   } while (image_info->adjoin != MagickFalse);
3213   (void) TIFFSetWarningHandler(warning_handler);
3214   (void) TIFFSetErrorHandler(error_handler);
3215   TIFFClose(tiff);
3216   return(MagickTrue);
3217 }
3218 #endif