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