]> granicus.if.org Git - imagemagick/blob - coders/tiff.c
Group4Compression requires a bilevel image
[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         size_t
1891           number_pixels;
1892
1893         /*
1894           Convert tiled TIFF image to DirectClass MIFF image.
1895         */
1896         if ((TIFFGetField(tiff,TIFFTAG_TILEWIDTH,&columns) != 1) ||
1897             (TIFFGetField(tiff,TIFFTAG_TILELENGTH,&rows) != 1))
1898           {
1899             TIFFClose(tiff);
1900             ThrowReaderException(CoderError,"ImageIsNotTiled");
1901           }
1902         (void) SetImageStorageClass(image,DirectClass,exception);
1903         number_pixels=columns*rows;
1904         tile_pixels=(uint32 *) AcquireQuantumMemory(number_pixels,
1905           sizeof(*tile_pixels));
1906         if (tile_pixels == (uint32 *) NULL)
1907           {
1908             TIFFClose(tiff);
1909             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1910           }
1911         for (y=0; y < (ssize_t) image->rows; y+=rows)
1912         {
1913           register ssize_t
1914             x;
1915
1916           register Quantum
1917             *magick_restrict q,
1918             *magick_restrict tile;
1919
1920           size_t
1921             columns_remaining,
1922             rows_remaining;
1923
1924           rows_remaining=image->rows-y;
1925           if ((ssize_t) (y+rows) < (ssize_t) image->rows)
1926             rows_remaining=rows;
1927           tile=QueueAuthenticPixels(image,0,y,image->columns,rows_remaining,
1928             exception);
1929           if (tile == (Quantum *) NULL)
1930             break;
1931           for (x=0; x < (ssize_t) image->columns; x+=columns)
1932           {
1933             size_t
1934               column,
1935               row;
1936
1937             if (TIFFReadRGBATile(tiff,(uint32) x,(uint32) y,tile_pixels) == 0)
1938               break;
1939             columns_remaining=image->columns-x;
1940             if ((ssize_t) (x+columns) < (ssize_t) image->columns)
1941               columns_remaining=columns;
1942             p=tile_pixels+(rows-rows_remaining)*columns;
1943             q=tile+GetPixelChannels(image)*(image->columns*(rows_remaining-1)+
1944               x);
1945             for (row=rows_remaining; row > 0; row--)
1946             {
1947               if (image->alpha_trait != UndefinedPixelTrait)
1948                 for (column=columns_remaining; column > 0; column--)
1949                 {
1950                   SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1951                     TIFFGetR(*p)),q);
1952                   SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1953                     TIFFGetG(*p)),q);
1954                   SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1955                     TIFFGetB(*p)),q);
1956                   SetPixelAlpha(image,ScaleCharToQuantum((unsigned char)
1957                     TIFFGetA(*p)),q);
1958                   p++;
1959                   q+=GetPixelChannels(image);
1960                 }
1961               else
1962                 for (column=columns_remaining; column > 0; column--)
1963                 {
1964                   SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1965                     TIFFGetR(*p)),q);
1966                   SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1967                     TIFFGetG(*p)),q);
1968                   SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1969                     TIFFGetB(*p)),q);
1970                   p++;
1971                   q+=GetPixelChannels(image);
1972                 }
1973               p+=columns-columns_remaining;
1974               q-=GetPixelChannels(image)*(image->columns+columns_remaining);
1975             }
1976           }
1977           if (SyncAuthenticPixels(image,exception) == MagickFalse)
1978             break;
1979           if (image->previous == (Image *) NULL)
1980             {
1981               status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1982                 image->rows);
1983               if (status == MagickFalse)
1984                 break;
1985             }
1986         }
1987         tile_pixels=(uint32 *) RelinquishMagickMemory(tile_pixels);
1988         break;
1989       }
1990       case ReadGenericMethod:
1991       default:
1992       {
1993         MemoryInfo
1994           *pixel_info;
1995
1996         register uint32
1997           *p;
1998
1999         uint32
2000           *pixels;
2001
2002         /*
2003           Convert TIFF image to DirectClass MIFF image.
2004         */
2005         number_pixels=(MagickSizeType) image->columns*image->rows;
2006         if ((number_pixels*sizeof(uint32)) != (MagickSizeType) ((size_t)
2007             (number_pixels*sizeof(uint32))))
2008           {
2009             TIFFClose(tiff);
2010             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2011           }
2012         pixel_info=AcquireVirtualMemory(image->columns,image->rows*
2013           sizeof(uint32));
2014         if (pixel_info == (MemoryInfo *) NULL)
2015           {
2016             TIFFClose(tiff);
2017             ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2018           }
2019         pixels=(uint32 *) GetVirtualMemoryBlob(pixel_info);
2020         (void) TIFFReadRGBAImage(tiff,(uint32) image->columns,
2021           (uint32) image->rows,(uint32 *) pixels,0);
2022         /*
2023           Convert image to DirectClass pixel packets.
2024         */
2025         p=pixels+number_pixels-1;
2026         for (y=0; y < (ssize_t) image->rows; y++)
2027         {
2028           register ssize_t
2029             x;
2030
2031           register Quantum
2032             *magick_restrict q;
2033
2034           q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
2035           if (q == (Quantum *) NULL)
2036             break;
2037           q+=GetPixelChannels(image)*(image->columns-1);
2038           for (x=0; x < (ssize_t) image->columns; x++)
2039           {
2040             SetPixelRed(image,ScaleCharToQuantum((unsigned char)
2041               TIFFGetR(*p)),q);
2042             SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
2043               TIFFGetG(*p)),q);
2044             SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
2045               TIFFGetB(*p)),q);
2046             if (image->alpha_trait != UndefinedPixelTrait)
2047               SetPixelAlpha(image,ScaleCharToQuantum((unsigned char)
2048                 TIFFGetA(*p)),q);
2049             p--;
2050             q-=GetPixelChannels(image);
2051           }
2052           if (SyncAuthenticPixels(image,exception) == MagickFalse)
2053             break;
2054           if (image->previous == (Image *) NULL)
2055             {
2056               status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
2057                 image->rows);
2058               if (status == MagickFalse)
2059                 break;
2060             }
2061         }
2062         pixel_info=RelinquishVirtualMemory(pixel_info);
2063         break;
2064       }
2065     }
2066     SetQuantumImageType(image,quantum_type);
2067   next_tiff_frame:
2068     quantum_info=DestroyQuantumInfo(quantum_info);
2069     if (photometric == PHOTOMETRIC_CIELAB)
2070       DecodeLabImage(image,exception);
2071     if ((photometric == PHOTOMETRIC_LOGL) ||
2072         (photometric == PHOTOMETRIC_MINISBLACK) ||
2073         (photometric == PHOTOMETRIC_MINISWHITE))
2074       {
2075         image->type=GrayscaleType;
2076         if (bits_per_sample == 1)
2077           image->type=BilevelType;
2078       }
2079     /*
2080       Proceed to next image.
2081     */
2082     if (image_info->number_scenes != 0)
2083       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
2084         break;
2085     status=TIFFReadDirectory(tiff) != 0 ? MagickTrue : MagickFalse;
2086     if (status != MagickFalse)
2087       {
2088         /*
2089           Allocate next image structure.
2090         */
2091         AcquireNextImage(image_info,image,exception);
2092         if (GetNextImageInList(image) == (Image *) NULL)
2093           {
2094             image=DestroyImageList(image);
2095             return((Image *) NULL);
2096           }
2097         image=SyncNextImageInList(image);
2098         status=SetImageProgress(image,LoadImagesTag,image->scene-1,
2099           image->scene);
2100         if (status == MagickFalse)
2101           break;
2102       }
2103   } while (status != MagickFalse);
2104   TIFFClose(tiff);
2105   TIFFReadPhotoshopLayers(image,image_info,exception);
2106   if (image_info->number_scenes != 0)
2107     {
2108       if (image_info->scene >= GetImageListLength(image))
2109         {
2110           /* Subimage was not found in the Photoshop layer */
2111           image=DestroyImageList(image);
2112           return((Image *)NULL);
2113         }
2114     }
2115   return(GetFirstImageInList(image));
2116 }
2117 #endif
2118 \f
2119 /*
2120 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2121 %                                                                             %
2122 %                                                                             %
2123 %                                                                             %
2124 %   R e g i s t e r T I F F I m a g e                                         %
2125 %                                                                             %
2126 %                                                                             %
2127 %                                                                             %
2128 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2129 %
2130 %  RegisterTIFFImage() adds properties for the TIFF image format to
2131 %  the list of supported formats.  The properties include the image format
2132 %  tag, a method to read and/or write the format, whether the format
2133 %  supports the saving of more than one frame to the same file or blob,
2134 %  whether the format supports native in-memory I/O, and a brief
2135 %  description of the format.
2136 %
2137 %  The format of the RegisterTIFFImage method is:
2138 %
2139 %      size_t RegisterTIFFImage(void)
2140 %
2141 */
2142
2143 #if defined(MAGICKCORE_HAVE_TIFFMERGEFIELDINFO) && defined(MAGICKCORE_HAVE_TIFFSETTAGEXTENDER)
2144 static TIFFExtendProc
2145   tag_extender = (TIFFExtendProc) NULL;
2146
2147 static void TIFFIgnoreTags(TIFF *tiff)
2148 {
2149   char
2150     *q;
2151
2152   const char
2153     *p,
2154     *tags;
2155
2156   Image
2157    *image;
2158
2159   register ssize_t
2160     i;
2161
2162   size_t
2163     count;
2164
2165   TIFFFieldInfo
2166     *ignore;
2167
2168   if (TIFFGetReadProc(tiff) != TIFFReadBlob)
2169     return;
2170   image=(Image *)TIFFClientdata(tiff);
2171   tags=GetImageArtifact(image,"tiff:ignore-tags");
2172   if (tags == (const char *) NULL)
2173     return;
2174   count=0;
2175   p=tags;
2176   while (*p != '\0')
2177   {
2178     while ((isspace((int) ((unsigned char) *p)) != 0))
2179       p++;
2180
2181     (void) strtol(p,&q,10);
2182     if (p == q)
2183       return;
2184
2185     p=q;
2186     count++;
2187
2188     while ((isspace((int) ((unsigned char) *p)) != 0) || (*p == ','))
2189       p++;
2190   }
2191   if (count == 0)
2192     return;
2193   i=0;
2194   p=tags;
2195   ignore=(TIFFFieldInfo *) AcquireQuantumMemory(count,sizeof(*ignore));
2196   /* This also sets field_bit to 0 (FIELD_IGNORE) */
2197   ResetMagickMemory(ignore,0,count*sizeof(*ignore));
2198   while (*p != '\0')
2199   {
2200     while ((isspace((int) ((unsigned char) *p)) != 0))
2201       p++;
2202
2203     ignore[i].field_tag=(ttag_t) strtol(p,&q,10);
2204
2205     p=q;
2206     i++;
2207
2208     while ((isspace((int) ((unsigned char) *p)) != 0) || (*p == ','))
2209       p++;
2210   }
2211   (void) TIFFMergeFieldInfo(tiff,ignore,(uint32) count);
2212   ignore=(TIFFFieldInfo *) RelinquishMagickMemory(ignore);
2213 }
2214
2215 static void TIFFTagExtender(TIFF *tiff)
2216 {
2217   static const TIFFFieldInfo
2218     TIFFExtensions[] =
2219     {
2220       { 37724, -3, -3, TIFF_UNDEFINED, FIELD_CUSTOM, 1, 1,
2221         (char *) "PhotoshopLayerData" },
2222       { 34118, -3, -3, TIFF_UNDEFINED, FIELD_CUSTOM, 1, 1,
2223         (char *) "Microscope" }
2224     };
2225
2226   TIFFMergeFieldInfo(tiff,TIFFExtensions,sizeof(TIFFExtensions)/
2227     sizeof(*TIFFExtensions));
2228   if (tag_extender != (TIFFExtendProc) NULL)
2229     (*tag_extender)(tiff);
2230   TIFFIgnoreTags(tiff);
2231 }
2232 #endif
2233
2234 ModuleExport size_t RegisterTIFFImage(void)
2235 {
2236 #define TIFFDescription  "Tagged Image File Format"
2237
2238   char
2239     version[MagickPathExtent];
2240
2241   MagickInfo
2242     *entry;
2243
2244   if (tiff_semaphore == (SemaphoreInfo *) NULL)
2245     ActivateSemaphoreInfo(&tiff_semaphore);
2246   LockSemaphoreInfo(tiff_semaphore);
2247   if (instantiate_key == MagickFalse)
2248     {
2249       if (CreateMagickThreadKey(&tiff_exception,NULL) == MagickFalse)
2250         ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
2251       error_handler=TIFFSetErrorHandler(TIFFErrors);
2252       warning_handler=TIFFSetWarningHandler(TIFFWarnings);
2253 #if defined(MAGICKCORE_HAVE_TIFFMERGEFIELDINFO) && defined(MAGICKCORE_HAVE_TIFFSETTAGEXTENDER)
2254       if (tag_extender == (TIFFExtendProc) NULL)
2255         tag_extender=TIFFSetTagExtender(TIFFTagExtender);
2256 #endif
2257       instantiate_key=MagickTrue;
2258     }
2259   UnlockSemaphoreInfo(tiff_semaphore);
2260   *version='\0';
2261 #if defined(TIFF_VERSION)
2262   (void) FormatLocaleString(version,MagickPathExtent,"%d",TIFF_VERSION);
2263 #endif
2264 #if defined(MAGICKCORE_TIFF_DELEGATE)
2265   {
2266     const char
2267       *p;
2268
2269     register ssize_t
2270       i;
2271
2272     p=TIFFGetVersion();
2273     for (i=0; (i < (MagickPathExtent-1)) && (*p != 0) && (*p != '\n'); i++)
2274       version[i]=(*p++);
2275     version[i]='\0';
2276   }
2277 #endif
2278
2279   entry=AcquireMagickInfo("TIFF","GROUP4","Raw CCITT Group4");
2280 #if defined(MAGICKCORE_TIFF_DELEGATE)
2281   entry->decoder=(DecodeImageHandler *) ReadGROUP4Image;
2282   entry->encoder=(EncodeImageHandler *) WriteGROUP4Image;
2283 #endif
2284   entry->flags|=CoderRawSupportFlag;
2285   entry->flags|=CoderEndianSupportFlag;
2286   entry->flags|=CoderSeekableStreamFlag;
2287   entry->flags^=CoderAdjoinFlag;
2288   entry->flags^=CoderUseExtensionFlag;
2289   entry->format_type=ImplicitFormatType;
2290   entry->mime_type=ConstantString("image/tiff");
2291   (void) RegisterMagickInfo(entry);
2292   entry=AcquireMagickInfo("TIFF","PTIF","Pyramid encoded TIFF");
2293 #if defined(MAGICKCORE_TIFF_DELEGATE)
2294   entry->decoder=(DecodeImageHandler *) ReadTIFFImage;
2295   entry->encoder=(EncodeImageHandler *) WritePTIFImage;
2296 #endif
2297   entry->flags|=CoderEndianSupportFlag;
2298   entry->flags|=CoderSeekableStreamFlag;
2299   entry->flags^=CoderUseExtensionFlag;
2300   entry->mime_type=ConstantString("image/tiff");
2301   (void) RegisterMagickInfo(entry);
2302   entry=AcquireMagickInfo("TIFF","TIF",TIFFDescription);
2303 #if defined(MAGICKCORE_TIFF_DELEGATE)
2304   entry->decoder=(DecodeImageHandler *) ReadTIFFImage;
2305   entry->encoder=(EncodeImageHandler *) WriteTIFFImage;
2306 #endif
2307   entry->flags|=CoderEndianSupportFlag;
2308   entry->flags|=CoderSeekableStreamFlag;
2309   entry->flags|=CoderStealthFlag;
2310   entry->flags^=CoderUseExtensionFlag;
2311   if (*version != '\0')
2312     entry->version=ConstantString(version);
2313   entry->mime_type=ConstantString("image/tiff");
2314   (void) RegisterMagickInfo(entry);
2315   entry=AcquireMagickInfo("TIFF","TIFF",TIFFDescription);
2316 #if defined(MAGICKCORE_TIFF_DELEGATE)
2317   entry->decoder=(DecodeImageHandler *) ReadTIFFImage;
2318   entry->encoder=(EncodeImageHandler *) WriteTIFFImage;
2319 #endif
2320   entry->magick=(IsImageFormatHandler *) IsTIFF;
2321   entry->flags|=CoderEndianSupportFlag;
2322   entry->flags|=CoderSeekableStreamFlag;
2323   entry->flags^=CoderUseExtensionFlag;
2324   if (*version != '\0')
2325     entry->version=ConstantString(version);
2326   entry->mime_type=ConstantString("image/tiff");
2327   (void) RegisterMagickInfo(entry);
2328   entry=AcquireMagickInfo("TIFF","TIFF64","Tagged Image File Format (64-bit)");
2329 #if defined(TIFF_VERSION_BIG)
2330   entry->decoder=(DecodeImageHandler *) ReadTIFFImage;
2331   entry->encoder=(EncodeImageHandler *) WriteTIFFImage;
2332 #endif
2333   entry->flags|=CoderEndianSupportFlag;
2334   entry->flags|=CoderSeekableStreamFlag;
2335   entry->flags^=CoderAdjoinFlag;
2336   entry->flags^=CoderUseExtensionFlag;
2337   if (*version != '\0')
2338     entry->version=ConstantString(version);
2339   entry->mime_type=ConstantString("image/tiff");
2340   (void) RegisterMagickInfo(entry);
2341   return(MagickImageCoderSignature);
2342 }
2343 \f
2344 /*
2345 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2346 %                                                                             %
2347 %                                                                             %
2348 %                                                                             %
2349 %   U n r e g i s t e r T I F F I m a g e                                     %
2350 %                                                                             %
2351 %                                                                             %
2352 %                                                                             %
2353 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2354 %
2355 %  UnregisterTIFFImage() removes format registrations made by the TIFF module
2356 %  from the list of supported formats.
2357 %
2358 %  The format of the UnregisterTIFFImage method is:
2359 %
2360 %      UnregisterTIFFImage(void)
2361 %
2362 */
2363 ModuleExport void UnregisterTIFFImage(void)
2364 {
2365   (void) UnregisterMagickInfo("TIFF64");
2366   (void) UnregisterMagickInfo("TIFF");
2367   (void) UnregisterMagickInfo("TIF");
2368   (void) UnregisterMagickInfo("PTIF");
2369   if (tiff_semaphore == (SemaphoreInfo *) NULL)
2370     ActivateSemaphoreInfo(&tiff_semaphore);
2371   LockSemaphoreInfo(tiff_semaphore);
2372   if (instantiate_key != MagickFalse)
2373     {
2374 #if defined(MAGICKCORE_HAVE_TIFFMERGEFIELDINFO) && defined(MAGICKCORE_HAVE_TIFFSETTAGEXTENDER)
2375       if (tag_extender == (TIFFExtendProc) NULL)
2376         (void) TIFFSetTagExtender(tag_extender);
2377 #endif
2378       if (DeleteMagickThreadKey(tiff_exception) == MagickFalse)
2379         ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
2380       (void) TIFFSetWarningHandler(warning_handler);
2381       (void) TIFFSetErrorHandler(error_handler);
2382       instantiate_key=MagickFalse;
2383     }
2384   UnlockSemaphoreInfo(tiff_semaphore);
2385   RelinquishSemaphoreInfo(&tiff_semaphore);
2386 }
2387 \f
2388 #if defined(MAGICKCORE_TIFF_DELEGATE)
2389 /*
2390 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2391 %                                                                             %
2392 %                                                                             %
2393 %                                                                             %
2394 %   W r i t e G R O U P 4 I m a g e                                           %
2395 %                                                                             %
2396 %                                                                             %
2397 %                                                                             %
2398 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2399 %
2400 %  WriteGROUP4Image() writes an image in the raw CCITT Group 4 image format.
2401 %
2402 %  The format of the WriteGROUP4Image method is:
2403 %
2404 %      MagickBooleanType WriteGROUP4Image(const ImageInfo *image_info,
2405 %        Image *image,ExceptionInfo *)
2406 %
2407 %  A description of each parameter follows:
2408 %
2409 %    o image_info: the image info.
2410 %
2411 %    o image:  The image.
2412 %
2413 %    o exception: return any errors or warnings in this structure.
2414 %
2415 */
2416 static MagickBooleanType WriteGROUP4Image(const ImageInfo *image_info,
2417   Image *image,ExceptionInfo *exception)
2418 {
2419   char
2420     filename[MagickPathExtent];
2421
2422   FILE
2423     *file;
2424
2425   Image
2426     *huffman_image;
2427
2428   ImageInfo
2429     *write_info;
2430
2431   int
2432     unique_file;
2433
2434   MagickBooleanType
2435     status;
2436
2437   register ssize_t
2438     i;
2439
2440   ssize_t
2441     count;
2442
2443   TIFF
2444     *tiff;
2445
2446   toff_t
2447     *byte_count,
2448     strip_size;
2449
2450   unsigned char
2451     *buffer;
2452
2453   /*
2454     Write image as CCITT Group4 TIFF image to a temporary file.
2455   */
2456   assert(image_info != (const ImageInfo *) NULL);
2457   assert(image_info->signature == MagickCoreSignature);
2458   assert(image != (Image *) NULL);
2459   assert(image->signature == MagickCoreSignature);
2460   if (image->debug != MagickFalse)
2461     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2462   assert(exception != (ExceptionInfo *) NULL);
2463   assert(exception->signature == MagickCoreSignature);
2464   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
2465   if (status == MagickFalse)
2466     return(status);
2467   huffman_image=CloneImage(image,0,0,MagickTrue,exception);
2468   if (huffman_image == (Image *) NULL)
2469     {
2470       (void) CloseBlob(image);
2471       return(MagickFalse);
2472     }
2473   huffman_image->endian=MSBEndian;
2474   file=(FILE *) NULL;
2475   unique_file=AcquireUniqueFileResource(filename);
2476   if (unique_file != -1)
2477     file=fdopen(unique_file,"wb");
2478   if ((unique_file == -1) || (file == (FILE *) NULL))
2479     {
2480       ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
2481         filename);
2482       return(MagickFalse);
2483     }
2484   (void) FormatLocaleString(huffman_image->filename,MagickPathExtent,"tiff:%s",
2485     filename);
2486   (void) SetImageType(huffman_image,BilevelType,exception);
2487   write_info=CloneImageInfo((ImageInfo *) NULL);
2488   SetImageInfoFile(write_info,file);
2489   (void) SetImageType(image,BilevelType,exception);
2490   (void) SetImageDepth(image,1,exception);
2491   write_info->compression=Group4Compression;
2492   write_info->type=BilevelType;
2493   (void) SetImageOption(write_info,"quantum:polarity","min-is-white");
2494   status=WriteTIFFImage(write_info,huffman_image,exception);
2495   (void) fflush(file);
2496   write_info=DestroyImageInfo(write_info);
2497   if (status == MagickFalse)
2498     {
2499       huffman_image=DestroyImage(huffman_image);
2500       (void) fclose(file);
2501       (void) RelinquishUniqueFileResource(filename);
2502       return(MagickFalse);
2503     }
2504   tiff=TIFFOpen(filename,"rb");
2505   if (tiff == (TIFF *) NULL)
2506     {
2507       huffman_image=DestroyImage(huffman_image);
2508       (void) fclose(file);
2509       (void) RelinquishUniqueFileResource(filename);
2510       ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
2511         image_info->filename);
2512       return(MagickFalse);
2513     }
2514   /*
2515     Allocate raw strip buffer.
2516   */
2517   if (TIFFGetField(tiff,TIFFTAG_STRIPBYTECOUNTS,&byte_count) != 1)
2518     {
2519       TIFFClose(tiff);
2520       huffman_image=DestroyImage(huffman_image);
2521       (void) fclose(file);
2522       (void) RelinquishUniqueFileResource(filename);
2523       return(MagickFalse);
2524     }
2525   strip_size=byte_count[0];
2526   for (i=1; i < (ssize_t) TIFFNumberOfStrips(tiff); i++)
2527     if (byte_count[i] > strip_size)
2528       strip_size=byte_count[i];
2529   buffer=(unsigned char *) AcquireQuantumMemory((size_t) strip_size,
2530     sizeof(*buffer));
2531   if (buffer == (unsigned char *) NULL)
2532     {
2533       TIFFClose(tiff);
2534       huffman_image=DestroyImage(huffman_image);
2535       (void) fclose(file);
2536       (void) RelinquishUniqueFileResource(filename);
2537       ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
2538         image_info->filename);
2539     }
2540   /*
2541     Compress runlength encoded to 2D Huffman pixels.
2542   */
2543   for (i=0; i < (ssize_t) TIFFNumberOfStrips(tiff); i++)
2544   {
2545     count=(ssize_t) TIFFReadRawStrip(tiff,(uint32) i,buffer,strip_size);
2546     if (WriteBlob(image,(size_t) count,buffer) != count)
2547       status=MagickFalse;
2548   }
2549   buffer=(unsigned char *) RelinquishMagickMemory(buffer);
2550   TIFFClose(tiff);
2551   huffman_image=DestroyImage(huffman_image);
2552   (void) fclose(file);
2553   (void) RelinquishUniqueFileResource(filename);
2554   (void) CloseBlob(image);
2555   return(status);
2556 }
2557 #endif
2558 \f
2559 #if defined(MAGICKCORE_TIFF_DELEGATE)
2560 /*
2561 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2562 %                                                                             %
2563 %                                                                             %
2564 %                                                                             %
2565 %   W r i t e P T I F I m a g e                                               %
2566 %                                                                             %
2567 %                                                                             %
2568 %                                                                             %
2569 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2570 %
2571 %  WritePTIFImage() writes an image in the pyrimid-encoded Tagged image file
2572 %  format.
2573 %
2574 %  The format of the WritePTIFImage method is:
2575 %
2576 %      MagickBooleanType WritePTIFImage(const ImageInfo *image_info,
2577 %        Image *image,ExceptionInfo *exception)
2578 %
2579 %  A description of each parameter follows:
2580 %
2581 %    o image_info: the image info.
2582 %
2583 %    o image:  The image.
2584 %
2585 %    o exception: return any errors or warnings in this structure.
2586 %
2587 */
2588 static MagickBooleanType WritePTIFImage(const ImageInfo *image_info,
2589   Image *image,ExceptionInfo *exception)
2590 {
2591   Image
2592     *images,
2593     *next,
2594     *pyramid_image;
2595
2596   ImageInfo
2597     *write_info;
2598
2599   MagickBooleanType
2600     status;
2601
2602   PointInfo
2603     resolution;
2604
2605   size_t
2606     columns,
2607     rows;
2608
2609   /*
2610     Create pyramid-encoded TIFF image.
2611   */
2612   images=NewImageList();
2613   for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
2614   {
2615     Image
2616       *clone_image;
2617
2618     clone_image=CloneImage(next,0,0,MagickFalse,exception);
2619     if (clone_image == (Image *) NULL)
2620       break;
2621     clone_image->previous=NewImageList();
2622     clone_image->next=NewImageList();
2623     (void) SetImageProperty(clone_image,"tiff:subfiletype","none",exception);
2624     AppendImageToList(&images,clone_image);
2625     columns=next->columns;
2626     rows=next->rows;
2627     resolution=next->resolution;
2628     while ((columns > 64) && (rows > 64))
2629     {
2630       columns/=2;
2631       rows/=2;
2632       resolution.x/=2;
2633       resolution.y/=2;
2634       pyramid_image=ResizeImage(next,columns,rows,image->filter,exception);
2635       if (pyramid_image == (Image *) NULL)
2636         break;
2637       pyramid_image->resolution=resolution;
2638       (void) SetImageProperty(pyramid_image,"tiff:subfiletype","REDUCEDIMAGE",
2639         exception);
2640       AppendImageToList(&images,pyramid_image);
2641     }
2642   }
2643   images=GetFirstImageInList(images);
2644   /*
2645     Write pyramid-encoded TIFF image.
2646   */
2647   write_info=CloneImageInfo(image_info);
2648   write_info->adjoin=MagickTrue;
2649   (void) CopyMagickString(write_info->magick,"TIFF",MagickPathExtent);
2650   (void) CopyMagickString(images->magick,"TIFF",MagickPathExtent);
2651   status=WriteTIFFImage(write_info,images,exception);
2652   images=DestroyImageList(images);
2653   write_info=DestroyImageInfo(write_info);
2654   return(status);
2655 }
2656 #endif
2657 \f
2658 #if defined(MAGICKCORE_TIFF_DELEGATE)
2659 /*
2660 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2661 %                                                                             %
2662 %                                                                             %
2663 %   W r i t e T I F F I m a g e                                               %
2664 %                                                                             %
2665 %                                                                             %
2666 %                                                                             %
2667 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2668 %
2669 %  WriteTIFFImage() writes an image in the Tagged image file format.
2670 %
2671 %  The format of the WriteTIFFImage method is:
2672 %
2673 %      MagickBooleanType WriteTIFFImage(const ImageInfo *image_info,
2674 %        Image *image,ExceptionInfo *exception)
2675 %
2676 %  A description of each parameter follows:
2677 %
2678 %    o image_info: the image info.
2679 %
2680 %    o image:  The image.
2681 %
2682 %    o exception: return any errors or warnings in this structure.
2683 %
2684 */
2685
2686 typedef struct _TIFFInfo
2687 {
2688   RectangleInfo
2689     tile_geometry;
2690
2691   unsigned char
2692     *scanline,
2693     *scanlines,
2694     *pixels;
2695 } TIFFInfo;
2696
2697 static void DestroyTIFFInfo(TIFFInfo *tiff_info)
2698 {
2699   assert(tiff_info != (TIFFInfo *) NULL);
2700   if (tiff_info->scanlines != (unsigned char *) NULL)
2701     tiff_info->scanlines=(unsigned char *) RelinquishMagickMemory(
2702       tiff_info->scanlines);
2703   if (tiff_info->pixels != (unsigned char *) NULL)
2704     tiff_info->pixels=(unsigned char *) RelinquishMagickMemory(
2705       tiff_info->pixels);
2706 }
2707
2708 static MagickBooleanType EncodeLabImage(Image *image,ExceptionInfo *exception)
2709 {
2710   CacheView
2711     *image_view;
2712
2713   MagickBooleanType
2714     status;
2715
2716   ssize_t
2717     y;
2718
2719   status=MagickTrue;
2720   image_view=AcquireAuthenticCacheView(image,exception);
2721   for (y=0; y < (ssize_t) image->rows; y++)
2722   {
2723     register Quantum
2724       *magick_restrict q;
2725
2726     register ssize_t
2727       x;
2728
2729     if (status == MagickFalse)
2730       continue;
2731     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2732     if (q == (Quantum *) NULL)
2733       {
2734         status=MagickFalse;
2735         continue;
2736       }
2737     for (x=0; x < (ssize_t) image->columns; x++)
2738     {
2739       double
2740         a,
2741         b;
2742
2743       a=QuantumScale*GetPixela(image,q)-0.5;
2744       if (a < 0.0)
2745         a+=1.0;
2746       b=QuantumScale*GetPixelb(image,q)-0.5;
2747       if (b < 0.0)
2748         b+=1.0;
2749       SetPixela(image,QuantumRange*a,q);
2750       SetPixelb(image,QuantumRange*b,q);
2751       q+=GetPixelChannels(image);
2752     }
2753     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2754       status=MagickFalse;
2755   }
2756   image_view=DestroyCacheView(image_view);
2757   return(status);
2758 }
2759
2760 static MagickBooleanType GetTIFFInfo(const ImageInfo *image_info,
2761   TIFF *tiff,TIFFInfo *tiff_info)
2762 {
2763   const char
2764     *option;
2765
2766   MagickStatusType
2767     flags;
2768
2769   uint32
2770     tile_columns,
2771     tile_rows;
2772
2773   assert(tiff_info != (TIFFInfo *) NULL);
2774   (void) ResetMagickMemory(tiff_info,0,sizeof(*tiff_info));
2775   option=GetImageOption(image_info,"tiff:tile-geometry");
2776   if (option == (const char *) NULL)
2777     return(MagickTrue);
2778   flags=ParseAbsoluteGeometry(option,&tiff_info->tile_geometry);
2779   if ((flags & HeightValue) == 0)
2780     tiff_info->tile_geometry.height=tiff_info->tile_geometry.width;
2781   tile_columns=(uint32) tiff_info->tile_geometry.width;
2782   tile_rows=(uint32) tiff_info->tile_geometry.height;
2783   TIFFDefaultTileSize(tiff,&tile_columns,&tile_rows);
2784   (void) TIFFSetField(tiff,TIFFTAG_TILEWIDTH,tile_columns);
2785   (void) TIFFSetField(tiff,TIFFTAG_TILELENGTH,tile_rows);
2786   tiff_info->tile_geometry.width=tile_columns;
2787   tiff_info->tile_geometry.height=tile_rows;
2788   tiff_info->scanlines=(unsigned char *) AcquireQuantumMemory((size_t)
2789     tile_rows*TIFFScanlineSize(tiff),sizeof(*tiff_info->scanlines));
2790   tiff_info->pixels=(unsigned char *) AcquireQuantumMemory((size_t)
2791     tile_rows*TIFFTileSize(tiff),sizeof(*tiff_info->scanlines));
2792   if ((tiff_info->scanlines == (unsigned char *) NULL) ||
2793       (tiff_info->pixels == (unsigned char *) NULL))
2794     {
2795       DestroyTIFFInfo(tiff_info);
2796       return(MagickFalse);
2797     }
2798   return(MagickTrue);
2799 }
2800
2801 static int32 TIFFWritePixels(TIFF *tiff,TIFFInfo *tiff_info,ssize_t row,
2802   tsample_t sample,Image *image)
2803 {
2804   int32
2805     status;
2806
2807   register ssize_t
2808     i;
2809
2810   register unsigned char
2811     *p,
2812     *q;
2813
2814   size_t
2815     number_tiles,
2816     tile_width;
2817
2818   ssize_t
2819     bytes_per_pixel,
2820     j,
2821     k,
2822     l;
2823
2824   if (TIFFIsTiled(tiff) == 0)
2825     return(TIFFWriteScanline(tiff,tiff_info->scanline,(uint32) row,sample));
2826   /*
2827     Fill scanlines to tile height.
2828   */
2829   i=(ssize_t) (row % tiff_info->tile_geometry.height)*TIFFScanlineSize(tiff);
2830   (void) CopyMagickMemory(tiff_info->scanlines+i,(char *) tiff_info->scanline,
2831     (size_t) TIFFScanlineSize(tiff));
2832   if (((size_t) (row % tiff_info->tile_geometry.height) !=
2833       (tiff_info->tile_geometry.height-1)) &&
2834       (row != (ssize_t) (image->rows-1)))
2835     return(0);
2836   /*
2837     Write tile to TIFF image.
2838   */
2839   status=0;
2840   bytes_per_pixel=TIFFTileSize(tiff)/(ssize_t) (
2841     tiff_info->tile_geometry.height*tiff_info->tile_geometry.width);
2842   number_tiles=(image->columns+tiff_info->tile_geometry.width)/
2843     tiff_info->tile_geometry.width;
2844   for (i=0; i < (ssize_t) number_tiles; i++)
2845   {
2846     tile_width=(i == (ssize_t) (number_tiles-1)) ? image->columns-(i*
2847       tiff_info->tile_geometry.width) : tiff_info->tile_geometry.width;
2848     for (j=0; j < (ssize_t) ((row % tiff_info->tile_geometry.height)+1); j++)
2849       for (k=0; k < (ssize_t) tile_width; k++)
2850       {
2851         if (bytes_per_pixel == 0)
2852           {
2853             p=tiff_info->scanlines+(j*TIFFScanlineSize(tiff)+(i*
2854               tiff_info->tile_geometry.width+k)/8);
2855             q=tiff_info->pixels+(j*TIFFTileRowSize(tiff)+k/8);
2856             *q++=(*p++);
2857             continue;
2858           }
2859         p=tiff_info->scanlines+(j*TIFFScanlineSize(tiff)+(i*
2860           tiff_info->tile_geometry.width+k)*bytes_per_pixel);
2861         q=tiff_info->pixels+(j*TIFFTileRowSize(tiff)+k*bytes_per_pixel);
2862         for (l=0; l < bytes_per_pixel; l++)
2863           *q++=(*p++);
2864       }
2865     if ((i*tiff_info->tile_geometry.width) != image->columns)
2866       status=TIFFWriteTile(tiff,tiff_info->pixels,(uint32) (i*
2867         tiff_info->tile_geometry.width),(uint32) ((row/
2868         tiff_info->tile_geometry.height)*tiff_info->tile_geometry.height),0,
2869         sample);
2870     if (status < 0)
2871       break;
2872   }
2873   return(status);
2874 }
2875
2876 static void TIFFSetProfiles(TIFF *tiff,Image *image)
2877 {
2878   const char
2879     *name;
2880
2881   const StringInfo
2882     *profile;
2883
2884   if (image->profiles == (void *) NULL)
2885     return;
2886   ResetImageProfileIterator(image);
2887   for (name=GetNextImageProfile(image); name != (const char *) NULL; )
2888   {
2889     profile=GetImageProfile(image,name);
2890     if (GetStringInfoLength(profile) == 0)
2891       {
2892         name=GetNextImageProfile(image);
2893         continue;
2894       }
2895 #if defined(TIFFTAG_XMLPACKET)
2896     if (LocaleCompare(name,"xmp") == 0)
2897       (void) TIFFSetField(tiff,TIFFTAG_XMLPACKET,(uint32) GetStringInfoLength(
2898         profile),GetStringInfoDatum(profile));
2899 #endif
2900 #if defined(TIFFTAG_ICCPROFILE)
2901     if (LocaleCompare(name,"icc") == 0)
2902       (void) TIFFSetField(tiff,TIFFTAG_ICCPROFILE,(uint32) GetStringInfoLength(
2903         profile),GetStringInfoDatum(profile));
2904 #endif
2905     if (LocaleCompare(name,"iptc") == 0)
2906       {
2907         size_t
2908           length;
2909
2910         StringInfo
2911           *iptc_profile;
2912
2913         iptc_profile=CloneStringInfo(profile);
2914         length=GetStringInfoLength(profile)+4-(GetStringInfoLength(profile) &
2915           0x03);
2916         SetStringInfoLength(iptc_profile,length);
2917         if (TIFFIsByteSwapped(tiff))
2918           TIFFSwabArrayOfLong((uint32 *) GetStringInfoDatum(iptc_profile),
2919             (unsigned long) (length/4));
2920         (void) TIFFSetField(tiff,TIFFTAG_RICHTIFFIPTC,(uint32)
2921           GetStringInfoLength(iptc_profile)/4,GetStringInfoDatum(iptc_profile));
2922         iptc_profile=DestroyStringInfo(iptc_profile);
2923       }
2924 #if defined(TIFFTAG_PHOTOSHOP)
2925     if (LocaleCompare(name,"8bim") == 0)
2926       (void) TIFFSetField(tiff,TIFFTAG_PHOTOSHOP,(uint32)
2927         GetStringInfoLength(profile),GetStringInfoDatum(profile));
2928 #endif
2929     if (LocaleCompare(name,"tiff:37724") == 0)
2930       (void) TIFFSetField(tiff,37724,(uint32) GetStringInfoLength(profile),
2931         GetStringInfoDatum(profile));
2932     if (LocaleCompare(name,"tiff:34118") == 0)
2933       (void) TIFFSetField(tiff,34118,(uint32) GetStringInfoLength(profile),
2934         GetStringInfoDatum(profile));
2935     name=GetNextImageProfile(image);
2936   }
2937 }
2938
2939 static void TIFFSetProperties(TIFF *tiff,const ImageInfo *image_info,
2940   Image *image,ExceptionInfo *exception)
2941 {
2942   const char
2943     *value;
2944
2945   value=GetImageArtifact(image,"tiff:document");
2946   if (value != (const char *) NULL)
2947     (void) TIFFSetField(tiff,TIFFTAG_DOCUMENTNAME,value);
2948   value=GetImageArtifact(image,"tiff:hostcomputer");
2949   if (value != (const char *) NULL)
2950     (void) TIFFSetField(tiff,TIFFTAG_HOSTCOMPUTER,value);
2951   value=GetImageArtifact(image,"tiff:artist");
2952   if (value != (const char *) NULL)
2953     (void) TIFFSetField(tiff,TIFFTAG_ARTIST,value);
2954   value=GetImageArtifact(image,"tiff:timestamp");
2955   if (value != (const char *) NULL)
2956     (void) TIFFSetField(tiff,TIFFTAG_DATETIME,value);
2957   value=GetImageArtifact(image,"tiff:make");
2958   if (value != (const char *) NULL)
2959     (void) TIFFSetField(tiff,TIFFTAG_MAKE,value);
2960   value=GetImageArtifact(image,"tiff:model");
2961   if (value != (const char *) NULL)
2962     (void) TIFFSetField(tiff,TIFFTAG_MODEL,value);
2963   value=GetImageArtifact(image,"tiff:software");
2964   if (value != (const char *) NULL)
2965     (void) TIFFSetField(tiff,TIFFTAG_SOFTWARE,value);
2966   value=GetImageArtifact(image,"tiff:copyright");
2967   if (value != (const char *) NULL)
2968     (void) TIFFSetField(tiff,TIFFTAG_COPYRIGHT,value);
2969   value=GetImageArtifact(image,"kodak-33423");
2970   if (value != (const char *) NULL)
2971     (void) TIFFSetField(tiff,33423,value);
2972   value=GetImageArtifact(image,"kodak-36867");
2973   if (value != (const char *) NULL)
2974     (void) TIFFSetField(tiff,36867,value);
2975   value=GetImageProperty(image,"label",exception);
2976   if (value != (const char *) NULL)
2977     (void) TIFFSetField(tiff,TIFFTAG_PAGENAME,value);
2978   value=GetImageProperty(image,"comment",exception);
2979   if (value != (const char *) NULL)
2980     (void) TIFFSetField(tiff,TIFFTAG_IMAGEDESCRIPTION,value);
2981   value=GetImageArtifact(image,"tiff:subfiletype");
2982   if (value != (const char *) NULL)
2983     {
2984       if (LocaleCompare(value,"REDUCEDIMAGE") == 0)
2985         (void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_REDUCEDIMAGE);
2986       else
2987         if (LocaleCompare(value,"PAGE") == 0)
2988           (void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_PAGE);
2989         else
2990           if (LocaleCompare(value,"MASK") == 0)
2991             (void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_MASK);
2992     }
2993   else
2994     {
2995       uint16
2996         page,
2997         pages;
2998       
2999       page=(uint16) image->scene;
3000       pages=(uint16) GetImageListLength(image);
3001       if ((image_info->adjoin != MagickFalse) && (pages > 1))
3002         (void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_PAGE);
3003       (void) TIFFSetField(tiff,TIFFTAG_PAGENUMBER,page,pages);
3004     }
3005 }
3006
3007 static void TIFFSetEXIFProperties(TIFF *tiff,Image *image,
3008   ExceptionInfo *exception)
3009 {
3010 #if defined(MAGICKCORE_HAVE_TIFFREADEXIFDIRECTORY)
3011   const char
3012     *value;
3013
3014   register ssize_t
3015     i;
3016
3017   uint32
3018     offset;
3019
3020   /*
3021     Write EXIF properties.
3022   */
3023   offset=0;
3024   (void) TIFFSetField(tiff,TIFFTAG_SUBIFD,1,&offset);
3025   for (i=0; exif_info[i].tag != 0; i++)
3026   {
3027     value=GetImageProperty(image,exif_info[i].property,exception);
3028     if (value == (const char *) NULL)
3029       continue;
3030     switch (exif_info[i].type)
3031     {
3032       case TIFF_ASCII:
3033       {
3034         (void) TIFFSetField(tiff,exif_info[i].tag,value);
3035         break;
3036       }
3037       case TIFF_SHORT:
3038       {
3039         uint16
3040           field;
3041
3042         field=(uint16) StringToLong(value);
3043         (void) TIFFSetField(tiff,exif_info[i].tag,field);
3044         break;
3045       }
3046       case TIFF_LONG:
3047       {
3048         uint16
3049           field;
3050
3051         field=(uint16) StringToLong(value);
3052         (void) TIFFSetField(tiff,exif_info[i].tag,field);
3053         break;
3054       }
3055       case TIFF_RATIONAL:
3056       case TIFF_SRATIONAL:
3057       {
3058         float
3059           field;
3060
3061         field=StringToDouble(value,(char **) NULL);
3062         (void) TIFFSetField(tiff,exif_info[i].tag,field);
3063         break;
3064       }
3065       default:
3066         break;
3067     }
3068   }
3069   /* (void) TIFFSetField(tiff,TIFFTAG_EXIFIFD,offset); */
3070 #else
3071   (void) tiff;
3072   (void) image;
3073 #endif
3074 }
3075
3076 static MagickBooleanType WriteTIFFImage(const ImageInfo *image_info,
3077   Image *image,ExceptionInfo *exception)
3078 {
3079 #if !defined(TIFFDefaultStripSize)
3080 #define TIFFDefaultStripSize(tiff,request)  (8192UL/TIFFScanlineSize(tiff))
3081 #endif
3082
3083   const char
3084     *mode,
3085     *option;
3086
3087   CompressionType
3088     compression;
3089
3090   EndianType
3091     endian_type;
3092
3093   MagickBooleanType
3094     debug,
3095     status;
3096
3097   MagickOffsetType
3098     scene;
3099
3100   QuantumInfo
3101     *quantum_info;
3102
3103   QuantumType
3104     quantum_type;
3105
3106   register ssize_t
3107     i;
3108
3109   size_t
3110     length;
3111
3112   ssize_t
3113     y;
3114
3115   TIFF
3116     *tiff;
3117
3118   TIFFInfo
3119     tiff_info;
3120
3121   uint16
3122     bits_per_sample,
3123     compress_tag,
3124     endian,
3125     photometric;
3126
3127   uint32
3128     rows_per_strip;
3129
3130   unsigned char
3131     *pixels;
3132
3133   /*
3134     Open TIFF file.
3135   */
3136   assert(image_info != (const ImageInfo *) NULL);
3137   assert(image_info->signature == MagickCoreSignature);
3138   assert(image != (Image *) NULL);
3139   assert(image->signature == MagickCoreSignature);
3140   if (image->debug != MagickFalse)
3141     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3142   assert(exception != (ExceptionInfo *) NULL);
3143   assert(exception->signature == MagickCoreSignature);
3144   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
3145   if (status == MagickFalse)
3146     return(status);
3147   (void) SetMagickThreadValue(tiff_exception,exception);
3148   endian_type=UndefinedEndian;
3149   option=GetImageOption(image_info,"tiff:endian");
3150   if (option != (const char *) NULL)
3151     {
3152       if (LocaleNCompare(option,"msb",3) == 0)
3153         endian_type=MSBEndian;
3154       if (LocaleNCompare(option,"lsb",3) == 0)
3155         endian_type=LSBEndian;;
3156     }
3157   switch (endian_type)
3158   {
3159     case LSBEndian: mode="wl"; break;
3160     case MSBEndian: mode="wb"; break;
3161     default: mode="w"; break;
3162   }
3163 #if defined(TIFF_VERSION_BIG)
3164   if (LocaleCompare(image_info->magick,"TIFF64") == 0)
3165     switch (endian_type)
3166     {
3167       case LSBEndian: mode="wl8"; break;
3168       case MSBEndian: mode="wb8"; break;
3169       default: mode="w8"; break;
3170     }
3171 #endif
3172   tiff=TIFFClientOpen(image->filename,mode,(thandle_t) image,TIFFReadBlob,
3173     TIFFWriteBlob,TIFFSeekBlob,TIFFCloseBlob,TIFFGetBlobSize,TIFFMapBlob,
3174     TIFFUnmapBlob);
3175   if (tiff == (TIFF *) NULL)
3176     return(MagickFalse);
3177   scene=0;
3178   debug=IsEventLogging();
3179   (void) debug;
3180   do
3181   {
3182     /*
3183       Initialize TIFF fields.
3184     */
3185     if ((image_info->type != UndefinedType) &&
3186         (image_info->type != OptimizeType))
3187       (void) SetImageType(image,image_info->type,exception);
3188     compression=UndefinedCompression;
3189     if (image->compression != JPEGCompression)
3190       compression=image->compression;
3191     if (image_info->compression != UndefinedCompression)
3192       compression=image_info->compression;
3193     switch (compression)
3194     {
3195       case FaxCompression:
3196       case Group4Compression:
3197       {
3198         (void) SetImageType(image,BilevelType,exception);
3199         (void) SetImageDepth(image,1,exception);
3200         break;
3201       }
3202       case JPEGCompression:
3203       {
3204         (void) SetImageStorageClass(image,DirectClass,exception);
3205         (void) SetImageDepth(image,8,exception);
3206         break;
3207       }
3208       default:
3209         break;
3210     }
3211     quantum_info=AcquireQuantumInfo(image_info,image);
3212     if (quantum_info == (QuantumInfo *) NULL)
3213       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3214     if ((image->storage_class != PseudoClass) && (image->depth >= 32) &&
3215         (quantum_info->format == UndefinedQuantumFormat) &&
3216         (IsHighDynamicRangeImage(image,exception) != MagickFalse))
3217       {
3218         status=SetQuantumFormat(image,quantum_info,FloatingPointQuantumFormat);
3219         if (status == MagickFalse)
3220           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3221       }
3222     if ((LocaleCompare(image_info->magick,"PTIF") == 0) &&
3223         (GetPreviousImageInList(image) != (Image *) NULL))
3224       (void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_REDUCEDIMAGE);
3225     if ((image->columns != (uint32) image->columns) ||
3226         (image->rows != (uint32) image->rows))
3227       ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
3228     (void) TIFFSetField(tiff,TIFFTAG_IMAGELENGTH,(uint32) image->rows);
3229     (void) TIFFSetField(tiff,TIFFTAG_IMAGEWIDTH,(uint32) image->columns);
3230     switch (compression)
3231     {
3232       case FaxCompression:
3233       {
3234         compress_tag=COMPRESSION_CCITTFAX3;
3235         SetQuantumMinIsWhite(quantum_info,MagickTrue);
3236         break;
3237       }
3238       case Group4Compression:
3239       {
3240         compress_tag=COMPRESSION_CCITTFAX4;
3241         SetQuantumMinIsWhite(quantum_info,MagickTrue);
3242         break;
3243       }
3244 #if defined(COMPRESSION_JBIG)
3245       case JBIG1Compression:
3246       {
3247         compress_tag=COMPRESSION_JBIG;
3248         break;
3249       }
3250 #endif
3251       case JPEGCompression:
3252       {
3253         compress_tag=COMPRESSION_JPEG;
3254         break;
3255       }
3256 #if defined(COMPRESSION_LZMA)
3257       case LZMACompression:
3258       {
3259         compress_tag=COMPRESSION_LZMA;
3260         break;
3261       }
3262 #endif
3263       case LZWCompression:
3264       {
3265         compress_tag=COMPRESSION_LZW;
3266         break;
3267       }
3268       case RLECompression:
3269       {
3270         compress_tag=COMPRESSION_PACKBITS;
3271         break;
3272       }
3273       case ZipCompression:
3274       {
3275         compress_tag=COMPRESSION_ADOBE_DEFLATE;
3276         break;
3277       }
3278       case NoCompression:
3279       default:
3280       {
3281         compress_tag=COMPRESSION_NONE;
3282         break;
3283       }
3284     }
3285 #if defined(MAGICKCORE_HAVE_TIFFISCODECCONFIGURED) || (TIFFLIB_VERSION > 20040919)
3286     if ((compress_tag != COMPRESSION_NONE) &&
3287         (TIFFIsCODECConfigured(compress_tag) == 0))
3288       {
3289         (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
3290           "CompressionNotSupported","`%s'",CommandOptionToMnemonic(
3291           MagickCompressOptions,(ssize_t) compression));
3292         compress_tag=COMPRESSION_NONE;
3293         compression=NoCompression;
3294       }
3295 #else
3296       switch (compress_tag)
3297       {
3298 #if defined(CCITT_SUPPORT)
3299         case COMPRESSION_CCITTFAX3:
3300         case COMPRESSION_CCITTFAX4:
3301 #endif
3302 #if defined(YCBCR_SUPPORT) && defined(JPEG_SUPPORT)
3303         case COMPRESSION_JPEG:
3304 #endif
3305 #if defined(LZMA_SUPPORT) && defined(COMPRESSION_LZMA)
3306         case COMPRESSION_LZMA:
3307 #endif
3308 #if defined(LZW_SUPPORT)
3309         case COMPRESSION_LZW:
3310 #endif
3311 #if defined(PACKBITS_SUPPORT)
3312         case COMPRESSION_PACKBITS:
3313 #endif
3314 #if defined(ZIP_SUPPORT)
3315         case COMPRESSION_ADOBE_DEFLATE:
3316 #endif
3317         case COMPRESSION_NONE:
3318           break;
3319         default:
3320         {
3321           (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
3322             "CompressionNotSupported","`%s'",CommandOptionToMnemonic(
3323               MagickCompressOptions,(ssize_t) compression));
3324           compress_tag=COMPRESSION_NONE;
3325           compression=NoCompression;
3326           break;
3327         }
3328       }
3329 #endif
3330     if (image->colorspace == CMYKColorspace)
3331       {
3332         photometric=PHOTOMETRIC_SEPARATED;
3333         (void) TIFFSetField(tiff,TIFFTAG_SAMPLESPERPIXEL,4);
3334         (void) TIFFSetField(tiff,TIFFTAG_INKSET,INKSET_CMYK);
3335       }
3336     else
3337       {
3338         /*
3339           Full color TIFF raster.
3340         */
3341         if (image->colorspace == LabColorspace)
3342           {
3343             photometric=PHOTOMETRIC_CIELAB;
3344             EncodeLabImage(image,exception);
3345           }
3346         else
3347           if (image->colorspace == YCbCrColorspace)
3348             {
3349               photometric=PHOTOMETRIC_YCBCR;
3350               (void) TIFFSetField(tiff,TIFFTAG_YCBCRSUBSAMPLING,1,1);
3351               (void) SetImageStorageClass(image,DirectClass,exception);
3352               (void) SetImageDepth(image,8,exception);
3353             }
3354           else
3355             photometric=PHOTOMETRIC_RGB;
3356         (void) TIFFSetField(tiff,TIFFTAG_SAMPLESPERPIXEL,3);
3357         if ((image_info->type != TrueColorType) &&
3358             (image_info->type != TrueColorAlphaType))
3359           {
3360             if ((image_info->type != PaletteType) &&
3361                 (SetImageGray(image,exception) != MagickFalse))
3362               {
3363                 photometric=(uint16) (quantum_info->min_is_white !=
3364                   MagickFalse ? PHOTOMETRIC_MINISWHITE :
3365                   PHOTOMETRIC_MINISBLACK);
3366                 (void) TIFFSetField(tiff,TIFFTAG_SAMPLESPERPIXEL,1);
3367                 if ((image->depth == 1) &&
3368                     (image->alpha_trait == UndefinedPixelTrait))
3369                   SetImageMonochrome(image,exception);
3370               }
3371             else
3372               if (image->storage_class == PseudoClass)
3373                 {
3374                   size_t
3375                     depth;
3376
3377                   /*
3378                     Colormapped TIFF raster.
3379                   */
3380                   (void) TIFFSetField(tiff,TIFFTAG_SAMPLESPERPIXEL,1);
3381                   photometric=PHOTOMETRIC_PALETTE;
3382                   depth=1;
3383                   while ((GetQuantumRange(depth)+1) < image->colors)
3384                     depth<<=1;
3385                   status=SetQuantumDepth(image,quantum_info,depth);
3386                   if (status == MagickFalse)
3387                     ThrowWriterException(ResourceLimitError,
3388                       "MemoryAllocationFailed");
3389                 }
3390           }
3391       }
3392     (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_FILLORDER,&endian);
3393     if ((compress_tag == COMPRESSION_CCITTFAX3) &&
3394         (photometric != PHOTOMETRIC_MINISWHITE))
3395       {
3396         compress_tag=COMPRESSION_NONE;
3397         endian=FILLORDER_MSB2LSB;
3398       }
3399     else
3400       if ((compress_tag == COMPRESSION_CCITTFAX4) &&
3401          (photometric != PHOTOMETRIC_MINISWHITE))
3402        {
3403          compress_tag=COMPRESSION_NONE;
3404          endian=FILLORDER_MSB2LSB;
3405        }
3406     option=GetImageOption(image_info,"tiff:fill-order");
3407     if (option != (const char *) NULL)
3408       {
3409         if (LocaleNCompare(option,"msb",3) == 0)
3410           endian=FILLORDER_MSB2LSB;
3411         if (LocaleNCompare(option,"lsb",3) == 0)
3412           endian=FILLORDER_LSB2MSB;
3413       }
3414     (void) TIFFSetField(tiff,TIFFTAG_COMPRESSION,compress_tag);
3415     (void) TIFFSetField(tiff,TIFFTAG_FILLORDER,endian);
3416     (void) TIFFSetField(tiff,TIFFTAG_BITSPERSAMPLE,quantum_info->depth);
3417     if (image->alpha_trait != UndefinedPixelTrait)
3418       {
3419         uint16
3420           extra_samples,
3421           sample_info[1],
3422           samples_per_pixel;
3423
3424         /*
3425           TIFF has a matte channel.
3426         */
3427         extra_samples=1;
3428         sample_info[0]=EXTRASAMPLE_UNASSALPHA;
3429         option=GetImageOption(image_info,"tiff:alpha");
3430         if (option != (const char *) NULL)
3431           {
3432             if (LocaleCompare(option,"associated") == 0)
3433               sample_info[0]=EXTRASAMPLE_ASSOCALPHA;
3434             else
3435               if (LocaleCompare(option,"unspecified") == 0)
3436                 sample_info[0]=EXTRASAMPLE_UNSPECIFIED;
3437           }
3438         (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_SAMPLESPERPIXEL,
3439           &samples_per_pixel);
3440         (void) TIFFSetField(tiff,TIFFTAG_SAMPLESPERPIXEL,samples_per_pixel+1);
3441         (void) TIFFSetField(tiff,TIFFTAG_EXTRASAMPLES,extra_samples,
3442           &sample_info);
3443         if (sample_info[0] == EXTRASAMPLE_ASSOCALPHA)
3444           SetQuantumAlphaType(quantum_info,AssociatedQuantumAlpha);
3445       }
3446     (void) TIFFSetField(tiff,TIFFTAG_PHOTOMETRIC,photometric);
3447     switch (quantum_info->format)
3448     {
3449       case FloatingPointQuantumFormat:
3450       {
3451         (void) TIFFSetField(tiff,TIFFTAG_SAMPLEFORMAT,SAMPLEFORMAT_IEEEFP);
3452         (void) TIFFSetField(tiff,TIFFTAG_SMINSAMPLEVALUE,quantum_info->minimum);
3453         (void) TIFFSetField(tiff,TIFFTAG_SMAXSAMPLEVALUE,quantum_info->maximum);
3454         break;
3455       }
3456       case SignedQuantumFormat:
3457       {
3458         (void) TIFFSetField(tiff,TIFFTAG_SAMPLEFORMAT,SAMPLEFORMAT_INT);
3459         break;
3460       }
3461       case UnsignedQuantumFormat:
3462       {
3463         (void) TIFFSetField(tiff,TIFFTAG_SAMPLEFORMAT,SAMPLEFORMAT_UINT);
3464         break;
3465       }
3466       default:
3467         break;
3468     }
3469     (void) TIFFSetField(tiff,TIFFTAG_ORIENTATION,ORIENTATION_TOPLEFT);
3470     (void) TIFFSetField(tiff,TIFFTAG_PLANARCONFIG,PLANARCONFIG_CONTIG);
3471     if (photometric == PHOTOMETRIC_RGB)
3472       if ((image_info->interlace == PlaneInterlace) ||
3473           (image_info->interlace == PartitionInterlace))
3474         (void) TIFFSetField(tiff,TIFFTAG_PLANARCONFIG,PLANARCONFIG_SEPARATE);
3475      rows_per_strip=TIFFDefaultStripSize(tiff,0);
3476     option=GetImageOption(image_info,"tiff:rows-per-strip");
3477     if (option != (const char *) NULL)
3478       rows_per_strip=(size_t) strtol(option,(char **) NULL,10);
3479     switch (compress_tag)
3480     {
3481       case COMPRESSION_JPEG:
3482       {
3483 #if defined(JPEG_SUPPORT)
3484         const char
3485           *sampling_factor;
3486
3487         GeometryInfo
3488           geometry_info;
3489
3490         MagickStatusType
3491           flags;
3492
3493         rows_per_strip+=(16-(rows_per_strip % 16));
3494         if (image_info->quality != UndefinedCompressionQuality)
3495           (void) TIFFSetField(tiff,TIFFTAG_JPEGQUALITY,image_info->quality);
3496         (void) TIFFSetField(tiff,TIFFTAG_JPEGCOLORMODE,JPEGCOLORMODE_RAW);
3497         if (IssRGBCompatibleColorspace(image->colorspace) != MagickFalse)
3498           {
3499             const char
3500               *value;
3501
3502             (void) TIFFSetField(tiff,TIFFTAG_JPEGCOLORMODE,JPEGCOLORMODE_RGB);
3503             sampling_factor=(const char *) NULL;
3504             value=GetImageProperty(image,"jpeg:sampling-factor",exception);
3505             if (value != (char *) NULL)
3506               {
3507                 sampling_factor=value;
3508                 if (image->debug != MagickFalse)
3509                   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3510                     "  Input sampling-factors=%s",sampling_factor);
3511               }
3512             if (image_info->sampling_factor != (char *) NULL)
3513               sampling_factor=image_info->sampling_factor;
3514             if (sampling_factor != (const char *) NULL)
3515               {
3516                 flags=ParseGeometry(sampling_factor,&geometry_info);
3517                 if ((flags & SigmaValue) == 0)
3518                   geometry_info.sigma=geometry_info.rho;
3519                 if (image->colorspace == YCbCrColorspace)
3520                   (void) TIFFSetField(tiff,TIFFTAG_YCBCRSUBSAMPLING,(uint16)
3521                     geometry_info.rho,(uint16) geometry_info.sigma);
3522               }
3523           }
3524         (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_BITSPERSAMPLE,
3525           &bits_per_sample);
3526         if (bits_per_sample == 12)
3527           (void) TIFFSetField(tiff,TIFFTAG_JPEGTABLESMODE,JPEGTABLESMODE_QUANT);
3528 #endif
3529         break;
3530       }
3531       case COMPRESSION_ADOBE_DEFLATE:
3532       {
3533         rows_per_strip=(uint32) image->rows;
3534         (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_BITSPERSAMPLE,
3535           &bits_per_sample);
3536         if (((photometric == PHOTOMETRIC_RGB) ||
3537              (photometric == PHOTOMETRIC_MINISBLACK)) &&
3538             ((bits_per_sample == 8) || (bits_per_sample == 16)))
3539           (void) TIFFSetField(tiff,TIFFTAG_PREDICTOR,PREDICTOR_HORIZONTAL);
3540         (void) TIFFSetField(tiff,TIFFTAG_ZIPQUALITY,(long) (
3541           image_info->quality == UndefinedCompressionQuality ? 7 :
3542           MagickMin((ssize_t) image_info->quality/10,9)));
3543         break;
3544       }
3545       case COMPRESSION_CCITTFAX3:
3546       {
3547         /*
3548           Byte-aligned EOL.
3549         */
3550         rows_per_strip=(uint32) image->rows;
3551         (void) TIFFSetField(tiff,TIFFTAG_GROUP3OPTIONS,4);
3552         break;
3553       }
3554       case COMPRESSION_CCITTFAX4:
3555       {
3556         rows_per_strip=(uint32) image->rows;
3557         break;
3558       }
3559 #if defined(LZMA_SUPPORT) && defined(COMPRESSION_LZMA)
3560       case COMPRESSION_LZMA:
3561       {
3562         if (((photometric == PHOTOMETRIC_RGB) ||
3563              (photometric == PHOTOMETRIC_MINISBLACK)) &&
3564             ((bits_per_sample == 8) || (bits_per_sample == 16)))
3565           (void) TIFFSetField(tiff,TIFFTAG_PREDICTOR,PREDICTOR_HORIZONTAL);
3566         (void) TIFFSetField(tiff,TIFFTAG_LZMAPRESET,(long) (
3567           image_info->quality == UndefinedCompressionQuality ? 7 :
3568           MagickMin((ssize_t) image_info->quality/10,9)));
3569         break;
3570       }
3571 #endif
3572       case COMPRESSION_LZW:
3573       {
3574         (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_BITSPERSAMPLE,
3575           &bits_per_sample);
3576         if (((photometric == PHOTOMETRIC_RGB) ||
3577              (photometric == PHOTOMETRIC_MINISBLACK)) &&
3578             ((bits_per_sample == 8) || (bits_per_sample == 16)))
3579           (void) TIFFSetField(tiff,TIFFTAG_PREDICTOR,PREDICTOR_HORIZONTAL);
3580         break;
3581       }
3582       default:
3583         break;
3584     }
3585     if (rows_per_strip < 1)
3586       rows_per_strip=1;
3587     if ((image->rows/rows_per_strip) >= (1UL << 15))
3588       rows_per_strip=(uint32) (image->rows >> 15);
3589     (void) TIFFSetField(tiff,TIFFTAG_ROWSPERSTRIP,rows_per_strip);
3590     if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
3591       {
3592         unsigned short
3593           units;
3594
3595         /*
3596           Set image resolution.
3597         */
3598         units=RESUNIT_NONE;
3599         if (image->units == PixelsPerInchResolution)
3600           units=RESUNIT_INCH;
3601         if (image->units == PixelsPerCentimeterResolution)
3602           units=RESUNIT_CENTIMETER;
3603         (void) TIFFSetField(tiff,TIFFTAG_RESOLUTIONUNIT,(uint16) units);
3604         (void) TIFFSetField(tiff,TIFFTAG_XRESOLUTION,image->resolution.x);
3605         (void) TIFFSetField(tiff,TIFFTAG_YRESOLUTION,image->resolution.y);
3606         if ((image->page.x < 0) || (image->page.y < 0))
3607           (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
3608             "TIFF: negative image positions unsupported","%s",image->filename);
3609         if ((image->page.x > 0) && (image->resolution.x > 0.0))
3610           {
3611             /*
3612               Set horizontal image position.
3613             */
3614             (void) TIFFSetField(tiff,TIFFTAG_XPOSITION,(float) image->page.x/
3615               image->resolution.x);
3616           }
3617         if ((image->page.y > 0) && (image->resolution.y > 0.0))
3618           {
3619             /*
3620               Set vertical image position.
3621             */
3622             (void) TIFFSetField(tiff,TIFFTAG_YPOSITION,(float) image->page.y/
3623               image->resolution.y);
3624           }
3625       }
3626     if (image->chromaticity.white_point.x != 0.0)
3627       {
3628         float
3629           chromaticity[6];
3630
3631         /*
3632           Set image chromaticity.
3633         */
3634         chromaticity[0]=(float) image->chromaticity.red_primary.x;
3635         chromaticity[1]=(float) image->chromaticity.red_primary.y;
3636         chromaticity[2]=(float) image->chromaticity.green_primary.x;
3637         chromaticity[3]=(float) image->chromaticity.green_primary.y;
3638         chromaticity[4]=(float) image->chromaticity.blue_primary.x;
3639         chromaticity[5]=(float) image->chromaticity.blue_primary.y;
3640         (void) TIFFSetField(tiff,TIFFTAG_PRIMARYCHROMATICITIES,chromaticity);
3641         chromaticity[0]=(float) image->chromaticity.white_point.x;
3642         chromaticity[1]=(float) image->chromaticity.white_point.y;
3643         (void) TIFFSetField(tiff,TIFFTAG_WHITEPOINT,chromaticity);
3644       }
3645     if ((LocaleCompare(image_info->magick,"PTIF") != 0) &&
3646         (image_info->adjoin != MagickFalse) && (GetImageListLength(image) > 1))
3647       {
3648         (void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_PAGE);
3649         if (image->scene != 0)
3650           (void) TIFFSetField(tiff,TIFFTAG_PAGENUMBER,(uint16) image->scene,
3651             GetImageListLength(image));
3652       }
3653     if (image->orientation != UndefinedOrientation)
3654       (void) TIFFSetField(tiff,TIFFTAG_ORIENTATION,(uint16) image->orientation);
3655     (void) TIFFSetProfiles(tiff,image);
3656     {
3657       uint16
3658         page,
3659         pages;
3660
3661       page=(uint16) scene;
3662       pages=(uint16) GetImageListLength(image);
3663       if ((LocaleCompare(image_info->magick,"PTIF") != 0) &&
3664           (image_info->adjoin != MagickFalse) && (pages > 1))
3665         (void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_PAGE);
3666       (void) TIFFSetField(tiff,TIFFTAG_PAGENUMBER,page,pages);
3667     }
3668     (void) TIFFSetProperties(tiff,image_info,image,exception);
3669 DisableMSCWarning(4127)
3670     if (0)
3671 RestoreMSCWarning
3672       (void) TIFFSetEXIFProperties(tiff,image,exception);
3673     /*
3674       Write image scanlines.
3675     */
3676     if (GetTIFFInfo(image_info,tiff,&tiff_info) == MagickFalse)
3677       ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3678     quantum_info->endian=LSBEndian;
3679     pixels=(unsigned char *) GetQuantumPixels(quantum_info);
3680     tiff_info.scanline=(unsigned char *) GetQuantumPixels(quantum_info);
3681     switch (photometric)
3682     {
3683       case PHOTOMETRIC_CIELAB:
3684       case PHOTOMETRIC_YCBCR:
3685       case PHOTOMETRIC_RGB:
3686       {
3687         /*
3688           RGB TIFF image.
3689         */
3690         switch (image_info->interlace)
3691         {
3692           case NoInterlace:
3693           default:
3694           {
3695             quantum_type=RGBQuantum;
3696             if (image->alpha_trait != UndefinedPixelTrait)
3697               quantum_type=RGBAQuantum;
3698             for (y=0; y < (ssize_t) image->rows; y++)
3699             {
3700               register const Quantum
3701                 *magick_restrict p;
3702
3703               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3704               if (p == (const Quantum *) NULL)
3705                 break;
3706               length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3707                 quantum_type,pixels,exception);
3708               (void) length;
3709               if (TIFFWritePixels(tiff,&tiff_info,y,0,image) == -1)
3710                 break;
3711               if (image->previous == (Image *) NULL)
3712                 {
3713                   status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
3714                     y,image->rows);
3715                   if (status == MagickFalse)
3716                     break;
3717                 }
3718             }
3719             break;
3720           }
3721           case PlaneInterlace:
3722           case PartitionInterlace:
3723           {
3724             /*
3725               Plane interlacing:  RRRRRR...GGGGGG...BBBBBB...
3726             */
3727             for (y=0; y < (ssize_t) image->rows; y++)
3728             {
3729               register const Quantum
3730                 *magick_restrict p;
3731
3732               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3733               if (p == (const Quantum *) NULL)
3734                 break;
3735               length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3736                 RedQuantum,pixels,exception);
3737               if (TIFFWritePixels(tiff,&tiff_info,y,0,image) == -1)
3738                 break;
3739             }
3740             if (image->previous == (Image *) NULL)
3741               {
3742                 status=SetImageProgress(image,SaveImageTag,100,400);
3743                 if (status == MagickFalse)
3744                   break;
3745               }
3746             for (y=0; y < (ssize_t) image->rows; y++)
3747             {
3748               register const Quantum
3749                 *magick_restrict p;
3750
3751               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3752               if (p == (const Quantum *) NULL)
3753                 break;
3754               length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3755                 GreenQuantum,pixels,exception);
3756               if (TIFFWritePixels(tiff,&tiff_info,y,1,image) == -1)
3757                 break;
3758             }
3759             if (image->previous == (Image *) NULL)
3760               {
3761                 status=SetImageProgress(image,SaveImageTag,200,400);
3762                 if (status == MagickFalse)
3763                   break;
3764               }
3765             for (y=0; y < (ssize_t) image->rows; y++)
3766             {
3767               register const Quantum
3768                 *magick_restrict p;
3769
3770               p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3771               if (p == (const Quantum *) NULL)
3772                 break;
3773               length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3774                 BlueQuantum,pixels,exception);
3775               if (TIFFWritePixels(tiff,&tiff_info,y,2,image) == -1)
3776                 break;
3777             }
3778             if (image->previous == (Image *) NULL)
3779               {
3780                 status=SetImageProgress(image,SaveImageTag,300,400);
3781                 if (status == MagickFalse)
3782                   break;
3783               }
3784             if (image->alpha_trait != UndefinedPixelTrait)
3785               for (y=0; y < (ssize_t) image->rows; y++)
3786               {
3787                 register const Quantum
3788                   *magick_restrict p;
3789
3790                 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3791                 if (p == (const Quantum *) NULL)
3792                   break;
3793                 length=ExportQuantumPixels(image,(CacheView *) NULL,
3794                   quantum_info,AlphaQuantum,pixels,exception);
3795                 if (TIFFWritePixels(tiff,&tiff_info,y,3,image) == -1)
3796                   break;
3797               }
3798             if (image->previous == (Image *) NULL)
3799               {
3800                 status=SetImageProgress(image,SaveImageTag,400,400);
3801                 if (status == MagickFalse)
3802                   break;
3803               }
3804             break;
3805           }
3806         }
3807         break;
3808       }
3809       case PHOTOMETRIC_SEPARATED:
3810       {
3811         /*
3812           CMYK TIFF image.
3813         */
3814         quantum_type=CMYKQuantum;
3815         if (image->alpha_trait != UndefinedPixelTrait)
3816           quantum_type=CMYKAQuantum;
3817         if (image->colorspace != CMYKColorspace)
3818           (void) TransformImageColorspace(image,CMYKColorspace,exception);
3819         for (y=0; y < (ssize_t) image->rows; y++)
3820         {
3821           register const Quantum
3822             *magick_restrict p;
3823
3824           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3825           if (p == (const Quantum *) NULL)
3826             break;
3827           length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3828             quantum_type,pixels,exception);
3829           if (TIFFWritePixels(tiff,&tiff_info,y,0,image) == -1)
3830             break;
3831           if (image->previous == (Image *) NULL)
3832             {
3833               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
3834                 image->rows);
3835               if (status == MagickFalse)
3836                 break;
3837             }
3838         }
3839         break;
3840       }
3841       case PHOTOMETRIC_PALETTE:
3842       {
3843         uint16
3844           *blue,
3845           *green,
3846           *red;
3847
3848         /*
3849           Colormapped TIFF image.
3850         */
3851         red=(uint16 *) AcquireQuantumMemory(65536,sizeof(*red));
3852         green=(uint16 *) AcquireQuantumMemory(65536,sizeof(*green));
3853         blue=(uint16 *) AcquireQuantumMemory(65536,sizeof(*blue));
3854         if ((red == (uint16 *) NULL) || (green == (uint16 *) NULL) ||
3855             (blue == (uint16 *) NULL))
3856           ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3857         /*
3858           Initialize TIFF colormap.
3859         */
3860         (void) ResetMagickMemory(red,0,65536*sizeof(*red));
3861         (void) ResetMagickMemory(green,0,65536*sizeof(*green));
3862         (void) ResetMagickMemory(blue,0,65536*sizeof(*blue));
3863         for (i=0; i < (ssize_t) image->colors; i++)
3864         {
3865           red[i]=ScaleQuantumToShort(image->colormap[i].red);
3866           green[i]=ScaleQuantumToShort(image->colormap[i].green);
3867           blue[i]=ScaleQuantumToShort(image->colormap[i].blue);
3868         }
3869         (void) TIFFSetField(tiff,TIFFTAG_COLORMAP,red,green,blue);
3870         red=(uint16 *) RelinquishMagickMemory(red);
3871         green=(uint16 *) RelinquishMagickMemory(green);
3872         blue=(uint16 *) RelinquishMagickMemory(blue);
3873       }
3874       default:
3875       {
3876         /*
3877           Convert PseudoClass packets to contiguous grayscale scanlines.
3878         */
3879         quantum_type=IndexQuantum;
3880         if (image->alpha_trait != UndefinedPixelTrait)
3881           {
3882             if (photometric != PHOTOMETRIC_PALETTE)
3883               quantum_type=GrayAlphaQuantum;
3884             else
3885               quantum_type=IndexAlphaQuantum;
3886            }
3887          else
3888            if (photometric != PHOTOMETRIC_PALETTE)
3889              quantum_type=GrayQuantum;
3890         for (y=0; y < (ssize_t) image->rows; y++)
3891         {
3892           register const Quantum
3893             *magick_restrict p;
3894
3895           p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3896           if (p == (const Quantum *) NULL)
3897             break;
3898           length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3899             quantum_type,pixels,exception);
3900           if (TIFFWritePixels(tiff,&tiff_info,y,0,image) == -1)
3901             break;
3902           if (image->previous == (Image *) NULL)
3903             {
3904               status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
3905                 image->rows);
3906               if (status == MagickFalse)
3907                 break;
3908             }
3909         }
3910         break;
3911       }
3912     }
3913     quantum_info=DestroyQuantumInfo(quantum_info);
3914     if (image->colorspace == LabColorspace)
3915       DecodeLabImage(image,exception);
3916     DestroyTIFFInfo(&tiff_info);
3917 DisableMSCWarning(4127)
3918     if (0 && (image_info->verbose != MagickFalse))
3919 RestoreMSCWarning
3920       TIFFPrintDirectory(tiff,stdout,MagickFalse);
3921     (void) TIFFWriteDirectory(tiff);
3922     image=SyncNextImageInList(image);
3923     if (image == (Image *) NULL)
3924       break;
3925     status=SetImageProgress(image,SaveImagesTag,scene++,
3926       GetImageListLength(image));
3927     if (status == MagickFalse)
3928       break;
3929   } while (image_info->adjoin != MagickFalse);
3930   TIFFClose(tiff);
3931   return(MagickTrue);
3932 }
3933 #endif