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