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