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