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