/src/graphicsmagick/coders/tiff.c
Line | Count | Source |
1 | | /* |
2 | | % Copyright (C) 2003-2025 GraphicsMagick Group |
3 | | % Copyright (C) 2002 ImageMagick Studio |
4 | | % Copyright 1991-1999 E. I. du Pont de Nemours and Company |
5 | | % |
6 | | % This program is covered by multiple licenses, which are described in |
7 | | % Copyright.txt. You should have received a copy of Copyright.txt with this |
8 | | % package; otherwise see http://www.graphicsmagick.org/www/Copyright.html. |
9 | | % |
10 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
11 | | % % |
12 | | % % |
13 | | % % |
14 | | % TTTTT IIIII FFFFF FFFFF % |
15 | | % T I F F % |
16 | | % T I FFF FFF % |
17 | | % T I F F % |
18 | | % T IIIII F F % |
19 | | % % |
20 | | % % |
21 | | % Read/Write TIFF Image Format. % |
22 | | % % |
23 | | % % |
24 | | % Original Software Design % |
25 | | % John Cristy % |
26 | | % July 1992 % |
27 | | % Re-Written For GraphicsMagick % |
28 | | % Bob Friesenhahn % |
29 | | % 2002-2015 % |
30 | | % Jaroslav Fojtik % |
31 | | % 2023-2024 % |
32 | | % % |
33 | | % % |
34 | | % % |
35 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
36 | | % |
37 | | % |
38 | | */ |
39 | | |
40 | | /* |
41 | | Include declarations. |
42 | | */ |
43 | | #include "magick/studio.h" |
44 | | #include "magick/analyze.h" |
45 | | #include "magick/attribute.h" |
46 | | #include "magick/bit_stream.h" |
47 | | #include "magick/blob.h" |
48 | | #include "magick/colormap.h" |
49 | | #include "magick/constitute.h" |
50 | | #include "magick/log.h" |
51 | | #include "magick/magick.h" |
52 | | #include "magick/monitor.h" |
53 | | #include "magick/pixel_cache.h" |
54 | | #include "magick/profile.h" |
55 | | #include "magick/quantize.h" |
56 | | #include "magick/resize.h" |
57 | | #include "magick/resource.h" |
58 | | #include "magick/tempfile.h" |
59 | | #include "magick/tsd.h" |
60 | | #include "magick/utility.h" |
61 | | #include "magick/version.h" |
62 | | #include "magick/static.h" |
63 | | #if defined(HasTIFF) |
64 | | # if defined(HAVE_TIFFCONF_H) |
65 | | # include "tiffconf.h" |
66 | | # endif |
67 | | # include "tiff.h" |
68 | | # include "tiffio.h" |
69 | | # if !defined(COMPRESSION_ADOBE_DEFLATE) |
70 | | # define COMPRESSION_ADOBE_DEFLATE 8 |
71 | | # endif /* !defined(COMPRESSION_ADOBE_DEFLATE) */ |
72 | | # if defined(COMPRESSION_ZSTD) && defined(HasZSTD) |
73 | | # include "zstd.h" |
74 | | # endif /* if defined(COMPRESSION_ZSTD) && defined(HasZSTD) */ |
75 | | |
76 | | #if !defined(EXPERIMENTAL_EXIF_TAGS) |
77 | | # define EXPERIMENTAL_EXIF_TAGS 1 |
78 | | #endif /* if !defined(EXPERIMENTAL_EXIF_TAGS) */ |
79 | | |
80 | | /* |
81 | | JPEG headers are needed in order to obtain BITS_IN_JSAMPLE |
82 | | */ |
83 | | # if !defined(_VISUALC_) |
84 | | # if defined(HasJPEG) |
85 | | # if defined(__MINGW32__) |
86 | | # define XMD_H 1 |
87 | | # endif |
88 | | # undef HAVE_STDLIB_H |
89 | | # include <jpeglib.h> |
90 | | # endif /* defined(HasJPEG) */ |
91 | | # endif /* !defined(_VISUALC_) */ |
92 | | |
93 | | #if defined(TIFF_VERSION_BIG) |
94 | | # define HasBigTIFF 1 |
95 | | #endif /* defined(TIFF_BIGTIFF_VERSION) */ |
96 | | |
97 | | #if (TIFFLIB_VERSION >= 20201219) |
98 | | # undef uint16 |
99 | 928k | # define uint16 uint16_t |
100 | | # undef uint32 |
101 | 882k | # define uint32 uint32_t |
102 | | #endif /* TIFFLIB_VERSION */ |
103 | | |
104 | | /* |
105 | | Set to 1 in order to log low-level BLOB I/O at "coder" level. |
106 | | */ |
107 | | #if !defined(LOG_TIFF_BLOB_IO) |
108 | | # define LOG_TIFF_BLOB_IO 0 |
109 | | #endif /* !defined(LOG_TIFF_BLOB_IO) */ |
110 | | |
111 | | /* |
112 | | The number of bytes to try to allocate per uncompressed strip by default. |
113 | | This is used to determine the default number of rows per strip. |
114 | | |
115 | | Target that each uncompressed strip is ~1MB. |
116 | | */ |
117 | | #if !defined(TIFF_BYTES_PER_STRIP) |
118 | 23.5k | # define TIFF_BYTES_PER_STRIP 1048576 |
119 | | #endif /* !defined(TIFF_BYTES_PER_STRIP) */ |
120 | | |
121 | | #if !defined(PREDICTOR_NONE) |
122 | | #define PREDICTOR_NONE 1 |
123 | | #endif |
124 | | #if !defined(PREDICTOR_HORIZONTAL) |
125 | | #define PREDICTOR_HORIZONTAL 2 |
126 | | #endif |
127 | | #if !defined(PREDICTOR_FLOATINGPOINT) |
128 | | #define PREDICTOR_FLOATINGPOINT 3 |
129 | | #endif |
130 | | #if !defined(SAMPLEFORMAT_COMPLEXINT) |
131 | | #define SAMPLEFORMAT_COMPLEXINT 5 |
132 | | #endif |
133 | | #if !defined(SAMPLEFORMAT_COMPLEXIEEEFP) |
134 | | #define SAMPLEFORMAT_COMPLEXIEEEFP 6 |
135 | | #endif |
136 | | |
137 | | #if !defined(TIFFTAG_COPYRIGHT) |
138 | | #define TIFFTAG_COPYRIGHT 33432 |
139 | | #endif |
140 | | #if !defined(TIFFTAG_OPIIMAGEID) |
141 | | #define TIFFTAG_OPIIMAGEID 32781 |
142 | | #endif |
143 | | |
144 | | /* |
145 | | Global declarations. |
146 | | */ |
147 | | static MagickTsdKey_t tsd_key = (MagickTsdKey_t) 0; |
148 | | |
149 | | /* static ExceptionInfo */ |
150 | | /* *tiff_exception; */ |
151 | | |
152 | | typedef struct _Magick_TIFF_ClientData |
153 | | { |
154 | | Image |
155 | | *image; |
156 | | |
157 | | const ImageInfo |
158 | | *image_info; |
159 | | } Magick_TIFF_ClientData; |
160 | | |
161 | | /* |
162 | | Forward declarations. |
163 | | */ |
164 | | #if defined(__cplusplus) || defined(c_plusplus) |
165 | | extern "C" { |
166 | | #endif |
167 | | |
168 | | static tsize_t |
169 | | TIFFReadBlob(thandle_t,tdata_t,tsize_t); |
170 | | |
171 | | static MagickPassFail |
172 | | WriteGROUP4RAWImage(const ImageInfo *image_info,Image *image), |
173 | | WritePTIFImage(const ImageInfo *,Image *), |
174 | | WriteTIFFImage(const ImageInfo *,Image *); |
175 | | |
176 | | #if defined(__cplusplus) || defined(c_plusplus) |
177 | | } |
178 | | #endif |
179 | | |
180 | | /* |
181 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
182 | | % % |
183 | | % % |
184 | | % % |
185 | | % I s T I F F % |
186 | | % % |
187 | | % % |
188 | | % % |
189 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
190 | | % |
191 | | % Method IsTIFF returns True if the image format type, identified by the |
192 | | % magick string, is TIFF. |
193 | | % |
194 | | % The format of the IsTIFF method is: |
195 | | % |
196 | | % MagickBool IsTIFF(const unsigned char *magick,const size_t length) |
197 | | % |
198 | | % A description of each parameter follows: |
199 | | % |
200 | | % o status: Method IsTIFF returns MagickTrue if the image format type |
201 | | % is TIFF. |
202 | | % |
203 | | % o magick: This string is generally the first few bytes of an image file |
204 | | % or blob. |
205 | | % |
206 | | % o length: Specifies the length of the magick string. |
207 | | % |
208 | | % |
209 | | */ |
210 | | static MagickBool |
211 | | IsTIFF(const unsigned char *magick,const size_t length) |
212 | 0 | { |
213 | 0 | if (length < 8) |
214 | 0 | return(False); |
215 | | |
216 | | /* Big endian Classic TIFF*/ |
217 | 0 | if (memcmp(magick,"\115\115\000\052",4) == 0) |
218 | 0 | return(True); |
219 | | |
220 | | /* Little endian Classic TIFF */ |
221 | 0 | if (memcmp(magick,"\111\111\052\000",4) == 0) |
222 | 0 | return(True); |
223 | | |
224 | 0 | #if defined(HasBigTIFF) |
225 | | /* |
226 | | * From http://www.remotesensing.org/libtiff/bigtiffdesign.html |
227 | | * |
228 | | * * The Version ID, in header bytes 2-3, formerly decimal 42, now changes to 43 |
229 | | * * Header bytes 4-5 contain the decimal number 8. |
230 | | * - If there is some other number here, a reader should give up. |
231 | | * - This is to provide a nice way to move to 16-byte pointers some day. |
232 | | * |
233 | | * * Header bytes 6-7 are reserved and must be zero. |
234 | | * - If they're not, a reader should give up. |
235 | | * |
236 | | * Also http://www.awaresystems.be/imaging/tiff/bigtiff.html |
237 | | */ |
238 | | |
239 | | /* Big endian BigTIFF*/ |
240 | 0 | if (memcmp(magick,"\115\115\000\053\000\010\000\000",8) == 0) |
241 | 0 | return(True); |
242 | | |
243 | | /* Little endian BigTIFF */ |
244 | 0 | if (memcmp(magick,"\111\111\053\000\010\000\000\000",8) == 0) |
245 | 0 | return(True); |
246 | 0 | #endif |
247 | | |
248 | 0 | return(False); |
249 | 0 | } |
250 | | |
251 | | /* |
252 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
253 | | % % |
254 | | % % |
255 | | % % |
256 | | % R e a d T I F F I m a g e % |
257 | | % % |
258 | | % % |
259 | | % % |
260 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
261 | | % |
262 | | % Method ReadTIFFImage reads a Tagged image file and returns it. It |
263 | | % allocates the memory necessary for the new Image structure and returns a |
264 | | % pointer to the new image. |
265 | | % |
266 | | % The format of the ReadTIFFImage method is: |
267 | | % |
268 | | % Image *ReadTIFFImage(const ImageInfo *image_info, |
269 | | % ExceptionInfo *exception) |
270 | | % |
271 | | % A description of each parameter follows: |
272 | | % |
273 | | % o image: Method ReadTIFFImage returns a pointer to the image after |
274 | | % reading. A null image is returned if there is a memory shortage or |
275 | | % if the image cannot be read. |
276 | | % |
277 | | % o image_info: Specifies a pointer to a ImageInfo structure. |
278 | | % |
279 | | % o exception: return any errors or warnings in this structure. |
280 | | % |
281 | | % |
282 | | */ |
283 | | #if defined(HAVE_TIFFMERGEFIELDINFO) && defined(HAVE_TIFFSETTAGEXTENDER) |
284 | | # define EXTEND_TIFF_TAGS 1 |
285 | | # if !defined(TIFFTAG_EXIFIFD) |
286 | | # define TIFFTAG_EXIFIFD 34665 |
287 | | # endif |
288 | | # if TIFFLIB_VERSION < 20050704 |
289 | | /* It seems that support was added for the EXIFIFDOffset tag in |
290 | | libtiff release 3-7-3 which corresponds with TIFFLIB_VERSION |
291 | | 20050704 */ |
292 | | static const TIFFFieldInfo |
293 | | ExtensionTiffFieldInfo[] = |
294 | | { |
295 | | { |
296 | | TIFFTAG_EXIFIFD, -1, -1, TIFF_LONG, FIELD_CUSTOM, |
297 | | MagickFalse, MagickTrue, "EXIFIFDOffset" |
298 | | } |
299 | | }; |
300 | | # endif |
301 | | |
302 | | /* |
303 | | Ignore specific tags |
304 | | */ |
305 | | static void |
306 | | TIFFIgnoreTags(TIFF *tiff) |
307 | 751k | { |
308 | 751k | char |
309 | 751k | *q; |
310 | | |
311 | 751k | const char |
312 | 751k | *p, |
313 | 751k | *tags; |
314 | | |
315 | 751k | Magick_TIFF_ClientData |
316 | 751k | *client_data; |
317 | | |
318 | 751k | register ssize_t |
319 | 751k | i; |
320 | | |
321 | 751k | size_t |
322 | 751k | count; |
323 | | |
324 | 751k | TIFFFieldInfo |
325 | 751k | *ignore; |
326 | | |
327 | 751k | if (TIFFGetReadProc(tiff) != TIFFReadBlob) |
328 | 1.50k | return; |
329 | | |
330 | 750k | client_data=((Magick_TIFF_ClientData *) TIFFClientdata(tiff)); |
331 | 750k | if (client_data == (Magick_TIFF_ClientData *) NULL) |
332 | 0 | return; |
333 | 750k | tags=AccessDefinition(client_data->image_info,"tiff","ignore-tags"); |
334 | 750k | if (tags == (const char *) NULL) |
335 | 750k | return; |
336 | 0 | count=0; |
337 | 0 | p=tags; |
338 | 0 | while (*p != '\0') |
339 | 0 | { |
340 | 0 | while ((isspace((int) ((unsigned char) *p)) != 0)) |
341 | 0 | p++; |
342 | |
|
343 | 0 | { |
344 | 0 | (void) strtol(p,&q,10); |
345 | 0 | } |
346 | 0 | if (p == q) |
347 | 0 | return; |
348 | | |
349 | 0 | p=q; |
350 | 0 | count++; |
351 | |
|
352 | 0 | while ((isspace((int) ((unsigned char) *p)) != 0) || (*p == ',')) |
353 | 0 | p++; |
354 | 0 | } |
355 | 0 | if (count == 0) |
356 | 0 | return; |
357 | 0 | i=0; |
358 | 0 | p=tags; |
359 | 0 | ignore=MagickAllocateResourceLimitedArray(TIFFFieldInfo*,count,sizeof(*ignore)); |
360 | 0 | if (ignore == (TIFFFieldInfo*) NULL) |
361 | 0 | { |
362 | 0 | ThrowException(&client_data->image->exception,ResourceLimitError, |
363 | 0 | MemoryAllocationFailed,client_data->image->filename); |
364 | 0 | return; |
365 | 0 | } |
366 | | /* This also sets field_bit to 0 (FIELD_IGNORE) */ |
367 | 0 | (void) memset(ignore,0,count*sizeof(*ignore)); |
368 | 0 | while (*p != '\0') |
369 | 0 | { |
370 | 0 | while ((isspace((int) ((unsigned char) *p)) != 0)) |
371 | 0 | p++; |
372 | |
|
373 | 0 | ignore[i].field_tag=(ttag_t) strtol(p,&q,10); |
374 | |
|
375 | 0 | p=q; |
376 | 0 | i++; |
377 | |
|
378 | 0 | while ((isspace((int) ((unsigned char) *p)) != 0) || (*p == ',')) |
379 | 0 | p++; |
380 | 0 | } |
381 | 0 | (void) TIFFMergeFieldInfo(tiff,ignore,(uint32) count); |
382 | 0 | MagickFreeResourceLimitedMemory(TIFFFieldInfo*,ignore); |
383 | 0 | } |
384 | | |
385 | | /* |
386 | | Merge in our new fields and then call the next extender if there is |
387 | | one in effect. |
388 | | */ |
389 | | static TIFFExtendProc _ParentExtender = NULL; |
390 | | static void |
391 | | ExtensionTagsDefaultDirectory(TIFF *tif) |
392 | 751k | { |
393 | | # if TIFFLIB_VERSION < 20050704 |
394 | | /* Install the extended Tag field info */ |
395 | | TIFFMergeFieldInfo(tif, ExtensionTiffFieldInfo, |
396 | | sizeof(ExtensionTiffFieldInfo)/ |
397 | | sizeof(ExtensionTiffFieldInfo[0])); |
398 | | # endif |
399 | | |
400 | | /* Since an XTIFF client module may have overridden |
401 | | * the default directory method, we call it now to |
402 | | * allow it to set up the rest of its own methods. |
403 | | */ |
404 | 751k | if (_ParentExtender) |
405 | 0 | (*_ParentExtender)(tif); |
406 | 751k | TIFFIgnoreTags(tif); |
407 | 751k | } |
408 | | |
409 | | /* |
410 | | Obtain the current handler at the front of the chain, and register |
411 | | ourselves as the new first handler. |
412 | | */ |
413 | | static |
414 | | void ExtensionTagsInitialize(void) |
415 | 8 | { |
416 | 8 | static int |
417 | 8 | not_first_time=0; |
418 | | |
419 | 8 | if (not_first_time) return; /* Been there. Done that. */ |
420 | 8 | not_first_time = 1; |
421 | | |
422 | | /* Grab the inherited method and install */ |
423 | 8 | _ParentExtender = TIFFSetTagExtender(ExtensionTagsDefaultDirectory); |
424 | 8 | } |
425 | | |
426 | | #endif /* defined(HAVE_TIFFMERGEFIELDINFO) && defined(HAVE_TIFFSETTAGEXTENDER) */ |
427 | | |
428 | | /* |
429 | | Return MagickTrue if libtiff supports the indicated compression type. |
430 | | Sets buffer pointed to by 'compression_name' to the name of the compression. |
431 | | */ |
432 | | static MagickBool |
433 | | CompressionSupported(const CompressionType compression, |
434 | | char *compression_name) |
435 | 28.4k | { |
436 | 28.4k | uint16 |
437 | 28.4k | compress_tag; |
438 | | |
439 | 28.4k | MagickBool |
440 | 28.4k | status; |
441 | | |
442 | 28.4k | status = MagickFalse; |
443 | 28.4k | compress_tag=COMPRESSION_NONE; |
444 | 28.4k | strlcpy(compression_name,"Undefined",MaxTextExtent); |
445 | | |
446 | | /* |
447 | | This switch statement should match all the values of CompressionType. |
448 | | */ |
449 | 28.4k | switch (compression) |
450 | 28.4k | { |
451 | 0 | case UndefinedCompression: |
452 | 0 | { |
453 | 0 | strlcpy(compression_name,"Undefined",MaxTextExtent); |
454 | 0 | break; |
455 | 0 | } |
456 | 12.0k | case NoCompression: |
457 | 12.0k | { |
458 | 12.0k | strlcpy(compression_name,"No",MaxTextExtent); |
459 | 12.0k | compress_tag=COMPRESSION_NONE; |
460 | 12.0k | status=MagickTrue; |
461 | 12.0k | break; |
462 | 0 | } |
463 | 0 | case BZipCompression: |
464 | 0 | { |
465 | 0 | strlcpy(compression_name,"BZip",MaxTextExtent); |
466 | 0 | break; |
467 | 0 | } |
468 | 1.24k | case FaxCompression: |
469 | 1.24k | { |
470 | 1.24k | strlcpy(compression_name,"Group3 FAX",MaxTextExtent); |
471 | 1.24k | #if defined(COMPRESSION_CCITTFAX3) |
472 | 1.24k | compress_tag=COMPRESSION_CCITTFAX3; |
473 | 1.24k | status=MagickTrue; |
474 | 1.24k | #endif |
475 | 1.24k | break; |
476 | 0 | } |
477 | 3.59k | case Group4Compression: |
478 | 3.59k | { |
479 | 3.59k | strlcpy(compression_name,"Group4 FAX",MaxTextExtent); |
480 | 3.59k | #if defined(COMPRESSION_CCITTFAX4) |
481 | 3.59k | compress_tag=COMPRESSION_CCITTFAX4; |
482 | 3.59k | status=MagickTrue; |
483 | 3.59k | #endif |
484 | 3.59k | break; |
485 | 0 | } |
486 | 0 | case JBIG1Compression: |
487 | 0 | { |
488 | 0 | strlcpy(compression_name,"JBIG",MaxTextExtent); |
489 | 0 | #if defined(COMPRESSION_JBIG) |
490 | 0 | compress_tag=COMPRESSION_JBIG; |
491 | 0 | status=MagickTrue; |
492 | 0 | #endif |
493 | 0 | break; |
494 | 0 | } |
495 | 0 | case JBIG2Compression: |
496 | 0 | { |
497 | 0 | strlcpy(compression_name,"JBIG2",MaxTextExtent); |
498 | 0 | break; |
499 | 0 | } |
500 | 5.35k | case JPEGCompression: |
501 | 5.35k | { |
502 | 5.35k | strlcpy(compression_name,"JPEG",MaxTextExtent); |
503 | 5.35k | #if defined(COMPRESSION_JPEG) |
504 | 5.35k | compress_tag=COMPRESSION_JPEG; |
505 | 5.35k | status=MagickTrue; |
506 | 5.35k | #endif |
507 | 5.35k | break; |
508 | 0 | } |
509 | 0 | case JPEG2000Compression: |
510 | 0 | { |
511 | 0 | strlcpy(compression_name,"JPEG2000",MaxTextExtent); |
512 | 0 | break; |
513 | 0 | } |
514 | 0 | case LosslessJPEGCompression: |
515 | 0 | { |
516 | 0 | strlcpy(compression_name,"Lossless JPEG",MaxTextExtent); |
517 | 0 | break; |
518 | 0 | } |
519 | 0 | case LZMACompression: |
520 | 0 | { |
521 | 0 | strlcpy(compression_name,"LZMA",MaxTextExtent); |
522 | 0 | #if defined(COMPRESSION_LZMA) |
523 | 0 | compress_tag=COMPRESSION_LZMA; |
524 | 0 | status=MagickTrue; |
525 | 0 | #endif |
526 | 0 | break; |
527 | 0 | } |
528 | 810 | case LZWCompression: |
529 | 810 | { |
530 | 810 | strlcpy(compression_name,"LZW",MaxTextExtent); |
531 | 810 | #if defined(COMPRESSION_LZW) |
532 | 810 | compress_tag=COMPRESSION_LZW; |
533 | 810 | status=MagickTrue; |
534 | 810 | #endif |
535 | 810 | break; |
536 | 0 | } |
537 | 0 | case RLECompression: |
538 | 0 | { |
539 | 0 | strlcpy(compression_name,"Macintosh RLE (Packbits)",MaxTextExtent); |
540 | 0 | #if defined(COMPRESSION_PACKBITS) |
541 | 0 | compress_tag=COMPRESSION_PACKBITS; |
542 | 0 | status=MagickTrue; |
543 | 0 | #endif |
544 | 0 | break; |
545 | 0 | } |
546 | 2.30k | case WebPCompression: |
547 | 2.30k | { |
548 | 2.30k | strlcpy(compression_name,"WebP",MaxTextExtent); |
549 | 2.30k | #if defined(COMPRESSION_WEBP) |
550 | 2.30k | compress_tag=COMPRESSION_WEBP; |
551 | 2.30k | status=MagickTrue; |
552 | 2.30k | #endif |
553 | 2.30k | break; |
554 | 0 | } |
555 | 1.75k | case ZipCompression: |
556 | 1.75k | { |
557 | 1.75k | strlcpy(compression_name,"Adobe Deflate",MaxTextExtent); |
558 | 1.75k | #if defined(COMPRESSION_ADOBE_DEFLATE) |
559 | 1.75k | compress_tag=COMPRESSION_ADOBE_DEFLATE; |
560 | 1.75k | status=MagickTrue; |
561 | 1.75k | #endif |
562 | 1.75k | break; |
563 | 0 | } |
564 | 1.32k | case ZSTDCompression: |
565 | 1.32k | { |
566 | 1.32k | strlcpy(compression_name,"Zstandard",MaxTextExtent); |
567 | 1.32k | #if defined(COMPRESSION_ZSTD) |
568 | 1.32k | compress_tag=COMPRESSION_ZSTD; |
569 | 1.32k | status=MagickTrue; |
570 | 1.32k | #endif |
571 | 1.32k | break; |
572 | 0 | } |
573 | 28.4k | } |
574 | | |
575 | 28.4k | if (MagickTrue == status) |
576 | 28.4k | { |
577 | 28.4k | #if defined(HAVE_TIFFISCODECCONFIGURED) || (TIFFLIB_VERSION > 20040919) |
578 | 28.4k | if (compress_tag != COMPRESSION_NONE) |
579 | 16.3k | { |
580 | | /* |
581 | | Returns 1 if the codec is configured and |
582 | | working. Otherwise 0 will be returned. |
583 | | */ |
584 | 16.3k | if (!TIFFIsCODECConfigured(compress_tag)) |
585 | 0 | status = MagickFalse; |
586 | 16.3k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
587 | 16.3k | "TIFFIsCODECConfigured says support for %s " |
588 | 16.3k | "compression %s configured.", |
589 | 16.3k | compression_name, |
590 | 16.3k | (status == MagickTrue ? "is" : "is not")); |
591 | 16.3k | } |
592 | | #else |
593 | | switch (compress_tag) |
594 | | { |
595 | | # if defined(CCITT_SUPPORT) |
596 | | case COMPRESSION_CCITTFAX3: |
597 | | case COMPRESSION_CCITTFAX4: |
598 | | # endif |
599 | | # if defined(YCBCR_SUPPORT) && defined(JPEG_SUPPORT) |
600 | | case COMPRESSION_JPEG: |
601 | | # endif |
602 | | # if defined(LZW_SUPPORT) |
603 | | case COMPRESSION_LZW: |
604 | | # endif |
605 | | # if defined(PACKBITS_SUPPORT) |
606 | | case COMPRESSION_PACKBITS: |
607 | | # endif |
608 | | # if defined(ZIP_SUPPORT) |
609 | | case COMPRESSION_ADOBE_DEFLATE: |
610 | | # endif |
611 | | case COMPRESSION_NONE: |
612 | | { |
613 | | status = MagickTrue; |
614 | | break; |
615 | | } |
616 | | default: |
617 | | { |
618 | | status = MagickFalse; |
619 | | break; |
620 | | } |
621 | | } |
622 | | #endif |
623 | 28.4k | } |
624 | 28.4k | return status; |
625 | 28.4k | } |
626 | | |
627 | | /* |
628 | | Convert a libtiff compression tag to a human readable string. |
629 | | */ |
630 | | static const char * |
631 | | CompressionTagToString(unsigned int compress_tag) |
632 | 76 | { |
633 | 76 | const char |
634 | 76 | *result = "Unknown"; |
635 | | |
636 | 76 | switch (compress_tag) |
637 | 76 | { |
638 | 0 | case COMPRESSION_ADOBE_DEFLATE: |
639 | 0 | result="ZIP deflate (Adobe)"; |
640 | 0 | break; |
641 | 0 | #if defined(COMPRESSION_DEFLATE) |
642 | 0 | case COMPRESSION_DEFLATE: |
643 | 0 | result="ZIP deflate (Pixar)"; |
644 | 0 | break; |
645 | 0 | #endif |
646 | 25 | case COMPRESSION_CCITTFAX3: |
647 | 25 | result="CCITT Group 3 fax"; |
648 | 25 | break; |
649 | 27 | case COMPRESSION_CCITTFAX4: |
650 | 27 | result="CCITT Group 4 fax"; |
651 | 27 | break; |
652 | 0 | case COMPRESSION_CCITTRLE: |
653 | 0 | result="CCITT modified Huffman RLE"; |
654 | 0 | break; |
655 | 0 | case COMPRESSION_CCITTRLEW: |
656 | 0 | result="CCITT modified Huffman RLE (Word aligned)"; |
657 | 0 | break; |
658 | 0 | #if defined(COMPRESSION_OJPEG) |
659 | 0 | case COMPRESSION_OJPEG: |
660 | 0 | result="JPEG DCT (Old)"; |
661 | 0 | break; |
662 | 0 | #endif |
663 | 0 | case COMPRESSION_JPEG: |
664 | 0 | result="JPEG DCT"; |
665 | 0 | break; |
666 | 0 | #if defined(COMPRESSION_JBIG) |
667 | 0 | case COMPRESSION_JBIG: |
668 | 0 | result="JBIG"; |
669 | 0 | break; |
670 | 0 | #endif |
671 | 0 | case COMPRESSION_LZW: |
672 | 0 | result="LZW"; |
673 | 0 | break; |
674 | 0 | #if defined(COMPRESSION_NEXT) |
675 | 0 | case COMPRESSION_NEXT: |
676 | 0 | result="NeXT 2-bit RLE"; |
677 | 0 | break; |
678 | 0 | #endif |
679 | 0 | case COMPRESSION_NONE: |
680 | 0 | result="not compressed"; |
681 | 0 | break; |
682 | 0 | case COMPRESSION_PACKBITS: |
683 | 0 | result="Macintosh RLE (Packbits)"; |
684 | 0 | break; |
685 | 0 | #if defined(COMPRESSION_THUNDERSCAN) |
686 | 0 | case COMPRESSION_THUNDERSCAN: |
687 | 0 | result="ThunderScan RLE"; |
688 | 0 | break; |
689 | 0 | #endif |
690 | 0 | #if defined(COMPRESSION_LZMA) |
691 | 0 | case COMPRESSION_LZMA: |
692 | 0 | result="LZMA"; |
693 | 0 | break; |
694 | 0 | #endif |
695 | 0 | #if defined(COMPRESSION_ZSTD) |
696 | 0 | case COMPRESSION_ZSTD: |
697 | 0 | result="Zstandard"; |
698 | 0 | break; |
699 | 0 | #endif |
700 | 0 | #if defined(COMPRESSION_WEBP) |
701 | 24 | case COMPRESSION_WEBP: |
702 | 24 | result="WebP"; |
703 | 24 | break; |
704 | 76 | #endif |
705 | 76 | } |
706 | 76 | return result; |
707 | 76 | } |
708 | | |
709 | | static const char * |
710 | | PhotometricTagToString(unsigned int photometric) |
711 | 1.18k | { |
712 | 1.18k | const char |
713 | 1.18k | *result = "Unknown"; |
714 | | |
715 | 1.18k | switch (photometric) |
716 | 1.18k | { |
717 | 0 | case PHOTOMETRIC_CIELAB: |
718 | 0 | result="CIELAB"; |
719 | 0 | break; |
720 | 0 | case PHOTOMETRIC_LOGL: |
721 | 0 | result="CIE Log2(L)"; |
722 | 0 | break; |
723 | 0 | case PHOTOMETRIC_LOGLUV: |
724 | 0 | result="LOGLUV"; |
725 | 0 | break; |
726 | 0 | #if defined(PHOTOMETRIC_MASK) |
727 | 0 | case PHOTOMETRIC_MASK: |
728 | 0 | result="MASK"; |
729 | 0 | break; |
730 | 0 | #endif |
731 | 294 | case PHOTOMETRIC_MINISBLACK: |
732 | 294 | result="MINISBLACK"; |
733 | 294 | break; |
734 | 84 | case PHOTOMETRIC_MINISWHITE: |
735 | 84 | result="MINISWHITE"; |
736 | 84 | break; |
737 | 0 | case PHOTOMETRIC_PALETTE: |
738 | 0 | result="PALETTE"; |
739 | 0 | break; |
740 | 811 | case PHOTOMETRIC_RGB: |
741 | 811 | result="RGB"; |
742 | 811 | break; |
743 | 0 | case PHOTOMETRIC_SEPARATED: |
744 | 0 | result="SEPARATED"; |
745 | 0 | break; |
746 | 0 | case PHOTOMETRIC_YCBCR: |
747 | 0 | result="YCBCR"; |
748 | 0 | break; |
749 | 1.18k | } |
750 | | |
751 | 1.18k | return result; |
752 | 1.18k | } |
753 | | |
754 | | static const char *ExtraSampleToString(const unsigned int sample_info) |
755 | 1.34M | { |
756 | 1.34M | const char |
757 | 1.34M | *result = "Unknown"; |
758 | | |
759 | 1.34M | switch (sample_info) |
760 | 1.34M | { |
761 | 1.34M | case EXTRASAMPLE_UNSPECIFIED: |
762 | 1.34M | result="Unspecified data"; |
763 | 1.34M | break; |
764 | 2.41k | case EXTRASAMPLE_ASSOCALPHA: |
765 | 2.41k | result="Associated alpha data (with pre-multiplied color)"; |
766 | 2.41k | break; |
767 | 2.46k | case EXTRASAMPLE_UNASSALPHA: |
768 | 2.46k | result="Unassociated alpha data"; |
769 | 2.46k | break; |
770 | 1.34M | } |
771 | | |
772 | 1.34M | return result; |
773 | 1.34M | } |
774 | | |
775 | | /* |
776 | | Locate and store Photoshop or IPTC profiles. |
777 | | |
778 | | Arguments: |
779 | | |
780 | | text - Pointer to octet buffer |
781 | | length - Number of bytes or 32-bit words in buffer |
782 | | image - Image to store into |
783 | | type - TIFF tag (TIFFTAG_PHOTOSHOP or TIFFTAG_RICHTIFFIPTC) |
784 | | |
785 | | If the tag is TIFFTAG_RICHTIFFIPTC then it appears that the length |
786 | | represents the number of 32-bit words. If the tag is |
787 | | TIFFTAG_PHOTOSHOP then the length is in bytes, but the underlying |
788 | | data is stored in units of 16-bit words. |
789 | | */ |
790 | 26.5k | #define NEWSP_REMAINING(base_p,current_p,length) ((ssize_t) length-(current_p-base_p)) |
791 | | static unsigned int |
792 | | ReadNewsProfile(const unsigned char *text,const size_t length,Image *image,const int type) |
793 | 112 | { |
794 | 112 | register const unsigned char |
795 | 112 | *p; |
796 | | |
797 | | #if defined(GET_ONLY_IPTC_DATA) |
798 | | static const char tag_header [] = "8BIM44"; |
799 | | #else |
800 | 112 | static const char tag_header [] = "8BIM"; |
801 | 112 | #endif |
802 | | |
803 | 112 | MagickBool found_header=MagickFalse; |
804 | | |
805 | 112 | if ((length == 0) || ((ssize_t) length < 0)) |
806 | 3 | return MagickFail; |
807 | | |
808 | 109 | p=(unsigned char *) text; |
809 | 109 | if (type == TIFFTAG_RICHTIFFIPTC) |
810 | 0 | { |
811 | | /* |
812 | | Handle IPTC tag (length is number of 32-bit words). |
813 | | */ |
814 | 0 | return SetImageProfile(image,"IPTC",p,(size_t) length*4U); |
815 | 0 | } |
816 | | /* |
817 | | Handle PHOTOSHOP tag (length is in bytes, but data is organized as |
818 | | array of 16-bit values. |
819 | | */ |
820 | 26.4k | while (NEWSP_REMAINING(text,p,length) > (ssize_t) sizeof(tag_header)) |
821 | 26.4k | { |
822 | 26.4k | if (LocaleNCompare((char *) p,tag_header,sizeof(tag_header)-1) == 0) |
823 | 88 | { |
824 | 88 | found_header=MagickTrue; |
825 | 88 | break; |
826 | 88 | } |
827 | 26.3k | p+=2; |
828 | 26.3k | } |
829 | 109 | if (!found_header) |
830 | 21 | { |
831 | 21 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
832 | 21 | "Failed to find %s header, ignoring profile.", |
833 | 21 | tag_header); |
834 | 21 | return MagickFail; |
835 | 21 | } |
836 | | #if defined(GET_ONLY_IPTC_DATA) |
837 | | /* |
838 | | Eat OSType, IPTC ID code, and Pascal string length bytes. |
839 | | */ |
840 | | do |
841 | | { |
842 | | magick_uint32_t |
843 | | hdr_length; |
844 | | |
845 | | p+=sizeof(tag_header)-1; |
846 | | if (NEWSP_REMAINING(text,p,length) < 8) |
847 | | { |
848 | | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
849 | | "Truncated profile: %" MAGICK_SIZE_T_F "u" |
850 | | " bytes, %" MAGICK_SSIZE_T_F "u remaining" |
851 | | ", ignoring profile.", |
852 | | (MAGICK_SIZE_T) length, |
853 | | (MAGICK_SSIZE_T) NEWSP_REMAINING(text,p,length)); |
854 | | break; |
855 | | } |
856 | | hdr_length=(*p++); |
857 | | p+=hdr_length; |
858 | | if (NEWSP_REMAINING(text,p,length) < 8) |
859 | | { |
860 | | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
861 | | "Truncated profile: %" MAGICK_SIZE_T_F "u" |
862 | | " bytes, %" MAGICK_SSIZE_T_F "u remaining" |
863 | | ", ignoring profile.", |
864 | | (MAGICK_SIZE_T) length, |
865 | | (MAGICK_SSIZE_T) NEWSP_REMAINING(text,p,length)); |
866 | | break; |
867 | | } |
868 | | if ((hdr_length & 0x01) == 0) |
869 | | p++; /* align to an even byte boundary */ |
870 | | hdr_length=(p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; |
871 | | p+=4; |
872 | | if (((ssize_t) hdr_length <= 0) || |
873 | | ((ssize_t) hdr_length > NEWSP_REMAINING(text,p,length))) |
874 | | { |
875 | | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
876 | | "Truncated profile: %" MAGICK_SIZE_T_F "u" |
877 | | " bytes, %" MAGICK_SSIZE_T_F "u " |
878 | | "remaining (need %u more bytes)" |
879 | | ", ignoring profile.", |
880 | | (MAGICK_SIZE_T) length, |
881 | | (MAGICK_SSIZE_T) NEWSP_REMAINING(text,p,length), |
882 | | hdr_length); |
883 | | return MagickFail; |
884 | | } |
885 | | return SetImageProfile(image,"8BIM",p,hdr_length); |
886 | | } while (0); |
887 | | return MagickFail; |
888 | | #else |
889 | 88 | return SetImageProfile(image,"8BIM",p,(size_t) NEWSP_REMAINING(text,p,length)); |
890 | 109 | #endif |
891 | 109 | } |
892 | | |
893 | | /* |
894 | | Return MagickTrue if TIFF warnings should be thrown as a warning |
895 | | exception rather than logged. |
896 | | */ |
897 | | static MagickBool |
898 | | CheckThrowWarnings(const ImageInfo *image_info) |
899 | 1.64M | { |
900 | 1.64M | const char * |
901 | 1.64M | definition_value; |
902 | | |
903 | 1.64M | MagickBool |
904 | 1.64M | report_warnings=MagickFalse; |
905 | | |
906 | 1.64M | if ((definition_value=AccessDefinition(image_info,"tiff","report-warnings"))) |
907 | 0 | { |
908 | 0 | if (LocaleCompare(definition_value,"TRUE") == 0) |
909 | 0 | report_warnings=MagickTrue; |
910 | 0 | } |
911 | | |
912 | 1.64M | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
913 | 1.64M | "Reporting TIFF warnings via %s", |
914 | 1.64M | (report_warnings ? "exception" : |
915 | 1.64M | "log message")); |
916 | | |
917 | 1.64M | return report_warnings; |
918 | 1.64M | } |
919 | | |
920 | | |
921 | | #if defined(__cplusplus) || defined(c_plusplus) |
922 | | extern "C" { |
923 | | #endif |
924 | | |
925 | | /* Close BLOB */ |
926 | | static int |
927 | | TIFFCloseBlob(thandle_t image_handle) |
928 | 109k | { |
929 | 109k | Image |
930 | 109k | *image = ((Magick_TIFF_ClientData *) image_handle)->image; |
931 | | |
932 | 109k | int |
933 | 109k | status = MagickPass; |
934 | | |
935 | | #if LOG_TIFF_BLOB_IO |
936 | | if (image->logging) |
937 | | (void) LogMagickEvent(CoderEvent,GetMagickModule(),"TIFF close blob"); |
938 | | #endif /* LOG_TIFF_BLOB_IO */ |
939 | 109k | while (image->previous != (Image *) NULL) |
940 | 0 | image=image->previous; |
941 | 109k | status &= CloseBlob(image); |
942 | 109k | return(status); |
943 | 109k | } |
944 | | |
945 | | /* Report errors. */ |
946 | | static void |
947 | | TIFFReadErrorsHandler(const char *module,const char *format, |
948 | | va_list warning) |
949 | | MAGICK_FUNC_PRINTF_FORMAT(2,0); |
950 | | #if defined(HAVE_TIFFERROREXTR) |
951 | | static int |
952 | | TIFFReadErrorsHandlerExtR(TIFF *tif, void *user_data, |
953 | | const char *module, const char *format, va_list warning) |
954 | | MAGICK_FUNC_PRINTF_FORMAT(4,0); |
955 | | #endif /* if defined(HAVE_TIFFERROREXTR) */ |
956 | | static void |
957 | | TIFFWriteErrorsHandler(const char *module,const char *format, |
958 | | va_list warning) MAGICK_FUNC_PRINTF_FORMAT(2,0); |
959 | | #if defined(HAVE_TIFFERROREXTR) |
960 | | static int |
961 | | TIFFWriteErrorsHandlerExtR(TIFF *tif, void *user_data, |
962 | | const char *module, const char *format, va_list warning) |
963 | | MAGICK_FUNC_PRINTF_FORMAT(4,0); |
964 | | #endif /* if defined(HAVE_TIFFERROREXTR) */ |
965 | | static void |
966 | | TIFFReadErrorsHandler(const char *module,const char *format, |
967 | | va_list warning) |
968 | 0 | { |
969 | 0 | ExceptionInfo |
970 | 0 | *tiff_exception; |
971 | |
|
972 | 0 | char |
973 | 0 | message[MaxTextExtent]; |
974 | |
|
975 | 0 | errno=0; |
976 | 0 | (void) vsnprintf(message,MaxTextExtent-2,format,warning); |
977 | 0 | message[MaxTextExtent-2]='\0'; |
978 | 0 | #define UNKNOWN_TAG_ERROR "Internal error, unknown tag" |
979 | 0 | if (LocaleNCompare(message,UNKNOWN_TAG_ERROR,sizeof(UNKNOWN_TAG_ERROR)-1) == 0) |
980 | 0 | return; |
981 | 0 | (void) strlcat(message,".",MaxTextExtent); |
982 | 0 | tiff_exception=(ExceptionInfo *) MagickTsdGetSpecific(tsd_key); |
983 | 0 | ThrowException2(tiff_exception,CorruptImageError,message,module); |
984 | 0 | } |
985 | | |
986 | | #if defined(HAVE_TIFFERROREXTR) |
987 | | static int TIFFReadErrorsHandlerExtR(TIFF *tif, void *user_data, |
988 | | const char *module, const char *format, |
989 | | va_list warning) |
990 | 3.37M | { |
991 | 3.37M | ExceptionInfo |
992 | 3.37M | *tiff_exception; |
993 | | |
994 | 3.37M | char |
995 | 3.37M | message[MaxTextExtent]; |
996 | | |
997 | 3.37M | (void) tif; |
998 | 3.37M | errno=0; |
999 | 3.37M | (void) vsnprintf(message,MaxTextExtent-2,format,warning); |
1000 | 3.37M | message[MaxTextExtent-2]='\0'; |
1001 | 6.74M | #define UNKNOWN_TAG_ERROR "Internal error, unknown tag" |
1002 | 3.37M | if (LocaleNCompare(message,UNKNOWN_TAG_ERROR,sizeof(UNKNOWN_TAG_ERROR)-1) == 0) |
1003 | 0 | return 0; |
1004 | 3.37M | (void) strlcat(message,".",MaxTextExtent); |
1005 | 3.37M | tiff_exception=(ExceptionInfo *) user_data; |
1006 | 3.37M | ThrowException2(tiff_exception,CorruptImageError,message,module); |
1007 | | /* |
1008 | | 0: both functions TIFFErrorHandler() and TIFFErrorHandlerExt() are called. |
1009 | | non-zero: no further error message function is called. |
1010 | | */ |
1011 | 3.37M | return 1; |
1012 | 3.37M | } |
1013 | | #endif /* if defined(HAVE_TIFFERROREXTR) */ |
1014 | | |
1015 | | static void |
1016 | | TIFFWriteErrorsHandler(const char *module,const char *format, |
1017 | | va_list warning) |
1018 | 44 | { |
1019 | 44 | ExceptionInfo |
1020 | 44 | *tiff_exception; |
1021 | | |
1022 | 44 | char |
1023 | 44 | message[MaxTextExtent]; |
1024 | | |
1025 | 44 | errno=0; |
1026 | 44 | (void) vsnprintf(message,MaxTextExtent-2,format,warning); |
1027 | 44 | message[MaxTextExtent-2]='\0'; |
1028 | 44 | (void) strlcat(message,".",MaxTextExtent); |
1029 | 44 | tiff_exception=(ExceptionInfo *) MagickTsdGetSpecific(tsd_key); |
1030 | 44 | ThrowException2(tiff_exception,CoderError,message,module); |
1031 | 44 | } |
1032 | | |
1033 | | #if defined(HAVE_TIFFERROREXTR) |
1034 | | static int |
1035 | | TIFFWriteErrorsHandlerExtR(TIFF *tif, void *user_data, |
1036 | | const char *module, const char *format, va_list warning) |
1037 | 204 | { |
1038 | 204 | ExceptionInfo |
1039 | 204 | *tiff_exception; |
1040 | | |
1041 | 204 | char |
1042 | 204 | message[MaxTextExtent]; |
1043 | | |
1044 | 204 | (void) tif; |
1045 | 204 | errno=0; |
1046 | 204 | (void) vsnprintf(message,MaxTextExtent-2,format,warning); |
1047 | 204 | message[MaxTextExtent-2]='\0'; |
1048 | 204 | (void) strlcat(message,".",MaxTextExtent); |
1049 | 204 | tiff_exception=(ExceptionInfo *) user_data; |
1050 | 204 | ThrowException2(tiff_exception,CoderError,message,module); |
1051 | | |
1052 | | /* |
1053 | | 0: both functions TIFFWarningHandler() and TIFFWarningHandlerExt() are called. |
1054 | | non-zero: no further warning message function is called. |
1055 | | */ |
1056 | 204 | return 1; |
1057 | 204 | } |
1058 | | #endif /* if defined(HAVE_TIFFERROREXTR) */ |
1059 | | |
1060 | | /* Memory map entire input file in read-only mode. */ |
1061 | | static int |
1062 | | TIFFMapBlob(thandle_t image_handle,tdata_t *base,toff_t *size) |
1063 | 807k | { |
1064 | 807k | Image |
1065 | 807k | *image = ((Magick_TIFF_ClientData *) image_handle)->image; |
1066 | | |
1067 | 807k | *base = (tdata_t *) GetBlobStreamData(image); |
1068 | 807k | if (*base) |
1069 | 805k | *size = (toff_t) GetBlobSize(image); |
1070 | | |
1071 | 807k | if (*base) |
1072 | 805k | { |
1073 | | #if LOG_TIFF_BLOB_IO |
1074 | | if (image->logging) |
1075 | | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1076 | | "TIFF mapped blob: base=0x%p size=%" MAGICK_OFF_F |
1077 | | "d",*base, (magick_off_t) *size); |
1078 | | #endif |
1079 | 805k | return 1; |
1080 | 805k | } |
1081 | 2.21k | return(0); |
1082 | 807k | } |
1083 | | |
1084 | | /* Read BLOB data at current offset */ |
1085 | | static tsize_t |
1086 | | TIFFReadBlob(thandle_t image_handle,tdata_t data,tsize_t size) |
1087 | 2.19M | { |
1088 | 2.19M | Image |
1089 | 2.19M | *image = ((Magick_TIFF_ClientData *) image_handle)->image; |
1090 | | |
1091 | 2.19M | tsize_t |
1092 | 2.19M | result; |
1093 | | |
1094 | 2.19M | result=(tsize_t) ReadBlob(image,(size_t) size,data); |
1095 | | |
1096 | | #if LOG_TIFF_BLOB_IO |
1097 | | if (image->logging) |
1098 | | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1099 | | "TIFF read blob: data=0x%p size=" |
1100 | | "%" MAGICK_SIZE_T_F "u, returns " |
1101 | | "%" MAGICK_SIZE_T_F "u", |
1102 | | data, (MAGICK_SIZE_T) size, |
1103 | | (MAGICK_SIZE_T) result); |
1104 | | #endif /* LOG_TIFF_BLOB_IO */ |
1105 | | |
1106 | 2.19M | return result; |
1107 | 2.19M | } |
1108 | | |
1109 | | /* Seek to BLOB offset */ |
1110 | | static toff_t |
1111 | | TIFFSeekBlob(thandle_t image_handle,toff_t offset,int whence) |
1112 | 1.45M | { |
1113 | 1.45M | Image |
1114 | 1.45M | *image = ((Magick_TIFF_ClientData *) image_handle)->image; |
1115 | | |
1116 | 1.45M | toff_t |
1117 | 1.45M | result; |
1118 | | |
1119 | 1.45M | result=SeekBlob(image,offset,whence); |
1120 | | #if LOG_TIFF_BLOB_IO |
1121 | | if (image->logging) |
1122 | | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1123 | | "TIFF seek blob: offset=%" MAGICK_OFF_F |
1124 | | "u whence=%d (%s), returns %" MAGICK_OFF_F "d", |
1125 | | (magick_off_t) offset, |
1126 | | whence, |
1127 | | (whence == SEEK_SET ? "SET" : |
1128 | | (whence == SEEK_CUR ? "CUR" : |
1129 | | (whence == SEEK_END ? "END" : "unknown"))), |
1130 | | (magick_off_t) result); |
1131 | | #endif /* LOG_TIFF_BLOB_IO */ |
1132 | 1.45M | return result; |
1133 | 1.45M | } |
1134 | | |
1135 | | /* Obtain BLOB size */ |
1136 | | static toff_t |
1137 | | TIFFGetBlobSize(thandle_t image_handle) |
1138 | 781k | { |
1139 | 781k | Image |
1140 | 781k | *image = ((Magick_TIFF_ClientData *) image_handle)->image; |
1141 | | |
1142 | 781k | toff_t |
1143 | 781k | result; |
1144 | | |
1145 | 781k | result=(toff_t) GetBlobSize(image); |
1146 | | |
1147 | | #if LOG_TIFF_BLOB_IO |
1148 | | if (image->logging) |
1149 | | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1150 | | "TIFF get blob size returns %" MAGICK_OFF_F "d", |
1151 | | (magick_off_t) result); |
1152 | | #endif /* LOG_TIFF_BLOB_IO */ |
1153 | | |
1154 | 781k | return result; |
1155 | 781k | } |
1156 | | |
1157 | | /* Unmap BLOB memory */ |
1158 | | static void |
1159 | | TIFFUnmapBlob(thandle_t image_handle, |
1160 | | tdata_t base, |
1161 | | toff_t size) |
1162 | 811k | { |
1163 | | #if LOG_TIFF_BLOB_IO |
1164 | | Image |
1165 | | *image = ((Magick_TIFF_ClientData *) image_handle)->image; |
1166 | | |
1167 | | if (image->logging) |
1168 | | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1169 | | "TIFF unmap blob: base=0x%p size=%" MAGICK_OFF_F "d", |
1170 | | base,(magick_off_t) size); |
1171 | | #else |
1172 | 811k | ARG_NOT_USED(image_handle); |
1173 | 811k | ARG_NOT_USED(base); |
1174 | 811k | ARG_NOT_USED(size); |
1175 | 811k | #endif /* LOG_TIFF_BLOB_IO */ |
1176 | 811k | } |
1177 | | |
1178 | | #if defined(HAVE_TIFFERROREXTR) |
1179 | | static int |
1180 | | TIFFReadWarningHandlerExtRLogOnly(TIFF *tif, void *user_data, |
1181 | | const char *module, const char *format, va_list warning) |
1182 | | MAGICK_FUNC_PRINTF_FORMAT(4,0); |
1183 | | static int TIFFReadWarningHandlerExtRLogOnly(TIFF *tif, void *user_data, |
1184 | | const char *module, const char *format, |
1185 | | va_list warning) |
1186 | 3.62M | { |
1187 | 3.62M | char |
1188 | 3.62M | message[MaxTextExtent]; |
1189 | | |
1190 | 3.62M | (void) tif; |
1191 | 3.62M | (void) user_data; |
1192 | 3.62M | (void) module; |
1193 | 3.62M | errno=0; |
1194 | 3.62M | (void) vsnprintf(message,MaxTextExtent-2,format,warning); |
1195 | 3.62M | message[MaxTextExtent-2]='\0'; |
1196 | 3.62M | (void) strlcat(message,".",MaxTextExtent); |
1197 | 3.62M | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1198 | 3.62M | "TIFF Warning: %s",message); |
1199 | | /* |
1200 | | 0: both functions TIFFErrorHandler() and TIFFErrorHandlerExt() are called. |
1201 | | non-zero: no further error message function is called. |
1202 | | */ |
1203 | 3.62M | return 1; |
1204 | 3.62M | } |
1205 | | |
1206 | | static int |
1207 | | TIFFReadWarningHandlerExtRThrowException(TIFF *tif, void *user_data, |
1208 | | const char *module, const char *format, va_list warning) |
1209 | | MAGICK_FUNC_PRINTF_FORMAT(4,0); |
1210 | | static int TIFFReadWarningHandlerExtRThrowException(TIFF *tif, void *user_data, |
1211 | | const char *module, const char *format, |
1212 | | va_list warning) |
1213 | 0 | { |
1214 | 0 | ExceptionInfo |
1215 | 0 | *tiff_exception; |
1216 | |
|
1217 | 0 | char |
1218 | 0 | message[MaxTextExtent]; |
1219 | |
|
1220 | 0 | (void) tif; |
1221 | 0 | errno=0; |
1222 | 0 | (void) vsnprintf(message,MaxTextExtent-2,format,warning); |
1223 | 0 | message[MaxTextExtent-2]='\0'; |
1224 | 0 | #define UNKNOWN_TAG_ERROR "Internal error, unknown tag" |
1225 | 0 | if (LocaleNCompare(message,UNKNOWN_TAG_ERROR,sizeof(UNKNOWN_TAG_ERROR)-1) == 0) |
1226 | 0 | return 0; |
1227 | 0 | (void) strlcat(message,".",MaxTextExtent); |
1228 | 0 | tiff_exception=(ExceptionInfo *) user_data; |
1229 | 0 | ThrowException2(tiff_exception,CoderWarning,message,module); |
1230 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1231 | 0 | "TIFF Warning: %s",message); |
1232 | | /* |
1233 | | 0: both functions TIFFWarningHandler() and then TIFFWarningHandlerExt() are called. |
1234 | | non-zero: no further error message function is called. |
1235 | | */ |
1236 | 0 | return 1; |
1237 | 0 | } |
1238 | | #endif /* if defined(HAVE_TIFFERROREXTR) */ |
1239 | | |
1240 | | /* Report warnings as a coder log message. */ |
1241 | | static void |
1242 | | TIFFWarningsLogOnly(const char *module,const char *format,va_list warning) |
1243 | | MAGICK_FUNC_PRINTF_FORMAT(2,0); |
1244 | | static void |
1245 | | TIFFWarningsLogOnly(const char *module,const char *format,va_list warning) |
1246 | 0 | { |
1247 | | /* ExceptionInfo */ |
1248 | | /* *tiff_exception; */ |
1249 | |
|
1250 | 0 | char |
1251 | 0 | message[MaxTextExtent]; |
1252 | |
|
1253 | 0 | (void) module; |
1254 | 0 | errno=0; |
1255 | 0 | (void) vsnprintf(message,MaxTextExtent-2,format,warning); |
1256 | 0 | message[MaxTextExtent-2]='\0'; |
1257 | 0 | (void) strlcat(message,".",MaxTextExtent); |
1258 | | /* tiff_exception=(ExceptionInfo *) MagickTsdGetSpecific(tsd_key); */ |
1259 | | /* ThrowException2(tiff_exception,CoderWarning,message,module); */ |
1260 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1261 | 0 | "TIFF Warning: %s",message); |
1262 | 0 | } |
1263 | | |
1264 | | /* Report warnings as exception in thread-specific ExceptionInfo */ |
1265 | | static void |
1266 | | TIFFWarningsThrowException(const char *module,const char *format,va_list warning) |
1267 | | MAGICK_FUNC_PRINTF_FORMAT(2,0); |
1268 | | static void |
1269 | | TIFFWarningsThrowException(const char *module,const char *format,va_list warning) |
1270 | 0 | { |
1271 | 0 | ExceptionInfo |
1272 | 0 | *tiff_exception; |
1273 | |
|
1274 | 0 | char |
1275 | 0 | message[MaxTextExtent]; |
1276 | |
|
1277 | 0 | (void) module; |
1278 | 0 | errno=0; |
1279 | 0 | (void) vsnprintf(message,MaxTextExtent-2,format,warning); |
1280 | 0 | message[MaxTextExtent-2]='\0'; |
1281 | 0 | (void) strlcat(message,".",MaxTextExtent); |
1282 | 0 | tiff_exception=(ExceptionInfo *) MagickTsdGetSpecific(tsd_key); |
1283 | 0 | ThrowException2(tiff_exception,CoderWarning,message,module); |
1284 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1285 | 0 | "TIFF Warning: %s",message); |
1286 | 0 | } |
1287 | | |
1288 | | /* Write data at current offset */ |
1289 | | static tsize_t |
1290 | | TIFFWriteBlob(thandle_t image_handle,tdata_t data,tsize_t size) |
1291 | 191k | { |
1292 | 191k | Image |
1293 | 191k | *image = ((Magick_TIFF_ClientData *) image_handle)->image; |
1294 | | |
1295 | 191k | tsize_t |
1296 | 191k | result; |
1297 | | |
1298 | 191k | result=(tsize_t) WriteBlob(image,(size_t) size,data); |
1299 | | |
1300 | | #if LOG_TIFF_BLOB_IO |
1301 | | if (image->logging) |
1302 | | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1303 | | "TIFF write blob: data=0x%p size=" |
1304 | | "%" MAGICK_SIZE_T_F "u, returns " |
1305 | | "%" MAGICK_SIZE_T_F "u", |
1306 | | data, (MAGICK_SIZE_T) size, |
1307 | | (MAGICK_SIZE_T) result); |
1308 | | #endif /* LOG_TIFF_BLOB_IO */ |
1309 | | |
1310 | 191k | return result; |
1311 | 191k | } |
1312 | | |
1313 | | /* |
1314 | | Convert TIFF data from libtiff "native" format to byte-parsable big endian |
1315 | | */ |
1316 | | #if !defined(WORDS_BIGENDIAN) |
1317 | | static void |
1318 | | SwabDataToBigEndian(const uint16 bits_per_sample, tdata_t data, |
1319 | | const tsize_t size) |
1320 | 2.02k | { |
1321 | 2.02k | if (bits_per_sample == 64U) |
1322 | 0 | { |
1323 | 0 | TIFFSwabArrayOfDouble((double*) data, |
1324 | 0 | NumberOfObjectsInArray(size,sizeof(double))); |
1325 | 0 | } |
1326 | 2.02k | else if (bits_per_sample == 32U) |
1327 | 0 | { |
1328 | 0 | TIFFSwabArrayOfLong((uint32*) data, |
1329 | 0 | NumberOfObjectsInArray(size,sizeof(uint32))); |
1330 | 0 | } |
1331 | 2.02k | #if defined(HAVE_TIFFSWABARRAYOFTRIPLES) |
1332 | | /* New libtiff function to swap 24 bit values. Grumble ... */ |
1333 | 2.02k | else if (bits_per_sample == 24U) |
1334 | 2.02k | { |
1335 | 2.02k | TIFFSwabArrayOfTriples((uint8_t*) data, |
1336 | 2.02k | NumberOfObjectsInArray(size,3)); |
1337 | 2.02k | } |
1338 | 0 | #endif |
1339 | 0 | else if (bits_per_sample == 16U) |
1340 | 0 | { |
1341 | 0 | TIFFSwabArrayOfShort((uint16*) data, |
1342 | 0 | NumberOfObjectsInArray(size,sizeof(uint16))); |
1343 | 0 | } |
1344 | 2.02k | } |
1345 | | #endif |
1346 | | |
1347 | | /* |
1348 | | Convert TIFF data from byte-parsable big endian to libtiff "native" format. |
1349 | | */ |
1350 | | #if !defined(WORDS_BIGENDIAN) |
1351 | | static void |
1352 | | SwabDataToNativeEndian(const uint16 bits_per_sample, tdata_t data, |
1353 | | const tsize_t size) |
1354 | 0 | { |
1355 | 0 | if (bits_per_sample == 64) |
1356 | 0 | { |
1357 | 0 | TIFFSwabArrayOfDouble((double*) data, |
1358 | 0 | NumberOfObjectsInArray(size,sizeof(double))); |
1359 | 0 | } |
1360 | 0 | else if (bits_per_sample == 32) |
1361 | 0 | { |
1362 | 0 | TIFFSwabArrayOfLong((uint32*) data, |
1363 | 0 | NumberOfObjectsInArray(size,sizeof(uint32))); |
1364 | 0 | } |
1365 | 0 | #if defined(HAVE_TIFFSWABARRAYOFTRIPLES) |
1366 | | /* New libtiff function to swap 24 bit values. Grumble ... */ |
1367 | 0 | else if (bits_per_sample == 24U) |
1368 | 0 | { |
1369 | 0 | TIFFSwabArrayOfTriples((uint8_t*) data, |
1370 | 0 | NumberOfObjectsInArray(size,3)); |
1371 | 0 | } |
1372 | 0 | #endif |
1373 | 0 | else if (bits_per_sample == 16) |
1374 | 0 | { |
1375 | 0 | TIFFSwabArrayOfShort((uint16*) data, |
1376 | 0 | NumberOfObjectsInArray(size,sizeof(uint16))); |
1377 | 0 | } |
1378 | 0 | } |
1379 | | #endif |
1380 | | |
1381 | | /* |
1382 | | Initialize the image colormap. |
1383 | | */ |
1384 | | static MagickPassFail |
1385 | | InitializeImageColormap(Image *image, TIFF *tiff) |
1386 | 1.83k | { |
1387 | 1.83k | uint16 |
1388 | 1.83k | bits_per_sample, |
1389 | 1.83k | photometric; |
1390 | | |
1391 | 1.83k | register unsigned int |
1392 | 1.83k | i; |
1393 | | |
1394 | 1.83k | unsigned int |
1395 | 1.83k | max_sample_value, |
1396 | 1.83k | status = MagickFail; |
1397 | | |
1398 | 1.83k | if (TIFFGetFieldDefaulted(tiff,TIFFTAG_BITSPERSAMPLE,&bits_per_sample) != 1) |
1399 | 0 | return status; |
1400 | 1.83k | if (TIFFGetFieldDefaulted(tiff,TIFFTAG_PHOTOMETRIC,&photometric) != 1) |
1401 | 0 | return status; |
1402 | | |
1403 | | /* |
1404 | | Compute colormap size |
1405 | | */ |
1406 | 1.83k | if (bits_per_sample > 64) |
1407 | 0 | { |
1408 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1409 | 0 | "Bits per sample (%u) is out of range!", |
1410 | 0 | (unsigned) bits_per_sample); |
1411 | 0 | ThrowException(&image->exception,CorruptImageError,ImproperImageHeader, |
1412 | 0 | image->filename); |
1413 | 0 | return status; |
1414 | 0 | } |
1415 | 1.83k | max_sample_value=MaxValueGivenBits(bits_per_sample); |
1416 | | |
1417 | 1.83k | image->colors=0; |
1418 | 1.83k | if (MaxColormapSize > max_sample_value) |
1419 | 1.83k | image->colors=max_sample_value+1; |
1420 | 0 | else if (MaxColormapSize > MaxRGB) |
1421 | 0 | { |
1422 | 0 | if (photometric == PHOTOMETRIC_PALETTE) |
1423 | 0 | return status; |
1424 | 0 | else |
1425 | 0 | image->colors=MaxColormapSize; |
1426 | 0 | } |
1427 | | |
1428 | 1.83k | if (image->colors > 0) |
1429 | 1.83k | { |
1430 | 1.83k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1431 | 1.83k | "Allocating colormap with %u colors", |
1432 | 1.83k | image->colors); |
1433 | | |
1434 | | /* |
1435 | | Allocate colormap. |
1436 | | */ |
1437 | 1.83k | if (AllocateImageColormap(image,image->colors) == MagickFail) |
1438 | 0 | return status; |
1439 | | |
1440 | | /* |
1441 | | Create colormap. |
1442 | | */ |
1443 | 1.83k | switch (photometric) |
1444 | 1.83k | { |
1445 | 0 | case PHOTOMETRIC_MINISBLACK: |
1446 | 0 | case PHOTOMETRIC_MINISWHITE: |
1447 | 0 | default: |
1448 | 0 | { |
1449 | | /* |
1450 | | Ascending order produced by AllocateImageColormap() is sufficient. |
1451 | | */ |
1452 | 0 | status = MagickPass; |
1453 | 0 | break; |
1454 | 0 | } |
1455 | 1.83k | case PHOTOMETRIC_PALETTE: |
1456 | 1.83k | { |
1457 | 1.83k | long |
1458 | 1.83k | range; |
1459 | | |
1460 | 1.83k | uint16 |
1461 | 1.83k | *blue_colormap, |
1462 | 1.83k | *green_colormap, |
1463 | 1.83k | *red_colormap; |
1464 | | |
1465 | 1.83k | (void) TIFFGetField(tiff,TIFFTAG_COLORMAP,&red_colormap, |
1466 | 1.83k | &green_colormap,&blue_colormap); |
1467 | 1.83k | range=256L; /* might be old style 8-bit colormap */ |
1468 | 25.5k | for (i=0; i < image->colors; i++) |
1469 | 25.3k | if ((red_colormap[i] >= 256) || (green_colormap[i] >= 256) || |
1470 | 24.0k | (blue_colormap[i] >= 256)) |
1471 | 1.61k | { |
1472 | 1.61k | range=65535L; |
1473 | 1.61k | break; |
1474 | 1.61k | } |
1475 | 321k | for (i=0; i < image->colors; i++) |
1476 | 319k | { |
1477 | 319k | image->colormap[i].red=(Quantum) |
1478 | 319k | (((double) MaxRGB*red_colormap[i])/range+0.5); |
1479 | 319k | image->colormap[i].green=(Quantum) |
1480 | 319k | (((double) MaxRGB*green_colormap[i])/range+0.5); |
1481 | 319k | image->colormap[i].blue=(Quantum) |
1482 | 319k | (((double) MaxRGB*blue_colormap[i])/range+0.5); |
1483 | 319k | } |
1484 | 1.83k | status = MagickPass; |
1485 | 1.83k | break; |
1486 | 0 | } |
1487 | 1.83k | } |
1488 | 1.83k | if (status == MagickPass) |
1489 | 1.83k | { |
1490 | 1.83k | register const PixelPacket |
1491 | 1.83k | *p; |
1492 | | |
1493 | 1.83k | register unsigned int |
1494 | 1.83k | scale; |
1495 | | |
1496 | 1.83k | unsigned int |
1497 | 1.83k | depth=1; |
1498 | | |
1499 | | /* |
1500 | | Evaluate colormap depth. |
1501 | | */ |
1502 | 1.83k | p=image->colormap; |
1503 | 1.83k | scale=MaxRGB / (MaxRGB >> (QuantumDepth-depth)); |
1504 | 43.8k | for (i=image->colors; i != 0; i--) |
1505 | 43.2k | { |
1506 | 43.2k | if ((p->red != scale*(p->red/scale)) || |
1507 | 31.0k | (p->green != scale*(p->green/scale)) || |
1508 | 26.2k | (p->blue != scale*(p->blue/scale))) |
1509 | 21.1k | { |
1510 | 21.1k | depth++; |
1511 | 21.1k | if (depth == QuantumDepth) |
1512 | 1.26k | break; |
1513 | 19.9k | scale=MaxRGB / (MaxRGB >> (QuantumDepth-depth)); |
1514 | 19.9k | continue; |
1515 | 21.1k | } |
1516 | 22.0k | p++; |
1517 | 22.0k | } |
1518 | 1.83k | if (depth < 8) |
1519 | 510 | depth=8; |
1520 | 1.32k | else |
1521 | 1.32k | depth=16; |
1522 | 1.83k | image->depth=depth; |
1523 | 1.83k | } |
1524 | 1.83k | } |
1525 | | |
1526 | 1.83k | return status; |
1527 | 1.83k | } |
1528 | | |
1529 | | /* |
1530 | | Determine the quauntum import/export method to use with |
1531 | | ImportImagePixelArea() and ExportImagePixelArea() based on the |
1532 | | nature of the image, the TIFF photometric, sample format, samples |
1533 | | per pixel, the desired planar configuration, and the specified plane |
1534 | | (0 for contiguous planar configuration). Updates quantum_type with |
1535 | | the import/export method, and quantum_samples with the number of |
1536 | | samples consumed by one pixel. Returns MagickPass if the photometric |
1537 | | is supported. |
1538 | | */ |
1539 | | static MagickPassFail |
1540 | | QuantumTransferMode(const Image *image, |
1541 | | const uint16 photometric, |
1542 | | const uint16 compress_tag, |
1543 | | const uint16 sample_format, |
1544 | | const unsigned int samples_per_pixel, |
1545 | | const uint16 planar_config, |
1546 | | const unsigned int plane, |
1547 | | QuantumType *quantum_type, |
1548 | | int *quantum_samples, |
1549 | | ExceptionInfo *exception) |
1550 | 898k | { |
1551 | 898k | ARG_NOT_USED(exception); |
1552 | | |
1553 | 898k | *quantum_type=UndefinedQuantum; |
1554 | 898k | *quantum_samples=0; |
1555 | 898k | if ((sample_format == SAMPLEFORMAT_INT) || |
1556 | 898k | (sample_format == SAMPLEFORMAT_UINT) || |
1557 | 27.0k | (sample_format == SAMPLEFORMAT_VOID) || |
1558 | 25.4k | (sample_format == SAMPLEFORMAT_IEEEFP)) |
1559 | 894k | { |
1560 | 894k | switch (photometric) |
1561 | 894k | { |
1562 | 18.4k | case PHOTOMETRIC_CIELAB: |
1563 | 18.4k | { |
1564 | | /* samples_per_pixel may be 1 or 3 */ |
1565 | 18.4k | if (planar_config == PLANARCONFIG_SEPARATE) |
1566 | 1.04k | { |
1567 | 1.04k | switch (plane) |
1568 | 1.04k | { |
1569 | 1.01k | case 0: |
1570 | 1.01k | if (samples_per_pixel == 1) |
1571 | 990 | *quantum_type=GrayQuantum; |
1572 | 29 | else |
1573 | 29 | *quantum_type=RedQuantum; |
1574 | 1.01k | break; |
1575 | 11 | case 1: |
1576 | 11 | *quantum_type=GreenQuantum; |
1577 | 11 | break; |
1578 | 10 | case 2: |
1579 | 10 | *quantum_type=BlueQuantum; |
1580 | 10 | break; |
1581 | 4 | case 3: |
1582 | 4 | *quantum_type=AlphaQuantum; |
1583 | 4 | break; |
1584 | 1.04k | } |
1585 | 1.04k | *quantum_samples=1; |
1586 | 1.04k | } |
1587 | 17.4k | else |
1588 | 17.4k | { |
1589 | 17.4k | if (samples_per_pixel == 1) |
1590 | 17.0k | { |
1591 | 17.0k | if (image->matte) |
1592 | 5 | { |
1593 | 5 | *quantum_type=GrayAlphaQuantum; |
1594 | 5 | *quantum_samples=2; |
1595 | 5 | } |
1596 | 17.0k | else |
1597 | 17.0k | { |
1598 | 17.0k | *quantum_type=GrayQuantum; |
1599 | 17.0k | *quantum_samples=1; |
1600 | 17.0k | } |
1601 | 17.0k | } |
1602 | 321 | else |
1603 | 321 | { |
1604 | 321 | if (image->matte) |
1605 | 38 | { |
1606 | 38 | *quantum_type=RGBAQuantum; |
1607 | 38 | *quantum_samples=4; |
1608 | 38 | } |
1609 | 283 | else |
1610 | 283 | { |
1611 | 283 | *quantum_type=RGBQuantum; |
1612 | 283 | *quantum_samples=3; |
1613 | 283 | } |
1614 | 321 | } |
1615 | 17.4k | } |
1616 | 18.4k | break; |
1617 | 18.4k | } |
1618 | 18.4k | case PHOTOMETRIC_LOGL: |
1619 | 10.6k | { |
1620 | 10.6k | if (((compress_tag == COMPRESSION_SGILOG) || |
1621 | 1.73k | (compress_tag == COMPRESSION_SGILOG24)) && |
1622 | 10.6k | (planar_config == PLANARCONFIG_CONTIG) && |
1623 | 10.6k | (samples_per_pixel == 1) && |
1624 | 10.6k | (!image->matte)) |
1625 | 10.6k | { |
1626 | 10.6k | *quantum_type=CIEYQuantum; |
1627 | 10.6k | *quantum_samples=1; |
1628 | 10.6k | } |
1629 | 10.6k | break; |
1630 | 18.4k | } |
1631 | 5.74k | case PHOTOMETRIC_LOGLUV: |
1632 | 5.74k | { |
1633 | 5.74k | if (((compress_tag == COMPRESSION_SGILOG) || |
1634 | 2.15k | (compress_tag == COMPRESSION_SGILOG24)) && |
1635 | 5.74k | (planar_config == PLANARCONFIG_CONTIG) && |
1636 | 5.73k | (!image->matte)) |
1637 | 5.73k | { |
1638 | 5.73k | if (samples_per_pixel == 1) |
1639 | 3.91k | { |
1640 | | /* FIXME: this might not work. */ |
1641 | 3.91k | *quantum_type=CIEYQuantum; |
1642 | 3.91k | *quantum_samples=1; |
1643 | 3.91k | } |
1644 | 1.81k | else if (samples_per_pixel == 3) |
1645 | 1.81k | { |
1646 | 1.81k | *quantum_type=CIEXYZQuantum; |
1647 | 1.81k | *quantum_samples=3; |
1648 | 1.81k | } |
1649 | 5.73k | } |
1650 | 5.74k | break; |
1651 | 18.4k | } |
1652 | 157k | case PHOTOMETRIC_MINISBLACK: |
1653 | 622k | case PHOTOMETRIC_MINISWHITE: |
1654 | 622k | { |
1655 | 622k | if (planar_config == PLANARCONFIG_SEPARATE) |
1656 | 2.35k | { |
1657 | 2.35k | switch (plane) |
1658 | 2.35k | { |
1659 | 1.96k | case 0: |
1660 | 1.96k | *quantum_type=GrayQuantum; |
1661 | 1.96k | *quantum_samples=1; |
1662 | 1.96k | break; |
1663 | 390 | case 1: |
1664 | 390 | *quantum_type=AlphaQuantum; |
1665 | 390 | *quantum_samples=1; |
1666 | 390 | break; |
1667 | 2.35k | } |
1668 | 2.35k | } |
1669 | 620k | else |
1670 | 620k | { |
1671 | 620k | if (image->matte) |
1672 | 2.48k | { |
1673 | 2.48k | *quantum_type=GrayAlphaQuantum; |
1674 | 2.48k | *quantum_samples=2; |
1675 | 2.48k | } |
1676 | 617k | else |
1677 | 617k | { |
1678 | 617k | *quantum_type=GrayQuantum; |
1679 | 617k | *quantum_samples=1; |
1680 | 617k | } |
1681 | 620k | } |
1682 | 622k | break; |
1683 | 622k | } |
1684 | 622k | case PHOTOMETRIC_PALETTE: |
1685 | 93.9k | { |
1686 | 93.9k | if (sample_format == SAMPLEFORMAT_UINT) |
1687 | 93.2k | { |
1688 | 93.2k | if (image->matte) |
1689 | 221 | { |
1690 | 221 | *quantum_type=IndexAlphaQuantum; |
1691 | 221 | *quantum_samples=2; |
1692 | 221 | } |
1693 | 92.9k | else |
1694 | 92.9k | { |
1695 | 92.9k | *quantum_type=IndexQuantum; |
1696 | 92.9k | *quantum_samples=1; |
1697 | 92.9k | } |
1698 | 93.2k | } |
1699 | 93.9k | break; |
1700 | 622k | } |
1701 | 135k | case PHOTOMETRIC_RGB: |
1702 | 135k | { |
1703 | 135k | if (compress_tag != COMPRESSION_OJPEG) |
1704 | 135k | { |
1705 | 135k | if (planar_config == PLANARCONFIG_SEPARATE) |
1706 | 4.40k | { |
1707 | 4.40k | switch (plane) |
1708 | 4.40k | { |
1709 | 1.65k | case 0: |
1710 | 1.65k | *quantum_type=RedQuantum; |
1711 | 1.65k | break; |
1712 | 1.21k | case 1: |
1713 | 1.21k | *quantum_type=GreenQuantum; |
1714 | 1.21k | break; |
1715 | 1.18k | case 2: |
1716 | 1.18k | *quantum_type=BlueQuantum; |
1717 | 1.18k | break; |
1718 | 351 | case 3: |
1719 | 351 | *quantum_type=AlphaQuantum; |
1720 | 351 | break; |
1721 | 4.40k | } |
1722 | 4.40k | *quantum_samples=1; |
1723 | 4.40k | } |
1724 | 131k | else |
1725 | 131k | { |
1726 | 131k | if (image->matte) |
1727 | 8.30k | { |
1728 | 8.30k | *quantum_type=RGBAQuantum; |
1729 | 8.30k | *quantum_samples=4; |
1730 | 8.30k | } |
1731 | 123k | else |
1732 | 123k | { |
1733 | 123k | *quantum_type=RGBQuantum; |
1734 | 123k | *quantum_samples=3; |
1735 | 123k | } |
1736 | 131k | } |
1737 | 135k | } |
1738 | 135k | break; |
1739 | 135k | } |
1740 | 135k | case PHOTOMETRIC_SEPARATED: |
1741 | 5.68k | { |
1742 | 5.68k | if (planar_config == PLANARCONFIG_SEPARATE) |
1743 | 3.02k | { |
1744 | 3.02k | switch (plane) |
1745 | 3.02k | { |
1746 | 1.04k | case 0: |
1747 | 1.04k | *quantum_type=CyanQuantum; |
1748 | 1.04k | break; |
1749 | 661 | case 1: |
1750 | 661 | *quantum_type=MagentaQuantum; |
1751 | 661 | break; |
1752 | 659 | case 2: |
1753 | 659 | *quantum_type=YellowQuantum; |
1754 | 659 | break; |
1755 | 659 | case 3: |
1756 | 659 | *quantum_type=BlackQuantum; |
1757 | 659 | break; |
1758 | 0 | case 4: |
1759 | 0 | *quantum_type=AlphaQuantum; |
1760 | 0 | break; |
1761 | 3.02k | } |
1762 | 3.02k | *quantum_samples=1; |
1763 | 3.02k | } |
1764 | 2.66k | else |
1765 | 2.66k | { |
1766 | 2.66k | if (image->matte) |
1767 | 297 | { |
1768 | 297 | *quantum_type=CMYKAQuantum; |
1769 | 297 | *quantum_samples=5; |
1770 | 297 | } |
1771 | 2.36k | else |
1772 | 2.36k | { |
1773 | 2.36k | *quantum_type=CMYKQuantum; |
1774 | 2.36k | *quantum_samples=4; |
1775 | 2.36k | } |
1776 | 2.66k | } |
1777 | 5.68k | break; |
1778 | 5.68k | } |
1779 | 5.68k | case PHOTOMETRIC_YCBCR: |
1780 | 1.73k | { |
1781 | | /* |
1782 | | This is here to support JPEGCOLORMODE_RGB which claims a |
1783 | | YCbCr photometric, but passes RGB to libtiff. |
1784 | | */ |
1785 | 1.73k | if (compress_tag == COMPRESSION_JPEG) |
1786 | 761 | { |
1787 | 761 | *quantum_type=RGBQuantum; |
1788 | 761 | *quantum_samples=3; |
1789 | 761 | } |
1790 | 1.73k | break; |
1791 | 5.68k | } |
1792 | 894k | } |
1793 | 894k | } |
1794 | 898k | if (image->logging) |
1795 | 872k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1796 | 872k | "Quantum Type: %s, Quantum Samples: %d", |
1797 | 872k | QuantumTypeToString(*quantum_type),*quantum_samples); |
1798 | | /* FIXME: We do need to support YCbCr! */ |
1799 | | |
1800 | 898k | if (*quantum_samples != 0) |
1801 | 892k | { |
1802 | | /* |
1803 | | Enforce that there are no buffer-overruns. |
1804 | | */ |
1805 | 892k | if (((planar_config == PLANARCONFIG_SEPARATE) && (*quantum_samples != 1)) || |
1806 | 892k | ((unsigned int) (*quantum_samples) > samples_per_pixel)) |
1807 | 68 | { |
1808 | 68 | if (image->logging) |
1809 | 68 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1810 | 68 | "Expected >= %u samples per pixel, have only %d!", |
1811 | 68 | *quantum_samples, samples_per_pixel); |
1812 | 68 | ThrowException(exception,CorruptImageError,ImproperImageHeader, |
1813 | 68 | image->filename); |
1814 | 68 | *quantum_type=UndefinedQuantum; |
1815 | 68 | *quantum_samples=0; |
1816 | 68 | } |
1817 | 892k | } |
1818 | | |
1819 | 898k | if ((image->logging) && (*quantum_samples == 0)) |
1820 | 5.78k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1821 | 5.78k | "QuantumTransferMode reports failure"); |
1822 | | |
1823 | 898k | return (*quantum_samples != 0 ? MagickPass : MagickFail); |
1824 | 898k | } |
1825 | | |
1826 | | /* |
1827 | | Compact samples to only contain raster data. This may seem |
1828 | | inefficient, but it allows us to easily deal with contiguous images |
1829 | | which contain extra samples while optimizing performance for images |
1830 | | without extra samples. |
1831 | | */ |
1832 | | static void |
1833 | | CompactSamples( const unsigned long total_pixels, |
1834 | | const unsigned int bits_per_sample, |
1835 | | const unsigned int samples_per_pixel, |
1836 | | const unsigned int quantum_samples, |
1837 | | unsigned char *samples) |
1838 | 1.92M | { |
1839 | 1.92M | if ((samples_per_pixel > quantum_samples) && |
1840 | 1.92M | (bits_per_sample > 0) && bits_per_sample <= 32) |
1841 | 1.83M | { |
1842 | | /* |
1843 | | Compact scanline to only contain raster data. |
1844 | | */ |
1845 | | |
1846 | 1.83M | BitStreamReadHandle |
1847 | 1.83M | read_stream; |
1848 | | |
1849 | 1.83M | BitStreamWriteHandle |
1850 | 1.83M | write_stream; |
1851 | | |
1852 | 1.83M | unsigned long |
1853 | 1.83M | pixels; |
1854 | | |
1855 | 1.83M | unsigned int |
1856 | 1.83M | count, |
1857 | 1.83M | quantum_value; |
1858 | | |
1859 | 1.83M | MagickBitStreamInitializeRead(&read_stream,samples); |
1860 | 1.83M | MagickBitStreamInitializeWrite(&write_stream,samples); |
1861 | | |
1862 | 22.0M | for (pixels = total_pixels; pixels != 0 ; pixels--) |
1863 | 20.1M | { |
1864 | 68.1M | for (count = quantum_samples; count != 0 ; count--) |
1865 | 47.9M | { |
1866 | 47.9M | quantum_value=MagickBitStreamMSBRead(&read_stream,bits_per_sample); |
1867 | 47.9M | MagickBitStreamMSBWrite(&write_stream,bits_per_sample,quantum_value); |
1868 | 47.9M | } |
1869 | 84.2M | for (count = samples_per_pixel-quantum_samples; count != 0 ; count--) |
1870 | 64.0M | { |
1871 | 64.0M | (void) MagickBitStreamMSBRead(&read_stream,bits_per_sample); |
1872 | 64.0M | } |
1873 | 20.1M | } |
1874 | 1.83M | } |
1875 | 1.92M | } |
1876 | | |
1877 | | |
1878 | | /* |
1879 | | Convert selected pixel area to associated alpha representation. |
1880 | | */ |
1881 | | static void |
1882 | | AssociateAlphaRegion(Image *image) |
1883 | 374k | { |
1884 | 374k | register PixelPacket |
1885 | 374k | *q; |
1886 | | |
1887 | 374k | register long |
1888 | 374k | x; |
1889 | | |
1890 | 374k | register double |
1891 | 374k | alpha, |
1892 | 374k | value; |
1893 | | |
1894 | 374k | long |
1895 | 374k | number_pixels; |
1896 | | |
1897 | 374k | number_pixels=(long) GetPixelCacheArea(image); |
1898 | 374k | q=AccessMutablePixels(image); |
1899 | | |
1900 | 16.1M | for (x = number_pixels; x > 0; --x) |
1901 | 15.8M | { |
1902 | 15.8M | alpha=((double) MaxRGB-q->opacity)/MaxRGB; |
1903 | 15.8M | value=(double) q->red*alpha; |
1904 | 15.8M | q->red=RoundDoubleToQuantum(value); |
1905 | 15.8M | value=(double) q->green*alpha; |
1906 | 15.8M | q->green=RoundDoubleToQuantum(value); |
1907 | 15.8M | value=(double) q->blue*alpha; |
1908 | 15.8M | q->blue=RoundDoubleToQuantum(value); |
1909 | 15.8M | q++; |
1910 | 15.8M | } |
1911 | 374k | } |
1912 | | |
1913 | | /* |
1914 | | Convert associated alpha to internal representation for selected |
1915 | | pixel area. |
1916 | | */ |
1917 | | static void |
1918 | | DisassociateAlphaRegion(Image *image) |
1919 | 320k | { |
1920 | 320k | register PixelPacket |
1921 | 320k | *q; |
1922 | | |
1923 | 320k | register long |
1924 | 320k | x; |
1925 | | |
1926 | 320k | register double |
1927 | 320k | alpha, |
1928 | 320k | value; |
1929 | | |
1930 | 320k | long |
1931 | 320k | number_pixels; |
1932 | | |
1933 | 320k | number_pixels=(long) GetPixelCacheArea(image); |
1934 | 320k | q=AccessMutablePixels(image); |
1935 | | |
1936 | 8.56M | for (x = number_pixels; x > 0; --x) |
1937 | 8.24M | { |
1938 | 8.24M | if (q->opacity != (Quantum) MaxRGB) |
1939 | 7.99M | { |
1940 | 7.99M | alpha=((double) MaxRGB-q->opacity)/MaxRGB; |
1941 | 7.99M | value=(double) q->red/alpha; |
1942 | 7.99M | q->red=RoundDoubleToQuantum(value); |
1943 | 7.99M | value=(double) q->green/alpha; |
1944 | 7.99M | q->green=RoundDoubleToQuantum(value); |
1945 | 7.99M | value=(double) q->blue/alpha; |
1946 | 7.99M | q->blue=RoundDoubleToQuantum(value); |
1947 | 7.99M | } |
1948 | 8.24M | q++; |
1949 | 8.24M | } |
1950 | 320k | } |
1951 | | |
1952 | | #if defined(__cplusplus) || defined(c_plusplus) |
1953 | | } |
1954 | | #endif |
1955 | | |
1956 | | /* |
1957 | | Copy a possibly unterminated sized string to an image attribute. |
1958 | | */ |
1959 | | #define CopySizedFieldToAttribute(key,count,text) \ |
1960 | 34 | do \ |
1961 | 34 | { \ |
1962 | 34 | char _attribute[MaxTextExtent]; \ |
1963 | 34 | (void) memcpy(_attribute,text,Min(sizeof(_attribute),count)); \ |
1964 | 34 | _attribute[Min(sizeof(_attribute)-1,count)]='\0'; \ |
1965 | 34 | (void) SetImageAttribute(image,key,_attribute); \ |
1966 | 34 | } while(0); |
1967 | | |
1968 | | |
1969 | | typedef enum |
1970 | | { |
1971 | | ScanLineMethod, /* Scanline method */ |
1972 | | StrippedMethod, /* Stripped method */ |
1973 | | TiledMethod, /* Tiled method */ |
1974 | | RGBAStrippedMethod, /* RGBA stripped method */ |
1975 | | RGBATiledMethod, /* RGBA tiled method */ |
1976 | | RGBAPuntMethod /* RGBA whole-image method (last resort) */ |
1977 | | } TIFFMethod; |
1978 | | |
1979 | 2.95k | #define ThrowTIFFReaderException(code_,reason_,image_) \ |
1980 | 2.95k | { \ |
1981 | 2.95k | if (tiff != (TIFF *) NULL) \ |
1982 | 2.95k | TIFFClose(tiff); \ |
1983 | 2.95k | ThrowReaderException(code_,reason_,image_); \ |
1984 | 0 | } |
1985 | | |
1986 | | static Image * |
1987 | | ReadTIFFImage(const ImageInfo *image_info,ExceptionInfo *exception) |
1988 | 814k | { |
1989 | 814k | char |
1990 | 814k | *text; |
1991 | | |
1992 | 814k | const char * |
1993 | 814k | definition_value; |
1994 | | |
1995 | 814k | float |
1996 | 814k | *chromaticity, |
1997 | 814k | x_resolution, |
1998 | 814k | y_resolution; |
1999 | | |
2000 | 814k | Image |
2001 | 814k | *image; |
2002 | | |
2003 | 814k | unsigned int |
2004 | 814k | y; |
2005 | | |
2006 | 814k | register unsigned int |
2007 | 814k | x; |
2008 | | |
2009 | 814k | register PixelPacket |
2010 | 814k | *q; |
2011 | | |
2012 | 814k | register unsigned int |
2013 | 814k | i; |
2014 | | |
2015 | 814k | TIFF |
2016 | 814k | *tiff = (TIFF *) NULL; |
2017 | | |
2018 | 814k | magick_off_t |
2019 | 814k | file_size, |
2020 | 814k | max_compress_ratio=1000; /* Maximum compression ratio */ |
2021 | | |
2022 | 814k | uint16 |
2023 | 814k | compress_tag, |
2024 | 814k | bits_per_sample, |
2025 | 814k | extra_samples, |
2026 | 814k | fill_order, |
2027 | 814k | max_sample_value, |
2028 | 814k | min_sample_value, |
2029 | 814k | orientation, |
2030 | 814k | pages, |
2031 | 814k | photometric, |
2032 | 814k | planar_config, |
2033 | 814k | *sample_info, |
2034 | 814k | sample_format, |
2035 | 814k | samples_per_pixel, |
2036 | 814k | units; |
2037 | | |
2038 | 814k | uint32 |
2039 | 814k | count, |
2040 | 814k | height, |
2041 | 814k | rows_per_strip, |
2042 | 814k | width; |
2043 | | |
2044 | 814k | TIFFMethod |
2045 | 814k | method; |
2046 | | |
2047 | 814k | Magick_TIFF_ClientData |
2048 | 814k | client_data; |
2049 | | |
2050 | 814k | ImportPixelAreaOptions |
2051 | 814k | import_options; |
2052 | | |
2053 | 814k | AlphaType |
2054 | 814k | alpha_type=UnspecifiedAlpha; |
2055 | | |
2056 | 814k | MagickBool |
2057 | 814k | logging, |
2058 | 814k | more_frames; |
2059 | | |
2060 | 814k | MagickPassFail |
2061 | 814k | status; |
2062 | | |
2063 | | /* |
2064 | | Open image. |
2065 | | */ |
2066 | 814k | assert(image_info != (const ImageInfo *) NULL); |
2067 | 814k | assert(image_info->signature == MagickSignature); |
2068 | 814k | assert(exception != (ExceptionInfo *) NULL); |
2069 | 814k | assert(exception->signature == MagickSignature); |
2070 | | |
2071 | 814k | logging=IsEventLogged(CoderEvent); |
2072 | 814k | image=AllocateImage(image_info); |
2073 | 814k | more_frames=MagickFalse; |
2074 | 814k | status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); |
2075 | 814k | if (status == MagickFail) |
2076 | 814k | ThrowReaderException(FileOpenError,UnableToOpenFile,image); |
2077 | 814k | file_size = GetBlobSize(image); |
2078 | 814k | (void) MagickTsdSetSpecific(tsd_key,(void *) exception); |
2079 | | |
2080 | | /* |
2081 | | Set global thread-specific reader errors and warnings handlers. |
2082 | | */ |
2083 | 814k | (void) TIFFSetErrorHandler((TIFFErrorHandler) TIFFReadErrorsHandler); |
2084 | 814k | (void) TIFFSetWarningHandler((TIFFErrorHandler) (CheckThrowWarnings(image_info) ? |
2085 | 0 | TIFFWarningsThrowException : |
2086 | 814k | TIFFWarningsLogOnly)); |
2087 | 814k | client_data.image=image; |
2088 | 814k | client_data.image_info=image_info; |
2089 | 814k | #if defined(HAVE_TIFFERROREXTR) |
2090 | 814k | { |
2091 | 814k | magick_int64_t |
2092 | 814k | memory_consumed, |
2093 | 814k | memory_maximum_limit; |
2094 | | |
2095 | 814k | tmsize_t |
2096 | 814k | max_single_mem_alloc, |
2097 | 814k | max_cumulated_mem_alloc; |
2098 | | |
2099 | 814k | TIFFOpenOptions *open_options = TIFFOpenOptionsAlloc(); |
2100 | | /* |
2101 | | TIFFOpenOptionsSetMaxSingleMemAlloc(TIFFOpenOptions *opts, |
2102 | | tmsize_t max_single_mem_alloc); |
2103 | | TIFFOpenOptionsSetMaxCumulatedMemAlloc(TIFFOpenOptions *opts, |
2104 | | tmsize_t max_cumulated_mem_alloc); |
2105 | | TIFFOpenOptionsSetWarnAboutUnknownTags(TIFFOpenOptions *opts, |
2106 | | int warn_about_unknown_tags); |
2107 | | TIFFOpenOptionsSetErrorHandlerExtR(TIFFOpenOptions *opts, |
2108 | | TIFFErrorHandlerExtR handler, |
2109 | | void *errorhandler_user_data); |
2110 | | TIFFOpenOptionsSetWarningHandlerExtR(TIFFOpenOptions *opts, |
2111 | | TIFFErrorHandlerExtR handler, |
2112 | | void *warnhandler_user_data); |
2113 | | */ |
2114 | 814k | TIFFOpenOptionsSetErrorHandlerExtR(open_options, TIFFReadErrorsHandlerExtR, (void *) exception); |
2115 | 814k | TIFFOpenOptionsSetWarningHandlerExtR(open_options, |
2116 | 814k | (CheckThrowWarnings(image_info) ? |
2117 | 814k | TIFFReadWarningHandlerExtRThrowException : TIFFReadWarningHandlerExtRLogOnly), |
2118 | 814k | (void *) exception); /* FIXME */ |
2119 | 814k | memory_maximum_limit=GetMagickResourceLimit(MemoryResource); |
2120 | 814k | memory_consumed=GetMagickResource(MemoryResource); |
2121 | 814k | max_single_mem_alloc=((memory_maximum_limit-memory_consumed)/8); /* FIXME: Support configuring ratio? */ |
2122 | 814k | TIFFOpenOptionsSetMaxSingleMemAlloc(open_options, max_single_mem_alloc); |
2123 | 814k | max_cumulated_mem_alloc=((memory_maximum_limit-memory_consumed)/4); /* FIXME: Support configuring ratio? */ |
2124 | 814k | TIFFOpenOptionsSetMaxCumulatedMemAlloc(open_options, max_cumulated_mem_alloc); |
2125 | 814k | tiff=TIFFClientOpenExt(image->filename,"rb",(thandle_t) &client_data, |
2126 | 814k | TIFFReadBlob,TIFFWriteBlob,TIFFSeekBlob,TIFFCloseBlob, |
2127 | 814k | TIFFGetBlobSize,TIFFMapBlob,TIFFUnmapBlob, |
2128 | 814k | open_options); |
2129 | 814k | TIFFOpenOptionsFree(open_options); |
2130 | 814k | } |
2131 | | #else |
2132 | | tiff=TIFFClientOpen(image->filename,"rb",(thandle_t) &client_data, |
2133 | | TIFFReadBlob, |
2134 | | TIFFWriteBlob,TIFFSeekBlob,TIFFCloseBlob, |
2135 | | TIFFGetBlobSize,TIFFMapBlob,TIFFUnmapBlob); |
2136 | | #endif /* if defined(HAVE_TIFFERROREXTR) */ |
2137 | 814k | if (tiff == (TIFF *) NULL) |
2138 | 723k | ThrowReaderException(FileOpenError,UnableToOpenFile,image); |
2139 | | |
2140 | | /* |
2141 | | Report error if error was reported via TIFFReadErrorsHandler() while in |
2142 | | TIFFClientOpen(). |
2143 | | */ |
2144 | 90.9k | if (exception->severity > ErrorException) |
2145 | 50.1k | { |
2146 | 50.1k | TIFFClose(tiff); |
2147 | 50.1k | DestroyImageList(image); |
2148 | 50.1k | return (Image *) NULL; |
2149 | 50.1k | } |
2150 | | |
2151 | 40.7k | if (image_info->subrange != 0) |
2152 | 38.6k | while (image->scene < image_info->subimage) |
2153 | 0 | { |
2154 | | /* |
2155 | | Skip to next image. |
2156 | | */ |
2157 | 0 | image->scene++; |
2158 | 0 | status=TIFFReadDirectory(tiff); |
2159 | 0 | if (status == False) |
2160 | 0 | { |
2161 | 0 | ThrowTIFFReaderException(CorruptImageError,UnableToReadSubImageData, |
2162 | 0 | image); |
2163 | 0 | } |
2164 | 0 | } |
2165 | 40.7k | do |
2166 | 40.7k | { |
2167 | 40.7k | if (image_info->verbose > 1) |
2168 | 0 | TIFFPrintDirectory(tiff,stdout,False); |
2169 | | |
2170 | | /* |
2171 | | Read critical tags. We need a value for these tags in order to proceed. |
2172 | | */ |
2173 | 40.7k | status = 1; |
2174 | 40.7k | status &= (TIFFGetFieldDefaulted(tiff,TIFFTAG_PHOTOMETRIC,&photometric) == 1); |
2175 | 40.7k | if ((status == 1) && |
2176 | 39.7k | ((photometric == PHOTOMETRIC_LOGL) || (photometric == PHOTOMETRIC_LOGLUV))) |
2177 | 881 | status &= (TIFFSetField(tiff,TIFFTAG_SGILOGDATAFMT,SGILOGDATAFMT_FLOAT) == 1); |
2178 | 40.7k | status &= (TIFFGetFieldDefaulted(tiff,TIFFTAG_COMPRESSION,&compress_tag) == 1); |
2179 | 40.7k | status &= (TIFFGetField(tiff,TIFFTAG_IMAGEWIDTH,&width) == 1); |
2180 | 40.7k | status &= (TIFFGetField(tiff,TIFFTAG_IMAGELENGTH,&height) == 1); |
2181 | 40.7k | status &= (TIFFGetFieldDefaulted(tiff,TIFFTAG_PLANARCONFIG,&planar_config) == 1); |
2182 | 40.7k | status &= (TIFFGetFieldDefaulted(tiff,TIFFTAG_SAMPLESPERPIXEL,&samples_per_pixel) == 1); |
2183 | 40.7k | status &= (TIFFGetFieldDefaulted(tiff,TIFFTAG_BITSPERSAMPLE,&bits_per_sample) == 1); |
2184 | 40.7k | status &= (TIFFGetFieldDefaulted(tiff,TIFFTAG_SAMPLEFORMAT,&sample_format) == 1); |
2185 | 40.7k | status &= (TIFFGetFieldDefaulted(tiff,TIFFTAG_MINSAMPLEVALUE,&min_sample_value) == 1); |
2186 | 40.7k | status &= (TIFFGetFieldDefaulted(tiff,TIFFTAG_MAXSAMPLEVALUE,&max_sample_value) == 1); |
2187 | 40.7k | status &= (TIFFGetFieldDefaulted(tiff,TIFFTAG_ROWSPERSTRIP,&rows_per_strip) == 1); |
2188 | 40.7k | status &= (TIFFGetFieldDefaulted(tiff,TIFFTAG_FILLORDER,&fill_order) == 1); |
2189 | 40.7k | if (status == 0) |
2190 | 984 | { |
2191 | | /* |
2192 | | Promote TIFF warnings to errors for these critical tags. |
2193 | | */ |
2194 | 984 | if ((exception->severity > WarningException) && |
2195 | 6 | (exception->severity < ErrorException)) |
2196 | 0 | exception->severity = (ExceptionType) ((int) exception->severity + |
2197 | 0 | ((int) ErrorException - (int)WarningException)); |
2198 | 984 | ThrowTIFFReaderException(CorruptImageError,ImproperImageHeader, |
2199 | 0 | image); |
2200 | 0 | } |
2201 | 39.7k | if (TIFFGetField(tiff,TIFFTAG_ORIENTATION,&orientation) == 1) |
2202 | 4.78k | image->orientation=(OrientationType) orientation; |
2203 | 39.7k | if (logging) |
2204 | 0 | { |
2205 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Geometry: %ux%u", |
2206 | 0 | (unsigned int) width,(unsigned int) height); |
2207 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(),"PlanarConfiguration: %s", |
2208 | 0 | planar_config == PLANARCONFIG_CONTIG ? "contiguous" : |
2209 | 0 | planar_config == PLANARCONFIG_SEPARATE ? "separate" : |
2210 | 0 | "UNKNOWN"); |
2211 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2212 | 0 | "Samples per pixel: %u", samples_per_pixel); |
2213 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2214 | 0 | "Sample format: %s", |
2215 | 0 | sample_format == SAMPLEFORMAT_UINT ? "Unsigned integer" : |
2216 | 0 | sample_format == SAMPLEFORMAT_INT ? "Signed integer" : |
2217 | 0 | sample_format == SAMPLEFORMAT_IEEEFP ? "IEEE floating point" : |
2218 | 0 | sample_format == SAMPLEFORMAT_VOID ? "Untyped data" : |
2219 | 0 | sample_format == SAMPLEFORMAT_COMPLEXINT ? "Complex signed int" : |
2220 | 0 | sample_format == SAMPLEFORMAT_COMPLEXIEEEFP ? "Complex IEEE floating point" : |
2221 | 0 | "UNKNOWN"); |
2222 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2223 | 0 | "Bits per sample: %u",bits_per_sample); |
2224 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2225 | 0 | "Min sample value: %u",min_sample_value); |
2226 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2227 | 0 | "Max sample value: %u",max_sample_value); |
2228 | 0 | if (sample_format == SAMPLEFORMAT_IEEEFP) |
2229 | 0 | { |
2230 | 0 | double |
2231 | 0 | value; |
2232 | |
|
2233 | 0 | if (TIFFGetField(tiff,TIFFTAG_SMINSAMPLEVALUE,&value) == 1) |
2234 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2235 | 0 | "Special min sample value: %g", value); |
2236 | 0 | if (TIFFGetField(tiff,TIFFTAG_SMAXSAMPLEVALUE,&value) == 1) |
2237 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2238 | 0 | "Special max sample value: %g", value); |
2239 | 0 | } |
2240 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2241 | 0 | "Photometric: %s", PhotometricTagToString(photometric)); |
2242 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2243 | 0 | "Compression: %s", CompressionTagToString(compress_tag)); |
2244 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2245 | 0 | "Byte swapped: %s",TIFFIsByteSwapped(tiff) ? |
2246 | 0 | "true" : "false"); |
2247 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2248 | 0 | "Bit fill order: %s", |
2249 | 0 | fill_order == FILLORDER_LSB2MSB ? "LSB2MSB" : |
2250 | 0 | fill_order == FILLORDER_MSB2LSB ? "MSB2LSB" : |
2251 | 0 | "unknown"); |
2252 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2253 | 0 | "Rows per strip: %u",(unsigned int) rows_per_strip); |
2254 | 0 | } |
2255 | 39.7k | ImportPixelAreaOptionsInit(&import_options); |
2256 | 39.7k | if (photometric == PHOTOMETRIC_CIELAB) |
2257 | 1.59k | { |
2258 | 1.59k | #if 1 |
2259 | 1.59k | image->colorspace=LABColorspace; |
2260 | | #else |
2261 | | ThrowTIFFReaderException(CoderError,UnableToReadCIELABImages,image); |
2262 | | #endif |
2263 | 1.59k | } |
2264 | 39.7k | if (photometric == PHOTOMETRIC_SEPARATED) |
2265 | 1.31k | image->colorspace=CMYKColorspace; |
2266 | 39.7k | if (planar_config == PLANARCONFIG_SEPARATE) |
2267 | 2.82k | image->interlace=PlaneInterlace; |
2268 | 39.7k | (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_RESOLUTIONUNIT,&units); |
2269 | 39.7k | x_resolution=(float) image->x_resolution; |
2270 | 39.7k | y_resolution=(float) image->y_resolution; |
2271 | 39.7k | (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_XRESOLUTION,&x_resolution); |
2272 | 39.7k | (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_YRESOLUTION,&y_resolution); |
2273 | 39.7k | image->x_resolution=x_resolution; |
2274 | 39.7k | image->y_resolution=y_resolution; |
2275 | 39.7k | chromaticity=(float *) NULL; |
2276 | 39.7k | if (TIFFGetField(tiff,TIFFTAG_WHITEPOINT,&chromaticity) == 1) |
2277 | 405 | { |
2278 | 405 | if (chromaticity != (float *) NULL) |
2279 | 405 | { |
2280 | 405 | if (logging) |
2281 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2282 | 0 | "White Point: %gx%g", |
2283 | 0 | chromaticity[0] /* white_point.x */, |
2284 | 0 | chromaticity[1] /* white_point.y */); |
2285 | 405 | if (MAGICK_ISNAN(chromaticity[0]) || (chromaticity[0] < 0.0) || |
2286 | 405 | MAGICK_ISNAN(chromaticity[1]) || (chromaticity[1] < 0.0)) |
2287 | 20 | { |
2288 | 20 | if (logging) |
2289 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2290 | 0 | "White Point: Is corrupt!"); |
2291 | 20 | } |
2292 | 385 | else |
2293 | 385 | { |
2294 | 385 | image->chromaticity.white_point.x=chromaticity[0]; |
2295 | 385 | image->chromaticity.white_point.y=chromaticity[1]; |
2296 | 385 | } |
2297 | 405 | } |
2298 | 405 | } |
2299 | 39.7k | chromaticity=(float *) NULL; |
2300 | 39.7k | if (TIFFGetField(tiff,TIFFTAG_PRIMARYCHROMATICITIES,&chromaticity) == 1) |
2301 | 295 | { |
2302 | 295 | if (chromaticity != (float *) NULL) |
2303 | 295 | { |
2304 | 295 | if (logging) |
2305 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2306 | 0 | "Primary Chromaticities: " |
2307 | 0 | "r=%gx%g g=%gx%g b=%gx%g", |
2308 | 0 | chromaticity[0] /* red_primary.x */, |
2309 | 0 | chromaticity[1] /* red_primary.y */, |
2310 | 0 | chromaticity[2] /* green_primary.x */, |
2311 | 0 | chromaticity[3] /* green_primary.y */, |
2312 | 0 | chromaticity[4] /* blue_primary.x */, |
2313 | 0 | chromaticity[5] /* blue_primary.y */); |
2314 | 295 | if (MAGICK_ISNAN(chromaticity[0]) || (chromaticity[0] < 0.0) || |
2315 | 295 | MAGICK_ISNAN(chromaticity[1]) || (chromaticity[1] < 0.0) || |
2316 | 295 | MAGICK_ISNAN(chromaticity[2]) || (chromaticity[2] < 0.0) || |
2317 | 295 | MAGICK_ISNAN(chromaticity[3]) || (chromaticity[3] < 0.0) || |
2318 | 295 | MAGICK_ISNAN(chromaticity[4]) || (chromaticity[4] < 0.0) || |
2319 | 295 | MAGICK_ISNAN(chromaticity[5]) || (chromaticity[5] < 0.0)) |
2320 | 64 | { |
2321 | 64 | if (logging) |
2322 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2323 | 0 | "Primary Chromaticities: Is corrupt!"); |
2324 | 64 | } |
2325 | 231 | else |
2326 | 231 | { |
2327 | 231 | image->chromaticity.red_primary.x=chromaticity[0]; |
2328 | 231 | image->chromaticity.red_primary.y=chromaticity[1]; |
2329 | 231 | image->chromaticity.green_primary.x=chromaticity[2]; |
2330 | 231 | image->chromaticity.green_primary.y=chromaticity[3]; |
2331 | 231 | image->chromaticity.blue_primary.x=chromaticity[4]; |
2332 | 231 | image->chromaticity.blue_primary.y=chromaticity[5]; |
2333 | 231 | } |
2334 | 295 | } |
2335 | 295 | } |
2336 | 39.7k | { |
2337 | | /* |
2338 | | Retrieve embedded profiles. |
2339 | | */ |
2340 | 39.7k | uint32 |
2341 | 39.7k | length; |
2342 | | /* |
2343 | | ICC ICM color profile. |
2344 | | */ |
2345 | 39.7k | #if defined(TIFFTAG_ICCPROFILE) |
2346 | 39.7k | if (TIFFGetField(tiff,TIFFTAG_ICCPROFILE,&length,&text) == 1) |
2347 | 33 | { |
2348 | 33 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2349 | 33 | "ICC ICM embedded profile with length %lu bytes", |
2350 | 33 | (unsigned long)length); |
2351 | 33 | (void) SetImageProfile(image,"ICM",(unsigned char *) text,(size_t) length); |
2352 | 33 | } |
2353 | 39.7k | #endif /* defined(TIFFTAG_ICCPROFILE) */ |
2354 | | /* |
2355 | | IPTC/Photoshop profile. |
2356 | | */ |
2357 | 39.7k | #if defined(TIFFTAG_PHOTOSHOP) |
2358 | | /* Photoshop profile (with embedded IPTC profile) */ |
2359 | 39.7k | if (TIFFGetField(tiff,TIFFTAG_PHOTOSHOP,&length,&text) == 1) |
2360 | 112 | { |
2361 | 112 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2362 | 112 | "Photoshop embedded profile with length %lu bytes", |
2363 | 112 | (unsigned long) length); |
2364 | 112 | (void) ReadNewsProfile((unsigned char *) text,(long) length,image,TIFFTAG_PHOTOSHOP); |
2365 | 112 | } |
2366 | | #elif defined(TIFFTAG_RICHTIFFIPTC) |
2367 | | /* IPTC TAG from RichTIFF specifications */ |
2368 | | if (TIFFGetField(tiff,TIFFTAG_RICHTIFFIPTC,&length,&text) == 1) |
2369 | | { |
2370 | | if (TIFFIsByteSwapped(tiff)) |
2371 | | TIFFSwabArrayOfLong((uint32 *) text,length); |
2372 | | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2373 | | "IPTC Newsphoto embedded profile with length %u bytes",length); |
2374 | | ReadNewsProfile((unsigned char *) text,length,image,TIFFTAG_RICHTIFFIPTC); |
2375 | | } |
2376 | | #endif |
2377 | | /* |
2378 | | XML XMP profile. |
2379 | | */ |
2380 | 39.7k | #if defined(TIFFTAG_XMLPACKET) |
2381 | | /* %XML packet [Adobe XMP Specification, Janary 2004] */ |
2382 | 39.7k | if (TIFFGetField(tiff,TIFFTAG_XMLPACKET,&length,&text) == 1) |
2383 | 40 | { |
2384 | 40 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2385 | 40 | "XMP embedded profile with length %lu bytes", |
2386 | 40 | (unsigned long) length); |
2387 | 40 | SetImageProfile(image,"XMP",(unsigned char *) text,(size_t) length); |
2388 | 40 | } |
2389 | 39.7k | #endif |
2390 | 39.7k | } |
2391 | | /* |
2392 | | Map from TIFF compression tags to GraphicsMagick equivalents |
2393 | | as well as estimate a maximum compression ratio (for |
2394 | | validating scanline/strip/tile allocation requests). |
2395 | | */ |
2396 | 39.7k | switch (compress_tag) |
2397 | 39.7k | { |
2398 | 6.44k | case COMPRESSION_NONE: |
2399 | 6.44k | image->compression=NoCompression; |
2400 | 6.44k | break; |
2401 | 2.86k | case COMPRESSION_CCITTFAX3: |
2402 | 2.86k | image->compression=FaxCompression; |
2403 | 2.86k | break; |
2404 | 3.88k | case COMPRESSION_CCITTFAX4: |
2405 | 3.88k | image->compression=Group4Compression; |
2406 | 3.88k | break; |
2407 | 8.26k | case COMPRESSION_JPEG: |
2408 | 8.26k | image->compression=JPEGCompression; |
2409 | 8.26k | break; |
2410 | 0 | case COMPRESSION_OJPEG: |
2411 | 0 | image->compression=JPEGCompression; |
2412 | 0 | break; |
2413 | 1.52k | case COMPRESSION_LZW: |
2414 | 1.52k | image->compression=LZWCompression; |
2415 | 1.52k | break; |
2416 | 0 | #if defined(COMPRESSION_LZMA) |
2417 | 26 | case COMPRESSION_LZMA: |
2418 | 26 | image->compression=LZMACompression; |
2419 | 26 | break; |
2420 | 0 | #endif /* defined(COMPRESSION_LZMA) */ |
2421 | 1.11k | case COMPRESSION_DEFLATE: |
2422 | 1.11k | image->compression=ZipCompression; |
2423 | 1.11k | break; |
2424 | 2.12k | case COMPRESSION_ADOBE_DEFLATE: |
2425 | 2.12k | image->compression=ZipCompression; |
2426 | 2.12k | break; |
2427 | 0 | #if defined(COMPRESSION_ZSTD) |
2428 | 4.14k | case COMPRESSION_ZSTD: |
2429 | 4.14k | image->compression=ZSTDCompression; |
2430 | 4.14k | break; |
2431 | 0 | #endif /* defined(COMPRESSION_ZSTD) */ |
2432 | 0 | #if defined(COMPRESSION_WEBP) |
2433 | 5.15k | case COMPRESSION_WEBP: |
2434 | 5.15k | image->compression=WebPCompression; |
2435 | 5.15k | break; |
2436 | 0 | #endif /* if defined(COMPRESSION_WEBP) */ |
2437 | 4.24k | default: |
2438 | 4.24k | image->compression=NoCompression; |
2439 | 4.24k | break; |
2440 | 39.7k | } |
2441 | 39.7k | image->columns=width; |
2442 | 39.7k | image->rows=height; |
2443 | 39.7k | image->depth=bits_per_sample; |
2444 | | |
2445 | 39.7k | if (image->scene != 0) |
2446 | 0 | status=MagickMonitorFormatted(image->scene-1,image->scene, |
2447 | 0 | &image->exception, |
2448 | 0 | LoadImageText,image->filename, |
2449 | 0 | image->columns,image->rows); |
2450 | | |
2451 | | /* |
2452 | | Obtain information about any extra samples. |
2453 | | FIXME samples_per_pixel = 4 and 1 extra sample which is 'unspecified' |
2454 | | */ |
2455 | 39.7k | extra_samples=0; |
2456 | 39.7k | if (TIFFGetField(tiff,TIFFTAG_EXTRASAMPLES,&extra_samples, |
2457 | 39.7k | &sample_info) == 1) |
2458 | 4.38k | { |
2459 | 4.38k | int |
2460 | 4.38k | sample_index; |
2461 | | |
2462 | 4.38k | if (extra_samples != 0) |
2463 | 4.31k | { |
2464 | 4.31k | if (sample_info[0] == EXTRASAMPLE_UNSPECIFIED) |
2465 | 210 | { |
2466 | 210 | alpha_type=UnspecifiedAlpha; |
2467 | 210 | } |
2468 | 4.10k | else if (sample_info[0] == EXTRASAMPLE_UNASSALPHA) |
2469 | 2.46k | { |
2470 | 2.46k | alpha_type=UnassociatedAlpha; |
2471 | 2.46k | } |
2472 | 1.64k | else if (sample_info[0] == EXTRASAMPLE_ASSOCALPHA) |
2473 | 1.64k | { |
2474 | 1.64k | alpha_type=AssociatedAlpha; |
2475 | 1.64k | } |
2476 | 4.31k | } |
2477 | 4.38k | if (image->logging) |
2478 | 1.34M | for (sample_index=0 ; sample_index < extra_samples; sample_index++) |
2479 | 1.34M | { |
2480 | 1.34M | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2481 | 1.34M | "Extra sample %u contains %s",sample_index+1, |
2482 | 1.34M | ExtraSampleToString(sample_info[sample_index])); |
2483 | 1.34M | } |
2484 | 4.38k | } |
2485 | | /* |
2486 | | Report RGBA images which may be improperly marked. |
2487 | | */ |
2488 | 39.7k | if ((image->logging) && (extra_samples == 0)) |
2489 | 35.4k | if (((PHOTOMETRIC_RGB == photometric) && (samples_per_pixel == 4)) || |
2490 | 34.6k | (((PHOTOMETRIC_MINISWHITE == photometric) || (PHOTOMETRIC_MINISBLACK == photometric)) && (samples_per_pixel == 2))) |
2491 | 1.18k | { |
2492 | 1.18k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2493 | 1.18k | "Photometric is %s but %u samples/pixel and %u extra_samples provided!", |
2494 | 1.18k | PhotometricTagToString(photometric),samples_per_pixel, extra_samples); |
2495 | 1.18k | } |
2496 | | /* |
2497 | | Deal with files which are marked as unspecified alpha, but |
2498 | | they should be unassociated alpha. |
2499 | | */ |
2500 | 39.7k | if (((extra_samples == 1) && (sample_info[0] == EXTRASAMPLE_UNSPECIFIED)) && |
2501 | 172 | ( |
2502 | 172 | ((samples_per_pixel == 2) && ((PHOTOMETRIC_MINISWHITE == photometric) || (PHOTOMETRIC_MINISBLACK == photometric))) || |
2503 | 72 | ((samples_per_pixel == 4) && (PHOTOMETRIC_RGB == photometric)) || |
2504 | 44 | ((samples_per_pixel == 5) && (PHOTOMETRIC_SEPARATED == photometric)) |
2505 | 172 | ) |
2506 | 39.7k | ) |
2507 | 137 | { |
2508 | 137 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2509 | 137 | "Promoting UnspecifiedAlpha to UnassociatedAlpha"); |
2510 | 137 | alpha_type=UnassociatedAlpha; |
2511 | 137 | image->matte=True; |
2512 | 137 | } |
2513 | | /* |
2514 | | Allow the user to over-ride the alpha channel type. |
2515 | | */ |
2516 | 39.7k | if (image->matte) |
2517 | 137 | { |
2518 | 137 | if ((definition_value=AccessDefinition(image_info,"tiff","alpha"))) |
2519 | 0 | { |
2520 | 0 | if (LocaleCompare(definition_value,"unspecified") == 0) |
2521 | 0 | alpha_type=UnspecifiedAlpha; |
2522 | 0 | else if (LocaleCompare(definition_value,"associated") == 0) |
2523 | 0 | alpha_type=AssociatedAlpha; |
2524 | 0 | else if (LocaleCompare(definition_value,"unassociated") == 0) |
2525 | 0 | alpha_type=UnassociatedAlpha; |
2526 | 0 | } |
2527 | 137 | } |
2528 | | |
2529 | | /* |
2530 | | Does alpha type deserve a matte channel? |
2531 | | */ |
2532 | 39.7k | switch (alpha_type) |
2533 | 39.7k | { |
2534 | 35.5k | case UnspecifiedAlpha: |
2535 | 35.5k | break; |
2536 | 2.60k | case UnassociatedAlpha: |
2537 | 2.60k | image->matte=True; |
2538 | 2.60k | break; |
2539 | 1.64k | case AssociatedAlpha: |
2540 | 1.64k | image->matte=True; |
2541 | 1.64k | break; |
2542 | 0 | default: |
2543 | 0 | break; |
2544 | 39.7k | } |
2545 | | |
2546 | | /* |
2547 | | Describe how the alpha channel will be treated. |
2548 | | */ |
2549 | 39.7k | if (image->matte) |
2550 | 4.24k | { |
2551 | 4.24k | char |
2552 | 4.24k | alpha_string[MaxTextExtent]; |
2553 | | |
2554 | 4.24k | switch (alpha_type) |
2555 | 4.24k | { |
2556 | 0 | default: |
2557 | 0 | case UnspecifiedAlpha: |
2558 | 0 | (void) strlcpy(alpha_string,"Unspecified",MaxTextExtent); |
2559 | 0 | break; |
2560 | 2.60k | case UnassociatedAlpha: |
2561 | 2.60k | (void) strlcpy(alpha_string,"Unassociated",MaxTextExtent); |
2562 | 2.60k | break; |
2563 | 1.64k | case AssociatedAlpha: |
2564 | 1.64k | (void) strlcpy(alpha_string,"Associated",MaxTextExtent); |
2565 | 1.64k | break; |
2566 | 4.24k | } |
2567 | 4.24k | (void) SetImageAttribute(image,"alpha",alpha_string); |
2568 | 4.24k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2569 | 4.24k | "Image has a matte channel of type: %s", |
2570 | 4.24k | alpha_string); |
2571 | 4.24k | } |
2572 | | |
2573 | 39.7k | if (units == RESUNIT_INCH) |
2574 | 39.1k | image->units=PixelsPerInchResolution; |
2575 | 39.7k | if (units == RESUNIT_CENTIMETER) |
2576 | 130 | image->units=PixelsPerCentimeterResolution; |
2577 | 39.7k | { |
2578 | 39.7k | uint16 |
2579 | 39.7k | pagenumber; |
2580 | | |
2581 | 39.7k | pagenumber=(unsigned short) image->scene; |
2582 | 39.7k | if (TIFFGetFieldDefaulted(tiff,TIFFTAG_PAGENUMBER,&pagenumber,&pages) == 1) |
2583 | 629 | image->scene=pagenumber; |
2584 | 39.7k | } |
2585 | | |
2586 | | /* |
2587 | | Convert TIFF tags to text attributes |
2588 | | https://gitlab.com/libtiff/libtiff/-/issues/575 |
2589 | | */ |
2590 | 39.7k | { |
2591 | 39.7k | static const struct |
2592 | 39.7k | { |
2593 | 39.7k | uint32 tag; |
2594 | 39.7k | const char name[14]; |
2595 | 39.7k | } text_tags[] = |
2596 | 39.7k | { |
2597 | 39.7k | { TIFFTAG_ARTIST, "artist" }, |
2598 | 39.7k | { TIFFTAG_COPYRIGHT, "copyright" }, |
2599 | 39.7k | { TIFFTAG_DATETIME, "timestamp" }, |
2600 | 39.7k | { TIFFTAG_DOCUMENTNAME, "document" }, |
2601 | 39.7k | { TIFFTAG_HOSTCOMPUTER, "hostcomputer" }, |
2602 | 39.7k | { TIFFTAG_IMAGEDESCRIPTION, "comment" }, |
2603 | 39.7k | { TIFFTAG_MAKE, "make" }, |
2604 | 39.7k | { TIFFTAG_MODEL, "model" }, |
2605 | 39.7k | { TIFFTAG_PAGENAME, "label" }, |
2606 | 39.7k | { TIFFTAG_SOFTWARE, "software" }, |
2607 | 39.7k | #if 1 |
2608 | | /* |
2609 | | These three cause TIFFFieldWithTag() to return NULL and |
2610 | | therefore produce "TIFF Warning: Warning, unknown tag" exceptions |
2611 | | while reading! |
2612 | | */ |
2613 | 39.7k | { TIFFTAG_OPIIMAGEID, "imageid" }, |
2614 | 39.7k | { 33423, "kodak-33423" }, |
2615 | 39.7k | { 36867, "kodak-36867" } |
2616 | 39.7k | #endif |
2617 | 39.7k | }; |
2618 | | |
2619 | 557k | for (i = 0; i < ArraySize(text_tags); i++) |
2620 | 517k | { |
2621 | 517k | const uint32 tag = text_tags[i].tag; |
2622 | 517k | const char *tag_name = text_tags[i].name; |
2623 | 517k | int field_passcount=1; /* "Unsupported" tags return two arguments */ |
2624 | | #if TIFFLIB_VERSION <= 20111221 |
2625 | | /* |
2626 | | Before tiff 4.0.0 (20111221), TIFFFieldWithTag returned |
2627 | | TIFFFieldInfo * which provides field_passcount |
2628 | | */ |
2629 | | const TIFFFieldInfo* tiff_field=TIFFFieldWithTag(tiff,tag); |
2630 | | if (tiff_field != (const TIFFFieldInfo *)) |
2631 | | field_passcount=tiff_field->field_passcount; |
2632 | | else |
2633 | | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2634 | | "TIFFFieldWithTag() returns NULL for tag %u \"%s\"", tag, tag_name); |
2635 | | #else |
2636 | 517k | const TIFFField *tiff_field=TIFFFieldWithTag(tiff,tag); |
2637 | 517k | if (tiff_field != (const TIFFField *) NULL) |
2638 | 397k | field_passcount=TIFFFieldPassCount(tiff_field); |
2639 | 119k | else |
2640 | 119k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2641 | 119k | "TIFFFieldWithTag() returns NULL for tag %u \"%s\"", tag, tag_name); |
2642 | 517k | #endif |
2643 | | #if 0 |
2644 | | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2645 | | "Field pass count for tag %u \"%s\" is %d", tag, tag_name, field_passcount); |
2646 | | #endif |
2647 | 517k | if (field_passcount) |
2648 | 119k | { |
2649 | 119k | if ((TIFFGetField(tiff,tag,&count,&text) == 1) && (count) && (text != (const char*) NULL)) |
2650 | 34 | CopySizedFieldToAttribute(tag_name,count,text); |
2651 | 119k | } |
2652 | 397k | else |
2653 | 397k | { |
2654 | 397k | if ((TIFFGetField(tiff,tag,&text) == 1) && (text != (const char*) NULL)) |
2655 | 11.5k | (void) SetImageAttribute(image,tag_name,text); |
2656 | 397k | } |
2657 | 517k | } |
2658 | 39.7k | } |
2659 | | |
2660 | 39.7k | if ((photometric == PHOTOMETRIC_PALETTE) || |
2661 | 37.9k | ((photometric == PHOTOMETRIC_MINISWHITE || |
2662 | 26.1k | photometric == PHOTOMETRIC_MINISBLACK) && |
2663 | 22.8k | ((image_info->type == PaletteType) || |
2664 | 22.8k | (image_info->type == PaletteMatteType)) && |
2665 | 0 | (MaxColormapSize > MaxValueGivenBits(bits_per_sample)) |
2666 | 37.9k | ) |
2667 | 39.7k | ) |
2668 | 1.83k | { |
2669 | | /* |
2670 | | Palette image |
2671 | | */ |
2672 | 1.83k | if (MaxColormapSize > MaxValueGivenBits(bits_per_sample)) |
2673 | 1.83k | { |
2674 | 1.83k | (void) InitializeImageColormap(image,tiff); |
2675 | 1.83k | } |
2676 | 0 | else |
2677 | 0 | { |
2678 | 0 | ThrowTIFFReaderException(CoderError,ColormapTooLarge,image); |
2679 | 0 | } |
2680 | 1.83k | } |
2681 | | |
2682 | | /* |
2683 | | Quit if in "ping" mode and we are outside of requested range, |
2684 | | otherwise continue to next frame. |
2685 | | */ |
2686 | 39.7k | if (image_info->ping) |
2687 | 0 | { |
2688 | 0 | if (image_info->subrange != 0) |
2689 | 0 | if (image->scene >= (image_info->subimage+image_info->subrange-1)) |
2690 | 0 | break; |
2691 | | |
2692 | 0 | goto read_next_frame; |
2693 | 0 | } |
2694 | | |
2695 | 39.7k | if (CheckImagePixelLimits(image, exception) != MagickPass) |
2696 | 1.40k | { |
2697 | 1.40k | ThrowTIFFReaderException(ResourceLimitError,ImagePixelLimitExceeded,image); |
2698 | 0 | } |
2699 | | |
2700 | | /* |
2701 | | Verify that the bits per sample, samples per pixel, and |
2702 | | photometric are suitable for the claimed compressor |
2703 | | */ |
2704 | 38.3k | #if defined(COMPRESSION_CCITTFAX3) |
2705 | 38.3k | if (COMPRESSION_CCITTFAX3 == compress_tag) |
2706 | 2.85k | { |
2707 | 2.85k | if (1 != bits_per_sample) |
2708 | 5 | { |
2709 | 5 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2710 | 5 | "%s compression requires 1 bits per sample!", |
2711 | 5 | CompressionTagToString(compress_tag)); |
2712 | 5 | ThrowTIFFReaderException(CorruptImageError,ImproperImageHeader,image); |
2713 | 0 | } |
2714 | 2.84k | if ((PHOTOMETRIC_MINISBLACK != photometric) && (PHOTOMETRIC_MINISWHITE != photometric)) |
2715 | 20 | { |
2716 | 20 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2717 | 20 | "%s compression requires photometric of minisblack or miniswhite!", |
2718 | 20 | CompressionTagToString(compress_tag)); |
2719 | 20 | ThrowTIFFReaderException(CorruptImageError,ImproperImageHeader,image); |
2720 | 0 | } |
2721 | 2.84k | } |
2722 | 38.3k | #endif /* if defined(COMPRESSION_CCITTFAX3) */ |
2723 | 38.3k | #if defined(COMPRESSION_CCITTFAX4) |
2724 | 38.3k | if (COMPRESSION_CCITTFAX4 == compress_tag) |
2725 | 3.75k | { |
2726 | 3.75k | if (1 != bits_per_sample) |
2727 | 4 | { |
2728 | 4 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2729 | 4 | "%s compression requires 1 bits per sample!", |
2730 | 4 | CompressionTagToString(compress_tag)); |
2731 | 4 | ThrowTIFFReaderException(CorruptImageError,ImproperImageHeader,image); |
2732 | 0 | } |
2733 | 3.75k | if ((PHOTOMETRIC_MINISBLACK != photometric) && (PHOTOMETRIC_MINISWHITE != photometric)) |
2734 | 23 | { |
2735 | 23 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2736 | 23 | "%s compression requires photometric of minisblack or miniswhite!", |
2737 | 23 | CompressionTagToString(compress_tag)); |
2738 | 23 | ThrowTIFFReaderException(CorruptImageError,ImproperImageHeader,image); |
2739 | 0 | } |
2740 | 3.75k | } |
2741 | 38.3k | #endif /* if defined(COMPRESSION_CCITTFAX4) */ |
2742 | 38.3k | #if defined(COMPRESSION_JBIG) |
2743 | 38.3k | if (COMPRESSION_JBIG == compress_tag) |
2744 | 0 | { |
2745 | 0 | if (1 != bits_per_sample) |
2746 | 0 | { |
2747 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2748 | 0 | "%s compression requires 1 bits per sample!", |
2749 | 0 | CompressionTagToString(compress_tag)); |
2750 | 0 | ThrowTIFFReaderException(CorruptImageError,ImproperImageHeader,image); |
2751 | 0 | } |
2752 | 0 | if ((PHOTOMETRIC_MINISBLACK != photometric) && (PHOTOMETRIC_MINISWHITE != photometric)) |
2753 | 0 | { |
2754 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2755 | 0 | "%s compression requires photometric of minisblack or miniswhite!", |
2756 | 0 | CompressionTagToString(compress_tag)); |
2757 | 0 | ThrowTIFFReaderException(CorruptImageError,ImproperImageHeader,image); |
2758 | 0 | } |
2759 | 0 | } |
2760 | 38.3k | #endif /* if defined(COMPRESSION_JBIG) */ |
2761 | 38.3k | #if defined(COMPRESSION_WEBP) |
2762 | 38.3k | if (COMPRESSION_WEBP == compress_tag) |
2763 | 5.14k | { |
2764 | 5.14k | if (8 != bits_per_sample) |
2765 | 10 | { |
2766 | 10 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2767 | 10 | "%s compression requires 8 bits per sample!", |
2768 | 10 | CompressionTagToString(compress_tag)); |
2769 | 10 | ThrowTIFFReaderException(CorruptImageError,ImproperImageHeader,image); |
2770 | 0 | } |
2771 | 5.13k | if ((3 != samples_per_pixel) && (4 != samples_per_pixel)) |
2772 | 11 | { |
2773 | 11 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2774 | 11 | "%s compression requires 3 or 4 samples per pixel!", |
2775 | 11 | CompressionTagToString(compress_tag)); |
2776 | 11 | ThrowTIFFReaderException(CorruptImageError,ImproperImageHeader,image); |
2777 | 0 | } |
2778 | 5.12k | if (PHOTOMETRIC_RGB != photometric) |
2779 | 3 | { |
2780 | 3 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2781 | 3 | "%s compression requires photometric RGB!", |
2782 | 3 | CompressionTagToString(compress_tag)); |
2783 | 3 | ThrowTIFFReaderException(CorruptImageError,ImproperImageHeader,image); |
2784 | 0 | } |
2785 | 5.12k | } |
2786 | 38.3k | #endif /* if defined(COMPRESSION_WEBP) */ |
2787 | | |
2788 | | /* |
2789 | | Check if the bits-per-sample value is supported by the |
2790 | | implementation before proceeding. |
2791 | | |
2792 | | Currently we support a range of 1-32, and 64 bits if the |
2793 | | samples are float. |
2794 | | */ |
2795 | 38.3k | if (!((sample_format == SAMPLEFORMAT_IEEEFP && bits_per_sample == 64) || |
2796 | 37.9k | ((bits_per_sample > 0) && (bits_per_sample <= 32)))) |
2797 | 46 | { |
2798 | 46 | ThrowTIFFReaderException(CoderError,UnsupportedBitsPerSample,image); |
2799 | 0 | } |
2800 | | |
2801 | | /* |
2802 | | Check for excessive samples per pixel or excessive extra samples. |
2803 | | */ |
2804 | 38.2k | if ((samples_per_pixel > 8U) || (extra_samples > 8U)) |
2805 | 51 | { |
2806 | 51 | ThrowTIFFReaderException(CoderError,UnsupportedSamplesPerPixel,image); |
2807 | 0 | } |
2808 | | |
2809 | | /* |
2810 | | Determine which method to use for reading pixels. |
2811 | | */ |
2812 | 38.2k | { |
2813 | 38.2k | int |
2814 | 38.2k | quantum_samples; |
2815 | | |
2816 | 38.2k | QuantumType |
2817 | 38.2k | quantum_type; |
2818 | | |
2819 | 38.2k | if ((samples_per_pixel > 1) && |
2820 | 15.3k | (compress_tag == COMPRESSION_JPEG) && |
2821 | 1.64k | (photometric == PHOTOMETRIC_YCBCR)) |
2822 | 1.09k | { |
2823 | | /* Following hack avoids the error message "Application |
2824 | | transferred too many scanlines. (JPEGLib)." caused by |
2825 | | YCbCr subsampling, but it returns data in RGB rather |
2826 | | than YCbCr. */ |
2827 | 1.09k | if (logging) |
2828 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2829 | 0 | "Resetting photometric from %s to %s for JPEG RGB", |
2830 | 0 | PhotometricTagToString(photometric), |
2831 | 0 | PhotometricTagToString(PHOTOMETRIC_RGB)); |
2832 | 1.09k | (void) TIFFSetField( tiff, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB ); |
2833 | 1.09k | photometric=PHOTOMETRIC_RGB; |
2834 | 1.09k | } |
2835 | 38.2k | method=RGBAPuntMethod; |
2836 | 38.2k | quantum_type=UndefinedQuantum; |
2837 | 38.2k | quantum_samples=0; |
2838 | 38.2k | if (QuantumTransferMode(image,photometric,compress_tag,sample_format, |
2839 | 38.2k | samples_per_pixel,planar_config,0,&quantum_type, |
2840 | 38.2k | &quantum_samples,exception) |
2841 | 38.2k | == MagickPass) |
2842 | 32.4k | { |
2843 | 32.4k | method=ScanLineMethod; |
2844 | 32.4k | if ((compress_tag == COMPRESSION_JPEG) || |
2845 | 24.3k | (compress_tag == COMPRESSION_OJPEG)) |
2846 | 8.14k | { |
2847 | 8.14k | if (TIFFIsTiled(tiff)) |
2848 | 475 | method=TiledMethod; |
2849 | 7.67k | else |
2850 | 7.67k | method=StrippedMethod; |
2851 | 8.14k | } |
2852 | 24.3k | #if defined(COMPRESSION_JBIG) |
2853 | 24.3k | else if (compress_tag == COMPRESSION_JBIG) |
2854 | | /* libtiff jbig coder only handles strips */ |
2855 | 0 | method=StrippedMethod; |
2856 | 24.3k | #endif |
2857 | 24.3k | else if (TIFFIsTiled(tiff)) |
2858 | 2.84k | method=TiledMethod; |
2859 | 21.4k | else if (TIFFStripSize(tiff) <= 1024*256) |
2860 | 19.0k | method=StrippedMethod; |
2861 | 32.4k | if (photometric == PHOTOMETRIC_MINISWHITE) |
2862 | 10.8k | import_options.grayscale_miniswhite=MagickTrue; |
2863 | 32.4k | } |
2864 | 5.76k | else if (exception->severity < ErrorException) |
2865 | 5.71k | { |
2866 | 5.71k | if (TIFFIsTiled(tiff)) |
2867 | 983 | method=RGBATiledMethod; |
2868 | 4.73k | else if (TIFFGetField(tiff,TIFFTAG_ROWSPERSTRIP,&rows_per_strip) == 1) |
2869 | 3.02k | method=RGBAStrippedMethod; |
2870 | 5.71k | } |
2871 | 47 | else |
2872 | 47 | { |
2873 | | /* |
2874 | | QuantumTransferMode reported an error |
2875 | | */ |
2876 | 47 | ThrowTIFFReaderException(CorruptImageError,ImproperImageHeader,image); |
2877 | 0 | } |
2878 | 38.2k | } |
2879 | | |
2880 | | /* |
2881 | | Set extra import options for floating point. |
2882 | | */ |
2883 | 38.1k | if (sample_format == SAMPLEFORMAT_IEEEFP) |
2884 | 2.73k | { |
2885 | 2.73k | double |
2886 | 2.73k | value; |
2887 | | |
2888 | 2.73k | import_options.sample_type=FloatQuantumSampleType; |
2889 | 2.73k | if (TIFFGetField(tiff,TIFFTAG_SMINSAMPLEVALUE,&value) == 1) |
2890 | 79 | import_options.double_minvalue=value; |
2891 | 2.73k | if (TIFFGetField(tiff,TIFFTAG_SMAXSAMPLEVALUE,&value) == 1) |
2892 | 161 | import_options.double_maxvalue=value; |
2893 | 2.73k | if ((definition_value=AccessDefinition(image_info,"tiff","min-sample-value"))) |
2894 | 0 | import_options.double_minvalue=strtod(definition_value,(char **)NULL); |
2895 | 2.73k | if ((definition_value=AccessDefinition(image_info,"tiff","max-sample-value"))) |
2896 | 0 | import_options.double_maxvalue=strtod(definition_value,(char **)NULL); |
2897 | 2.73k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2898 | 2.73k | "Using min sample value %g, max sample value %g", |
2899 | 2.73k | import_options.double_minvalue, |
2900 | 2.73k | import_options.double_maxvalue); |
2901 | 2.73k | } |
2902 | | |
2903 | | /* |
2904 | | For sample sizes matching a CPU native word, use native endian |
2905 | | order for import. |
2906 | | */ |
2907 | 38.1k | if ((16 == bits_per_sample) || (32 == bits_per_sample) || (64 == bits_per_sample)) |
2908 | 3.96k | import_options.endian=NativeEndian; |
2909 | | |
2910 | 38.1k | switch (method) |
2911 | 38.1k | { |
2912 | 2.38k | case ScanLineMethod: |
2913 | 2.38k | { |
2914 | | /* |
2915 | | Read TIFF image as scanlines. |
2916 | | */ |
2917 | 2.38k | unsigned char |
2918 | 2.38k | *scanline = (unsigned char *) NULL; |
2919 | | |
2920 | 2.38k | int |
2921 | 2.38k | max_sample, |
2922 | 2.38k | quantum_samples, |
2923 | 2.38k | sample; |
2924 | | |
2925 | 2.38k | tsize_t |
2926 | 2.38k | scanline_size = 0; |
2927 | | |
2928 | 2.38k | QuantumType |
2929 | 2.38k | quantum_type; |
2930 | | |
2931 | 2.38k | if (logging) |
2932 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2933 | 0 | "Using scanline %s read method with %u bits per sample", |
2934 | 0 | PhotometricTagToString(photometric),bits_per_sample); |
2935 | | /* |
2936 | | Prepare for separate/contiguous retrieval. |
2937 | | */ |
2938 | 2.38k | max_sample=1; |
2939 | 2.38k | if (planar_config == PLANARCONFIG_SEPARATE) |
2940 | 12 | { |
2941 | 12 | if (QuantumTransferMode(image,photometric,compress_tag, |
2942 | 12 | sample_format,samples_per_pixel, |
2943 | 12 | PLANARCONFIG_CONTIG,0, |
2944 | 12 | &quantum_type,&quantum_samples, |
2945 | 12 | exception) |
2946 | 12 | != MagickPass) |
2947 | 3 | ThrowTIFFReaderException(CorruptImageError, |
2948 | 12 | ImproperImageHeader,image); |
2949 | 9 | max_sample=quantum_samples; |
2950 | 9 | } |
2951 | | /* |
2952 | | Allocate memory for one scanline. |
2953 | | */ |
2954 | 2.37k | scanline_size=TIFFScanlineSize(tiff); |
2955 | 2.37k | if (scanline_size <= 0) |
2956 | 0 | { |
2957 | 0 | status=MagickFail; |
2958 | 0 | break; |
2959 | 0 | } |
2960 | | /* |
2961 | | Scale up to size of 32-bit word. |
2962 | | */ |
2963 | 2.37k | scanline_size=RoundUpToAlignment(scanline_size,sizeof(magick_int32_t)); |
2964 | | |
2965 | 2.37k | if (logging) |
2966 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2967 | 0 | "Request to allocate scanline buffer of " |
2968 | 0 | "%" MAGICK_SIZE_T_F "u bytes", |
2969 | 0 | (MAGICK_SIZE_T) scanline_size); |
2970 | | |
2971 | | /* |
2972 | | Rationalize memory request based on file size |
2973 | | */ |
2974 | 2.37k | if (scanline_size > file_size*max_compress_ratio) |
2975 | 0 | { |
2976 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
2977 | 0 | "Unreasonable allocation size " |
2978 | 0 | "(ratio of alloc to file size %g)", |
2979 | 0 | (double) scanline_size/file_size); |
2980 | 0 | ThrowTIFFReaderException(CorruptImageError,InsufficientImageDataInFile, |
2981 | 0 | image); |
2982 | 0 | } |
2983 | | |
2984 | 2.37k | scanline=MagickAllocateResourceLimitedClearedMemory(unsigned char *,(size_t) scanline_size); |
2985 | 2.37k | if (scanline == (unsigned char *) NULL) |
2986 | 0 | { |
2987 | 0 | ThrowTIFFReaderException(ResourceLimitError,MemoryAllocationFailed, |
2988 | 0 | image); |
2989 | 0 | } |
2990 | 4.75k | for (sample=0; (status != MagickFail) && (sample < max_sample); sample++) |
2991 | 2.37k | { |
2992 | 795k | for (y=0; (status != MagickFail) && (y < image->rows); y++) |
2993 | 795k | { |
2994 | | /* |
2995 | | Obtain a scanline |
2996 | | */ |
2997 | 795k | if (TIFFReadScanline(tiff,(char *) scanline,(uint32) y,sample) == -1) |
2998 | 1.69k | { |
2999 | 1.69k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3000 | 1.69k | "TIFFReadScanline() failed!"); |
3001 | 1.69k | status=MagickFail; |
3002 | 1.69k | break; |
3003 | 1.69k | } |
3004 | 793k | if (image->exception.severity >= ErrorException) |
3005 | 0 | { |
3006 | 0 | status=MagickFail; |
3007 | 0 | break; |
3008 | 0 | } |
3009 | 793k | #if !defined(WORDS_BIGENDIAN) |
3010 | 793k | if (24 == bits_per_sample) |
3011 | 14 | SwabDataToBigEndian(bits_per_sample,scanline,scanline_size); |
3012 | 793k | #endif |
3013 | | /* |
3014 | | Determine quantum parse method. |
3015 | | */ |
3016 | 793k | if (QuantumTransferMode(image,photometric,compress_tag, |
3017 | 793k | sample_format, |
3018 | 793k | samples_per_pixel,planar_config, |
3019 | 793k | sample, |
3020 | 793k | &quantum_type,&quantum_samples, |
3021 | 793k | exception) |
3022 | 793k | == MagickFail) |
3023 | 0 | { |
3024 | 0 | status=MagickFail; |
3025 | 0 | break; |
3026 | 0 | } |
3027 | | /* |
3028 | | Compact scanline to only contain raster data. |
3029 | | */ |
3030 | 793k | if ((samples_per_pixel > quantum_samples) && |
3031 | 35.0k | (planar_config == PLANARCONFIG_CONTIG)) |
3032 | 35.0k | CompactSamples(image->columns, bits_per_sample, |
3033 | 35.0k | samples_per_pixel, quantum_samples, scanline); |
3034 | | /* |
3035 | | Import scanline into image. |
3036 | | */ |
3037 | 793k | if (sample == 0) |
3038 | 793k | q=SetImagePixelsEx(image,0,y,image->columns,1,exception); |
3039 | 0 | else |
3040 | 0 | q=GetImagePixelsEx(image,0,y,image->columns,1,exception); |
3041 | 793k | if (q == (PixelPacket *) NULL) |
3042 | 0 | { |
3043 | 0 | status=MagickFail; |
3044 | 0 | break; |
3045 | 0 | } |
3046 | 793k | if ((sample == 0) && (max_sample > 1)) |
3047 | 0 | (void) memset(q,0,image->columns*sizeof(PixelPacket)); |
3048 | 793k | if (ImportImagePixelArea(image,quantum_type,bits_per_sample,scanline, |
3049 | 793k | &import_options,0) == MagickFail) |
3050 | 0 | { |
3051 | 0 | CopyException(exception,&image->exception); |
3052 | 0 | status=MagickFail; |
3053 | 0 | break; |
3054 | 0 | } |
3055 | | /* |
3056 | | Disassociate alpha from pixels if necessary. |
3057 | | */ |
3058 | 793k | if ((PHOTOMETRIC_RGB == photometric) && |
3059 | 101k | (image->matte) && (alpha_type == AssociatedAlpha) && |
3060 | 808 | (sample == (max_sample-1))) |
3061 | 808 | DisassociateAlphaRegion(image); |
3062 | | /* |
3063 | | Save our updates. |
3064 | | */ |
3065 | 793k | if (!SyncImagePixelsEx(image,exception)) |
3066 | 0 | { |
3067 | 0 | status=MagickFail; |
3068 | 0 | break; |
3069 | 0 | } |
3070 | 793k | if (image->previous == (Image *) NULL) |
3071 | 793k | if (QuantumTick(y+(magick_int64_t)sample*image->rows, (magick_int64_t)image->rows*max_sample)) |
3072 | 86.4k | if (!MagickMonitorFormatted(y+ (magick_int64_t)sample*image->rows, |
3073 | 86.4k | (magick_int64_t)image->rows*max_sample,exception, |
3074 | 86.4k | LoadImageText,image->filename, |
3075 | 86.4k | image->columns,image->rows)) |
3076 | 0 | break; |
3077 | 793k | } |
3078 | 2.37k | } |
3079 | 2.37k | MagickFreeResourceLimitedMemory(unsigned char *,scanline); |
3080 | 2.37k | break; |
3081 | 2.37k | } |
3082 | 26.7k | case StrippedMethod: |
3083 | 26.7k | { |
3084 | | /* |
3085 | | Read TIFF image using multi-row strip storage. |
3086 | | */ |
3087 | 26.7k | unsigned char |
3088 | 26.7k | *p, |
3089 | 26.7k | *strip = (unsigned char *) NULL; |
3090 | | |
3091 | 26.7k | long |
3092 | | /* pixels_per_strip, */ |
3093 | 26.7k | stride, |
3094 | 26.7k | rows_remaining; |
3095 | | |
3096 | 26.7k | int |
3097 | 26.7k | max_sample, |
3098 | 26.7k | quantum_samples, |
3099 | 26.7k | sample; |
3100 | | |
3101 | 26.7k | tsize_t |
3102 | 26.7k | strip_size, |
3103 | 26.7k | strip_size_max = 0; |
3104 | | |
3105 | 26.7k | tstrip_t |
3106 | 26.7k | strip_id; |
3107 | | |
3108 | 26.7k | QuantumType |
3109 | 26.7k | quantum_type; |
3110 | | |
3111 | 26.7k | ImportPixelAreaInfo |
3112 | 26.7k | import_info; |
3113 | | |
3114 | 26.7k | if (logging) |
3115 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3116 | 0 | "Using stripped read method with %u bits per sample", |
3117 | 0 | bits_per_sample); |
3118 | | /* |
3119 | | Prepare for separate/contiguous retrieval. |
3120 | | */ |
3121 | 26.7k | max_sample=1; |
3122 | 26.7k | if (planar_config == PLANARCONFIG_SEPARATE) |
3123 | 2.07k | { |
3124 | 2.07k | if (QuantumTransferMode(image,photometric,compress_tag, |
3125 | 2.07k | sample_format, |
3126 | 2.07k | samples_per_pixel,PLANARCONFIG_CONTIG, |
3127 | 2.07k | 0,&quantum_type,&quantum_samples, |
3128 | 2.07k | exception) |
3129 | 2.07k | != MagickPass) |
3130 | 14 | ThrowTIFFReaderException(CorruptImageError, |
3131 | 2.07k | ImproperImageHeader,image); |
3132 | 2.06k | max_sample=quantum_samples; |
3133 | 2.06k | } |
3134 | | |
3135 | | /* pixels_per_strip=rows_per_strip*image->columns; */ |
3136 | 26.7k | p=0; |
3137 | 26.7k | strip_size=0; |
3138 | 26.7k | strip_id=0; |
3139 | | /* |
3140 | | Allocate memory for one strip. |
3141 | | */ |
3142 | 26.7k | strip_size_max=TIFFStripSize(tiff); |
3143 | 26.7k | if (strip_size_max <= 0) |
3144 | 0 | { |
3145 | 0 | status=MagickFail; |
3146 | 0 | break; |
3147 | 0 | } |
3148 | | /* |
3149 | | Scale up to size of 32-bit word. |
3150 | | */ |
3151 | 26.7k | strip_size_max=RoundUpToAlignment(strip_size_max,sizeof(magick_int32_t)); |
3152 | 26.7k | if (logging) |
3153 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3154 | 0 | "Maximum strip size %" MAGICK_SIZE_T_F "u", |
3155 | 0 | (MAGICK_SSIZE_T) strip_size_max); |
3156 | 26.7k | if (strip_size_max <= 0) |
3157 | 0 | { |
3158 | 0 | status=MagickFail; |
3159 | 0 | break; |
3160 | 0 | } |
3161 | | |
3162 | | /* |
3163 | | Rationalize memory request based on file size |
3164 | | */ |
3165 | 26.7k | if (strip_size_max > file_size*max_compress_ratio) |
3166 | 62 | { |
3167 | 62 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3168 | 62 | "Unreasonable allocation size " |
3169 | 62 | "(ratio of alloc to file size %g)", |
3170 | 62 | (double) strip_size_max/file_size); |
3171 | 62 | ThrowTIFFReaderException(CorruptImageError,InsufficientImageDataInFile, |
3172 | 0 | image); |
3173 | 0 | } |
3174 | | |
3175 | 26.6k | strip=MagickAllocateResourceLimitedClearedMemory(unsigned char *,(size_t) strip_size_max); |
3176 | 26.6k | if (strip == (unsigned char *) NULL) |
3177 | 0 | { |
3178 | 0 | ThrowTIFFReaderException(ResourceLimitError,MemoryAllocationFailed, |
3179 | 0 | image); |
3180 | 0 | } |
3181 | | /* |
3182 | | Compute per-row stride. |
3183 | | */ |
3184 | 26.6k | stride=TIFFVStripSize(tiff,1); |
3185 | | /* |
3186 | | Process each plane |
3187 | | */ |
3188 | 44.6k | for (sample=0; (status != MagickFail) && (sample < max_sample); sample++) |
3189 | 28.7k | { |
3190 | 28.7k | rows_remaining=0; |
3191 | | /* |
3192 | | Determine quantum parse method. |
3193 | | */ |
3194 | 28.7k | if (QuantumTransferMode(image,photometric,compress_tag, |
3195 | 28.7k | sample_format,samples_per_pixel, |
3196 | 28.7k | planar_config,sample, |
3197 | 28.7k | &quantum_type,&quantum_samples, |
3198 | 28.7k | exception) |
3199 | 28.7k | == MagickFail) |
3200 | 0 | { |
3201 | 0 | status=MagickFail; |
3202 | 0 | break; |
3203 | 0 | } |
3204 | 7.22M | for (y=0; (status != MagickFail) && (y < image->rows); y++) |
3205 | 7.20M | { |
3206 | 7.20M | if (rows_remaining == 0) |
3207 | 72.1k | { |
3208 | | /* |
3209 | | Obtain a strip |
3210 | | */ |
3211 | 72.1k | if (((strip_size=TIFFReadEncodedStrip(tiff,strip_id,strip, |
3212 | 72.1k | strip_size_max)) == -1)) |
3213 | 10.7k | { |
3214 | 10.7k | status=MagickFail; |
3215 | 10.7k | break; |
3216 | 10.7k | } |
3217 | 61.4k | #if !defined(WORDS_BIGENDIAN) |
3218 | 61.4k | if (24 == bits_per_sample) |
3219 | 1.92k | SwabDataToBigEndian(bits_per_sample,strip,strip_size); |
3220 | 61.4k | #endif |
3221 | 61.4k | rows_remaining=rows_per_strip; |
3222 | 61.4k | if (y+rows_per_strip > image->rows) |
3223 | 7.01k | rows_remaining=(rows_per_strip-(y+rows_per_strip-image->rows)); |
3224 | 61.4k | p=strip; |
3225 | 61.4k | strip_id++; |
3226 | 61.4k | } |
3227 | | /* |
3228 | | Compact strip row to only contain raster data. |
3229 | | */ |
3230 | 7.19M | if ((samples_per_pixel > quantum_samples) && |
3231 | 241k | (planar_config == PLANARCONFIG_CONTIG)) |
3232 | 131k | CompactSamples(image->columns, bits_per_sample, |
3233 | 131k | samples_per_pixel, quantum_samples, p); |
3234 | | /* |
3235 | | Access Magick pixels. |
3236 | | */ |
3237 | 7.19M | if (sample == 0) |
3238 | 7.13M | q=SetImagePixelsEx(image,0,y,image->columns,1,exception); |
3239 | 60.7k | else |
3240 | 60.7k | q=GetImagePixelsEx(image,0,y,image->columns,1,exception); |
3241 | 7.19M | if (q == (PixelPacket *) NULL) |
3242 | 0 | { |
3243 | 0 | status=MagickFail; |
3244 | 0 | break; |
3245 | 0 | } |
3246 | 7.19M | if ((sample == 0) && (max_sample > 1)) |
3247 | 28.0k | (void) memset(q,0,image->columns*sizeof(PixelPacket)); |
3248 | | /* |
3249 | | Import strip row into image. |
3250 | | */ |
3251 | 7.19M | if (ImportImagePixelArea(image,quantum_type,bits_per_sample,p, |
3252 | 7.19M | &import_options,&import_info) == MagickFail) |
3253 | 13 | { |
3254 | 13 | CopyException(exception,&image->exception); |
3255 | 13 | status=MagickFail; |
3256 | 13 | break; |
3257 | 13 | } |
3258 | | /* |
3259 | | Disassociate alpha from pixels if necessary. |
3260 | | */ |
3261 | 7.19M | if ((PHOTOMETRIC_RGB == photometric) && |
3262 | 1.57M | (image->matte) && (alpha_type == AssociatedAlpha) |
3263 | 319k | && (sample == (max_sample-1))) |
3264 | 318k | DisassociateAlphaRegion(image); |
3265 | | /* |
3266 | | Save our updates. |
3267 | | */ |
3268 | 7.19M | if (!SyncImagePixelsEx(image,exception)) |
3269 | 0 | { |
3270 | 0 | status=MagickFail; |
3271 | 0 | break; |
3272 | 0 | } |
3273 | | /* |
3274 | | Advance to next row |
3275 | | */ |
3276 | 7.19M | p += stride; |
3277 | 7.19M | rows_remaining--; |
3278 | | |
3279 | 7.19M | if (image->previous == (Image *) NULL) |
3280 | 7.19M | if (QuantumTick(y+(magick_int64_t)image->rows*sample, (magick_int64_t)image->rows*max_sample)) |
3281 | 1.03M | if (!MagickMonitorFormatted(y+ (magick_int64_t)image->rows*sample, (magick_int64_t)image->rows*max_sample,exception, |
3282 | 1.03M | LoadImageText,image->filename, |
3283 | 1.03M | image->columns,image->rows)) |
3284 | 0 | { |
3285 | 0 | status=MagickFail; |
3286 | 0 | break; |
3287 | 0 | } |
3288 | 7.19M | } |
3289 | 28.7k | if (status == MagickFail) |
3290 | 10.7k | break; |
3291 | 28.7k | } |
3292 | 26.6k | MagickFreeResourceLimitedMemory(unsigned char *,strip); |
3293 | 26.6k | break; |
3294 | 26.6k | } |
3295 | 3.32k | case TiledMethod: |
3296 | 3.32k | { |
3297 | | /* |
3298 | | Read TIFF using tiled storage. |
3299 | | */ |
3300 | 3.32k | unsigned char |
3301 | 3.32k | *tile = (unsigned char *) NULL; |
3302 | | |
3303 | 3.32k | uint32 |
3304 | 3.32k | tile_columns, |
3305 | 3.32k | tile_rows; |
3306 | | |
3307 | 3.32k | tsize_t |
3308 | 3.32k | stride, |
3309 | 3.32k | tile_size, |
3310 | 3.32k | tile_size_max = 0; |
3311 | | |
3312 | 3.32k | int |
3313 | 3.32k | max_sample, |
3314 | 3.32k | quantum_samples, |
3315 | 3.32k | sample; |
3316 | | |
3317 | 3.32k | QuantumType |
3318 | 3.32k | quantum_type; |
3319 | | |
3320 | 3.32k | size_t |
3321 | 3.32k | tile_total_pixels, |
3322 | 3.32k | tile_num=0, |
3323 | 3.32k | tiles_total; |
3324 | | |
3325 | 3.32k | if (logging) |
3326 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3327 | 0 | "Using tiled %s read method with %u bits per sample", |
3328 | 0 | PhotometricTagToString(photometric), bits_per_sample); |
3329 | | /* |
3330 | | Prepare for separate/contiguous retrieval. |
3331 | | */ |
3332 | 3.32k | max_sample=1; |
3333 | 3.32k | if (planar_config == PLANARCONFIG_SEPARATE) |
3334 | 48 | { |
3335 | 48 | if (QuantumTransferMode(image,photometric,compress_tag, |
3336 | 48 | sample_format,samples_per_pixel, |
3337 | 48 | PLANARCONFIG_CONTIG,0,&quantum_type, |
3338 | 48 | &quantum_samples, |
3339 | 48 | exception) |
3340 | 48 | != MagickPass) |
3341 | 4 | ThrowTIFFReaderException(CorruptImageError, |
3342 | 48 | ImproperImageHeader,image); |
3343 | 44 | max_sample=quantum_samples; |
3344 | 44 | } |
3345 | | /* |
3346 | | Obtain tile geometry |
3347 | | */ |
3348 | 3.31k | if (!(TIFFGetField(tiff,TIFFTAG_TILEWIDTH,&tile_columns) == 1) || |
3349 | 3.31k | !(TIFFGetField(tiff,TIFFTAG_TILELENGTH,&tile_rows) == 1)) |
3350 | 0 | { |
3351 | 0 | ThrowTIFFReaderException(CoderError,ImageIsNotTiled,image); |
3352 | 0 | } |
3353 | | /* |
3354 | | Obtain the maximum number of bytes required to contain a tile. |
3355 | | */ |
3356 | 3.31k | tile_size_max=TIFFTileSize(tiff); |
3357 | 3.31k | if (tile_size_max <= 0) |
3358 | 0 | { |
3359 | 0 | ThrowTIFFReaderException(ResourceLimitError,MemoryAllocationFailed, |
3360 | 0 | image); |
3361 | 0 | } |
3362 | | /* |
3363 | | Scale up to size of 32-bit word. |
3364 | | */ |
3365 | 3.31k | tile_size_max=RoundUpToAlignment(tile_size_max,sizeof(magick_int32_t)); |
3366 | 3.31k | if (0 == tile_size_max) |
3367 | 0 | { |
3368 | 0 | ThrowTIFFReaderException(ResourceLimitError,MemoryAllocationFailed, |
3369 | 0 | image); |
3370 | 0 | } |
3371 | | /* |
3372 | | Compute the total number of pixels in one tile |
3373 | | */ |
3374 | 3.31k | tile_total_pixels=MagickArraySize(tile_columns,tile_rows); |
3375 | 3.31k | if (logging) |
3376 | 0 | { |
3377 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3378 | 0 | "TIFF tile geometry %ux%u, " |
3379 | 0 | "%" MAGICK_SIZE_T_F "u pixels" |
3380 | 0 | " (%" MAGICK_SIZE_T_F "u bytes max)", |
3381 | 0 | (unsigned int)tile_columns, |
3382 | 0 | (unsigned int)tile_rows, |
3383 | 0 | (MAGICK_SIZE_T) tile_total_pixels, |
3384 | 0 | (MAGICK_SIZE_T) tile_size_max); |
3385 | 0 | } |
3386 | | |
3387 | | /* |
3388 | | Rationalize memory request based on file size |
3389 | | */ |
3390 | 3.31k | if (tile_size_max > file_size*max_compress_ratio) |
3391 | 132 | { |
3392 | 132 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3393 | 132 | "Unreasonable tile allocation size " |
3394 | 132 | "(ratio of alloc to file size %g)", |
3395 | 132 | (double) tile_size_max/file_size); |
3396 | 132 | ThrowTIFFReaderException(CorruptImageError,InsufficientImageDataInFile, |
3397 | 0 | image); |
3398 | 0 | } |
3399 | | |
3400 | 3.18k | if ((tile_columns > 1024) && (tile_columns > image->columns*10)) |
3401 | 5 | { |
3402 | 5 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3403 | 5 | "Unreasonable tile columns %u", |
3404 | 5 | (unsigned) tile_columns); |
3405 | 5 | ThrowTIFFReaderException(CorruptImageError,ImproperImageHeader, |
3406 | 0 | image); |
3407 | 0 | } |
3408 | | |
3409 | 3.18k | if ((tile_rows > 1024) && (tile_rows > image->rows*10)) |
3410 | 6 | { |
3411 | 6 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3412 | 6 | "Unreasonable tile rows %u", |
3413 | 6 | (unsigned) tile_rows); |
3414 | 6 | ThrowTIFFReaderException(CorruptImageError,ImproperImageHeader, |
3415 | 0 | image); |
3416 | 0 | } |
3417 | | |
3418 | | /* |
3419 | | Allocate tile buffer |
3420 | | */ |
3421 | 3.17k | tile=MagickAllocateResourceLimitedClearedMemory(unsigned char *, (size_t) tile_size_max); |
3422 | 3.17k | if (tile == (unsigned char *) NULL) |
3423 | 0 | { |
3424 | 0 | ThrowTIFFReaderException(ResourceLimitError,MemoryAllocationFailed, |
3425 | 0 | image); |
3426 | 0 | } |
3427 | 3.17k | tiles_total=((((size_t) image->columns/tile_columns)+((image->columns % tile_columns) ? 1 : 0)) |
3428 | 3.17k | *(((size_t) image->rows/tile_rows)+((image->rows % tile_rows) ? 1 : 0)))*max_sample; |
3429 | | /* |
3430 | | Compute per-row stride. |
3431 | | */ |
3432 | 3.17k | stride=TIFFTileRowSize(tiff); |
3433 | | |
3434 | | /* |
3435 | | Process each plane. |
3436 | | */ |
3437 | 4.60k | for (sample=0; (status != MagickFail) && (sample < max_sample); sample++) |
3438 | 3.18k | { |
3439 | | /* |
3440 | | Determine quantum parse method. |
3441 | | */ |
3442 | 3.18k | if (QuantumTransferMode(image,photometric,compress_tag, |
3443 | 3.18k | sample_format,samples_per_pixel, |
3444 | 3.18k | planar_config,sample,&quantum_type, |
3445 | 3.18k | &quantum_samples,exception) |
3446 | 3.18k | == MagickFail) |
3447 | 0 | { |
3448 | 0 | status=MagickFail; |
3449 | 0 | break; |
3450 | 0 | } |
3451 | 12.3k | for (y=0; (status != MagickFail) && (y < image->rows); y+=tile_rows) |
3452 | 10.9k | { |
3453 | 567k | for (x=0; (status != MagickFail) && (x < image->columns); x+=tile_columns) |
3454 | 558k | { |
3455 | 558k | long |
3456 | 558k | tile_set_columns, |
3457 | 558k | tile_set_rows; |
3458 | | |
3459 | 558k | unsigned char |
3460 | 558k | *p; |
3461 | | |
3462 | 558k | register long |
3463 | 558k | yy; |
3464 | | |
3465 | | /* |
3466 | | Compute image region corresponding to tile. |
3467 | | */ |
3468 | 558k | if (x+tile_columns > image->columns) |
3469 | 5.59k | tile_set_columns=(tile_columns-(x+tile_columns-image->columns)); |
3470 | 552k | else |
3471 | 552k | tile_set_columns=tile_columns; |
3472 | 558k | if (y+tile_rows > image->rows) |
3473 | 6.94k | tile_set_rows=(tile_rows-(y+tile_rows-image->rows)); |
3474 | 551k | else |
3475 | 551k | tile_set_rows=tile_rows; |
3476 | | |
3477 | | /* |
3478 | | Read a tile. |
3479 | | */ |
3480 | 558k | tile_num++; |
3481 | 558k | if ((tile_size=TIFFReadTile(tiff,tile,x,y,0,sample)) == -1) |
3482 | 1.74k | { |
3483 | 1.74k | status=MagickFail; |
3484 | 1.74k | break; |
3485 | 1.74k | } |
3486 | 556k | #if !defined(WORDS_BIGENDIAN) |
3487 | 556k | if (24 == bits_per_sample) |
3488 | 88 | SwabDataToBigEndian(bits_per_sample,tile,tile_size); |
3489 | 556k | #endif |
3490 | 556k | p=tile; |
3491 | 4.70M | for (yy=y; (status != MagickFail) && (yy < (long) y+tile_set_rows); yy++) |
3492 | 4.14M | { |
3493 | | /* |
3494 | | Compact tile row to only contain raster data. |
3495 | | */ |
3496 | 4.14M | if ((samples_per_pixel > quantum_samples) && |
3497 | 1.75M | (planar_config == PLANARCONFIG_CONTIG)) |
3498 | 1.75M | CompactSamples(tile_set_columns, bits_per_sample, |
3499 | 1.75M | samples_per_pixel, quantum_samples, p); |
3500 | | /* |
3501 | | Obtain pixel region corresponding to tile row. |
3502 | | */ |
3503 | 4.14M | if (sample == 0) |
3504 | 4.14M | q=SetImagePixelsEx(image,x,yy,tile_set_columns,1,exception); |
3505 | 11 | else |
3506 | 11 | q=GetImagePixelsEx(image,x,yy,tile_set_columns,1,exception); |
3507 | 4.14M | if (q == (PixelPacket *) NULL) |
3508 | 0 | { |
3509 | 0 | status=MagickFail; |
3510 | 0 | break; |
3511 | 0 | } |
3512 | 4.14M | if ((sample == 0) && (max_sample > 1)) |
3513 | 272 | (void) memset(q,0,tile_set_columns*sizeof(PixelPacket)); |
3514 | | /* |
3515 | | Import tile row |
3516 | | */ |
3517 | 4.14M | if (ImportImagePixelArea(image,quantum_type, |
3518 | 4.14M | bits_per_sample,p, |
3519 | 4.14M | &import_options,0) |
3520 | 4.14M | == MagickFail) |
3521 | 3 | { |
3522 | 3 | CopyException(exception,&image->exception); |
3523 | 3 | status=MagickFail; |
3524 | 3 | break; |
3525 | 3 | } |
3526 | | /* |
3527 | | Disassociate alpha from pixels if necessary. |
3528 | | */ |
3529 | 4.14M | if ((PHOTOMETRIC_RGB == photometric) && |
3530 | 67.0k | (image->matte) && (alpha_type == AssociatedAlpha) |
3531 | 863 | && (sample == (max_sample-1))) |
3532 | 764 | DisassociateAlphaRegion(image); |
3533 | | /* |
3534 | | Save our updates. |
3535 | | */ |
3536 | 4.14M | if (!SyncImagePixelsEx(image,exception)) |
3537 | 0 | { |
3538 | 0 | status=MagickFail; |
3539 | 0 | break; |
3540 | 0 | } |
3541 | 4.14M | p += stride; |
3542 | 4.14M | } |
3543 | 556k | if (image->previous == (Image *) NULL) |
3544 | 556k | if (QuantumTick(tile_num,tiles_total)) |
3545 | 10.3k | if (!MagickMonitorFormatted(tile_num, |
3546 | 10.3k | tiles_total, |
3547 | 10.3k | exception, |
3548 | 10.3k | LoadImageText,image->filename, |
3549 | 10.3k | image->columns,image->rows)) |
3550 | 0 | { |
3551 | 0 | status=MagickFail; |
3552 | 0 | } |
3553 | 556k | if (status == MagickFail) |
3554 | 3 | break; |
3555 | 556k | } |
3556 | 10.9k | if (status == MagickFail) |
3557 | 1.75k | break; |
3558 | 10.9k | } |
3559 | 3.18k | if (status == MagickFail) |
3560 | 1.75k | break; |
3561 | 3.18k | } |
3562 | | |
3563 | 3.17k | MagickFreeResourceLimitedMemory(unsigned char *,tile); |
3564 | 3.17k | break; |
3565 | 3.17k | } |
3566 | 3.02k | case RGBAStrippedMethod: |
3567 | 3.02k | { |
3568 | 3.02k | size_t |
3569 | 3.02k | number_pixels, |
3570 | 3.02k | strip_pixels_size; |
3571 | | |
3572 | 3.02k | uint32 |
3573 | 3.02k | *strip_pixels; |
3574 | | |
3575 | 3.02k | register uint32 |
3576 | 3.02k | *p; |
3577 | | |
3578 | 3.02k | if (logging) |
3579 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3580 | 0 | "Using RGB stripped read method with %u bits per sample", |
3581 | 0 | bits_per_sample); |
3582 | | /* |
3583 | | Convert stripped TIFF image to DirectClass MIFF image. |
3584 | | */ |
3585 | 3.02k | image->storage_class=DirectClass; |
3586 | 3.02k | number_pixels=MagickArraySize(image->columns,rows_per_strip); |
3587 | 3.02k | if (0 == number_pixels) |
3588 | 0 | { |
3589 | 0 | ThrowTIFFReaderException(ResourceLimitError,MemoryAllocationFailed, |
3590 | 0 | image); |
3591 | 0 | } |
3592 | | /* |
3593 | | Rationalize memory request based on file size |
3594 | | */ |
3595 | 3.02k | if ((magick_off_t) (number_pixels*sizeof(uint32)) > |
3596 | 3.02k | file_size*max_compress_ratio) |
3597 | 45 | { |
3598 | 45 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3599 | 45 | "Unreasonable allocation size " |
3600 | 45 | "(ratio of alloc to file size %g)", |
3601 | 45 | (double) (number_pixels*sizeof(uint32))/file_size); |
3602 | 45 | ThrowTIFFReaderException(CorruptImageError,InsufficientImageDataInFile, |
3603 | 0 | image); |
3604 | 0 | } |
3605 | 2.97k | strip_pixels_size=MagickArraySize(number_pixels,sizeof(uint32)); |
3606 | 2.97k | if (strip_pixels_size == 0) |
3607 | 0 | ThrowTIFFReaderException(ResourceLimitError,MemoryAllocationFailed, |
3608 | 2.97k | image); |
3609 | 2.97k | strip_pixels=MagickAllocateResourceLimitedClearedMemory(uint32 *,strip_pixels_size); |
3610 | 2.97k | if (strip_pixels == (uint32 *) NULL) |
3611 | 0 | { |
3612 | 0 | ThrowTIFFReaderException(ResourceLimitError,MemoryAllocationFailed, |
3613 | 0 | image); |
3614 | 0 | } |
3615 | 2.97k | if (logging) |
3616 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3617 | 0 | "Allocated %" MAGICK_SIZE_T_F "u bytes for RGBA strip", |
3618 | 0 | (MAGICK_SIZE_T) number_pixels*sizeof(uint32)); |
3619 | | /* |
3620 | | Convert image to DirectClass pixel packets. |
3621 | | */ |
3622 | 2.97k | i=0; |
3623 | 2.97k | p=0; |
3624 | 350k | for (y=0; (status != MagickFail) && (y < image->rows); y++) |
3625 | 349k | { |
3626 | 349k | q=SetImagePixelsEx(image,0,y,image->columns,1,exception); |
3627 | 349k | if (q == (PixelPacket *) NULL) |
3628 | 0 | { |
3629 | 0 | status=MagickFail; |
3630 | 0 | break; |
3631 | 0 | } |
3632 | 349k | if (0 == i) |
3633 | 43.5k | { |
3634 | 43.5k | if (!TIFFReadRGBAStrip(tiff,y,strip_pixels)) |
3635 | 2.18k | { |
3636 | 2.18k | if (logging) |
3637 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3638 | 0 | "TIFFReadRGBAStrip reports failure"); |
3639 | 2.18k | status=MagickFail; |
3640 | 2.18k | break; |
3641 | 2.18k | } |
3642 | 41.3k | i=(long) Min(rows_per_strip,image->rows-y); |
3643 | 41.3k | } |
3644 | 347k | i--; |
3645 | 347k | p=strip_pixels+(size_t) image->columns*i; |
3646 | 171M | for (x=0; (status != MagickFail) && (x < image->columns); x++) |
3647 | 171M | { |
3648 | 171M | q->red=ScaleCharToQuantum(TIFFGetR(*p)); |
3649 | 171M | q->green=ScaleCharToQuantum(TIFFGetG(*p)); |
3650 | 171M | q->blue=ScaleCharToQuantum(TIFFGetB(*p)); |
3651 | 171M | if (image->matte) |
3652 | 767k | q->opacity=(Quantum) ScaleCharToQuantum(TIFFGetA(*p)); |
3653 | 170M | else |
3654 | 170M | q->opacity=OpaqueOpacity; |
3655 | 171M | p++; |
3656 | 171M | q++; |
3657 | 171M | } |
3658 | | /* |
3659 | | Disassociate alpha from pixels if necessary. |
3660 | | */ |
3661 | 347k | if ((PHOTOMETRIC_RGB == photometric) && |
3662 | 7.88k | (image->matte) && (alpha_type == AssociatedAlpha)) |
3663 | 156 | DisassociateAlphaRegion(image); |
3664 | 347k | if (!SyncImagePixelsEx(image,exception)) |
3665 | 0 | { |
3666 | 0 | status=MagickFail; |
3667 | 0 | break; |
3668 | 0 | } |
3669 | 347k | if (image->previous == (Image *) NULL) |
3670 | 347k | if (QuantumTick(y,image->rows)) |
3671 | 102k | if (!MagickMonitorFormatted(y,image->rows,exception, |
3672 | 102k | LoadImageText,image->filename, |
3673 | 102k | image->columns,image->rows)) |
3674 | 0 | { |
3675 | 0 | status=MagickFail; |
3676 | 0 | break; |
3677 | 0 | } |
3678 | 347k | } |
3679 | 2.97k | MagickFreeResourceLimitedMemory(uint32 *,strip_pixels); |
3680 | 2.97k | break; |
3681 | 2.97k | } |
3682 | 983 | case RGBATiledMethod: |
3683 | 983 | { |
3684 | | /* |
3685 | | Convert tiled TIFF image to DirectClass MIFF image. |
3686 | | */ |
3687 | 983 | register uint32 |
3688 | 983 | *p; |
3689 | | |
3690 | 983 | uint32 |
3691 | 983 | *tile_pixels, |
3692 | 983 | tile_columns, |
3693 | 983 | tile_rows; |
3694 | | |
3695 | 983 | tsize_t |
3696 | 983 | tile_size_max; |
3697 | | |
3698 | 983 | size_t |
3699 | 983 | tile_pixels_size, |
3700 | 983 | tile_total_pixels, |
3701 | 983 | tile_num=0, |
3702 | 983 | tiles_total; |
3703 | | |
3704 | 983 | if (logging) |
3705 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3706 | 0 | "Using RGB tiled read method with %u bits per sample", |
3707 | 0 | bits_per_sample); |
3708 | 983 | image->storage_class=DirectClass; |
3709 | | /* |
3710 | | Obtain tile geometry |
3711 | | */ |
3712 | 983 | if (!(TIFFGetField(tiff,TIFFTAG_TILEWIDTH,&tile_columns) == 1) || |
3713 | 983 | !(TIFFGetField(tiff,TIFFTAG_TILELENGTH,&tile_rows) == 1)) |
3714 | 0 | { |
3715 | 0 | ThrowTIFFReaderException(CoderError,ImageIsNotTiled,image); |
3716 | 0 | } |
3717 | 983 | tile_total_pixels=MagickArraySize(tile_columns,tile_rows); |
3718 | 983 | tiles_total=((((size_t) image->columns/tile_columns)+((image->columns % tile_columns) ? 1 : 0)) |
3719 | 983 | *(((size_t) image->rows/tile_rows)+((image->rows % tile_rows) ? 1 : 0))); |
3720 | 983 | if (logging) |
3721 | 0 | { |
3722 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Reading TIFF tiles ..."); |
3723 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3724 | 0 | "TIFF tile geometry %ux%u, %" MAGICK_SIZE_T_F "u pixels/tile" |
3725 | 0 | ", %" MAGICK_SIZE_T_F "u tiles", |
3726 | 0 | (unsigned int)tile_columns, |
3727 | 0 | (unsigned int)tile_rows, |
3728 | 0 | (MAGICK_SIZE_T) tile_total_pixels, |
3729 | 0 | (MAGICK_SIZE_T) tiles_total); |
3730 | 0 | } |
3731 | | /* |
3732 | | Obtain the maximum number of bytes required to contain a tile. |
3733 | | */ |
3734 | 983 | tile_size_max=TIFFTileSize(tiff); |
3735 | 983 | if (tile_size_max <= 0) |
3736 | 0 | { |
3737 | 0 | ThrowTIFFReaderException(ResourceLimitError,MemoryAllocationFailed, |
3738 | 0 | image); |
3739 | 0 | } |
3740 | | /* |
3741 | | Apply image resource limits to tile width, height, and pixels. |
3742 | | */ |
3743 | 983 | errno=0; |
3744 | 983 | if (AcquireMagickResource(WidthResource,tile_columns) != MagickPass) |
3745 | 53 | { |
3746 | 53 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3747 | 53 | "TIFF tile width %u exceeds limit!",tile_columns); |
3748 | 53 | ThrowTIFFReaderException(ResourceLimitError,ImagePixelWidthLimitExceeded, |
3749 | 0 | image); |
3750 | 0 | } |
3751 | 930 | if (AcquireMagickResource(HeightResource,tile_rows) != MagickPass) |
3752 | 9 | { |
3753 | 9 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3754 | 9 | "TIFF tile width %u exceeds limit!",tile_rows); |
3755 | 9 | ThrowTIFFReaderException(ResourceLimitError,ImagePixelHeightLimitExceeded, |
3756 | 0 | image); |
3757 | 0 | } |
3758 | 921 | if (AcquireMagickResource(PixelsResource,tile_total_pixels) != MagickPass) |
3759 | 0 | { |
3760 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3761 | 0 | "TIFF tile pixels %" MAGICK_SIZE_T_F "u exceeds limit!", |
3762 | 0 | (MAGICK_SIZE_T) tile_total_pixels); |
3763 | 0 | ThrowTIFFReaderException(ResourceLimitError,ImagePixelLimitExceeded, |
3764 | 0 | image); |
3765 | 0 | } |
3766 | | /* |
3767 | | Rationalize memory request based on file size |
3768 | | */ |
3769 | 921 | if (tile_size_max > file_size*max_compress_ratio) |
3770 | 7 | { |
3771 | 7 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3772 | 7 | "Unreasonable tile allocation size " |
3773 | 7 | "(ratio of alloc to file size %g)", |
3774 | 7 | (double) tile_size_max/file_size); |
3775 | 7 | ThrowTIFFReaderException(CorruptImageError,InsufficientImageDataInFile, |
3776 | 0 | image); |
3777 | 0 | } |
3778 | | /* |
3779 | | Allocate tile buffer |
3780 | | */ |
3781 | 914 | tile_pixels_size=MagickArraySize(MagickArraySize(tile_columns,tile_rows), |
3782 | 914 | sizeof (uint32)); |
3783 | 914 | if (tile_pixels_size == 0) |
3784 | 0 | ThrowTIFFReaderException(ResourceLimitError,MemoryAllocationFailed, |
3785 | 914 | image); |
3786 | 914 | tile_pixels=MagickAllocateResourceLimitedMemory(uint32*,tile_pixels_size); |
3787 | 914 | if (tile_pixels == (uint32 *) NULL) |
3788 | 0 | { |
3789 | 0 | ThrowTIFFReaderException(ResourceLimitError,MemoryAllocationFailed, |
3790 | 0 | image); |
3791 | 0 | } |
3792 | 9.95k | for (y=0; (status != MagickFail) && (y < image->rows); y+=tile_rows) |
3793 | 9.77k | { |
3794 | | /* |
3795 | | Retrieve a tile height's worth of rows |
3796 | | */ |
3797 | 9.77k | PixelPacket |
3798 | 9.77k | *strip; |
3799 | | |
3800 | 9.77k | unsigned int |
3801 | 9.77k | tile_columns_remaining, |
3802 | 9.77k | tile_rows_remaining; |
3803 | | |
3804 | | /* Compute remaining tile rows */ |
3805 | 9.77k | if (y+tile_rows < image->rows) |
3806 | 9.37k | tile_rows_remaining=tile_rows; |
3807 | 398 | else |
3808 | 398 | tile_rows_remaining=image->rows-y; |
3809 | | /* |
3810 | | Obtain a row of pixels |
3811 | | */ |
3812 | 9.77k | strip=SetImagePixelsEx(image,0,y,image->columns,tile_rows_remaining,exception); |
3813 | 9.77k | if (strip == (PixelPacket *) NULL) |
3814 | 0 | { |
3815 | 0 | status=MagickFail; |
3816 | 0 | break; |
3817 | 0 | } |
3818 | 227k | for (x=0; (status != MagickFail) && (x < image->columns); x+=tile_columns) |
3819 | 218k | { |
3820 | 218k | register unsigned int |
3821 | 218k | tile_column, |
3822 | 218k | tile_row; |
3823 | | |
3824 | | /* |
3825 | | Obtain one tile. Origin is bottom left of tile. |
3826 | | */ |
3827 | 218k | tile_num++; |
3828 | 218k | if (!TIFFReadRGBATile(tiff,x,y,tile_pixels)) |
3829 | 732 | { |
3830 | 732 | status=MagickFail; |
3831 | 732 | break; |
3832 | 732 | } |
3833 | | /* |
3834 | | Compute remaining tile columns |
3835 | | */ |
3836 | 217k | if (x+tile_columns < image->columns) |
3837 | 208k | tile_columns_remaining=tile_columns; |
3838 | 9.03k | else |
3839 | 9.03k | tile_columns_remaining=image->columns-x; |
3840 | | /* |
3841 | | Transfer tile to image |
3842 | | */ |
3843 | 217k | p=tile_pixels+(size_t)(tile_rows-tile_rows_remaining)*tile_columns; |
3844 | 217k | q=strip+(x+(size_t)(tile_rows_remaining-1)*image->columns); |
3845 | 5.36M | for ( tile_row=tile_rows_remaining; tile_row != 0; tile_row--) |
3846 | 5.15M | { |
3847 | 5.15M | if (image->matte) |
3848 | 40.9k | for (tile_column=tile_columns_remaining; tile_column != 0; |
3849 | 38.5k | tile_column--) |
3850 | 38.5k | { |
3851 | 38.5k | q->red=ScaleCharToQuantum(TIFFGetR(*p)); |
3852 | 38.5k | q->green=ScaleCharToQuantum(TIFFGetG(*p)); |
3853 | 38.5k | q->blue=ScaleCharToQuantum(TIFFGetB(*p)); |
3854 | 38.5k | q->opacity=(Quantum) ScaleCharToQuantum(TIFFGetA(*p)); |
3855 | 38.5k | q++; |
3856 | 38.5k | p++; |
3857 | 38.5k | } |
3858 | 5.14M | else |
3859 | 14.1M | for (tile_column=tile_columns_remaining; tile_column != 0; |
3860 | 9.04M | tile_column--) |
3861 | 9.04M | { |
3862 | 9.04M | q->red=ScaleCharToQuantum(TIFFGetR(*p)); |
3863 | 9.04M | q->green=ScaleCharToQuantum(TIFFGetG(*p)); |
3864 | 9.04M | q->blue=ScaleCharToQuantum(TIFFGetB(*p)); |
3865 | 9.04M | q->opacity=OpaqueOpacity; |
3866 | 9.04M | q++; |
3867 | 9.04M | p++; |
3868 | 9.04M | } |
3869 | 5.15M | p+=tile_columns-tile_columns_remaining; |
3870 | 5.15M | q-=((size_t) image->columns+tile_columns_remaining); |
3871 | 5.15M | } |
3872 | 217k | if (image->previous == (Image *) NULL) |
3873 | 217k | if (QuantumTick(tile_num,tiles_total)) |
3874 | 12.6k | if (!MagickMonitorFormatted(tile_num, |
3875 | 12.6k | tiles_total, |
3876 | 12.6k | exception, |
3877 | 12.6k | LoadImageText,image->filename, |
3878 | 12.6k | image->columns,image->rows)) |
3879 | 0 | { |
3880 | 0 | status=MagickFail; |
3881 | 0 | } |
3882 | 217k | if (status == MagickFail) |
3883 | 0 | break; |
3884 | 217k | } |
3885 | 9.77k | if (status == MagickFail) |
3886 | 732 | break; |
3887 | | /* |
3888 | | Disassociate alpha from pixels if necessary. |
3889 | | */ |
3890 | 9.03k | if ((PHOTOMETRIC_RGB == photometric) && |
3891 | 53 | (image->matte) && (alpha_type == AssociatedAlpha)) |
3892 | 1 | DisassociateAlphaRegion(image); |
3893 | 9.03k | if (!SyncImagePixelsEx(image,exception)) |
3894 | 0 | { |
3895 | 0 | status=MagickFail; |
3896 | 0 | break; |
3897 | 0 | } |
3898 | 9.03k | } |
3899 | 914 | MagickFreeResourceLimitedMemory(uint32 *,tile_pixels); |
3900 | 914 | break; |
3901 | 914 | } |
3902 | 1.71k | case RGBAPuntMethod: |
3903 | 1.71k | default: |
3904 | 1.71k | { |
3905 | 1.71k | register uint32 |
3906 | 1.71k | *p; |
3907 | | |
3908 | 1.71k | uint32 |
3909 | 1.71k | *pixels; |
3910 | | |
3911 | 1.71k | size_t |
3912 | 1.71k | number_pixels, |
3913 | 1.71k | pixels_size; |
3914 | | |
3915 | 1.71k | if (logging) |
3916 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3917 | 0 | "Using RGB punt read method with %u bits per sample", |
3918 | 0 | bits_per_sample); |
3919 | | |
3920 | | |
3921 | | /* |
3922 | | TIFFReadRGBAImage() does not handle more than 4 samples per pixel. |
3923 | | */ |
3924 | 1.71k | if (samples_per_pixel > 4) |
3925 | 6 | { |
3926 | 6 | ThrowTIFFReaderException(CoderError,UnsupportedSamplesPerPixel,image); |
3927 | 0 | } |
3928 | | |
3929 | | /* |
3930 | | Convert TIFF image to DirectClass MIFF image. |
3931 | | */ |
3932 | 1.70k | image->storage_class=DirectClass; |
3933 | 1.70k | number_pixels=MagickArraySize(image->columns,image->rows); |
3934 | 1.70k | if (number_pixels == 0) |
3935 | 0 | ThrowTIFFReaderException(ResourceLimitError,MemoryAllocationFailed, |
3936 | 1.70k | image); |
3937 | | |
3938 | | |
3939 | | /* |
3940 | | TIFFReadRGBAImage reads a strip- or tile-based image |
3941 | | into memory, storing the result in the user supplied |
3942 | | raster. The raster is assumed to be an array of width |
3943 | | times height 32-bit entries, where width must be less |
3944 | | than or equal to the width of the image (height may be |
3945 | | any non-zero size). If the raster dimensions are smaller |
3946 | | than the image, the image data is cropped to the raster |
3947 | | bounds. If the raster height is greater than that of |
3948 | | the image, then the image data are placed in the lower |
3949 | | part of the raster. (Note that the raster is assumed to |
3950 | | be organized such that the pixel at location (x,y) is |
3951 | | raster[y*width+x]; with the raster origin in the |
3952 | | lower-left hand corner.) |
3953 | | |
3954 | | Please note that this allocation used to be |
3955 | | (number_pixels+6*image->columns)*sizeof(uint32) for |
3956 | | unknown reasons. |
3957 | | */ |
3958 | 1.70k | pixels_size=MagickArraySize(number_pixels,sizeof(uint32)); |
3959 | 1.70k | if (pixels_size == 0) |
3960 | 0 | ThrowTIFFReaderException(ResourceLimitError,MemoryAllocationFailed, |
3961 | 1.70k | image); |
3962 | 1.70k | pixels=MagickAllocateResourceLimitedMemory(uint32 *,pixels_size); |
3963 | 1.70k | if (pixels == (uint32 *) NULL) |
3964 | 0 | { |
3965 | 0 | ThrowTIFFReaderException(ResourceLimitError,MemoryAllocationFailed, |
3966 | 0 | image); |
3967 | 0 | } |
3968 | 1.70k | if (logging) |
3969 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3970 | 0 | "Dispatching to TIFFReadRGBAImage()"); |
3971 | 1.70k | if (!TIFFReadRGBAImage(tiff,(uint32) image->columns, |
3972 | 1.70k | (uint32) image->rows, |
3973 | 1.70k | pixels,0)) |
3974 | 399 | { |
3975 | 399 | if (logging) |
3976 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
3977 | 0 | "TIFFReadRGBAImage() returns failure!"); |
3978 | 399 | MagickFreeResourceLimitedMemory(uint32 *,pixels); |
3979 | 399 | status=MagickFail; |
3980 | 399 | break; |
3981 | 399 | } |
3982 | | /* |
3983 | | Convert image to DirectClass pixel packets. |
3984 | | */ |
3985 | 1.30k | p=pixels+number_pixels-1; |
3986 | 185k | for (y=0; y < image->rows; y++) |
3987 | 184k | { |
3988 | 184k | q=SetImagePixelsEx(image,0,y,image->columns,1,exception); |
3989 | 184k | if (q == (PixelPacket *) NULL) |
3990 | 0 | { |
3991 | 0 | status=MagickFail; |
3992 | 0 | break; |
3993 | 0 | } |
3994 | 184k | q+=image->columns-1; |
3995 | 184k | if (image->matte) |
3996 | 522k | for (x=(long) image->columns; x != 0; x--) |
3997 | 508k | { |
3998 | 508k | q->red=ScaleCharToQuantum(TIFFGetR(*p)); |
3999 | 508k | q->green=ScaleCharToQuantum(TIFFGetG(*p)); |
4000 | 508k | q->blue=ScaleCharToQuantum(TIFFGetB(*p)); |
4001 | 508k | q->opacity=(Quantum) ScaleCharToQuantum(TIFFGetA(*p)); |
4002 | 508k | p--; |
4003 | 508k | q--; |
4004 | 508k | } |
4005 | 171k | else |
4006 | 81.1M | for (x=(long) image->columns; x != 0; x--) |
4007 | 81.0M | { |
4008 | 81.0M | q->red=ScaleCharToQuantum(TIFFGetR(*p)); |
4009 | 81.0M | q->green=ScaleCharToQuantum(TIFFGetG(*p)); |
4010 | 81.0M | q->blue=ScaleCharToQuantum(TIFFGetB(*p)); |
4011 | 81.0M | q->opacity=OpaqueOpacity; |
4012 | 81.0M | p--; |
4013 | 81.0M | q--; |
4014 | 81.0M | } |
4015 | | /* |
4016 | | Disassociate alpha from pixels if necessary. |
4017 | | */ |
4018 | 184k | if ((PHOTOMETRIC_RGB == photometric) && |
4019 | 17.0k | (image->matte) && (alpha_type == AssociatedAlpha)) |
4020 | 683 | DisassociateAlphaRegion(image); |
4021 | 184k | if (!SyncImagePixelsEx(image,exception)) |
4022 | 0 | { |
4023 | 0 | status=MagickFail; |
4024 | 0 | break; |
4025 | 0 | } |
4026 | 184k | if (image->previous == (Image *) NULL) |
4027 | 184k | if (QuantumTick(y,image->rows)) |
4028 | 101k | if (!MagickMonitorFormatted(y,image->rows,exception, |
4029 | 101k | LoadImageText,image->filename, |
4030 | 101k | image->columns,image->rows)) |
4031 | 0 | { |
4032 | 0 | status=MagickFail; |
4033 | 0 | break; |
4034 | 0 | } |
4035 | 184k | if (status == MagickFail) |
4036 | 0 | break; |
4037 | 184k | } |
4038 | 1.30k | MagickFreeResourceLimitedMemory(uint32 *,pixels); |
4039 | 1.30k | break; |
4040 | 1.70k | } |
4041 | 38.1k | } |
4042 | | |
4043 | 37.8k | read_next_frame: |
4044 | 37.8k | if (status == MagickPass) |
4045 | 20.2k | { |
4046 | 20.2k | StopTimer(&image->timer); |
4047 | 20.2k | if (image->depth > QuantumDepth) |
4048 | 1.62k | image->depth=QuantumDepth; |
4049 | 20.2k | if ((photometric == PHOTOMETRIC_LOGL) || |
4050 | 20.2k | (photometric == PHOTOMETRIC_MINISBLACK) || |
4051 | 16.4k | (photometric == PHOTOMETRIC_MINISWHITE)) |
4052 | 12.1k | image->is_grayscale=MagickTrue; |
4053 | 20.2k | if ((image->is_grayscale == MagickTrue) && (bits_per_sample == 1)) |
4054 | 5.77k | image->is_monochrome=MagickTrue; |
4055 | | /* |
4056 | | Proceed to next image. |
4057 | | */ |
4058 | 20.2k | if (image_info->subrange != 0) |
4059 | 18.6k | if (image->scene >= (image_info->subimage+image_info->subrange-1)) |
4060 | 18.6k | break; |
4061 | 1.68k | more_frames=TIFFReadDirectory(tiff); |
4062 | 1.68k | if (logging) |
4063 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4064 | 0 | "TIFFReadDirectory() returned %d",more_frames); |
4065 | 1.68k | if ((more_frames == 0) && (exception->severity == CorruptImageError)) |
4066 | 180 | { |
4067 | 180 | if (logging) |
4068 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4069 | 0 | "Re-casting 'CorruptImageError' to" |
4070 | 0 | " 'CorruptImageWarning' due to" |
4071 | 0 | " TIFFReadDirectory() error"); |
4072 | 180 | exception->severity=CorruptImageWarning; |
4073 | 180 | } |
4074 | 1.68k | if (more_frames) |
4075 | 0 | { |
4076 | | /* |
4077 | | Allocate next image structure. |
4078 | | */ |
4079 | 0 | AllocateNextImage(image_info,image); |
4080 | 0 | if (image->next == (Image *) NULL) |
4081 | 0 | { |
4082 | 0 | DestroyImageList(image); |
4083 | 0 | return((Image *) NULL); |
4084 | 0 | } |
4085 | 0 | image=SyncNextImageInList(image); |
4086 | 0 | } |
4087 | 1.68k | } |
4088 | | |
4089 | 19.2k | if (status == MagickFail) |
4090 | 17.5k | break; |
4091 | | |
4092 | 19.2k | } while ((status == MagickPass) && (more_frames)); |
4093 | 37.8k | TIFFClose(tiff); |
4094 | 37.8k | if (status == MagickFail) |
4095 | 17.5k | { |
4096 | 17.5k | if (logging) |
4097 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4098 | 0 | "Delete image %ld from list due to error", |
4099 | 0 | image->scene); |
4100 | 17.5k | DeleteImageFromList(&image); |
4101 | 17.5k | } |
4102 | 37.8k | return GetFirstImageInList(image); |
4103 | 40.7k | } |
4104 | | #endif |
4105 | | |
4106 | | /* |
4107 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
4108 | | % % |
4109 | | % % |
4110 | | % % |
4111 | | % R e g i s t e r T I F F I m a g e % |
4112 | | % % |
4113 | | % % |
4114 | | % % |
4115 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
4116 | | % |
4117 | | % Method RegisterTIFFImage adds attributes for the TIFF image format to |
4118 | | % the list of supported formats. The attributes include the image format |
4119 | | % tag, a method to read and/or write the format, whether the format |
4120 | | % supports the saving of more than one frame to the same file or blob, |
4121 | | % whether the format supports native in-memory I/O, and a brief |
4122 | | % description of the format. |
4123 | | % |
4124 | | % The format of the RegisterTIFFImage method is: |
4125 | | % |
4126 | | % void RegisterTIFFImage(void) |
4127 | | % |
4128 | | */ |
4129 | | ModuleExport void |
4130 | | RegisterTIFFImage(void) |
4131 | 8 | { |
4132 | 8 | #define BIGTIFFDescription "Tagged Image File Format (64-bit offsets)" |
4133 | 8 | #define GROUP4RAWDescription "CCITT Group4 RAW" |
4134 | 8 | #define PTIFDescription "Pyramid encoded TIFF" |
4135 | 16 | #define TIFFDescription "Tagged Image File Format" |
4136 | 8 | #if defined(HasTIFF) |
4137 | | |
4138 | 8 | static char |
4139 | 8 | version[32]; |
4140 | | |
4141 | 8 | MagickInfo |
4142 | 8 | *entry; |
4143 | | |
4144 | 8 | static const char |
4145 | 8 | TIFFNote[] = |
4146 | 8 | "Supported Compressions: " |
4147 | 8 | #if defined(COMPRESSION_NONE) |
4148 | 8 | "None" |
4149 | 8 | #endif |
4150 | 8 | #if defined(COMPRESSION_CCITTFAX3) |
4151 | 8 | ", Fax/Group3" |
4152 | 8 | #endif |
4153 | 8 | #if defined(COMPRESSION_CCITTFAX4) |
4154 | 8 | ", Group4" |
4155 | 8 | #endif |
4156 | 8 | #if defined(COMPRESSION_JBIG) |
4157 | 8 | ", JBIG" |
4158 | 8 | #endif |
4159 | 8 | #if defined(COMPRESSION_JPEG) |
4160 | 8 | ", JPEG" |
4161 | 8 | #endif |
4162 | 8 | #if defined(COMPRESSION_LZW) |
4163 | 8 | ", LZW" |
4164 | 8 | #endif |
4165 | 8 | #if defined(COMPRESSION_LZMA) |
4166 | 8 | ", LZMA" |
4167 | 8 | #endif |
4168 | 8 | #if defined(COMPRESSION_PACKBITS) |
4169 | 8 | ", RLE" |
4170 | 8 | #endif |
4171 | 8 | #if defined(COMPRESSION_ADOBE_DEFLATE) |
4172 | 8 | ", ZIP" |
4173 | 8 | #endif |
4174 | 8 | #if defined(COMPRESSION_ZSTD) |
4175 | 8 | ", ZSTD" |
4176 | 8 | #endif |
4177 | 8 | #if defined(COMPRESSION_WEBP) |
4178 | 8 | ", WEBP" |
4179 | 8 | #endif |
4180 | 8 | ; |
4181 | | |
4182 | | /* |
4183 | | Initialize thread specific data key. |
4184 | | */ |
4185 | 8 | if (tsd_key == (MagickTsdKey_t) 0) |
4186 | 8 | (void) MagickTsdKeyCreate(&tsd_key); |
4187 | | |
4188 | 8 | version[0]='\0'; |
4189 | 8 | { |
4190 | 8 | unsigned int |
4191 | 8 | i; |
4192 | | |
4193 | 8 | const char |
4194 | 8 | *p; |
4195 | | |
4196 | | /* TIFFGetVersion() is in libtiff 3.5.3 and later */ |
4197 | 8 | for (p=TIFFGetVersion(), i=0; |
4198 | 184 | (i < sizeof(version)-1) && (*p != 0) && (*p != '\n'); |
4199 | 176 | p++, i++) |
4200 | 176 | version[i] = *p; |
4201 | 8 | version[i]=0; |
4202 | 8 | } |
4203 | | |
4204 | | /* |
4205 | | Big TIFF (64-bit offsets) |
4206 | | */ |
4207 | 8 | #if defined(HasBigTIFF) |
4208 | 8 | entry=SetMagickInfo("BIGTIFF"); |
4209 | 8 | entry->thread_support=MagickFalse; /* libtiff uses libjpeg which is not thread safe */ |
4210 | 8 | entry->decoder=(DecoderHandler) ReadTIFFImage; |
4211 | 8 | entry->encoder=(EncoderHandler) WriteTIFFImage; |
4212 | 8 | entry->seekable_stream=MagickTrue; |
4213 | 8 | entry->description=BIGTIFFDescription; |
4214 | 8 | entry->note=TIFFNote; |
4215 | 8 | entry->module="TIFF"; |
4216 | 8 | entry->coder_class=PrimaryCoderClass; |
4217 | 8 | (void) RegisterMagickInfo(entry); |
4218 | 8 | #endif /* defined(HasBigTIFF) */ |
4219 | | |
4220 | | /* |
4221 | | CCITT Group4 RAW encoded page. |
4222 | | */ |
4223 | 8 | entry=SetMagickInfo("GROUP4RAW"); |
4224 | 8 | entry->thread_support=MagickTrue; |
4225 | | /* entry->decoder=(DecoderHandler) ReadGROUP4RAWImage; */ |
4226 | 8 | entry->encoder=(EncoderHandler) WriteGROUP4RAWImage; |
4227 | 8 | entry->raw=MagickTrue; |
4228 | 8 | entry->adjoin=MagickFalse; |
4229 | 8 | entry->seekable_stream=MagickFalse; |
4230 | 8 | entry->extension_treatment=IgnoreExtensionTreatment; |
4231 | 8 | entry->stealth=MagickTrue; /* Don't list in '-list format' output */ |
4232 | 8 | entry->description=GROUP4RAWDescription; |
4233 | 8 | entry->module="TIFF"; |
4234 | 8 | (void) RegisterMagickInfo(entry); |
4235 | | |
4236 | | /* |
4237 | | Pyramid TIFF (sequence of successively smaller versions of the same image) |
4238 | | */ |
4239 | 8 | entry=SetMagickInfo("PTIF"); |
4240 | 8 | entry->thread_support=MagickFalse; /* libtiff uses libjpeg which is not thread safe */ |
4241 | 8 | entry->decoder=(DecoderHandler) ReadTIFFImage; |
4242 | 8 | entry->encoder=(EncoderHandler) WritePTIFImage; |
4243 | 8 | entry->seekable_stream=MagickTrue; |
4244 | 8 | entry->description=PTIFDescription; |
4245 | 8 | entry->note=TIFFNote; |
4246 | 8 | entry->module="TIFF"; |
4247 | 8 | (void) RegisterMagickInfo(entry); |
4248 | | |
4249 | | /* |
4250 | | Another name for 32-bit TIFF |
4251 | | */ |
4252 | 8 | entry=SetMagickInfo("TIF"); |
4253 | 8 | entry->thread_support=MagickFalse; /* libtiff uses libjpeg which is not thread safe */ |
4254 | 8 | entry->decoder=(DecoderHandler) ReadTIFFImage; |
4255 | 8 | entry->encoder=(EncoderHandler) WriteTIFFImage; |
4256 | 8 | entry->seekable_stream=MagickTrue; |
4257 | 8 | entry->description=TIFFDescription; |
4258 | 8 | if (*version != '\0') |
4259 | 8 | entry->version=version; |
4260 | 8 | entry->note=TIFFNote; |
4261 | 8 | entry->stealth=MagickTrue; /* Don't list in '-list format' output */ |
4262 | 8 | entry->module="TIFF"; |
4263 | 8 | entry->coder_class=PrimaryCoderClass; |
4264 | 8 | (void) RegisterMagickInfo(entry); |
4265 | | |
4266 | | /* |
4267 | | Traditional 32-bit TIFF |
4268 | | */ |
4269 | 8 | entry=SetMagickInfo("TIFF"); |
4270 | 8 | entry->thread_support=MagickFalse; /* libtiff uses libjpeg which is not thread safe */ |
4271 | 8 | entry->decoder=(DecoderHandler) ReadTIFFImage; |
4272 | 8 | entry->encoder=(EncoderHandler) WriteTIFFImage; |
4273 | 8 | entry->magick=(MagickHandler) IsTIFF; |
4274 | 8 | entry->seekable_stream=MagickTrue; |
4275 | 8 | entry->description=TIFFDescription; |
4276 | 8 | if (*version != '\0') |
4277 | 8 | entry->version=version; |
4278 | 8 | entry->note=TIFFNote; |
4279 | 8 | entry->module="TIFF"; |
4280 | 8 | entry->coder_class=PrimaryCoderClass; |
4281 | 8 | (void) RegisterMagickInfo(entry); |
4282 | | |
4283 | 8 | #if defined(EXTEND_TIFF_TAGS) |
4284 | | /* |
4285 | | Add our own TIFF tag extensions. |
4286 | | */ |
4287 | 8 | ExtensionTagsInitialize(); |
4288 | 8 | #endif /* defined(EXTEND_TIFF_TAGS) */ |
4289 | | |
4290 | | |
4291 | 8 | #endif /* if defined(HasTIFF) */ |
4292 | 8 | } |
4293 | | |
4294 | | /* |
4295 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
4296 | | % % |
4297 | | % % |
4298 | | % % |
4299 | | % U n r e g i s t e r T I F F I m a g e % |
4300 | | % % |
4301 | | % % |
4302 | | % % |
4303 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
4304 | | % |
4305 | | % Method UnregisterTIFFImage removes format registrations made by the |
4306 | | % TIFF module from the list of supported formats. |
4307 | | % |
4308 | | % The format of the UnregisterTIFFImage method is: |
4309 | | % |
4310 | | % void UnregisterTIFFImage(void) |
4311 | | % |
4312 | | */ |
4313 | | ModuleExport void |
4314 | | UnregisterTIFFImage(void) |
4315 | 0 | { |
4316 | 0 | #if defined(HasTIFF) |
4317 | 0 | #if defined(HasBigTIFF) |
4318 | 0 | (void) UnregisterMagickInfo("BIGTIFF"); |
4319 | 0 | #endif /* defined(HasBigTIFF) */ |
4320 | 0 | (void) UnregisterMagickInfo("GROUP4RAW"); |
4321 | 0 | (void) UnregisterMagickInfo("PTIF"); |
4322 | 0 | (void) UnregisterMagickInfo("TIF"); |
4323 | 0 | (void) UnregisterMagickInfo("TIFF"); |
4324 | | |
4325 | | /* |
4326 | | Destroy thread specific data key. |
4327 | | */ |
4328 | 0 | if (tsd_key != (MagickTsdKey_t) 0) |
4329 | 0 | { |
4330 | 0 | (void) MagickTsdKeyDelete(tsd_key); |
4331 | 0 | tsd_key = (MagickTsdKey_t) 0; |
4332 | 0 | } |
4333 | 0 | #endif |
4334 | 0 | } |
4335 | | |
4336 | | #if defined(HasTIFF) |
4337 | | /* |
4338 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
4339 | | % % |
4340 | | % % |
4341 | | % % |
4342 | | % W r i t e G R O U P 4 R A W I m a g e % |
4343 | | % % |
4344 | | % % |
4345 | | % % |
4346 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
4347 | | % |
4348 | | % Method WriteGROUP4RAWImage writes an image as raw Group4 compressed data. |
4349 | | % |
4350 | | % The format of the WriteGROUP4RAWImage method is: |
4351 | | % |
4352 | | % MagickPassFail WriteGROUP4RAWImage(const ImageInfo *image_info,Image *image) |
4353 | | % |
4354 | | % A description of each parameter follows: |
4355 | | % |
4356 | | % o status: Method WriteGROUP4RAWImage return True if the image is written. |
4357 | | % False is returned is there is of a memory shortage or if the image |
4358 | | % file cannot be opened for writing. |
4359 | | % |
4360 | | % o image_info: Specifies a pointer to a ImageInfo structure. |
4361 | | % |
4362 | | % o image: A pointer to an Image structure. |
4363 | | % |
4364 | | % |
4365 | | */ |
4366 | | static MagickPassFail |
4367 | | WriteGROUP4RAWImage(const ImageInfo *image_info,Image *image) |
4368 | 1.50k | { |
4369 | 1.50k | char |
4370 | 1.50k | temporary_filename[MaxTextExtent]; |
4371 | | |
4372 | 1.50k | Image |
4373 | 1.50k | *huffman_image; |
4374 | | |
4375 | 1.50k | ImageInfo |
4376 | 1.50k | *clone_info; |
4377 | | |
4378 | 1.50k | TIFF |
4379 | 1.50k | *tiff; |
4380 | | |
4381 | 1.50k | toff_t |
4382 | 1.50k | *byte_counts, |
4383 | 1.50k | count, |
4384 | 1.50k | strip_size; |
4385 | | |
4386 | 1.50k | unsigned char |
4387 | 1.50k | *strip; |
4388 | | |
4389 | 1.50k | unsigned int |
4390 | 1.50k | i; |
4391 | | |
4392 | 1.50k | MagickPassFail |
4393 | 1.50k | status; |
4394 | | |
4395 | | /* |
4396 | | Write image as CCITTFax4 TIFF image. |
4397 | | */ |
4398 | 1.50k | assert(image_info != (ImageInfo *) NULL); |
4399 | 1.50k | assert(image_info->signature == MagickSignature); |
4400 | 1.50k | assert(image != (Image *) NULL); |
4401 | 1.50k | assert(image->signature == MagickSignature); |
4402 | | |
4403 | 1.50k | if (!AcquireTemporaryFileName(temporary_filename)) |
4404 | 1.50k | ThrowWriterException(FileOpenError,UnableToCreateTemporaryFile,image); |
4405 | | |
4406 | 1.50k | huffman_image=CloneImage(image,0,0,True,&image->exception); |
4407 | 1.50k | if (huffman_image == (Image *) NULL) |
4408 | 0 | return(False); |
4409 | | |
4410 | 1.50k | (void) SetImageType(huffman_image,BilevelType); |
4411 | 1.50k | FormatString(huffman_image->filename,"tiff:%s",temporary_filename); |
4412 | 1.50k | clone_info=CloneImageInfo((const ImageInfo *) NULL); |
4413 | | /* clone_info->blob=0; */ |
4414 | 1.50k | clone_info->compression=Group4Compression; |
4415 | 1.50k | clone_info->type=BilevelType; |
4416 | 1.50k | (void) AddDefinitions(clone_info,"tiff:strip-per-page=TRUE", |
4417 | 1.50k | &image->exception); |
4418 | 1.50k | (void) AddDefinitions(clone_info,"tiff:fill-order=msb2lsb", |
4419 | 1.50k | &image->exception); |
4420 | 1.50k | status=WriteImage(clone_info,huffman_image); |
4421 | 1.50k | if (status == MagickFail) |
4422 | 0 | CopyException(&image->exception,&huffman_image->exception); |
4423 | 1.50k | DestroyImageInfo(clone_info); |
4424 | 1.50k | DestroyImage(huffman_image); |
4425 | 1.50k | if (status == MagickFail) |
4426 | 0 | { |
4427 | 0 | (void) LiberateTemporaryFile(temporary_filename); |
4428 | 0 | return MagickFail; |
4429 | 0 | } |
4430 | | |
4431 | 1.50k | (void) MagickTsdSetSpecific(tsd_key,(void *) (&image->exception)); |
4432 | 1.50k | (void) TIFFSetErrorHandler((TIFFErrorHandler) TIFFWriteErrorsHandler); |
4433 | 1.50k | (void) TIFFSetWarningHandler((TIFFErrorHandler) (CheckThrowWarnings(image_info) ? |
4434 | 0 | TIFFWarningsThrowException : |
4435 | 1.50k | TIFFWarningsLogOnly)); |
4436 | | |
4437 | 1.50k | tiff=TIFFOpen(temporary_filename,"rb"); |
4438 | 1.50k | if (tiff == (TIFF *) NULL) |
4439 | 0 | { |
4440 | 0 | (void) LiberateTemporaryFile(temporary_filename); |
4441 | 0 | return MagickFail; |
4442 | 0 | } |
4443 | | |
4444 | | /* |
4445 | | Allocate raw strip buffer. |
4446 | | */ |
4447 | 1.50k | if (TIFFGetField(tiff,TIFFTAG_STRIPBYTECOUNTS,&byte_counts) != 1) |
4448 | 0 | { |
4449 | 0 | TIFFClose(tiff); |
4450 | 0 | (void) LiberateTemporaryFile(temporary_filename); |
4451 | 0 | return MagickFail; |
4452 | 0 | } |
4453 | 1.50k | strip_size=byte_counts[0]; |
4454 | 1.50k | for (i=1; i < TIFFNumberOfStrips(tiff); i++) |
4455 | 0 | if (byte_counts[i] > strip_size) |
4456 | 0 | strip_size=byte_counts[i]; |
4457 | 1.50k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4458 | 1.50k | "Allocating %lu bytes of memory for TIFF strip", |
4459 | 1.50k | (unsigned long) strip_size); |
4460 | 1.50k | strip=MagickAllocateResourceLimitedMemory(unsigned char *,(size_t) strip_size); |
4461 | 1.50k | if (strip == (unsigned char *) NULL) |
4462 | 0 | { |
4463 | 0 | TIFFClose(tiff); |
4464 | 0 | (void) LiberateTemporaryFile(temporary_filename); |
4465 | 0 | ThrowWriterException(ResourceLimitError,MemoryAllocationFailed, |
4466 | 0 | image); |
4467 | 0 | } |
4468 | | /* |
4469 | | Open blob for output |
4470 | | */ |
4471 | 1.50k | if ((status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception)) |
4472 | 1.50k | == MagickFail) |
4473 | 0 | { |
4474 | 0 | MagickFreeResourceLimitedMemory(unsigned char *,strip); |
4475 | 0 | TIFFClose(tiff); |
4476 | 0 | (void) LiberateTemporaryFile(temporary_filename); |
4477 | 0 | ThrowWriterException(FileOpenError,UnableToOpenFile,image); |
4478 | 0 | } |
4479 | | |
4480 | | /* |
4481 | | Compress runlength encoded to 2D Huffman pixels. |
4482 | | */ |
4483 | 1.50k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4484 | 1.50k | "Output 2D Huffman pixels."); |
4485 | 3.01k | for (i=0; i < TIFFNumberOfStrips(tiff); i++) |
4486 | 1.50k | { |
4487 | 1.50k | count=TIFFReadRawStrip(tiff,(uint32) i,strip,strip_size); |
4488 | 1.50k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4489 | 1.50k | "Writing strip %u (%lu bytes) to blob ...", |
4490 | 1.50k | i,(unsigned long) count); |
4491 | 1.50k | if ((toff_t) WriteBlob(image,count,strip) != count) |
4492 | 0 | status=MagickFail; |
4493 | 1.50k | } |
4494 | | |
4495 | 1.50k | MagickFreeResourceLimitedMemory(unsigned char *,strip); |
4496 | 1.50k | TIFFClose(tiff); |
4497 | | |
4498 | 1.50k | (void) LiberateTemporaryFile(temporary_filename); |
4499 | 1.50k | status &= CloseBlob(image); |
4500 | 1.50k | return status; |
4501 | 1.50k | } |
4502 | | #endif /* if defined(HasTIFF) */ |
4503 | | |
4504 | | #if defined(HasTIFF) |
4505 | | /* |
4506 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
4507 | | % % |
4508 | | % % |
4509 | | % % |
4510 | | % W r i t e P T I F I m a g e % |
4511 | | % % |
4512 | | % % |
4513 | | % % |
4514 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
4515 | | % |
4516 | | % WritePTIFImage() writes an image in the pyramid-encoded Tagged image file |
4517 | | % format. |
4518 | | % |
4519 | | % The format of the WritePTIFImage method is: |
4520 | | % |
4521 | | % MagickPassFail WritePTIFImage(const ImageInfo *image_info,Image *image) |
4522 | | % |
4523 | | % A description of each parameter follows: |
4524 | | % |
4525 | | % o status: Method WritePTIFImage return MagickPass if the image is written. |
4526 | | % MagickFail is returned is there is of a memory shortage or if the image |
4527 | | % file cannot be opened for writing. |
4528 | | % |
4529 | | % o image_info: Specifies a pointer to a ImageInfo structure. |
4530 | | % |
4531 | | % o image: A pointer to an Image structure. |
4532 | | % |
4533 | | % |
4534 | | */ |
4535 | | static MagickPassFail |
4536 | | WritePTIFImage(const ImageInfo *image_info,Image *image) |
4537 | 5.86k | { |
4538 | 5.86k | Image |
4539 | 5.86k | *pyramid_image; |
4540 | | |
4541 | 5.86k | ImageInfo |
4542 | 5.86k | *clone_info; |
4543 | | |
4544 | 5.86k | FilterTypes |
4545 | 5.86k | filter; |
4546 | | |
4547 | 5.86k | unsigned int |
4548 | 5.86k | status; |
4549 | | |
4550 | 5.86k | const char |
4551 | 5.86k | *def; |
4552 | | |
4553 | 5.86k | RectangleInfo |
4554 | 5.86k | min_geometry; |
4555 | | |
4556 | | /* |
4557 | | Create pyramid-encoded TIFF image. |
4558 | | */ |
4559 | 5.86k | assert(image_info != (const ImageInfo *) NULL); |
4560 | 5.86k | assert(image_info->signature == MagickSignature); |
4561 | 5.86k | assert(image != (Image *) NULL); |
4562 | 5.86k | assert(image->signature == MagickSignature); |
4563 | 5.86k | if (!(((def=AccessDefinition(image_info,"ptif","minimum-geometry")) != NULL) && |
4564 | 0 | (GetGeometry(def,&min_geometry.x,&min_geometry.y,&min_geometry.width, |
4565 | 0 | &min_geometry.height) & (WidthValue|HeightValue)))) |
4566 | 5.86k | { |
4567 | | /* |
4568 | | Minimum default subresolution frame is 32x32 |
4569 | | */ |
4570 | 5.86k | min_geometry.height=32; |
4571 | 5.86k | min_geometry.width=32; |
4572 | 5.86k | } |
4573 | 5.86k | if (image->logging) |
4574 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4575 | 0 | "PTIF minimum pyramid dimensions: %lux%lu", |
4576 | 0 | min_geometry.width, min_geometry.height); |
4577 | 5.86k | filter=TriangleFilter; |
4578 | 5.86k | if (image->is_monochrome) |
4579 | 940 | filter=PointFilter; |
4580 | 5.86k | pyramid_image=CloneImage(image,0,0,True,&image->exception); |
4581 | 5.86k | if (pyramid_image == (Image *) NULL) |
4582 | 5.86k | ThrowWriterException2(FileOpenError,image->exception.reason,image); |
4583 | 5.86k | DestroyBlob(pyramid_image); |
4584 | 5.86k | pyramid_image->blob=ReferenceBlob(image->blob); |
4585 | 5.86k | (void) SetImageAttribute(pyramid_image,"subfiletype","NONE"); |
4586 | 9.25k | while(1) |
4587 | 9.25k | { |
4588 | 9.25k | if ((pyramid_image->columns/2 < min_geometry.width) || |
4589 | 4.75k | (pyramid_image->rows/2 < min_geometry.height)) |
4590 | 5.86k | break; |
4591 | | |
4592 | 3.38k | pyramid_image->next=ResizeImage(image,pyramid_image->columns/2, |
4593 | 3.38k | pyramid_image->rows/2,filter, |
4594 | 3.38k | 1.0,&image->exception); |
4595 | 3.38k | if (pyramid_image->next == (Image *) NULL) |
4596 | 0 | { |
4597 | 0 | DestroyImageList(pyramid_image); |
4598 | 0 | ThrowWriterException2(FileOpenError,image->exception.reason,image); |
4599 | 0 | } |
4600 | 3.38k | DestroyBlob(pyramid_image->next); |
4601 | 3.38k | pyramid_image->next->blob=ReferenceBlob(image->blob); |
4602 | 3.38k | if ((!image->is_monochrome) && (image->storage_class == PseudoClass)) |
4603 | 530 | (void) MapImage(pyramid_image->next,image,False); |
4604 | 3.38k | pyramid_image->next->x_resolution=pyramid_image->x_resolution/2.0; |
4605 | 3.38k | pyramid_image->next->y_resolution=pyramid_image->y_resolution/2.0; |
4606 | 3.38k | (void) SetImageAttribute(pyramid_image->next,"subfiletype","REDUCEDIMAGE"); |
4607 | 3.38k | pyramid_image->next->previous=pyramid_image; |
4608 | 3.38k | pyramid_image=pyramid_image->next; |
4609 | 5.86k | }; |
4610 | 9.25k | while (pyramid_image->previous != (Image *) NULL) |
4611 | 3.38k | pyramid_image=pyramid_image->previous; |
4612 | | /* |
4613 | | Write pyramid-encoded TIFF image. |
4614 | | */ |
4615 | 5.86k | clone_info=CloneImageInfo(image_info); |
4616 | 5.86k | clone_info->adjoin=True; |
4617 | 5.86k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
4618 | 5.86k | "Invoking \"%.1024s\" encoder, monochrome=%s, grayscale=%s", |
4619 | 5.86k | "TIFF", |
4620 | 5.86k | MagickBoolToString(image->is_monochrome), |
4621 | 5.86k | MagickBoolToString(image->is_grayscale)); |
4622 | 5.86k | status=WriteTIFFImage(clone_info,pyramid_image); |
4623 | 5.86k | DestroyImageList(pyramid_image); |
4624 | 5.86k | DestroyImageInfo(clone_info); |
4625 | 5.86k | return(status); |
4626 | 5.86k | } |
4627 | | #endif /* defined(HasTIFF) */ |
4628 | | |
4629 | | #if defined(HasTIFF) |
4630 | | |
4631 | | #if EXPERIMENTAL_EXIF_TAGS |
4632 | | #if TIFFLIB_VERSION >= 20120922 |
4633 | | |
4634 | 84 | #define FLAG_EXIF 1 |
4635 | 531 | #define FLAG_GPS 2 |
4636 | 439 | #define FLAG_BASE 4 |
4637 | | |
4638 | | |
4639 | | /* |
4640 | | static TIFFField customFields[] = { |
4641 | | {544, -1, -1, TIFF_LONG, 0, TIFF_SETGET_UINT32, |
4642 | | TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, "Custom1", NULL}, |
4643 | | }; |
4644 | | |
4645 | | static TIFFFieldArray customFieldArray = {tfiatOther, 0, 1, customFields}; |
4646 | | */ |
4647 | | |
4648 | | |
4649 | | static magick_uint32_t LD_UINT32_LO(const unsigned char *Mem) |
4650 | 102 | { |
4651 | | #ifdef WORDS_BIGENDIAN |
4652 | | return (magick_uint32_t)Mem[0] | ((magick_uint32_t)Mem[1] << 8) | ((magick_uint32_t)Mem[2] << 16) | ((magick_uint32_t)Mem[3] << 24); |
4653 | | #else |
4654 | 102 | return *(magick_uint32_t*)Mem; |
4655 | 102 | #endif |
4656 | 102 | } |
4657 | | |
4658 | | static magick_uint32_t LD_UINT32_HI(const unsigned char *Mem) |
4659 | 9.43k | { |
4660 | 9.43k | return ((magick_uint32_t)Mem[0]<<24) | ((magick_uint32_t)Mem[1] << 16) | ((magick_uint32_t)Mem[2] << 8) | ((magick_uint32_t)Mem[3]); |
4661 | 9.43k | } |
4662 | | |
4663 | | static magick_uint16_t LD_UINT16_LO(const unsigned char *Mem) |
4664 | 90 | { |
4665 | | #ifdef WORDS_BIGENDIAN |
4666 | | return (magick_uint16_t)Mem[0] | ((magick_uint16_t)Mem[1] << 8); |
4667 | | #else |
4668 | 90 | return *(magick_uint16_t*)Mem; |
4669 | 90 | #endif |
4670 | 90 | } |
4671 | | |
4672 | | static magick_uint16_t LD_UINT16_HI(const unsigned char *Mem) |
4673 | 9.39k | { |
4674 | 9.39k | return ((magick_uint16_t)Mem[0] << 8) | ((magick_uint16_t)Mem[1]); |
4675 | 9.39k | } |
4676 | | |
4677 | | |
4678 | | static const char *FipFieldName(const TIFFField *fip) |
4679 | 0 | { |
4680 | 0 | if (fip) |
4681 | 0 | { |
4682 | 0 | const char * const FName = TIFFFieldName(fip); |
4683 | 0 | if (FName==NULL) |
4684 | 0 | return "N/A"; |
4685 | 0 | return FName; |
4686 | 0 | } |
4687 | 0 | return "UNSUPPORTED"; |
4688 | 0 | } |
4689 | | |
4690 | | static const char *FipFieldTypeToStr(const TIFFDataType data_type) |
4691 | 0 | { |
4692 | 0 | const char *str = "UNKNOWN"; |
4693 | 0 | switch (data_type) |
4694 | 0 | { |
4695 | 0 | case TIFF_NOTYPE: /* placeholder */ |
4696 | 0 | str = "NOTYPE"; |
4697 | 0 | break; |
4698 | 0 | case TIFF_BYTE: /* 8-bit unsigned integer */ |
4699 | 0 | str = "BYTE"; |
4700 | 0 | break; |
4701 | 0 | case TIFF_ASCII: /* 8-bit bytes w/ last byte null */ |
4702 | 0 | str = "STRING"; /* vs "ASCII */ |
4703 | 0 | break; |
4704 | 0 | case TIFF_SHORT: /* 16-bit unsigned integer */ |
4705 | 0 | str = "USHORT"; |
4706 | 0 | break; |
4707 | 0 | case TIFF_LONG: /* 32-bit unsigned integer */ |
4708 | 0 | str = "ULONG"; |
4709 | 0 | break; |
4710 | 0 | case TIFF_RATIONAL: /* 64-bit unsigned fraction */ |
4711 | 0 | str = "URATIONAL"; |
4712 | 0 | break; |
4713 | 0 | case TIFF_SBYTE: /* !8-bit signed integer */ |
4714 | 0 | str = "SBYTE"; |
4715 | 0 | break; |
4716 | 0 | case TIFF_UNDEFINED: /* !8-bit untyped data */ |
4717 | 0 | str = "UNDEFINED"; |
4718 | 0 | break; |
4719 | 0 | case TIFF_SSHORT: /* !16-bit signed integer */ |
4720 | 0 | str = "SSHORT"; |
4721 | 0 | break; |
4722 | 0 | case TIFF_SLONG: /* !32-bit signed integer */ |
4723 | 0 | str = "SLONG"; |
4724 | 0 | break; |
4725 | 0 | case TIFF_SRATIONAL: /* !64-bit signed fraction */ |
4726 | 0 | str = "SRATIONAL"; |
4727 | 0 | break; |
4728 | 0 | case TIFF_FLOAT: /* !32-bit IEEE floating point */ |
4729 | 0 | str = "FLOAT"; |
4730 | 0 | break; |
4731 | 0 | case TIFF_DOUBLE: /* !64-bit IEEE floating point */ |
4732 | 0 | str = "DOUBLE"; |
4733 | 0 | break; |
4734 | 0 | case TIFF_IFD: /* %32-bit unsigned integer (offset) */ |
4735 | 0 | str = "IFD"; |
4736 | 0 | break; |
4737 | 0 | #if defined(HasBigTIFF) |
4738 | 0 | case TIFF_LONG8: /* BigTIFF 64-bit unsigned integer */ |
4739 | 0 | str = "LONG8"; |
4740 | 0 | break; |
4741 | 0 | case TIFF_SLONG8: /* BigTIFF 64-bit signed integer */ |
4742 | 0 | str = "SLONG8"; |
4743 | 0 | break; |
4744 | 0 | case TIFF_IFD8: /* BigTIFF 64-bit unsigned integer (offset) */ |
4745 | 0 | str = "IFD8"; |
4746 | 0 | break; |
4747 | 0 | #endif /* if defined(HasBigTIFF) */ |
4748 | 0 | } |
4749 | 0 | return str; |
4750 | 0 | } |
4751 | | |
4752 | | |
4753 | | static int CheckAndStoreStr(TIFF *tiff, const magick_uint16_t Tag, const char *String, const magick_uint32_t StrSize) |
4754 | 0 | { |
4755 | 0 | magick_uint32_t i = StrSize; |
4756 | |
|
4757 | 0 | if (Tag == TIFFTAG_INKNAMES) /* Variant of call is tag dependent, too bad. */ |
4758 | 0 | { |
4759 | 0 | if (StrSize > 0xFFFF) |
4760 | 0 | return 0; |
4761 | | /* TIFFTAG_INKNAMES needs only uint16_t https://libtiff.gitlab.io/libtiff/functions/TIFFSetField.html#c.TIFFSetField */ |
4762 | 0 | return TIFFSetField(tiff, Tag, (magick_uint16_t)StrSize, String); |
4763 | 0 | } |
4764 | | |
4765 | | /* Look for zero terminator. */ |
4766 | 0 | while (i > 0) |
4767 | 0 | { |
4768 | 0 | i--; |
4769 | 0 | if (String[i] == 0) |
4770 | 0 | { |
4771 | 0 | return TIFFSetField(tiff, Tag, String); |
4772 | 0 | } |
4773 | 0 | } |
4774 | | |
4775 | 0 | if (StrSize > 0) |
4776 | 0 | { |
4777 | | /* Try to duplicate unterminated string. */ |
4778 | 0 | char *StringDup = MagickAllocateResourceLimitedMemory(char *, StrSize+1); |
4779 | 0 | if (StringDup != NULL) |
4780 | 0 | { |
4781 | 0 | memcpy(StringDup,String,StrSize); |
4782 | 0 | StringDup[StrSize] = 0; |
4783 | 0 | i = TIFFSetField(tiff, Tag, String); |
4784 | 0 | MagickFreeResourceLimitedMemory(char *,StringDup); |
4785 | 0 | return i; |
4786 | 0 | } |
4787 | 0 | } |
4788 | 0 | return 0; |
4789 | 0 | } |
4790 | | |
4791 | | |
4792 | | static int AddIFDExifFields(TIFF *tiff, unsigned int *ifds_handled, |
4793 | | const unsigned char * const profile_data, |
4794 | | const unsigned char *IFD_data, |
4795 | | const size_t profile_length, |
4796 | | MagickBool logging, magick_uint16_t Flags) |
4797 | 275 | { |
4798 | 275 | magick_uint32_t(*LD_UINT32)(const unsigned char *Mem); |
4799 | 275 | magick_uint16_t(*LD_UINT16)(const unsigned char *Mem); |
4800 | 275 | const TIFFField *fip; |
4801 | 275 | magick_uint16_t EntryNum; |
4802 | 275 | magick_uint16_t Tag, Field; |
4803 | 275 | magick_uint32_t Long2, Value; |
4804 | 275 | const size_t Max_IFD_data_Loops = 4096; |
4805 | 275 | size_t IFD_data_Loops = 0; |
4806 | 275 | MagickBool continue_looping = MagickTrue; |
4807 | 275 | int FieldCount = 0; |
4808 | | |
4809 | 275 | if (*profile_data == 'M') |
4810 | 236 | { |
4811 | 236 | LD_UINT32 = LD_UINT32_HI; |
4812 | 236 | LD_UINT16 = LD_UINT16_HI; |
4813 | 236 | } |
4814 | 39 | else |
4815 | 39 | { |
4816 | 39 | if (*profile_data != 'I') |
4817 | 3 | return 0; |
4818 | 36 | LD_UINT32 = LD_UINT32_LO; |
4819 | 36 | LD_UINT16 = LD_UINT16_LO; |
4820 | 36 | } |
4821 | | |
4822 | 272 | do |
4823 | 302 | { |
4824 | 302 | const unsigned char *Orig_IFD_data |
4825 | 302 | = IFD_data; |
4826 | | |
4827 | 302 | if (profile_length < (size_t)(IFD_data-profile_data)+2) |
4828 | 7 | return 0; |
4829 | 295 | EntryNum = LD_UINT16(IFD_data); /* Number of IFD directory entries */ |
4830 | 295 | if (logging && (Flags & FLAG_BASE) != 0) |
4831 | 0 | (void)LogMagickEvent(CoderEvent,GetMagickModule(), |
4832 | 0 | "IFD EntryNum %u", (unsigned) EntryNum); |
4833 | 295 | if (profile_length < (size_t)(IFD_data-profile_data)+(EntryNum*12)) |
4834 | 101 | return 0; |
4835 | 194 | IFD_data += 2; |
4836 | | |
4837 | 4.75k | while (EntryNum > 0) |
4838 | 4.56k | { |
4839 | | /* Directory Entry */ |
4840 | 4.56k | Tag = LD_UINT16(IFD_data); /* Tag */ |
4841 | 4.56k | Field = LD_UINT16(IFD_data+2); /* Tag Type Code */ |
4842 | 4.56k | Long2 = LD_UINT32(IFD_data+4); /* Count */ |
4843 | 4.56k | Value = LD_UINT32(IFD_data+8); /* Value or Offset */ |
4844 | | |
4845 | 4.56k | fip = TIFFFindField(tiff, Tag, TIFF_ANY); |
4846 | 4.56k | if (logging && (Flags & FLAG_BASE) != 0) |
4847 | 0 | (void)LogMagickEvent(CoderEvent,GetMagickModule(), |
4848 | 0 | "Extracted tag from EXIF %xh.H (%u), Field %u (%s), Long2 %u, val %u %s", |
4849 | 0 | (unsigned) Tag, (unsigned) Tag, (unsigned) Field, |
4850 | 0 | FipFieldTypeToStr((TIFFDataType) Field), |
4851 | 0 | (unsigned) Long2, (unsigned) Value, FipFieldName(fip)); |
4852 | | |
4853 | 4.56k | if (Tag == 0 || |
4854 | 4.14k | Tag == TIFFTAG_COLORMAP || |
4855 | 4.14k | Tag == TIFFTAG_COMPRESSION || |
4856 | 4.11k | Tag == TIFFTAG_IMAGELENGTH || |
4857 | 4.06k | Tag == TIFFTAG_IMAGEWIDTH || |
4858 | 3.95k | Tag == TIFFTAG_SAMPLESPERPIXEL || |
4859 | 3.95k | Tag == TIFFTAG_BITSPERSAMPLE || |
4860 | 3.95k | Tag == TIFFTAG_SAMPLEFORMAT || |
4861 | 3.95k | Tag == TIFFTAG_STRIPOFFSETS || |
4862 | 3.93k | Tag == TIFFTAG_ROWSPERSTRIP || |
4863 | 3.93k | Tag == TIFFTAG_STRIPBYTECOUNTS || |
4864 | 3.92k | Tag == TIFFTAG_ORIENTATION || /* Orientation is handled different way. */ |
4865 | 3.92k | Tag == TIFFTAG_XRESOLUTION || |
4866 | 3.91k | Tag == TIFFTAG_YRESOLUTION || |
4867 | 3.91k | Tag == TIFFTAG_TRANSFERFUNCTION /* Depends on TIFFTAG_BITSPERSAMPLE and TIFFTAG_SAMPLESPERPIXEL (above) */ |
4868 | 4.56k | ) |
4869 | 653 | { |
4870 | 653 | goto NextItem; /* Banned TIFF tags that cannot be copied from EXIF. */ |
4871 | 653 | } |
4872 | | |
4873 | 3.90k | if (Tag == TIFFTAG_EXIFIFD) |
4874 | 0 | { |
4875 | 0 | if (Value >= profile_length) |
4876 | 0 | { |
4877 | 0 | if (logging) |
4878 | 0 | (void)LogMagickEvent(CoderEvent,GetMagickModule(), |
4879 | 0 | "EXIF IFD data length (%u) exceeds profile length (%zu)!", |
4880 | 0 | (unsigned) Value, profile_length); |
4881 | 0 | goto NextItem; |
4882 | 0 | } |
4883 | 0 | if (((Flags & FLAG_EXIF) != 0) && ((*ifds_handled & FLAG_EXIF) == 0)) |
4884 | 0 | { |
4885 | 0 | if (logging) |
4886 | 0 | (void)LogMagickEvent(CoderEvent,GetMagickModule(),"Recursing into EXIF IFD..."); |
4887 | 0 | *ifds_handled |= FLAG_EXIF; |
4888 | |
|
4889 | 0 | FieldCount += AddIFDExifFields(tiff, ifds_handled, profile_data, profile_data+Value, |
4890 | 0 | profile_length, logging, Flags|FLAG_BASE); |
4891 | 0 | if (logging) |
4892 | 0 | (void)LogMagickEvent(CoderEvent,GetMagickModule(),"Recursing out of EXIF IFD..."); |
4893 | 0 | } |
4894 | 0 | goto NextItem; |
4895 | 0 | } |
4896 | 3.90k | if (Tag == TIFFTAG_GPSIFD) |
4897 | 452 | { |
4898 | 452 | if (Value >= profile_length) |
4899 | 144 | { |
4900 | 144 | if (logging) |
4901 | 0 | (void)LogMagickEvent(CoderEvent,GetMagickModule(), |
4902 | 0 | "GPS IFD data length (%u) exceeds profile length (%zu)!", |
4903 | 0 | (unsigned) Value, profile_length); |
4904 | 144 | goto NextItem; |
4905 | 144 | } |
4906 | 308 | if (((Flags & FLAG_GPS) != 0) && ((*ifds_handled & FLAG_GPS) == 0)) |
4907 | 35 | { |
4908 | 35 | if (logging) |
4909 | 0 | (void)LogMagickEvent(CoderEvent,GetMagickModule(),"Recursing into GPS IFD..."); |
4910 | 35 | *ifds_handled |= FLAG_GPS; |
4911 | | |
4912 | 35 | FieldCount += AddIFDExifFields(tiff, ifds_handled, profile_data, profile_data+Value, |
4913 | 35 | profile_length, logging, Flags|FLAG_BASE); |
4914 | 35 | if (logging) |
4915 | 0 | (void)LogMagickEvent(CoderEvent,GetMagickModule(),"Recursing out of GPS IFD..."); |
4916 | 35 | } |
4917 | 308 | goto NextItem; |
4918 | 452 | } |
4919 | | |
4920 | 3.45k | if (fip != NULL && (Flags & FLAG_BASE)!=0) /* libtiff doesn't understand these */ |
4921 | 185 | { |
4922 | 185 | const TIFFDataType FDT = TIFFFieldDataType(fip); |
4923 | 185 | const int WriteCount = TIFFFieldWriteCount(fip); |
4924 | 185 | switch (Field) |
4925 | 185 | { |
4926 | 1 | case TIFF_ASCII: |
4927 | 1 | if (FDT != TIFF_ASCII) |
4928 | 1 | break; /* Incompatible recipe.*/ |
4929 | 0 | if (Long2 <= 4) |
4930 | 0 | { |
4931 | 0 | if (CheckAndStoreStr(tiff, Tag, (const char *) IFD_data+8, Long2)) /* The short string is inside Value. */ |
4932 | 0 | FieldCount++; |
4933 | 0 | } |
4934 | 0 | else |
4935 | 0 | { |
4936 | 0 | if ((Value > (Value+Long2)) || (Value+Long2 >= profile_length-1)) |
4937 | 0 | break; /* String outside EXIF boundary. */ |
4938 | 0 | if (CheckAndStoreStr(tiff, Tag, (const char *) profile_data+Value, Long2)) |
4939 | 0 | FieldCount++; |
4940 | 0 | } |
4941 | 0 | break; |
4942 | | |
4943 | 13 | case TIFF_SHORT: |
4944 | 13 | if (WriteCount!=1) |
4945 | 7 | { |
4946 | 7 | magick_uint16_t *Array; |
4947 | 7 | magick_uint32_t i; |
4948 | 7 | if (FDT != Field) |
4949 | 1 | break; /* Incompatible array type, might be converted in future. */ |
4950 | 6 | if (WriteCount != TIFF_VARIABLE && WriteCount != TIFF_VARIABLE2) |
4951 | 0 | { |
4952 | 0 | if (logging && (Flags & FLAG_BASE) != 0) |
4953 | 0 | (void)LogMagickEvent(CoderEvent,GetMagickModule(),"%s fixed size arrays are not supported yet.", |
4954 | 0 | FipFieldTypeToStr((TIFFDataType) Field)); |
4955 | 0 | break; /* Fixed size arrays not handled. */ |
4956 | 0 | } |
4957 | 6 | if ((Value > (Value+2U*Long2)) || (Value+2U*Long2 >= profile_length-1)) |
4958 | 3 | break; |
4959 | 3 | if (Long2 == 0) |
4960 | 1 | break; |
4961 | 2 | Array = MagickAllocateResourceLimitedMemory(magick_uint16_t *, 2*Long2); |
4962 | 2 | if (Array == NULL) |
4963 | 0 | break; |
4964 | 67 | for (i=0; i < Long2; i++) |
4965 | 65 | Array[i] = LD_UINT16(profile_data+Value+2*i); |
4966 | 2 | if (WriteCount == TIFF_VARIABLE) |
4967 | 2 | { |
4968 | 2 | if (TIFFSetField(tiff, Tag, (int)Long2, Array)) /* Argument 3 type int, argument 4 uint16_t*. */ |
4969 | 2 | FieldCount++; |
4970 | 2 | } else if (WriteCount == TIFF_VARIABLE2) |
4971 | 0 | { |
4972 | 0 | if (TIFFSetField(tiff, Tag, Long2, Array)) /* Argument 3 type uint32_t, argument 4 uint16_t*.. */ |
4973 | 0 | FieldCount++; |
4974 | 0 | } |
4975 | 2 | MagickFreeResourceLimitedMemory(magick_uint16_t *,Array); |
4976 | 2 | break; |
4977 | 2 | } |
4978 | 6 | goto Scalar; |
4979 | | |
4980 | 22 | case TIFF_LONG: |
4981 | 22 | if (WriteCount != 1) |
4982 | 1 | { |
4983 | 1 | magick_uint32_t *Array; |
4984 | 1 | magick_uint32_t i; |
4985 | 1 | if (FDT != Field) |
4986 | 1 | break; /* Incompatible array type, might be converted in future. */ |
4987 | 0 | if (WriteCount != TIFF_VARIABLE && WriteCount != TIFF_VARIABLE2) |
4988 | 0 | { |
4989 | 0 | if (logging && (Flags & FLAG_BASE) != 0) |
4990 | 0 | (void)LogMagickEvent(CoderEvent,GetMagickModule(),"%s fixed size arrays are not supported yet.", |
4991 | 0 | FipFieldTypeToStr((TIFFDataType) Field)); |
4992 | 0 | break; /* Fixed size arrays not handled. */ |
4993 | 0 | } |
4994 | 0 | if ((Value > (Value+4U*Long2)) || (Value+4U*Long2 >= profile_length-1)) |
4995 | 0 | break; |
4996 | 0 | if (Long2==0) |
4997 | 0 | break; |
4998 | 0 | Array = MagickAllocateResourceLimitedMemory(magick_uint32_t *, 4*Long2); |
4999 | 0 | if (Array == NULL) |
5000 | 0 | break; |
5001 | 0 | for (i=0; i < Long2; i++) |
5002 | 0 | Array[i] = LD_UINT32(profile_data+Value+4*i); |
5003 | 0 | if (WriteCount == TIFF_VARIABLE) |
5004 | 0 | { |
5005 | 0 | if (TIFFSetField(tiff, Tag, (int)Long2, Array)) /* Argument 3 type int, argument 4 uint32_t*. */ |
5006 | 0 | FieldCount++; |
5007 | 0 | } else if (WriteCount == TIFF_VARIABLE2) |
5008 | 0 | { |
5009 | 0 | if (TIFFSetField(tiff, Tag, Long2, Array)) /* Argument 3 type uint32_t, argument 4 uint32_t*. */ |
5010 | 0 | FieldCount++; |
5011 | 0 | } |
5012 | 0 | MagickFreeResourceLimitedMemory(magick_uint32_t *,Array); |
5013 | 0 | break; |
5014 | 0 | } |
5015 | 21 | goto Scalar; |
5016 | | |
5017 | 21 | case TIFF_BYTE: |
5018 | 15 | if (WriteCount != 1) |
5019 | 0 | { |
5020 | 0 | if (FDT != Field) |
5021 | 0 | break; /* Incompatible array type, might be converted in future. */ |
5022 | 0 | if (WriteCount != TIFF_VARIABLE && WriteCount != TIFF_VARIABLE2) |
5023 | 0 | { |
5024 | 0 | if ((WriteCount <= 0) || (Long2 < (magick_uint32_t)WriteCount)) |
5025 | 0 | break; /* Too small amount of mandatory items. */ |
5026 | 0 | if (Long2 < (magick_uint32_t)WriteCount) |
5027 | 0 | break; /* Too small amount of mandatory items. */ |
5028 | 0 | if (Long2 <= 4) |
5029 | 0 | { |
5030 | 0 | if (TIFFSetField(tiff, Tag, IFD_data+8)) /* Argument 3 uint8_t[4]. */ |
5031 | 0 | FieldCount++; |
5032 | 0 | } |
5033 | 0 | else |
5034 | 0 | { |
5035 | 0 | if ((Value > (Value+Long2)) || (Value+Long2 >= profile_length-1)) |
5036 | 0 | break; |
5037 | 0 | if (TIFFSetField(tiff, Tag, profile_data+Value)) /* Argument 3 uint8_t[4]. */ |
5038 | 0 | FieldCount++; |
5039 | 0 | } |
5040 | 0 | break; /* Fixed size arrays not handled. */ |
5041 | 0 | } |
5042 | 0 | if ((Value > (Value+Long2)) || (Value+Long2 >= profile_length-1)) |
5043 | 0 | break; |
5044 | | /* No need to convert endianity for BYTES. */ |
5045 | 0 | if (WriteCount == TIFF_VARIABLE) |
5046 | 0 | { |
5047 | 0 | if (TIFFSetField(tiff, Tag, (int)Long2, profile_data+Value)) /* Argument 3 type int, argument 4 uint8_t*. */ |
5048 | 0 | FieldCount++; |
5049 | 0 | } else if (WriteCount == TIFF_VARIABLE2) |
5050 | 0 | { |
5051 | 0 | if (TIFFSetField(tiff, Tag, Long2, profile_data+Value)) /* Argument 3 type uint32_t, argument 4 uint8_t*. */ |
5052 | 0 | FieldCount++; |
5053 | 0 | } |
5054 | 0 | break; |
5055 | 0 | } |
5056 | | |
5057 | 42 | Scalar: |
5058 | 42 | if (FDT == TIFF_SHORT) |
5059 | 10 | { |
5060 | 10 | if (TIFFSetField(tiff, Tag, (unsigned)Value & 0xFFFF)) |
5061 | 10 | FieldCount++; |
5062 | 10 | } |
5063 | 42 | if (FDT != TIFF_BYTE && FDT != TIFF_LONG) |
5064 | 41 | break; |
5065 | 1 | if (TIFFSetField(tiff, Tag, Value)) |
5066 | 1 | FieldCount++; |
5067 | 1 | break; |
5068 | | |
5069 | 1 | case TIFF_SRATIONAL: |
5070 | 1 | if (logging && (Flags & FLAG_BASE) != 0) |
5071 | 0 | (void)LogMagickEvent(CoderEvent,GetMagickModule(),"TIFF_SRATIONAL type is not supported yet."); |
5072 | 1 | break; |
5073 | 28 | case TIFF_RATIONAL: |
5074 | 28 | if (FDT != TIFF_RATIONAL) |
5075 | 11 | break; |
5076 | 17 | if (WriteCount != 1) |
5077 | 17 | { |
5078 | 17 | if (WriteCount > 1) |
5079 | 17 | { |
5080 | 17 | if (Long2 < (magick_uint32_t)WriteCount) |
5081 | 14 | break; /* Too small amount of mandatory items. */ |
5082 | 3 | if ((Value > (Value+8*WriteCount)) || (Value+8*WriteCount >= profile_length-1)) |
5083 | 3 | break; /* Array falls over blob boundary. */ |
5084 | 0 | #if TIFFLIB_VERSION >= 20230609 |
5085 | 0 | { |
5086 | 0 | int i; |
5087 | 0 | switch (TIFFFieldSetGetSize(fip)) |
5088 | 0 | { |
5089 | 0 | case 8: /* double array is required in input. */ |
5090 | 0 | { |
5091 | 0 | double *ArrayD; |
5092 | 0 | ArrayD = MagickAllocateResourceLimitedMemory(double *, sizeof(double)*WriteCount); |
5093 | 0 | if (ArrayD == NULL) |
5094 | 0 | break; |
5095 | 0 | for (i=0; i < WriteCount; i++) |
5096 | 0 | { |
5097 | 0 | const magick_uint32_t val = LD_UINT32(profile_data+Value+4+8*i); |
5098 | 0 | ArrayD[i] = (val==0) ? 0.0 : (LD_UINT32(profile_data+Value+8*i) / (double)val); |
5099 | 0 | } |
5100 | 0 | if (TIFFSetField(tiff, Tag, ArrayD)) |
5101 | 0 | FieldCount++; |
5102 | 0 | MagickFreeResourceLimitedMemory(double *,ArrayD); |
5103 | 0 | } |
5104 | 0 | break; |
5105 | 0 | case 4: /* float array is required in input. */ |
5106 | 0 | { |
5107 | 0 | float *ArrayF; |
5108 | 0 | ArrayF = MagickAllocateResourceLimitedMemory(float *, sizeof(float)*WriteCount); |
5109 | 0 | if (ArrayF==NULL) |
5110 | 0 | break; |
5111 | 0 | for (i=0; i < WriteCount; i++) |
5112 | 0 | { |
5113 | 0 | const magick_uint32_t val = LD_UINT32(profile_data+Value+4+8*i); |
5114 | 0 | ArrayF[i] = (val==0) ? 0.0f : (LD_UINT32(profile_data+Value+8*i) / (float)val); |
5115 | 0 | } |
5116 | 0 | if (TIFFSetField(tiff, Tag, ArrayF)) |
5117 | 0 | FieldCount++; |
5118 | 0 | MagickFreeResourceLimitedMemory(float *,ArrayF); |
5119 | 0 | } |
5120 | 0 | break; |
5121 | 0 | } |
5122 | 0 | } |
5123 | 0 | #endif |
5124 | 0 | break; |
5125 | 0 | } |
5126 | | |
5127 | 0 | if (WriteCount == TIFF_VARIABLE || WriteCount == TIFF_VARIABLE2) |
5128 | 0 | { |
5129 | 0 | if (logging && (Flags & FLAG_BASE) != 0) |
5130 | 0 | (void)LogMagickEvent(CoderEvent,GetMagickModule(),"Variable size fractional arrays are not supported yet."); |
5131 | 0 | break; |
5132 | 0 | } |
5133 | 0 | break; |
5134 | 0 | } |
5135 | 0 | else /* Process as scalar. */ |
5136 | 0 | { |
5137 | 0 | double d; |
5138 | 0 | if ((Value > (Value+8U)) || (Value+8U >= profile_length)) |
5139 | 0 | break; |
5140 | 0 | d = LD_UINT32(profile_data+Value+4); |
5141 | 0 | if (d == 0) |
5142 | 0 | break; /* Prevent division by 0. */ |
5143 | 0 | d = LD_UINT32(profile_data+Value) / d; |
5144 | 0 | if (TIFFSetField(tiff, Tag, d)) |
5145 | 0 | FieldCount++; |
5146 | 0 | } |
5147 | 0 | break; |
5148 | 185 | } |
5149 | 185 | } |
5150 | | |
5151 | 4.56k | NextItem: |
5152 | 4.56k | if (profile_length <= 12) |
5153 | 0 | break; |
5154 | 4.56k | IFD_data += 12; |
5155 | 4.56k | EntryNum--; |
5156 | 4.56k | } |
5157 | | |
5158 | 194 | if (profile_length < (size_t)(IFD_data-profile_data)+4) |
5159 | 24 | break; |
5160 | 170 | Value = LD_UINT32(IFD_data); |
5161 | 170 | if (Value >= profile_length) |
5162 | 131 | break; |
5163 | 39 | IFD_data = profile_data+Value; |
5164 | | /* |
5165 | | It is possible for the calculated IFD_data to create a |
5166 | | non-terminal loop by computing the same IFD or one earlier in |
5167 | | IFD list. Defend against this by placing a limit on loops, as |
5168 | | well as detecting the immediate looping case. |
5169 | | */ |
5170 | 39 | IFD_data_Loops++; |
5171 | 39 | if (Orig_IFD_data == IFD_data) |
5172 | 2 | { |
5173 | 2 | (void)LogMagickEvent(CoderEvent,GetMagickModule(), |
5174 | 2 | "IFD direct loop detected!"); |
5175 | 2 | continue_looping = MagickFalse; /* Break looping */ |
5176 | 2 | } |
5177 | 39 | if (IFD_data_Loops == Max_IFD_data_Loops) |
5178 | 0 | continue_looping = MagickFalse; |
5179 | 39 | } while ((continue_looping) && (Value > 8)); |
5180 | | |
5181 | 164 | if ((logging && (Flags & FLAG_BASE) != 0) && (!continue_looping)) |
5182 | 0 | (void)LogMagickEvent(CoderEvent,GetMagickModule(), |
5183 | 0 | "IFD looping detected (%zu loops)!", IFD_data_Loops); |
5184 | | |
5185 | 164 | return FieldCount; |
5186 | 272 | } |
5187 | | |
5188 | | |
5189 | | static int AddExifFields(TIFF *tiff, const unsigned char *profile_data, size_t profile_length, MagickBool logging, magick_uint16_t Flags) |
5190 | 252 | { |
5191 | 252 | const char EXIF[6] |
5192 | 252 | = {'E','x','i','f',0,0}; |
5193 | | |
5194 | 252 | unsigned int |
5195 | 252 | ifds_handled = 0; |
5196 | | |
5197 | 252 | if (profile_data==NULL || profile_length < 12+8) |
5198 | 0 | return 0; |
5199 | | |
5200 | 252 | if (memcmp(EXIF,profile_data,6)==0) |
5201 | 249 | { |
5202 | 249 | profile_data += 6; |
5203 | 249 | profile_length -= 6; |
5204 | 249 | if (profile_length < 12+8) |
5205 | 3 | return 0; |
5206 | 249 | } |
5207 | | |
5208 | 249 | if (profile_data[0] != profile_data[1]) |
5209 | 9 | return 0; |
5210 | | |
5211 | 240 | return AddIFDExifFields(tiff, &ifds_handled, profile_data, |
5212 | 240 | profile_data + ((profile_data[0]=='M')?LD_UINT32_HI(profile_data+4):LD_UINT32_LO(profile_data+4)), |
5213 | 240 | profile_length-2, logging, Flags); |
5214 | 249 | } |
5215 | | |
5216 | | #endif /* if TIFFLIB_VERSION >= 20120922 */ |
5217 | | #endif /* if EXPERIMENTAL_EXIF_TAGS */ |
5218 | | |
5219 | | /* |
5220 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
5221 | | % % |
5222 | | % % |
5223 | | % % |
5224 | | % W r i t e T I F F I m a g e % |
5225 | | % % |
5226 | | % % |
5227 | | % % |
5228 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
5229 | | % |
5230 | | % Method WriteTIFFImage writes an image in the Tagged image file format. |
5231 | | % |
5232 | | % The format of the WriteTIFFImage method is: |
5233 | | % |
5234 | | % MagickPassFail WriteTIFFImage(const ImageInfo *image_info,Image *image) |
5235 | | % |
5236 | | % A description of each parameter follows: |
5237 | | % |
5238 | | % o status: Method WriteTIFFImage return True if the image is written. |
5239 | | % False is returned is there is of a memory shortage or if the image |
5240 | | % file cannot be opened for writing. |
5241 | | % |
5242 | | % o image_info: Specifies a pointer to a ImageInfo structure. |
5243 | | % |
5244 | | % o image: A pointer to an Image structure. |
5245 | | % |
5246 | | % |
5247 | | */ |
5248 | | |
5249 | | static void |
5250 | | WriteNewsProfile(TIFF *tiff, |
5251 | | int profile_tag, |
5252 | | const unsigned char *profile_data, |
5253 | | const size_t profile_length) |
5254 | 403 | { |
5255 | 403 | unsigned char |
5256 | 403 | *profile=0; |
5257 | | |
5258 | 403 | size_t |
5259 | 403 | length; |
5260 | | |
5261 | 403 | assert(tiff != (TIFF *) NULL); |
5262 | 403 | assert(profile_tag != 0); |
5263 | 403 | assert(profile_data != (const unsigned char *) NULL); |
5264 | | |
5265 | 403 | length = (uint32) profile_length; |
5266 | 403 | if (length == 0) |
5267 | 0 | return; |
5268 | | |
5269 | 403 | if (profile_tag == TIFFTAG_RICHTIFFIPTC) |
5270 | 0 | { |
5271 | | /* |
5272 | | Handle TIFFTAG_RICHTIFFIPTC tag. |
5273 | | */ |
5274 | 0 | length += (4-(length & 0x03)); /* Round up for long word alignment */ |
5275 | 0 | profile=MagickAllocateResourceLimitedClearedMemory(unsigned char *,length); |
5276 | 0 | if (profile == (unsigned char *) NULL) |
5277 | 0 | return; |
5278 | 0 | (void) memcpy(profile,profile_data,profile_length); |
5279 | |
|
5280 | 0 | if (TIFFIsByteSwapped(tiff)) |
5281 | 0 | TIFFSwabArrayOfLong((uint32 *) profile,length/4); |
5282 | | |
5283 | | /* Tag is type TIFF_LONG so byte length is divided by four */ |
5284 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5285 | 0 | "TIFFSetField(tiff=0x%p,tag=%d," |
5286 | 0 | "length=%" MAGICK_SIZE_T_F "u,data=0x%p)", |
5287 | 0 | tiff,profile_tag,(MAGICK_SIZE_T) length/4,profile); |
5288 | 0 | (void) TIFFSetField(tiff,profile_tag,(uint32) length/4,(void *) profile); |
5289 | 0 | } |
5290 | 403 | else if (profile_tag == TIFFTAG_PHOTOSHOP) |
5291 | 403 | { |
5292 | | /* |
5293 | | Handle TIFFTAG_PHOTOSHOP tag. |
5294 | | */ |
5295 | 403 | length += (length & 0x01); /* Round up for Photoshop */ |
5296 | | #if defined(GET_ONLY_IPTC_DATA) |
5297 | | length += 12; /* Space for 8BIM header */ |
5298 | | profile=MagickAllocateResourceLimitedClearedMemory(unsigned char *,length); |
5299 | | if (profile == (unsigned char *) NULL) |
5300 | | return; |
5301 | | (void) memcpy(profile,"8BIM\04\04\0\0",8); |
5302 | | profile[8]=(length >> 24) & 0xff; |
5303 | | profile[9]=(length >> 16) & 0xff; |
5304 | | profile[10]=(length >> 8) & 0xff; |
5305 | | profile[11]=length & 0xff; |
5306 | | (void) memcpy(profile+12,profile_data,profile_length); |
5307 | | #else |
5308 | 403 | profile=MagickAllocateResourceLimitedClearedMemory(unsigned char *,length); |
5309 | 403 | if (profile == (unsigned char *) NULL) |
5310 | 0 | return; |
5311 | 403 | (void) memcpy(profile,profile_data,profile_length); |
5312 | 403 | #endif |
5313 | 403 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5314 | 403 | "TIFFSetField(tiff=0x%p,tag=%d," |
5315 | 403 | "length=%" MAGICK_SIZE_T_F "u,data=0x%p)", |
5316 | 403 | tiff,profile_tag,(MAGICK_SIZE_T) length,profile); |
5317 | 403 | (void) TIFFSetField(tiff,profile_tag,(uint32) length,(void *) profile); |
5318 | 403 | } |
5319 | | |
5320 | 403 | MagickFreeResourceLimitedMemory(unsigned char *,profile); |
5321 | 403 | } |
5322 | | |
5323 | 0 | #define ThrowTIFFWriterException(code_,reason_,image_) \ |
5324 | 0 | { \ |
5325 | 0 | if (tiff != (TIFF *) NULL) \ |
5326 | 0 | TIFFClose(tiff); \ |
5327 | 0 | ThrowWriterException(code_,reason_,image_); \ |
5328 | 0 | } |
5329 | | |
5330 | | static MagickPassFail |
5331 | | WriteTIFFImage(const ImageInfo *image_info,Image *image) |
5332 | 18.7k | { |
5333 | 18.7k | char |
5334 | 18.7k | filename[MaxTextExtent], |
5335 | 18.7k | open_flags[MaxTextExtent]; |
5336 | | |
5337 | 18.7k | const ImageAttribute |
5338 | 18.7k | *attribute; |
5339 | | |
5340 | 18.7k | unsigned int |
5341 | 18.7k | x, |
5342 | 18.7k | y; |
5343 | | |
5344 | 18.7k | register unsigned int |
5345 | 18.7k | i; |
5346 | | |
5347 | 18.7k | TIFF |
5348 | 18.7k | *tiff = (TIFF *) NULL; |
5349 | | |
5350 | 18.7k | size_t |
5351 | 18.7k | bytes_per_strip_target = TIFF_BYTES_PER_STRIP; |
5352 | | |
5353 | 18.7k | uint16 |
5354 | 18.7k | bits_per_sample, |
5355 | 18.7k | compress_tag, |
5356 | 18.7k | fill_order, |
5357 | 18.7k | photometric, |
5358 | 18.7k | planar_config, |
5359 | 18.7k | predictor, |
5360 | 18.7k | sample_format, |
5361 | 18.7k | samples_per_pixel; |
5362 | | |
5363 | 18.7k | uint32 |
5364 | 18.7k | rows_per_strip; |
5365 | | |
5366 | 18.7k | tsize_t |
5367 | 18.7k | scanline_size; |
5368 | | |
5369 | 18.7k | AlphaType |
5370 | 18.7k | alpha_type; |
5371 | | |
5372 | 18.7k | CompressionType |
5373 | 18.7k | compression=UndefinedCompression; |
5374 | | |
5375 | 18.7k | TIFFMethod |
5376 | 18.7k | method; |
5377 | | |
5378 | 18.7k | Magick_TIFF_ClientData |
5379 | 18.7k | client_data; |
5380 | | |
5381 | 18.7k | ExportPixelAreaOptions |
5382 | 18.7k | export_options; |
5383 | | |
5384 | 18.7k | ExportPixelAreaInfo |
5385 | 18.7k | export_info; |
5386 | | |
5387 | 18.7k | MagickBool |
5388 | 18.7k | logging=MagickFalse; |
5389 | | |
5390 | 18.7k | MagickPassFail |
5391 | 18.7k | status; |
5392 | | |
5393 | 18.7k | unsigned long |
5394 | 18.7k | depth, |
5395 | 18.7k | scene; |
5396 | | |
5397 | 18.7k | size_t |
5398 | 18.7k | image_list_length; |
5399 | | |
5400 | | |
5401 | | |
5402 | | /* |
5403 | | Open TIFF file. |
5404 | | */ |
5405 | 18.7k | assert(image_info != (const ImageInfo *) NULL); |
5406 | 18.7k | assert(image_info->signature == MagickSignature); |
5407 | 18.7k | assert(image != (Image *) NULL); |
5408 | 18.7k | assert(image->signature == MagickSignature); |
5409 | 18.7k | image_list_length=GetImageListLength(image); |
5410 | 18.7k | logging=IsEventLogged(CoderEvent); |
5411 | 18.7k | status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception); |
5412 | 18.7k | if (status == MagickFail) |
5413 | 18.7k | ThrowWriterException(FileOpenError,UnableToOpenFile,image); |
5414 | 18.7k | (void) MagickTsdSetSpecific(tsd_key,(void *) (&image->exception)); |
5415 | 18.7k | (void) TIFFSetErrorHandler((TIFFErrorHandler) TIFFWriteErrorsHandler); |
5416 | 18.7k | (void) TIFFSetWarningHandler((TIFFErrorHandler) (CheckThrowWarnings(image_info) ? |
5417 | 0 | TIFFWarningsThrowException : |
5418 | 18.7k | TIFFWarningsLogOnly)); |
5419 | 18.7k | (void) strlcpy(filename,image->filename,MaxTextExtent); |
5420 | | /* |
5421 | | Open TIFF file |
5422 | | |
5423 | | 'w' open for write |
5424 | | 'l' force little-endian byte order |
5425 | | 'b' force big-endian byte order |
5426 | | 'L' force LSB to MSB bit order (weird) |
5427 | | 'B' force MSB to LSB bit order (normal) |
5428 | | '8' 64-bit offsets (BigTIFF) |
5429 | | */ |
5430 | 18.7k | (void) strlcpy(open_flags, "w", sizeof(open_flags)); |
5431 | 18.7k | switch (image_info->endian) |
5432 | 18.7k | { |
5433 | 0 | case LSBEndian: |
5434 | 0 | (void) strlcat(open_flags, "l", sizeof(open_flags)); |
5435 | 0 | if (logging) |
5436 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5437 | 0 | "Using little endian byte order"); |
5438 | 0 | break; |
5439 | 0 | case MSBEndian: |
5440 | 0 | (void) strlcat(open_flags, "b", sizeof(open_flags)); |
5441 | 0 | if (logging) |
5442 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5443 | 0 | "Using big endian byte order"); |
5444 | 0 | break; |
5445 | 0 | default: |
5446 | 18.7k | case UndefinedEndian: |
5447 | 18.7k | { |
5448 | | /* Default is native byte order */ |
5449 | 18.7k | if (logging) |
5450 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5451 | 0 | "Using native endian byte order"); |
5452 | 18.7k | } |
5453 | 18.7k | } |
5454 | | |
5455 | 18.7k | #if defined(HasBigTIFF) |
5456 | 18.7k | if (strcmp(image_info->magick,"BIGTIFF") == 0) |
5457 | 5.14k | { |
5458 | 5.14k | (void) strlcat(open_flags, "8", sizeof(open_flags)); |
5459 | 5.14k | if (logging) |
5460 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5461 | 0 | "Using 64-bit offsets (BigTIFF format)"); |
5462 | 5.14k | } |
5463 | 18.7k | #endif |
5464 | | |
5465 | 18.7k | if (logging) |
5466 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5467 | 0 | "Opening TIFF file \"%s\" using open flags \"%s\".", |
5468 | 0 | filename,open_flags); |
5469 | 18.7k | client_data.image=image; |
5470 | 18.7k | client_data.image_info=image_info; |
5471 | 18.7k | #if defined(HAVE_TIFFERROREXTR) |
5472 | 18.7k | { |
5473 | 18.7k | TIFFOpenOptions *open_options = TIFFOpenOptionsAlloc(); |
5474 | 18.7k | TIFFOpenOptionsSetErrorHandlerExtR(open_options, TIFFWriteErrorsHandlerExtR, (void *) &image->exception); |
5475 | 18.7k | TIFFOpenOptionsSetWarningHandlerExtR(open_options, TIFFWriteErrorsHandlerExtR, (void *) &image->exception); /* FIXME */ |
5476 | 18.7k | tiff=TIFFClientOpenExt(filename,open_flags,(thandle_t) &client_data, |
5477 | 18.7k | TIFFReadBlob,TIFFWriteBlob,TIFFSeekBlob, |
5478 | 18.7k | TIFFCloseBlob,TIFFGetBlobSize,TIFFMapBlob, |
5479 | 18.7k | TIFFUnmapBlob, |
5480 | 18.7k | open_options); |
5481 | 18.7k | TIFFOpenOptionsFree(open_options); |
5482 | 18.7k | } |
5483 | | #else |
5484 | | { |
5485 | | tiff=TIFFClientOpen(filename,open_flags,(thandle_t) &client_data, |
5486 | | TIFFReadBlob,TIFFWriteBlob,TIFFSeekBlob, |
5487 | | TIFFCloseBlob,TIFFGetBlobSize,TIFFMapBlob, |
5488 | | TIFFUnmapBlob); |
5489 | | } |
5490 | | #endif /* if defined(HAVE_TIFFERROREXTR) */ |
5491 | 18.7k | if (tiff == (TIFF *) NULL) |
5492 | 0 | { |
5493 | 0 | if (GetBlobIsOpen(image)) |
5494 | 0 | CloseBlob(image); |
5495 | 0 | return(MagickFail); |
5496 | 0 | } |
5497 | 18.7k | scene=0; |
5498 | 18.7k | do |
5499 | 28.4k | { |
5500 | 28.4k | ImageCharacteristics |
5501 | 28.4k | characteristics; |
5502 | | |
5503 | 28.4k | if ((image->columns == 0) || (image->rows == 0) || !GetPixelCachePresent(image)) |
5504 | 1 | { |
5505 | 1 | if (logging) |
5506 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5507 | 0 | "Image columns=%lu, rows=%lu, pixel-cache=%s", |
5508 | 0 | image->columns, image->rows, |
5509 | 0 | GetPixelCachePresent(image) ? "Present" : "Missing!"); |
5510 | 1 | ThrowException(&(image->exception),CoderError,ImageColumnOrRowSizeIsNotSupported,image->filename); |
5511 | 1 | break; |
5512 | 1 | } |
5513 | | |
5514 | | /* |
5515 | | Initialize TIFF fields. |
5516 | | */ |
5517 | 28.4k | (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_SAMPLESPERPIXEL, |
5518 | 28.4k | &samples_per_pixel); |
5519 | 28.4k | (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_BITSPERSAMPLE, |
5520 | 28.4k | &bits_per_sample); |
5521 | 28.4k | (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_SAMPLEFORMAT,&sample_format); |
5522 | 28.4k | (void) TIFFSetField(tiff,TIFFTAG_IMAGELENGTH,(uint32) image->rows); |
5523 | 28.4k | (void) TIFFSetField(tiff,TIFFTAG_IMAGEWIDTH,(uint32) image->columns); |
5524 | | |
5525 | 28.4k | ExportPixelAreaOptionsInit(&export_options); |
5526 | 28.4k | depth=image->depth; |
5527 | 28.4k | bits_per_sample=8; |
5528 | 28.4k | predictor=0U; |
5529 | 28.4k | method=ScanLineMethod; |
5530 | 28.4k | if ((AccessDefinition(image_info,"tiff","tile")) || |
5531 | 28.4k | (AccessDefinition(image_info,"tiff","tile-geometry")) || |
5532 | 28.4k | (AccessDefinition(image_info,"tiff","tile-width")) || |
5533 | 28.4k | (AccessDefinition(image_info,"tiff","tile-height"))) |
5534 | 0 | method=TiledMethod; |
5535 | | |
5536 | | /* |
5537 | | Decide how to compress the image. |
5538 | | */ |
5539 | 28.4k | compression=image->compression; |
5540 | 28.4k | if (image_info->compression != UndefinedCompression) |
5541 | 1.50k | compression=image_info->compression; |
5542 | 28.4k | if (UndefinedCompression == compression) |
5543 | 7.61k | compression=NoCompression; |
5544 | | |
5545 | | /* |
5546 | | Ensure that only supported compression types are requested. |
5547 | | */ |
5548 | 28.4k | { |
5549 | 28.4k | char |
5550 | 28.4k | compression_name[MaxTextExtent]; |
5551 | | |
5552 | 28.4k | if (CompressionSupported(compression,compression_name) != MagickTrue) |
5553 | 0 | { |
5554 | 0 | compression=NoCompression; |
5555 | 0 | if (logging) |
5556 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5557 | 0 | "%s compression not supported. " |
5558 | 0 | "Compression request removed", |
5559 | 0 | compression_name); |
5560 | 0 | } |
5561 | 28.4k | } |
5562 | | |
5563 | | /* |
5564 | | Determine libtiff compression settings. |
5565 | | */ |
5566 | 28.4k | compress_tag=COMPRESSION_NONE; |
5567 | 28.4k | fill_order=FILLORDER_MSB2LSB; |
5568 | 28.4k | switch (compression) |
5569 | 28.4k | { |
5570 | | /* |
5571 | | Note that RFC 2301 recommends using LSB2MSB fill order for FAX |
5572 | | since it is the transmission order used on the wire for FAX. |
5573 | | However, it also states that all conforming readers should be |
5574 | | able to read data in both bit orders. |
5575 | | */ |
5576 | 1.24k | case FaxCompression: |
5577 | 1.24k | { |
5578 | 1.24k | compress_tag=COMPRESSION_CCITTFAX3; |
5579 | 1.24k | fill_order=FILLORDER_LSB2MSB; |
5580 | 1.24k | break; |
5581 | 0 | } |
5582 | 3.59k | case Group4Compression: |
5583 | 3.59k | { |
5584 | 3.59k | compress_tag=COMPRESSION_CCITTFAX4; |
5585 | 3.59k | fill_order=FILLORDER_LSB2MSB; |
5586 | 3.59k | break; |
5587 | 0 | } |
5588 | 0 | #if defined(COMPRESSION_JBIG) |
5589 | 0 | case JBIG1Compression: |
5590 | 0 | { |
5591 | 0 | compress_tag=COMPRESSION_JBIG; |
5592 | 0 | fill_order=FILLORDER_LSB2MSB; |
5593 | 0 | break; |
5594 | 0 | } |
5595 | 0 | #endif /* defined(COMPRESSION_JBIG) */ |
5596 | 5.35k | case JPEGCompression: |
5597 | 5.35k | { |
5598 | 5.35k | compress_tag=COMPRESSION_JPEG; |
5599 | 5.35k | break; |
5600 | 0 | } |
5601 | 810 | case LZWCompression: |
5602 | 810 | { |
5603 | 810 | compress_tag=COMPRESSION_LZW; |
5604 | 810 | break; |
5605 | 0 | } |
5606 | 0 | #if defined(COMPRESSION_LZMA) |
5607 | 0 | case LZMACompression: |
5608 | 0 | { |
5609 | 0 | compress_tag=COMPRESSION_LZMA; |
5610 | 0 | break; |
5611 | 0 | } |
5612 | 0 | #endif /* defined(COMPRESSION_LZMA) */ |
5613 | 0 | case RLECompression: |
5614 | 0 | { |
5615 | 0 | compress_tag=COMPRESSION_PACKBITS; |
5616 | 0 | break; |
5617 | 0 | } |
5618 | 1.75k | case ZipCompression: |
5619 | 1.75k | { |
5620 | 1.75k | compress_tag=COMPRESSION_ADOBE_DEFLATE; |
5621 | 1.75k | break; |
5622 | 0 | } |
5623 | 0 | #if defined(COMPRESSION_ZSTD) |
5624 | 1.32k | case ZSTDCompression: |
5625 | 1.32k | { |
5626 | 1.32k | compress_tag=COMPRESSION_ZSTD; |
5627 | 1.32k | break; |
5628 | 0 | } |
5629 | 0 | #endif /* defined(COMPRESSION_ZSTD) */ |
5630 | 0 | #if defined(COMPRESSION_WEBP) |
5631 | 2.30k | case WebPCompression: |
5632 | 2.30k | { |
5633 | 2.30k | compress_tag=COMPRESSION_WEBP; |
5634 | 2.30k | break; |
5635 | 0 | } |
5636 | 0 | #endif /* defined(COMPRESSION_WEBP) */ |
5637 | 12.0k | default: |
5638 | 12.0k | { |
5639 | 12.0k | compress_tag=COMPRESSION_NONE; |
5640 | 12.0k | break; |
5641 | 0 | } |
5642 | 28.4k | } |
5643 | | |
5644 | | /* |
5645 | | Ensure that image is in desired output space |
5646 | | */ |
5647 | 28.4k | if ((image_info->type != UndefinedType) && |
5648 | 1.50k | (image_info->type != OptimizeType)) |
5649 | 1.50k | (void) SetImageType(image,image_info->type); |
5650 | 26.9k | else if (!IsCMYKColorspace(image->colorspace) && |
5651 | 26.0k | (!IsRGBColorspace(image->colorspace))) |
5652 | 1.39k | (void) TransformColorspace(image,RGBColorspace); |
5653 | | |
5654 | | /* |
5655 | | Analyze image to be written. |
5656 | | */ |
5657 | 28.4k | if (!GetImageCharacteristics(image,&characteristics, |
5658 | 28.4k | (OptimizeType == image_info->type), |
5659 | 28.4k | &image->exception)) |
5660 | 0 | { |
5661 | 0 | status=MagickFail; |
5662 | 0 | break; |
5663 | 0 | } |
5664 | | |
5665 | 28.4k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5666 | 28.4k | "Image characteristics: cmyk=%c, gray=%c, mono=%c," |
5667 | 28.4k | " opaque=%c, palette=%c", |
5668 | 28.4k | (characteristics.cmyk ? 'y' : 'n'), |
5669 | 28.4k | (characteristics.grayscale ? 'y' : 'n'), |
5670 | 28.4k | (characteristics.monochrome ? 'y' : 'n'), |
5671 | 28.4k | (characteristics.opaque ? 'y' : 'n'), |
5672 | 28.4k | (characteristics.palette ? 'y' : 'n')); |
5673 | | |
5674 | | |
5675 | | /* |
5676 | | Some compression types do not work with a matte channel. |
5677 | | Disable matte channel for these types. |
5678 | | */ |
5679 | 28.4k | if (image->matte) |
5680 | 3.20k | { |
5681 | 3.20k | switch (compress_tag) |
5682 | 3.20k | { |
5683 | 1 | case COMPRESSION_CCITTFAX3: |
5684 | 15 | case COMPRESSION_CCITTFAX4: |
5685 | 15 | case COMPRESSION_JBIG: |
5686 | 131 | case COMPRESSION_JPEG: |
5687 | 131 | { |
5688 | 131 | if (logging) |
5689 | 0 | { |
5690 | 0 | const char * |
5691 | 0 | compress_type; |
5692 | |
|
5693 | 0 | compress_type=CompressionTagToString(compress_tag); |
5694 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5695 | 0 | "Disabled image matte channel since " |
5696 | 0 | "%s compression not supported with " |
5697 | 0 | "alpha channel.", |
5698 | 0 | compress_type); |
5699 | 0 | } |
5700 | 131 | image->matte=MagickFalse; |
5701 | 131 | break; |
5702 | 15 | } |
5703 | 3.07k | default: |
5704 | 3.07k | { |
5705 | 3.07k | } |
5706 | 3.20k | } |
5707 | 3.20k | } |
5708 | | |
5709 | | /* |
5710 | | Choose best photometric based on image properties. |
5711 | | */ |
5712 | 28.4k | if (characteristics.cmyk) |
5713 | 840 | { |
5714 | 840 | photometric=PHOTOMETRIC_SEPARATED; |
5715 | 840 | } |
5716 | 27.5k | else if (characteristics.monochrome) |
5717 | 4.97k | { |
5718 | 4.97k | photometric=PHOTOMETRIC_MINISWHITE; |
5719 | 4.97k | depth=1; |
5720 | 4.97k | } |
5721 | 22.6k | else if (characteristics.palette) |
5722 | 1.20k | { |
5723 | 1.20k | photometric=PHOTOMETRIC_PALETTE; |
5724 | 1.20k | } |
5725 | 21.4k | else if (characteristics.grayscale) |
5726 | 8.15k | { |
5727 | 8.15k | photometric=PHOTOMETRIC_MINISBLACK; |
5728 | 8.15k | } |
5729 | 13.2k | else |
5730 | 13.2k | { |
5731 | 13.2k | photometric=PHOTOMETRIC_RGB; |
5732 | 13.2k | } |
5733 | | |
5734 | | /* |
5735 | | If optimization is requested, disable matte channel if image |
5736 | | is opaque. |
5737 | | */ |
5738 | 28.4k | if ((OptimizeType == image_info->type) && |
5739 | 0 | (characteristics.opaque && image->matte)) |
5740 | 0 | { |
5741 | 0 | image->matte=MagickFalse; |
5742 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5743 | 0 | "Disabled image matte channel since image is " |
5744 | 0 | "opaque."); |
5745 | 0 | } |
5746 | | |
5747 | | /* |
5748 | | Currently we only support JPEG compression with MINISWHITE, |
5749 | | MINISBLACK, and RGB. FAX compression types require |
5750 | | MINISWHITE. CMYK takes precedence over JPEG compression. |
5751 | | */ |
5752 | 28.4k | if ((compress_tag == COMPRESSION_JPEG) && |
5753 | 5.35k | (photometric == PHOTOMETRIC_PALETTE)) |
5754 | 2 | { |
5755 | 2 | photometric=PHOTOMETRIC_RGB; |
5756 | 2 | if (logging) |
5757 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5758 | 0 | "Using RGB photometric due to request for" |
5759 | 0 | " JPEG compression."); |
5760 | 2 | } |
5761 | 28.4k | else if (compress_tag == COMPRESSION_CCITTFAX3) |
5762 | 1.24k | { |
5763 | 1.24k | photometric=PHOTOMETRIC_MINISWHITE; |
5764 | 1.24k | depth=1; |
5765 | 1.24k | if (logging) |
5766 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5767 | 0 | "Using MINISWHITE photometric due to request" |
5768 | 0 | " for Group3 FAX compression."); |
5769 | 1.24k | } |
5770 | 27.1k | else if (compress_tag == COMPRESSION_CCITTFAX4) |
5771 | 3.59k | { |
5772 | 3.59k | photometric=PHOTOMETRIC_MINISWHITE; |
5773 | 3.59k | depth=1; |
5774 | 3.59k | if (logging) |
5775 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5776 | 0 | "Using MINISWHITE photometric due to request" |
5777 | 0 | " for Group4 FAX compression."); |
5778 | 3.59k | } |
5779 | 23.5k | #if defined(COMPRESSION_JBIG) |
5780 | 23.5k | else if (compress_tag == COMPRESSION_JBIG) |
5781 | 0 | { |
5782 | 0 | photometric=PHOTOMETRIC_MINISWHITE; |
5783 | 0 | depth=1; |
5784 | 0 | if (logging) |
5785 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5786 | 0 | "Using MINISWHITE photometric due to request" |
5787 | 0 | " for JBIG compression."); |
5788 | 0 | } |
5789 | 23.5k | #endif /* defined(COMPRESSION_JBIG) */ |
5790 | 23.5k | #if defined(COMPRESSION_WEBP) |
5791 | 23.5k | else if (compress_tag == COMPRESSION_WEBP) |
5792 | 2.30k | { |
5793 | 2.30k | photometric=PHOTOMETRIC_RGB; |
5794 | 2.30k | if (logging) |
5795 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5796 | 0 | "Using RGB photometric due to request for" |
5797 | 0 | " WebP compression."); |
5798 | 2.30k | } |
5799 | 28.4k | #endif /* defined(COMPRESSION_WEBP) */ |
5800 | | |
5801 | | /* |
5802 | | Allow user to override the photometric. |
5803 | | */ |
5804 | 28.4k | switch (image_info->type) |
5805 | 28.4k | { |
5806 | 1.50k | case BilevelType: |
5807 | 1.50k | { |
5808 | 1.50k | photometric=PHOTOMETRIC_MINISWHITE; |
5809 | 1.50k | depth=1; |
5810 | 1.50k | break; |
5811 | 0 | } |
5812 | 0 | case GrayscaleType: |
5813 | 0 | { |
5814 | 0 | photometric=PHOTOMETRIC_MINISBLACK; |
5815 | 0 | break; |
5816 | 0 | } |
5817 | 0 | case GrayscaleMatteType: |
5818 | 0 | { |
5819 | 0 | photometric=PHOTOMETRIC_MINISBLACK; |
5820 | 0 | if (!image->matte) |
5821 | 0 | SetImageOpacity(image,OpaqueOpacity); |
5822 | 0 | break; |
5823 | 0 | } |
5824 | 0 | case PaletteType: |
5825 | 0 | { |
5826 | 0 | photometric=PHOTOMETRIC_PALETTE; |
5827 | 0 | break; |
5828 | 0 | } |
5829 | 0 | case PaletteMatteType: |
5830 | 0 | { |
5831 | 0 | photometric=PHOTOMETRIC_PALETTE; |
5832 | 0 | if (!image->matte) |
5833 | 0 | SetImageOpacity(image,OpaqueOpacity); |
5834 | 0 | break; |
5835 | 0 | } |
5836 | 0 | case TrueColorType: |
5837 | 0 | { |
5838 | 0 | photometric=PHOTOMETRIC_RGB; |
5839 | 0 | break; |
5840 | 0 | } |
5841 | 0 | case TrueColorMatteType: |
5842 | 0 | { |
5843 | 0 | photometric=PHOTOMETRIC_RGB; |
5844 | 0 | if (!image->matte) |
5845 | 0 | SetImageOpacity(image,OpaqueOpacity); |
5846 | 0 | break; |
5847 | 0 | } |
5848 | 0 | case ColorSeparationType: |
5849 | 0 | { |
5850 | 0 | photometric=PHOTOMETRIC_SEPARATED; |
5851 | 0 | break; |
5852 | 0 | } |
5853 | 0 | case ColorSeparationMatteType: |
5854 | 0 | { |
5855 | 0 | photometric=PHOTOMETRIC_SEPARATED; |
5856 | 0 | if (!image->matte) |
5857 | 0 | SetImageOpacity(image,OpaqueOpacity); |
5858 | 0 | break; |
5859 | 0 | } |
5860 | 26.9k | case UndefinedType: |
5861 | 26.9k | case OptimizeType: |
5862 | 26.9k | { |
5863 | | /* No special handling */ |
5864 | 26.9k | } |
5865 | 28.4k | } |
5866 | | |
5867 | | /* |
5868 | | Allow the user to over-ride the photometric for bilevel and |
5869 | | gray images since 'type' is insufficient for this. |
5870 | | */ |
5871 | 28.4k | if ((PHOTOMETRIC_MINISWHITE == photometric) || |
5872 | 21.8k | (PHOTOMETRIC_MINISBLACK == photometric)) |
5873 | 13.1k | { |
5874 | 13.1k | const char * |
5875 | 13.1k | value; |
5876 | | |
5877 | | /* |
5878 | | Photometric |
5879 | | */ |
5880 | 13.1k | value=AccessDefinition(image_info,"tiff","photometric"); |
5881 | 13.1k | if (value) |
5882 | 0 | { |
5883 | 0 | if (LocaleCompare(value,"miniswhite") == 0) |
5884 | 0 | photometric=PHOTOMETRIC_MINISWHITE; |
5885 | 0 | else if (LocaleCompare(value,"minisblack") == 0) |
5886 | 0 | photometric=PHOTOMETRIC_MINISBLACK; |
5887 | 0 | } |
5888 | 13.1k | } |
5889 | | |
5890 | | /* |
5891 | | If the user has selected something other than MINISWHITE, |
5892 | | MINISBLACK, or RGB, then remove JPEG compression. Also remove |
5893 | | fax compression if photometric is not compatible. |
5894 | | */ |
5895 | 28.4k | if ((compress_tag == COMPRESSION_JPEG) && |
5896 | 5.35k | ((photometric != PHOTOMETRIC_MINISWHITE) && |
5897 | 5.35k | (photometric != PHOTOMETRIC_MINISBLACK) && |
5898 | 889 | (photometric != PHOTOMETRIC_RGB) && |
5899 | 21 | (photometric != PHOTOMETRIC_YCBCR))) |
5900 | 21 | { |
5901 | 21 | compress_tag=COMPRESSION_NONE; |
5902 | 21 | if (logging) |
5903 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5904 | 0 | "Ignoring request for JPEG compression due " |
5905 | 0 | "to incompatible photometric."); |
5906 | 21 | } |
5907 | 28.4k | else if (((compress_tag == COMPRESSION_CCITTFAX3) || |
5908 | 27.1k | (compress_tag == COMPRESSION_CCITTFAX4)) && |
5909 | 4.83k | ((photometric != PHOTOMETRIC_MINISWHITE) && |
5910 | 0 | (photometric != PHOTOMETRIC_MINISBLACK))) |
5911 | 0 | { |
5912 | 0 | compress_tag=COMPRESSION_NONE; |
5913 | 0 | fill_order=FILLORDER_MSB2LSB; |
5914 | 0 | if (logging) |
5915 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5916 | 0 | "Ignoring request for FAX compression" |
5917 | 0 | " due to incompatible photometric."); |
5918 | 0 | } |
5919 | 28.4k | #if defined(COMPRESSION_JBIG) |
5920 | 28.4k | else if ((compress_tag == COMPRESSION_JBIG) && |
5921 | 0 | (photometric != PHOTOMETRIC_MINISWHITE)) |
5922 | 0 | { |
5923 | 0 | compress_tag=COMPRESSION_NONE; |
5924 | 0 | fill_order=FILLORDER_MSB2LSB; |
5925 | 0 | if (logging) |
5926 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5927 | 0 | "Ignoring request for JBIG compression" |
5928 | 0 | " due to incompatible photometric."); |
5929 | 0 | } |
5930 | 28.4k | #endif /* defined(COMPRESSION_JBIG) */ |
5931 | | |
5932 | | /* |
5933 | | Support writing bits per sample of 8, 16, & 32 by default. |
5934 | | */ |
5935 | 40.5k | for (bits_per_sample=8; bits_per_sample < depth; ) |
5936 | 12.1k | bits_per_sample*=2; |
5937 | | |
5938 | | /* |
5939 | | Now choose appropriate settings for the photometric. |
5940 | | */ |
5941 | 28.4k | switch (photometric) |
5942 | 28.4k | { |
5943 | 6.54k | case PHOTOMETRIC_MINISWHITE: |
5944 | 13.1k | case PHOTOMETRIC_MINISBLACK: |
5945 | 13.1k | { |
5946 | 13.1k | samples_per_pixel=1; |
5947 | 13.1k | if (depth == 1) |
5948 | 6.65k | bits_per_sample=1; |
5949 | 13.1k | break; |
5950 | 6.54k | } |
5951 | 13.2k | case PHOTOMETRIC_RGB: |
5952 | 13.2k | { |
5953 | 13.2k | samples_per_pixel=3; |
5954 | 13.2k | break; |
5955 | 6.54k | } |
5956 | 1.20k | case PHOTOMETRIC_PALETTE: |
5957 | 1.20k | { |
5958 | 1.20k | samples_per_pixel=1; |
5959 | 1.20k | bits_per_sample=1; |
5960 | | /* |
5961 | | Support colormap indexes of 1, 2, 4, 8, and 16 by default. |
5962 | | */ |
5963 | 3.20k | while ((1UL << bits_per_sample) < image->colors) |
5964 | 2.00k | bits_per_sample*=2; |
5965 | 1.20k | break; |
5966 | 6.54k | } |
5967 | 840 | case PHOTOMETRIC_SEPARATED: |
5968 | 840 | { |
5969 | 840 | samples_per_pixel=4; /* CMYK */ |
5970 | | |
5971 | 840 | (void) TIFFSetField(tiff,TIFFTAG_INKSET,INKSET_CMYK); |
5972 | 840 | if (logging) |
5973 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
5974 | 0 | "Using INKSET_CMYK"); |
5975 | 840 | break; |
5976 | 6.54k | } |
5977 | 0 | case PHOTOMETRIC_YCBCR: |
5978 | 0 | { |
5979 | | /* This is here to support JPEGCOLORMODE_RGB*/ |
5980 | 0 | samples_per_pixel=3; |
5981 | 0 | break; |
5982 | 6.54k | } |
5983 | 28.4k | } |
5984 | | |
5985 | 28.4k | if (COMPRESSION_JPEG == compress_tag) |
5986 | 5.33k | { |
5987 | | /* |
5988 | | JPEG compression can only use size specified by |
5989 | | BITS_IN_JSAMPLE (except for MK1 JPEG) which supports two |
5990 | | sizes. |
5991 | | |
5992 | | Maybe there is a tricky way to obtain this value from |
5993 | | libtiff or libtiff can be extended? |
5994 | | |
5995 | | FIXME |
5996 | | */ |
5997 | 5.33k | #if defined(BITS_IN_JSAMPLE) |
5998 | 5.33k | depth=BITS_IN_JSAMPLE; |
5999 | 5.33k | bits_per_sample=BITS_IN_JSAMPLE; |
6000 | | #else |
6001 | | depth=8; |
6002 | | bits_per_sample=8; |
6003 | | #endif |
6004 | 5.33k | } |
6005 | | |
6006 | 28.4k | #if defined(COMPRESSION_WEBP) |
6007 | 28.4k | if (COMPRESSION_WEBP == compress_tag) |
6008 | 2.30k | { |
6009 | | /* |
6010 | | WebP compression only supports a depth of 8. |
6011 | | */ |
6012 | 2.30k | depth=8; |
6013 | 2.30k | bits_per_sample=8; |
6014 | 2.30k | } |
6015 | 28.4k | #endif /* if defined(COMPRESSION_WEBP) */ |
6016 | | |
6017 | 28.4k | alpha_type=UnspecifiedAlpha; |
6018 | 28.4k | if (image->matte) |
6019 | 3.07k | { |
6020 | | /* |
6021 | | Image has a matte channel. Mark it correctly. |
6022 | | */ |
6023 | 3.07k | uint16 |
6024 | 3.07k | extra_samples, |
6025 | 3.07k | sample_info[1]; |
6026 | | |
6027 | 3.07k | const char * |
6028 | 3.07k | value; |
6029 | | |
6030 | 3.07k | alpha_type=UnassociatedAlpha; |
6031 | | |
6032 | 3.07k | if ((value=AccessDefinition(image_info,"tiff","alpha"))) |
6033 | 0 | { |
6034 | 0 | if (LocaleCompare(value,"unspecified") == 0) |
6035 | 0 | alpha_type=UnspecifiedAlpha; |
6036 | 0 | else if (LocaleCompare(value,"associated") == 0) |
6037 | 0 | alpha_type=AssociatedAlpha; |
6038 | 0 | else if (LocaleCompare(value,"unassociated") == 0) |
6039 | 0 | alpha_type=UnassociatedAlpha; |
6040 | 0 | } |
6041 | 3.07k | else if ((attribute=GetImageAttribute(image,"alpha"))) |
6042 | 2.97k | { |
6043 | 2.97k | if (LocaleCompare(attribute->value,"unspecified") == 0) |
6044 | 0 | alpha_type=UnspecifiedAlpha; |
6045 | 2.97k | else if (LocaleCompare(attribute->value,"associated") == 0) |
6046 | 1.03k | alpha_type=AssociatedAlpha; |
6047 | 1.94k | else if (LocaleCompare(attribute->value,"unassociated") == 0) |
6048 | 1.94k | alpha_type=UnassociatedAlpha; |
6049 | 2.97k | } |
6050 | | |
6051 | 3.07k | samples_per_pixel += 1; |
6052 | 3.07k | extra_samples=1; |
6053 | 3.07k | sample_info[0]=EXTRASAMPLE_ASSOCALPHA; |
6054 | 3.07k | switch (alpha_type) |
6055 | 3.07k | { |
6056 | 0 | case UnspecifiedAlpha: |
6057 | 0 | { |
6058 | 0 | sample_info[0]=EXTRASAMPLE_UNSPECIFIED; |
6059 | 0 | break; |
6060 | 0 | } |
6061 | 1.03k | case AssociatedAlpha: |
6062 | 1.03k | { |
6063 | 1.03k | sample_info[0]=EXTRASAMPLE_ASSOCALPHA; |
6064 | 1.03k | break; |
6065 | 0 | } |
6066 | 2.04k | case UnassociatedAlpha: |
6067 | 2.04k | { |
6068 | 2.04k | sample_info[0]=EXTRASAMPLE_UNASSALPHA; |
6069 | 2.04k | break; |
6070 | 0 | } |
6071 | 3.07k | } |
6072 | | |
6073 | 3.07k | (void) TIFFSetField(tiff,TIFFTAG_EXTRASAMPLES,extra_samples, |
6074 | 3.07k | &sample_info); |
6075 | 3.07k | } |
6076 | | |
6077 | | /* |
6078 | | Allow the advanced user to over-ride some TIFF write options |
6079 | | */ |
6080 | 28.4k | { |
6081 | 28.4k | const char * |
6082 | 28.4k | value; |
6083 | | |
6084 | 28.4k | unsigned int |
6085 | 28.4k | old_value; |
6086 | | |
6087 | | /* |
6088 | | Fill order |
6089 | | */ |
6090 | 28.4k | value=AccessDefinition(image_info,"tiff","fill-order"); |
6091 | 28.4k | if (value) |
6092 | 1.50k | { |
6093 | 1.50k | if (LocaleNCompare(value,"msb2lsb",3) == 0) |
6094 | 1.50k | fill_order=FILLORDER_MSB2LSB; |
6095 | 0 | else if (LocaleNCompare(value,"lsb2msb",3) == 0) |
6096 | 0 | fill_order=FILLORDER_LSB2MSB; |
6097 | 1.50k | } |
6098 | | |
6099 | | /* |
6100 | | Sample format |
6101 | | */ |
6102 | 28.4k | value=AccessDefinition(image_info,"tiff","sample-format"); |
6103 | 28.4k | if (value) |
6104 | 0 | { |
6105 | 0 | if (LocaleCompare(value,"unsigned") == 0) |
6106 | 0 | sample_format=SAMPLEFORMAT_UINT; |
6107 | 0 | else if (LocaleCompare(value,"ieeefp") == 0) |
6108 | 0 | sample_format=SAMPLEFORMAT_IEEEFP; |
6109 | 0 | } |
6110 | | |
6111 | | /* |
6112 | | Bits per sample (needs to be after sample format) |
6113 | | */ |
6114 | 28.4k | value=AccessDefinition(image_info,"tiff","bits-per-sample"); |
6115 | 28.4k | if (value) |
6116 | 0 | { |
6117 | 0 | old_value=bits_per_sample; |
6118 | 0 | bits_per_sample=MagickAtoI(value); |
6119 | 0 | if (sample_format == SAMPLEFORMAT_IEEEFP) |
6120 | 0 | { |
6121 | | /* |
6122 | | If floating point is selected, ensure that valid |
6123 | | bits-per-sample values are specified. |
6124 | | */ |
6125 | 0 | if ((bits_per_sample != 16) && |
6126 | 0 | (bits_per_sample != 24) && |
6127 | 0 | (bits_per_sample != 32) && |
6128 | 0 | (bits_per_sample != 64)) |
6129 | 0 | bits_per_sample=32; |
6130 | 0 | } |
6131 | 0 | else |
6132 | 0 | { |
6133 | | /* Clamp maximum unsigned bits per sample to 32 bits */ |
6134 | 0 | if ((bits_per_sample < 1) || |
6135 | 0 | ((bits_per_sample > 32) && (bits_per_sample != 64))) |
6136 | 0 | bits_per_sample=old_value; |
6137 | 0 | } |
6138 | 0 | if ((logging) && (old_value != bits_per_sample)) |
6139 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6140 | 0 | "User override (bits-per-sample): %u bits " |
6141 | 0 | "per sample (was %u)", |
6142 | 0 | (unsigned int) bits_per_sample, old_value); |
6143 | 0 | } |
6144 | | |
6145 | | /* |
6146 | | Samples per pixel |
6147 | | */ |
6148 | 28.4k | value=AccessDefinition(image_info,"tiff","samples-per-pixel"); |
6149 | 28.4k | if (value) |
6150 | 0 | { |
6151 | 0 | old_value=samples_per_pixel; |
6152 | 0 | samples_per_pixel=MagickAtoI(value); |
6153 | 0 | if (logging) |
6154 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6155 | 0 | "User override (samples-per-pixel): %u " |
6156 | 0 | "samples per pixel (was %u)", |
6157 | 0 | (unsigned int) samples_per_pixel, old_value); |
6158 | 0 | } |
6159 | 28.4k | } |
6160 | | |
6161 | | /* |
6162 | | Determine planar configuration. |
6163 | | */ |
6164 | 28.4k | planar_config=PLANARCONFIG_CONTIG; |
6165 | 28.4k | if (samples_per_pixel > 1) |
6166 | 15.0k | { |
6167 | 15.0k | switch (image->interlace) |
6168 | 15.0k | { |
6169 | 13.6k | case UndefinedInterlace: |
6170 | 13.6k | break; |
6171 | 4 | case NoInterlace: |
6172 | 12 | case LineInterlace: |
6173 | 12 | case PartitionInterlace: |
6174 | 12 | planar_config=PLANARCONFIG_CONTIG; |
6175 | 12 | break; |
6176 | 1.38k | case PlaneInterlace: |
6177 | 1.38k | planar_config=PLANARCONFIG_SEPARATE; |
6178 | 1.38k | break; |
6179 | 15.0k | } |
6180 | | |
6181 | 15.0k | switch (image_info->interlace) |
6182 | 15.0k | { |
6183 | 15.0k | case UndefinedInterlace: |
6184 | 15.0k | break; |
6185 | 0 | case NoInterlace: |
6186 | 0 | case LineInterlace: |
6187 | 0 | case PartitionInterlace: |
6188 | 0 | planar_config=PLANARCONFIG_CONTIG; |
6189 | 0 | break; |
6190 | 0 | case PlaneInterlace: |
6191 | 0 | planar_config=PLANARCONFIG_SEPARATE; |
6192 | 0 | break; |
6193 | 15.0k | } |
6194 | 15.0k | } |
6195 | | |
6196 | | /* |
6197 | | YCbCr encoding compresses much better than RGB. Use YCbCr |
6198 | | encoding for JPEG (normal for JPEG files). |
6199 | | |
6200 | | FIXME: Need to find a way to select between RGB or YCbCr |
6201 | | encoding with JPEG compression. Testing shows that YCbCr is |
6202 | | over 2.5X smaller than RGB but the PSNR is a bit lower, |
6203 | | particularly in red and blue channels. Someone might want to |
6204 | | use RGB to minimize color loss. |
6205 | | */ |
6206 | 28.4k | if ((compress_tag == COMPRESSION_JPEG) && |
6207 | 5.33k | (planar_config == PLANARCONFIG_CONTIG) && |
6208 | 5.22k | (photometric == PHOTOMETRIC_RGB)) |
6209 | 755 | photometric=PHOTOMETRIC_YCBCR; |
6210 | | |
6211 | 28.4k | if (logging) |
6212 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6213 | 0 | "Using %s photometric, %u samples per pixel, " |
6214 | 0 | "%u bits per sample, format %s", |
6215 | 0 | PhotometricTagToString(photometric), |
6216 | 0 | (unsigned int) samples_per_pixel, |
6217 | 0 | (unsigned int) bits_per_sample, |
6218 | 0 | sample_format == SAMPLEFORMAT_UINT ? "Unsigned" : |
6219 | 0 | sample_format == SAMPLEFORMAT_IEEEFP ? "IEEEFP" : |
6220 | 0 | "unknown"); |
6221 | | |
6222 | | /* |
6223 | | Only set fill order if the setting is not the default. |
6224 | | */ |
6225 | 28.4k | if (FILLORDER_MSB2LSB != fill_order) |
6226 | 3.33k | (void) TIFFSetField(tiff,TIFFTAG_FILLORDER,fill_order); |
6227 | 28.4k | if (logging) |
6228 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6229 | 0 | "Using %s bit fill order", |
6230 | 0 | (fill_order == FILLORDER_MSB2LSB ? "MSB2LSB" : |
6231 | 0 | (fill_order == FILLORDER_LSB2MSB ? "LSB2MSB" : |
6232 | 0 | "undefined"))); |
6233 | 28.4k | if (image->orientation != UndefinedOrientation) |
6234 | 3.51k | (void) TIFFSetField(tiff,TIFFTAG_ORIENTATION,(uint16) image->orientation); |
6235 | 28.4k | (void) TIFFSetField(tiff,TIFFTAG_PHOTOMETRIC,photometric); |
6236 | 28.4k | (void) TIFFSetField(tiff,TIFFTAG_BITSPERSAMPLE,bits_per_sample); |
6237 | 28.4k | (void) TIFFSetField(tiff,TIFFTAG_SAMPLESPERPIXEL,samples_per_pixel); |
6238 | 28.4k | (void) TIFFSetField(tiff,TIFFTAG_SAMPLEFORMAT,sample_format); |
6239 | 28.4k | (void) TIFFSetField(tiff,TIFFTAG_PLANARCONFIG,planar_config); |
6240 | 28.4k | if (logging) |
6241 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6242 | 0 | "%s image planes", |
6243 | 0 | (planar_config == PLANARCONFIG_SEPARATE ? |
6244 | 0 | "Separate" : "Contiguous")); |
6245 | 28.4k | (void) TIFFSetField(tiff,TIFFTAG_COMPRESSION,compress_tag); |
6246 | | |
6247 | | /* |
6248 | | Determine rows per strip given current image width, bits per |
6249 | | sample, samples per pixel, tags, and compression specific |
6250 | | requirements. Tries to create strips with |
6251 | | TARGET_BYTES_PER_STRIP of uncompressed data. |
6252 | | */ |
6253 | 28.4k | switch (compress_tag) |
6254 | 28.4k | { |
6255 | 5.33k | case COMPRESSION_JPEG: |
6256 | 5.33k | { |
6257 | | /* |
6258 | | Set JPEG RGB mode since we don't have a suitable YCbCR encoder. |
6259 | | */ |
6260 | 5.33k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6261 | 5.33k | "JPEG Quality: %u", (unsigned) image_info->quality); |
6262 | 5.33k | (void) TIFFSetField(tiff,TIFFTAG_JPEGQUALITY,image_info->quality); |
6263 | 5.33k | if (IsRGBColorspace(image->colorspace)) |
6264 | 5.33k | { |
6265 | 5.33k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6266 | 5.33k | "TIFFTAG_JPEGCOLORMODE: JPEGCOLORMODE_RGB"); |
6267 | 5.33k | (void) TIFFSetField(tiff,TIFFTAG_JPEGCOLORMODE,JPEGCOLORMODE_RGB); |
6268 | 5.33k | } |
6269 | 5.33k | if (bits_per_sample == 12) |
6270 | 0 | { |
6271 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6272 | 0 | "TIFFTAG_JPEGTABLESMODE: JPEGTABLESMODE_QUANT"); |
6273 | 0 | (void) TIFFSetField(tiff,TIFFTAG_JPEGTABLESMODE,JPEGTABLESMODE_QUANT); |
6274 | 0 | } |
6275 | 5.33k | break; |
6276 | 0 | } |
6277 | 1.75k | case COMPRESSION_ADOBE_DEFLATE: |
6278 | 1.75k | { |
6279 | | /* |
6280 | | Use horizontal differencing (type 2) for images which are |
6281 | | likely to be continuous tone. The TIFF spec says that this |
6282 | | usually leads to better compression. |
6283 | | */ |
6284 | 1.75k | if (((photometric == PHOTOMETRIC_RGB) || |
6285 | 549 | (photometric == PHOTOMETRIC_MINISBLACK)) && |
6286 | 1.49k | ((bits_per_sample == 8) || (bits_per_sample == 16))) |
6287 | 1.46k | predictor=PREDICTOR_HORIZONTAL; |
6288 | 1.75k | { |
6289 | | /* |
6290 | | Zip quality has a useful range of 1-9. |
6291 | | */ |
6292 | 1.75k | unsigned int zip_quality=image_info->quality / 10; |
6293 | 1.75k | if (zip_quality < 1) |
6294 | 0 | zip_quality=1; |
6295 | 1.75k | if (zip_quality > 9) |
6296 | 0 | zip_quality=9; |
6297 | | |
6298 | 1.75k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6299 | 1.75k | "TIFFTAG_ZIPQUALITY: %u", zip_quality); |
6300 | 1.75k | (void) TIFFSetField(tiff,TIFFTAG_ZIPQUALITY,zip_quality); |
6301 | 1.75k | } |
6302 | 1.75k | break; |
6303 | 0 | } |
6304 | 1.24k | case COMPRESSION_CCITTFAX3: |
6305 | 1.24k | { |
6306 | | /* |
6307 | | Set Group 3 Options. Group 3 options are arranged as 32 flag bits. |
6308 | | Specify byte-aligned EOL padding option. |
6309 | | |
6310 | | Group3Options = 4,5. LONG. Data may be one- or |
6311 | | two-dimensional, but EOLs must be |
6312 | | byte-aligned. Uncompressed data is not allowed. |
6313 | | |
6314 | | bit 0 = 0 for 1-Dimensional, 1 for 2-Dimensional |
6315 | | |
6316 | | bit 1 = must be 0 (uncompressed data not allowed) |
6317 | | |
6318 | | bit 2 = 1 for byte-aligned EOLs |
6319 | | |
6320 | | */ |
6321 | 1.24k | uint32 |
6322 | 1.24k | group_three_options = 4; |
6323 | | |
6324 | 1.24k | const char * |
6325 | 1.24k | value; |
6326 | | |
6327 | 1.24k | if ((value=AccessDefinition(image_info,"tiff","group-three-options"))) |
6328 | 0 | { |
6329 | 0 | group_three_options=(uint32) strtol(value,(char **)NULL, 10); |
6330 | 0 | } |
6331 | 1.24k | (void) TIFFSetField(tiff,TIFFTAG_GROUP3OPTIONS,group_three_options); |
6332 | 1.24k | break; |
6333 | 0 | } |
6334 | 3.59k | case COMPRESSION_CCITTFAX4: |
6335 | 3.59k | { |
6336 | 3.59k | break; |
6337 | 0 | } |
6338 | 0 | #if defined(COMPRESSION_LZMA) |
6339 | 0 | case COMPRESSION_LZMA: |
6340 | 0 | { |
6341 | 0 | unsigned int |
6342 | 0 | lzma_preset; |
6343 | |
|
6344 | 0 | const char * |
6345 | 0 | lzma_preset_str; |
6346 | | |
6347 | | /* |
6348 | | Lzma preset has a useful range of 1-9. |
6349 | | |
6350 | | We default to 1 since testing does not show much benefit |
6351 | | from use of larger values. However, we allow the |
6352 | | power-user who wants to experiment to change the preset |
6353 | | value via syntax like '-define tiff:lzmapreset=7'. This |
6354 | | ability is intentionally not documented other than here. |
6355 | | */ |
6356 | |
|
6357 | 0 | lzma_preset=1; |
6358 | 0 | if ((lzma_preset_str=AccessDefinition(image_info,"tiff","lzmapreset"))) |
6359 | 0 | lzma_preset=(unsigned short) MagickAtoI(lzma_preset_str); |
6360 | |
|
6361 | 0 | if (lzma_preset < 1) |
6362 | 0 | lzma_preset=1; |
6363 | 0 | if (lzma_preset > 9) |
6364 | 0 | lzma_preset=9; |
6365 | 0 | (void) TIFFSetField(tiff,TIFFTAG_LZMAPRESET,lzma_preset); |
6366 | 0 | if (logging) |
6367 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6368 | 0 | "LZMA PRESET set to %u", lzma_preset); |
6369 | | |
6370 | | /* |
6371 | | Use horizontal differencing (type 2) for images which are |
6372 | | likely to be continuous tone. The TIFF spec says that this |
6373 | | usually leads to better compression. |
6374 | | */ |
6375 | 0 | if (((photometric == PHOTOMETRIC_RGB) || |
6376 | 0 | (photometric == PHOTOMETRIC_MINISBLACK)) && |
6377 | 0 | ((bits_per_sample == 8) || (bits_per_sample == 16))) |
6378 | 0 | predictor=PREDICTOR_HORIZONTAL; |
6379 | 0 | break; |
6380 | 0 | } |
6381 | 0 | #endif /* COMPRESSION_LZMA */ |
6382 | 0 | #if defined(COMPRESSION_JBIG) |
6383 | 0 | case COMPRESSION_JBIG: |
6384 | 0 | { |
6385 | 0 | break; |
6386 | 0 | } |
6387 | 0 | #endif /* COMPRESSION_JBIG */ |
6388 | 810 | case COMPRESSION_LZW: |
6389 | 810 | { |
6390 | | /* |
6391 | | Use horizontal differencing (type 2) for images which are |
6392 | | likely to be continuous tone. The TIFF spec says that this |
6393 | | usually leads to better compression. |
6394 | | */ |
6395 | 810 | if (((photometric == PHOTOMETRIC_RGB) || |
6396 | 530 | (photometric == PHOTOMETRIC_MINISBLACK)) && |
6397 | 601 | ((bits_per_sample == 8) || (bits_per_sample == 16))) |
6398 | 597 | predictor=PREDICTOR_HORIZONTAL; |
6399 | 810 | break; |
6400 | 0 | } |
6401 | 0 | #if defined(COMPRESSION_ZSTD) |
6402 | 1.32k | case COMPRESSION_ZSTD: |
6403 | 1.32k | { |
6404 | | /* |
6405 | | Use horizontal differencing (type 2) for images which are |
6406 | | likely to be continuous tone. The TIFF spec says that this |
6407 | | usually leads to better compression. |
6408 | | */ |
6409 | 1.32k | if (((photometric == PHOTOMETRIC_RGB) || |
6410 | 570 | (photometric == PHOTOMETRIC_MINISBLACK)) && |
6411 | 993 | ((bits_per_sample == 8) || (bits_per_sample == 16))) |
6412 | 991 | predictor=PREDICTOR_HORIZONTAL; |
6413 | 1.32k | { |
6414 | | /* |
6415 | | Zstd level has a useful range of 1-19 (or even 22). |
6416 | | |
6417 | | Libtiff uses a default level of 9. |
6418 | | |
6419 | | Default for ImageInfo 'quality' is 75, which is translated to 9. |
6420 | | |
6421 | | Use -define tiff:zstd-compress-level=<value> to specify a value. |
6422 | | */ |
6423 | 1.32k | const char *value; |
6424 | 1.32k | int compress_level = (image_info->quality*9)/75; |
6425 | 1.32k | #if defined(HasZSTD) |
6426 | 1.32k | int max_compression = ZSTD_maxCLevel(); |
6427 | | #else |
6428 | | int max_compression = 19; |
6429 | | #endif |
6430 | 1.32k | if ((value=AccessDefinition(image_info,"tiff","zstd-compress-level"))) |
6431 | 0 | compress_level=MagickAtoI(value); |
6432 | 1.32k | if (compress_level < 1) |
6433 | 0 | compress_level=1; |
6434 | 1.32k | if (compress_level > max_compression) |
6435 | 0 | compress_level=max_compression; |
6436 | 1.32k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6437 | 1.32k | "TIFFTAG_ZSTD_LEVEL: %u", compress_level); |
6438 | 1.32k | (void) TIFFSetField(tiff,TIFFTAG_ZSTD_LEVEL,compress_level); |
6439 | 1.32k | } |
6440 | 1.32k | break; |
6441 | 0 | } |
6442 | 0 | #endif /* defined(COMPRESSION_ZSTD) */ |
6443 | 0 | #if defined(COMPRESSION_WEBP) |
6444 | 2.30k | case COMPRESSION_WEBP: |
6445 | 2.30k | { |
6446 | | /* TIFFTAG_WEBP_LEVEL */ |
6447 | 2.30k | if (image_info->quality != DefaultCompressionQuality) |
6448 | 0 | { |
6449 | 0 | int quality = (int) image_info->quality; |
6450 | 0 | if (quality < 1) |
6451 | 0 | quality=1; |
6452 | 0 | else if (quality > 100) |
6453 | 0 | quality=100; |
6454 | |
|
6455 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6456 | 0 | "TIFFTAG_WEBP_LEVEL: %d", quality); |
6457 | 0 | (void) TIFFSetField(tiff,TIFFTAG_WEBP_LEVEL,quality); |
6458 | 0 | } |
6459 | | |
6460 | | /* TIFFTAG_WEBP_LOSSLESS */ |
6461 | 2.30k | { |
6462 | 2.30k | const char *value; |
6463 | 2.30k | if (((value=AccessDefinition(image_info,"tiff","webp-lossless")) != NULL) || |
6464 | 2.30k | ((value=AccessDefinition(image_info,"webp","lossless")) != NULL)) |
6465 | 0 | { |
6466 | 0 | int lossless=(LocaleCompare(value,"TRUE") == 0 ? 1 : 0); |
6467 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6468 | 0 | "TIFFTAG_WEBP_LOSSLESS: %d", lossless); |
6469 | 0 | (void) TIFFSetField(tiff,TIFFTAG_WEBP_LOSSLESS,lossless); |
6470 | 0 | } |
6471 | 2.30k | } |
6472 | 2.30k | break; |
6473 | 0 | } |
6474 | 0 | #endif /* defined(COMPRESSION_WEBP) */ |
6475 | 12.0k | default: |
6476 | 12.0k | { |
6477 | 12.0k | break; |
6478 | 0 | } |
6479 | 28.4k | } |
6480 | | |
6481 | 28.4k | scanline_size=TIFFScanlineSize(tiff); |
6482 | | /* (void) LogMagickEvent(CoderEvent,GetMagickModule(),"TIFFScanlineSize(): %lu", (unsigned long) scanline_size); */ |
6483 | 28.4k | rows_per_strip=TIFFDefaultStripSize(tiff,0); |
6484 | | /* (void) LogMagickEvent(CoderEvent,GetMagickModule(),"TIFFDefaultStripSize(): %lu", (unsigned long) rows_per_strip); */ |
6485 | | |
6486 | 28.4k | switch (compress_tag) |
6487 | 28.4k | { |
6488 | 1.24k | case COMPRESSION_CCITTFAX3: |
6489 | 4.83k | case COMPRESSION_CCITTFAX4: |
6490 | 4.83k | #if defined(COMPRESSION_JBIG) |
6491 | 4.83k | case COMPRESSION_JBIG: |
6492 | 4.83k | #endif /* COMPRESSION_JBIG */ |
6493 | 4.83k | { |
6494 | | /* |
6495 | | It is recommended (but not required) to output FAX/JBIG |
6496 | | as one strip. We will limit strip size to 32 megapixels |
6497 | | (4MiB) by default. |
6498 | | */ |
6499 | 4.83k | bytes_per_strip_target = 4*TIFF_BYTES_PER_STRIP; |
6500 | 4.83k | break; |
6501 | 4.83k | } |
6502 | 0 | #if defined(COMPRESSION_LZMA) |
6503 | 0 | case COMPRESSION_LZMA: |
6504 | 0 | { |
6505 | 0 | uint32 |
6506 | 0 | lzma_preset = 0; |
6507 | | |
6508 | | /* |
6509 | | Strip memory target for various compression preset levels. |
6510 | | Values are arbitrary. LZMA is a memory and CPU pig. |
6511 | | */ |
6512 | 0 | static const unsigned int |
6513 | 0 | lzma_memory_mb[] = |
6514 | 0 | { /* Level Compress Decompress */ |
6515 | 0 | 1U, /* 1 2 MB 1 MB */ |
6516 | 0 | 4U, /* 2 12 MB 2 MB */ |
6517 | 0 | 4U, /* 3 12 MB 1 MB */ |
6518 | 0 | 4U, /* 4 16 MB 2 MB */ |
6519 | 0 | 6U, /* 5 26 MB 3 MB */ |
6520 | 0 | 10U, /* 6 45 MB 5 MB */ |
6521 | 0 | 18U, /* 7 83 MB 9 MB */ |
6522 | 0 | 34U, /* 8 159 MB 17 MB */ |
6523 | 0 | 66U /* 9 311 MB 33 MB */ |
6524 | 0 | }; |
6525 | |
|
6526 | 0 | (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_LZMAPRESET,&lzma_preset); |
6527 | 0 | bytes_per_strip_target = (size_t) lzma_memory_mb[lzma_preset-1]*1024*1024; |
6528 | 0 | break; |
6529 | 4.83k | } |
6530 | 0 | #endif /* COMPRESSION_LZMA */ |
6531 | 23.5k | default: |
6532 | 23.5k | { |
6533 | 23.5k | } |
6534 | 28.4k | } |
6535 | | |
6536 | 28.4k | if (rows_per_strip==0 || scanline_size==0) |
6537 | 0 | rows_per_strip=1; |
6538 | 28.4k | else |
6539 | 28.4k | { |
6540 | 28.4k | if (scanline_size < (tsize_t) bytes_per_strip_target) |
6541 | 28.4k | rows_per_strip *= (uint32) ((size_t) bytes_per_strip_target / ((size_t) rows_per_strip*scanline_size)); |
6542 | 28.4k | if (rows_per_strip > image->rows) |
6543 | 28.3k | rows_per_strip=image->rows; |
6544 | 28.4k | if (rows_per_strip < 1) |
6545 | 0 | rows_per_strip=1; |
6546 | 28.4k | } |
6547 | | |
6548 | | /* |
6549 | | It seems that some programs fail to handle more than 32K or |
6550 | | 64K strips in an image due to using a 16-bit strip counter. |
6551 | | The solution is to use a larger strip size. This approach |
6552 | | might cause excessively large strips for mega-sized images and |
6553 | | someday we may remove the solution since the problematic |
6554 | | readers will have expired. |
6555 | | */ |
6556 | 28.4k | if ((image->rows/rows_per_strip) > 32767) |
6557 | 0 | rows_per_strip=image->rows/32768; |
6558 | 28.4k | if (rows_per_strip < 1) |
6559 | 0 | rows_per_strip=1; |
6560 | | |
6561 | | /* |
6562 | | Allow the user to specify the predictor (at their own peril) |
6563 | | */ |
6564 | 28.4k | { |
6565 | 28.4k | const char * |
6566 | 28.4k | value; |
6567 | | |
6568 | 28.4k | if ((value=AccessDefinition(image_info,"tiff","predictor"))) |
6569 | 0 | predictor=(unsigned short) MagickAtoI(value); |
6570 | 28.4k | } |
6571 | | |
6572 | 28.4k | if (predictor != 0) |
6573 | 3.05k | { |
6574 | 3.05k | if (logging) |
6575 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6576 | 0 | "Requesting predictor %u", |
6577 | 0 | (unsigned int) predictor); |
6578 | 3.05k | (void) TIFFSetField(tiff,TIFFTAG_PREDICTOR,predictor); |
6579 | 3.05k | } |
6580 | | |
6581 | | /* |
6582 | | Allow the user to override rows-per-strip settings. |
6583 | | */ |
6584 | 28.4k | if (method != TiledMethod) |
6585 | 28.4k | { |
6586 | 28.4k | const char * |
6587 | 28.4k | value; |
6588 | | |
6589 | 28.4k | if ((value=AccessDefinition(image_info,"tiff","rows-per-strip"))) |
6590 | 0 | { |
6591 | 0 | unsigned int |
6592 | 0 | old_value; |
6593 | |
|
6594 | 0 | old_value=rows_per_strip; |
6595 | 0 | rows_per_strip=MagickAtoI(value); |
6596 | 0 | if (logging) |
6597 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6598 | 0 | "User override (rows_per_strip): %u rows" |
6599 | 0 | " per strip (was %u)", |
6600 | 0 | (unsigned int) rows_per_strip, old_value); |
6601 | 0 | } |
6602 | 28.4k | if ((value=AccessDefinition(image_info,"tiff","strip-per-page"))) |
6603 | 1.50k | { |
6604 | 1.50k | if (LocaleCompare("TRUE",value) == 0) |
6605 | 1.50k | { |
6606 | 1.50k | rows_per_strip=(uint32) image->rows; |
6607 | | |
6608 | 1.50k | if (logging) |
6609 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6610 | 0 | "User requested a single strip per " |
6611 | 0 | "page (strip-per-page)"); |
6612 | 1.50k | } |
6613 | 1.50k | } |
6614 | 28.4k | } |
6615 | | |
6616 | 28.4k | if (COMPRESSION_JPEG == compress_tag) |
6617 | 5.33k | { |
6618 | | /* |
6619 | | RowsPerStrip must be multiple of 16 for JPEG. |
6620 | | */ |
6621 | 5.33k | rows_per_strip=(((rows_per_strip < 16 ? 16 : rows_per_strip)+1)/16)*16; |
6622 | 5.33k | } |
6623 | | |
6624 | 28.4k | if (logging) |
6625 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6626 | 0 | "Using %s compression", |
6627 | 0 | CompressionTagToString(compress_tag)); |
6628 | 28.4k | if (logging) |
6629 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6630 | 0 | "Image depth %lu bits",depth); |
6631 | 28.4k | if (method != TiledMethod) |
6632 | 28.4k | { |
6633 | 28.4k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6634 | 28.4k | "Rows per strip: %u (%lu bytes/strip)", |
6635 | 28.4k | (unsigned int) rows_per_strip, |
6636 | 28.4k | (unsigned long) scanline_size*rows_per_strip); |
6637 | 28.4k | (void) TIFFSetField(tiff,TIFFTAG_ROWSPERSTRIP,rows_per_strip); |
6638 | 28.4k | } |
6639 | | |
6640 | | |
6641 | 28.4k | if ((image->x_resolution != 0) && (image->y_resolution != 0)) |
6642 | 2.83k | { |
6643 | 2.83k | unsigned short |
6644 | 2.83k | units; |
6645 | | |
6646 | | /* |
6647 | | Set image resolution. |
6648 | | */ |
6649 | 2.83k | units=RESUNIT_NONE; |
6650 | 2.83k | if (image->units == PixelsPerInchResolution) |
6651 | 2.42k | units=RESUNIT_INCH; |
6652 | 2.83k | if (image->units == PixelsPerCentimeterResolution) |
6653 | 208 | units=RESUNIT_CENTIMETER; |
6654 | 2.83k | if (logging) |
6655 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6656 | 0 | "Resolution %gx%g pixels%s", |
6657 | 0 | image->x_resolution, image->y_resolution, |
6658 | 0 | (units == RESUNIT_NONE ? " (undefined units)" : |
6659 | 0 | (units == RESUNIT_INCH ? " per inch" : |
6660 | 0 | (units == RESUNIT_CENTIMETER ? " per centimeter" |
6661 | 0 | : "BAD VALUE")))); |
6662 | 2.83k | (void) TIFFSetField(tiff,TIFFTAG_RESOLUTIONUNIT,(uint16) units); |
6663 | 2.83k | (void) TIFFSetField(tiff,TIFFTAG_XRESOLUTION,image->x_resolution); |
6664 | 2.83k | (void) TIFFSetField(tiff,TIFFTAG_YRESOLUTION,image->y_resolution); |
6665 | 2.83k | } |
6666 | | |
6667 | 28.4k | #if EXPERIMENTAL_EXIF_TAGS |
6668 | 28.4k | #if TIFFLIB_VERSION >= 20120922 |
6669 | 28.4k | if (status!=MagickFail) |
6670 | 28.4k | { |
6671 | 28.4k | const unsigned char *profile_data; |
6672 | 28.4k | size_t profile_length; |
6673 | 28.4k | if ((profile_data=GetImageProfile(image,"Exif",&profile_length)) != 0) |
6674 | 84 | { |
6675 | 84 | AddExifFields(tiff,profile_data,profile_length,logging, FLAG_BASE); |
6676 | 84 | } |
6677 | 28.4k | } |
6678 | 28.4k | #endif /* TIFFLIB_VERSION >= 20120922 */ |
6679 | 28.4k | #endif /* defined(EXPERIMENTAL_EXIF_TAGS) */ |
6680 | | |
6681 | 28.4k | if (image->chromaticity.white_point.x != 0.0) |
6682 | 299 | { |
6683 | 299 | float |
6684 | 299 | chromaticity[6]; |
6685 | | |
6686 | | /* |
6687 | | Set image primary chromaticities (x,y coordinates of RGB |
6688 | | colorants and white point). |
6689 | | */ |
6690 | 299 | chromaticity[0]=(float) image->chromaticity.red_primary.x; |
6691 | 299 | chromaticity[1]=(float) image->chromaticity.red_primary.y; |
6692 | 299 | chromaticity[2]=(float) image->chromaticity.green_primary.x; |
6693 | 299 | chromaticity[3]=(float) image->chromaticity.green_primary.y; |
6694 | 299 | chromaticity[4]=(float) image->chromaticity.blue_primary.x; |
6695 | 299 | chromaticity[5]=(float) image->chromaticity.blue_primary.y; |
6696 | 299 | if (logging) |
6697 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6698 | 0 | "Primary Chromaticities: " |
6699 | 0 | "r=%gx%g g=%gx%g b=%gx%g", |
6700 | 0 | chromaticity[0] /* red_primary.x */, |
6701 | 0 | chromaticity[1] /* red_primary.y */, |
6702 | 0 | chromaticity[2] /* green_primary.x */, |
6703 | 0 | chromaticity[3] /* green_primary.y */, |
6704 | 0 | chromaticity[4] /* blue_primary.x */, |
6705 | 0 | chromaticity[5] /* blue_primary.y */); |
6706 | 299 | (void) TIFFSetField(tiff,TIFFTAG_PRIMARYCHROMATICITIES,chromaticity); |
6707 | 299 | chromaticity[0]=(float) image->chromaticity.white_point.x; |
6708 | 299 | chromaticity[1]=(float) image->chromaticity.white_point.y; |
6709 | 299 | if (logging) |
6710 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6711 | 0 | "White Point: %gx%g", |
6712 | 0 | chromaticity[0] /* white_point.x */, |
6713 | 0 | chromaticity[1] /* white_point.y */); |
6714 | 299 | (void) TIFFSetField(tiff,TIFFTAG_WHITEPOINT,chromaticity); |
6715 | 299 | } |
6716 | 28.4k | { |
6717 | | /* |
6718 | | Copy any embedded profiles to TIFF. |
6719 | | */ |
6720 | 28.4k | size_t |
6721 | 28.4k | profile_length=0; |
6722 | | |
6723 | 28.4k | const unsigned char |
6724 | 28.4k | *profile_data=0; |
6725 | | |
6726 | 28.4k | #if defined(TIFFTAG_XMLPACKET) |
6727 | | /* |
6728 | | XML XMP profile. |
6729 | | */ |
6730 | 28.4k | if ((profile_data=GetImageProfile(image,"XMP",&profile_length)) != 0) |
6731 | 13 | { |
6732 | 13 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6733 | 13 | "XMP embedded profile with length %lu bytes", |
6734 | 13 | (unsigned long) profile_length); |
6735 | 13 | (void) TIFFSetField(tiff,TIFFTAG_XMLPACKET,(uint32) profile_length, |
6736 | 13 | profile_data); |
6737 | 13 | } |
6738 | 28.4k | #endif /* defined(TIFFTAG_XMLPACKET) */ |
6739 | | |
6740 | 28.4k | #if defined(TIFFTAG_ICCPROFILE) |
6741 | | /* |
6742 | | ICC color profile. |
6743 | | */ |
6744 | 28.4k | if ((profile_data=GetImageProfile(image,"ICM",&profile_length)) != 0) |
6745 | 165 | { |
6746 | 165 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6747 | 165 | "ICC ICM embedded profile with length %lu bytes", |
6748 | 165 | (unsigned long) profile_length); |
6749 | 165 | (void) TIFFSetField(tiff,TIFFTAG_ICCPROFILE,(uint32)profile_length, |
6750 | 165 | profile_data); |
6751 | 165 | } |
6752 | 28.4k | #endif /* defined(ICC_SUPPORT) */ |
6753 | | |
6754 | | /* |
6755 | | IPTC NewsPhoto profile. |
6756 | | */ |
6757 | 28.4k | if ((profile_data=GetImageProfile(image,"IPTC",&profile_length)) != 0) |
6758 | 403 | { |
6759 | 403 | int |
6760 | 403 | profile_tag=0; |
6761 | 403 | #if defined(TIFFTAG_PHOTOSHOP) |
6762 | | /* Photoshop profile (with embedded IPTC profile). */ |
6763 | 403 | profile_tag=TIFFTAG_PHOTOSHOP; |
6764 | 403 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6765 | 403 | "Photoshop embedded profile with length %lu" |
6766 | 403 | " bytes", |
6767 | 403 | (unsigned long) profile_length); |
6768 | | #else |
6769 | | /* IPTC TAG from RichTIFF specifications */ |
6770 | | profile_tag=TIFFTAG_RICHTIFFIPTC; |
6771 | | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6772 | | "IPTC Newsphoto embedded profile with length" |
6773 | | " %lu bytes", |
6774 | | (unsigned long) profile_length); |
6775 | | |
6776 | | #endif /* defined(PHOTOSHOP_SUPPORT) */ |
6777 | 403 | WriteNewsProfile(tiff,profile_tag,profile_data,profile_length); |
6778 | 403 | } |
6779 | 28.4k | } |
6780 | 28.4k | attribute=GetImageAttribute(image,"subfiletype"); |
6781 | 28.4k | if (attribute != (const ImageAttribute *) NULL) |
6782 | 9.16k | { |
6783 | | /* |
6784 | | Support "REDUCEDIMAGE", "PAGE", and "MASK". Any other |
6785 | | value results in no subfile type tag applied. |
6786 | | */ |
6787 | 9.16k | if (LocaleCompare(attribute->value,"REDUCEDIMAGE") == 0) |
6788 | 3.29k | { |
6789 | 3.29k | (void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_REDUCEDIMAGE); |
6790 | 3.29k | } |
6791 | 5.86k | else if (LocaleCompare(attribute->value,"PAGE") == 0) |
6792 | 0 | { |
6793 | 0 | (void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_PAGE); |
6794 | 0 | } |
6795 | 5.86k | else if (LocaleCompare(attribute->value,"MASK") == 0) |
6796 | 0 | { |
6797 | 0 | (void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_MASK); |
6798 | 0 | } |
6799 | 9.16k | } |
6800 | 19.2k | else |
6801 | 19.2k | { |
6802 | | /* |
6803 | | Page and Page number tags. Page is the current page number |
6804 | | (0 based) and pages is the total number of pages. |
6805 | | */ |
6806 | | |
6807 | 19.2k | uint16 |
6808 | 19.2k | page, |
6809 | 19.2k | pages; |
6810 | | |
6811 | 19.2k | page=(uint16) scene; |
6812 | 19.2k | pages=(uint16) image_list_length; |
6813 | | |
6814 | 19.2k | if (image_info->adjoin && pages > 1) |
6815 | 6.57k | { |
6816 | | /* |
6817 | | SubFileType = 2. LONG. The value 2 identifies a single |
6818 | | page of a multi-page image. |
6819 | | */ |
6820 | 6.57k | (void) TIFFSetField(tiff,TIFFTAG_SUBFILETYPE,FILETYPE_PAGE); |
6821 | 6.57k | } |
6822 | | |
6823 | 19.2k | (void) TIFFSetField(tiff,TIFFTAG_PAGENUMBER,page,pages); |
6824 | 19.2k | } |
6825 | 28.4k | attribute=GetImageAttribute(image,"artist"); |
6826 | 28.4k | if (attribute != (const ImageAttribute *) NULL) |
6827 | 856 | (void) TIFFSetField(tiff,TIFFTAG_ARTIST,attribute->value); |
6828 | | |
6829 | 28.4k | attribute=GetImageAttribute(image,"copyright"); |
6830 | 28.4k | if (attribute != (const ImageAttribute *) NULL) |
6831 | 1.02k | (void) TIFFSetField(tiff,33432,attribute->value); /* TIFFTAG_COPYRIGHT */ |
6832 | | |
6833 | 28.4k | attribute=GetImageAttribute(image,"timestamp"); |
6834 | 28.4k | if (attribute != (const ImageAttribute *) NULL) |
6835 | 1.08k | (void) TIFFSetField(tiff,TIFFTAG_DATETIME,attribute->value); |
6836 | | |
6837 | 28.4k | (void) TIFFSetField(tiff,TIFFTAG_DOCUMENTNAME,image->filename); |
6838 | | |
6839 | 28.4k | attribute=GetImageAttribute(image,"hostcomputer"); |
6840 | 28.4k | if (attribute != (const ImageAttribute *) NULL) |
6841 | 2.79k | (void) TIFFSetField(tiff,TIFFTAG_HOSTCOMPUTER,attribute->value); |
6842 | | |
6843 | 28.4k | attribute=GetImageAttribute(image,"comment"); |
6844 | 28.4k | if (attribute != (const ImageAttribute *) NULL) |
6845 | 330 | (void) TIFFSetField(tiff,TIFFTAG_IMAGEDESCRIPTION,attribute->value); |
6846 | | |
6847 | 28.4k | attribute=GetImageAttribute(image,"make"); |
6848 | 28.4k | if (attribute != (const ImageAttribute *) NULL) |
6849 | 1.19k | (void) TIFFSetField(tiff,TIFFTAG_MAKE,attribute->value); |
6850 | | |
6851 | 28.4k | attribute=GetImageAttribute(image,"model"); |
6852 | 28.4k | if (attribute != (const ImageAttribute *) NULL) |
6853 | 1.08k | (void) TIFFSetField(tiff,TIFFTAG_MODEL,attribute->value); |
6854 | | |
6855 | 28.4k | attribute=GetImageAttribute(image,"label"); |
6856 | 28.4k | if (attribute != (const ImageAttribute *) NULL) |
6857 | 236 | (void) TIFFSetField(tiff,TIFFTAG_PAGENAME,attribute->value); |
6858 | | |
6859 | 28.4k | attribute=GetImageAttribute(image,"software"); |
6860 | 28.4k | if (attribute != (const ImageAttribute *) NULL) |
6861 | 1.31k | { |
6862 | | /* |
6863 | | Allow skipping software tag if attribute exists but is empty. |
6864 | | */ |
6865 | 1.31k | if (strlen(attribute->value)) |
6866 | 703 | (void) TIFFSetField(tiff,TIFFTAG_SOFTWARE,attribute->value); |
6867 | 1.31k | } |
6868 | 27.1k | else |
6869 | 27.1k | { |
6870 | 27.1k | (void) TIFFSetField(tiff,TIFFTAG_SOFTWARE, |
6871 | 27.1k | GetMagickVersion((unsigned long *) NULL)); |
6872 | 27.1k | } |
6873 | | |
6874 | | #if 0 |
6875 | | /* |
6876 | | This tag is not supported by libtiff so the tag extension |
6877 | | mechanism would need to be used to add support for it. |
6878 | | */ |
6879 | | attribute=GetImageAttribute(image,"imageid"); |
6880 | | if (attribute != (const ImageAttribute *) NULL) |
6881 | | (void) TIFFSetField(tiff,TIFFTAG_OPIIMAGEID,attribute->value); |
6882 | | #endif |
6883 | | |
6884 | 28.4k | if (photometric == PHOTOMETRIC_PALETTE) |
6885 | 1.20k | { |
6886 | 1.20k | uint16 |
6887 | 1.20k | *blue, |
6888 | 1.20k | *green, |
6889 | 1.20k | *red; |
6890 | | |
6891 | | /* |
6892 | | Initialize TIFF colormap. |
6893 | | */ |
6894 | 1.20k | blue=MagickAllocateResourceLimitedClearedArray(unsigned short *, |
6895 | 1.20k | 65536L,sizeof(unsigned short)); |
6896 | 1.20k | green=MagickAllocateResourceLimitedClearedArray(unsigned short *, |
6897 | 1.20k | 65536L,sizeof(unsigned short)); |
6898 | 1.20k | red=MagickAllocateResourceLimitedClearedArray(unsigned short *, |
6899 | 1.20k | 65536L,sizeof(unsigned short)); |
6900 | 1.20k | if ((blue == (unsigned short *) NULL) || |
6901 | 1.20k | (green == (unsigned short *) NULL) || |
6902 | 1.20k | (red == (unsigned short *) NULL)) |
6903 | 0 | { |
6904 | 0 | MagickFreeResourceLimitedMemory(unsigned short *,blue); |
6905 | 0 | MagickFreeResourceLimitedMemory(unsigned short *,green); |
6906 | 0 | MagickFreeResourceLimitedMemory(unsigned short *,red); |
6907 | 0 | ThrowTIFFWriterException(ResourceLimitError,MemoryAllocationFailed, |
6908 | 0 | image); |
6909 | 0 | } |
6910 | 149k | for (i=0; i < image->colors; i++) |
6911 | 148k | { |
6912 | 148k | red[i]=ScaleQuantumToShort(image->colormap[i].red); |
6913 | 148k | green[i]=ScaleQuantumToShort(image->colormap[i].green); |
6914 | 148k | blue[i]=ScaleQuantumToShort(image->colormap[i].blue); |
6915 | 148k | } |
6916 | 1.20k | (void) TIFFSetField(tiff,TIFFTAG_COLORMAP,red,green,blue); |
6917 | 1.20k | MagickFreeResourceLimitedMemory(unsigned short *,red); |
6918 | 1.20k | MagickFreeResourceLimitedMemory(unsigned short *,green); |
6919 | 1.20k | MagickFreeResourceLimitedMemory(unsigned short *,blue); |
6920 | 1.20k | } |
6921 | | /* |
6922 | | Set extra export options for grayscale. |
6923 | | */ |
6924 | 28.4k | if (photometric == PHOTOMETRIC_MINISWHITE) |
6925 | 6.54k | export_options.grayscale_miniswhite=MagickTrue; |
6926 | 21.8k | else if (photometric == PHOTOMETRIC_MINISBLACK) |
6927 | 6.58k | export_options.grayscale_miniswhite=MagickFalse; |
6928 | | /* |
6929 | | Set extra export options for floating point. |
6930 | | */ |
6931 | 28.4k | if (sample_format == SAMPLEFORMAT_IEEEFP) |
6932 | 0 | { |
6933 | 0 | const char * |
6934 | 0 | definition_value; |
6935 | |
|
6936 | 0 | export_options.sample_type=FloatQuantumSampleType; |
6937 | 0 | if ((definition_value=AccessDefinition(image_info,"tiff","min-sample-value"))) |
6938 | 0 | export_options.double_minvalue=strtod(definition_value,(char **)NULL); |
6939 | 0 | if ((definition_value=AccessDefinition(image_info,"tiff","max-sample-value"))) |
6940 | 0 | export_options.double_maxvalue=strtod(definition_value,(char **)NULL); |
6941 | 0 | (void) TIFFSetField(tiff,TIFFTAG_SMINSAMPLEVALUE, |
6942 | 0 | export_options.double_minvalue); |
6943 | 0 | (void) TIFFSetField(tiff,TIFFTAG_SMAXSAMPLEVALUE, |
6944 | 0 | export_options.double_maxvalue); |
6945 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6946 | 0 | "Using min sample value %g, max sample value %g", |
6947 | 0 | export_options.double_minvalue, |
6948 | 0 | export_options.double_maxvalue); |
6949 | 0 | } |
6950 | | |
6951 | | /* |
6952 | | For sample sizes matching a CPU native word, use native endian |
6953 | | order for import. |
6954 | | */ |
6955 | 28.4k | if ((16 == bits_per_sample) || (32 == bits_per_sample) || (64 == bits_per_sample)) |
6956 | 7.86k | export_options.endian=NativeEndian; |
6957 | | |
6958 | | /* |
6959 | | Export pixels to TIFF. |
6960 | | |
6961 | | FIXME: JBIG needs a Strip writer. |
6962 | | */ |
6963 | 28.4k | switch (method) |
6964 | 28.4k | { |
6965 | 0 | default: |
6966 | 28.4k | case ScanLineMethod: |
6967 | 28.4k | { |
6968 | | /* |
6969 | | Write TIFF image as scanlines |
6970 | | */ |
6971 | 28.4k | unsigned char |
6972 | 28.4k | *scanline; |
6973 | | |
6974 | 28.4k | const PixelPacket |
6975 | 28.4k | *p; |
6976 | | |
6977 | 28.4k | int |
6978 | 28.4k | max_sample, |
6979 | 28.4k | quantum_samples, |
6980 | 28.4k | sample; |
6981 | | |
6982 | 28.4k | QuantumType |
6983 | 28.4k | quantum_type; |
6984 | | |
6985 | | /* |
6986 | | Allocate memory for one scanline. |
6987 | | */ |
6988 | 28.4k | scanline_size=TIFFScanlineSize(tiff); |
6989 | | |
6990 | 28.4k | if (logging) |
6991 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
6992 | 0 | "Using scanline %s write method with %u " |
6993 | 0 | "bits per sample (%lu bytes/scanline)", |
6994 | 0 | PhotometricTagToString(photometric), |
6995 | 0 | bits_per_sample, (unsigned long) scanline_size); |
6996 | | /* |
6997 | | Prepare for separate/contiguous retrieval. |
6998 | | */ |
6999 | 28.4k | max_sample=1; |
7000 | 28.4k | if (planar_config == PLANARCONFIG_SEPARATE) |
7001 | 1.38k | { |
7002 | 1.38k | if (QuantumTransferMode(image,photometric,compress_tag, |
7003 | 1.38k | sample_format,samples_per_pixel, |
7004 | 1.38k | PLANARCONFIG_CONTIG,0,&quantum_type, |
7005 | 1.38k | &quantum_samples,&image->exception) |
7006 | 1.38k | == MagickPass) |
7007 | 1.38k | max_sample=quantum_samples; |
7008 | 1.38k | } |
7009 | | |
7010 | 28.4k | scanline=MagickAllocateResourceLimitedMemory(unsigned char *,(size_t) scanline_size); |
7011 | 28.4k | if (scanline == (unsigned char *) NULL) |
7012 | 28.4k | ThrowTIFFWriterException(ResourceLimitError,MemoryAllocationFailed,image); |
7013 | | /* |
7014 | | For each plane |
7015 | | */ |
7016 | 59.8k | for (sample=0; (status != MagickFail) && (sample < max_sample); sample++) |
7017 | 31.4k | { |
7018 | | /* |
7019 | | Determine quantum parse method. |
7020 | | */ |
7021 | 31.4k | if (QuantumTransferMode(image,photometric,compress_tag, |
7022 | 31.4k | sample_format,samples_per_pixel, |
7023 | 31.4k | planar_config,sample,&quantum_type, |
7024 | 31.4k | &quantum_samples,&image->exception) |
7025 | 31.4k | == MagickFail) |
7026 | 0 | { |
7027 | 0 | status=MagickFail; |
7028 | 0 | break; |
7029 | 0 | } |
7030 | 8.03M | for (y=0; (status != MagickFail) && (y < image->rows); y++) |
7031 | 8.00M | { |
7032 | 8.00M | if ((image->matte) && (alpha_type == AssociatedAlpha)) |
7033 | 376k | p=GetImagePixels(image,0,y,image->columns,1); |
7034 | 7.62M | else |
7035 | 7.62M | p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception); |
7036 | 8.00M | if (p == (const PixelPacket *) NULL) |
7037 | 0 | { |
7038 | 0 | status=MagickFail; |
7039 | 0 | break; |
7040 | 0 | } |
7041 | | /* |
7042 | | Convert to associated alpha if necessary. |
7043 | | */ |
7044 | 8.00M | if ((sample == 0) && (image->matte) && |
7045 | 425k | (alpha_type == AssociatedAlpha)) |
7046 | 374k | AssociateAlphaRegion(image); |
7047 | | /* |
7048 | | Export pixels to scanline. |
7049 | | */ |
7050 | 8.00M | if (ExportImagePixelArea(image,quantum_type,bits_per_sample, |
7051 | 8.00M | scanline,&export_options,&export_info) |
7052 | 8.00M | == MagickFail) |
7053 | 0 | { |
7054 | 0 | status=MagickFail; |
7055 | 0 | break; |
7056 | 0 | } |
7057 | | /* |
7058 | | Write scanline. |
7059 | | */ |
7060 | 8.00M | #if !defined(WORDS_BIGENDIAN) |
7061 | 8.00M | if (24 == bits_per_sample) |
7062 | 0 | SwabDataToNativeEndian(bits_per_sample,scanline,scanline_size); |
7063 | 8.00M | #endif |
7064 | 8.00M | if (TIFFWriteScanline(tiff, scanline,y,sample) == -1) |
7065 | 12 | { |
7066 | 12 | status=MagickFail; |
7067 | 12 | break; |
7068 | 12 | } |
7069 | | |
7070 | 8.00M | if (image->previous == (Image *) NULL) |
7071 | 7.40M | if (QuantumTick(y+(magick_int64_t)sample*image->rows, (magick_int64_t)image->rows*max_sample)) |
7072 | 1.13M | if (!MagickMonitorFormatted(y+ (magick_int64_t)sample*image->rows, |
7073 | 1.13M | (magick_int64_t)image->rows*max_sample,&image->exception, |
7074 | 1.13M | SaveImageText,image->filename, |
7075 | 1.13M | image->columns,image->rows)) |
7076 | 0 | { |
7077 | 0 | status=MagickFail; |
7078 | 0 | break; |
7079 | 0 | } |
7080 | | |
7081 | 8.00M | } |
7082 | 31.4k | if (status == MagickFail) |
7083 | 12 | break; |
7084 | 31.4k | } |
7085 | 28.4k | MagickFreeResourceLimitedMemory(unsigned char *,scanline); |
7086 | 28.4k | break; |
7087 | 28.4k | } |
7088 | 0 | case TiledMethod: |
7089 | 0 | { |
7090 | | /* |
7091 | | Write TIFF image as tiles |
7092 | | */ |
7093 | 0 | unsigned char |
7094 | 0 | *tile; |
7095 | |
|
7096 | 0 | uint32 |
7097 | 0 | tile_columns, |
7098 | 0 | tile_rows; |
7099 | |
|
7100 | 0 | tsize_t |
7101 | 0 | stride, |
7102 | 0 | tile_size, |
7103 | 0 | tile_size_max; |
7104 | |
|
7105 | 0 | int |
7106 | 0 | max_sample, |
7107 | 0 | quantum_samples, |
7108 | 0 | sample; |
7109 | |
|
7110 | 0 | QuantumType |
7111 | 0 | quantum_type; |
7112 | |
|
7113 | 0 | unsigned long |
7114 | 0 | tile_total_pixels; |
7115 | |
|
7116 | 0 | if (logging) |
7117 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7118 | 0 | "Using tiled %s write method with %u bits " |
7119 | 0 | "per sample", |
7120 | 0 | PhotometricTagToString(photometric), |
7121 | 0 | bits_per_sample); |
7122 | | |
7123 | | /* |
7124 | | Determine tile size |
7125 | | */ |
7126 | 0 | { |
7127 | 0 | const char * |
7128 | 0 | value; |
7129 | |
|
7130 | 0 | tile_columns=0; |
7131 | 0 | tile_rows=0; |
7132 | | |
7133 | | /* |
7134 | | Enable tiled output (with default size, or specified separately) |
7135 | | -define tiff:tile |
7136 | | |
7137 | | Use an exact tile size in rows & columns |
7138 | | -define tiff:tile-geometry=128x128 |
7139 | | |
7140 | | Use a specific tile width (pixels) |
7141 | | -define tiff:tile-width=128 |
7142 | | |
7143 | | Use a specific tile height (pixels) |
7144 | | -define tiff:tile-height=128 |
7145 | | */ |
7146 | 0 | if ((value=AccessDefinition(image_info,"tiff","tile-geometry"))) |
7147 | 0 | { |
7148 | 0 | double |
7149 | 0 | width, |
7150 | 0 | height; |
7151 | |
|
7152 | 0 | if (GetMagickDimension(value,&width,&height,NULL,NULL) == 2) |
7153 | 0 | { |
7154 | 0 | tile_rows=(uint32) height; |
7155 | 0 | tile_columns=(uint32) width; |
7156 | 0 | } |
7157 | 0 | } |
7158 | 0 | if ((value=AccessDefinition(image_info,"tiff","tile-width"))) |
7159 | 0 | { |
7160 | 0 | tile_columns=MagickAtoL(value); |
7161 | 0 | } |
7162 | 0 | if ((value=AccessDefinition(image_info,"tiff","tile-height"))) |
7163 | 0 | { |
7164 | 0 | tile_rows=MagickAtoL(value); |
7165 | 0 | } |
7166 | |
|
7167 | 0 | TIFFDefaultTileSize(tiff,&tile_columns,&tile_rows); |
7168 | 0 | } |
7169 | |
|
7170 | 0 | if (!TIFFSetField(tiff,TIFFTAG_TILEWIDTH,tile_columns)) |
7171 | 0 | status=MagickFail; |
7172 | 0 | if (!TIFFSetField(tiff,TIFFTAG_TILELENGTH,tile_rows)) |
7173 | 0 | status=MagickFail; |
7174 | | /* |
7175 | | Obtain the maximum number of bytes required to contain a tile. |
7176 | | */ |
7177 | 0 | tile_size_max=TIFFTileSize(tiff); |
7178 | | /* |
7179 | | Compute the total number of pixels in one tile |
7180 | | */ |
7181 | 0 | tile_total_pixels=tile_columns*tile_rows; |
7182 | 0 | if (logging) |
7183 | 0 | { |
7184 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7185 | 0 | "TIFF tile geometry %ux%u, %lu pixels", |
7186 | 0 | (unsigned int)tile_columns, |
7187 | 0 | (unsigned int)tile_rows, |
7188 | 0 | tile_total_pixels); |
7189 | 0 | } |
7190 | | /* |
7191 | | Allocate tile buffer |
7192 | | */ |
7193 | 0 | tile=MagickAllocateResourceLimitedMemory(unsigned char *, (size_t) tile_size_max); |
7194 | 0 | if (tile == (unsigned char *) NULL) |
7195 | 0 | ThrowTIFFWriterException(ResourceLimitError,MemoryAllocationFailed,image); |
7196 | | /* |
7197 | | Prepare for separate/contiguous retrieval. |
7198 | | */ |
7199 | 0 | max_sample=1; |
7200 | 0 | if (planar_config == PLANARCONFIG_SEPARATE) |
7201 | 0 | { |
7202 | 0 | if (QuantumTransferMode(image,photometric,compress_tag, |
7203 | 0 | sample_format,samples_per_pixel, |
7204 | 0 | PLANARCONFIG_CONTIG,0,&quantum_type, |
7205 | 0 | &quantum_samples,&image->exception) |
7206 | 0 | == MagickPass) |
7207 | 0 | max_sample=quantum_samples; |
7208 | 0 | } |
7209 | | /* |
7210 | | Obtain per-row stride. |
7211 | | */ |
7212 | 0 | stride=TIFFTileRowSize(tiff); |
7213 | | |
7214 | | /* |
7215 | | Process each plane. |
7216 | | */ |
7217 | 0 | for (sample=0; (status != MagickFail) && (sample < max_sample); sample++) |
7218 | 0 | { |
7219 | | /* |
7220 | | Determine quantum parse method. |
7221 | | */ |
7222 | 0 | if (QuantumTransferMode(image,photometric,compress_tag, |
7223 | 0 | sample_format,samples_per_pixel, |
7224 | 0 | planar_config,sample,&quantum_type, |
7225 | 0 | &quantum_samples,&image->exception) |
7226 | 0 | == MagickFail) |
7227 | 0 | { |
7228 | 0 | status=MagickFail; |
7229 | 0 | break; |
7230 | 0 | } |
7231 | 0 | for (y=0; (status != MagickFail) && (y < image->rows); y+=tile_rows) |
7232 | 0 | { |
7233 | 0 | for (x=0; (status != MagickFail) && (x < image->columns); x+=tile_columns) |
7234 | 0 | { |
7235 | 0 | const PixelPacket |
7236 | 0 | *p; |
7237 | |
|
7238 | 0 | long |
7239 | 0 | tile_set_columns, |
7240 | 0 | tile_set_rows; |
7241 | |
|
7242 | 0 | unsigned char |
7243 | 0 | *q; |
7244 | |
|
7245 | 0 | register long |
7246 | 0 | yy; |
7247 | | |
7248 | | /* |
7249 | | Compute image region corresponding to tile. |
7250 | | */ |
7251 | 0 | if (x+tile_columns > image->columns) |
7252 | 0 | tile_set_columns=(tile_columns-(x+tile_columns-image->columns)); |
7253 | 0 | else |
7254 | 0 | tile_set_columns=tile_columns; |
7255 | 0 | if (y+tile_rows > image->rows) |
7256 | 0 | tile_set_rows=(tile_rows-(y+tile_rows-image->rows)); |
7257 | 0 | else |
7258 | 0 | tile_set_rows=tile_rows; |
7259 | |
|
7260 | 0 | q=tile; |
7261 | 0 | for (yy=y; (status != MagickFail) && (yy < (long) y+tile_set_rows); yy++) |
7262 | 0 | { |
7263 | | /* |
7264 | | Obtain pixel region corresponding to tile row. |
7265 | | */ |
7266 | 0 | if ((image->matte) && (alpha_type == AssociatedAlpha)) |
7267 | 0 | p=GetImagePixels(image,x,yy,tile_set_columns,1); |
7268 | 0 | else |
7269 | 0 | p=AcquireImagePixels(image,x,yy,tile_set_columns, |
7270 | 0 | 1,&image->exception); |
7271 | 0 | if (p == (const PixelPacket *) NULL) |
7272 | 0 | { |
7273 | 0 | status=MagickFail; |
7274 | 0 | break; |
7275 | 0 | } |
7276 | | /* |
7277 | | Convert to associated alpha if necessary. |
7278 | | */ |
7279 | 0 | if ((sample == 0) && (image->matte) && |
7280 | 0 | (alpha_type == AssociatedAlpha)) |
7281 | 0 | AssociateAlphaRegion(image); |
7282 | | /* |
7283 | | Export tile row |
7284 | | */ |
7285 | 0 | if (ExportImagePixelArea(image,quantum_type, |
7286 | 0 | bits_per_sample,q, |
7287 | 0 | &export_options,&export_info) |
7288 | 0 | == MagickFail) |
7289 | 0 | { |
7290 | 0 | status=MagickFail; |
7291 | 0 | break; |
7292 | 0 | } |
7293 | | /* |
7294 | | Enforce that we did not overrun our buffer. |
7295 | | */ |
7296 | 0 | assert(export_info.bytes_exported <= (size_t) scanline_size); |
7297 | 0 | q += stride; |
7298 | 0 | } /* for yy */ |
7299 | 0 | if (status == MagickFail) |
7300 | 0 | break; |
7301 | | /* |
7302 | | Write tile. |
7303 | | */ |
7304 | 0 | #if !defined(WORDS_BIGENDIAN) |
7305 | 0 | if (24 == bits_per_sample) |
7306 | 0 | SwabDataToNativeEndian(bits_per_sample,tile,tile_size_max); |
7307 | 0 | #endif |
7308 | 0 | if ((tile_size=TIFFWriteTile(tiff,tile,x,y,0,sample)) == -1) |
7309 | 0 | { |
7310 | 0 | status=MagickFail; |
7311 | 0 | } |
7312 | 0 | if (status == MagickFail) |
7313 | 0 | break; |
7314 | 0 | } /* for x */ |
7315 | | /* |
7316 | | Progress indicator. |
7317 | | */ |
7318 | 0 | if (image->previous == (Image *) NULL) |
7319 | 0 | if (QuantumTick((y+sample*image->rows)/tile_rows, |
7320 | 0 | (image->rows*max_sample)/tile_rows)) |
7321 | 0 | if (!MagickMonitorFormatted((y+sample*image->rows)/tile_rows, |
7322 | 0 | (image->rows*max_sample)/tile_rows, |
7323 | 0 | &image->exception, |
7324 | 0 | SaveImageText,image->filename, |
7325 | 0 | image->columns,image->rows)) |
7326 | 0 | status=MagickFail; |
7327 | |
|
7328 | 0 | if (status == MagickFail) |
7329 | 0 | break; |
7330 | 0 | } /* for y */ |
7331 | 0 | } /* for sample */ |
7332 | 0 | MagickFreeResourceLimitedMemory(unsigned char *,tile); |
7333 | 0 | break; |
7334 | 0 | } |
7335 | 28.4k | } |
7336 | 28.4k | if (image_info->verbose > 1) |
7337 | 0 | TIFFPrintDirectory(tiff,stdout,MagickFalse); |
7338 | 28.4k | if (!TIFFWriteDirectory(tiff)) |
7339 | 51 | { |
7340 | 51 | status=MagickFail; |
7341 | 51 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7342 | 51 | "TIFFWriteDirectory returns failed status!"); |
7343 | 51 | } |
7344 | | |
7345 | 28.4k | #if EXPERIMENTAL_EXIF_TAGS |
7346 | 28.4k | #if TIFFLIB_VERSION >= 20120922 |
7347 | | |
7348 | 28.4k | if (status!=MagickFail) |
7349 | 28.3k | { |
7350 | 28.3k | const unsigned char *profile_data; |
7351 | 28.3k | size_t profile_length; |
7352 | 28.3k | if ((profile_data=GetImageProfile(image,"Exif",&profile_length)) != 0) |
7353 | 84 | { |
7354 | 84 | magick_uint64_t dir_EXIF_offset = 0; |
7355 | 84 | magick_uint64_t dir_GPS_offset = 0; |
7356 | | /* |
7357 | | * Unfortunately it depends on the prehistory, what number TIFFCurrentDirectory() will get back. |
7358 | | * Therefore, the current main IFD number has to be adapted. However, this is an inconsistency in LibTIFF which should be |
7359 | | * corrected. This means that the provided code to determíne/handle current directory number here is just a current work around. |
7360 | | */ |
7361 | 84 | tdir_t current_mainifd = TIFFCurrentDirectory(tiff); |
7362 | 84 | if (TIFFCurrentDirOffset(tiff) > 0 && current_mainifd > 0) current_mainifd--; |
7363 | | |
7364 | 84 | TIFFFreeDirectory(tiff); |
7365 | 84 | if (TIFFCreateEXIFDirectory(tiff) == 0) |
7366 | 84 | { |
7367 | 84 | if (AddExifFields(tiff,profile_data,profile_length,logging, FLAG_EXIF) > 0) |
7368 | 0 | { /* Now write the directory of Exif data */ |
7369 | |
|
7370 | 0 | if (!TIFFWriteCustomDirectory(tiff, &dir_EXIF_offset)) |
7371 | 0 | { |
7372 | 0 | LogMagickEvent(CoderEvent,GetMagickModule(),"Failed TIFFWriteCustomDirectory() of the Exif data"); |
7373 | 0 | } |
7374 | 0 | } |
7375 | 84 | } |
7376 | | |
7377 | 84 | #if TIFFLIB_VERSION >= 20230609 |
7378 | 84 | if (TIFFCreateGPSDirectory(tiff) == 0) |
7379 | 84 | { |
7380 | 84 | if (AddExifFields(tiff,profile_data,profile_length,logging, FLAG_GPS) > 0) |
7381 | 0 | { /* Now write the directory of Exif data */ |
7382 | 0 | if (!TIFFWriteCustomDirectory(tiff, &dir_GPS_offset)) |
7383 | 0 | { |
7384 | 0 | LogMagickEvent(CoderEvent,GetMagickModule(),"Failed TIFFWriteCustomDirectory() of the ExifGPS data"); |
7385 | 0 | } |
7386 | 0 | } |
7387 | 84 | else |
7388 | 84 | TIFFSetDirectory(tiff, 0); |
7389 | 84 | } |
7390 | 84 | #endif |
7391 | | |
7392 | 84 | if (dir_EXIF_offset>0 || dir_GPS_offset>0) |
7393 | 0 | { /* Go back to the first directory, and add the EXIFIFD pointer. */ |
7394 | 0 | TIFFSetDirectory(tiff, 0); |
7395 | 0 | if (dir_EXIF_offset>0) |
7396 | 0 | TIFFSetField(tiff, TIFFTAG_EXIFIFD, dir_EXIF_offset); |
7397 | 0 | if (dir_GPS_offset>0) |
7398 | 0 | TIFFSetField(tiff, TIFFTAG_GPSIFD, dir_GPS_offset); |
7399 | 0 | } |
7400 | | |
7401 | | /* Save changed tiff-directory to file */ |
7402 | 84 | if (image->next != (Image *)NULL) |
7403 | 0 | { |
7404 | 0 | if (!TIFFWriteDirectory(tiff)) |
7405 | 0 | { |
7406 | 0 | (void)LogMagickEvent(CoderEvent, GetMagickModule(), "TIFFWriteDirectory returns failed status!"); |
7407 | 0 | } |
7408 | | /* Re configure directory status for next image. Reset current IFD number. */ |
7409 | 0 | if (!TIFFSetDirectory(tiff, current_mainifd)) |
7410 | 0 | { |
7411 | 0 | if (logging) |
7412 | 0 | LogMagickEvent(CoderEvent,GetMagickModule(),"TIFFSetDirectory() failed.\n"); |
7413 | 0 | } |
7414 | 0 | TIFFFreeDirectory(tiff); |
7415 | 0 | if (!TIFFCreateDirectory(tiff)) |
7416 | 0 | { |
7417 | 0 | if (logging) |
7418 | 0 | LogMagickEvent(CoderEvent,GetMagickModule(),"TIFFCreateDirectory() failed.\n"); |
7419 | 0 | } |
7420 | 0 | } |
7421 | 84 | } |
7422 | 28.3k | } |
7423 | 28.4k | #endif /* TIFFLIB_VERSION >= 20120922 */ |
7424 | 28.4k | #endif /* if EXPERIMENTAL_EXIF_TAGS */ |
7425 | | |
7426 | 28.4k | if (image->next == (Image *) NULL) |
7427 | 18.7k | break; |
7428 | 9.71k | image=SyncNextImageInList(image); |
7429 | 9.71k | if ((status &= MagickMonitorFormatted(scene++, |
7430 | 9.71k | image_list_length, |
7431 | 9.71k | &image->exception, |
7432 | 9.71k | SaveImagesText, |
7433 | 9.71k | image->filename)) == MagickFail) |
7434 | 28 | break; |
7435 | 9.71k | } while (image_info->adjoin); |
7436 | 28.4k | while (image->previous != (Image *) NULL) |
7437 | 9.71k | image=image->previous; |
7438 | 18.7k | if (TIFFFlush(tiff) != 1) /* Flush pending writes, check status */ |
7439 | 51 | status=MagickFail; |
7440 | 18.7k | TIFFClose(tiff); /* Should implicity invoke CloseBlob(image) */ |
7441 | | |
7442 | 18.7k | if (status == MagickFail) |
7443 | 51 | { |
7444 | | /* |
7445 | | Handle write failure. |
7446 | | */ |
7447 | | |
7448 | 51 | if (unlink(filename) != -1) |
7449 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
7450 | 0 | "Removed broken output file \"%s\"",filename); |
7451 | 51 | } |
7452 | | |
7453 | 18.7k | return(status); |
7454 | 18.7k | } |
7455 | | #endif |