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