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