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