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