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