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