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