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