blob: 6335f5ac0371ee41d47f4fb8b41ec35fd05aa61e [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
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 %
cristyde984cd2013-12-01 14:49:27 +000016% Cristy %
cristy3ed852e2009-09-05 21:47:34 +000017% July 1992 %
18% %
19% %
Cristy7ce65e72015-12-12 18:03:16 -050020% Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% 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
Cristy9125cd52015-09-17 20:16:13 -040039#ifdef __VMS
40#define JPEG_SUPPORT 1
41#endif
42
cristy3ed852e2009-09-05 21:47:34 +000043/*
44 Include declarations.
45*/
cristy4c08aed2011-07-01 19:47:50 +000046#include "MagickCore/studio.h"
cristyc4debe62012-02-09 13:51:53 +000047#include "MagickCore/artifact.h"
cristy4c08aed2011-07-01 19:47:50 +000048#include "MagickCore/attribute.h"
49#include "MagickCore/blob.h"
50#include "MagickCore/blob-private.h"
51#include "MagickCore/cache.h"
52#include "MagickCore/color.h"
53#include "MagickCore/color-private.h"
54#include "MagickCore/colormap.h"
55#include "MagickCore/colorspace.h"
cristy510d06a2011-07-06 23:43:54 +000056#include "MagickCore/colorspace-private.h"
cristy4c08aed2011-07-01 19:47:50 +000057#include "MagickCore/constitute.h"
58#include "MagickCore/enhance.h"
59#include "MagickCore/exception.h"
60#include "MagickCore/exception-private.h"
61#include "MagickCore/geometry.h"
62#include "MagickCore/image.h"
63#include "MagickCore/image-private.h"
64#include "MagickCore/list.h"
65#include "MagickCore/log.h"
66#include "MagickCore/magick.h"
67#include "MagickCore/memory_.h"
68#include "MagickCore/module.h"
69#include "MagickCore/monitor.h"
70#include "MagickCore/monitor-private.h"
71#include "MagickCore/option.h"
72#include "MagickCore/pixel-accessor.h"
cristy5ee04f12012-09-20 23:48:03 +000073#include "MagickCore/pixel-private.h"
cristy4c08aed2011-07-01 19:47:50 +000074#include "MagickCore/property.h"
75#include "MagickCore/quantum.h"
76#include "MagickCore/quantum-private.h"
77#include "MagickCore/profile.h"
78#include "MagickCore/resize.h"
79#include "MagickCore/resource_.h"
80#include "MagickCore/semaphore.h"
81#include "MagickCore/splay-tree.h"
82#include "MagickCore/static.h"
83#include "MagickCore/statistic.h"
84#include "MagickCore/string_.h"
85#include "MagickCore/string-private.h"
86#include "MagickCore/thread_.h"
cristye40005d2012-03-23 12:18:45 +000087#include "MagickCore/token.h"
cristy4c08aed2011-07-01 19:47:50 +000088#include "MagickCore/utility.h"
cristy3ed852e2009-09-05 21:47:34 +000089#if defined(MAGICKCORE_TIFF_DELEGATE)
90# if defined(MAGICKCORE_HAVE_TIFFCONF_H)
91# include "tiffconf.h"
cristyef8f26b2010-12-19 20:29:16 +000092# endif
cristy3ed852e2009-09-05 21:47:34 +000093# include "tiff.h"
94# include "tiffio.h"
95# if !defined(COMPRESSION_ADOBE_DEFLATE)
96# define COMPRESSION_ADOBE_DEFLATE 8
97# endif
cristyef8f26b2010-12-19 20:29:16 +000098# if !defined(PREDICTOR_HORIZONTAL)
99# define PREDICTOR_HORIZONTAL 2
100# endif
cristy98ca0f52011-10-08 23:19:10 +0000101# if !defined(TIFFTAG_COPYRIGHT)
102# define TIFFTAG_COPYRIGHT 33432
103# endif
104# if !defined(TIFFTAG_OPIIMAGEID)
cristyd58a6622013-12-18 13:51:01 +0000105# define TIFFTAG_OPIIMAGEID 32781
cristy98ca0f52011-10-08 23:19:10 +0000106# endif
dirk14c08dc2015-05-25 11:52:13 +0000107#include "psd-private.h"
108
cristy3ed852e2009-09-05 21:47:34 +0000109/*
110 Typedef declarations.
111*/
dirkde364872014-10-26 21:17:59 +0000112typedef enum
113{
114 ReadSingleSampleMethod,
115 ReadRGBAMethod,
116 ReadCMYKAMethod,
117 ReadYCCKMethod,
118 ReadStripMethod,
119 ReadTileMethod,
120 ReadGenericMethod
121} TIFFMethodType;
122
cristy3ed852e2009-09-05 21:47:34 +0000123#if defined(MAGICKCORE_HAVE_TIFFREADEXIFDIRECTORY)
124typedef struct _ExifInfo
125{
126 unsigned int
127 tag,
cristy9e6517b2013-08-15 12:13:41 +0000128 type,
129 variable_length;
cristy3ed852e2009-09-05 21:47:34 +0000130
131 const char
132 *property;
133} ExifInfo;
134
135static const ExifInfo
136 exif_info[] = {
cristy9e6517b2013-08-15 12:13:41 +0000137 { EXIFTAG_EXPOSURETIME, TIFF_RATIONAL, 0, "exif:ExposureTime" },
138 { EXIFTAG_FNUMBER, TIFF_RATIONAL, 0, "exif:FNumber" },
139 { EXIFTAG_EXPOSUREPROGRAM, TIFF_SHORT, 0, "exif:ExposureProgram" },
140 { EXIFTAG_SPECTRALSENSITIVITY, TIFF_ASCII, 0, "exif:SpectralSensitivity" },
141 { EXIFTAG_ISOSPEEDRATINGS, TIFF_SHORT, 1, "exif:ISOSpeedRatings" },
142 { EXIFTAG_OECF, TIFF_NOTYPE, 0, "exif:OptoelectricConversionFactor" },
143 { EXIFTAG_EXIFVERSION, TIFF_NOTYPE, 0, "exif:ExifVersion" },
144 { EXIFTAG_DATETIMEORIGINAL, TIFF_ASCII, 0, "exif:DateTimeOriginal" },
145 { EXIFTAG_DATETIMEDIGITIZED, TIFF_ASCII, 0, "exif:DateTimeDigitized" },
146 { EXIFTAG_COMPONENTSCONFIGURATION, TIFF_NOTYPE, 0, "exif:ComponentsConfiguration" },
147 { EXIFTAG_COMPRESSEDBITSPERPIXEL, TIFF_RATIONAL, 0, "exif:CompressedBitsPerPixel" },
148 { EXIFTAG_SHUTTERSPEEDVALUE, TIFF_SRATIONAL, 0, "exif:ShutterSpeedValue" },
149 { EXIFTAG_APERTUREVALUE, TIFF_RATIONAL, 0, "exif:ApertureValue" },
150 { EXIFTAG_BRIGHTNESSVALUE, TIFF_SRATIONAL, 0, "exif:BrightnessValue" },
151 { EXIFTAG_EXPOSUREBIASVALUE, TIFF_SRATIONAL, 0, "exif:ExposureBiasValue" },
152 { EXIFTAG_MAXAPERTUREVALUE, TIFF_RATIONAL, 0, "exif:MaxApertureValue" },
153 { EXIFTAG_SUBJECTDISTANCE, TIFF_RATIONAL, 0, "exif:SubjectDistance" },
154 { EXIFTAG_METERINGMODE, TIFF_SHORT, 0, "exif:MeteringMode" },
155 { EXIFTAG_LIGHTSOURCE, TIFF_SHORT, 0, "exif:LightSource" },
156 { EXIFTAG_FLASH, TIFF_SHORT, 0, "exif:Flash" },
157 { EXIFTAG_FOCALLENGTH, TIFF_RATIONAL, 0, "exif:FocalLength" },
158 { EXIFTAG_SUBJECTAREA, TIFF_NOTYPE, 0, "exif:SubjectArea" },
159 { EXIFTAG_MAKERNOTE, TIFF_NOTYPE, 0, "exif:MakerNote" },
160 { EXIFTAG_USERCOMMENT, TIFF_NOTYPE, 0, "exif:UserComment" },
161 { EXIFTAG_SUBSECTIME, TIFF_ASCII, 0, "exif:SubSecTime" },
162 { EXIFTAG_SUBSECTIMEORIGINAL, TIFF_ASCII, 0, "exif:SubSecTimeOriginal" },
163 { EXIFTAG_SUBSECTIMEDIGITIZED, TIFF_ASCII, 0, "exif:SubSecTimeDigitized" },
164 { EXIFTAG_FLASHPIXVERSION, TIFF_NOTYPE, 0, "exif:FlashpixVersion" },
165 { EXIFTAG_PIXELXDIMENSION, TIFF_LONG, 0, "exif:PixelXDimension" },
cristy9e6517b2013-08-15 12:13:41 +0000166 { EXIFTAG_PIXELYDIMENSION, TIFF_LONG, 0, "exif:PixelYDimension" },
cristy9e6517b2013-08-15 12:13:41 +0000167 { EXIFTAG_RELATEDSOUNDFILE, TIFF_ASCII, 0, "exif:RelatedSoundFile" },
168 { EXIFTAG_FLASHENERGY, TIFF_RATIONAL, 0, "exif:FlashEnergy" },
169 { EXIFTAG_SPATIALFREQUENCYRESPONSE, TIFF_NOTYPE, 0, "exif:SpatialFrequencyResponse" },
170 { EXIFTAG_FOCALPLANEXRESOLUTION, TIFF_RATIONAL, 0, "exif:FocalPlaneXResolution" },
171 { EXIFTAG_FOCALPLANEYRESOLUTION, TIFF_RATIONAL, 0, "exif:FocalPlaneYResolution" },
172 { EXIFTAG_FOCALPLANERESOLUTIONUNIT, TIFF_SHORT, 0, "exif:FocalPlaneResolutionUnit" },
173 { EXIFTAG_SUBJECTLOCATION, TIFF_SHORT, 0, "exif:SubjectLocation" },
174 { EXIFTAG_EXPOSUREINDEX, TIFF_RATIONAL, 0, "exif:ExposureIndex" },
175 { EXIFTAG_SENSINGMETHOD, TIFF_SHORT, 0, "exif:SensingMethod" },
176 { EXIFTAG_FILESOURCE, TIFF_NOTYPE, 0, "exif:FileSource" },
177 { EXIFTAG_SCENETYPE, TIFF_NOTYPE, 0, "exif:SceneType" },
178 { EXIFTAG_CFAPATTERN, TIFF_NOTYPE, 0, "exif:CFAPattern" },
179 { EXIFTAG_CUSTOMRENDERED, TIFF_SHORT, 0, "exif:CustomRendered" },
180 { EXIFTAG_EXPOSUREMODE, TIFF_SHORT, 0, "exif:ExposureMode" },
181 { EXIFTAG_WHITEBALANCE, TIFF_SHORT, 0, "exif:WhiteBalance" },
182 { EXIFTAG_DIGITALZOOMRATIO, TIFF_RATIONAL, 0, "exif:DigitalZoomRatio" },
183 { EXIFTAG_FOCALLENGTHIN35MMFILM, TIFF_SHORT, 0, "exif:FocalLengthIn35mmFilm" },
184 { EXIFTAG_SCENECAPTURETYPE, TIFF_SHORT, 0, "exif:SceneCaptureType" },
185 { EXIFTAG_GAINCONTROL, TIFF_RATIONAL, 0, "exif:GainControl" },
186 { EXIFTAG_CONTRAST, TIFF_SHORT, 0, "exif:Contrast" },
187 { EXIFTAG_SATURATION, TIFF_SHORT, 0, "exif:Saturation" },
188 { EXIFTAG_SHARPNESS, TIFF_SHORT, 0, "exif:Sharpness" },
189 { EXIFTAG_DEVICESETTINGDESCRIPTION, TIFF_NOTYPE, 0, "exif:DeviceSettingDescription" },
190 { EXIFTAG_SUBJECTDISTANCERANGE, TIFF_SHORT, 0, "exif:SubjectDistanceRange" },
191 { EXIFTAG_IMAGEUNIQUEID, TIFF_ASCII, 0, "exif:ImageUniqueID" },
192 { 0, 0, 0, (char *) NULL }
cristy3ed852e2009-09-05 21:47:34 +0000193};
194#endif
cristy0805e062011-01-30 02:56:36 +0000195#endif /* MAGICKCORE_TIFF_DELEGATE */
cristy3ed852e2009-09-05 21:47:34 +0000196
197/*
198 Global declarations.
199*/
200static MagickThreadKey
201 tiff_exception;
202
203static SemaphoreInfo
204 *tiff_semaphore = (SemaphoreInfo *) NULL;
205
Cristy97af9962015-12-19 06:51:20 -0500206static TIFFErrorHandler
207 error_handler,
208 warning_handler;
209
cristy3ed852e2009-09-05 21:47:34 +0000210static volatile MagickBooleanType
211 instantiate_key = MagickFalse;
cristy3ed852e2009-09-05 21:47:34 +0000212
213/*
214 Forward declarations.
215*/
216#if defined(MAGICKCORE_TIFF_DELEGATE)
cristy3d7f8062009-09-24 20:45:35 +0000217static Image *
218 ReadTIFFImage(const ImageInfo *,ExceptionInfo *);
219
cristy3ed852e2009-09-05 21:47:34 +0000220static MagickBooleanType
cristy3a37efd2011-08-28 20:31:03 +0000221 WriteGROUP4Image(const ImageInfo *,Image *,ExceptionInfo *),
222 WritePTIFImage(const ImageInfo *,Image *,ExceptionInfo *),
223 WriteTIFFImage(const ImageInfo *,Image *,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +0000224#endif
225
226/*
227%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
228% %
229% %
230% %
231% I s T I F F %
232% %
233% %
234% %
235%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
236%
237% IsTIFF() returns MagickTrue if the image format type, identified by the
238% magick string, is TIFF.
239%
240% The format of the IsTIFF method is:
241%
242% MagickBooleanType IsTIFF(const unsigned char *magick,const size_t length)
243%
244% A description of each parameter follows:
245%
246% o magick: compare image format pattern against these bytes.
247%
248% o length: Specifies the length of the magick string.
249%
250*/
251static MagickBooleanType IsTIFF(const unsigned char *magick,const size_t length)
252{
253 if (length < 4)
254 return(MagickFalse);
255 if (memcmp(magick,"\115\115\000\052",4) == 0)
256 return(MagickTrue);
257 if (memcmp(magick,"\111\111\052\000",4) == 0)
258 return(MagickTrue);
259#if defined(TIFF_VERSION_BIG)
260 if (length < 8)
261 return(MagickFalse);
262 if (memcmp(magick,"\115\115\000\053\000\010\000\000",8) == 0)
263 return(MagickTrue);
264 if (memcmp(magick,"\111\111\053\000\010\000\000\000",8) == 0)
265 return(MagickTrue);
266#endif
267 return(MagickFalse);
268}
269
270#if defined(MAGICKCORE_TIFF_DELEGATE)
271/*
272%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
273% %
274% %
275% %
cristy3d7f8062009-09-24 20:45:35 +0000276% R e a d G R O U P 4 I m a g e %
277% %
278% %
279% %
280%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
281%
282% ReadGROUP4Image() reads a raw CCITT Group 4 image file and returns it. It
283% allocates the memory necessary for the new Image structure and returns a
284% pointer to the new image.
285%
286% The format of the ReadGROUP4Image method is:
287%
288% Image *ReadGROUP4Image(const ImageInfo *image_info,
289% ExceptionInfo *exception)
290%
291% A description of each parameter follows:
292%
293% o image_info: the image info.
294%
295% o exception: return any errors or warnings in this structure.
296%
297*/
298
cristyeaedf062010-05-29 22:36:02 +0000299static inline size_t WriteLSBLong(FILE *file,const size_t value)
cristy3d7f8062009-09-24 20:45:35 +0000300{
301 unsigned char
302 buffer[4];
303
304 buffer[0]=(unsigned char) value;
305 buffer[1]=(unsigned char) (value >> 8);
306 buffer[2]=(unsigned char) (value >> 16);
307 buffer[3]=(unsigned char) (value >> 24);
308 return(fwrite(buffer,1,4,file));
309}
310
311static Image *ReadGROUP4Image(const ImageInfo *image_info,
312 ExceptionInfo *exception)
313{
314 char
cristy151b66d2015-04-15 10:50:31 +0000315 filename[MagickPathExtent];
cristy3d7f8062009-09-24 20:45:35 +0000316
317 FILE
318 *file;
319
320 Image
321 *image;
322
323 ImageInfo
324 *read_info;
325
326 int
327 c,
328 unique_file;
329
330 MagickBooleanType
331 status;
332
333 size_t
334 length;
335
336 ssize_t
337 offset,
338 strip_offset;
339
340 /*
341 Open image file.
342 */
343 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000344 assert(image_info->signature == MagickCoreSignature);
cristy3d7f8062009-09-24 20:45:35 +0000345 if (image_info->debug != MagickFalse)
346 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
347 image_info->filename);
348 assert(exception != (ExceptionInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000349 assert(exception->signature == MagickCoreSignature);
cristy9950d572011-10-01 18:22:35 +0000350 image=AcquireImage(image_info,exception);
cristy3d7f8062009-09-24 20:45:35 +0000351 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
352 if (status == MagickFalse)
353 {
354 image=DestroyImageList(image);
355 return((Image *) NULL);
356 }
357 /*
358 Write raw CCITT Group 4 wrapped as a TIFF image file.
359 */
360 file=(FILE *) NULL;
361 unique_file=AcquireUniqueFileResource(filename);
362 if (unique_file != -1)
363 file=fdopen(unique_file,"wb");
364 if ((unique_file == -1) || (file == (FILE *) NULL))
365 ThrowImageException(FileOpenError,"UnableToCreateTemporaryFile");
366 length=fwrite("\111\111\052\000\010\000\000\000\016\000",1,10,file);
367 length=fwrite("\376\000\003\000\001\000\000\000\000\000\000\000",1,12,file);
368 length=fwrite("\000\001\004\000\001\000\000\000",1,8,file);
369 length=WriteLSBLong(file,image->columns);
370 length=fwrite("\001\001\004\000\001\000\000\000",1,8,file);
371 length=WriteLSBLong(file,image->rows);
372 length=fwrite("\002\001\003\000\001\000\000\000\001\000\000\000",1,12,file);
373 length=fwrite("\003\001\003\000\001\000\000\000\004\000\000\000",1,12,file);
374 length=fwrite("\006\001\003\000\001\000\000\000\000\000\000\000",1,12,file);
375 length=fwrite("\021\001\003\000\001\000\000\000",1,8,file);
376 strip_offset=10+(12*14)+4+8;
cristybb503372010-05-27 20:51:26 +0000377 length=WriteLSBLong(file,(size_t) strip_offset);
cristy3d7f8062009-09-24 20:45:35 +0000378 length=fwrite("\022\001\003\000\001\000\000\000",1,8,file);
cristybb503372010-05-27 20:51:26 +0000379 length=WriteLSBLong(file,(size_t) image_info->orientation);
cristy3d7f8062009-09-24 20:45:35 +0000380 length=fwrite("\025\001\003\000\001\000\000\000\001\000\000\000",1,12,file);
381 length=fwrite("\026\001\004\000\001\000\000\000",1,8,file);
cristy94c8fe42009-10-06 01:57:36 +0000382 length=WriteLSBLong(file,image->rows);
cristy3d7f8062009-09-24 20:45:35 +0000383 length=fwrite("\027\001\004\000\001\000\000\000\000\000\000\000",1,12,file);
384 offset=(ssize_t) ftell(file)-4;
385 length=fwrite("\032\001\005\000\001\000\000\000",1,8,file);
cristybb503372010-05-27 20:51:26 +0000386 length=WriteLSBLong(file,(size_t) (strip_offset-8));
cristy3d7f8062009-09-24 20:45:35 +0000387 length=fwrite("\033\001\005\000\001\000\000\000",1,8,file);
cristybb503372010-05-27 20:51:26 +0000388 length=WriteLSBLong(file,(size_t) (strip_offset-8));
cristy3d7f8062009-09-24 20:45:35 +0000389 length=fwrite("\050\001\003\000\001\000\000\000\002\000\000\000",1,12,file);
390 length=fwrite("\000\000\000\000",1,4,file);
cristy2a11bef2011-10-28 18:33:11 +0000391 length=WriteLSBLong(file,(long) image->resolution.x);
cristy3d7f8062009-09-24 20:45:35 +0000392 length=WriteLSBLong(file,1);
393 for (length=0; (c=ReadBlobByte(image)) != EOF; length++)
394 (void) fputc(c,file);
cristybb503372010-05-27 20:51:26 +0000395 offset=(ssize_t) fseek(file,(ssize_t) offset,SEEK_SET);
cristy3d7f8062009-09-24 20:45:35 +0000396 length=WriteLSBLong(file,(unsigned int) length);
397 (void) fclose(file);
398 (void) CloseBlob(image);
399 image=DestroyImage(image);
400 /*
401 Read TIFF image.
402 */
cristy14efd992009-09-26 23:46:03 +0000403 read_info=CloneImageInfo((ImageInfo *) NULL);
cristy151b66d2015-04-15 10:50:31 +0000404 (void) FormatLocaleString(read_info->filename,MagickPathExtent,"%s",filename);
cristy3d7f8062009-09-24 20:45:35 +0000405 image=ReadTIFFImage(read_info,exception);
406 read_info=DestroyImageInfo(read_info);
407 if (image != (Image *) NULL)
408 {
409 (void) CopyMagickString(image->filename,image_info->filename,
cristy151b66d2015-04-15 10:50:31 +0000410 MagickPathExtent);
cristy3d7f8062009-09-24 20:45:35 +0000411 (void) CopyMagickString(image->magick_filename,image_info->filename,
cristy151b66d2015-04-15 10:50:31 +0000412 MagickPathExtent);
413 (void) CopyMagickString(image->magick,"GROUP4",MagickPathExtent);
cristy3d7f8062009-09-24 20:45:35 +0000414 }
415 (void) RelinquishUniqueFileResource(filename);
416 return(image);
417}
418#endif
419
420#if defined(MAGICKCORE_TIFF_DELEGATE)
421/*
422%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
423% %
424% %
425% %
cristy3ed852e2009-09-05 21:47:34 +0000426% R e a d T I F F I m a g e %
427% %
428% %
429% %
430%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
431%
432% ReadTIFFImage() reads a Tagged image file and returns it. It allocates the
433% memory necessary for the new Image structure and returns a pointer to the
434% new image.
435%
436% The format of the ReadTIFFImage method is:
437%
438% Image *ReadTIFFImage(const ImageInfo *image_info,
439% ExceptionInfo *exception)
440%
441% A description of each parameter follows:
442%
443% o image_info: the image info.
444%
445% o exception: return any errors or warnings in this structure.
446%
447*/
448
dirkde364872014-10-26 21:17:59 +0000449static inline unsigned char ClampYCC(double value)
450{
451 value=255.0-value;
452 if (value < 0.0)
453 return((unsigned char)0);
454 if (value > 255.0)
455 return((unsigned char)255);
456 return((unsigned char)(value));
457}
458
cristy514da942012-07-06 23:24:14 +0000459static MagickBooleanType DecodeLabImage(Image *image,ExceptionInfo *exception)
cristyf2273ac2012-06-30 22:45:42 +0000460{
461 CacheView
462 *image_view;
463
464 MagickBooleanType
465 status;
466
467 ssize_t
468 y;
469
470 status=MagickTrue;
cristy46ff2672012-12-14 15:32:26 +0000471 image_view=AcquireAuthenticCacheView(image,exception);
cristyf2273ac2012-06-30 22:45:42 +0000472 for (y=0; y < (ssize_t) image->rows; y++)
473 {
474 register Quantum
dirk05d2ff72015-11-18 23:13:43 +0100475 *magick_restrict q;
cristyf2273ac2012-06-30 22:45:42 +0000476
477 register ssize_t
478 x;
479
480 if (status == MagickFalse)
481 continue;
482 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
483 if (q == (Quantum *) NULL)
484 {
485 status=MagickFalse;
486 continue;
487 }
488 for (x=0; x < (ssize_t) image->columns; x++)
489 {
cristy514da942012-07-06 23:24:14 +0000490 double
491 a,
492 b;
493
cristy459f7662012-07-07 01:18:24 +0000494 a=QuantumScale*GetPixela(image,q)+0.5;
495 if (a > 1.0)
cristy514da942012-07-06 23:24:14 +0000496 a-=1.0;
cristy459f7662012-07-07 01:18:24 +0000497 b=QuantumScale*GetPixelb(image,q)+0.5;
498 if (b > 1.0)
cristy514da942012-07-06 23:24:14 +0000499 b-=1.0;
cristy514da942012-07-06 23:24:14 +0000500 SetPixela(image,QuantumRange*a,q);
501 SetPixelb(image,QuantumRange*b,q);
cristyf2273ac2012-06-30 22:45:42 +0000502 q+=GetPixelChannels(image);
503 }
504 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
505 status=MagickFalse;
506 }
507 image_view=DestroyCacheView(image_view);
508 return(status);
509}
510
cristy3ed852e2009-09-05 21:47:34 +0000511static MagickBooleanType ReadProfile(Image *image,const char *name,
dirk14c08dc2015-05-25 11:52:13 +0000512 const unsigned char *datum,ssize_t length,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000513{
514 MagickBooleanType
515 status;
516
cristy3ed852e2009-09-05 21:47:34 +0000517 StringInfo
518 *profile;
519
520 if (length < 4)
521 return(MagickFalse);
dirk35cb8332014-12-22 23:49:40 +0000522 profile=BlobToStringInfo(datum,(size_t) length);
cristye8f8f382011-09-01 13:32:37 +0000523 if (profile == (StringInfo *) NULL)
524 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
525 image->filename);
cristyd15e6592011-10-15 00:13:06 +0000526 status=SetImageProfile(image,name,profile,exception);
cristy3ed852e2009-09-05 21:47:34 +0000527 profile=DestroyStringInfo(profile);
528 if (status == MagickFalse)
529 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
530 image->filename);
531 return(MagickTrue);
532}
533
534#if defined(__cplusplus) || defined(c_plusplus)
535extern "C" {
536#endif
537
538static int TIFFCloseBlob(thandle_t image)
539{
540 (void) CloseBlob((Image *) image);
541 return(0);
542}
543
544static void TIFFErrors(const char *module,const char *format,va_list error)
545{
546 char
cristy151b66d2015-04-15 10:50:31 +0000547 message[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +0000548
549 ExceptionInfo
550 *exception;
551
552#if defined(MAGICKCORE_HAVE_VSNPRINTF)
cristy151b66d2015-04-15 10:50:31 +0000553 (void) vsnprintf(message,MagickPathExtent,format,error);
cristy3ed852e2009-09-05 21:47:34 +0000554#else
555 (void) vsprintf(message,format,error);
556#endif
cristy151b66d2015-04-15 10:50:31 +0000557 (void) ConcatenateMagickString(message,".",MagickPathExtent);
Cristy47950f62015-12-18 18:31:40 -0500558 exception=(ExceptionInfo *) GetMagickThreadValue(tiff_exception);
cristy3ed852e2009-09-05 21:47:34 +0000559 if (exception != (ExceptionInfo *) NULL)
cristyb1db6232010-07-26 17:31:48 +0000560 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,message,
561 "`%s'",module);
cristy3ed852e2009-09-05 21:47:34 +0000562}
563
cristy9c47c732011-11-09 19:58:33 +0000564static toff_t TIFFGetBlobSize(thandle_t image)
565{
566 return((toff_t) GetBlobSize((Image *) image));
567}
568
dirk14c08dc2015-05-25 11:52:13 +0000569static void TIFFGetProfiles(TIFF *tiff,Image *image,MagickBooleanType ping,
570 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000571{
572 uint32
573 length;
574
575 unsigned char
576 *profile;
577
cristy3ed852e2009-09-05 21:47:34 +0000578 length=0;
dirk14c08dc2015-05-25 11:52:13 +0000579 if (ping == MagickFalse)
580 {
cristy997c0442014-06-03 11:11:04 +0000581#if defined(TIFFTAG_ICCPROFILE)
dirk14c08dc2015-05-25 11:52:13 +0000582 if ((TIFFGetField(tiff,TIFFTAG_ICCPROFILE,&length,&profile) == 1) &&
583 (profile != (unsigned char *) NULL))
584 (void) ReadProfile(image,"icc",profile,(ssize_t) length,exception);
cristy3ed852e2009-09-05 21:47:34 +0000585#endif
586#if defined(TIFFTAG_PHOTOSHOP)
dirk14c08dc2015-05-25 11:52:13 +0000587 if ((TIFFGetField(tiff,TIFFTAG_PHOTOSHOP,&length,&profile) == 1) &&
588 (profile != (unsigned char *) NULL))
589 (void) ReadProfile(image,"8bim",profile,(ssize_t) length,exception);
cristy3ed852e2009-09-05 21:47:34 +0000590#endif
591#if defined(TIFFTAG_RICHTIFFIPTC)
dirk14c08dc2015-05-25 11:52:13 +0000592 if ((TIFFGetField(tiff,TIFFTAG_RICHTIFFIPTC,&length,&profile) == 1) &&
593 (profile != (unsigned char *) NULL))
594 {
595 if (TIFFIsByteSwapped(tiff) != 0)
596 TIFFSwabArrayOfLong((uint32 *) profile,(size_t) length);
597 (void) ReadProfile(image,"iptc",profile,4L*length,exception);
598 }
cristy3ed852e2009-09-05 21:47:34 +0000599#endif
600#if defined(TIFFTAG_XMLPACKET)
dirk14c08dc2015-05-25 11:52:13 +0000601 if ((TIFFGetField(tiff,TIFFTAG_XMLPACKET,&length,&profile) == 1) &&
602 (profile != (unsigned char *) NULL))
603 (void) ReadProfile(image,"xmp",profile,(ssize_t) length,exception);
cristy3ed852e2009-09-05 21:47:34 +0000604#endif
dirk14c08dc2015-05-25 11:52:13 +0000605 if ((TIFFGetField(tiff,34118,&length,&profile) == 1) &&
606 (profile != (unsigned char *) NULL))
Cristy32565792015-09-17 20:44:51 -0400607 (void) ReadProfile(image,"tiff:34118",profile,(ssize_t) length,
608 exception);
dirk14c08dc2015-05-25 11:52:13 +0000609 }
cristy5e326802014-06-20 20:56:46 +0000610 if ((TIFFGetField(tiff,37724,&length,&profile) == 1) &&
611 (profile != (unsigned char *) NULL))
cristy018f07f2011-09-04 21:15:19 +0000612 (void) ReadProfile(image,"tiff:37724",profile,(ssize_t) length,exception);
cristy3ed852e2009-09-05 21:47:34 +0000613}
614
cristyd15e6592011-10-15 00:13:06 +0000615static void TIFFGetProperties(TIFF *tiff,Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000616{
617 char
cristy151b66d2015-04-15 10:50:31 +0000618 message[MagickPathExtent],
cristy3ed852e2009-09-05 21:47:34 +0000619 *text;
620
cristy98ca0f52011-10-08 23:19:10 +0000621 uint32
cristyfe33a412015-07-27 13:18:43 +0000622 count,
Cristyb5be9322015-09-20 06:43:25 -0400623 length,
cristyfe33a412015-07-27 13:18:43 +0000624 type;
cristy98ca0f52011-10-08 23:19:10 +0000625
Cristyb5be9322015-09-20 06:43:25 -0400626 unsigned long
627 *tietz;
628
629
cristy3ed852e2009-09-05 21:47:34 +0000630 if (TIFFGetField(tiff,TIFFTAG_ARTIST,&text) == 1)
cristyd15e6592011-10-15 00:13:06 +0000631 (void) SetImageProperty(image,"tiff:artist",text,exception);
cristy98ca0f52011-10-08 23:19:10 +0000632 if (TIFFGetField(tiff,TIFFTAG_COPYRIGHT,&text) == 1)
cristyd15e6592011-10-15 00:13:06 +0000633 (void) SetImageProperty(image,"tiff:copyright",text,exception);
cristy3ed852e2009-09-05 21:47:34 +0000634 if (TIFFGetField(tiff,TIFFTAG_DATETIME,&text) == 1)
cristyd15e6592011-10-15 00:13:06 +0000635 (void) SetImageProperty(image,"tiff:timestamp",text,exception);
cristy3ed852e2009-09-05 21:47:34 +0000636 if (TIFFGetField(tiff,TIFFTAG_DOCUMENTNAME,&text) == 1)
cristyd15e6592011-10-15 00:13:06 +0000637 (void) SetImageProperty(image,"tiff:document",text,exception);
cristy98ca0f52011-10-08 23:19:10 +0000638 if (TIFFGetField(tiff,TIFFTAG_HOSTCOMPUTER,&text) == 1)
cristyd15e6592011-10-15 00:13:06 +0000639 (void) SetImageProperty(image,"tiff:hostcomputer",text,exception);
cristy98ca0f52011-10-08 23:19:10 +0000640 if (TIFFGetField(tiff,TIFFTAG_IMAGEDESCRIPTION,&text) == 1)
cristyd15e6592011-10-15 00:13:06 +0000641 (void) SetImageProperty(image,"comment",text,exception);
cristy3ed852e2009-09-05 21:47:34 +0000642 if (TIFFGetField(tiff,TIFFTAG_MAKE,&text) == 1)
cristyd15e6592011-10-15 00:13:06 +0000643 (void) SetImageProperty(image,"tiff:make",text,exception);
cristy3ed852e2009-09-05 21:47:34 +0000644 if (TIFFGetField(tiff,TIFFTAG_MODEL,&text) == 1)
cristyd15e6592011-10-15 00:13:06 +0000645 (void) SetImageProperty(image,"tiff:model",text,exception);
cristy98ca0f52011-10-08 23:19:10 +0000646 if (TIFFGetField(tiff,TIFFTAG_OPIIMAGEID,&count,&text) == 1)
647 {
cristy151b66d2015-04-15 10:50:31 +0000648 if (count >= MagickPathExtent)
649 count=MagickPathExtent-1;
cristy98ca0f52011-10-08 23:19:10 +0000650 (void) CopyMagickString(message,text,count+1);
cristyd15e6592011-10-15 00:13:06 +0000651 (void) SetImageProperty(image,"tiff:image-id",message,exception);
cristy98ca0f52011-10-08 23:19:10 +0000652 }
cristy3ed852e2009-09-05 21:47:34 +0000653 if (TIFFGetField(tiff,TIFFTAG_PAGENAME,&text) == 1)
cristyd15e6592011-10-15 00:13:06 +0000654 (void) SetImageProperty(image,"label",text,exception);
cristy98ca0f52011-10-08 23:19:10 +0000655 if (TIFFGetField(tiff,TIFFTAG_SOFTWARE,&text) == 1)
cristyd15e6592011-10-15 00:13:06 +0000656 (void) SetImageProperty(image,"tiff:software",text,exception);
cristy98ca0f52011-10-08 23:19:10 +0000657 if (TIFFGetField(tiff,33423,&count,&text) == 1)
658 {
cristy151b66d2015-04-15 10:50:31 +0000659 if (count >= MagickPathExtent)
660 count=MagickPathExtent-1;
cristy98ca0f52011-10-08 23:19:10 +0000661 (void) CopyMagickString(message,text,count+1);
cristyd15e6592011-10-15 00:13:06 +0000662 (void) SetImageProperty(image,"tiff:kodak-33423",message,exception);
cristy98ca0f52011-10-08 23:19:10 +0000663 }
664 if (TIFFGetField(tiff,36867,&count,&text) == 1)
665 {
cristy151b66d2015-04-15 10:50:31 +0000666 if (count >= MagickPathExtent)
667 count=MagickPathExtent-1;
cristy98ca0f52011-10-08 23:19:10 +0000668 (void) CopyMagickString(message,text,count+1);
cristyd15e6592011-10-15 00:13:06 +0000669 (void) SetImageProperty(image,"tiff:kodak-36867",message,exception);
cristy98ca0f52011-10-08 23:19:10 +0000670 }
cristyfe33a412015-07-27 13:18:43 +0000671 if (TIFFGetField(tiff,TIFFTAG_SUBFILETYPE,&type) == 1)
672 switch (type)
673 {
674 case 0x01:
675 {
676 (void) SetImageProperty(image,"tiff:subfiletype","REDUCEDIMAGE",
677 exception);
678 break;
679 }
680 case 0x02:
681 {
682 (void) SetImageProperty(image,"tiff:subfiletype","PAGE",exception);
683 break;
684 }
685 case 0x04:
686 {
687 (void) SetImageProperty(image,"tiff:subfiletype","MASK",exception);
688 break;
689 }
690 default:
691 break;
692 }
Cristyb5be9322015-09-20 06:43:25 -0400693 if (TIFFGetField(tiff,37706,&length,&tietz) == 1)
694 {
695 (void) FormatLocaleString(message,MagickPathExtent,"%lu",tietz[0]);
696 (void) SetImageProperty(image,"tiff:tietz_offset",message,exception);
697 }
cristy3ed852e2009-09-05 21:47:34 +0000698}
699
cristyd15e6592011-10-15 00:13:06 +0000700static void TIFFGetEXIFProperties(TIFF *tiff,Image *image,
701 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000702{
703#if defined(MAGICKCORE_HAVE_TIFFREADEXIFDIRECTORY)
704 char
cristy151b66d2015-04-15 10:50:31 +0000705 value[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +0000706
cristybb503372010-05-27 20:51:26 +0000707 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000708 i;
709
710 tdir_t
711 directory;
712
cristyccf4e122011-10-29 00:29:19 +0000713#if defined(TIFF_VERSION_BIG)
714 uint64
715#else
cristy3ed852e2009-09-05 21:47:34 +0000716 uint32
cristyccf4e122011-10-29 00:29:19 +0000717#endif
cristy3ed852e2009-09-05 21:47:34 +0000718 offset;
719
cristy7992e402011-09-16 15:24:22 +0000720 void
721 *sans;
722
cristy3ed852e2009-09-05 21:47:34 +0000723 /*
724 Read EXIF properties.
725 */
cristy00170cd2012-01-25 00:55:46 +0000726 offset=0;
cristy3abd1032014-06-03 01:09:12 +0000727 if (TIFFGetField(tiff,TIFFTAG_EXIFIFD,&offset) != 1)
cristy3ed852e2009-09-05 21:47:34 +0000728 return;
729 directory=TIFFCurrentDirectory(tiff);
cristy3abd1032014-06-03 01:09:12 +0000730 if (TIFFReadEXIFDirectory(tiff,offset) != 1)
dirkd49a3a52014-02-07 23:30:34 +0000731 {
dirkba6d7782015-06-20 10:14:02 +0000732 TIFFSetDirectory(tiff,directory);
dirkd49a3a52014-02-07 23:30:34 +0000733 return;
734 }
cristy7992e402011-09-16 15:24:22 +0000735 sans=NULL;
cristy3ed852e2009-09-05 21:47:34 +0000736 for (i=0; exif_info[i].tag != 0; i++)
737 {
738 *value='\0';
739 switch (exif_info[i].type)
740 {
741 case TIFF_ASCII:
742 {
743 char
dirk18ec3562013-12-21 14:43:07 +0000744 *ascii;
cristy3ed852e2009-09-05 21:47:34 +0000745
dirk18ec3562013-12-21 14:43:07 +0000746 ascii=(char *) NULL;
cristy3abd1032014-06-03 01:09:12 +0000747 if ((TIFFGetField(tiff,exif_info[i].tag,&ascii,&sans,&sans) == 1) &&
dirk18ec3562013-12-21 14:43:07 +0000748 (ascii != (char *) NULL) && (*ascii != '\0'))
cristy151b66d2015-04-15 10:50:31 +0000749 (void) CopyMagickString(value,ascii,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000750 break;
751 }
752 case TIFF_SHORT:
753 {
cristy1c45a702014-12-05 11:13:48 +0000754 if (exif_info[i].variable_length == 0)
dirk18ec3562013-12-21 14:43:07 +0000755 {
756 uint16
757 shorty;
758
759 shorty=0;
cristy3abd1032014-06-03 01:09:12 +0000760 if (TIFFGetField(tiff,exif_info[i].tag,&shorty,&sans,&sans) == 1)
cristy151b66d2015-04-15 10:50:31 +0000761 (void) FormatLocaleString(value,MagickPathExtent,"%d",shorty);
dirk18ec3562013-12-21 14:43:07 +0000762 }
cristy1c45a702014-12-05 11:13:48 +0000763 else
cristyb21e5842015-02-10 00:48:08 +0000764 {
cristy1c45a702014-12-05 11:13:48 +0000765 int
766 tiff_status;
cristyb21e5842015-02-10 00:48:08 +0000767
cristy1c45a702014-12-05 11:13:48 +0000768 uint16
769 *shorty;
cristyb21e5842015-02-10 00:48:08 +0000770
cristy1c45a702014-12-05 11:13:48 +0000771 uint16
772 shorty_num;
cristyb21e5842015-02-10 00:48:08 +0000773
cristy1c45a702014-12-05 11:13:48 +0000774 tiff_status=TIFFGetField(tiff,exif_info[i].tag,&shorty_num,&shorty,
cristyb21e5842015-02-10 00:48:08 +0000775 &sans,&sans);
cristy1c45a702014-12-05 11:13:48 +0000776 if (tiff_status == 1)
cristy151b66d2015-04-15 10:50:31 +0000777 (void) FormatLocaleString(value,MagickPathExtent,"%d",
cristy1c45a702014-12-05 11:13:48 +0000778 shorty_num != 0 ? shorty[0] : 0);
779 }
cristy3ed852e2009-09-05 21:47:34 +0000780 break;
781 }
782 case TIFF_LONG:
783 {
cristya93d4962013-09-29 20:20:01 +0000784 uint32
dirk18ec3562013-12-21 14:43:07 +0000785 longy;
cristy3ed852e2009-09-05 21:47:34 +0000786
dirk18ec3562013-12-21 14:43:07 +0000787 longy=0;
cristy3abd1032014-06-03 01:09:12 +0000788 if (TIFFGetField(tiff,exif_info[i].tag,&longy,&sans,&sans) == 1)
cristy151b66d2015-04-15 10:50:31 +0000789 (void) FormatLocaleString(value,MagickPathExtent,"%d",longy);
cristy3ed852e2009-09-05 21:47:34 +0000790 break;
791 }
cristyccf4e122011-10-29 00:29:19 +0000792#if defined(TIFF_VERSION_BIG)
793 case TIFF_LONG8:
794 {
cristya93d4962013-09-29 20:20:01 +0000795 uint64
dirk18ec3562013-12-21 14:43:07 +0000796 long8y;
cristyccf4e122011-10-29 00:29:19 +0000797
dirk18ec3562013-12-21 14:43:07 +0000798 long8y=0;
cristy3abd1032014-06-03 01:09:12 +0000799 if (TIFFGetField(tiff,exif_info[i].tag,&long8y,&sans,&sans) == 1)
cristy151b66d2015-04-15 10:50:31 +0000800 (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double)
dirk18ec3562013-12-21 14:43:07 +0000801 ((MagickOffsetType) long8y));
cristyccf4e122011-10-29 00:29:19 +0000802 break;
803 }
804#endif
cristy3ed852e2009-09-05 21:47:34 +0000805 case TIFF_RATIONAL:
806 case TIFF_SRATIONAL:
cristy7992e402011-09-16 15:24:22 +0000807 case TIFF_FLOAT:
cristy3ed852e2009-09-05 21:47:34 +0000808 {
cristya93d4962013-09-29 20:20:01 +0000809 float
dirk18ec3562013-12-21 14:43:07 +0000810 floaty;
cristy3ed852e2009-09-05 21:47:34 +0000811
dirk18ec3562013-12-21 14:43:07 +0000812 floaty=0.0;
cristy3abd1032014-06-03 01:09:12 +0000813 if (TIFFGetField(tiff,exif_info[i].tag,&floaty,&sans,&sans) == 1)
Cristy32565792015-09-17 20:44:51 -0400814 (void) FormatLocaleString(value,MagickPathExtent,"%g",(double)
815 floaty);
cristy3ed852e2009-09-05 21:47:34 +0000816 break;
817 }
cristy31c130f2013-09-29 20:26:50 +0000818 case TIFF_DOUBLE:
819 {
820 double
dirk18ec3562013-12-21 14:43:07 +0000821 doubley;
cristy31c130f2013-09-29 20:26:50 +0000822
dirk18ec3562013-12-21 14:43:07 +0000823 doubley=0.0;
cristy3abd1032014-06-03 01:09:12 +0000824 if (TIFFGetField(tiff,exif_info[i].tag,&doubley,&sans,&sans) == 1)
cristy151b66d2015-04-15 10:50:31 +0000825 (void) FormatLocaleString(value,MagickPathExtent,"%g",doubley);
cristy31c130f2013-09-29 20:26:50 +0000826 break;
827 }
cristy3ed852e2009-09-05 21:47:34 +0000828 default:
829 break;
830 }
831 if (*value != '\0')
cristyd15e6592011-10-15 00:13:06 +0000832 (void) SetImageProperty(image,exif_info[i].property,value,exception);
cristy3ed852e2009-09-05 21:47:34 +0000833 }
834 TIFFSetDirectory(tiff,directory);
835#else
836 (void) tiff;
837 (void) image;
838#endif
839}
840
841static int TIFFMapBlob(thandle_t image,tdata_t *base,toff_t *size)
842{
843 *base=(tdata_t *) GetBlobStreamData((Image *) image);
844 if (*base != (tdata_t *) NULL)
845 *size=(toff_t) GetBlobSize((Image *) image);
846 if (*base != (tdata_t *) NULL)
847 return(1);
848 return(0);
849}
850
851static tsize_t TIFFReadBlob(thandle_t image,tdata_t data,tsize_t size)
852{
853 tsize_t
854 count;
855
856 count=(tsize_t) ReadBlob((Image *) image,(size_t) size,
857 (unsigned char *) data);
858 return(count);
859}
860
cristybb503372010-05-27 20:51:26 +0000861static int32 TIFFReadPixels(TIFF *tiff,size_t bits_per_sample,
862 tsample_t sample,ssize_t row,tdata_t scanline)
cristy3ed852e2009-09-05 21:47:34 +0000863{
864 int32
865 status;
866
867 (void) bits_per_sample;
868 status=TIFFReadScanline(tiff,scanline,(uint32) row,sample);
869 return(status);
870}
871
872static toff_t TIFFSeekBlob(thandle_t image,toff_t offset,int whence)
873{
874 return((toff_t) SeekBlob((Image *) image,(MagickOffsetType) offset,whence));
875}
876
cristy3ed852e2009-09-05 21:47:34 +0000877static void TIFFUnmapBlob(thandle_t image,tdata_t base,toff_t size)
878{
879 (void) image;
880 (void) base;
881 (void) size;
882}
883
884static void TIFFWarnings(const char *module,const char *format,va_list warning)
885{
886 char
cristy151b66d2015-04-15 10:50:31 +0000887 message[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +0000888
889 ExceptionInfo
890 *exception;
891
892#if defined(MAGICKCORE_HAVE_VSNPRINTF)
cristy151b66d2015-04-15 10:50:31 +0000893 (void) vsnprintf(message,MagickPathExtent,format,warning);
cristy3ed852e2009-09-05 21:47:34 +0000894#else
895 (void) vsprintf(message,format,warning);
896#endif
cristy151b66d2015-04-15 10:50:31 +0000897 (void) ConcatenateMagickString(message,".",MagickPathExtent);
Cristy47950f62015-12-18 18:31:40 -0500898 exception=(ExceptionInfo *) GetMagickThreadValue(tiff_exception);
cristy3ed852e2009-09-05 21:47:34 +0000899 if (exception != (ExceptionInfo *) NULL)
900 (void) ThrowMagickException(exception,GetMagickModule(),CoderWarning,
901 message,"`%s'",module);
902}
903
904static tsize_t TIFFWriteBlob(thandle_t image,tdata_t data,tsize_t size)
905{
906 tsize_t
907 count;
908
909 count=(tsize_t) WriteBlob((Image *) image,(size_t) size,
910 (unsigned char *) data);
911 return(count);
912}
913
cristy9679b082015-01-19 01:47:07 +0000914static TIFFMethodType GetJPEGMethod(Image* image,TIFF *tiff,uint16 photometric,
dirkde364872014-10-26 21:17:59 +0000915 uint16 bits_per_sample,uint16 samples_per_pixel)
916{
917#define BUFFER_SIZE 2048
918
919 MagickOffsetType
920 position,
921 offset;
922
923 register size_t
924 i;
925
926 TIFFMethodType
927 method;
928
dirk36fe2622014-10-27 15:27:24 +0000929#if defined(TIFF_VERSION_BIG)
dirkde364872014-10-26 21:17:59 +0000930 uint64
dirk36fe2622014-10-27 15:27:24 +0000931#else
932 uint32
933#endif
dirkde364872014-10-26 21:17:59 +0000934 **value;
935
936 unsigned char
cristya0b01db2015-02-28 22:13:21 +0000937 buffer[BUFFER_SIZE+32];
dirkde364872014-10-26 21:17:59 +0000938
939 unsigned short
940 length;
941
942 /* only support 8 bit for now */
cristy9679b082015-01-19 01:47:07 +0000943 if ((photometric != PHOTOMETRIC_SEPARATED) || (bits_per_sample != 8) ||
944 (samples_per_pixel != 4))
dirkde364872014-10-26 21:17:59 +0000945 return(ReadGenericMethod);
946 /* Search for Adobe APP14 JPEG Marker */
947 if (!TIFFGetField(tiff,TIFFTAG_STRIPOFFSETS,&value))
948 return(ReadRGBAMethod);
949 position=TellBlob(image);
cristyf6f32c52015-02-25 21:33:21 +0000950 offset=(MagickOffsetType) (value[0]);
dirkde364872014-10-26 21:17:59 +0000951 if (SeekBlob(image,offset,SEEK_SET) != offset)
952 return(ReadRGBAMethod);
953 method=ReadRGBAMethod;
954 if (ReadBlob(image,BUFFER_SIZE,buffer) == BUFFER_SIZE)
955 {
956 for (i=0; i < BUFFER_SIZE; i++)
957 {
958 while (i < BUFFER_SIZE)
959 {
960 if (buffer[i++] == 255)
961 break;
962 }
963 while (i < BUFFER_SIZE)
964 {
965 if (buffer[++i] != 255)
966 break;
967 }
968 if (buffer[i++] == 216) /* JPEG_MARKER_SOI */
969 continue;
970 length=(unsigned short) (((unsigned int) (buffer[i] << 8) |
971 (unsigned int) buffer[i+1]) & 0xffff);
972 if (i+(size_t) length >= BUFFER_SIZE)
973 break;
974 if (buffer[i-1] == 238) /* JPEG_MARKER_APP0+14 */
975 {
976 if (length != 14)
977 break;
978 /* 0 == CMYK, 1 == YCbCr, 2 = YCCK */
979 if (buffer[i+13] == 2)
980 method=ReadYCCKMethod;
981 break;
982 }
983 i+=(size_t) length;
984 }
985 }
cristy85893d32015-05-06 13:44:09 +0000986 (void) SeekBlob(image,position,SEEK_SET);
dirkde364872014-10-26 21:17:59 +0000987 return(method);
988}
989
dirk14c08dc2015-05-25 11:52:13 +0000990static void TIFFReadPhotoshopLayers(Image* image,const ImageInfo *image_info,
991 ExceptionInfo *exception)
992{
993 const char
994 *option;
995
996 const StringInfo
997 *layer_info;
998
999 Image
1000 *layers;
1001
1002 PSDInfo
1003 info;
1004
1005 register ssize_t
1006 i;
1007
1008 if (GetImageListLength(image) != 1)
1009 return;
dirk3a211532015-10-23 22:12:55 +02001010 if ((image_info->number_scenes == 1) && (image_info->scene == 0))
1011 return;
dirk14c08dc2015-05-25 11:52:13 +00001012 option=GetImageOption(image_info,"tiff:ignore-layers");
dirkc229d4b2015-07-14 20:36:01 +00001013 if (option != (const char * ) NULL)
dirk14c08dc2015-05-25 11:52:13 +00001014 return;
1015 layer_info=GetImageProfile(image,"tiff:37724");
1016 if (layer_info == (const StringInfo *) NULL)
1017 return;
1018 for (i=0; i < (ssize_t) layer_info->length-8; i++)
1019 {
dirk87038d52015-08-11 23:56:45 +02001020 if (LocaleNCompare((const char *) (layer_info->datum+i),
1021 image->endian == MSBEndian ? "8BIM" : "MIB8",4) != 0)
dirk14c08dc2015-05-25 11:52:13 +00001022 continue;
1023 i+=4;
dirk87038d52015-08-11 23:56:45 +02001024 if ((LocaleNCompare((const char *) (layer_info->datum+i),
1025 image->endian == MSBEndian ? "Layr" : "ryaL",4) == 0) ||
1026 (LocaleNCompare((const char *) (layer_info->datum+i),
1027 image->endian == MSBEndian ? "LMsk" : "ksML",4) == 0) ||
1028 (LocaleNCompare((const char *) (layer_info->datum+i),
1029 image->endian == MSBEndian ? "Lr16" : "61rL",4) == 0) ||
1030 (LocaleNCompare((const char *) (layer_info->datum+i),
1031 image->endian == MSBEndian ? "Lr32" : "23rL",4) == 0))
dirk14c08dc2015-05-25 11:52:13 +00001032 break;
1033 }
1034 i+=4;
cristyb1253cd2015-05-31 01:06:54 +00001035 if (i >= (ssize_t) (layer_info->length-8))
dirk14c08dc2015-05-25 11:52:13 +00001036 return;
1037 layers=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
dirk42b62302015-10-23 22:45:20 +02001038 (void) DeleteImageProfile(layers,"tiff:37724");
dirk14c08dc2015-05-25 11:52:13 +00001039 AttachBlob(layers->blob,layer_info->datum,layer_info->length);
1040 SeekBlob(layers,(MagickOffsetType) i,SEEK_SET);
1041 info.version=1;
1042 info.columns=layers->columns;
1043 info.rows=layers->rows;
cristyb9d46a12015-06-08 22:29:45 +00001044 info.channels=(unsigned short) layers->number_channels;
dirk75b96c82015-07-14 20:15:34 +00001045 /* Setting the mode to a value that won't change the colorspace */
1046 info.mode=10;
dirk14c08dc2015-05-25 11:52:13 +00001047 ReadPSDLayers(layers,image_info,&info,MagickFalse,exception);
1048 DeleteImageFromList(&layers);
1049 if (layers != (Image *) NULL)
1050 {
dirk96f82a02015-07-18 21:44:04 +00001051 SetImageArtifact(image,"tiff:has-layers","true");
dirk14c08dc2015-05-25 11:52:13 +00001052 AppendImageToList(&image,layers);
1053 while (layers != (Image *) NULL)
1054 {
dirk96f82a02015-07-18 21:44:04 +00001055 SetImageArtifact(layers,"tiff:has-layers","true");
dirk14c08dc2015-05-25 11:52:13 +00001056 DetachBlob(layers->blob);
1057 layers=GetNextImageInList(layers);
1058 }
1059 }
1060}
1061
cristy3ed852e2009-09-05 21:47:34 +00001062#if defined(__cplusplus) || defined(c_plusplus)
1063}
1064#endif
1065
cristyba18d462014-11-02 00:28:12 +00001066static Image *ReadTIFFImage(const ImageInfo *image_info,
1067 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00001068{
cristy3ed852e2009-09-05 21:47:34 +00001069 const char
1070 *option;
1071
1072 float
1073 *chromaticity,
1074 x_position,
1075 y_position,
1076 x_resolution,
1077 y_resolution;
1078
1079 Image
1080 *image;
1081
cristy997c0442014-06-03 11:11:04 +00001082 int
1083 tiff_status;
1084
cristy3ed852e2009-09-05 21:47:34 +00001085 MagickBooleanType
cristy3ed852e2009-09-05 21:47:34 +00001086 status;
1087
1088 MagickSizeType
1089 number_pixels;
1090
1091 QuantumInfo
1092 *quantum_info;
1093
1094 QuantumType
1095 quantum_type;
1096
cristybb503372010-05-27 20:51:26 +00001097 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001098 i;
1099
1100 size_t
cristy3ed852e2009-09-05 21:47:34 +00001101 pad;
1102
cristyc6da28e2011-04-28 01:41:35 +00001103 ssize_t
1104 y;
1105
cristy3ed852e2009-09-05 21:47:34 +00001106 TIFF
1107 *tiff;
1108
cristy3ed852e2009-09-05 21:47:34 +00001109 TIFFMethodType
1110 method;
1111
1112 uint16
1113 compress_tag,
1114 bits_per_sample,
cristyf2687ca2010-06-29 16:32:38 +00001115 endian,
cristy3ed852e2009-09-05 21:47:34 +00001116 extra_samples,
1117 interlace,
1118 max_sample_value,
1119 min_sample_value,
1120 orientation,
1121 pages,
1122 photometric,
1123 *sample_info,
1124 sample_format,
1125 samples_per_pixel,
1126 units,
1127 value;
1128
1129 uint32
1130 height,
1131 rows_per_strip,
1132 width;
1133
1134 unsigned char
1135 *pixels;
1136
cristy3ed852e2009-09-05 21:47:34 +00001137 /*
1138 Open image.
1139 */
1140 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +00001141 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00001142 if (image_info->debug != MagickFalse)
1143 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1144 image_info->filename);
1145 assert(exception != (ExceptionInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +00001146 assert(exception->signature == MagickCoreSignature);
cristy9950d572011-10-01 18:22:35 +00001147 image=AcquireImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +00001148 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1149 if (status == MagickFalse)
1150 {
1151 image=DestroyImageList(image);
1152 return((Image *) NULL);
1153 }
Cristy47950f62015-12-18 18:31:40 -05001154 (void) SetMagickThreadValue(tiff_exception,exception);
cristy1630f7f2011-02-18 01:10:02 +00001155 tiff=TIFFClientOpen(image->filename,"rb",(thandle_t) image,TIFFReadBlob,
cristy3ed852e2009-09-05 21:47:34 +00001156 TIFFWriteBlob,TIFFSeekBlob,TIFFCloseBlob,TIFFGetBlobSize,TIFFMapBlob,
1157 TIFFUnmapBlob);
1158 if (tiff == (TIFF *) NULL)
1159 {
cristy3ed852e2009-09-05 21:47:34 +00001160 image=DestroyImageList(image);
1161 return((Image *) NULL);
1162 }
cristy3ed852e2009-09-05 21:47:34 +00001163 if (image_info->number_scenes != 0)
1164 {
1165 /*
1166 Generate blank images for subimage specification (e.g. image.tif[4].
dirkaf51eab2015-10-08 22:47:31 +02001167 We need to check the number of directores because it is possible that
1168 the subimage(s) are stored in the photoshop profile.
cristy3ed852e2009-09-05 21:47:34 +00001169 */
dirkaf51eab2015-10-08 22:47:31 +02001170 if (image_info->scene < (size_t) TIFFNumberOfDirectories(tiff))
1171 {
1172 for (i=0; i < (ssize_t) image_info->scene; i++)
dirke380de92014-09-07 08:57:02 +00001173 {
dirkaf51eab2015-10-08 22:47:31 +02001174 status=TIFFReadDirectory(tiff) != 0 ? MagickTrue : MagickFalse;
1175 if (status == MagickFalse)
1176 {
1177 TIFFClose(tiff);
1178 image=DestroyImageList(image);
1179 return((Image *) NULL);
1180 }
1181 AcquireNextImage(image_info,image,exception);
1182 if (GetNextImageInList(image) == (Image *) NULL)
1183 {
1184 TIFFClose(tiff);
1185 image=DestroyImageList(image);
1186 return((Image *) NULL);
1187 }
1188 image=SyncNextImageInList(image);
dirke380de92014-09-07 08:57:02 +00001189 }
cristy3ed852e2009-09-05 21:47:34 +00001190 }
dirkaf51eab2015-10-08 22:47:31 +02001191 }
cristy3ed852e2009-09-05 21:47:34 +00001192 do
1193 {
dirk93b02b72013-11-16 16:03:36 +00001194DisableMSCWarning(4127)
cristy3ed852e2009-09-05 21:47:34 +00001195 if (0 && (image_info->verbose != MagickFalse))
1196 TIFFPrintDirectory(tiff,stdout,MagickFalse);
dirkddb0f7a2014-07-14 20:05:15 +00001197RestoreMSCWarning
cristyac7fec22014-06-03 00:52:29 +00001198 if ((TIFFGetField(tiff,TIFFTAG_IMAGEWIDTH,&width) != 1) ||
1199 (TIFFGetField(tiff,TIFFTAG_IMAGELENGTH,&height) != 1) ||
1200 (TIFFGetFieldDefaulted(tiff,TIFFTAG_COMPRESSION,&compress_tag) != 1) ||
1201 (TIFFGetFieldDefaulted(tiff,TIFFTAG_FILLORDER,&endian) != 1) ||
1202 (TIFFGetFieldDefaulted(tiff,TIFFTAG_PLANARCONFIG,&interlace) != 1) ||
1203 (TIFFGetFieldDefaulted(tiff,TIFFTAG_SAMPLESPERPIXEL,&samples_per_pixel) != 1) ||
1204 (TIFFGetFieldDefaulted(tiff,TIFFTAG_BITSPERSAMPLE,&bits_per_sample) != 1) ||
1205 (TIFFGetFieldDefaulted(tiff,TIFFTAG_SAMPLEFORMAT,&sample_format) != 1) ||
1206 (TIFFGetFieldDefaulted(tiff,TIFFTAG_MINSAMPLEVALUE,&min_sample_value) != 1) ||
1207 (TIFFGetFieldDefaulted(tiff,TIFFTAG_MAXSAMPLEVALUE,&max_sample_value) != 1) ||
1208 (TIFFGetFieldDefaulted(tiff,TIFFTAG_PHOTOMETRIC,&photometric) != 1))
1209 {
1210 TIFFClose(tiff);
1211 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1212 }
cristyae1319c2011-01-19 20:18:53 +00001213 if (sample_format == SAMPLEFORMAT_IEEEFP)
cristyd15e6592011-10-15 00:13:06 +00001214 (void) SetImageProperty(image,"quantum:format","floating-point",
1215 exception);
cristy3ed852e2009-09-05 21:47:34 +00001216 switch (photometric)
1217 {
1218 case PHOTOMETRIC_MINISBLACK:
1219 {
cristyd15e6592011-10-15 00:13:06 +00001220 (void) SetImageProperty(image,"tiff:photometric","min-is-black",
1221 exception);
cristy3ed852e2009-09-05 21:47:34 +00001222 break;
1223 }
1224 case PHOTOMETRIC_MINISWHITE:
1225 {
cristyd15e6592011-10-15 00:13:06 +00001226 (void) SetImageProperty(image,"tiff:photometric","min-is-white",
1227 exception);
cristy3ed852e2009-09-05 21:47:34 +00001228 break;
1229 }
1230 case PHOTOMETRIC_PALETTE:
1231 {
cristyd15e6592011-10-15 00:13:06 +00001232 (void) SetImageProperty(image,"tiff:photometric","palette",exception);
cristy3ed852e2009-09-05 21:47:34 +00001233 break;
1234 }
1235 case PHOTOMETRIC_RGB:
1236 {
cristyd15e6592011-10-15 00:13:06 +00001237 (void) SetImageProperty(image,"tiff:photometric","RGB",exception);
cristy3ed852e2009-09-05 21:47:34 +00001238 break;
1239 }
1240 case PHOTOMETRIC_CIELAB:
1241 {
cristyd15e6592011-10-15 00:13:06 +00001242 (void) SetImageProperty(image,"tiff:photometric","CIELAB",exception);
cristy3ed852e2009-09-05 21:47:34 +00001243 break;
1244 }
cristyac7fec22014-06-03 00:52:29 +00001245 case PHOTOMETRIC_LOGL:
dirkba6d7782015-06-20 10:14:02 +00001246 {
Cristyb5be9322015-09-20 06:43:25 -04001247 (void) SetImageProperty(image,"tiff:photometric","CIE Log2(L)",
1248 exception);
cristy886278d2015-03-17 20:05:09 +00001249 break;
dirkba6d7782015-06-20 10:14:02 +00001250 }
cristyac7fec22014-06-03 00:52:29 +00001251 case PHOTOMETRIC_LOGLUV:
dirkba6d7782015-06-20 10:14:02 +00001252 {
cristy5ce7c262015-03-18 18:59:25 +00001253 (void) SetImageProperty(image,"tiff:photometric","LOGLUV",exception);
cristy886278d2015-03-17 20:05:09 +00001254 break;
dirkba6d7782015-06-20 10:14:02 +00001255 }
cristy886278d2015-03-17 20:05:09 +00001256#if defined(PHOTOMETRIC_MASK)
1257 case PHOTOMETRIC_MASK:
cristyac7fec22014-06-03 00:52:29 +00001258 {
cristy5ce7c262015-03-18 18:59:25 +00001259 (void) SetImageProperty(image,"tiff:photometric","MASK",exception);
cristyac7fec22014-06-03 00:52:29 +00001260 break;
1261 }
cristy886278d2015-03-17 20:05:09 +00001262#endif
cristy3ed852e2009-09-05 21:47:34 +00001263 case PHOTOMETRIC_SEPARATED:
1264 {
cristyd15e6592011-10-15 00:13:06 +00001265 (void) SetImageProperty(image,"tiff:photometric","separated",exception);
cristy3ed852e2009-09-05 21:47:34 +00001266 break;
1267 }
cristy79e5dad2010-09-16 19:48:33 +00001268 case PHOTOMETRIC_YCBCR:
1269 {
cristyd15e6592011-10-15 00:13:06 +00001270 (void) SetImageProperty(image,"tiff:photometric","YCBCR",exception);
cristy79e5dad2010-09-16 19:48:33 +00001271 break;
1272 }
cristy3ed852e2009-09-05 21:47:34 +00001273 default:
1274 {
cristyd15e6592011-10-15 00:13:06 +00001275 (void) SetImageProperty(image,"tiff:photometric","unknown",exception);
cristy3ed852e2009-09-05 21:47:34 +00001276 break;
1277 }
1278 }
1279 if (image->debug != MagickFalse)
1280 {
1281 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %ux%u",
1282 (unsigned int) width,(unsigned int) height);
1283 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Interlace: %u",
1284 interlace);
1285 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1286 "Bits per sample: %u",bits_per_sample);
1287 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1288 "Min sample value: %u",min_sample_value);
1289 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1290 "Max sample value: %u",max_sample_value);
1291 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Photometric "
cristyd15e6592011-10-15 00:13:06 +00001292 "interpretation: %s",GetImageProperty(image,"tiff:photometric",
1293 exception));
cristy3ed852e2009-09-05 21:47:34 +00001294 }
cristybb503372010-05-27 20:51:26 +00001295 image->columns=(size_t) width;
1296 image->rows=(size_t) height;
1297 image->depth=(size_t) bits_per_sample;
cristyacabb842014-12-14 23:36:33 +00001298 status=SetImageExtent(image,image->columns,image->rows,exception);
1299 if (status == MagickFalse)
1300 return(DestroyImageList(image));
cristy3ed852e2009-09-05 21:47:34 +00001301 if (image->debug != MagickFalse)
cristye8c25f92010-06-03 00:53:06 +00001302 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Image depth: %.20g",
1303 (double) image->depth);
cristye669ae42012-02-08 19:07:45 +00001304 image->endian=MSBEndian;
cristy50c2b692012-02-06 14:45:10 +00001305 if (endian == FILLORDER_LSB2MSB)
cristye669ae42012-02-08 19:07:45 +00001306 image->endian=LSBEndian;
dirkddb0f7a2014-07-14 20:05:15 +00001307#if defined(MAGICKCORE_HAVE_TIFFISBIGENDIAN)
1308 if (TIFFIsBigEndian(tiff) == 0)
1309 {
1310 (void) SetImageProperty(image,"tiff:endian","lsb",exception);
1311 image->endian=LSBEndian;
1312 }
1313 else
1314 {
1315 (void) SetImageProperty(image,"tiff:endian","msb",exception);
1316 image->endian=MSBEndian;
1317 }
1318#endif
cristyb241f382012-01-01 01:45:57 +00001319 if ((photometric == PHOTOMETRIC_MINISBLACK) ||
1320 (photometric == PHOTOMETRIC_MINISWHITE))
cristye2c4f182012-05-12 14:11:53 +00001321 SetImageColorspace(image,GRAYColorspace,exception);
cristy3ed852e2009-09-05 21:47:34 +00001322 if (photometric == PHOTOMETRIC_SEPARATED)
cristye2c4f182012-05-12 14:11:53 +00001323 SetImageColorspace(image,CMYKColorspace,exception);
cristy3ed852e2009-09-05 21:47:34 +00001324 if (photometric == PHOTOMETRIC_CIELAB)
cristye2c4f182012-05-12 14:11:53 +00001325 SetImageColorspace(image,LabColorspace,exception);
dirk14c08dc2015-05-25 11:52:13 +00001326 TIFFGetProfiles(tiff,image,image_info->ping,exception);
cristye4f023a2013-02-27 21:01:50 +00001327 TIFFGetProperties(tiff,image,exception);
cristy092ec8d2013-04-26 13:46:22 +00001328 option=GetImageOption(image_info,"tiff:exif-properties");
dirk9a846de2015-07-25 16:51:01 +00001329 if (IsStringFalse(option) == MagickFalse) /* enabled by default */
cristye4f023a2013-02-27 21:01:50 +00001330 TIFFGetEXIFProperties(tiff,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00001331 (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_SAMPLESPERPIXEL,
1332 &samples_per_pixel);
cristy3abd1032014-06-03 01:09:12 +00001333 if ((TIFFGetFieldDefaulted(tiff,TIFFTAG_XRESOLUTION,&x_resolution) == 1) &&
1334 (TIFFGetFieldDefaulted(tiff,TIFFTAG_YRESOLUTION,&y_resolution) == 1))
cristy3ed852e2009-09-05 21:47:34 +00001335 {
cristy3abd1032014-06-03 01:09:12 +00001336 image->resolution.x=x_resolution;
1337 image->resolution.y=y_resolution;
cristy3ed852e2009-09-05 21:47:34 +00001338 }
cristy997c0442014-06-03 11:11:04 +00001339 if (TIFFGetFieldDefaulted(tiff,TIFFTAG_RESOLUTIONUNIT,&units) == 1)
1340 {
1341 if (units == RESUNIT_INCH)
1342 image->units=PixelsPerInchResolution;
1343 if (units == RESUNIT_CENTIMETER)
1344 image->units=PixelsPerCentimeterResolution;
1345 }
cristy3abd1032014-06-03 01:09:12 +00001346 if ((TIFFGetFieldDefaulted(tiff,TIFFTAG_XPOSITION,&x_position) == 1) &&
1347 (TIFFGetFieldDefaulted(tiff,TIFFTAG_YPOSITION,&y_position) == 1))
cristy3ed852e2009-09-05 21:47:34 +00001348 {
dirk8e230cb2014-06-09 08:11:19 +00001349 image->page.x=(ssize_t) ceil(x_position*image->resolution.x-0.5);
1350 image->page.y=(ssize_t) ceil(y_position*image->resolution.y-0.5);
cristy3abd1032014-06-03 01:09:12 +00001351 }
1352 if (TIFFGetFieldDefaulted(tiff,TIFFTAG_ORIENTATION,&orientation) == 1)
1353 image->orientation=(OrientationType) orientation;
1354 if (TIFFGetField(tiff,TIFFTAG_WHITEPOINT,&chromaticity) == 1)
1355 {
1356 if (chromaticity != (float *) NULL)
1357 {
1358 image->chromaticity.white_point.x=chromaticity[0];
1359 image->chromaticity.white_point.y=chromaticity[1];
1360 }
1361 }
1362 if (TIFFGetField(tiff,TIFFTAG_PRIMARYCHROMATICITIES,&chromaticity) == 1)
1363 {
1364 if (chromaticity != (float *) NULL)
1365 {
1366 image->chromaticity.red_primary.x=chromaticity[0];
1367 image->chromaticity.red_primary.y=chromaticity[1];
1368 image->chromaticity.green_primary.x=chromaticity[2];
1369 image->chromaticity.green_primary.y=chromaticity[3];
1370 image->chromaticity.blue_primary.x=chromaticity[4];
1371 image->chromaticity.blue_primary.y=chromaticity[5];
1372 }
cristy3ed852e2009-09-05 21:47:34 +00001373 }
cristy3ed852e2009-09-05 21:47:34 +00001374#if defined(MAGICKCORE_HAVE_TIFFISCODECCONFIGURED) || (TIFFLIB_VERSION > 20040919)
1375 if ((compress_tag != COMPRESSION_NONE) &&
1376 (TIFFIsCODECConfigured(compress_tag) == 0))
1377 {
1378 TIFFClose(tiff);
1379 ThrowReaderException(CoderError,"CompressNotSupported");
1380 }
1381#endif
1382 switch (compress_tag)
1383 {
1384 case COMPRESSION_NONE: image->compression=NoCompression; break;
1385 case COMPRESSION_CCITTFAX3: image->compression=FaxCompression; break;
1386 case COMPRESSION_CCITTFAX4: image->compression=Group4Compression; break;
1387 case COMPRESSION_JPEG:
1388 {
1389 image->compression=JPEGCompression;
1390#if defined(JPEG_SUPPORT)
1391 {
1392 char
cristy151b66d2015-04-15 10:50:31 +00001393 sampling_factor[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00001394
cristy997c0442014-06-03 11:11:04 +00001395 int
1396 tiff_status;
1397
cristy3ed852e2009-09-05 21:47:34 +00001398 uint16
1399 horizontal,
1400 vertical;
1401
cristy997c0442014-06-03 11:11:04 +00001402 tiff_status=TIFFGetFieldDefaulted(tiff,TIFFTAG_YCBCRSUBSAMPLING,
1403 &horizontal,&vertical);
1404 if (tiff_status == 1)
cristy3abd1032014-06-03 01:09:12 +00001405 {
Cristyb5be9322015-09-20 06:43:25 -04001406 (void) FormatLocaleString(sampling_factor,MagickPathExtent,
1407 "%dx%d",horizontal,vertical);
cristy3abd1032014-06-03 01:09:12 +00001408 (void) SetImageProperty(image,"jpeg:sampling-factor",
1409 sampling_factor,exception);
1410 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1411 "Sampling Factors: %s",sampling_factor);
1412 }
cristy3ed852e2009-09-05 21:47:34 +00001413 }
1414#endif
1415 break;
1416 }
1417 case COMPRESSION_OJPEG: image->compression=JPEGCompression; break;
cristyfbb0ef02010-12-19 02:32:11 +00001418#if defined(COMPRESSION_LZMA)
1419 case COMPRESSION_LZMA: image->compression=LZMACompression; break;
1420#endif
cristy3ed852e2009-09-05 21:47:34 +00001421 case COMPRESSION_LZW: image->compression=LZWCompression; break;
1422 case COMPRESSION_DEFLATE: image->compression=ZipCompression; break;
1423 case COMPRESSION_ADOBE_DEFLATE: image->compression=ZipCompression; break;
1424 default: image->compression=RLECompression; break;
1425 }
cristy809fdbd2011-12-01 01:26:27 +00001426 /*
1427 Allocate memory for the image and pixel buffer.
1428 */
cristy5f766ef2014-12-14 21:12:47 +00001429 quantum_info=AcquireQuantumInfo(image_info,image);
cristy3ed852e2009-09-05 21:47:34 +00001430 if (quantum_info == (QuantumInfo *) NULL)
cristy8d137bf2010-04-21 23:52:04 +00001431 {
1432 TIFFClose(tiff);
1433 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1434 }
cristy3ed852e2009-09-05 21:47:34 +00001435 if (sample_format == SAMPLEFORMAT_UINT)
1436 status=SetQuantumFormat(image,quantum_info,UnsignedQuantumFormat);
1437 if (sample_format == SAMPLEFORMAT_INT)
1438 status=SetQuantumFormat(image,quantum_info,SignedQuantumFormat);
1439 if (sample_format == SAMPLEFORMAT_IEEEFP)
1440 status=SetQuantumFormat(image,quantum_info,FloatingPointQuantumFormat);
1441 if (status == MagickFalse)
cristy8d137bf2010-04-21 23:52:04 +00001442 {
1443 TIFFClose(tiff);
dirkba6d7782015-06-20 10:14:02 +00001444 quantum_info=DestroyQuantumInfo(quantum_info);
cristy8d137bf2010-04-21 23:52:04 +00001445 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1446 }
cristy3ed852e2009-09-05 21:47:34 +00001447 status=MagickTrue;
1448 switch (photometric)
1449 {
1450 case PHOTOMETRIC_MINISBLACK:
1451 {
1452 quantum_info->min_is_white=MagickFalse;
1453 break;
1454 }
1455 case PHOTOMETRIC_MINISWHITE:
1456 {
1457 quantum_info->min_is_white=MagickTrue;
1458 break;
1459 }
1460 default:
1461 break;
1462 }
cristy997c0442014-06-03 11:11:04 +00001463 tiff_status=TIFFGetFieldDefaulted(tiff,TIFFTAG_EXTRASAMPLES,&extra_samples,
1464 &sample_info);
1465 if (tiff_status == 1)
cristy3ed852e2009-09-05 21:47:34 +00001466 {
dirk42bc62a2014-10-07 20:17:51 +00001467 (void) SetImageProperty(image,"tiff:alpha","unspecified",exception);
cristy3abd1032014-06-03 01:09:12 +00001468 if (extra_samples == 0)
1469 {
1470 if ((samples_per_pixel == 4) && (photometric == PHOTOMETRIC_RGB))
1471 image->alpha_trait=BlendPixelTrait;
1472 }
1473 else
1474 for (i=0; i < extra_samples; i++)
1475 {
1476 image->alpha_trait=BlendPixelTrait;
1477 if (sample_info[i] == EXTRASAMPLE_ASSOCALPHA)
dirk42bc62a2014-10-07 20:17:51 +00001478 {
1479 SetQuantumAlphaType(quantum_info,DisassociatedQuantumAlpha);
1480 (void) SetImageProperty(image,"tiff:alpha","associated",
1481 exception);
1482 }
cristy269e8e72014-10-12 21:27:45 +00001483 else
1484 if (sample_info[i] == EXTRASAMPLE_UNASSALPHA)
1485 (void) SetImageProperty(image,"tiff:alpha","unassociated",
1486 exception);
cristy3abd1032014-06-03 01:09:12 +00001487 }
cristy3ed852e2009-09-05 21:47:34 +00001488 }
cristy3ed852e2009-09-05 21:47:34 +00001489 if ((photometric == PHOTOMETRIC_PALETTE) &&
1490 (pow(2.0,1.0*bits_per_sample) <= MaxColormapSize))
1491 {
cristybb503372010-05-27 20:51:26 +00001492 size_t
cristy3ed852e2009-09-05 21:47:34 +00001493 colors;
1494
cristybb503372010-05-27 20:51:26 +00001495 colors=(size_t) GetQuantumRange(bits_per_sample)+1;
cristy018f07f2011-09-04 21:15:19 +00001496 if (AcquireImageColormap(image,colors,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001497 {
1498 TIFFClose(tiff);
1499 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1500 }
1501 }
cristy3ed852e2009-09-05 21:47:34 +00001502 value=(unsigned short) image->scene;
cristy3abd1032014-06-03 01:09:12 +00001503 if (TIFFGetFieldDefaulted(tiff,TIFFTAG_PAGENUMBER,&value,&pages) == 1)
1504 image->scene=value;
cristyb21e5842015-02-10 00:48:08 +00001505 if (image->storage_class == PseudoClass)
1506 {
1507 int
1508 tiff_status;
1509
1510 size_t
1511 range;
1512
1513 uint16
1514 *blue_colormap,
1515 *green_colormap,
1516 *red_colormap;
1517
1518 /*
1519 Initialize colormap.
1520 */
1521 tiff_status=TIFFGetField(tiff,TIFFTAG_COLORMAP,&red_colormap,
1522 &green_colormap,&blue_colormap);
1523 if (tiff_status == 1)
1524 {
1525 if ((red_colormap != (uint16 *) NULL) &&
1526 (green_colormap != (uint16 *) NULL) &&
1527 (blue_colormap != (uint16 *) NULL))
1528 {
1529 range=255; /* might be old style 8-bit colormap */
1530 for (i=0; i < (ssize_t) image->colors; i++)
1531 if ((red_colormap[i] >= 256) || (green_colormap[i] >= 256) ||
1532 (blue_colormap[i] >= 256))
1533 {
1534 range=65535;
1535 break;
1536 }
1537 for (i=0; i < (ssize_t) image->colors; i++)
1538 {
1539 image->colormap[i].red=ClampToQuantum(((double)
1540 QuantumRange*red_colormap[i])/range);
1541 image->colormap[i].green=ClampToQuantum(((double)
1542 QuantumRange*green_colormap[i])/range);
1543 image->colormap[i].blue=ClampToQuantum(((double)
1544 QuantumRange*blue_colormap[i])/range);
1545 }
1546 }
1547 }
1548 if (image->alpha_trait == UndefinedPixelTrait)
1549 image->depth=GetImageDepth(image,exception);
1550 }
cristy3ed852e2009-09-05 21:47:34 +00001551 if (image_info->ping != MagickFalse)
1552 {
1553 if (image_info->number_scenes != 0)
1554 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
cristybe83c812015-01-28 18:16:24 +00001555 {
1556 quantum_info=DestroyQuantumInfo(quantum_info);
1557 break;
1558 }
cristy3ed852e2009-09-05 21:47:34 +00001559 goto next_tiff_frame;
1560 }
1561 method=ReadGenericMethod;
cristy3abd1032014-06-03 01:09:12 +00001562 if (TIFFGetField(tiff,TIFFTAG_ROWSPERSTRIP,&rows_per_strip) == 1)
cristy3ed852e2009-09-05 21:47:34 +00001563 {
1564 char
cristy151b66d2015-04-15 10:50:31 +00001565 value[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00001566
1567 method=ReadStripMethod;
cristy151b66d2015-04-15 10:50:31 +00001568 (void) FormatLocaleString(value,MagickPathExtent,"%u",
cristy3ed852e2009-09-05 21:47:34 +00001569 (unsigned int) rows_per_strip);
cristyd15e6592011-10-15 00:13:06 +00001570 (void) SetImageProperty(image,"tiff:rows-per-strip",value,exception);
cristy3ed852e2009-09-05 21:47:34 +00001571 }
1572 if ((samples_per_pixel >= 2) && (interlace == PLANARCONFIG_CONTIG))
1573 method=ReadRGBAMethod;
1574 if ((samples_per_pixel >= 2) && (interlace == PLANARCONFIG_SEPARATE))
1575 method=ReadCMYKAMethod;
1576 if ((photometric != PHOTOMETRIC_RGB) &&
1577 (photometric != PHOTOMETRIC_CIELAB) &&
1578 (photometric != PHOTOMETRIC_SEPARATED))
1579 method=ReadGenericMethod;
1580 if (image->storage_class == PseudoClass)
1581 method=ReadSingleSampleMethod;
1582 if ((photometric == PHOTOMETRIC_MINISBLACK) ||
1583 (photometric == PHOTOMETRIC_MINISWHITE))
1584 method=ReadSingleSampleMethod;
1585 if ((photometric != PHOTOMETRIC_SEPARATED) &&
cristybc736662011-03-09 13:39:42 +00001586 (interlace == PLANARCONFIG_SEPARATE) && (bits_per_sample < 64))
cristy3ed852e2009-09-05 21:47:34 +00001587 method=ReadGenericMethod;
cristy0f4751f2013-07-24 13:06:44 +00001588 if (image->compression == JPEGCompression)
cristy9679b082015-01-19 01:47:07 +00001589 method=GetJPEGMethod(image,tiff,photometric,bits_per_sample,
dirkde364872014-10-26 21:17:59 +00001590 samples_per_pixel);
cristyafe75812014-12-24 22:14:24 +00001591 if (compress_tag == COMPRESSION_JBIG)
cristy256906d2014-12-24 18:47:44 +00001592 method=ReadStripMethod;
cristy3ed852e2009-09-05 21:47:34 +00001593 if (TIFFIsTiled(tiff) != MagickFalse)
1594 method=ReadTileMethod;
cristy50c2b692012-02-06 14:45:10 +00001595 quantum_info->endian=LSBEndian;
cristy3ed852e2009-09-05 21:47:34 +00001596 quantum_type=RGBQuantum;
cristyb3f97ae2015-05-18 12:29:32 +00001597 pixels=(unsigned char *) GetQuantumPixels(quantum_info);
cristy3ed852e2009-09-05 21:47:34 +00001598 switch (method)
1599 {
1600 case ReadSingleSampleMethod:
1601 {
1602 /*
1603 Convert TIFF image to PseudoClass MIFF image.
1604 */
cristy3ed852e2009-09-05 21:47:34 +00001605 quantum_type=IndexQuantum;
1606 pad=(size_t) MagickMax((size_t) samples_per_pixel-1,0);
cristy17f11b02014-12-20 19:37:04 +00001607 if (image->alpha_trait != UndefinedPixelTrait)
cristy3ed852e2009-09-05 21:47:34 +00001608 {
1609 if (image->storage_class != PseudoClass)
1610 {
1611 quantum_type=samples_per_pixel == 1 ? AlphaQuantum :
1612 GrayAlphaQuantum;
1613 pad=(size_t) MagickMax((size_t) samples_per_pixel-2,0);
1614 }
1615 else
1616 {
1617 quantum_type=IndexAlphaQuantum;
1618 pad=(size_t) MagickMax((size_t) samples_per_pixel-2,0);
1619 }
1620 }
1621 else
1622 if (image->storage_class != PseudoClass)
1623 {
1624 quantum_type=GrayQuantum;
1625 pad=(size_t) MagickMax((size_t) samples_per_pixel-1,0);
1626 }
1627 status=SetQuantumPad(image,quantum_info,pad*((bits_per_sample+7) >> 3));
1628 if (status == MagickFalse)
cristy8d137bf2010-04-21 23:52:04 +00001629 {
1630 TIFFClose(tiff);
1631 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1632 }
cristyb3f97ae2015-05-18 12:29:32 +00001633 pixels=(unsigned char *) GetQuantumPixels(quantum_info);
cristybb503372010-05-27 20:51:26 +00001634 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001635 {
1636 int
1637 status;
1638
cristy4c08aed2011-07-01 19:47:50 +00001639 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01001640 *magick_restrict q;
cristy3ed852e2009-09-05 21:47:34 +00001641
1642 status=TIFFReadPixels(tiff,bits_per_sample,0,y,(char *) pixels);
1643 if (status == -1)
1644 break;
1645 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +00001646 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001647 break;
dirkde364872014-10-26 21:17:59 +00001648 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
cristy3ed852e2009-09-05 21:47:34 +00001649 quantum_type,pixels,exception);
1650 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1651 break;
1652 if (image->previous == (Image *) NULL)
1653 {
cristycee97112010-05-28 00:44:52 +00001654 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1655 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001656 if (status == MagickFalse)
1657 break;
1658 }
1659 }
1660 break;
1661 }
1662 case ReadRGBAMethod:
1663 {
1664 /*
1665 Convert TIFF image to DirectClass MIFF image.
1666 */
1667 pad=(size_t) MagickMax((size_t) samples_per_pixel-3,0);
1668 quantum_type=RGBQuantum;
cristy17f11b02014-12-20 19:37:04 +00001669 if (image->alpha_trait != UndefinedPixelTrait)
cristy3ed852e2009-09-05 21:47:34 +00001670 {
1671 quantum_type=RGBAQuantum;
1672 pad=(size_t) MagickMax((size_t) samples_per_pixel-4,0);
1673 }
1674 if (image->colorspace == CMYKColorspace)
1675 {
1676 pad=(size_t) MagickMax((size_t) samples_per_pixel-4,0);
1677 quantum_type=CMYKQuantum;
cristy17f11b02014-12-20 19:37:04 +00001678 if (image->alpha_trait != UndefinedPixelTrait)
cristy3ed852e2009-09-05 21:47:34 +00001679 {
1680 quantum_type=CMYKAQuantum;
1681 pad=(size_t) MagickMax((size_t) samples_per_pixel-5,0);
1682 }
1683 }
1684 status=SetQuantumPad(image,quantum_info,pad*((bits_per_sample+7) >> 3));
1685 if (status == MagickFalse)
cristy8d137bf2010-04-21 23:52:04 +00001686 {
1687 TIFFClose(tiff);
1688 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1689 }
cristyb3f97ae2015-05-18 12:29:32 +00001690 pixels=(unsigned char *) GetQuantumPixels(quantum_info);
cristybb503372010-05-27 20:51:26 +00001691 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001692 {
1693 int
1694 status;
1695
cristy4c08aed2011-07-01 19:47:50 +00001696 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01001697 *magick_restrict q;
cristy3ed852e2009-09-05 21:47:34 +00001698
1699 status=TIFFReadPixels(tiff,bits_per_sample,0,y,(char *) pixels);
1700 if (status == -1)
1701 break;
1702 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +00001703 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001704 break;
dirkde364872014-10-26 21:17:59 +00001705 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
cristy0b334892010-03-15 02:26:46 +00001706 quantum_type,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +00001707 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1708 break;
1709 if (image->previous == (Image *) NULL)
1710 {
cristycee97112010-05-28 00:44:52 +00001711 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1712 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001713 if (status == MagickFalse)
1714 break;
1715 }
1716 }
1717 break;
1718 }
1719 case ReadCMYKAMethod:
1720 {
1721 /*
1722 Convert TIFF image to DirectClass MIFF image.
1723 */
cristybb503372010-05-27 20:51:26 +00001724 for (i=0; i < (ssize_t) samples_per_pixel; i++)
cristy3ed852e2009-09-05 21:47:34 +00001725 {
cristybb503372010-05-27 20:51:26 +00001726 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001727 {
cristy4c08aed2011-07-01 19:47:50 +00001728 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01001729 *magick_restrict q;
cristy6d9f12f2009-11-03 14:50:26 +00001730
cristy3ed852e2009-09-05 21:47:34 +00001731 int
1732 status;
1733
1734 status=TIFFReadPixels(tiff,bits_per_sample,(tsample_t) i,y,(char *)
1735 pixels);
1736 if (status == -1)
1737 break;
1738 q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +00001739 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001740 break;
1741 if (image->colorspace != CMYKColorspace)
1742 switch (i)
1743 {
1744 case 0: quantum_type=RedQuantum; break;
1745 case 1: quantum_type=GreenQuantum; break;
1746 case 2: quantum_type=BlueQuantum; break;
1747 case 3: quantum_type=AlphaQuantum; break;
1748 default: quantum_type=UndefinedQuantum; break;
1749 }
cristy6d9f12f2009-11-03 14:50:26 +00001750 else
cristy3ed852e2009-09-05 21:47:34 +00001751 switch (i)
1752 {
1753 case 0: quantum_type=CyanQuantum; break;
1754 case 1: quantum_type=MagentaQuantum; break;
1755 case 2: quantum_type=YellowQuantum; break;
1756 case 3: quantum_type=BlackQuantum; break;
1757 case 4: quantum_type=AlphaQuantum; break;
1758 default: quantum_type=UndefinedQuantum; break;
1759 }
dirkde364872014-10-26 21:17:59 +00001760 (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
cristy3ed852e2009-09-05 21:47:34 +00001761 quantum_type,pixels,exception);
1762 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1763 break;
1764 }
1765 if (image->previous == (Image *) NULL)
1766 {
cristycee97112010-05-28 00:44:52 +00001767 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1768 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001769 if (status == MagickFalse)
1770 break;
1771 }
1772 }
1773 break;
1774 }
dirkde364872014-10-26 21:17:59 +00001775 case ReadYCCKMethod:
1776 {
cristyb3f97ae2015-05-18 12:29:32 +00001777 pixels=(unsigned char *) GetQuantumPixels(quantum_info);
dirkde364872014-10-26 21:17:59 +00001778 for (y=0; y < (ssize_t) image->rows; y++)
1779 {
1780 int
1781 status;
1782
1783 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01001784 *magick_restrict q;
dirkde364872014-10-26 21:17:59 +00001785
1786 register ssize_t
1787 x;
1788
1789 unsigned char
1790 *p;
1791
1792 status=TIFFReadPixels(tiff,bits_per_sample,0,y,(char *) pixels);
1793 if (status == -1)
1794 break;
1795 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
1796 if (q == (Quantum *) NULL)
1797 break;
1798 p=pixels;
1799 for (x=0; x < (ssize_t) image->columns; x++)
1800 {
1801 SetPixelCyan(image,ScaleCharToQuantum(ClampYCC((double) *p+
1802 (1.402*(double) *(p+2))-179.456)),q);
1803 SetPixelMagenta(image,ScaleCharToQuantum(ClampYCC((double) *p-
1804 (0.34414*(double) *(p+1))-(0.71414*(double ) *(p+2))+
1805 135.45984)),q);
1806 SetPixelYellow(image,ScaleCharToQuantum(ClampYCC((double) *p+
1807 (1.772*(double) *(p+1))-226.816)),q);
1808 SetPixelBlack(image,ScaleCharToQuantum((unsigned char) *(p+3)),q);
1809 q+=GetPixelChannels(image);
1810 p+=4;
1811 }
1812 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1813 break;
1814 if (image->previous == (Image *) NULL)
1815 {
1816 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1817 image->rows);
1818 if (status == MagickFalse)
1819 break;
1820 }
1821 }
1822 break;
1823 }
cristy3ed852e2009-09-05 21:47:34 +00001824 case ReadStripMethod:
1825 {
cristyd8192d32012-03-14 01:35:47 +00001826 register uint32
cristy3ed852e2009-09-05 21:47:34 +00001827 *p;
1828
1829 /*
1830 Convert stripped TIFF image to DirectClass MIFF image.
1831 */
1832 i=0;
cristyd8192d32012-03-14 01:35:47 +00001833 p=(uint32 *) NULL;
cristybb503372010-05-27 20:51:26 +00001834 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00001835 {
cristybb503372010-05-27 20:51:26 +00001836 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001837 x;
1838
cristy4c08aed2011-07-01 19:47:50 +00001839 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01001840 *magick_restrict q;
cristy3ed852e2009-09-05 21:47:34 +00001841
1842 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +00001843 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001844 break;
1845 if (i == 0)
1846 {
1847 if (TIFFReadRGBAStrip(tiff,(tstrip_t) y,(uint32 *) pixels) == 0)
1848 break;
cristyeaedf062010-05-29 22:36:02 +00001849 i=(ssize_t) MagickMin((ssize_t) rows_per_strip,(ssize_t)
1850 image->rows-y);
cristy3ed852e2009-09-05 21:47:34 +00001851 }
1852 i--;
cristyd8192d32012-03-14 01:35:47 +00001853 p=((uint32 *) pixels)+image->columns*i;
cristybb503372010-05-27 20:51:26 +00001854 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00001855 {
cristy4c08aed2011-07-01 19:47:50 +00001856 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1857 (TIFFGetR(*p))),q);
1858 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1859 (TIFFGetG(*p))),q);
1860 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1861 (TIFFGetB(*p))),q);
cristy17f11b02014-12-20 19:37:04 +00001862 if (image->alpha_trait != UndefinedPixelTrait)
cristy4c08aed2011-07-01 19:47:50 +00001863 SetPixelAlpha(image,ScaleCharToQuantum((unsigned char)
1864 (TIFFGetA(*p))),q);
cristy3ed852e2009-09-05 21:47:34 +00001865 p++;
cristyed231572011-07-14 02:18:59 +00001866 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001867 }
1868 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1869 break;
1870 if (image->previous == (Image *) NULL)
1871 {
cristycee97112010-05-28 00:44:52 +00001872 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1873 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001874 if (status == MagickFalse)
1875 break;
1876 }
1877 }
1878 break;
1879 }
1880 case ReadTileMethod:
1881 {
1882 register uint32
1883 *p;
1884
1885 uint32
1886 *tile_pixels,
1887 columns,
1888 rows;
1889
cristybb503372010-05-27 20:51:26 +00001890 size_t
cristy3ed852e2009-09-05 21:47:34 +00001891 number_pixels;
1892
1893 /*
1894 Convert tiled TIFF image to DirectClass MIFF image.
1895 */
cristy3abd1032014-06-03 01:09:12 +00001896 if ((TIFFGetField(tiff,TIFFTAG_TILEWIDTH,&columns) != 1) ||
1897 (TIFFGetField(tiff,TIFFTAG_TILELENGTH,&rows) != 1))
cristy3ed852e2009-09-05 21:47:34 +00001898 {
1899 TIFFClose(tiff);
1900 ThrowReaderException(CoderError,"ImageIsNotTiled");
1901 }
cristyc82a27b2011-10-21 01:07:16 +00001902 (void) SetImageStorageClass(image,DirectClass,exception);
cristy3ed852e2009-09-05 21:47:34 +00001903 number_pixels=columns*rows;
cristyda16f162011-02-19 23:52:17 +00001904 tile_pixels=(uint32 *) AcquireQuantumMemory(number_pixels,
cristy3ed852e2009-09-05 21:47:34 +00001905 sizeof(*tile_pixels));
1906 if (tile_pixels == (uint32 *) NULL)
1907 {
1908 TIFFClose(tiff);
1909 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1910 }
cristybb503372010-05-27 20:51:26 +00001911 for (y=0; y < (ssize_t) image->rows; y+=rows)
cristy3ed852e2009-09-05 21:47:34 +00001912 {
cristybb503372010-05-27 20:51:26 +00001913 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001914 x;
1915
cristy4c08aed2011-07-01 19:47:50 +00001916 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01001917 *magick_restrict q,
1918 *magick_restrict tile;
cristy3ed852e2009-09-05 21:47:34 +00001919
cristybb503372010-05-27 20:51:26 +00001920 size_t
cristy3ed852e2009-09-05 21:47:34 +00001921 columns_remaining,
1922 rows_remaining;
1923
1924 rows_remaining=image->rows-y;
cristybb503372010-05-27 20:51:26 +00001925 if ((ssize_t) (y+rows) < (ssize_t) image->rows)
cristy3ed852e2009-09-05 21:47:34 +00001926 rows_remaining=rows;
1927 tile=QueueAuthenticPixels(image,0,y,image->columns,rows_remaining,
1928 exception);
cristy4c08aed2011-07-01 19:47:50 +00001929 if (tile == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00001930 break;
cristybb503372010-05-27 20:51:26 +00001931 for (x=0; x < (ssize_t) image->columns; x+=columns)
cristy3ed852e2009-09-05 21:47:34 +00001932 {
cristybb503372010-05-27 20:51:26 +00001933 size_t
cristy3ed852e2009-09-05 21:47:34 +00001934 column,
1935 row;
1936
1937 if (TIFFReadRGBATile(tiff,(uint32) x,(uint32) y,tile_pixels) == 0)
1938 break;
1939 columns_remaining=image->columns-x;
cristybb503372010-05-27 20:51:26 +00001940 if ((ssize_t) (x+columns) < (ssize_t) image->columns)
cristy3ed852e2009-09-05 21:47:34 +00001941 columns_remaining=columns;
1942 p=tile_pixels+(rows-rows_remaining)*columns;
cristy68473222011-08-17 17:39:19 +00001943 q=tile+GetPixelChannels(image)*(image->columns*(rows_remaining-1)+
1944 x);
cristy3ed852e2009-09-05 21:47:34 +00001945 for (row=rows_remaining; row > 0; row--)
1946 {
cristy17f11b02014-12-20 19:37:04 +00001947 if (image->alpha_trait != UndefinedPixelTrait)
cristy3ed852e2009-09-05 21:47:34 +00001948 for (column=columns_remaining; column > 0; column--)
1949 {
cristy4c08aed2011-07-01 19:47:50 +00001950 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1951 TIFFGetR(*p)),q);
1952 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1953 TIFFGetG(*p)),q);
1954 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1955 TIFFGetB(*p)),q);
1956 SetPixelAlpha(image,ScaleCharToQuantum((unsigned char)
1957 TIFFGetA(*p)),q);
cristy3ed852e2009-09-05 21:47:34 +00001958 p++;
cristyed231572011-07-14 02:18:59 +00001959 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001960 }
1961 else
1962 for (column=columns_remaining; column > 0; column--)
1963 {
cristy4c08aed2011-07-01 19:47:50 +00001964 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1965 TIFFGetR(*p)),q);
1966 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1967 TIFFGetG(*p)),q);
1968 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1969 TIFFGetB(*p)),q);
cristy3ed852e2009-09-05 21:47:34 +00001970 p++;
cristyed231572011-07-14 02:18:59 +00001971 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00001972 }
1973 p+=columns-columns_remaining;
cristyed231572011-07-14 02:18:59 +00001974 q-=GetPixelChannels(image)*(image->columns+columns_remaining);
cristy3ed852e2009-09-05 21:47:34 +00001975 }
1976 }
1977 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1978 break;
1979 if (image->previous == (Image *) NULL)
1980 {
cristycee97112010-05-28 00:44:52 +00001981 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
1982 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00001983 if (status == MagickFalse)
1984 break;
1985 }
1986 }
1987 tile_pixels=(uint32 *) RelinquishMagickMemory(tile_pixels);
1988 break;
1989 }
1990 case ReadGenericMethod:
1991 default:
1992 {
cristy5def2032013-06-30 17:44:08 +00001993 MemoryInfo
1994 *pixel_info;
1995
cristy3ed852e2009-09-05 21:47:34 +00001996 register uint32
1997 *p;
1998
1999 uint32
2000 *pixels;
2001
2002 /*
2003 Convert TIFF image to DirectClass MIFF image.
2004 */
2005 number_pixels=(MagickSizeType) image->columns*image->rows;
2006 if ((number_pixels*sizeof(uint32)) != (MagickSizeType) ((size_t)
2007 (number_pixels*sizeof(uint32))))
2008 {
2009 TIFFClose(tiff);
2010 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2011 }
cristy5def2032013-06-30 17:44:08 +00002012 pixel_info=AcquireVirtualMemory(image->columns,image->rows*
cristy3ed852e2009-09-05 21:47:34 +00002013 sizeof(uint32));
cristy5def2032013-06-30 17:44:08 +00002014 if (pixel_info == (MemoryInfo *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002015 {
2016 TIFFClose(tiff);
2017 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
2018 }
cristy5def2032013-06-30 17:44:08 +00002019 pixels=(uint32 *) GetVirtualMemoryBlob(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +00002020 (void) TIFFReadRGBAImage(tiff,(uint32) image->columns,
2021 (uint32) image->rows,(uint32 *) pixels,0);
2022 /*
2023 Convert image to DirectClass pixel packets.
2024 */
2025 p=pixels+number_pixels-1;
cristybb503372010-05-27 20:51:26 +00002026 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00002027 {
cristybb503372010-05-27 20:51:26 +00002028 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002029 x;
2030
cristy4c08aed2011-07-01 19:47:50 +00002031 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01002032 *magick_restrict q;
cristy3ed852e2009-09-05 21:47:34 +00002033
2034 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +00002035 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00002036 break;
cristyed231572011-07-14 02:18:59 +00002037 q+=GetPixelChannels(image)*(image->columns-1);
cristybb503372010-05-27 20:51:26 +00002038 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +00002039 {
cristyf0a55ec2015-02-09 23:09:01 +00002040 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
2041 TIFFGetR(*p)),q);
cristy4c08aed2011-07-01 19:47:50 +00002042 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
2043 TIFFGetG(*p)),q);
cristyf0a55ec2015-02-09 23:09:01 +00002044 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
2045 TIFFGetB(*p)),q);
cristy17f11b02014-12-20 19:37:04 +00002046 if (image->alpha_trait != UndefinedPixelTrait)
cristy4c08aed2011-07-01 19:47:50 +00002047 SetPixelAlpha(image,ScaleCharToQuantum((unsigned char)
2048 TIFFGetA(*p)),q);
cristy3ed852e2009-09-05 21:47:34 +00002049 p--;
cristy128e5be2013-11-09 02:47:12 +00002050 q-=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +00002051 }
2052 if (SyncAuthenticPixels(image,exception) == MagickFalse)
2053 break;
2054 if (image->previous == (Image *) NULL)
2055 {
cristycee97112010-05-28 00:44:52 +00002056 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
2057 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00002058 if (status == MagickFalse)
2059 break;
2060 }
2061 }
cristy5def2032013-06-30 17:44:08 +00002062 pixel_info=RelinquishVirtualMemory(pixel_info);
cristy3ed852e2009-09-05 21:47:34 +00002063 break;
2064 }
2065 }
2066 SetQuantumImageType(image,quantum_type);
2067 next_tiff_frame:
cristya9a6ec42011-10-26 16:55:01 +00002068 quantum_info=DestroyQuantumInfo(quantum_info);
cristyf2273ac2012-06-30 22:45:42 +00002069 if (photometric == PHOTOMETRIC_CIELAB)
cristy514da942012-07-06 23:24:14 +00002070 DecodeLabImage(image,exception);
cristy3ed852e2009-09-05 21:47:34 +00002071 if ((photometric == PHOTOMETRIC_LOGL) ||
2072 (photometric == PHOTOMETRIC_MINISBLACK) ||
2073 (photometric == PHOTOMETRIC_MINISWHITE))
2074 {
2075 image->type=GrayscaleType;
2076 if (bits_per_sample == 1)
2077 image->type=BilevelType;
2078 }
cristy3ed852e2009-09-05 21:47:34 +00002079 /*
2080 Proceed to next image.
2081 */
2082 if (image_info->number_scenes != 0)
2083 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
2084 break;
2085 status=TIFFReadDirectory(tiff) != 0 ? MagickTrue : MagickFalse;
cristycd8b3312013-12-22 01:51:11 +00002086 if (status != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002087 {
2088 /*
2089 Allocate next image structure.
2090 */
cristy9950d572011-10-01 18:22:35 +00002091 AcquireNextImage(image_info,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00002092 if (GetNextImageInList(image) == (Image *) NULL)
2093 {
2094 image=DestroyImageList(image);
2095 return((Image *) NULL);
2096 }
2097 image=SyncNextImageInList(image);
2098 status=SetImageProgress(image,LoadImagesTag,image->scene-1,
2099 image->scene);
2100 if (status == MagickFalse)
2101 break;
2102 }
cristycd8b3312013-12-22 01:51:11 +00002103 } while (status != MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +00002104 TIFFClose(tiff);
dirk14c08dc2015-05-25 11:52:13 +00002105 TIFFReadPhotoshopLayers(image,image_info,exception);
dirkaf51eab2015-10-08 22:47:31 +02002106 if (image_info->number_scenes != 0)
2107 {
2108 if (image_info->scene >= GetImageListLength(image))
2109 {
2110 /* Subimage was not found in the Photoshop layer */
2111 image=DestroyImageList(image);
2112 return((Image *)NULL);
2113 }
2114 }
cristy3ed852e2009-09-05 21:47:34 +00002115 return(GetFirstImageInList(image));
2116}
2117#endif
2118
2119/*
2120%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2121% %
2122% %
2123% %
2124% R e g i s t e r T I F F I m a g e %
2125% %
2126% %
2127% %
2128%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2129%
2130% RegisterTIFFImage() adds properties for the TIFF image format to
2131% the list of supported formats. The properties include the image format
2132% tag, a method to read and/or write the format, whether the format
2133% supports the saving of more than one frame to the same file or blob,
2134% whether the format supports native in-memory I/O, and a brief
2135% description of the format.
2136%
2137% The format of the RegisterTIFFImage method is:
2138%
cristybb503372010-05-27 20:51:26 +00002139% size_t RegisterTIFFImage(void)
cristy3ed852e2009-09-05 21:47:34 +00002140%
2141*/
cristy7e3eb0a2011-11-09 22:50:49 +00002142
2143#if defined(MAGICKCORE_HAVE_TIFFMERGEFIELDINFO) && defined(MAGICKCORE_HAVE_TIFFSETTAGEXTENDER)
2144static TIFFExtendProc
cristy60e1bf92011-11-09 23:00:15 +00002145 tag_extender = (TIFFExtendProc) NULL;
cristy7e3eb0a2011-11-09 22:50:49 +00002146
dirk63dda212014-03-15 10:49:26 +00002147static void TIFFIgnoreTags(TIFF *tiff)
2148{
2149 char
2150 *q;
2151
2152 const char
2153 *p,
2154 *tags;
2155
2156 Image
2157 *image;
2158
dirk63dda212014-03-15 10:49:26 +00002159 register ssize_t
2160 i;
2161
2162 size_t
2163 count;
2164
dirka41b0452014-03-21 21:50:45 +00002165 TIFFFieldInfo
2166 *ignore;
2167
2168 if (TIFFGetReadProc(tiff) != TIFFReadBlob)
2169 return;
dirk63dda212014-03-15 10:49:26 +00002170 image=(Image *)TIFFClientdata(tiff);
2171 tags=GetImageArtifact(image,"tiff:ignore-tags");
2172 if (tags == (const char *) NULL)
2173 return;
2174 count=0;
2175 p=tags;
2176 while (*p != '\0')
2177 {
2178 while ((isspace((int) ((unsigned char) *p)) != 0))
2179 p++;
2180
2181 (void) strtol(p,&q,10);
2182 if (p == q)
2183 return;
2184
2185 p=q;
2186 count++;
2187
2188 while ((isspace((int) ((unsigned char) *p)) != 0) || (*p == ','))
2189 p++;
2190 }
2191 if (count == 0)
2192 return;
2193 i=0;
2194 p=tags;
2195 ignore=(TIFFFieldInfo *) AcquireQuantumMemory(count,sizeof(*ignore));
cristy771c8842015-01-09 12:13:22 +00002196 /* This also sets field_bit to 0 (FIELD_IGNORE) */
dirk63dda212014-03-15 10:49:26 +00002197 ResetMagickMemory(ignore,0,count*sizeof(*ignore));
2198 while (*p != '\0')
2199 {
2200 while ((isspace((int) ((unsigned char) *p)) != 0))
2201 p++;
2202
2203 ignore[i].field_tag=(ttag_t) strtol(p,&q,10);
2204
2205 p=q;
2206 i++;
2207
2208 while ((isspace((int) ((unsigned char) *p)) != 0) || (*p == ','))
2209 p++;
2210 }
2211 (void) TIFFMergeFieldInfo(tiff,ignore,(uint32) count);
2212 ignore=(TIFFFieldInfo *) RelinquishMagickMemory(ignore);
2213}
2214
cristy7e3eb0a2011-11-09 22:50:49 +00002215static void TIFFTagExtender(TIFF *tiff)
2216{
2217 static const TIFFFieldInfo
2218 TIFFExtensions[] =
2219 {
cristy504a72b2012-10-04 12:56:53 +00002220 { 37724, -3, -3, TIFF_UNDEFINED, FIELD_CUSTOM, 1, 1,
2221 (char *) "PhotoshopLayerData" },
2222 { 34118, -3, -3, TIFF_UNDEFINED, FIELD_CUSTOM, 1, 1,
2223 (char *) "Microscope" }
cristy7e3eb0a2011-11-09 22:50:49 +00002224 };
2225
2226 TIFFMergeFieldInfo(tiff,TIFFExtensions,sizeof(TIFFExtensions)/
2227 sizeof(*TIFFExtensions));
cristy60e1bf92011-11-09 23:00:15 +00002228 if (tag_extender != (TIFFExtendProc) NULL)
2229 (*tag_extender)(tiff);
dirk63dda212014-03-15 10:49:26 +00002230 TIFFIgnoreTags(tiff);
cristy7e3eb0a2011-11-09 22:50:49 +00002231}
2232#endif
2233
cristybb503372010-05-27 20:51:26 +00002234ModuleExport size_t RegisterTIFFImage(void)
cristy3ed852e2009-09-05 21:47:34 +00002235{
2236#define TIFFDescription "Tagged Image File Format"
2237
2238 char
cristy151b66d2015-04-15 10:50:31 +00002239 version[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +00002240
2241 MagickInfo
2242 *entry;
cristy6b032822010-06-29 16:52:32 +00002243
cristy18b17442009-10-25 18:36:48 +00002244 if (tiff_semaphore == (SemaphoreInfo *) NULL)
cristy04b11db2014-02-16 15:10:39 +00002245 ActivateSemaphoreInfo(&tiff_semaphore);
cristyf84a1932010-01-03 18:00:18 +00002246 LockSemaphoreInfo(tiff_semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002247 if (instantiate_key == MagickFalse)
2248 {
Cristy47950f62015-12-18 18:31:40 -05002249 if (CreateMagickThreadKey(&tiff_exception,NULL) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00002250 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
Cristy97af9962015-12-19 06:51:20 -05002251 error_handler=TIFFSetErrorHandler(TIFFErrors);
2252 warning_handler=TIFFSetWarningHandler(TIFFWarnings);
cristy7e3eb0a2011-11-09 22:50:49 +00002253#if defined(MAGICKCORE_HAVE_TIFFMERGEFIELDINFO) && defined(MAGICKCORE_HAVE_TIFFSETTAGEXTENDER)
cristy60e1bf92011-11-09 23:00:15 +00002254 if (tag_extender == (TIFFExtendProc) NULL)
2255 tag_extender=TIFFSetTagExtender(TIFFTagExtender);
cristy7e3eb0a2011-11-09 22:50:49 +00002256#endif
cristy3ed852e2009-09-05 21:47:34 +00002257 instantiate_key=MagickTrue;
2258 }
cristyf84a1932010-01-03 18:00:18 +00002259 UnlockSemaphoreInfo(tiff_semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002260 *version='\0';
2261#if defined(TIFF_VERSION)
cristy151b66d2015-04-15 10:50:31 +00002262 (void) FormatLocaleString(version,MagickPathExtent,"%d",TIFF_VERSION);
cristy3ed852e2009-09-05 21:47:34 +00002263#endif
2264#if defined(MAGICKCORE_TIFF_DELEGATE)
2265 {
2266 const char
2267 *p;
2268
cristybb503372010-05-27 20:51:26 +00002269 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002270 i;
2271
2272 p=TIFFGetVersion();
cristy151b66d2015-04-15 10:50:31 +00002273 for (i=0; (i < (MagickPathExtent-1)) && (*p != 0) && (*p != '\n'); i++)
cristy3ed852e2009-09-05 21:47:34 +00002274 version[i]=(*p++);
2275 version[i]='\0';
2276 }
2277#endif
2278
dirk06b627a2015-04-06 18:59:17 +00002279 entry=AcquireMagickInfo("TIFF","GROUP4","Raw CCITT Group4");
cristy3d7f8062009-09-24 20:45:35 +00002280#if defined(MAGICKCORE_TIFF_DELEGATE)
2281 entry->decoder=(DecodeImageHandler *) ReadGROUP4Image;
2282 entry->encoder=(EncodeImageHandler *) WriteGROUP4Image;
2283#endif
dirk08e9a112015-02-22 01:51:41 +00002284 entry->flags|=CoderRawSupportFlag;
2285 entry->flags|=CoderEndianSupportFlag;
dirk08e9a112015-02-22 01:51:41 +00002286 entry->flags|=CoderSeekableStreamFlag;
dirkceb557d2015-02-24 22:03:57 +00002287 entry->flags^=CoderAdjoinFlag;
2288 entry->flags^=CoderUseExtensionFlag;
2289 entry->format_type=ImplicitFormatType;
cristy9d974562013-08-09 11:51:49 +00002290 entry->mime_type=ConstantString("image/tiff");
cristy3d7f8062009-09-24 20:45:35 +00002291 (void) RegisterMagickInfo(entry);
dirk06b627a2015-04-06 18:59:17 +00002292 entry=AcquireMagickInfo("TIFF","PTIF","Pyramid encoded TIFF");
cristy3ed852e2009-09-05 21:47:34 +00002293#if defined(MAGICKCORE_TIFF_DELEGATE)
2294 entry->decoder=(DecodeImageHandler *) ReadTIFFImage;
2295 entry->encoder=(EncodeImageHandler *) WritePTIFImage;
2296#endif
dirk08e9a112015-02-22 01:51:41 +00002297 entry->flags|=CoderEndianSupportFlag;
2298 entry->flags|=CoderSeekableStreamFlag;
dirkceb557d2015-02-24 22:03:57 +00002299 entry->flags^=CoderUseExtensionFlag;
cristy9d974562013-08-09 11:51:49 +00002300 entry->mime_type=ConstantString("image/tiff");
cristy3ed852e2009-09-05 21:47:34 +00002301 (void) RegisterMagickInfo(entry);
dirk06b627a2015-04-06 18:59:17 +00002302 entry=AcquireMagickInfo("TIFF","TIF",TIFFDescription);
cristy3ed852e2009-09-05 21:47:34 +00002303#if defined(MAGICKCORE_TIFF_DELEGATE)
2304 entry->decoder=(DecodeImageHandler *) ReadTIFFImage;
2305 entry->encoder=(EncodeImageHandler *) WriteTIFFImage;
2306#endif
dirk08e9a112015-02-22 01:51:41 +00002307 entry->flags|=CoderEndianSupportFlag;
2308 entry->flags|=CoderSeekableStreamFlag;
2309 entry->flags|=CoderStealthFlag;
dirkceb557d2015-02-24 22:03:57 +00002310 entry->flags^=CoderUseExtensionFlag;
cristy3ed852e2009-09-05 21:47:34 +00002311 if (*version != '\0')
2312 entry->version=ConstantString(version);
cristy9d974562013-08-09 11:51:49 +00002313 entry->mime_type=ConstantString("image/tiff");
cristy3ed852e2009-09-05 21:47:34 +00002314 (void) RegisterMagickInfo(entry);
dirk06b627a2015-04-06 18:59:17 +00002315 entry=AcquireMagickInfo("TIFF","TIFF",TIFFDescription);
cristy3ed852e2009-09-05 21:47:34 +00002316#if defined(MAGICKCORE_TIFF_DELEGATE)
2317 entry->decoder=(DecodeImageHandler *) ReadTIFFImage;
2318 entry->encoder=(EncodeImageHandler *) WriteTIFFImage;
2319#endif
2320 entry->magick=(IsImageFormatHandler *) IsTIFF;
dirk08e9a112015-02-22 01:51:41 +00002321 entry->flags|=CoderEndianSupportFlag;
2322 entry->flags|=CoderSeekableStreamFlag;
dirkceb557d2015-02-24 22:03:57 +00002323 entry->flags^=CoderUseExtensionFlag;
cristy3ed852e2009-09-05 21:47:34 +00002324 if (*version != '\0')
2325 entry->version=ConstantString(version);
cristy9d974562013-08-09 11:51:49 +00002326 entry->mime_type=ConstantString("image/tiff");
cristy3ed852e2009-09-05 21:47:34 +00002327 (void) RegisterMagickInfo(entry);
dirk06b627a2015-04-06 18:59:17 +00002328 entry=AcquireMagickInfo("TIFF","TIFF64","Tagged Image File Format (64-bit)");
cristy3ed852e2009-09-05 21:47:34 +00002329#if defined(TIFF_VERSION_BIG)
2330 entry->decoder=(DecodeImageHandler *) ReadTIFFImage;
cristy9d6964e2011-11-10 17:48:45 +00002331 entry->encoder=(EncodeImageHandler *) WriteTIFFImage;
cristy3ed852e2009-09-05 21:47:34 +00002332#endif
dirk08e9a112015-02-22 01:51:41 +00002333 entry->flags|=CoderEndianSupportFlag;
2334 entry->flags|=CoderSeekableStreamFlag;
dirkceb557d2015-02-24 22:03:57 +00002335 entry->flags^=CoderAdjoinFlag;
2336 entry->flags^=CoderUseExtensionFlag;
cristy3ed852e2009-09-05 21:47:34 +00002337 if (*version != '\0')
2338 entry->version=ConstantString(version);
cristy9d974562013-08-09 11:51:49 +00002339 entry->mime_type=ConstantString("image/tiff");
cristy3ed852e2009-09-05 21:47:34 +00002340 (void) RegisterMagickInfo(entry);
2341 return(MagickImageCoderSignature);
2342}
2343
2344/*
2345%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2346% %
2347% %
2348% %
2349% U n r e g i s t e r T I F F I m a g e %
2350% %
2351% %
2352% %
2353%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2354%
2355% UnregisterTIFFImage() removes format registrations made by the TIFF module
2356% from the list of supported formats.
2357%
2358% The format of the UnregisterTIFFImage method is:
2359%
2360% UnregisterTIFFImage(void)
2361%
2362*/
2363ModuleExport void UnregisterTIFFImage(void)
2364{
cristy3ed852e2009-09-05 21:47:34 +00002365 (void) UnregisterMagickInfo("TIFF64");
cristy9d6964e2011-11-10 17:48:45 +00002366 (void) UnregisterMagickInfo("TIFF");
2367 (void) UnregisterMagickInfo("TIF");
2368 (void) UnregisterMagickInfo("PTIF");
cristy514e9e72009-11-20 02:12:08 +00002369 if (tiff_semaphore == (SemaphoreInfo *) NULL)
cristy04b11db2014-02-16 15:10:39 +00002370 ActivateSemaphoreInfo(&tiff_semaphore);
cristyf84a1932010-01-03 18:00:18 +00002371 LockSemaphoreInfo(tiff_semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002372 if (instantiate_key != MagickFalse)
cristy9ebdd932011-11-09 23:07:28 +00002373 {
2374#if defined(MAGICKCORE_HAVE_TIFFMERGEFIELDINFO) && defined(MAGICKCORE_HAVE_TIFFSETTAGEXTENDER)
2375 if (tag_extender == (TIFFExtendProc) NULL)
2376 (void) TIFFSetTagExtender(tag_extender);
2377#endif
Cristy47950f62015-12-18 18:31:40 -05002378 if (DeleteMagickThreadKey(tiff_exception) == MagickFalse)
cristy9ebdd932011-11-09 23:07:28 +00002379 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
Cristy97af9962015-12-19 06:51:20 -05002380 (void) TIFFSetWarningHandler(warning_handler);
2381 (void) TIFFSetErrorHandler(error_handler);
cristy9ebdd932011-11-09 23:07:28 +00002382 instantiate_key=MagickFalse;
2383 }
cristyf84a1932010-01-03 18:00:18 +00002384 UnlockSemaphoreInfo(tiff_semaphore);
cristy3d162a92014-02-16 14:05:06 +00002385 RelinquishSemaphoreInfo(&tiff_semaphore);
cristy3ed852e2009-09-05 21:47:34 +00002386}
2387
2388#if defined(MAGICKCORE_TIFF_DELEGATE)
2389/*
2390%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2391% %
2392% %
2393% %
cristy3d7f8062009-09-24 20:45:35 +00002394% W r i t e G R O U P 4 I m a g e %
2395% %
2396% %
2397% %
2398%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2399%
2400% WriteGROUP4Image() writes an image in the raw CCITT Group 4 image format.
2401%
2402% The format of the WriteGROUP4Image method is:
2403%
2404% MagickBooleanType WriteGROUP4Image(const ImageInfo *image_info,
cristy3a37efd2011-08-28 20:31:03 +00002405% Image *image,ExceptionInfo *)
cristy3d7f8062009-09-24 20:45:35 +00002406%
2407% A description of each parameter follows:
2408%
2409% o image_info: the image info.
2410%
2411% o image: The image.
2412%
cristy3a37efd2011-08-28 20:31:03 +00002413% o exception: return any errors or warnings in this structure.
2414%
cristy3d7f8062009-09-24 20:45:35 +00002415*/
2416static MagickBooleanType WriteGROUP4Image(const ImageInfo *image_info,
cristy3a37efd2011-08-28 20:31:03 +00002417 Image *image,ExceptionInfo *exception)
cristy3d7f8062009-09-24 20:45:35 +00002418{
2419 char
cristy151b66d2015-04-15 10:50:31 +00002420 filename[MagickPathExtent];
cristy3d7f8062009-09-24 20:45:35 +00002421
2422 FILE
2423 *file;
2424
2425 Image
2426 *huffman_image;
2427
2428 ImageInfo
2429 *write_info;
2430
2431 int
2432 unique_file;
2433
2434 MagickBooleanType
2435 status;
2436
cristybb503372010-05-27 20:51:26 +00002437 register ssize_t
cristy3d7f8062009-09-24 20:45:35 +00002438 i;
2439
2440 ssize_t
2441 count;
2442
2443 TIFF
2444 *tiff;
2445
cristy94c8fe42009-10-06 01:57:36 +00002446 toff_t
cristy3d7f8062009-09-24 20:45:35 +00002447 *byte_count,
2448 strip_size;
2449
2450 unsigned char
2451 *buffer;
2452
2453 /*
2454 Write image as CCITT Group4 TIFF image to a temporary file.
2455 */
2456 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +00002457 assert(image_info->signature == MagickCoreSignature);
cristy3d7f8062009-09-24 20:45:35 +00002458 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00002459 assert(image->signature == MagickCoreSignature);
cristy3d7f8062009-09-24 20:45:35 +00002460 if (image->debug != MagickFalse)
2461 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy3a37efd2011-08-28 20:31:03 +00002462 assert(exception != (ExceptionInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +00002463 assert(exception->signature == MagickCoreSignature);
cristy3a37efd2011-08-28 20:31:03 +00002464 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3d7f8062009-09-24 20:45:35 +00002465 if (status == MagickFalse)
2466 return(status);
cristy3a37efd2011-08-28 20:31:03 +00002467 huffman_image=CloneImage(image,0,0,MagickTrue,exception);
cristy3d7f8062009-09-24 20:45:35 +00002468 if (huffman_image == (Image *) NULL)
2469 {
2470 (void) CloseBlob(image);
2471 return(MagickFalse);
2472 }
cristy94c8fe42009-10-06 01:57:36 +00002473 huffman_image->endian=MSBEndian;
cristy3d7f8062009-09-24 20:45:35 +00002474 file=(FILE *) NULL;
2475 unique_file=AcquireUniqueFileResource(filename);
2476 if (unique_file != -1)
cristy0accf6e2009-10-01 13:14:28 +00002477 file=fdopen(unique_file,"wb");
cristy3d7f8062009-09-24 20:45:35 +00002478 if ((unique_file == -1) || (file == (FILE *) NULL))
2479 {
cristy3a37efd2011-08-28 20:31:03 +00002480 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
2481 filename);
cristy3d7f8062009-09-24 20:45:35 +00002482 return(MagickFalse);
2483 }
cristy151b66d2015-04-15 10:50:31 +00002484 (void) FormatLocaleString(huffman_image->filename,MagickPathExtent,"tiff:%s",
cristy3d7f8062009-09-24 20:45:35 +00002485 filename);
cristy018f07f2011-09-04 21:15:19 +00002486 (void) SetImageType(huffman_image,BilevelType,exception);
cristy14efd992009-09-26 23:46:03 +00002487 write_info=CloneImageInfo((ImageInfo *) NULL);
cristy3d7f8062009-09-24 20:45:35 +00002488 SetImageInfoFile(write_info,file);
Cristy745b3bc2015-12-30 21:24:49 -05002489 (void) SetImageType(image,BilevelType,exception);
2490 (void) SetImageDepth(image,1,exception);
cristy3d7f8062009-09-24 20:45:35 +00002491 write_info->compression=Group4Compression;
2492 write_info->type=BilevelType;
2493 (void) SetImageOption(write_info,"quantum:polarity","min-is-white");
cristy3a37efd2011-08-28 20:31:03 +00002494 status=WriteTIFFImage(write_info,huffman_image,exception);
cristy3d7f8062009-09-24 20:45:35 +00002495 (void) fflush(file);
2496 write_info=DestroyImageInfo(write_info);
2497 if (status == MagickFalse)
2498 {
cristy3d7f8062009-09-24 20:45:35 +00002499 huffman_image=DestroyImage(huffman_image);
2500 (void) fclose(file);
2501 (void) RelinquishUniqueFileResource(filename);
2502 return(MagickFalse);
2503 }
2504 tiff=TIFFOpen(filename,"rb");
2505 if (tiff == (TIFF *) NULL)
2506 {
2507 huffman_image=DestroyImage(huffman_image);
2508 (void) fclose(file);
2509 (void) RelinquishUniqueFileResource(filename);
cristy3a37efd2011-08-28 20:31:03 +00002510 ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
cristy3d7f8062009-09-24 20:45:35 +00002511 image_info->filename);
2512 return(MagickFalse);
2513 }
2514 /*
2515 Allocate raw strip buffer.
2516 */
cristy94c8fe42009-10-06 01:57:36 +00002517 if (TIFFGetField(tiff,TIFFTAG_STRIPBYTECOUNTS,&byte_count) != 1)
2518 {
2519 TIFFClose(tiff);
2520 huffman_image=DestroyImage(huffman_image);
2521 (void) fclose(file);
2522 (void) RelinquishUniqueFileResource(filename);
2523 return(MagickFalse);
2524 }
cristy3d7f8062009-09-24 20:45:35 +00002525 strip_size=byte_count[0];
cristybb503372010-05-27 20:51:26 +00002526 for (i=1; i < (ssize_t) TIFFNumberOfStrips(tiff); i++)
cristy3d7f8062009-09-24 20:45:35 +00002527 if (byte_count[i] > strip_size)
2528 strip_size=byte_count[i];
2529 buffer=(unsigned char *) AcquireQuantumMemory((size_t) strip_size,
2530 sizeof(*buffer));
2531 if (buffer == (unsigned char *) NULL)
2532 {
2533 TIFFClose(tiff);
2534 huffman_image=DestroyImage(huffman_image);
2535 (void) fclose(file);
2536 (void) RelinquishUniqueFileResource(filename);
2537 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
2538 image_info->filename);
2539 }
2540 /*
2541 Compress runlength encoded to 2D Huffman pixels.
2542 */
cristybb503372010-05-27 20:51:26 +00002543 for (i=0; i < (ssize_t) TIFFNumberOfStrips(tiff); i++)
cristy3d7f8062009-09-24 20:45:35 +00002544 {
cristy94c8fe42009-10-06 01:57:36 +00002545 count=(ssize_t) TIFFReadRawStrip(tiff,(uint32) i,buffer,strip_size);
cristy3d7f8062009-09-24 20:45:35 +00002546 if (WriteBlob(image,(size_t) count,buffer) != count)
2547 status=MagickFalse;
2548 }
2549 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
2550 TIFFClose(tiff);
2551 huffman_image=DestroyImage(huffman_image);
2552 (void) fclose(file);
2553 (void) RelinquishUniqueFileResource(filename);
2554 (void) CloseBlob(image);
2555 return(status);
2556}
2557#endif
2558
2559#if defined(MAGICKCORE_TIFF_DELEGATE)
2560/*
2561%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2562% %
2563% %
2564% %
cristy3ed852e2009-09-05 21:47:34 +00002565% W r i t e P T I F I m a g e %
2566% %
2567% %
2568% %
2569%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2570%
2571% WritePTIFImage() writes an image in the pyrimid-encoded Tagged image file
2572% format.
2573%
2574% The format of the WritePTIFImage method is:
2575%
2576% MagickBooleanType WritePTIFImage(const ImageInfo *image_info,
cristy3a37efd2011-08-28 20:31:03 +00002577% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002578%
2579% A description of each parameter follows:
2580%
2581% o image_info: the image info.
2582%
2583% o image: The image.
2584%
cristy3a37efd2011-08-28 20:31:03 +00002585% o exception: return any errors or warnings in this structure.
2586%
cristy3ed852e2009-09-05 21:47:34 +00002587*/
2588static MagickBooleanType WritePTIFImage(const ImageInfo *image_info,
cristy3a37efd2011-08-28 20:31:03 +00002589 Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002590{
2591 Image
2592 *images,
2593 *next,
2594 *pyramid_image;
2595
2596 ImageInfo
2597 *write_info;
2598
2599 MagickBooleanType
2600 status;
2601
cristyf164a872012-01-20 18:26:34 +00002602 PointInfo
2603 resolution;
2604
cristybb503372010-05-27 20:51:26 +00002605 size_t
cristy3ed852e2009-09-05 21:47:34 +00002606 columns,
2607 rows;
2608
2609 /*
2610 Create pyramid-encoded TIFF image.
2611 */
2612 images=NewImageList();
2613 for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
2614 {
cristy892484b2014-10-08 15:52:56 +00002615 Image
2616 *clone_image;
2617
2618 clone_image=CloneImage(next,0,0,MagickFalse,exception);
cristyfe33a412015-07-27 13:18:43 +00002619 if (clone_image == (Image *) NULL)
2620 break;
cristy892484b2014-10-08 15:52:56 +00002621 clone_image->previous=NewImageList();
2622 clone_image->next=NewImageList();
cristyfe33a412015-07-27 13:18:43 +00002623 (void) SetImageProperty(clone_image,"tiff:subfiletype","none",exception);
cristy892484b2014-10-08 15:52:56 +00002624 AppendImageToList(&images,clone_image);
cristy3ed852e2009-09-05 21:47:34 +00002625 columns=next->columns;
2626 rows=next->rows;
cristyf164a872012-01-20 18:26:34 +00002627 resolution=next->resolution;
cristy3ed852e2009-09-05 21:47:34 +00002628 while ((columns > 64) && (rows > 64))
2629 {
2630 columns/=2;
2631 rows/=2;
cristyf164a872012-01-20 18:26:34 +00002632 resolution.x/=2;
2633 resolution.y/=2;
cristyaa2c16c2012-03-25 22:21:35 +00002634 pyramid_image=ResizeImage(next,columns,rows,image->filter,exception);
cristyf164a872012-01-20 18:26:34 +00002635 if (pyramid_image == (Image *) NULL)
2636 break;
2637 pyramid_image->resolution=resolution;
cristyfe33a412015-07-27 13:18:43 +00002638 (void) SetImageProperty(pyramid_image,"tiff:subfiletype","REDUCEDIMAGE",
2639 exception);
cristy3ed852e2009-09-05 21:47:34 +00002640 AppendImageToList(&images,pyramid_image);
2641 }
2642 }
cristyf164a872012-01-20 18:26:34 +00002643 images=GetFirstImageInList(images);
cristy3ed852e2009-09-05 21:47:34 +00002644 /*
2645 Write pyramid-encoded TIFF image.
2646 */
cristy58567532009-09-26 01:13:32 +00002647 write_info=CloneImageInfo(image_info);
cristy3ed852e2009-09-05 21:47:34 +00002648 write_info->adjoin=MagickTrue;
cristy151b66d2015-04-15 10:50:31 +00002649 (void) CopyMagickString(write_info->magick,"TIFF",MagickPathExtent);
2650 (void) CopyMagickString(images->magick,"TIFF",MagickPathExtent);
cristyf164a872012-01-20 18:26:34 +00002651 status=WriteTIFFImage(write_info,images,exception);
cristy3ed852e2009-09-05 21:47:34 +00002652 images=DestroyImageList(images);
2653 write_info=DestroyImageInfo(write_info);
2654 return(status);
2655}
2656#endif
2657
2658#if defined(MAGICKCORE_TIFF_DELEGATE)
2659/*
2660%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2661% %
2662% %
2663% W r i t e T I F F I m a g e %
2664% %
2665% %
2666% %
2667%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2668%
2669% WriteTIFFImage() writes an image in the Tagged image file format.
2670%
2671% The format of the WriteTIFFImage method is:
2672%
2673% MagickBooleanType WriteTIFFImage(const ImageInfo *image_info,
cristy3a37efd2011-08-28 20:31:03 +00002674% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002675%
2676% A description of each parameter follows:
2677%
2678% o image_info: the image info.
2679%
2680% o image: The image.
2681%
cristy3a37efd2011-08-28 20:31:03 +00002682% o exception: return any errors or warnings in this structure.
2683%
cristy3ed852e2009-09-05 21:47:34 +00002684*/
2685
2686typedef struct _TIFFInfo
2687{
2688 RectangleInfo
2689 tile_geometry;
2690
2691 unsigned char
2692 *scanline,
2693 *scanlines,
2694 *pixels;
2695} TIFFInfo;
2696
2697static void DestroyTIFFInfo(TIFFInfo *tiff_info)
2698{
2699 assert(tiff_info != (TIFFInfo *) NULL);
2700 if (tiff_info->scanlines != (unsigned char *) NULL)
2701 tiff_info->scanlines=(unsigned char *) RelinquishMagickMemory(
2702 tiff_info->scanlines);
2703 if (tiff_info->pixels != (unsigned char *) NULL)
2704 tiff_info->pixels=(unsigned char *) RelinquishMagickMemory(
2705 tiff_info->pixels);
2706}
2707
cristy514da942012-07-06 23:24:14 +00002708static MagickBooleanType EncodeLabImage(Image *image,ExceptionInfo *exception)
2709{
2710 CacheView
2711 *image_view;
2712
2713 MagickBooleanType
2714 status;
2715
2716 ssize_t
2717 y;
2718
2719 status=MagickTrue;
cristy46ff2672012-12-14 15:32:26 +00002720 image_view=AcquireAuthenticCacheView(image,exception);
cristy514da942012-07-06 23:24:14 +00002721 for (y=0; y < (ssize_t) image->rows; y++)
2722 {
2723 register Quantum
dirk05d2ff72015-11-18 23:13:43 +01002724 *magick_restrict q;
cristy514da942012-07-06 23:24:14 +00002725
2726 register ssize_t
2727 x;
2728
2729 if (status == MagickFalse)
2730 continue;
2731 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2732 if (q == (Quantum *) NULL)
2733 {
2734 status=MagickFalse;
2735 continue;
2736 }
2737 for (x=0; x < (ssize_t) image->columns; x++)
2738 {
2739 double
2740 a,
2741 b;
2742
2743 a=QuantumScale*GetPixela(image,q)-0.5;
2744 if (a < 0.0)
2745 a+=1.0;
2746 b=QuantumScale*GetPixelb(image,q)-0.5;
2747 if (b < 0.0)
2748 b+=1.0;
2749 SetPixela(image,QuantumRange*a,q);
2750 SetPixelb(image,QuantumRange*b,q);
2751 q+=GetPixelChannels(image);
2752 }
2753 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2754 status=MagickFalse;
2755 }
2756 image_view=DestroyCacheView(image_view);
2757 return(status);
2758}
2759
cristy092ec8d2013-04-26 13:46:22 +00002760static MagickBooleanType GetTIFFInfo(const ImageInfo *image_info,
cristyb0de93f2013-05-03 13:39:25 +00002761 TIFF *tiff,TIFFInfo *tiff_info)
cristy3ed852e2009-09-05 21:47:34 +00002762{
2763 const char
2764 *option;
2765
2766 MagickStatusType
2767 flags;
2768
cristy79e5dad2010-09-16 19:48:33 +00002769 uint32
2770 tile_columns,
2771 tile_rows;
2772
cristy3ed852e2009-09-05 21:47:34 +00002773 assert(tiff_info != (TIFFInfo *) NULL);
2774 (void) ResetMagickMemory(tiff_info,0,sizeof(*tiff_info));
cristy092ec8d2013-04-26 13:46:22 +00002775 option=GetImageOption(image_info,"tiff:tile-geometry");
cristy3ed852e2009-09-05 21:47:34 +00002776 if (option == (const char *) NULL)
2777 return(MagickTrue);
2778 flags=ParseAbsoluteGeometry(option,&tiff_info->tile_geometry);
2779 if ((flags & HeightValue) == 0)
2780 tiff_info->tile_geometry.height=tiff_info->tile_geometry.width;
cristydf6d6d42010-09-18 02:15:37 +00002781 tile_columns=(uint32) tiff_info->tile_geometry.width;
2782 tile_rows=(uint32) tiff_info->tile_geometry.height;
cristy79e5dad2010-09-16 19:48:33 +00002783 TIFFDefaultTileSize(tiff,&tile_columns,&tile_rows);
2784 (void) TIFFSetField(tiff,TIFFTAG_TILEWIDTH,tile_columns);
2785 (void) TIFFSetField(tiff,TIFFTAG_TILELENGTH,tile_rows);
2786 tiff_info->tile_geometry.width=tile_columns;
2787 tiff_info->tile_geometry.height=tile_rows;
cristy3ed852e2009-09-05 21:47:34 +00002788 tiff_info->scanlines=(unsigned char *) AcquireQuantumMemory((size_t)
cristy79e5dad2010-09-16 19:48:33 +00002789 tile_rows*TIFFScanlineSize(tiff),sizeof(*tiff_info->scanlines));
cristy3ed852e2009-09-05 21:47:34 +00002790 tiff_info->pixels=(unsigned char *) AcquireQuantumMemory((size_t)
cristy79e5dad2010-09-16 19:48:33 +00002791 tile_rows*TIFFTileSize(tiff),sizeof(*tiff_info->scanlines));
cristy3ed852e2009-09-05 21:47:34 +00002792 if ((tiff_info->scanlines == (unsigned char *) NULL) ||
2793 (tiff_info->pixels == (unsigned char *) NULL))
2794 {
2795 DestroyTIFFInfo(tiff_info);
2796 return(MagickFalse);
2797 }
2798 return(MagickTrue);
2799}
2800
cristybb503372010-05-27 20:51:26 +00002801static int32 TIFFWritePixels(TIFF *tiff,TIFFInfo *tiff_info,ssize_t row,
cristy3ed852e2009-09-05 21:47:34 +00002802 tsample_t sample,Image *image)
2803{
2804 int32
2805 status;
2806
cristybb503372010-05-27 20:51:26 +00002807 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00002808 i;
2809
2810 register unsigned char
2811 *p,
2812 *q;
2813
cristybb503372010-05-27 20:51:26 +00002814 size_t
cristy3ed852e2009-09-05 21:47:34 +00002815 number_tiles,
2816 tile_width;
2817
cristyc6da28e2011-04-28 01:41:35 +00002818 ssize_t
2819 bytes_per_pixel,
2820 j,
2821 k,
2822 l;
2823
cristy3ed852e2009-09-05 21:47:34 +00002824 if (TIFFIsTiled(tiff) == 0)
2825 return(TIFFWriteScanline(tiff,tiff_info->scanline,(uint32) row,sample));
2826 /*
2827 Fill scanlines to tile height.
2828 */
cristybb503372010-05-27 20:51:26 +00002829 i=(ssize_t) (row % tiff_info->tile_geometry.height)*TIFFScanlineSize(tiff);
cristy3ed852e2009-09-05 21:47:34 +00002830 (void) CopyMagickMemory(tiff_info->scanlines+i,(char *) tiff_info->scanline,
2831 (size_t) TIFFScanlineSize(tiff));
cristybb503372010-05-27 20:51:26 +00002832 if (((size_t) (row % tiff_info->tile_geometry.height) !=
cristyc6da28e2011-04-28 01:41:35 +00002833 (tiff_info->tile_geometry.height-1)) &&
2834 (row != (ssize_t) (image->rows-1)))
cristy3ed852e2009-09-05 21:47:34 +00002835 return(0);
2836 /*
2837 Write tile to TIFF image.
2838 */
2839 status=0;
cristy32fab702012-01-18 02:47:47 +00002840 bytes_per_pixel=TIFFTileSize(tiff)/(ssize_t) (
2841 tiff_info->tile_geometry.height*tiff_info->tile_geometry.width);
cristy3ed852e2009-09-05 21:47:34 +00002842 number_tiles=(image->columns+tiff_info->tile_geometry.width)/
2843 tiff_info->tile_geometry.width;
cristybb503372010-05-27 20:51:26 +00002844 for (i=0; i < (ssize_t) number_tiles; i++)
cristy3ed852e2009-09-05 21:47:34 +00002845 {
cristybb503372010-05-27 20:51:26 +00002846 tile_width=(i == (ssize_t) (number_tiles-1)) ? image->columns-(i*
cristy3ed852e2009-09-05 21:47:34 +00002847 tiff_info->tile_geometry.width) : tiff_info->tile_geometry.width;
cristybb503372010-05-27 20:51:26 +00002848 for (j=0; j < (ssize_t) ((row % tiff_info->tile_geometry.height)+1); j++)
2849 for (k=0; k < (ssize_t) tile_width; k++)
cristy3ed852e2009-09-05 21:47:34 +00002850 {
2851 if (bytes_per_pixel == 0)
2852 {
2853 p=tiff_info->scanlines+(j*TIFFScanlineSize(tiff)+(i*
2854 tiff_info->tile_geometry.width+k)/8);
2855 q=tiff_info->pixels+(j*TIFFTileRowSize(tiff)+k/8);
2856 *q++=(*p++);
2857 continue;
2858 }
2859 p=tiff_info->scanlines+(j*TIFFScanlineSize(tiff)+(i*
2860 tiff_info->tile_geometry.width+k)*bytes_per_pixel);
2861 q=tiff_info->pixels+(j*TIFFTileRowSize(tiff)+k*bytes_per_pixel);
2862 for (l=0; l < bytes_per_pixel; l++)
2863 *q++=(*p++);
2864 }
cristydaff8092010-04-22 14:50:53 +00002865 if ((i*tiff_info->tile_geometry.width) != image->columns)
2866 status=TIFFWriteTile(tiff,tiff_info->pixels,(uint32) (i*
2867 tiff_info->tile_geometry.width),(uint32) ((row/
2868 tiff_info->tile_geometry.height)*tiff_info->tile_geometry.height),0,
2869 sample);
cristy3ed852e2009-09-05 21:47:34 +00002870 if (status < 0)
2871 break;
2872 }
2873 return(status);
2874}
2875
2876static void TIFFSetProfiles(TIFF *tiff,Image *image)
2877{
2878 const char
2879 *name;
2880
2881 const StringInfo
2882 *profile;
2883
2884 if (image->profiles == (void *) NULL)
2885 return;
2886 ResetImageProfileIterator(image);
2887 for (name=GetNextImageProfile(image); name != (const char *) NULL; )
2888 {
2889 profile=GetImageProfile(image,name);
cristy4c698232013-03-17 20:55:22 +00002890 if (GetStringInfoLength(profile) == 0)
2891 {
2892 name=GetNextImageProfile(image);
2893 continue;
2894 }
cristy3ed852e2009-09-05 21:47:34 +00002895#if defined(TIFFTAG_XMLPACKET)
2896 if (LocaleCompare(name,"xmp") == 0)
2897 (void) TIFFSetField(tiff,TIFFTAG_XMLPACKET,(uint32) GetStringInfoLength(
2898 profile),GetStringInfoDatum(profile));
2899#endif
2900#if defined(TIFFTAG_ICCPROFILE)
2901 if (LocaleCompare(name,"icc") == 0)
2902 (void) TIFFSetField(tiff,TIFFTAG_ICCPROFILE,(uint32) GetStringInfoLength(
2903 profile),GetStringInfoDatum(profile));
2904#endif
2905 if (LocaleCompare(name,"iptc") == 0)
2906 {
2907 size_t
2908 length;
2909
2910 StringInfo
2911 *iptc_profile;
2912
2913 iptc_profile=CloneStringInfo(profile);
2914 length=GetStringInfoLength(profile)+4-(GetStringInfoLength(profile) &
2915 0x03);
2916 SetStringInfoLength(iptc_profile,length);
2917 if (TIFFIsByteSwapped(tiff))
2918 TIFFSwabArrayOfLong((uint32 *) GetStringInfoDatum(iptc_profile),
cristyf6fe0a12010-05-30 00:44:47 +00002919 (unsigned long) (length/4));
cristy3ed852e2009-09-05 21:47:34 +00002920 (void) TIFFSetField(tiff,TIFFTAG_RICHTIFFIPTC,(uint32)
2921 GetStringInfoLength(iptc_profile)/4,GetStringInfoDatum(iptc_profile));
2922 iptc_profile=DestroyStringInfo(iptc_profile);
2923 }
2924#if defined(TIFFTAG_PHOTOSHOP)
2925 if (LocaleCompare(name,"8bim") == 0)
2926 (void) TIFFSetField(tiff,TIFFTAG_PHOTOSHOP,(uint32)
2927 GetStringInfoLength(profile),GetStringInfoDatum(profile));
2928#endif
2929 if (LocaleCompare(name,"tiff:37724") == 0)
cristye5d85502011-11-09 19:45:06 +00002930 (void) TIFFSetField(tiff,37724,(uint32) GetStringInfoLength(profile),
cristy3ed852e2009-09-05 21:47:34 +00002931 GetStringInfoDatum(profile));
cristy30df84f2012-10-04 01:34:18 +00002932 if (LocaleCompare(name,"tiff:34118") == 0)
2933 (void) TIFFSetField(tiff,34118,(uint32) GetStringInfoLength(profile),
2934 GetStringInfoDatum(profile));
cristy3ed852e2009-09-05 21:47:34 +00002935 name=GetNextImageProfile(image);
2936 }
2937}
2938
cristyfe33a412015-07-27 13:18:43 +00002939static void TIFFSetProperties(TIFF *tiff,const ImageInfo *image_info,
2940 Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00002941{
2942 const char
2943 *value;
2944
cristy64bcc412014-02-23 12:22:22 +00002945 value=GetImageArtifact(image,"tiff:document");
cristy7ae12162014-02-22 22:36:29 +00002946 if (value != (const char *) NULL)
2947 (void) TIFFSetField(tiff,TIFFTAG_DOCUMENTNAME,value);
cristy64bcc412014-02-23 12:22:22 +00002948 value=GetImageArtifact(image,"tiff:hostcomputer");
cristy3ed852e2009-09-05 21:47:34 +00002949 if (value != (const char *) NULL)
2950 (void) TIFFSetField(tiff,TIFFTAG_HOSTCOMPUTER,value);
cristy64bcc412014-02-23 12:22:22 +00002951 value=GetImageArtifact(image,"tiff:artist");
cristy3ed852e2009-09-05 21:47:34 +00002952 if (value != (const char *) NULL)
2953 (void) TIFFSetField(tiff,TIFFTAG_ARTIST,value);
cristy64bcc412014-02-23 12:22:22 +00002954 value=GetImageArtifact(image,"tiff:timestamp");
cristy3ed852e2009-09-05 21:47:34 +00002955 if (value != (const char *) NULL)
2956 (void) TIFFSetField(tiff,TIFFTAG_DATETIME,value);
cristy64bcc412014-02-23 12:22:22 +00002957 value=GetImageArtifact(image,"tiff:make");
cristy3ed852e2009-09-05 21:47:34 +00002958 if (value != (const char *) NULL)
2959 (void) TIFFSetField(tiff,TIFFTAG_MAKE,value);
cristy64bcc412014-02-23 12:22:22 +00002960 value=GetImageArtifact(image,"tiff:model");
cristy3ed852e2009-09-05 21:47:34 +00002961 if (value != (const char *) NULL)
2962 (void) TIFFSetField(tiff,TIFFTAG_MODEL,value);
cristy64bcc412014-02-23 12:22:22 +00002963 value=GetImageArtifact(image,"tiff:software");
cristy15d8d212010-09-17 01:56:30 +00002964 if (value != (const char *) NULL)
2965 (void) TIFFSetField(tiff,TIFFTAG_SOFTWARE,value);
cristy64bcc412014-02-23 12:22:22 +00002966 value=GetImageArtifact(image,"tiff:copyright");
cristy3ed852e2009-09-05 21:47:34 +00002967 if (value != (const char *) NULL)
cristy98ca0f52011-10-08 23:19:10 +00002968 (void) TIFFSetField(tiff,TIFFTAG_COPYRIGHT,value);
cristy64bcc412014-02-23 12:22:22 +00002969 value=GetImageArtifact(image,"kodak-33423");
cristy3ed852e2009-09-05 21:47:34 +00002970 if (value != (const char *) NULL)
2971 (void) TIFFSetField(tiff,33423,value);
cristy64bcc412014-02-23 12:22:22 +00002972 value=GetImageArtifact(image,"kodak-36867");
cristy3ed852e2009-09-05 21:47:34 +00002973 if (value != (const char *) NULL)
2974 (void) TIFFSetField(tiff,36867,value);
dirka2e407a2015-05-05 13:10:50 +00002975 value=GetImageProperty(image,"label",exception);
cristy3ed852e2009-09-05 21:47:34 +00002976 if (value != (const char *) NULL)
2977 (void) TIFFSetField(tiff,TIFFTAG_PAGENAME,value);
dirka2e407a2015-05-05 13:10:50 +00002978 value=GetImageProperty(image,"comment",exception);
cristy3ed852e2009-09-05 21:47:34 +00002979 if (value != (const char *) NULL)
2980 (void) TIFFSetField(tiff,TIFFTAG_IMAGEDESCRIPTION,value);
cristyfe33a412015-07-27 13:18:43 +00002981 value=GetImageArtifact(image,"tiff:subfiletype");
2982 if (value != (const char *) NULL)
2983 {
2984 if (LocaleCompare(value,"REDUCEDIMAGE") == 0)
2985 (void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_REDUCEDIMAGE);
2986 else
2987 if (LocaleCompare(value,"PAGE") == 0)
2988 (void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_PAGE);
2989 else
2990 if (LocaleCompare(value,"MASK") == 0)
2991 (void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_MASK);
2992 }
2993 else
2994 {
2995 uint16
2996 page,
2997 pages;
2998
2999 page=(uint16) image->scene;
dirk1678aec2015-08-30 12:07:29 +02003000 pages=(uint16) GetImageListLength(image);
cristyfe33a412015-07-27 13:18:43 +00003001 if ((image_info->adjoin != MagickFalse) && (pages > 1))
3002 (void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_PAGE);
3003 (void) TIFFSetField(tiff,TIFFTAG_PAGENUMBER,page,pages);
3004 }
cristy3ed852e2009-09-05 21:47:34 +00003005}
3006
cristyd15e6592011-10-15 00:13:06 +00003007static void TIFFSetEXIFProperties(TIFF *tiff,Image *image,
3008 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003009{
3010#if defined(MAGICKCORE_HAVE_TIFFREADEXIFDIRECTORY)
3011 const char
3012 *value;
3013
cristybb503372010-05-27 20:51:26 +00003014 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003015 i;
3016
3017 uint32
3018 offset;
3019
3020 /*
3021 Write EXIF properties.
3022 */
3023 offset=0;
3024 (void) TIFFSetField(tiff,TIFFTAG_SUBIFD,1,&offset);
3025 for (i=0; exif_info[i].tag != 0; i++)
3026 {
cristyd15e6592011-10-15 00:13:06 +00003027 value=GetImageProperty(image,exif_info[i].property,exception);
cristy3ed852e2009-09-05 21:47:34 +00003028 if (value == (const char *) NULL)
3029 continue;
3030 switch (exif_info[i].type)
3031 {
3032 case TIFF_ASCII:
3033 {
3034 (void) TIFFSetField(tiff,exif_info[i].tag,value);
3035 break;
3036 }
3037 case TIFF_SHORT:
3038 {
3039 uint16
cristy0382cd32013-10-02 13:49:48 +00003040 field;
cristy3ed852e2009-09-05 21:47:34 +00003041
cristy0382cd32013-10-02 13:49:48 +00003042 field=(uint16) StringToLong(value);
3043 (void) TIFFSetField(tiff,exif_info[i].tag,field);
cristy3ed852e2009-09-05 21:47:34 +00003044 break;
3045 }
3046 case TIFF_LONG:
3047 {
3048 uint16
cristy0382cd32013-10-02 13:49:48 +00003049 field;
cristy3ed852e2009-09-05 21:47:34 +00003050
cristy0382cd32013-10-02 13:49:48 +00003051 field=(uint16) StringToLong(value);
3052 (void) TIFFSetField(tiff,exif_info[i].tag,field);
cristy3ed852e2009-09-05 21:47:34 +00003053 break;
3054 }
3055 case TIFF_RATIONAL:
3056 case TIFF_SRATIONAL:
3057 {
3058 float
cristy0382cd32013-10-02 13:49:48 +00003059 field;
cristy3ed852e2009-09-05 21:47:34 +00003060
cristy0382cd32013-10-02 13:49:48 +00003061 field=StringToDouble(value,(char **) NULL);
3062 (void) TIFFSetField(tiff,exif_info[i].tag,field);
cristy3ed852e2009-09-05 21:47:34 +00003063 break;
3064 }
3065 default:
3066 break;
3067 }
3068 }
3069 /* (void) TIFFSetField(tiff,TIFFTAG_EXIFIFD,offset); */
3070#else
3071 (void) tiff;
3072 (void) image;
3073#endif
3074}
3075
3076static MagickBooleanType WriteTIFFImage(const ImageInfo *image_info,
cristy3a37efd2011-08-28 20:31:03 +00003077 Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +00003078{
3079#if !defined(TIFFDefaultStripSize)
3080#define TIFFDefaultStripSize(tiff,request) (8192UL/TIFFScanlineSize(tiff))
3081#endif
3082
3083 const char
3084 *mode,
cristy949bf5b2010-05-08 02:47:03 +00003085 *option;
cristy3ed852e2009-09-05 21:47:34 +00003086
3087 CompressionType
3088 compression;
3089
cristy6b032822010-06-29 16:52:32 +00003090 EndianType
3091 endian_type;
3092
cristy3ed852e2009-09-05 21:47:34 +00003093 MagickBooleanType
3094 debug,
3095 status;
3096
3097 MagickOffsetType
3098 scene;
3099
3100 QuantumInfo
3101 *quantum_info;
3102
3103 QuantumType
3104 quantum_type;
3105
cristybb503372010-05-27 20:51:26 +00003106 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00003107 i;
3108
3109 size_t
cristy9945c6e2012-01-23 19:49:26 +00003110 length;
cristy3ed852e2009-09-05 21:47:34 +00003111
cristyc6da28e2011-04-28 01:41:35 +00003112 ssize_t
3113 y;
3114
cristy3ed852e2009-09-05 21:47:34 +00003115 TIFF
3116 *tiff;
3117
cristy3ed852e2009-09-05 21:47:34 +00003118 TIFFInfo
3119 tiff_info;
3120
3121 uint16
3122 bits_per_sample,
3123 compress_tag,
cristyf2687ca2010-06-29 16:32:38 +00003124 endian,
cristy3ed852e2009-09-05 21:47:34 +00003125 photometric;
3126
3127 uint32
3128 rows_per_strip;
3129
3130 unsigned char
3131 *pixels;
3132
cristy3ed852e2009-09-05 21:47:34 +00003133 /*
3134 Open TIFF file.
3135 */
3136 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +00003137 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00003138 assert(image != (Image *) NULL);
cristye1c94d92015-06-28 12:16:33 +00003139 assert(image->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +00003140 if (image->debug != MagickFalse)
3141 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy3a37efd2011-08-28 20:31:03 +00003142 assert(exception != (ExceptionInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +00003143 assert(exception->signature == MagickCoreSignature);
cristy3a37efd2011-08-28 20:31:03 +00003144 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +00003145 if (status == MagickFalse)
3146 return(status);
Cristy47950f62015-12-18 18:31:40 -05003147 (void) SetMagickThreadValue(tiff_exception,exception);
cristy6b032822010-06-29 16:52:32 +00003148 endian_type=UndefinedEndian;
cristy092ec8d2013-04-26 13:46:22 +00003149 option=GetImageOption(image_info,"tiff:endian");
cristy6b032822010-06-29 16:52:32 +00003150 if (option != (const char *) NULL)
3151 {
3152 if (LocaleNCompare(option,"msb",3) == 0)
3153 endian_type=MSBEndian;
3154 if (LocaleNCompare(option,"lsb",3) == 0)
3155 endian_type=LSBEndian;;
3156 }
3157 switch (endian_type)
cristy3ed852e2009-09-05 21:47:34 +00003158 {
3159 case LSBEndian: mode="wl"; break;
3160 case MSBEndian: mode="wb"; break;
3161 default: mode="w"; break;
3162 }
3163#if defined(TIFF_VERSION_BIG)
3164 if (LocaleCompare(image_info->magick,"TIFF64") == 0)
cristy6b032822010-06-29 16:52:32 +00003165 switch (endian_type)
cristy3ed852e2009-09-05 21:47:34 +00003166 {
3167 case LSBEndian: mode="wl8"; break;
3168 case MSBEndian: mode="wb8"; break;
3169 default: mode="w8"; break;
3170 }
3171#endif
3172 tiff=TIFFClientOpen(image->filename,mode,(thandle_t) image,TIFFReadBlob,
3173 TIFFWriteBlob,TIFFSeekBlob,TIFFCloseBlob,TIFFGetBlobSize,TIFFMapBlob,
3174 TIFFUnmapBlob);
3175 if (tiff == (TIFF *) NULL)
Cristy97af9962015-12-19 06:51:20 -05003176 return(MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +00003177 scene=0;
3178 debug=IsEventLogging();
cristyda16f162011-02-19 23:52:17 +00003179 (void) debug;
cristy3ed852e2009-09-05 21:47:34 +00003180 do
3181 {
3182 /*
3183 Initialize TIFF fields.
3184 */
cristy5f1c1ff2010-12-23 21:38:06 +00003185 if ((image_info->type != UndefinedType) &&
cristy3ed852e2009-09-05 21:47:34 +00003186 (image_info->type != OptimizeType))
cristy018f07f2011-09-04 21:15:19 +00003187 (void) SetImageType(image,image_info->type,exception);
dirk29dd80e2013-10-31 23:11:11 +00003188 compression=UndefinedCompression;
dirke2ef17a2014-05-15 10:58:44 +00003189 if (image->compression != JPEGCompression)
3190 compression=image->compression;
cristy3ed852e2009-09-05 21:47:34 +00003191 if (image_info->compression != UndefinedCompression)
3192 compression=image_info->compression;
3193 switch (compression)
3194 {
3195 case FaxCompression:
cristya5573bc2013-10-26 14:13:34 +00003196 case Group4Compression:
3197 {
3198 (void) SetImageType(image,BilevelType,exception);
Cristy3cb17ec2015-12-30 10:17:39 -05003199 (void) SetImageDepth(image,1,exception);
cristya5573bc2013-10-26 14:13:34 +00003200 break;
3201 }
3202 case JPEGCompression:
3203 {
3204 (void) SetImageStorageClass(image,DirectClass,exception);
3205 (void) SetImageDepth(image,8,exception);
3206 break;
3207 }
3208 default:
3209 break;
3210 }
cristy5f766ef2014-12-14 21:12:47 +00003211 quantum_info=AcquireQuantumInfo(image_info,image);
cristya5573bc2013-10-26 14:13:34 +00003212 if (quantum_info == (QuantumInfo *) NULL)
3213 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3214 if ((image->storage_class != PseudoClass) && (image->depth >= 32) &&
3215 (quantum_info->format == UndefinedQuantumFormat) &&
3216 (IsHighDynamicRangeImage(image,exception) != MagickFalse))
3217 {
3218 status=SetQuantumFormat(image,quantum_info,FloatingPointQuantumFormat);
3219 if (status == MagickFalse)
3220 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3221 }
3222 if ((LocaleCompare(image_info->magick,"PTIF") == 0) &&
3223 (GetPreviousImageInList(image) != (Image *) NULL))
3224 (void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_REDUCEDIMAGE);
3225 if ((image->columns != (uint32) image->columns) ||
3226 (image->rows != (uint32) image->rows))
3227 ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
3228 (void) TIFFSetField(tiff,TIFFTAG_IMAGELENGTH,(uint32) image->rows);
3229 (void) TIFFSetField(tiff,TIFFTAG_IMAGEWIDTH,(uint32) image->columns);
3230 switch (compression)
3231 {
3232 case FaxCompression:
cristy3ed852e2009-09-05 21:47:34 +00003233 {
3234 compress_tag=COMPRESSION_CCITTFAX3;
3235 SetQuantumMinIsWhite(quantum_info,MagickTrue);
3236 break;
3237 }
3238 case Group4Compression:
3239 {
3240 compress_tag=COMPRESSION_CCITTFAX4;
3241 SetQuantumMinIsWhite(quantum_info,MagickTrue);
3242 break;
3243 }
cristy6d5e20f2011-04-25 13:48:54 +00003244#if defined(COMPRESSION_JBIG)
3245 case JBIG1Compression:
3246 {
3247 compress_tag=COMPRESSION_JBIG;
3248 break;
3249 }
3250#endif
cristy3ed852e2009-09-05 21:47:34 +00003251 case JPEGCompression:
3252 {
3253 compress_tag=COMPRESSION_JPEG;
3254 break;
3255 }
cristyfbb0ef02010-12-19 02:32:11 +00003256#if defined(COMPRESSION_LZMA)
3257 case LZMACompression:
3258 {
3259 compress_tag=COMPRESSION_LZMA;
3260 break;
3261 }
3262#endif
cristy3ed852e2009-09-05 21:47:34 +00003263 case LZWCompression:
3264 {
3265 compress_tag=COMPRESSION_LZW;
3266 break;
3267 }
3268 case RLECompression:
3269 {
3270 compress_tag=COMPRESSION_PACKBITS;
3271 break;
3272 }
3273 case ZipCompression:
3274 {
3275 compress_tag=COMPRESSION_ADOBE_DEFLATE;
3276 break;
3277 }
3278 case NoCompression:
3279 default:
3280 {
3281 compress_tag=COMPRESSION_NONE;
3282 break;
3283 }
3284 }
cristy5b675872009-10-21 13:12:00 +00003285#if defined(MAGICKCORE_HAVE_TIFFISCODECCONFIGURED) || (TIFFLIB_VERSION > 20040919)
3286 if ((compress_tag != COMPRESSION_NONE) &&
3287 (TIFFIsCODECConfigured(compress_tag) == 0))
cristy3ed852e2009-09-05 21:47:34 +00003288 {
cristy3a37efd2011-08-28 20:31:03 +00003289 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
3290 "CompressionNotSupported","`%s'",CommandOptionToMnemonic(
cristybb503372010-05-27 20:51:26 +00003291 MagickCompressOptions,(ssize_t) compression));
cristy5b675872009-10-21 13:12:00 +00003292 compress_tag=COMPRESSION_NONE;
3293 compression=NoCompression;
cristy3ed852e2009-09-05 21:47:34 +00003294 }
3295#else
3296 switch (compress_tag)
3297 {
3298#if defined(CCITT_SUPPORT)
3299 case COMPRESSION_CCITTFAX3:
3300 case COMPRESSION_CCITTFAX4:
3301#endif
3302#if defined(YCBCR_SUPPORT) && defined(JPEG_SUPPORT)
3303 case COMPRESSION_JPEG:
3304#endif
cristyfbb0ef02010-12-19 02:32:11 +00003305#if defined(LZMA_SUPPORT) && defined(COMPRESSION_LZMA)
3306 case COMPRESSION_LZMA:
3307#endif
cristy3ed852e2009-09-05 21:47:34 +00003308#if defined(LZW_SUPPORT)
3309 case COMPRESSION_LZW:
3310#endif
3311#if defined(PACKBITS_SUPPORT)
3312 case COMPRESSION_PACKBITS:
3313#endif
3314#if defined(ZIP_SUPPORT)
3315 case COMPRESSION_ADOBE_DEFLATE:
3316#endif
3317 case COMPRESSION_NONE:
3318 break;
3319 default:
3320 {
cristy3a37efd2011-08-28 20:31:03 +00003321 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
3322 "CompressionNotSupported","`%s'",CommandOptionToMnemonic(
cristybb503372010-05-27 20:51:26 +00003323 MagickCompressOptions,(ssize_t) compression));
cristy3ed852e2009-09-05 21:47:34 +00003324 compress_tag=COMPRESSION_NONE;
3325 compression=NoCompression;
3326 break;
3327 }
3328 }
3329#endif
cristy3ed852e2009-09-05 21:47:34 +00003330 if (image->colorspace == CMYKColorspace)
3331 {
3332 photometric=PHOTOMETRIC_SEPARATED;
3333 (void) TIFFSetField(tiff,TIFFTAG_SAMPLESPERPIXEL,4);
3334 (void) TIFFSetField(tiff,TIFFTAG_INKSET,INKSET_CMYK);
3335 }
3336 else
3337 {
3338 /*
3339 Full color TIFF raster.
3340 */
3341 if (image->colorspace == LabColorspace)
cristy514da942012-07-06 23:24:14 +00003342 {
3343 photometric=PHOTOMETRIC_CIELAB;
3344 EncodeLabImage(image,exception);
3345 }
cristy3ed852e2009-09-05 21:47:34 +00003346 else
3347 if (image->colorspace == YCbCrColorspace)
3348 {
3349 photometric=PHOTOMETRIC_YCBCR;
3350 (void) TIFFSetField(tiff,TIFFTAG_YCBCRSUBSAMPLING,1,1);
cristy3a37efd2011-08-28 20:31:03 +00003351 (void) SetImageStorageClass(image,DirectClass,exception);
cristy8a11cb12011-10-19 23:53:34 +00003352 (void) SetImageDepth(image,8,exception);
cristy3ed852e2009-09-05 21:47:34 +00003353 }
3354 else
cristybdf2cb22012-05-30 12:06:16 +00003355 photometric=PHOTOMETRIC_RGB;
cristy3ed852e2009-09-05 21:47:34 +00003356 (void) TIFFSetField(tiff,TIFFTAG_SAMPLESPERPIXEL,3);
3357 if ((image_info->type != TrueColorType) &&
cristydef23e52015-01-22 11:52:01 +00003358 (image_info->type != TrueColorAlphaType))
cristy3ed852e2009-09-05 21:47:34 +00003359 {
cristy94c8fe42009-10-06 01:57:36 +00003360 if ((image_info->type != PaletteType) &&
cristy258ccf52015-07-24 01:07:31 +00003361 (SetImageGray(image,exception) != MagickFalse))
cristy3ed852e2009-09-05 21:47:34 +00003362 {
cristy94c8fe42009-10-06 01:57:36 +00003363 photometric=(uint16) (quantum_info->min_is_white !=
3364 MagickFalse ? PHOTOMETRIC_MINISWHITE :
3365 PHOTOMETRIC_MINISBLACK);
cristy3ed852e2009-09-05 21:47:34 +00003366 (void) TIFFSetField(tiff,TIFFTAG_SAMPLESPERPIXEL,1);
Cristya648c5a2015-12-29 14:08:57 -05003367 if ((image->depth == 1) &&
3368 (image->alpha_trait == UndefinedPixelTrait))
3369 SetImageMonochrome(image,exception);
cristy3ed852e2009-09-05 21:47:34 +00003370 }
3371 else
cristy94c8fe42009-10-06 01:57:36 +00003372 if (image->storage_class == PseudoClass)
cristy3ed852e2009-09-05 21:47:34 +00003373 {
cristybb503372010-05-27 20:51:26 +00003374 size_t
cristy94c8fe42009-10-06 01:57:36 +00003375 depth;
3376
3377 /*
3378 Colormapped TIFF raster.
3379 */
cristy3ed852e2009-09-05 21:47:34 +00003380 (void) TIFFSetField(tiff,TIFFTAG_SAMPLESPERPIXEL,1);
cristy94c8fe42009-10-06 01:57:36 +00003381 photometric=PHOTOMETRIC_PALETTE;
3382 depth=1;
3383 while ((GetQuantumRange(depth)+1) < image->colors)
3384 depth<<=1;
3385 status=SetQuantumDepth(image,quantum_info,depth);
3386 if (status == MagickFalse)
3387 ThrowWriterException(ResourceLimitError,
3388 "MemoryAllocationFailed");
cristy3ed852e2009-09-05 21:47:34 +00003389 }
3390 }
3391 }
cristy82653b22014-09-20 12:41:42 +00003392 (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_FILLORDER,&endian);
cristydaff8092010-04-22 14:50:53 +00003393 if ((compress_tag == COMPRESSION_CCITTFAX3) &&
3394 (photometric != PHOTOMETRIC_MINISWHITE))
3395 {
3396 compress_tag=COMPRESSION_NONE;
cristyf2687ca2010-06-29 16:32:38 +00003397 endian=FILLORDER_MSB2LSB;
cristydaff8092010-04-22 14:50:53 +00003398 }
cristy0accf6e2009-10-01 13:14:28 +00003399 else
cristydaff8092010-04-22 14:50:53 +00003400 if ((compress_tag == COMPRESSION_CCITTFAX4) &&
3401 (photometric != PHOTOMETRIC_MINISWHITE))
3402 {
3403 compress_tag=COMPRESSION_NONE;
cristyf2687ca2010-06-29 16:32:38 +00003404 endian=FILLORDER_MSB2LSB;
cristydaff8092010-04-22 14:50:53 +00003405 }
cristy092ec8d2013-04-26 13:46:22 +00003406 option=GetImageOption(image_info,"tiff:fill-order");
cristy62e282b2010-06-29 01:27:13 +00003407 if (option != (const char *) NULL)
3408 {
3409 if (LocaleNCompare(option,"msb",3) == 0)
cristyf2687ca2010-06-29 16:32:38 +00003410 endian=FILLORDER_MSB2LSB;
cristy62e282b2010-06-29 01:27:13 +00003411 if (LocaleNCompare(option,"lsb",3) == 0)
cristyf2687ca2010-06-29 16:32:38 +00003412 endian=FILLORDER_LSB2MSB;
cristy62e282b2010-06-29 01:27:13 +00003413 }
cristyf2687ca2010-06-29 16:32:38 +00003414 (void) TIFFSetField(tiff,TIFFTAG_COMPRESSION,compress_tag);
3415 (void) TIFFSetField(tiff,TIFFTAG_FILLORDER,endian);
cristy3ed852e2009-09-05 21:47:34 +00003416 (void) TIFFSetField(tiff,TIFFTAG_BITSPERSAMPLE,quantum_info->depth);
cristy17f11b02014-12-20 19:37:04 +00003417 if (image->alpha_trait != UndefinedPixelTrait)
cristy3ed852e2009-09-05 21:47:34 +00003418 {
3419 uint16
3420 extra_samples,
3421 sample_info[1],
3422 samples_per_pixel;
3423
3424 /*
3425 TIFF has a matte channel.
3426 */
3427 extra_samples=1;
3428 sample_info[0]=EXTRASAMPLE_UNASSALPHA;
cristy092ec8d2013-04-26 13:46:22 +00003429 option=GetImageOption(image_info,"tiff:alpha");
dirk42bc62a2014-10-07 20:17:51 +00003430 if (option != (const char *) NULL)
3431 {
3432 if (LocaleCompare(option,"associated") == 0)
3433 sample_info[0]=EXTRASAMPLE_ASSOCALPHA;
cristy269e8e72014-10-12 21:27:45 +00003434 else
3435 if (LocaleCompare(option,"unspecified") == 0)
3436 sample_info[0]=EXTRASAMPLE_UNSPECIFIED;
dirk42bc62a2014-10-07 20:17:51 +00003437 }
cristy3ed852e2009-09-05 21:47:34 +00003438 (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_SAMPLESPERPIXEL,
3439 &samples_per_pixel);
3440 (void) TIFFSetField(tiff,TIFFTAG_SAMPLESPERPIXEL,samples_per_pixel+1);
3441 (void) TIFFSetField(tiff,TIFFTAG_EXTRASAMPLES,extra_samples,
3442 &sample_info);
3443 if (sample_info[0] == EXTRASAMPLE_ASSOCALPHA)
3444 SetQuantumAlphaType(quantum_info,AssociatedQuantumAlpha);
3445 }
3446 (void) TIFFSetField(tiff,TIFFTAG_PHOTOMETRIC,photometric);
3447 switch (quantum_info->format)
3448 {
3449 case FloatingPointQuantumFormat:
3450 {
3451 (void) TIFFSetField(tiff,TIFFTAG_SAMPLEFORMAT,SAMPLEFORMAT_IEEEFP);
3452 (void) TIFFSetField(tiff,TIFFTAG_SMINSAMPLEVALUE,quantum_info->minimum);
3453 (void) TIFFSetField(tiff,TIFFTAG_SMAXSAMPLEVALUE,quantum_info->maximum);
3454 break;
3455 }
3456 case SignedQuantumFormat:
3457 {
3458 (void) TIFFSetField(tiff,TIFFTAG_SAMPLEFORMAT,SAMPLEFORMAT_INT);
3459 break;
3460 }
3461 case UnsignedQuantumFormat:
3462 {
3463 (void) TIFFSetField(tiff,TIFFTAG_SAMPLEFORMAT,SAMPLEFORMAT_UINT);
3464 break;
3465 }
3466 default:
3467 break;
3468 }
cristy3ed852e2009-09-05 21:47:34 +00003469 (void) TIFFSetField(tiff,TIFFTAG_ORIENTATION,ORIENTATION_TOPLEFT);
3470 (void) TIFFSetField(tiff,TIFFTAG_PLANARCONFIG,PLANARCONFIG_CONTIG);
3471 if (photometric == PHOTOMETRIC_RGB)
3472 if ((image_info->interlace == PlaneInterlace) ||
3473 (image_info->interlace == PartitionInterlace))
3474 (void) TIFFSetField(tiff,TIFFTAG_PLANARCONFIG,PLANARCONFIG_SEPARATE);
cristyefc63e42013-09-05 16:15:56 +00003475 rows_per_strip=TIFFDefaultStripSize(tiff,0);
cristy092ec8d2013-04-26 13:46:22 +00003476 option=GetImageOption(image_info,"tiff:rows-per-strip");
cristy3ed852e2009-09-05 21:47:34 +00003477 if (option != (const char *) NULL)
cristybb503372010-05-27 20:51:26 +00003478 rows_per_strip=(size_t) strtol(option,(char **) NULL,10);
cristy3ed852e2009-09-05 21:47:34 +00003479 switch (compress_tag)
3480 {
3481 case COMPRESSION_JPEG:
3482 {
3483#if defined(JPEG_SUPPORT)
3484 const char
3485 *sampling_factor;
3486
3487 GeometryInfo
3488 geometry_info;
3489
3490 MagickStatusType
3491 flags;
3492
3493 rows_per_strip+=(16-(rows_per_strip % 16));
cristy3ed852e2009-09-05 21:47:34 +00003494 if (image_info->quality != UndefinedCompressionQuality)
3495 (void) TIFFSetField(tiff,TIFFTAG_JPEGQUALITY,image_info->quality);
3496 (void) TIFFSetField(tiff,TIFFTAG_JPEGCOLORMODE,JPEGCOLORMODE_RAW);
cristy3d9f5ba2012-06-26 13:37:31 +00003497 if (IssRGBCompatibleColorspace(image->colorspace) != MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003498 {
cristy949bf5b2010-05-08 02:47:03 +00003499 const char
3500 *value;
3501
cristy3ed852e2009-09-05 21:47:34 +00003502 (void) TIFFSetField(tiff,TIFFTAG_JPEGCOLORMODE,JPEGCOLORMODE_RGB);
3503 sampling_factor=(const char *) NULL;
cristyd15e6592011-10-15 00:13:06 +00003504 value=GetImageProperty(image,"jpeg:sampling-factor",exception);
cristy3ed852e2009-09-05 21:47:34 +00003505 if (value != (char *) NULL)
3506 {
3507 sampling_factor=value;
3508 if (image->debug != MagickFalse)
3509 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3510 " Input sampling-factors=%s",sampling_factor);
3511 }
3512 if (image_info->sampling_factor != (char *) NULL)
3513 sampling_factor=image_info->sampling_factor;
3514 if (sampling_factor != (const char *) NULL)
3515 {
3516 flags=ParseGeometry(sampling_factor,&geometry_info);
3517 if ((flags & SigmaValue) == 0)
3518 geometry_info.sigma=geometry_info.rho;
cristy79e5dad2010-09-16 19:48:33 +00003519 if (image->colorspace == YCbCrColorspace)
3520 (void) TIFFSetField(tiff,TIFFTAG_YCBCRSUBSAMPLING,(uint16)
3521 geometry_info.rho,(uint16) geometry_info.sigma);
cristy3ed852e2009-09-05 21:47:34 +00003522 }
3523 }
cristy875a5ba2014-07-25 16:14:05 +00003524 (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_BITSPERSAMPLE,
3525 &bits_per_sample);
cristy3ed852e2009-09-05 21:47:34 +00003526 if (bits_per_sample == 12)
3527 (void) TIFFSetField(tiff,TIFFTAG_JPEGTABLESMODE,JPEGTABLESMODE_QUANT);
3528#endif
3529 break;
3530 }
3531 case COMPRESSION_ADOBE_DEFLATE:
3532 {
cristyf6fe0a12010-05-30 00:44:47 +00003533 rows_per_strip=(uint32) image->rows;
cristy3ed852e2009-09-05 21:47:34 +00003534 (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_BITSPERSAMPLE,
3535 &bits_per_sample);
3536 if (((photometric == PHOTOMETRIC_RGB) ||
3537 (photometric == PHOTOMETRIC_MINISBLACK)) &&
3538 ((bits_per_sample == 8) || (bits_per_sample == 16)))
cristyef8f26b2010-12-19 20:29:16 +00003539 (void) TIFFSetField(tiff,TIFFTAG_PREDICTOR,PREDICTOR_HORIZONTAL);
cristyf6fe0a12010-05-30 00:44:47 +00003540 (void) TIFFSetField(tiff,TIFFTAG_ZIPQUALITY,(long) (
3541 image_info->quality == UndefinedCompressionQuality ? 7 :
cristy0b29b252010-05-30 01:59:46 +00003542 MagickMin((ssize_t) image_info->quality/10,9)));
cristy3ed852e2009-09-05 21:47:34 +00003543 break;
3544 }
3545 case COMPRESSION_CCITTFAX3:
3546 {
3547 /*
3548 Byte-aligned EOL.
3549 */
cristyeaedf062010-05-29 22:36:02 +00003550 rows_per_strip=(uint32) image->rows;
cristy3ed852e2009-09-05 21:47:34 +00003551 (void) TIFFSetField(tiff,TIFFTAG_GROUP3OPTIONS,4);
3552 break;
3553 }
3554 case COMPRESSION_CCITTFAX4:
3555 {
cristyeaedf062010-05-29 22:36:02 +00003556 rows_per_strip=(uint32) image->rows;
cristy3ed852e2009-09-05 21:47:34 +00003557 break;
3558 }
cristyef8f26b2010-12-19 20:29:16 +00003559#if defined(LZMA_SUPPORT) && defined(COMPRESSION_LZMA)
3560 case COMPRESSION_LZMA:
3561 {
3562 if (((photometric == PHOTOMETRIC_RGB) ||
3563 (photometric == PHOTOMETRIC_MINISBLACK)) &&
3564 ((bits_per_sample == 8) || (bits_per_sample == 16)))
3565 (void) TIFFSetField(tiff,TIFFTAG_PREDICTOR,PREDICTOR_HORIZONTAL);
3566 (void) TIFFSetField(tiff,TIFFTAG_LZMAPRESET,(long) (
3567 image_info->quality == UndefinedCompressionQuality ? 7 :
3568 MagickMin((ssize_t) image_info->quality/10,9)));
3569 break;
3570 }
3571#endif
cristy3ed852e2009-09-05 21:47:34 +00003572 case COMPRESSION_LZW:
3573 {
3574 (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_BITSPERSAMPLE,
3575 &bits_per_sample);
3576 if (((photometric == PHOTOMETRIC_RGB) ||
3577 (photometric == PHOTOMETRIC_MINISBLACK)) &&
3578 ((bits_per_sample == 8) || (bits_per_sample == 16)))
cristyef8f26b2010-12-19 20:29:16 +00003579 (void) TIFFSetField(tiff,TIFFTAG_PREDICTOR,PREDICTOR_HORIZONTAL);
cristy3ed852e2009-09-05 21:47:34 +00003580 break;
3581 }
3582 default:
3583 break;
3584 }
cristyefc63e42013-09-05 16:15:56 +00003585 if (rows_per_strip < 1)
3586 rows_per_strip=1;
cristyc0cbda02013-09-05 16:05:31 +00003587 if ((image->rows/rows_per_strip) >= (1UL << 15))
cristy0e274112014-03-25 14:09:19 +00003588 rows_per_strip=(uint32) (image->rows >> 15);
cristy548dfc72013-05-07 13:34:36 +00003589 (void) TIFFSetField(tiff,TIFFTAG_ROWSPERSTRIP,rows_per_strip);
cristy2a11bef2011-10-28 18:33:11 +00003590 if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
cristy3ed852e2009-09-05 21:47:34 +00003591 {
3592 unsigned short
3593 units;
3594
3595 /*
3596 Set image resolution.
3597 */
3598 units=RESUNIT_NONE;
3599 if (image->units == PixelsPerInchResolution)
3600 units=RESUNIT_INCH;
3601 if (image->units == PixelsPerCentimeterResolution)
3602 units=RESUNIT_CENTIMETER;
3603 (void) TIFFSetField(tiff,TIFFTAG_RESOLUTIONUNIT,(uint16) units);
cristy2a11bef2011-10-28 18:33:11 +00003604 (void) TIFFSetField(tiff,TIFFTAG_XRESOLUTION,image->resolution.x);
3605 (void) TIFFSetField(tiff,TIFFTAG_YRESOLUTION,image->resolution.y);
cristyaaf690a2013-07-25 12:00:12 +00003606 if ((image->page.x < 0) || (image->page.y < 0))
3607 (void) ThrowMagickException(exception,GetMagickModule(),CoderError,
3608 "TIFF: negative image positions unsupported","%s",image->filename);
3609 if ((image->page.x > 0) && (image->resolution.x > 0.0))
cristy3ed852e2009-09-05 21:47:34 +00003610 {
3611 /*
cristyaaf690a2013-07-25 12:00:12 +00003612 Set horizontal image position.
cristy3ed852e2009-09-05 21:47:34 +00003613 */
cristyaaf690a2013-07-25 12:00:12 +00003614 (void) TIFFSetField(tiff,TIFFTAG_XPOSITION,(float) image->page.x/
3615 image->resolution.x);
3616 }
3617 if ((image->page.y > 0) && (image->resolution.y > 0.0))
3618 {
3619 /*
3620 Set vertical image position.
3621 */
3622 (void) TIFFSetField(tiff,TIFFTAG_YPOSITION,(float) image->page.y/
3623 image->resolution.y);
cristy3ed852e2009-09-05 21:47:34 +00003624 }
3625 }
3626 if (image->chromaticity.white_point.x != 0.0)
3627 {
3628 float
3629 chromaticity[6];
3630
3631 /*
3632 Set image chromaticity.
3633 */
3634 chromaticity[0]=(float) image->chromaticity.red_primary.x;
3635 chromaticity[1]=(float) image->chromaticity.red_primary.y;
3636 chromaticity[2]=(float) image->chromaticity.green_primary.x;
3637 chromaticity[3]=(float) image->chromaticity.green_primary.y;
3638 chromaticity[4]=(float) image->chromaticity.blue_primary.x;
3639 chromaticity[5]=(float) image->chromaticity.blue_primary.y;
3640 (void) TIFFSetField(tiff,TIFFTAG_PRIMARYCHROMATICITIES,chromaticity);
3641 chromaticity[0]=(float) image->chromaticity.white_point.x;
3642 chromaticity[1]=(float) image->chromaticity.white_point.y;
3643 (void) TIFFSetField(tiff,TIFFTAG_WHITEPOINT,chromaticity);
3644 }
cristy59788de2011-11-23 13:56:19 +00003645 if ((LocaleCompare(image_info->magick,"PTIF") != 0) &&
3646 (image_info->adjoin != MagickFalse) && (GetImageListLength(image) > 1))
cristy3ed852e2009-09-05 21:47:34 +00003647 {
3648 (void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_PAGE);
3649 if (image->scene != 0)
3650 (void) TIFFSetField(tiff,TIFFTAG_PAGENUMBER,(uint16) image->scene,
3651 GetImageListLength(image));
3652 }
3653 if (image->orientation != UndefinedOrientation)
3654 (void) TIFFSetField(tiff,TIFFTAG_ORIENTATION,(uint16) image->orientation);
3655 (void) TIFFSetProfiles(tiff,image);
3656 {
3657 uint16
3658 page,
3659 pages;
3660
3661 page=(uint16) scene;
cristyeaedf062010-05-29 22:36:02 +00003662 pages=(uint16) GetImageListLength(image);
cristy59788de2011-11-23 13:56:19 +00003663 if ((LocaleCompare(image_info->magick,"PTIF") != 0) &&
3664 (image_info->adjoin != MagickFalse) && (pages > 1))
cristy3ed852e2009-09-05 21:47:34 +00003665 (void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_PAGE);
3666 (void) TIFFSetField(tiff,TIFFTAG_PAGENUMBER,page,pages);
3667 }
cristyfe33a412015-07-27 13:18:43 +00003668 (void) TIFFSetProperties(tiff,image_info,image,exception);
dirk93b02b72013-11-16 16:03:36 +00003669DisableMSCWarning(4127)
cristy3ed852e2009-09-05 21:47:34 +00003670 if (0)
dirk93b02b72013-11-16 16:03:36 +00003671RestoreMSCWarning
cristyd15e6592011-10-15 00:13:06 +00003672 (void) TIFFSetEXIFProperties(tiff,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00003673 /*
3674 Write image scanlines.
3675 */
cristyb0de93f2013-05-03 13:39:25 +00003676 if (GetTIFFInfo(image_info,tiff,&tiff_info) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00003677 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
cristyf164a872012-01-20 18:26:34 +00003678 quantum_info->endian=LSBEndian;
cristyb3f97ae2015-05-18 12:29:32 +00003679 pixels=(unsigned char *) GetQuantumPixels(quantum_info);
3680 tiff_info.scanline=(unsigned char *) GetQuantumPixels(quantum_info);
cristy3ed852e2009-09-05 21:47:34 +00003681 switch (photometric)
3682 {
3683 case PHOTOMETRIC_CIELAB:
3684 case PHOTOMETRIC_YCBCR:
3685 case PHOTOMETRIC_RGB:
3686 {
3687 /*
3688 RGB TIFF image.
3689 */
3690 switch (image_info->interlace)
3691 {
3692 case NoInterlace:
3693 default:
3694 {
3695 quantum_type=RGBQuantum;
cristy17f11b02014-12-20 19:37:04 +00003696 if (image->alpha_trait != UndefinedPixelTrait)
cristy3ed852e2009-09-05 21:47:34 +00003697 quantum_type=RGBAQuantum;
cristybb503372010-05-27 20:51:26 +00003698 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00003699 {
cristy4c08aed2011-07-01 19:47:50 +00003700 register const Quantum
dirk05d2ff72015-11-18 23:13:43 +01003701 *magick_restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003702
cristy3a37efd2011-08-28 20:31:03 +00003703 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003704 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003705 break;
cristy4c08aed2011-07-01 19:47:50 +00003706 length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
cristy3a37efd2011-08-28 20:31:03 +00003707 quantum_type,pixels,exception);
cristyda16f162011-02-19 23:52:17 +00003708 (void) length;
cristy3ed852e2009-09-05 21:47:34 +00003709 if (TIFFWritePixels(tiff,&tiff_info,y,0,image) == -1)
3710 break;
3711 if (image->previous == (Image *) NULL)
3712 {
cristy2837bcc2010-08-07 23:57:39 +00003713 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType)
3714 y,image->rows);
cristy3ed852e2009-09-05 21:47:34 +00003715 if (status == MagickFalse)
3716 break;
3717 }
3718 }
3719 break;
3720 }
3721 case PlaneInterlace:
3722 case PartitionInterlace:
3723 {
3724 /*
3725 Plane interlacing: RRRRRR...GGGGGG...BBBBBB...
3726 */
cristybb503372010-05-27 20:51:26 +00003727 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00003728 {
cristy4c08aed2011-07-01 19:47:50 +00003729 register const Quantum
dirk05d2ff72015-11-18 23:13:43 +01003730 *magick_restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003731
cristy3a37efd2011-08-28 20:31:03 +00003732 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003733 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003734 break;
cristy4c08aed2011-07-01 19:47:50 +00003735 length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
cristy3a37efd2011-08-28 20:31:03 +00003736 RedQuantum,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +00003737 if (TIFFWritePixels(tiff,&tiff_info,y,0,image) == -1)
3738 break;
3739 }
3740 if (image->previous == (Image *) NULL)
3741 {
3742 status=SetImageProgress(image,SaveImageTag,100,400);
3743 if (status == MagickFalse)
3744 break;
3745 }
cristybb503372010-05-27 20:51:26 +00003746 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00003747 {
cristy4c08aed2011-07-01 19:47:50 +00003748 register const Quantum
dirk05d2ff72015-11-18 23:13:43 +01003749 *magick_restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003750
cristy3a37efd2011-08-28 20:31:03 +00003751 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003752 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003753 break;
cristy4c08aed2011-07-01 19:47:50 +00003754 length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
cristy3a37efd2011-08-28 20:31:03 +00003755 GreenQuantum,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +00003756 if (TIFFWritePixels(tiff,&tiff_info,y,1,image) == -1)
3757 break;
3758 }
3759 if (image->previous == (Image *) NULL)
3760 {
3761 status=SetImageProgress(image,SaveImageTag,200,400);
3762 if (status == MagickFalse)
3763 break;
3764 }
cristybb503372010-05-27 20:51:26 +00003765 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00003766 {
cristy4c08aed2011-07-01 19:47:50 +00003767 register const Quantum
dirk05d2ff72015-11-18 23:13:43 +01003768 *magick_restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003769
cristy3a37efd2011-08-28 20:31:03 +00003770 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003771 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003772 break;
cristy4c08aed2011-07-01 19:47:50 +00003773 length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
cristy3a37efd2011-08-28 20:31:03 +00003774 BlueQuantum,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +00003775 if (TIFFWritePixels(tiff,&tiff_info,y,2,image) == -1)
3776 break;
3777 }
3778 if (image->previous == (Image *) NULL)
3779 {
3780 status=SetImageProgress(image,SaveImageTag,300,400);
3781 if (status == MagickFalse)
3782 break;
3783 }
cristy17f11b02014-12-20 19:37:04 +00003784 if (image->alpha_trait != UndefinedPixelTrait)
cristybb503372010-05-27 20:51:26 +00003785 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00003786 {
cristy4c08aed2011-07-01 19:47:50 +00003787 register const Quantum
dirk05d2ff72015-11-18 23:13:43 +01003788 *magick_restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003789
cristy3a37efd2011-08-28 20:31:03 +00003790 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003791 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003792 break;
cristy4c08aed2011-07-01 19:47:50 +00003793 length=ExportQuantumPixels(image,(CacheView *) NULL,
cristy3a37efd2011-08-28 20:31:03 +00003794 quantum_info,AlphaQuantum,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +00003795 if (TIFFWritePixels(tiff,&tiff_info,y,3,image) == -1)
3796 break;
3797 }
3798 if (image->previous == (Image *) NULL)
3799 {
3800 status=SetImageProgress(image,SaveImageTag,400,400);
3801 if (status == MagickFalse)
3802 break;
3803 }
3804 break;
3805 }
3806 }
3807 break;
3808 }
3809 case PHOTOMETRIC_SEPARATED:
3810 {
3811 /*
3812 CMYK TIFF image.
3813 */
3814 quantum_type=CMYKQuantum;
cristy17f11b02014-12-20 19:37:04 +00003815 if (image->alpha_trait != UndefinedPixelTrait)
cristy3ed852e2009-09-05 21:47:34 +00003816 quantum_type=CMYKAQuantum;
3817 if (image->colorspace != CMYKColorspace)
cristye941a752011-10-15 01:52:48 +00003818 (void) TransformImageColorspace(image,CMYKColorspace,exception);
cristybb503372010-05-27 20:51:26 +00003819 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00003820 {
cristy4c08aed2011-07-01 19:47:50 +00003821 register const Quantum
dirk05d2ff72015-11-18 23:13:43 +01003822 *magick_restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003823
cristy3a37efd2011-08-28 20:31:03 +00003824 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003825 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003826 break;
cristy4c08aed2011-07-01 19:47:50 +00003827 length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
cristy3a37efd2011-08-28 20:31:03 +00003828 quantum_type,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +00003829 if (TIFFWritePixels(tiff,&tiff_info,y,0,image) == -1)
3830 break;
3831 if (image->previous == (Image *) NULL)
3832 {
cristycee97112010-05-28 00:44:52 +00003833 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
3834 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00003835 if (status == MagickFalse)
3836 break;
3837 }
3838 }
3839 break;
3840 }
3841 case PHOTOMETRIC_PALETTE:
3842 {
3843 uint16
3844 *blue,
3845 *green,
3846 *red;
3847
3848 /*
3849 Colormapped TIFF image.
3850 */
3851 red=(uint16 *) AcquireQuantumMemory(65536,sizeof(*red));
3852 green=(uint16 *) AcquireQuantumMemory(65536,sizeof(*green));
3853 blue=(uint16 *) AcquireQuantumMemory(65536,sizeof(*blue));
3854 if ((red == (uint16 *) NULL) || (green == (uint16 *) NULL) ||
3855 (blue == (uint16 *) NULL))
3856 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
3857 /*
3858 Initialize TIFF colormap.
3859 */
3860 (void) ResetMagickMemory(red,0,65536*sizeof(*red));
3861 (void) ResetMagickMemory(green,0,65536*sizeof(*green));
3862 (void) ResetMagickMemory(blue,0,65536*sizeof(*blue));
cristybb503372010-05-27 20:51:26 +00003863 for (i=0; i < (ssize_t) image->colors; i++)
cristy3ed852e2009-09-05 21:47:34 +00003864 {
3865 red[i]=ScaleQuantumToShort(image->colormap[i].red);
3866 green[i]=ScaleQuantumToShort(image->colormap[i].green);
3867 blue[i]=ScaleQuantumToShort(image->colormap[i].blue);
3868 }
3869 (void) TIFFSetField(tiff,TIFFTAG_COLORMAP,red,green,blue);
3870 red=(uint16 *) RelinquishMagickMemory(red);
3871 green=(uint16 *) RelinquishMagickMemory(green);
3872 blue=(uint16 *) RelinquishMagickMemory(blue);
3873 }
3874 default:
3875 {
3876 /*
3877 Convert PseudoClass packets to contiguous grayscale scanlines.
3878 */
3879 quantum_type=IndexQuantum;
cristy17f11b02014-12-20 19:37:04 +00003880 if (image->alpha_trait != UndefinedPixelTrait)
cristy3ed852e2009-09-05 21:47:34 +00003881 {
3882 if (photometric != PHOTOMETRIC_PALETTE)
3883 quantum_type=GrayAlphaQuantum;
3884 else
3885 quantum_type=IndexAlphaQuantum;
3886 }
3887 else
3888 if (photometric != PHOTOMETRIC_PALETTE)
3889 quantum_type=GrayQuantum;
cristybb503372010-05-27 20:51:26 +00003890 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +00003891 {
cristy4c08aed2011-07-01 19:47:50 +00003892 register const Quantum
dirk05d2ff72015-11-18 23:13:43 +01003893 *magick_restrict p;
cristy3ed852e2009-09-05 21:47:34 +00003894
cristy3a37efd2011-08-28 20:31:03 +00003895 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +00003896 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +00003897 break;
cristy4c08aed2011-07-01 19:47:50 +00003898 length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
cristy3a37efd2011-08-28 20:31:03 +00003899 quantum_type,pixels,exception);
cristy3ed852e2009-09-05 21:47:34 +00003900 if (TIFFWritePixels(tiff,&tiff_info,y,0,image) == -1)
3901 break;
3902 if (image->previous == (Image *) NULL)
3903 {
cristycee97112010-05-28 00:44:52 +00003904 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
3905 image->rows);
cristy3ed852e2009-09-05 21:47:34 +00003906 if (status == MagickFalse)
3907 break;
3908 }
3909 }
3910 break;
3911 }
3912 }
3913 quantum_info=DestroyQuantumInfo(quantum_info);
cristy514da942012-07-06 23:24:14 +00003914 if (image->colorspace == LabColorspace)
3915 DecodeLabImage(image,exception);
cristy3ed852e2009-09-05 21:47:34 +00003916 DestroyTIFFInfo(&tiff_info);
dirk93b02b72013-11-16 16:03:36 +00003917DisableMSCWarning(4127)
cristycd8b3312013-12-22 01:51:11 +00003918 if (0 && (image_info->verbose != MagickFalse))
dirk93b02b72013-11-16 16:03:36 +00003919RestoreMSCWarning
cristy3ed852e2009-09-05 21:47:34 +00003920 TIFFPrintDirectory(tiff,stdout,MagickFalse);
3921 (void) TIFFWriteDirectory(tiff);
cristy3ed852e2009-09-05 21:47:34 +00003922 image=SyncNextImageInList(image);
3923 if (image == (Image *) NULL)
3924 break;
3925 status=SetImageProgress(image,SaveImagesTag,scene++,
3926 GetImageListLength(image));
3927 if (status == MagickFalse)
3928 break;
3929 } while (image_info->adjoin != MagickFalse);
cristy3ed852e2009-09-05 21:47:34 +00003930 TIFFClose(tiff);
3931 return(MagickTrue);
3932}
3933#endif