Coverage Report

Created: 2026-06-07 07:20

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