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