]> 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/token.h"
83 #include "MagickCore/utility.h"
84 #if defined(MAGICKCORE_TIFF_DELEGATE)
85 # if defined(MAGICKCORE_HAVE_TIFFCONF_H)
86 #  include "tiffconf.h"
87 # endif
88 # include "tiff.h"
89 # include "tiffio.h"
90 # if !defined(COMPRESSION_ADOBE_DEFLATE)
91 #  define COMPRESSION_ADOBE_DEFLATE  8
92 # endif
93 # if !defined(PREDICTOR_HORIZONTAL)
94 # define PREDICTOR_HORIZONTAL  2
95 # endif
96 # if !defined(TIFFTAG_COPYRIGHT)
97 #  define TIFFTAG_COPYRIGHT  33432
98 # endif
99 # if !defined(TIFFTAG_OPIIMAGEID)
100 #  define TIFF_OPIIMAGEID  32781
101 # endif
102 \f
103 /*
104   Typedef declarations.
105 */
106 #if defined(MAGICKCORE_HAVE_TIFFREADEXIFDIRECTORY)
107 typedef struct _ExifInfo
108 {
109   unsigned int
110     tag,
111     type;
112
113   const char
114     *property;
115 } ExifInfo;
116
117 static const ExifInfo
118   exif_info[] = {
119     { EXIFTAG_EXPOSURETIME, TIFF_RATIONAL, "exif:ExposureTime" },
120     { EXIFTAG_FNUMBER, TIFF_RATIONAL, "exif:FNumber" },
121     { EXIFTAG_EXPOSUREPROGRAM, TIFF_SHORT, "exif:ExposureProgram" },
122     { EXIFTAG_SPECTRALSENSITIVITY, TIFF_ASCII, "exif:SpectralSensitivity" },
123     { EXIFTAG_ISOSPEEDRATINGS, TIFF_SHORT, "exif:ISOSpeedRatings" },
124     { EXIFTAG_OECF, TIFF_NOTYPE, "exif:OptoelectricConversionFactor" },
125     { EXIFTAG_EXIFVERSION, TIFF_NOTYPE, "exif:ExifVersion" },
126     { EXIFTAG_DATETIMEORIGINAL, TIFF_ASCII, "exif:DateTimeOriginal" },
127     { EXIFTAG_DATETIMEDIGITIZED, TIFF_ASCII, "exif:DateTimeDigitized" },
128     { EXIFTAG_COMPONENTSCONFIGURATION, TIFF_NOTYPE, "exif:ComponentsConfiguration" },
129     { EXIFTAG_COMPRESSEDBITSPERPIXEL, TIFF_RATIONAL, "exif:CompressedBitsPerPixel" },
130     { EXIFTAG_SHUTTERSPEEDVALUE, TIFF_SRATIONAL, "exif:ShutterSpeedValue" },
131     { EXIFTAG_APERTUREVALUE, TIFF_RATIONAL, "exif:ApertureValue" },
132     { EXIFTAG_BRIGHTNESSVALUE, TIFF_SRATIONAL, "exif:BrightnessValue" },
133     { EXIFTAG_EXPOSUREBIASVALUE, TIFF_SRATIONAL, "exif:ExposureBiasValue" },
134     { EXIFTAG_MAXAPERTUREVALUE, TIFF_RATIONAL, "exif:MaxApertureValue" },
135     { EXIFTAG_SUBJECTDISTANCE, TIFF_RATIONAL, "exif:SubjectDistance" },
136     { EXIFTAG_METERINGMODE, TIFF_SHORT, "exif:MeteringMode" },
137     { EXIFTAG_LIGHTSOURCE, TIFF_SHORT, "exif:LightSource" },
138     { EXIFTAG_FLASH, TIFF_SHORT, "exif:Flash" },
139     { EXIFTAG_FOCALLENGTH, TIFF_RATIONAL, "exif:FocalLength" },
140     { EXIFTAG_SUBJECTAREA, TIFF_NOTYPE, "exif:SubjectArea" },
141     { EXIFTAG_MAKERNOTE, TIFF_NOTYPE, "exif:MakerNote" },
142     { EXIFTAG_USERCOMMENT, TIFF_NOTYPE, "exif:UserComment" },
143     { EXIFTAG_SUBSECTIME, TIFF_ASCII, "exif:SubSecTime" },
144     { EXIFTAG_SUBSECTIMEORIGINAL, TIFF_ASCII, "exif:SubSecTimeOriginal" },
145     { EXIFTAG_SUBSECTIMEDIGITIZED, TIFF_ASCII, "exif:SubSecTimeDigitized" },
146     { EXIFTAG_FLASHPIXVERSION, TIFF_NOTYPE, "exif:FlashpixVersion" },
147     { EXIFTAG_PIXELXDIMENSION, TIFF_LONG, "exif:PixelXDimension" },
148     { EXIFTAG_PIXELXDIMENSION, TIFF_SHORT, "exif:PixelXDimension" },
149     { EXIFTAG_PIXELYDIMENSION, TIFF_LONG, "exif:PixelYDimension" },
150     { EXIFTAG_PIXELYDIMENSION, TIFF_SHORT, "exif:PixelYDimension" },
151     { EXIFTAG_RELATEDSOUNDFILE, TIFF_ASCII, "exif:RelatedSoundFile" },
152     { EXIFTAG_FLASHENERGY, TIFF_RATIONAL, "exif:FlashEnergy" },
153     { EXIFTAG_SPATIALFREQUENCYRESPONSE, TIFF_NOTYPE, "exif:SpatialFrequencyResponse" },
154     { EXIFTAG_FOCALPLANEXRESOLUTION, TIFF_RATIONAL, "exif:FocalPlaneXResolution" },
155     { EXIFTAG_FOCALPLANEYRESOLUTION, TIFF_RATIONAL, "exif:FocalPlaneYResolution" },
156     { EXIFTAG_FOCALPLANERESOLUTIONUNIT, TIFF_SHORT, "exif:FocalPlaneResolutionUnit" },
157     { EXIFTAG_SUBJECTLOCATION, TIFF_SHORT, "exif:SubjectLocation" },
158     { EXIFTAG_EXPOSUREINDEX, TIFF_RATIONAL, "exif:ExposureIndex" },
159     { EXIFTAG_SENSINGMETHOD, TIFF_SHORT, "exif:SensingMethod" },
160     { EXIFTAG_FILESOURCE, TIFF_NOTYPE, "exif:FileSource" },
161     { EXIFTAG_SCENETYPE, TIFF_NOTYPE, "exif:SceneType" },
162     { EXIFTAG_CFAPATTERN, TIFF_NOTYPE, "exif:CFAPattern" },
163     { EXIFTAG_CUSTOMRENDERED, TIFF_SHORT, "exif:CustomRendered" },
164     { EXIFTAG_EXPOSUREMODE, TIFF_SHORT, "exif:ExposureMode" },
165     { EXIFTAG_WHITEBALANCE, TIFF_SHORT, "exif:WhiteBalance" },
166     { EXIFTAG_DIGITALZOOMRATIO, TIFF_RATIONAL, "exif:DigitalZoomRatio" },
167     { EXIFTAG_FOCALLENGTHIN35MMFILM, TIFF_SHORT, "exif:FocalLengthIn35mmFilm" },
168     { EXIFTAG_SCENECAPTURETYPE, TIFF_SHORT, "exif:SceneCaptureType" },
169     { EXIFTAG_GAINCONTROL, TIFF_RATIONAL, "exif:GainControl" },
170     { EXIFTAG_CONTRAST, TIFF_SHORT, "exif:Contrast" },
171     { EXIFTAG_SATURATION, TIFF_SHORT, "exif:Saturation" },
172     { EXIFTAG_SHARPNESS, TIFF_SHORT, "exif:Sharpness" },
173     { EXIFTAG_DEVICESETTINGDESCRIPTION, TIFF_NOTYPE, "exif:DeviceSettingDescription" },
174     { EXIFTAG_SUBJECTDISTANCERANGE, TIFF_SHORT, "exif:SubjectDistanceRange" },
175     { EXIFTAG_IMAGEUNIQUEID, TIFF_ASCII, "exif:ImageUniqueID" },
176     { 0, 0, (char *) NULL }
177 };
178 #endif
179 #endif  /* MAGICKCORE_TIFF_DELEGATE */
180 \f
181 /*
182   Global declarations.
183 */
184 static MagickThreadKey
185   tiff_exception;
186
187 static SemaphoreInfo
188   *tiff_semaphore = (SemaphoreInfo *) NULL;
189
190 static volatile MagickBooleanType
191   instantiate_key = MagickFalse;
192 \f
193 /*
194   Forward declarations.
195 */
196 #if defined(MAGICKCORE_TIFF_DELEGATE)
197 static Image *
198   ReadTIFFImage(const ImageInfo *,ExceptionInfo *);
199
200 static MagickBooleanType
201   WriteGROUP4Image(const ImageInfo *,Image *,ExceptionInfo *),
202   WritePTIFImage(const ImageInfo *,Image *,ExceptionInfo *),
203   WriteTIFFImage(const ImageInfo *,Image *,ExceptionInfo *);
204 #endif
205 \f
206 /*
207 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
208 %                                                                             %
209 %                                                                             %
210 %                                                                             %
211 %   I s T I F F                                                               %
212 %                                                                             %
213 %                                                                             %
214 %                                                                             %
215 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
216 %
217 %  IsTIFF() returns MagickTrue if the image format type, identified by the
218 %  magick string, is TIFF.
219 %
220 %  The format of the IsTIFF method is:
221 %
222 %      MagickBooleanType IsTIFF(const unsigned char *magick,const size_t length)
223 %
224 %  A description of each parameter follows:
225 %
226 %    o magick: compare image format pattern against these bytes.
227 %
228 %    o length: Specifies the length of the magick string.
229 %
230 */
231 static MagickBooleanType IsTIFF(const unsigned char *magick,const size_t length)
232 {
233   if (length < 4)
234     return(MagickFalse);
235   if (memcmp(magick,"\115\115\000\052",4) == 0)
236     return(MagickTrue);
237   if (memcmp(magick,"\111\111\052\000",4) == 0)
238     return(MagickTrue);
239 #if defined(TIFF_VERSION_BIG)
240   if (length < 8)
241     return(MagickFalse);
242   if (memcmp(magick,"\115\115\000\053\000\010\000\000",8) == 0)
243     return(MagickTrue);
244   if (memcmp(magick,"\111\111\053\000\010\000\000\000",8) == 0)
245     return(MagickTrue);
246 #endif
247   return(MagickFalse);
248 }
249 \f
250 #if defined(MAGICKCORE_TIFF_DELEGATE)
251 /*
252 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
253 %                                                                             %
254 %                                                                             %
255 %                                                                             %
256 %   R e a d G R O U P 4 I m a g e                                             %
257 %                                                                             %
258 %                                                                             %
259 %                                                                             %
260 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
261 %
262 %  ReadGROUP4Image() reads a raw CCITT Group 4 image file and returns it.  It
263 %  allocates the memory necessary for the new Image structure and returns a
264 %  pointer to the new image.
265 %
266 %  The format of the ReadGROUP4Image method is:
267 %
268 %      Image *ReadGROUP4Image(const ImageInfo *image_info,
269 %        ExceptionInfo *exception)
270 %
271 %  A description of each parameter follows:
272 %
273 %    o image_info: the image info.
274 %
275 %    o exception: return any errors or warnings in this structure.
276 %
277 */
278
279 static inline size_t WriteLSBLong(FILE *file,const size_t value)
280 {
281   unsigned char
282     buffer[4];
283
284   buffer[0]=(unsigned char) value;
285   buffer[1]=(unsigned char) (value >> 8);
286   buffer[2]=(unsigned char) (value >> 16);
287   buffer[3]=(unsigned char) (value >> 24);
288   return(fwrite(buffer,1,4,file));
289 }
290
291 static Image *ReadGROUP4Image(const ImageInfo *image_info,
292   ExceptionInfo *exception)
293 {
294   char
295     filename[MaxTextExtent];
296
297   FILE
298     *file;
299
300   Image
301     *image;
302
303   ImageInfo
304     *read_info;
305
306   int
307     c,
308     unique_file;
309
310   MagickBooleanType
311     status;
312
313   size_t
314     length;
315
316   ssize_t
317     offset,
318     strip_offset;
319
320   /*
321     Open image file.
322   */
323   assert(image_info != (const ImageInfo *) NULL);
324   assert(image_info->signature == MagickSignature);
325   if (image_info->debug != MagickFalse)
326     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
327       image_info->filename);
328   assert(exception != (ExceptionInfo *) NULL);
329   assert(exception->signature == MagickSignature);
330   image=AcquireImage(image_info,exception);
331   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
332   if (status == MagickFalse)
333     {
334       image=DestroyImageList(image);
335       return((Image *) NULL);
336     }
337   /*
338     Write raw CCITT Group 4 wrapped as a TIFF image file.
339   */
340   file=(FILE *) NULL;
341   unique_file=AcquireUniqueFileResource(filename);
342   if (unique_file != -1)
343     file=fdopen(unique_file,"wb");
344   if ((unique_file == -1) || (file == (FILE *) NULL))
345     ThrowImageException(FileOpenError,"UnableToCreateTemporaryFile");
346   length=fwrite("\111\111\052\000\010\000\000\000\016\000",1,10,file);
347   length=fwrite("\376\000\003\000\001\000\000\000\000\000\000\000",1,12,file);
348   length=fwrite("\000\001\004\000\001\000\000\000",1,8,file);
349   length=WriteLSBLong(file,image->columns);
350   length=fwrite("\001\001\004\000\001\000\000\000",1,8,file);
351   length=WriteLSBLong(file,image->rows);
352   length=fwrite("\002\001\003\000\001\000\000\000\001\000\000\000",1,12,file);
353   length=fwrite("\003\001\003\000\001\000\000\000\004\000\000\000",1,12,file);
354   length=fwrite("\006\001\003\000\001\000\000\000\000\000\000\000",1,12,file);
355   length=fwrite("\021\001\003\000\001\000\000\000",1,8,file);
356   strip_offset=10+(12*14)+4+8;
357   length=WriteLSBLong(file,(size_t) strip_offset);
358   length=fwrite("\022\001\003\000\001\000\000\000",1,8,file);
359   length=WriteLSBLong(file,(size_t) image_info->orientation);
360   length=fwrite("\025\001\003\000\001\000\000\000\001\000\000\000",1,12,file);
361   length=fwrite("\026\001\004\000\001\000\000\000",1,8,file);
362   length=WriteLSBLong(file,image->rows);
363   length=fwrite("\027\001\004\000\001\000\000\000\000\000\000\000",1,12,file);
364   offset=(ssize_t) ftell(file)-4;
365   length=fwrite("\032\001\005\000\001\000\000\000",1,8,file);
366   length=WriteLSBLong(file,(size_t) (strip_offset-8));
367   length=fwrite("\033\001\005\000\001\000\000\000",1,8,file);
368   length=WriteLSBLong(file,(size_t) (strip_offset-8));
369   length=fwrite("\050\001\003\000\001\000\000\000\002\000\000\000",1,12,file);
370   length=fwrite("\000\000\000\000",1,4,file);
371   length=WriteLSBLong(file,(long) image->resolution.x);
372   length=WriteLSBLong(file,1);
373   for (length=0; (c=ReadBlobByte(image)) != EOF; length++)
374     (void) fputc(c,file);
375   offset=(ssize_t) fseek(file,(ssize_t) offset,SEEK_SET);
376   length=WriteLSBLong(file,(unsigned int) length);
377   (void) fclose(file);
378   (void) CloseBlob(image);
379   image=DestroyImage(image);
380   /*
381     Read TIFF image.
382   */
383   read_info=CloneImageInfo((ImageInfo *) NULL);
384   (void) FormatLocaleString(read_info->filename,MaxTextExtent,"%s",filename);
385   image=ReadTIFFImage(read_info,exception);
386   read_info=DestroyImageInfo(read_info);
387   if (image != (Image *) NULL)
388     {
389       (void) CopyMagickString(image->filename,image_info->filename,
390         MaxTextExtent);
391       (void) CopyMagickString(image->magick_filename,image_info->filename,
392         MaxTextExtent);
393       (void) CopyMagickString(image->magick,"GROUP4",MaxTextExtent);
394     }
395   (void) RelinquishUniqueFileResource(filename);
396   return(image);
397 }
398 #endif
399 \f
400 #if defined(MAGICKCORE_TIFF_DELEGATE)
401 /*
402 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
403 %                                                                             %
404 %                                                                             %
405 %                                                                             %
406 %   R e a d T I F F I m a g e                                                 %
407 %                                                                             %
408 %                                                                             %
409 %                                                                             %
410 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
411 %
412 %  ReadTIFFImage() reads a Tagged image file and returns it.  It allocates the
413 %  memory necessary for the new Image structure and returns a pointer to the
414 %  new image.
415 %
416 %  The format of the ReadTIFFImage method is:
417 %
418 %      Image *ReadTIFFImage(const ImageInfo *image_info,
419 %        ExceptionInfo *exception)
420 %
421 %  A description of each parameter follows:
422 %
423 %    o image_info: the image info.
424 %
425 %    o exception: return any errors or warnings in this structure.
426 %
427 */
428
429 static inline size_t MagickMax(const size_t x,const size_t y)
430 {
431   if (x > y)
432     return(x);
433   return(y);
434 }
435
436 static inline ssize_t MagickMin(const ssize_t x,const ssize_t y)
437 {
438   if (x < y)
439     return(x);
440   return(y);
441 }
442
443 static MagickBooleanType ReadProfile(Image *image,const char *name,
444   unsigned char *datum,ssize_t length,ExceptionInfo *exception)
445 {
446   MagickBooleanType
447     status;
448
449   register ssize_t
450     i;
451
452   StringInfo
453     *profile;
454
455   if (length < 4)
456     return(MagickFalse);
457   i=0;
458   if ((LocaleCompare(name,"icc") != 0) && (LocaleCompare(name,"xmp") != 0))
459     {
460       for (i=0; i < (length-4); i+=2)
461         if (LocaleNCompare((char *) (datum+i),"8BIM",4) == 0)
462           break;
463       if (i == length)
464         length-=i;
465       else
466         i=0;
467       if (length < 4)
468         return(MagickFalse);
469     }
470   profile=BlobToStringInfo(datum+i,(size_t) length);
471   if (profile == (StringInfo *) NULL)
472     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
473       image->filename);
474   status=SetImageProfile(image,name,profile,exception);
475   profile=DestroyStringInfo(profile);
476   if (status == MagickFalse)
477     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
478       image->filename);
479   return(MagickTrue);
480 }
481
482 #if defined(__cplusplus) || defined(c_plusplus)
483 extern "C" {
484 #endif
485
486 static int TIFFCloseBlob(thandle_t image)
487 {
488   (void) CloseBlob((Image *) image);
489   return(0);
490 }
491
492 static void TIFFErrors(const char *module,const char *format,va_list error)
493 {
494   char
495     message[MaxTextExtent];
496
497   ExceptionInfo
498     *exception;
499
500 #if defined(MAGICKCORE_HAVE_VSNPRINTF)
501   (void) vsnprintf(message,MaxTextExtent,format,error);
502 #else
503   (void) vsprintf(message,format,error);
504 #endif
505   (void) ConcatenateMagickString(message,".",MaxTextExtent);
506   exception=(ExceptionInfo *) MagickGetThreadValue(tiff_exception);
507   if (exception != (ExceptionInfo *) NULL)
508     (void) ThrowMagickException(exception,GetMagickModule(),CoderError,message,
509       "`%s'",module);
510 }
511
512 static toff_t TIFFGetBlobSize(thandle_t image)
513 {
514   return((toff_t) GetBlobSize((Image *) image));
515 }
516
517 static void TIFFGetProfiles(TIFF *tiff,Image *image,ExceptionInfo *exception)
518 {
519   uint32
520     length;
521
522   unsigned char
523     *profile;
524
525 #if defined(TIFFTAG_ICCPROFILE)
526   length=0;
527   if (TIFFGetField(tiff,TIFFTAG_ICCPROFILE,&length,&profile) == 1)
528     (void) ReadProfile(image,"icc",profile,(ssize_t) length,exception);
529 #endif
530 #if defined(TIFFTAG_PHOTOSHOP)
531   length=0;
532   if (TIFFGetField(tiff,TIFFTAG_PHOTOSHOP,&length,&profile) == 1)
533     (void) ReadProfile(image,"8bim",profile,(ssize_t) length,exception);
534 #endif
535 #if defined(TIFFTAG_RICHTIFFIPTC)
536   length=0;
537   if (TIFFGetField(tiff,TIFFTAG_RICHTIFFIPTC,&length,&profile) == 1)
538     {
539       if (TIFFIsByteSwapped(tiff) != 0)
540         TIFFSwabArrayOfLong((uint32 *) profile,(size_t) length);
541       (void) ReadProfile(image,"iptc",profile,4L*length,exception);
542     }
543 #endif
544 #if defined(TIFFTAG_XMLPACKET)
545   length=0;
546   if (TIFFGetField(tiff,TIFFTAG_XMLPACKET,&length,&profile) == 1)
547     (void) ReadProfile(image,"xmp",profile,(ssize_t) length,exception);
548 #endif
549   length=0;
550   if (TIFFGetField(tiff,37724,&length,&profile) == 1)
551     (void) ReadProfile(image,"tiff:37724",profile,(ssize_t) length,exception);
552 }
553
554 static void TIFFGetProperties(TIFF *tiff,Image *image,ExceptionInfo *exception)
555 {
556   char
557     message[MaxTextExtent],
558     *text;
559
560   uint32
561     count;
562
563   if (TIFFGetField(tiff,TIFFTAG_ARTIST,&text) == 1)
564     (void) SetImageProperty(image,"tiff:artist",text,exception);
565   if (TIFFGetField(tiff,TIFFTAG_COPYRIGHT,&text) == 1)
566     (void) SetImageProperty(image,"tiff:copyright",text,exception);
567   if (TIFFGetField(tiff,TIFFTAG_DATETIME,&text) == 1)
568     (void) SetImageProperty(image,"tiff:timestamp",text,exception);
569   if (TIFFGetField(tiff,TIFFTAG_DOCUMENTNAME,&text) == 1)
570     (void) SetImageProperty(image,"tiff:document",text,exception);
571   if (TIFFGetField(tiff,TIFFTAG_HOSTCOMPUTER,&text) == 1)
572     (void) SetImageProperty(image,"tiff:hostcomputer",text,exception);
573   if (TIFFGetField(tiff,TIFFTAG_IMAGEDESCRIPTION,&text) == 1)
574     (void) SetImageProperty(image,"comment",text,exception);
575   if (TIFFGetField(tiff,TIFFTAG_MAKE,&text) == 1)
576     (void) SetImageProperty(image,"tiff:make",text,exception);
577   if (TIFFGetField(tiff,TIFFTAG_MODEL,&text) == 1)
578     (void) SetImageProperty(image,"tiff:model",text,exception);
579   if (TIFFGetField(tiff,TIFFTAG_OPIIMAGEID,&count,&text) == 1)
580     {
581       if (count >= MaxTextExtent)
582         count=MaxTextExtent-1;
583       (void) CopyMagickString(message,text,count+1);
584       (void) SetImageProperty(image,"tiff:image-id",message,exception);
585     }
586   if (TIFFGetField(tiff,TIFFTAG_PAGENAME,&text) == 1)
587     (void) SetImageProperty(image,"label",text,exception);
588   if (TIFFGetField(tiff,TIFFTAG_SOFTWARE,&text) == 1)
589     (void) SetImageProperty(image,"tiff:software",text,exception);
590   if (TIFFGetField(tiff,33423,&count,&text) == 1)
591     {
592       if (count >= MaxTextExtent)
593         count=MaxTextExtent-1;
594       (void) CopyMagickString(message,text,count+1);
595       (void) SetImageProperty(image,"tiff:kodak-33423",message,exception);
596     }
597   if (TIFFGetField(tiff,36867,&count,&text) == 1)
598     {
599       if (count >= MaxTextExtent)
600         count=MaxTextExtent-1;
601       (void) CopyMagickString(message,text,count+1);
602       (void) SetImageProperty(image,"tiff:kodak-36867",message,exception);
603     }
604 }
605
606 static void TIFFGetEXIFProperties(TIFF *tiff,Image *image,
607   ExceptionInfo *exception)
608 {
609 #if defined(MAGICKCORE_HAVE_TIFFREADEXIFDIRECTORY)
610   char
611     value[MaxTextExtent];
612
613   register ssize_t
614     i;
615
616   tdir_t
617     directory;
618
619 #if defined(TIFF_VERSION_BIG)
620   uint64
621 #else
622   uint32
623 #endif
624     offset;
625
626   void
627     *sans;
628
629   /*
630     Read EXIF properties.
631   */
632   offset=0;
633   if (TIFFGetField(tiff,TIFFTAG_EXIFIFD,&offset) == 0)
634     return;
635   directory=TIFFCurrentDirectory(tiff);
636   if (TIFFReadEXIFDirectory(tiff,offset) == 0)
637     return;
638   sans=NULL;
639   for (i=0; exif_info[i].tag != 0; i++)
640   {
641     *value='\0';
642     switch (exif_info[i].type)
643     {
644       case TIFF_ASCII:
645       {
646         char
647           *ascii;
648
649         ascii=(char *) NULL;
650         if ((TIFFGetField(tiff,exif_info[i].tag,&ascii,&sans,&sans) != 0) &&
651             (ascii != (char *) NULL) && (*ascii != '\0'))
652           (void) CopyMagickString(value,ascii,MaxTextExtent);
653         break;
654       }
655       case TIFF_SHORT:
656       {
657         uint16
658           shorty[2] = { 0, 0};
659
660         if (TIFFGetField(tiff,exif_info[i].tag,&shorty,&sans,&sans) != 0)
661           (void) FormatLocaleString(value,MaxTextExtent,"%d",(int) shorty[0]);
662         break;
663       }
664       case TIFF_LONG:
665       {
666         uint32
667           longy;
668
669         if (TIFFGetField(tiff,exif_info[i].tag,&longy,&sans,&sans) != 0)
670           (void) FormatLocaleString(value,MaxTextExtent,"%d",longy);
671         break;
672       }
673 #if defined(TIFF_VERSION_BIG)
674       case TIFF_LONG8:
675       {
676         uint64
677           longy;
678
679         if (TIFFGetField(tiff,exif_info[i].tag,&longy,&sans,&sans) != 0)
680           (void) FormatLocaleString(value,MaxTextExtent,"%.20g",(double)
681             ((MagickOffsetType) longy));
682         break;
683       }
684 #endif
685       case TIFF_RATIONAL:
686       case TIFF_SRATIONAL:
687       case TIFF_FLOAT:
688       case TIFF_DOUBLE:
689       {
690         float
691           rational[16];
692
693         if (TIFFGetField(tiff,exif_info[i].tag,&rational,&sans,&sans) != 0)
694           (void) FormatLocaleString(value,MaxTextExtent,"%g",rational[0]);
695         break;
696       }
697       default:
698         break;
699     }
700     if (*value != '\0')
701       (void) SetImageProperty(image,exif_info[i].property,value,exception);
702   }
703   TIFFSetDirectory(tiff,directory);
704 #else
705   (void) tiff;
706   (void) image;
707 #endif
708 }
709
710 static int TIFFMapBlob(thandle_t image,tdata_t *base,toff_t *size)
711 {
712   *base=(tdata_t *) GetBlobStreamData((Image *) image);
713   if (*base != (tdata_t *) NULL)
714     *size=(toff_t) GetBlobSize((Image *) image);
715   if (*base != (tdata_t *) NULL)
716     return(1);
717   return(0);
718 }
719
720 static tsize_t TIFFReadBlob(thandle_t image,tdata_t data,tsize_t size)
721 {
722   tsize_t
723     count;
724
725   count=(tsize_t) ReadBlob((Image *) image,(size_t) size,
726     (unsigned char *) data);
727   return(count);
728 }
729
730 static int32 TIFFReadPixels(TIFF *tiff,size_t bits_per_sample,
731   tsample_t sample,ssize_t row,tdata_t scanline)
732 {
733   int32
734     status;
735
736   (void) bits_per_sample;
737   status=TIFFReadScanline(tiff,scanline,(uint32) row,sample);
738   return(status);
739 }
740
741 static toff_t TIFFSeekBlob(thandle_t image,toff_t offset,int whence)
742 {
743   return((toff_t) SeekBlob((Image *) image,(MagickOffsetType) offset,whence));
744 }
745
746 static void TIFFUnmapBlob(thandle_t image,tdata_t base,toff_t size)
747 {
748   (void) image;
749   (void) base;
750   (void) size;
751 }
752
753 static void TIFFWarnings(const char *module,const char *format,va_list warning)
754 {
755   char
756     message[MaxTextExtent];
757
758   ExceptionInfo
759     *exception;
760
761 #if defined(MAGICKCORE_HAVE_VSNPRINTF)
762   (void) vsnprintf(message,MaxTextExtent,format,warning);
763 #else
764   (void) vsprintf(message,format,warning);
765 #endif
766   (void) ConcatenateMagickString(message,".",MaxTextExtent);
767   exception=(ExceptionInfo *) MagickGetThreadValue(tiff_exception);
768   if (exception != (ExceptionInfo *) NULL)
769     (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
770       message,"`%s'",module);
771 }
772
773 static tsize_t TIFFWriteBlob(thandle_t image,tdata_t data,tsize_t size)
774 {
775   tsize_t
776     count;
777
778   count=(tsize_t) WriteBlob((Image *) image,(size_t) size,
779     (unsigned char *) data);
780   return(count);
781 }
782
783 #if defined(__cplusplus) || defined(c_plusplus)
784 }
785 #endif
786
787 static Image *ReadTIFFImage(const ImageInfo *image_info,
788   ExceptionInfo *exception)
789 {
790   typedef enum
791   {
792     ReadSingleSampleMethod,
793     ReadRGBAMethod,
794     ReadCMYKAMethod,
795     ReadStripMethod,
796     ReadTileMethod,
797     ReadGenericMethod
798   } TIFFMethodType;
799
800   const char
801     *option;
802
803   float
804     *chromaticity,
805     x_position,
806     y_position,
807     x_resolution,
808     y_resolution;
809
810   Image
811     *image;
812
813   MagickBooleanType
814     associated_alpha,
815     debug,
816     status;
817
818   MagickSizeType
819     number_pixels;
820
821   QuantumInfo
822     *quantum_info;
823
824   QuantumType
825     quantum_type;
826
827   register ssize_t
828     i;
829
830   size_t
831     length,
832     pad;
833
834   ssize_t
835     y;
836
837   TIFF
838     *tiff;
839
840   TIFFErrorHandler
841     error_handler,
842     warning_handler;
843
844   TIFFMethodType
845     method;
846
847   uint16
848     compress_tag,
849     bits_per_sample,
850     endian,
851     extra_samples,
852     interlace,
853     max_sample_value,
854     min_sample_value,
855     orientation,
856     pages,
857     photometric,
858     *sample_info,
859     sample_format,
860     samples_per_pixel,
861     units,
862     value;
863
864   uint32
865     height,
866     rows_per_strip,
867     width;
868
869   unsigned char
870     *pixels;
871
872   /*
873     Open image.
874   */
875   assert(image_info != (const ImageInfo *) NULL);
876   assert(image_info->signature == MagickSignature);
877   if (image_info->debug != MagickFalse)
878     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
879       image_info->filename);
880   assert(exception != (ExceptionInfo *) NULL);
881   assert(exception->signature == MagickSignature);
882   image=AcquireImage(image_info,exception);
883   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
884   if (status == MagickFalse)
885     {
886       image=DestroyImageList(image);
887       return((Image *) NULL);
888     }
889   (void) MagickSetThreadValue(tiff_exception,exception);
890   error_handler=TIFFSetErrorHandler(TIFFErrors);
891   warning_handler=TIFFSetWarningHandler(TIFFWarnings);
892   tiff=TIFFClientOpen(image->filename,"rb",(thandle_t) image,TIFFReadBlob,
893     TIFFWriteBlob,TIFFSeekBlob,TIFFCloseBlob,TIFFGetBlobSize,TIFFMapBlob,
894     TIFFUnmapBlob);
895   if (tiff == (TIFF *) NULL)
896     {
897       (void) TIFFSetWarningHandler(warning_handler);
898       (void) TIFFSetErrorHandler(error_handler);
899       image=DestroyImageList(image);
900       return((Image *) NULL);
901     }
902   debug=IsEventLogging();
903   (void) debug;
904   if (image_info->number_scenes != 0)
905     {
906       /*
907         Generate blank images for subimage specification (e.g. image.tif[4].
908       */
909       for (i=0; i < (ssize_t) image_info->scene; i++)
910       {
911         (void) TIFFReadDirectory(tiff);
912         AcquireNextImage(image_info,image,exception);
913         if (GetNextImageInList(image) == (Image *) NULL)
914           {
915             image=DestroyImageList(image);
916             return((Image *) NULL);
917           }
918         image=SyncNextImageInList(image);
919       }
920     }
921   do
922   {
923     if (0 && (image_info->verbose != MagickFalse))
924       TIFFPrintDirectory(tiff,stdout,MagickFalse);
925 #if defined(MAGICKCORE_HAVE_TIFFISBIGENDIAN)
926     (void) SetImageProperty(image,"tiff:endian",TIFFIsBigEndian(tiff) == 0 ?
927       "lsb" : "msb",exception);
928 #endif
929     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_COMPRESSION,&compress_tag);
930     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_ORIENTATION,&orientation);
931     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_IMAGEWIDTH,&width);
932     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_IMAGELENGTH,&height);
933     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_FILLORDER,&endian);
934     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_PLANARCONFIG,&interlace);
935     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_BITSPERSAMPLE,&bits_per_sample);
936     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_SAMPLEFORMAT,&sample_format);
937     if (sample_format == SAMPLEFORMAT_IEEEFP)
938       (void) SetImageProperty(image,"quantum:format","floating-point",
939         exception);
940     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_MINSAMPLEVALUE,&min_sample_value);
941     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_MAXSAMPLEVALUE,&max_sample_value);
942     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_PHOTOMETRIC,&photometric);
943     switch (photometric)
944     {
945       case PHOTOMETRIC_MINISBLACK:
946       {
947         (void) SetImageProperty(image,"tiff:photometric","min-is-black",
948           exception);
949         break;
950       }
951       case PHOTOMETRIC_MINISWHITE:
952       {
953         (void) SetImageProperty(image,"tiff:photometric","min-is-white",
954           exception);
955         break;
956       }
957       case PHOTOMETRIC_PALETTE:
958       {
959         (void) SetImageProperty(image,"tiff:photometric","palette",exception);
960         break;
961       }
962       case PHOTOMETRIC_RGB:
963       {
964         (void) SetImageProperty(image,"tiff:photometric","RGB",exception);
965         break;
966       }
967       case PHOTOMETRIC_CIELAB:
968       {
969         (void) SetImageProperty(image,"tiff:photometric","CIELAB",exception);
970         break;
971       }
972       case PHOTOMETRIC_SEPARATED:
973       {
974         (void) SetImageProperty(image,"tiff:photometric","separated",exception);
975         break;
976       }
977       case PHOTOMETRIC_YCBCR:
978       {
979         (void) SetImageProperty(image,"tiff:photometric","YCBCR",exception);
980         break;
981       }
982       default:
983       {
984         (void) SetImageProperty(image,"tiff:photometric","unknown",exception);
985         break;
986       }
987     }
988     if (image->debug != MagickFalse)
989       {
990         (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %ux%u",
991           (unsigned int) width,(unsigned int) height);
992         (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Interlace: %u",
993           interlace);
994         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
995           "Bits per sample: %u",bits_per_sample);
996         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
997           "Min sample value: %u",min_sample_value);
998         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
999           "Max sample value: %u",max_sample_value);
1000         (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Photometric "
1001           "interpretation: %s",GetImageProperty(image,"tiff:photometric",
1002           exception));
1003       }
1004     image->columns=(size_t) width;
1005     image->rows=(size_t) height;
1006     image->depth=(size_t) bits_per_sample;
1007     if (image->debug != MagickFalse)
1008       (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Image depth: %.20g",
1009         (double) image->depth);
1010     image->endian=MSBEndian;
1011     if (endian == FILLORDER_LSB2MSB)
1012       image->endian=LSBEndian;
1013     if ((photometric == PHOTOMETRIC_MINISBLACK) ||
1014         (photometric == PHOTOMETRIC_MINISWHITE))
1015       image->colorspace=GRAYColorspace;
1016     if (photometric == PHOTOMETRIC_SEPARATED)
1017       image->colorspace=CMYKColorspace;
1018     if (photometric == PHOTOMETRIC_CIELAB)
1019       image->colorspace=LabColorspace;
1020     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_SAMPLESPERPIXEL,
1021       &samples_per_pixel);
1022     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_RESOLUTIONUNIT,&units);
1023     x_resolution=(float) image->resolution.x;
1024     y_resolution=(float) image->resolution.y;
1025     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_XRESOLUTION,&x_resolution);
1026     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_YRESOLUTION,&y_resolution);
1027     image->resolution.x=x_resolution;
1028     image->resolution.y=y_resolution;
1029     x_position=(float) image->page.x/x_resolution;
1030     y_position=(float) image->page.y/y_resolution;
1031     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_XPOSITION,&x_position);
1032     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_YPOSITION,&y_position);
1033     image->page.x=(ssize_t) ceil(x_position*x_resolution-0.5);
1034     image->page.y=(ssize_t) ceil(y_position*y_resolution-0.5);
1035     image->orientation=(OrientationType) orientation;
1036     chromaticity=(float *) NULL;
1037     (void) TIFFGetField(tiff,TIFFTAG_WHITEPOINT,&chromaticity);
1038     if (chromaticity != (float *) NULL)
1039       {
1040         image->chromaticity.white_point.x=chromaticity[0];
1041         image->chromaticity.white_point.y=chromaticity[1];
1042       }
1043     chromaticity=(float *) NULL;
1044     (void) TIFFGetField(tiff,TIFFTAG_PRIMARYCHROMATICITIES,&chromaticity);
1045     if (chromaticity != (float *) NULL)
1046       {
1047         image->chromaticity.red_primary.x=chromaticity[0];
1048         image->chromaticity.red_primary.y=chromaticity[1];
1049         image->chromaticity.green_primary.x=chromaticity[2];
1050         image->chromaticity.green_primary.y=chromaticity[3];
1051         image->chromaticity.blue_primary.x=chromaticity[4];
1052         image->chromaticity.blue_primary.y=chromaticity[5];
1053       }
1054 #if defined(MAGICKCORE_HAVE_TIFFISCODECCONFIGURED) || (TIFFLIB_VERSION > 20040919)
1055     if ((compress_tag != COMPRESSION_NONE) &&
1056         (TIFFIsCODECConfigured(compress_tag) == 0))
1057       {
1058         TIFFClose(tiff);
1059         ThrowReaderException(CoderError,"CompressNotSupported");
1060       }
1061 #endif
1062     switch (compress_tag)
1063     {
1064       case COMPRESSION_NONE: image->compression=NoCompression; break;
1065       case COMPRESSION_CCITTFAX3: image->compression=FaxCompression; break;
1066       case COMPRESSION_CCITTFAX4: image->compression=Group4Compression; break;
1067       case COMPRESSION_JPEG:
1068       {
1069          image->compression=JPEGCompression;
1070 #if defined(JPEG_SUPPORT)
1071          {
1072            char
1073              sampling_factor[MaxTextExtent];
1074
1075            uint16
1076              horizontal,
1077              vertical;
1078
1079            (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_YCBCRSUBSAMPLING,
1080              &horizontal,&vertical);
1081            (void) FormatLocaleString(sampling_factor,MaxTextExtent,"%dx%d",
1082              horizontal,vertical);
1083            (void) SetImageProperty(image,"jpeg:sampling-factor",
1084              sampling_factor,exception);
1085            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1086              "Sampling Factors: %s",sampling_factor);
1087            if ((samples_per_pixel > 1) && (photometric == PHOTOMETRIC_YCBCR))
1088              {
1089                (void) TIFFSetField(tiff,TIFFTAG_JPEGCOLORMODE,
1090                  JPEGCOLORMODE_RGB);
1091                photometric=PHOTOMETRIC_RGB;
1092              }
1093          }
1094 #endif
1095         break;
1096       }
1097       case COMPRESSION_OJPEG: image->compression=JPEGCompression; break;
1098 #if defined(COMPRESSION_LZMA)
1099       case COMPRESSION_LZMA: image->compression=LZMACompression; break;
1100 #endif
1101       case COMPRESSION_LZW: image->compression=LZWCompression; break;
1102       case COMPRESSION_DEFLATE: image->compression=ZipCompression; break;
1103       case COMPRESSION_ADOBE_DEFLATE: image->compression=ZipCompression; break;
1104       default: image->compression=RLECompression; break;
1105     }
1106     TIFFGetProfiles(tiff,image,exception);
1107     TIFFGetProperties(tiff,image,exception);
1108     option=GetImageOption(image_info,"tiff:exif-properties");
1109     if (IfMagickTrue(IsStringNotFalse(option))) /* enabled by default */
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,exception);
2171       if (pyramid_image == (Image *) NULL)
2172         break;
2173       pyramid_image->resolution=resolution;
2174       AppendImageToList(&images,pyramid_image);
2175     }
2176   }
2177   images=GetFirstImageInList(images);
2178   /*
2179     Write pyramid-encoded TIFF image.
2180   */
2181   write_info=CloneImageInfo(image_info);
2182   write_info->adjoin=MagickTrue;
2183   (void) CopyMagickString(write_info->magick,"TIFF",MaxTextExtent);
2184   (void) CopyMagickString(images->magick,"TIFF",MaxTextExtent);
2185   status=WriteTIFFImage(write_info,images,exception);
2186   images=DestroyImageList(images);
2187   write_info=DestroyImageInfo(write_info);
2188   return(status);
2189 }
2190 #endif
2191 \f
2192 #if defined(MAGICKCORE_TIFF_DELEGATE)
2193 /*
2194 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2195 %                                                                             %
2196 %                                                                             %
2197 %   W r i t e T I F F I m a g e                                               %
2198 %                                                                             %
2199 %                                                                             %
2200 %                                                                             %
2201 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2202 %
2203 %  WriteTIFFImage() writes an image in the Tagged image file format.
2204 %
2205 %  The format of the WriteTIFFImage method is:
2206 %
2207 %      MagickBooleanType WriteTIFFImage(const ImageInfo *image_info,
2208 %        Image *image,ExceptionInfo *exception)
2209 %
2210 %  A description of each parameter follows:
2211 %
2212 %    o image_info: the image info.
2213 %
2214 %    o image:  The image.
2215 %
2216 %    o exception: return any errors or warnings in this structure.
2217 %
2218 */
2219
2220 typedef struct _TIFFInfo
2221 {
2222   RectangleInfo
2223     tile_geometry;
2224
2225   unsigned char
2226     *scanline,
2227     *scanlines,
2228     *pixels;
2229 } TIFFInfo;
2230
2231 static void DestroyTIFFInfo(TIFFInfo *tiff_info)
2232 {
2233   assert(tiff_info != (TIFFInfo *) NULL);
2234   if (tiff_info->scanlines != (unsigned char *) NULL)
2235     tiff_info->scanlines=(unsigned char *) RelinquishMagickMemory(
2236       tiff_info->scanlines);
2237   if (tiff_info->pixels != (unsigned char *) NULL)
2238     tiff_info->pixels=(unsigned char *) RelinquishMagickMemory(
2239       tiff_info->pixels);
2240 }
2241
2242 static MagickBooleanType GetTIFFInfo(const ImageInfo *image_info,TIFF *tiff,
2243   TIFFInfo *tiff_info)
2244 {
2245   const char
2246     *option;
2247
2248   MagickStatusType
2249     flags;
2250
2251   uint32
2252     tile_columns,
2253     tile_rows;
2254
2255   assert(tiff_info != (TIFFInfo *) NULL);
2256   (void) ResetMagickMemory(tiff_info,0,sizeof(*tiff_info));
2257   option=GetImageOption(image_info,"tiff:tile-geometry");
2258   if (option == (const char *) NULL)
2259     return(MagickTrue);
2260   flags=ParseAbsoluteGeometry(option,&tiff_info->tile_geometry);
2261   if ((flags & HeightValue) == 0)
2262     tiff_info->tile_geometry.height=tiff_info->tile_geometry.width;
2263   tile_columns=(uint32) tiff_info->tile_geometry.width;
2264   tile_rows=(uint32) tiff_info->tile_geometry.height;
2265   TIFFDefaultTileSize(tiff,&tile_columns,&tile_rows);
2266   (void) TIFFSetField(tiff,TIFFTAG_TILEWIDTH,tile_columns);
2267   (void) TIFFSetField(tiff,TIFFTAG_TILELENGTH,tile_rows);
2268   tiff_info->tile_geometry.width=tile_columns;
2269   tiff_info->tile_geometry.height=tile_rows;
2270   tiff_info->scanlines=(unsigned char *) AcquireQuantumMemory((size_t)
2271     tile_rows*TIFFScanlineSize(tiff),sizeof(*tiff_info->scanlines));
2272   tiff_info->pixels=(unsigned char *) AcquireQuantumMemory((size_t)
2273     tile_rows*TIFFTileSize(tiff),sizeof(*tiff_info->scanlines));
2274   if ((tiff_info->scanlines == (unsigned char *) NULL) ||
2275       (tiff_info->pixels == (unsigned char *) NULL))
2276     {
2277       DestroyTIFFInfo(tiff_info);
2278       return(MagickFalse);
2279     }
2280   return(MagickTrue);
2281 }
2282
2283 static int32 TIFFWritePixels(TIFF *tiff,TIFFInfo *tiff_info,ssize_t row,
2284   tsample_t sample,Image *image)
2285 {
2286   int32
2287     status;
2288
2289   register ssize_t
2290     i;
2291
2292   register unsigned char
2293     *p,
2294     *q;
2295
2296   size_t
2297     number_tiles,
2298     tile_width;
2299
2300   ssize_t
2301     bytes_per_pixel,
2302     j,
2303     k,
2304     l;
2305
2306   if (TIFFIsTiled(tiff) == 0)
2307     return(TIFFWriteScanline(tiff,tiff_info->scanline,(uint32) row,sample));
2308   /*
2309     Fill scanlines to tile height.
2310   */
2311   i=(ssize_t) (row % tiff_info->tile_geometry.height)*TIFFScanlineSize(tiff);
2312   (void) CopyMagickMemory(tiff_info->scanlines+i,(char *) tiff_info->scanline,
2313     (size_t) TIFFScanlineSize(tiff));
2314   if (((size_t) (row % tiff_info->tile_geometry.height) !=
2315       (tiff_info->tile_geometry.height-1)) &&
2316       (row != (ssize_t) (image->rows-1)))
2317     return(0);
2318   /*
2319     Write tile to TIFF image.
2320   */
2321   status=0;
2322   bytes_per_pixel=TIFFTileSize(tiff)/(ssize_t) (
2323     tiff_info->tile_geometry.height*tiff_info->tile_geometry.width);
2324   number_tiles=(image->columns+tiff_info->tile_geometry.width)/
2325     tiff_info->tile_geometry.width;
2326   for (i=0; i < (ssize_t) number_tiles; i++)
2327   {
2328     tile_width=(i == (ssize_t) (number_tiles-1)) ? image->columns-(i*
2329       tiff_info->tile_geometry.width) : tiff_info->tile_geometry.width;
2330     for (j=0; j < (ssize_t) ((row % tiff_info->tile_geometry.height)+1); j++)
2331       for (k=0; k < (ssize_t) tile_width; k++)
2332       {
2333         if (bytes_per_pixel == 0)
2334           {
2335             p=tiff_info->scanlines+(j*TIFFScanlineSize(tiff)+(i*
2336               tiff_info->tile_geometry.width+k)/8);
2337             q=tiff_info->pixels+(j*TIFFTileRowSize(tiff)+k/8);
2338             *q++=(*p++);
2339             continue;
2340           }
2341         p=tiff_info->scanlines+(j*TIFFScanlineSize(tiff)+(i*
2342           tiff_info->tile_geometry.width+k)*bytes_per_pixel);
2343         q=tiff_info->pixels+(j*TIFFTileRowSize(tiff)+k*bytes_per_pixel);
2344         for (l=0; l < bytes_per_pixel; l++)
2345           *q++=(*p++);
2346       }
2347     if ((i*tiff_info->tile_geometry.width) != image->columns)
2348       status=TIFFWriteTile(tiff,tiff_info->pixels,(uint32) (i*
2349         tiff_info->tile_geometry.width),(uint32) ((row/
2350         tiff_info->tile_geometry.height)*tiff_info->tile_geometry.height),0,
2351         sample);
2352     if (status < 0)
2353       break;
2354   }
2355   return(status);
2356 }
2357
2358 static void TIFFSetProfiles(TIFF *tiff,Image *image)
2359 {
2360   const char
2361     *name;
2362
2363   const StringInfo
2364     *profile;
2365
2366   if (image->profiles == (void *) NULL)
2367     return;
2368   ResetImageProfileIterator(image);
2369   for (name=GetNextImageProfile(image); name != (const char *) NULL; )
2370   {
2371     profile=GetImageProfile(image,name);
2372 #if defined(TIFFTAG_XMLPACKET)
2373     if (LocaleCompare(name,"xmp") == 0)
2374       (void) TIFFSetField(tiff,TIFFTAG_XMLPACKET,(uint32) GetStringInfoLength(
2375         profile),GetStringInfoDatum(profile));
2376 #endif
2377 #if defined(TIFFTAG_ICCPROFILE)
2378     if (LocaleCompare(name,"icc") == 0)
2379       (void) TIFFSetField(tiff,TIFFTAG_ICCPROFILE,(uint32) GetStringInfoLength(
2380         profile),GetStringInfoDatum(profile));
2381 #endif
2382     if (LocaleCompare(name,"iptc") == 0)
2383       {
2384         size_t
2385           length;
2386
2387         StringInfo
2388           *iptc_profile;
2389
2390         iptc_profile=CloneStringInfo(profile);
2391         length=GetStringInfoLength(profile)+4-(GetStringInfoLength(profile) &
2392           0x03);
2393         SetStringInfoLength(iptc_profile,length);
2394         if (TIFFIsByteSwapped(tiff))
2395           TIFFSwabArrayOfLong((uint32 *) GetStringInfoDatum(iptc_profile),
2396             (unsigned long) (length/4));
2397         (void) TIFFSetField(tiff,TIFFTAG_RICHTIFFIPTC,(uint32)
2398           GetStringInfoLength(iptc_profile)/4,GetStringInfoDatum(iptc_profile));
2399         iptc_profile=DestroyStringInfo(iptc_profile);
2400       }
2401 #if defined(TIFFTAG_PHOTOSHOP)
2402     if (LocaleCompare(name,"8bim") == 0)
2403       (void) TIFFSetField(tiff,TIFFTAG_PHOTOSHOP,(uint32)
2404         GetStringInfoLength(profile),GetStringInfoDatum(profile));
2405 #endif
2406     if (LocaleCompare(name,"tiff:37724") == 0)
2407       (void) TIFFSetField(tiff,37724,(uint32) GetStringInfoLength(profile),
2408         GetStringInfoDatum(profile));
2409     name=GetNextImageProfile(image);
2410   }
2411 }
2412
2413 static void TIFFSetProperties(TIFF *tiff,Image *image,ExceptionInfo *exception)
2414 {
2415   const char
2416     *value;
2417
2418   (void) TIFFSetField(tiff,TIFFTAG_DOCUMENTNAME,image->filename);
2419   value=GetImageProperty(image,"tiff:hostcomputer",exception);
2420   if (value != (const char *) NULL)
2421     (void) TIFFSetField(tiff,TIFFTAG_HOSTCOMPUTER,value);
2422   value=GetImageProperty(image,"tiff:artist",exception);
2423   if (value != (const char *) NULL)
2424     (void) TIFFSetField(tiff,TIFFTAG_ARTIST,value);
2425   value=GetImageProperty(image,"tiff:timestamp",exception);
2426   if (value != (const char *) NULL)
2427     (void) TIFFSetField(tiff,TIFFTAG_DATETIME,value);
2428   value=GetImageProperty(image,"tiff:make",exception);
2429   if (value != (const char *) NULL)
2430     (void) TIFFSetField(tiff,TIFFTAG_MAKE,value);
2431   value=GetImageProperty(image,"tiff:model",exception);
2432   if (value != (const char *) NULL)
2433     (void) TIFFSetField(tiff,TIFFTAG_MODEL,value);
2434   value=GetImageProperty(image,"tiff:software",exception);
2435   if (value != (const char *) NULL)
2436     (void) TIFFSetField(tiff,TIFFTAG_SOFTWARE,value);
2437   value=GetImageProperty(image,"tiff:copyright",exception);
2438   if (value != (const char *) NULL)
2439     (void) TIFFSetField(tiff,TIFFTAG_COPYRIGHT,value);
2440   value=GetImageProperty(image,"kodak-33423",exception);
2441   if (value != (const char *) NULL)
2442     (void) TIFFSetField(tiff,33423,value);
2443   value=GetImageProperty(image,"kodak-36867",exception);
2444   if (value != (const char *) NULL)
2445     (void) TIFFSetField(tiff,36867,value);
2446   value=GetImageProperty(image,"label",exception);
2447   if (value != (const char *) NULL)
2448     (void) TIFFSetField(tiff,TIFFTAG_PAGENAME,value);
2449   value=GetImageProperty(image,"comment",exception);
2450   if (value != (const char *) NULL)
2451     (void) TIFFSetField(tiff,TIFFTAG_IMAGEDESCRIPTION,value);
2452 }
2453
2454 static void TIFFSetEXIFProperties(TIFF *tiff,Image *image,
2455   ExceptionInfo *exception)
2456 {
2457 #if defined(MAGICKCORE_HAVE_TIFFREADEXIFDIRECTORY)
2458   const char
2459     *value;
2460
2461   register ssize_t
2462     i;
2463
2464   uint32
2465     offset;
2466
2467   /*
2468     Write EXIF properties.
2469   */
2470   offset=0;
2471   (void) TIFFSetField(tiff,TIFFTAG_SUBIFD,1,&offset);
2472   for (i=0; exif_info[i].tag != 0; i++)
2473   {
2474     value=GetImageProperty(image,exif_info[i].property,exception);
2475     if (value == (const char *) NULL)
2476       continue;
2477     switch (exif_info[i].type)
2478     {
2479       case TIFF_ASCII:
2480       {
2481         (void) TIFFSetField(tiff,exif_info[i].tag,value);
2482         break;
2483       }
2484       case TIFF_SHORT:
2485       {
2486         uint16
2487           shorty;
2488
2489         shorty=(uint16) StringToLong(value);
2490         (void) TIFFSetField(tiff,exif_info[i].tag,shorty);
2491         break;
2492       }
2493       case TIFF_LONG:
2494       {
2495         uint16
2496           ssize_ty;
2497
2498         ssize_ty=(uint16) StringToLong(value);
2499         (void) TIFFSetField(tiff,exif_info[i].tag,ssize_ty);
2500         break;
2501       }
2502       case TIFF_RATIONAL:
2503       case TIFF_SRATIONAL:
2504       {
2505         float
2506           rational;
2507
2508         rational=StringToDouble(value,(char **) NULL);
2509         (void) TIFFSetField(tiff,exif_info[i].tag,rational);
2510         break;
2511       }
2512       default:
2513         break;
2514     }
2515   }
2516   /* (void) TIFFSetField(tiff,TIFFTAG_EXIFIFD,offset); */
2517 #else
2518   (void) tiff;
2519   (void) image;
2520 #endif
2521 }
2522
2523 static MagickBooleanType WriteTIFFImage(const ImageInfo *image_info,
2524   Image *image,ExceptionInfo *exception)
2525 {
2526 #if !defined(TIFFDefaultStripSize)
2527 #define TIFFDefaultStripSize(tiff,request)  (8192UL/TIFFScanlineSize(tiff))
2528 #endif
2529
2530   const char
2531     *mode,
2532     *option;
2533
2534   CompressionType
2535     compression;
2536
2537   EndianType
2538     endian_type;
2539
2540   MagickBooleanType
2541     debug,
2542     status;
2543
2544   MagickOffsetType
2545     scene;
2546
2547   QuantumInfo
2548     *quantum_info;
2549
2550   QuantumType
2551     quantum_type;
2552
2553   register ssize_t
2554     i;
2555
2556   size_t
2557     length;
2558
2559   ssize_t
2560     y;
2561
2562   TIFF
2563     *tiff;
2564
2565   TIFFErrorHandler
2566     error_handler,
2567     warning_handler;
2568
2569   TIFFInfo
2570     tiff_info;
2571
2572   uint16
2573     bits_per_sample,
2574     compress_tag,
2575     endian,
2576     photometric;
2577
2578   uint32
2579     rows_per_strip;
2580
2581   unsigned char
2582     *pixels;
2583
2584   /*
2585     Open TIFF file.
2586   */
2587   assert(image_info != (const ImageInfo *) NULL);
2588   assert(image_info->signature == MagickSignature);
2589   assert(image != (Image *) NULL);
2590   assert(image->signature == MagickSignature);
2591   if (image->debug != MagickFalse)
2592     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2593   assert(exception != (ExceptionInfo *) NULL);
2594   assert(exception->signature == MagickSignature);
2595   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2596   if (status == MagickFalse)
2597     return(status);
2598   (void) MagickSetThreadValue(tiff_exception,exception);
2599   error_handler=TIFFSetErrorHandler((TIFFErrorHandler) TIFFErrors);
2600   warning_handler=TIFFSetWarningHandler((TIFFErrorHandler) TIFFWarnings);
2601   endian_type=UndefinedEndian;
2602   option=GetImageArtifact(image,"tiff:endian");
2603   if (option != (const char *) NULL)
2604     {
2605       if (LocaleNCompare(option,"msb",3) == 0)
2606         endian_type=MSBEndian;
2607       if (LocaleNCompare(option,"lsb",3) == 0)
2608         endian_type=LSBEndian;;
2609     }
2610   switch (endian_type)
2611   {
2612     case LSBEndian: mode="wl"; break;
2613     case MSBEndian: mode="wb"; break;
2614     default: mode="w"; break;
2615   }
2616 #if defined(TIFF_VERSION_BIG)
2617   if (LocaleCompare(image_info->magick,"TIFF64") == 0)
2618     switch (endian_type)
2619     {
2620       case LSBEndian: mode="wl8"; break;
2621       case MSBEndian: mode="wb8"; break;
2622       default: mode="w8"; break;
2623     }
2624 #endif
2625   tiff=TIFFClientOpen(image->filename,mode,(thandle_t) image,TIFFReadBlob,
2626     TIFFWriteBlob,TIFFSeekBlob,TIFFCloseBlob,TIFFGetBlobSize,TIFFMapBlob,
2627     TIFFUnmapBlob);
2628   if (tiff == (TIFF *) NULL)
2629     {
2630       (void) TIFFSetWarningHandler(warning_handler);
2631       (void) TIFFSetErrorHandler(error_handler);
2632       return(MagickFalse);
2633     }
2634   scene=0;
2635   debug=IsEventLogging();
2636   (void) debug;
2637   do
2638   {
2639     /*
2640       Initialize TIFF fields.
2641     */
2642     if ((image_info->type != UndefinedType) &&
2643         (image_info->type != OptimizeType))
2644       (void) SetImageType(image,image_info->type,exception);
2645     quantum_info=AcquireQuantumInfo(image_info,image);
2646     if (quantum_info == (QuantumInfo *) NULL)
2647       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2648     if ((image->storage_class != PseudoClass) && (image->depth >= 32) &&
2649         (quantum_info->format == UndefinedQuantumFormat) &&
2650         (IsHighDynamicRangeImage(image,exception) != MagickFalse))
2651       {
2652         status=SetQuantumFormat(image,quantum_info,FloatingPointQuantumFormat);
2653         if (status == MagickFalse)
2654           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
2655       }
2656     if ((LocaleCompare(image_info->magick,"PTIF") == 0) &&
2657         (GetPreviousImageInList(image) != (Image *) NULL))
2658       (void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_REDUCEDIMAGE);
2659     if ((image->columns != (uint32) image->columns) ||
2660         (image->rows != (uint32) image->rows))
2661       ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
2662     (void) TIFFSetField(tiff,TIFFTAG_IMAGELENGTH,(uint32) image->rows);
2663     (void) TIFFSetField(tiff,TIFFTAG_IMAGEWIDTH,(uint32) image->columns);
2664     compression=image->compression;
2665     if (image_info->compression != UndefinedCompression)
2666       compression=image_info->compression;
2667     switch (compression)
2668     {
2669       case FaxCompression:
2670       {
2671         compress_tag=COMPRESSION_CCITTFAX3;
2672         SetQuantumMinIsWhite(quantum_info,MagickTrue);
2673         break;
2674       }
2675       case Group4Compression:
2676       {
2677         compress_tag=COMPRESSION_CCITTFAX4;
2678         SetQuantumMinIsWhite(quantum_info,MagickTrue);
2679         break;
2680       }
2681 #if defined(COMPRESSION_JBIG)
2682       case JBIG1Compression:
2683       {
2684         compress_tag=COMPRESSION_JBIG;
2685         break;
2686       }
2687 #endif
2688       case JPEGCompression:
2689       {
2690         compress_tag=COMPRESSION_JPEG;
2691         break;
2692       }
2693 #if defined(COMPRESSION_LZMA)
2694       case LZMACompression:
2695       {
2696         compress_tag=COMPRESSION_LZMA;
2697         break;
2698       }
2699 #endif
2700       case LZWCompression:
2701       {
2702         compress_tag=COMPRESSION_LZW;
2703         break;
2704       }
2705       case RLECompression:
2706       {
2707         compress_tag=COMPRESSION_PACKBITS;
2708         break;
2709       }
2710       case ZipCompression:
2711       {
2712         compress_tag=COMPRESSION_ADOBE_DEFLATE;
2713         break;
2714       }
2715       case NoCompression:
2716       default:
2717       {
2718         compress_tag=COMPRESSION_NONE;
2719         break;
2720       }
2721     }
2722 #if defined(MAGICKCORE_HAVE_TIFFISCODECCONFIGURED) || (TIFFLIB_VERSION > 20040919)
2723     if ((compress_tag != COMPRESSION_NONE) &&
2724         (TIFFIsCODECConfigured(compress_tag) == 0))
2725       {
2726         (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
2727           "CompressionNotSupported","`%s'",CommandOptionToMnemonic(
2728           MagickCompressOptions,(ssize_t) compression));
2729         compress_tag=COMPRESSION_NONE;
2730         compression=NoCompression;
2731       }
2732 #else
2733       switch (compress_tag)
2734       {
2735 #if defined(CCITT_SUPPORT)
2736         case COMPRESSION_CCITTFAX3:
2737         case COMPRESSION_CCITTFAX4:
2738 #endif
2739 #if defined(YCBCR_SUPPORT) && defined(JPEG_SUPPORT)
2740         case COMPRESSION_JPEG:
2741 #endif
2742 #if defined(LZMA_SUPPORT) && defined(COMPRESSION_LZMA)
2743         case COMPRESSION_LZMA:
2744 #endif
2745 #if defined(LZW_SUPPORT)
2746         case COMPRESSION_LZW:
2747 #endif
2748 #if defined(PACKBITS_SUPPORT)
2749         case COMPRESSION_PACKBITS:
2750 #endif
2751 #if defined(ZIP_SUPPORT)
2752         case COMPRESSION_ADOBE_DEFLATE:
2753 #endif
2754         case COMPRESSION_NONE:
2755           break;
2756         default:
2757         {
2758           (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
2759             "CompressionNotSupported","`%s'",CommandOptionToMnemonic(
2760               MagickCompressOptions,(ssize_t) compression));
2761           compress_tag=COMPRESSION_NONE;
2762           compression=NoCompression;
2763           break;
2764         }
2765       }
2766 #endif
2767     switch (compression)
2768     {
2769       case FaxCompression:
2770       case Group4Compression:
2771       {
2772         (void) SetImageType(image,BilevelType,exception);
2773         break;
2774       }
2775       case JPEGCompression:
2776       {
2777         (void) SetImageStorageClass(image,DirectClass,exception);
2778         (void) SetImageDepth(image,8,exception);
2779         break;
2780       }
2781       default:
2782         break;
2783     }
2784     if (image->colorspace == CMYKColorspace)
2785       {
2786         photometric=PHOTOMETRIC_SEPARATED;
2787         (void) TIFFSetField(tiff,TIFFTAG_SAMPLESPERPIXEL,4);
2788         (void) TIFFSetField(tiff,TIFFTAG_INKSET,INKSET_CMYK);
2789       }
2790     else
2791       {
2792         /*
2793           Full color TIFF raster.
2794         */
2795         if (image->colorspace == LabColorspace)
2796           photometric=PHOTOMETRIC_CIELAB;
2797         else
2798           if (image->colorspace == YCbCrColorspace)
2799             {
2800               photometric=PHOTOMETRIC_YCBCR;
2801               (void) TIFFSetField(tiff,TIFFTAG_YCBCRSUBSAMPLING,1,1);
2802               (void) SetImageStorageClass(image,DirectClass,exception);
2803               (void) SetImageDepth(image,8,exception);
2804             }
2805           else
2806             {
2807               if (IsRGBColorspace(image->colorspace) == MagickFalse)
2808                 (void) TransformImageColorspace(image,sRGBColorspace,exception);
2809               photometric=PHOTOMETRIC_RGB;
2810             }
2811         (void) TIFFSetField(tiff,TIFFTAG_SAMPLESPERPIXEL,3);
2812         if ((image_info->type != TrueColorType) &&
2813             (image_info->type != TrueColorMatteType))
2814           {
2815             if ((image_info->type != PaletteType) &&
2816                 (IsImageGray(image,exception) != MagickFalse))
2817               {
2818                 photometric=(uint16) (quantum_info->min_is_white !=
2819                   MagickFalse ? PHOTOMETRIC_MINISWHITE :
2820                   PHOTOMETRIC_MINISBLACK);
2821                 (void) TIFFSetField(tiff,TIFFTAG_SAMPLESPERPIXEL,1);
2822                 if ((image_info->depth == 0) && (image->matte == MagickFalse) &&
2823                     (IsImageMonochrome(image,exception) != MagickFalse))
2824                   {
2825                     status=SetQuantumDepth(image,quantum_info,1);
2826                     if (status == MagickFalse)
2827                       ThrowWriterException(ResourceLimitError,
2828                         "MemoryAllocationFailed");
2829                   }
2830               }
2831             else
2832               if (image->storage_class == PseudoClass)
2833                 {
2834                   size_t
2835                     depth;
2836
2837                   /*
2838                     Colormapped TIFF raster.
2839                   */
2840                   (void) TIFFSetField(tiff,TIFFTAG_SAMPLESPERPIXEL,1);
2841                   photometric=PHOTOMETRIC_PALETTE;
2842                   depth=1;
2843                   while ((GetQuantumRange(depth)+1) < image->colors)
2844                     depth<<=1;
2845                   status=SetQuantumDepth(image,quantum_info,depth);
2846                   if (status == MagickFalse)
2847                     ThrowWriterException(ResourceLimitError,
2848                       "MemoryAllocationFailed");
2849                 }
2850           }
2851       }
2852     switch (image->endian)
2853     {
2854       case LSBEndian:
2855       {
2856         endian=FILLORDER_LSB2MSB;
2857         break;
2858       }
2859       case MSBEndian:
2860       {
2861         endian=FILLORDER_MSB2LSB;
2862         break;
2863       }
2864       case UndefinedEndian:
2865       default:
2866       {
2867         (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_FILLORDER,&endian);
2868         break;
2869       }
2870     }
2871     if ((compress_tag == COMPRESSION_CCITTFAX3) &&
2872         (photometric != PHOTOMETRIC_MINISWHITE))
2873       {
2874         compress_tag=COMPRESSION_NONE;
2875         endian=FILLORDER_MSB2LSB;
2876       }
2877     else
2878       if ((compress_tag == COMPRESSION_CCITTFAX4) &&
2879          (photometric != PHOTOMETRIC_MINISWHITE))
2880        {
2881          compress_tag=COMPRESSION_NONE;
2882          endian=FILLORDER_MSB2LSB;
2883        }
2884     option=GetImageArtifact(image,"tiff:fill-order");
2885     if (option != (const char *) NULL)
2886       {
2887         if (LocaleNCompare(option,"msb",3) == 0)
2888           endian=FILLORDER_MSB2LSB;
2889         if (LocaleNCompare(option,"lsb",3) == 0)
2890           endian=FILLORDER_LSB2MSB;
2891       }
2892     (void) TIFFSetField(tiff,TIFFTAG_COMPRESSION,compress_tag);
2893     (void) TIFFSetField(tiff,TIFFTAG_FILLORDER,endian);
2894     (void) TIFFSetField(tiff,TIFFTAG_BITSPERSAMPLE,quantum_info->depth);
2895     if (image->matte != MagickFalse)
2896       {
2897         uint16
2898           extra_samples,
2899           sample_info[1],
2900           samples_per_pixel;
2901
2902         /*
2903           TIFF has a matte channel.
2904         */
2905         extra_samples=1;
2906         sample_info[0]=EXTRASAMPLE_UNASSALPHA;
2907         option=GetImageArtifact(image,"tiff:alpha");
2908         if ((option != (const char *) NULL) &&
2909             (LocaleCompare(option,"associated") == 0))
2910           sample_info[0]=EXTRASAMPLE_ASSOCALPHA;
2911         (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_SAMPLESPERPIXEL,
2912           &samples_per_pixel);
2913         (void) TIFFSetField(tiff,TIFFTAG_SAMPLESPERPIXEL,samples_per_pixel+1);
2914         (void) TIFFSetField(tiff,TIFFTAG_EXTRASAMPLES,extra_samples,
2915           &sample_info);
2916         if (sample_info[0] == EXTRASAMPLE_ASSOCALPHA)
2917           SetQuantumAlphaType(quantum_info,AssociatedQuantumAlpha);
2918       }
2919     (void) TIFFSetField(tiff,TIFFTAG_PHOTOMETRIC,photometric);
2920     switch (quantum_info->format)
2921     {
2922       case FloatingPointQuantumFormat:
2923       {
2924         (void) TIFFSetField(tiff,TIFFTAG_SAMPLEFORMAT,SAMPLEFORMAT_IEEEFP);
2925         (void) TIFFSetField(tiff,TIFFTAG_SMINSAMPLEVALUE,quantum_info->minimum);
2926         (void) TIFFSetField(tiff,TIFFTAG_SMAXSAMPLEVALUE,quantum_info->maximum);
2927         break;
2928       }
2929       case SignedQuantumFormat:
2930       {
2931         (void) TIFFSetField(tiff,TIFFTAG_SAMPLEFORMAT,SAMPLEFORMAT_INT);
2932         break;
2933       }
2934       case UnsignedQuantumFormat:
2935       {
2936         (void) TIFFSetField(tiff,TIFFTAG_SAMPLEFORMAT,SAMPLEFORMAT_UINT);
2937         break;
2938       }
2939       default:
2940         break;
2941     }
2942     (void) TIFFSetField(tiff,TIFFTAG_ORIENTATION,ORIENTATION_TOPLEFT);
2943     (void) TIFFSetField(tiff,TIFFTAG_PLANARCONFIG,PLANARCONFIG_CONTIG);
2944     if (photometric == PHOTOMETRIC_RGB)
2945       if ((image_info->interlace == PlaneInterlace) ||
2946           (image_info->interlace == PartitionInterlace))
2947         (void) TIFFSetField(tiff,TIFFTAG_PLANARCONFIG,PLANARCONFIG_SEPARATE);
2948     rows_per_strip=1;
2949     if (TIFFScanlineSize(tiff) != 0)
2950       rows_per_strip=(uint32) MagickMax((size_t) TIFFDefaultStripSize(tiff,0),
2951         1);
2952     option=GetImageArtifact(image,"tiff:rows-per-strip");
2953     if (option != (const char *) NULL)
2954       rows_per_strip=(size_t) strtol(option,(char **) NULL,10);
2955     switch (compress_tag)
2956     {
2957       case COMPRESSION_JPEG:
2958       {
2959 #if defined(JPEG_SUPPORT)
2960         const char
2961           *sampling_factor;
2962
2963         GeometryInfo
2964           geometry_info;
2965
2966         MagickStatusType
2967           flags;
2968
2969         rows_per_strip+=(16-(rows_per_strip % 16));
2970         if (image->quality != 0)
2971           (void) TIFFSetField(tiff,TIFFTAG_JPEGQUALITY,image->quality);
2972         if (image_info->quality != UndefinedCompressionQuality)
2973           (void) TIFFSetField(tiff,TIFFTAG_JPEGQUALITY,image_info->quality);
2974         (void) TIFFSetField(tiff,TIFFTAG_JPEGCOLORMODE,JPEGCOLORMODE_RAW);
2975         if (IsRGBColorspace(image->colorspace) == MagickTrue)
2976           {
2977             const char
2978               *value;
2979
2980             (void) TIFFSetField(tiff,TIFFTAG_JPEGCOLORMODE,JPEGCOLORMODE_RGB);
2981             sampling_factor=(const char *) NULL;
2982             value=GetImageProperty(image,"jpeg:sampling-factor",exception);
2983             if (value != (char *) NULL)
2984               {
2985                 sampling_factor=value;
2986                 if (image->debug != MagickFalse)
2987                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2988                     "  Input sampling-factors=%s",sampling_factor);
2989               }
2990             if (image_info->sampling_factor != (char *) NULL)
2991               sampling_factor=image_info->sampling_factor;
2992             if (sampling_factor != (const char *) NULL)
2993               {
2994                 flags=ParseGeometry(sampling_factor,&geometry_info);
2995                 if ((flags & SigmaValue) == 0)
2996                   geometry_info.sigma=geometry_info.rho;
2997                 if (image->colorspace == YCbCrColorspace)
2998                   (void) TIFFSetField(tiff,TIFFTAG_YCBCRSUBSAMPLING,(uint16)
2999                     geometry_info.rho,(uint16) geometry_info.sigma);
3000               }
3001           }
3002         if (bits_per_sample == 12)
3003           (void) TIFFSetField(tiff,TIFFTAG_JPEGTABLESMODE,JPEGTABLESMODE_QUANT);
3004 #endif
3005         break;
3006       }
3007       case COMPRESSION_ADOBE_DEFLATE:
3008       {
3009         rows_per_strip=(uint32) image->rows;
3010         (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_BITSPERSAMPLE,
3011           &bits_per_sample);
3012         if (((photometric == PHOTOMETRIC_RGB) ||
3013              (photometric == PHOTOMETRIC_MINISBLACK)) &&
3014             ((bits_per_sample == 8) || (bits_per_sample == 16)))
3015           (void) TIFFSetField(tiff,TIFFTAG_PREDICTOR,PREDICTOR_HORIZONTAL);
3016         (void) TIFFSetField(tiff,TIFFTAG_ZIPQUALITY,(long) (
3017           image_info->quality == UndefinedCompressionQuality ? 7 :
3018           MagickMin((ssize_t) image_info->quality/10,9)));
3019         break;
3020       }
3021       case COMPRESSION_CCITTFAX3:
3022       {
3023         /*
3024           Byte-aligned EOL.
3025         */
3026         rows_per_strip=(uint32) image->rows;
3027         (void) TIFFSetField(tiff,TIFFTAG_GROUP3OPTIONS,4);
3028         break;
3029       }
3030       case COMPRESSION_CCITTFAX4:
3031       {
3032         rows_per_strip=(uint32) image->rows;
3033         break;
3034       }
3035 #if defined(LZMA_SUPPORT) && defined(COMPRESSION_LZMA)
3036       case COMPRESSION_LZMA:
3037       {
3038         if (((photometric == PHOTOMETRIC_RGB) ||
3039              (photometric == PHOTOMETRIC_MINISBLACK)) &&
3040             ((bits_per_sample == 8) || (bits_per_sample == 16)))
3041           (void) TIFFSetField(tiff,TIFFTAG_PREDICTOR,PREDICTOR_HORIZONTAL);
3042         (void) TIFFSetField(tiff,TIFFTAG_LZMAPRESET,(long) (
3043           image_info->quality == UndefinedCompressionQuality ? 7 :
3044           MagickMin((ssize_t) image_info->quality/10,9)));
3045         break;
3046       }
3047 #endif
3048       case COMPRESSION_LZW:
3049       {
3050         (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_BITSPERSAMPLE,
3051           &bits_per_sample);
3052         if (((photometric == PHOTOMETRIC_RGB) ||
3053              (photometric == PHOTOMETRIC_MINISBLACK)) &&
3054             ((bits_per_sample == 8) || (bits_per_sample == 16)))
3055           (void) TIFFSetField(tiff,TIFFTAG_PREDICTOR,PREDICTOR_HORIZONTAL);
3056         break;
3057       }
3058       default:
3059         break;
3060     }
3061     option=GetImageArtifact(image,"tiff:rows-per-strip");
3062     if (option == (const char *) NULL)
3063       (void) TIFFSetField(tiff,TIFFTAG_ROWSPERSTRIP,rows_per_strip);
3064     if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
3065       {
3066         unsigned short
3067           units;
3068
3069         /*
3070           Set image resolution.
3071         */
3072         units=RESUNIT_NONE;
3073         if (image->units == PixelsPerInchResolution)
3074           units=RESUNIT_INCH;
3075         if (image->units == PixelsPerCentimeterResolution)
3076           units=RESUNIT_CENTIMETER;
3077         (void) TIFFSetField(tiff,TIFFTAG_RESOLUTIONUNIT,(uint16) units);
3078         (void) TIFFSetField(tiff,TIFFTAG_XRESOLUTION,image->resolution.x);
3079         (void) TIFFSetField(tiff,TIFFTAG_YRESOLUTION,image->resolution.y);
3080         if ((image->page.x != 0) || (image->page.y != 0))
3081           {
3082             /*
3083               Set image position.
3084             */
3085             (void) TIFFSetField(tiff,TIFFTAG_XPOSITION,(float) image->page.x/
3086               image->resolution.x);
3087             (void) TIFFSetField(tiff,TIFFTAG_YPOSITION,(float) image->page.y/
3088               image->resolution.y);
3089           }
3090       }
3091     if (image->chromaticity.white_point.x != 0.0)
3092       {
3093         float
3094           chromaticity[6];
3095
3096         /*
3097           Set image chromaticity.
3098         */
3099         chromaticity[0]=(float) image->chromaticity.red_primary.x;
3100         chromaticity[1]=(float) image->chromaticity.red_primary.y;
3101         chromaticity[2]=(float) image->chromaticity.green_primary.x;
3102         chromaticity[3]=(float) image->chromaticity.green_primary.y;
3103         chromaticity[4]=(float) image->chromaticity.blue_primary.x;
3104         chromaticity[5]=(float) image->chromaticity.blue_primary.y;
3105         (void) TIFFSetField(tiff,TIFFTAG_PRIMARYCHROMATICITIES,chromaticity);
3106         chromaticity[0]=(float) image->chromaticity.white_point.x;
3107         chromaticity[1]=(float) image->chromaticity.white_point.y;
3108         (void) TIFFSetField(tiff,TIFFTAG_WHITEPOINT,chromaticity);
3109       }
3110     if ((LocaleCompare(image_info->magick,"PTIF") != 0) &&
3111         (image_info->adjoin != MagickFalse) && (GetImageListLength(image) > 1))
3112       {
3113         (void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_PAGE);
3114         if (image->scene != 0)
3115           (void) TIFFSetField(tiff,TIFFTAG_PAGENUMBER,(uint16) image->scene,
3116             GetImageListLength(image));
3117       }
3118     if (image->orientation != UndefinedOrientation)
3119       (void) TIFFSetField(tiff,TIFFTAG_ORIENTATION,(uint16) image->orientation);
3120     (void) TIFFSetProfiles(tiff,image);
3121     {
3122       uint16
3123         page,
3124         pages;
3125
3126       page=(uint16) scene;
3127       pages=(uint16) GetImageListLength(image);
3128       if ((LocaleCompare(image_info->magick,"PTIF") != 0) &&
3129           (image_info->adjoin != MagickFalse) && (pages > 1))
3130         (void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_PAGE);
3131       (void) TIFFSetField(tiff,TIFFTAG_PAGENUMBER,page,pages);
3132     }
3133     (void) TIFFSetProperties(tiff,image,exception);
3134     if (0)
3135       (void) TIFFSetEXIFProperties(tiff,image,exception);
3136     /*
3137       Write image scanlines.
3138     */
3139     if (GetTIFFInfo(image_info,tiff,&tiff_info) == MagickFalse)
3140       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3141     quantum_info->endian=LSBEndian;
3142     pixels=GetQuantumPixels(quantum_info);
3143     tiff_info.scanline=GetQuantumPixels(quantum_info);
3144     switch (photometric)
3145     {
3146       case PHOTOMETRIC_CIELAB:
3147       case PHOTOMETRIC_YCBCR:
3148       case PHOTOMETRIC_RGB:
3149       {
3150         /*
3151           RGB TIFF image.
3152         */
3153         switch (image_info->interlace)
3154         {
3155           case NoInterlace:
3156           default:
3157           {
3158             quantum_type=RGBQuantum;
3159             if (image->matte != MagickFalse)
3160               quantum_type=RGBAQuantum;
3161             for (y=0; y < (ssize_t) image->rows; y++)
3162             {
3163               register const Quantum
3164                 *restrict p;
3165
3166               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3167               if (p == (const Quantum *) NULL)
3168                 break;
3169               length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3170                 quantum_type,pixels,exception);
3171               (void) length;
3172               if (TIFFWritePixels(tiff,&tiff_info,y,0,image) == -1)
3173                 break;
3174               if (image->previous == (Image *) NULL)
3175                 {
3176                   status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
3177                     y,image->rows);
3178                   if (status == MagickFalse)
3179                     break;
3180                 }
3181             }
3182             break;
3183           }
3184           case PlaneInterlace:
3185           case PartitionInterlace:
3186           {
3187             /*
3188               Plane interlacing:  RRRRRR...GGGGGG...BBBBBB...
3189             */
3190             for (y=0; y < (ssize_t) image->rows; y++)
3191             {
3192               register const Quantum
3193                 *restrict p;
3194
3195               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3196               if (p == (const Quantum *) NULL)
3197                 break;
3198               length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3199                 RedQuantum,pixels,exception);
3200               if (TIFFWritePixels(tiff,&tiff_info,y,0,image) == -1)
3201                 break;
3202             }
3203             if (image->previous == (Image *) NULL)
3204               {
3205                 status=SetImageProgress(image,SaveImageTag,100,400);
3206                 if (status == MagickFalse)
3207                   break;
3208               }
3209             for (y=0; y < (ssize_t) image->rows; y++)
3210             {
3211               register const Quantum
3212                 *restrict p;
3213
3214               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3215               if (p == (const Quantum *) NULL)
3216                 break;
3217               length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3218                 GreenQuantum,pixels,exception);
3219               if (TIFFWritePixels(tiff,&tiff_info,y,1,image) == -1)
3220                 break;
3221             }
3222             if (image->previous == (Image *) NULL)
3223               {
3224                 status=SetImageProgress(image,SaveImageTag,200,400);
3225                 if (status == MagickFalse)
3226                   break;
3227               }
3228             for (y=0; y < (ssize_t) image->rows; y++)
3229             {
3230               register const Quantum
3231                 *restrict p;
3232
3233               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3234               if (p == (const Quantum *) NULL)
3235                 break;
3236               length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3237                 BlueQuantum,pixels,exception);
3238               if (TIFFWritePixels(tiff,&tiff_info,y,2,image) == -1)
3239                 break;
3240             }
3241             if (image->previous == (Image *) NULL)
3242               {
3243                 status=SetImageProgress(image,SaveImageTag,300,400);
3244                 if (status == MagickFalse)
3245                   break;
3246               }
3247             if (image->matte != MagickFalse)
3248               for (y=0; y < (ssize_t) image->rows; y++)
3249               {
3250                 register const Quantum
3251                   *restrict p;
3252
3253                 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3254                 if (p == (const Quantum *) NULL)
3255                   break;
3256                 length=ExportQuantumPixels(image,(CacheView *) NULL,
3257                   quantum_info,AlphaQuantum,pixels,exception);
3258                 if (TIFFWritePixels(tiff,&tiff_info,y,3,image) == -1)
3259                   break;
3260               }
3261             if (image->previous == (Image *) NULL)
3262               {
3263                 status=SetImageProgress(image,SaveImageTag,400,400);
3264                 if (status == MagickFalse)
3265                   break;
3266               }
3267             break;
3268           }
3269         }
3270         break;
3271       }
3272       case PHOTOMETRIC_SEPARATED:
3273       {
3274         /*
3275           CMYK TIFF image.
3276         */
3277         quantum_type=CMYKQuantum;
3278         if (image->matte != MagickFalse)
3279           quantum_type=CMYKAQuantum;
3280         if (image->colorspace != CMYKColorspace)
3281           (void) TransformImageColorspace(image,CMYKColorspace,exception);
3282         for (y=0; y < (ssize_t) image->rows; y++)
3283         {
3284           register const Quantum
3285             *restrict p;
3286
3287           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3288           if (p == (const Quantum *) NULL)
3289             break;
3290           length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3291             quantum_type,pixels,exception);
3292           if (TIFFWritePixels(tiff,&tiff_info,y,0,image) == -1)
3293             break;
3294           if (image->previous == (Image *) NULL)
3295             {
3296               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
3297                 image->rows);
3298               if (status == MagickFalse)
3299                 break;
3300             }
3301         }
3302         break;
3303       }
3304       case PHOTOMETRIC_PALETTE:
3305       {
3306         uint16
3307           *blue,
3308           *green,
3309           *red;
3310
3311         /*
3312           Colormapped TIFF image.
3313         */
3314         red=(uint16 *) AcquireQuantumMemory(65536,sizeof(*red));
3315         green=(uint16 *) AcquireQuantumMemory(65536,sizeof(*green));
3316         blue=(uint16 *) AcquireQuantumMemory(65536,sizeof(*blue));
3317         if ((red == (uint16 *) NULL) || (green == (uint16 *) NULL) ||
3318             (blue == (uint16 *) NULL))
3319           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3320         /*
3321           Initialize TIFF colormap.
3322         */
3323         (void) ResetMagickMemory(red,0,65536*sizeof(*red));
3324         (void) ResetMagickMemory(green,0,65536*sizeof(*green));
3325         (void) ResetMagickMemory(blue,0,65536*sizeof(*blue));
3326         for (i=0; i < (ssize_t) image->colors; i++)
3327         {
3328           red[i]=ScaleQuantumToShort(image->colormap[i].red);
3329           green[i]=ScaleQuantumToShort(image->colormap[i].green);
3330           blue[i]=ScaleQuantumToShort(image->colormap[i].blue);
3331         }
3332         (void) TIFFSetField(tiff,TIFFTAG_COLORMAP,red,green,blue);
3333         red=(uint16 *) RelinquishMagickMemory(red);
3334         green=(uint16 *) RelinquishMagickMemory(green);
3335         blue=(uint16 *) RelinquishMagickMemory(blue);
3336       }
3337       default:
3338       {
3339         /*
3340           Convert PseudoClass packets to contiguous grayscale scanlines.
3341         */
3342         quantum_type=IndexQuantum;
3343         if (image->matte != MagickFalse)
3344           {
3345             if (photometric != PHOTOMETRIC_PALETTE)
3346               quantum_type=GrayAlphaQuantum;
3347             else
3348               quantum_type=IndexAlphaQuantum;
3349            }
3350          else
3351            if (photometric != PHOTOMETRIC_PALETTE)
3352              quantum_type=GrayQuantum;
3353         for (y=0; y < (ssize_t) image->rows; y++)
3354         {
3355           register const Quantum
3356             *restrict p;
3357
3358           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3359           if (p == (const Quantum *) NULL)
3360             break;
3361           length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3362             quantum_type,pixels,exception);
3363           if (TIFFWritePixels(tiff,&tiff_info,y,0,image) == -1)
3364             break;
3365           if (image->previous == (Image *) NULL)
3366             {
3367               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
3368                 image->rows);
3369               if (status == MagickFalse)
3370                 break;
3371             }
3372         }
3373         break;
3374       }
3375     }
3376     quantum_info=DestroyQuantumInfo(quantum_info);
3377     DestroyTIFFInfo(&tiff_info);
3378     if (0 && (image_info->verbose == MagickTrue))
3379       TIFFPrintDirectory(tiff,stdout,MagickFalse);
3380     (void) TIFFWriteDirectory(tiff);
3381     image=SyncNextImageInList(image);
3382     if (image == (Image *) NULL)
3383       break;
3384     status=SetImageProgress(image,SaveImagesTag,scene++,
3385       GetImageListLength(image));
3386     if (status == MagickFalse)
3387       break;
3388   } while (image_info->adjoin != MagickFalse);
3389   (void) TIFFSetWarningHandler(warning_handler);
3390   (void) TIFFSetErrorHandler(error_handler);
3391   TIFFClose(tiff);
3392   return(MagickTrue);
3393 }
3394 #endif