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