Coverage Report

Created: 2025-12-03 07:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/graphicsmagick/coders/dpx.c
Line
Count
Source
1
/*
2
% Copyright (C) 2005-2022 GraphicsMagick Group
3
%
4
% This program is covered by multiple licenses, which are described in
5
% Copyright.txt. You should have received a copy of Copyright.txt with this
6
% package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
7
%
8
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9
%                                                                             %
10
%                                                                             %
11
%                                                                             %
12
%                            DDDD   PPPP   X   X                              %
13
%                            D   D  P   P   X X                               %
14
%                            D   D  PPPP    XXX                               %
15
%                            D   D  P       X X                               %
16
%                            DDDD   P      X   X                              %
17
%                                                                             %
18
%                                                                             %
19
%               Read/Write SMTPE 268M-2003 DPX Image Format.                  %
20
%                                                                             %
21
%                                                                             %
22
%                              Software Design                                %
23
%                              Bob Friesenhahn                                %
24
%                                March 2005                                   %
25
%                                                                             %
26
%                                                                             %
27
%                                                                             %
28
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
29
%
30
%
31
% Supported features:
32
%
33
%   Anything which can be read, can also be written.
34
%   All DPX header information is saved as image attributes and saved
35
%   when the image is written.
36
%
37
%   Colorspaces:
38
%    RGB
39
%    Log RGB (density range = 2.048)
40
%    Grayscale (Luma)
41
%    YCbCr 4:4:4 and 4:2:2 (use -sampling-factor 2x1 for 4:2:2)
42
%
43
%   Storage:
44
%    Bits per sample of 1, 8, 10, 12, and 16.
45
%    Packed, or fill type A or B for 10/12 bits.
46
%    All RGB-oriented element types (R, G, B, A, RGB, RGBA, ABGR).
47
%    All YCbCr-oriented element types.
48
%    Planar (multi-element) storage fully supported.
49
%    Alpha (key channel) may be stored in a separate element.
50
%
51
% Not currently supported:
52
%
53
%   Colorspaces:
54
%    Composite Video
55
%
56
%   Storage:
57
%    Bits per sample of 32 and 64 (floating point).
58
%    Depth.
59
%
60
% Notes about byte order:
61
%
62
%    The DPX specification doesn't say anything about how endian byte
63
%    order should influence the image pixels.  The 1994 version of the
64
%    specification suggests very strongly that *all* formats are
65
%    accessed as an array of 32-bit words (therefore implying 32-bit
66
%    swapping) but the 2003 specification has amended this (ambiguously)
67
%    to imply the mixed use of 16 and 32 bit words.  As we all know,
68
%    performing endian swapping on two 16-bit values does not have the
69
%    same effect as performing endian swapping on one 32-bit value (the
70
%    order of the two 16-bit samples is reversed) so the 2003 specification
71
%    is not compatible with the 1994 specification.
72
%
73
%    Due to the lack of an unambiguous standard, GraphicsMagick is currently
74
%    using the following endian rules.  These rules may change at any time:
75
%
76
%      o 8 bit format is always written in ascending order so endian rules
77
%        do not apply.
78
%
79
%      o Packed 10 and 12-bit formats are based on a 32-bit word, so
80
%        32-bit words are byte-swapped to native order.
81
%
82
%      o 12-bit filled format, and 16 bit format are based on 16-bit words,
83
%        so 16-bit words are byte-swapped to native order.
84
%
85
%      o 10-bit filled format is based on a 32-bit word, so 32-bit words
86
%        are byte-swapped to native order.
87
%
88
%    The default format is big-endian.
89
%
90
% Additional notes:
91
%
92
%    I have received many 4:2:2 YCbCr files in which the Cb/Cr channels are
93
%    swapped from my interpretation of the specification. This has caused
94
%    considerable consternation.  As a result I have decided to observe the
95
%    "majority rules" rule and follow the apparent direction set by systems
96
%    set by Quantel iQ, and DVS Clipster.  Therefore, 4:2:2 YCbCr files have
97
%    Cb/Cr intentionally swapped from the standard.  But 4:4:4 YCbCr files
98
%    use the ordering suggested by the standard since all such files received
99
%    to date follow the standard.
100
%
101
%     If a YCbCr file reads with vertical or color distortion, try adding
102
%    "-define dpx:swap-samples=true" when reading the image. The same option
103
%    may be used to write YCbCr files with swapped samples.
104
%
105
%    Note that some YCbCr files are interlaced.  Interlaced files combine
106
%    two fields into one image.  This means that 1/60th of a second has
107
%    elapsed between odd and even rows.  Distortion will be evident if
108
%    the camera or observed object is in motion.  This distortion is not
109
%    due to a defect in GraphicsMagick.
110
%
111
%    The DPX specification does not specify row alignment on a 32-bit
112
%    word boundary, but unofficial documentation (e.g. the O'Reilly
113
%    GFF book) and "lore" suggest it.  The GraphicsMagick implementation
114
%    does pad rows to the next word (16-bit or 32-bit) boundary.  It is not
115
%    clear if the End-of-line padding field should reflect padding to a
116
%    word boundary.
117
%
118
*/
119

120
/*
121
  Include declarations.
122
*/
123
#include "magick/studio.h"
124
#include "magick/attribute.h"
125
#include "magick/blob.h"
126
#include "magick/bit_stream.h"
127
#include "magick/pixel_cache.h"
128
#include "magick/constitute.h"
129
#include "magick/enum_strings.h"
130
#include "magick/magick_endian.h"
131
#include "magick/log.h"
132
#include "magick/magick.h"
133
#include "magick/monitor.h"
134
#include "magick/omp_data_view.h"
135
#include "magick/profile.h"
136
#include "magick/resize.h"
137
#include "magick/utility.h"
138
#include "magick/version.h"
139
140
/*
141
  Define STATIC to nothing so that normally static functions are
142
  externally visible in the symbol table (for profiling).
143
*/
144
#undef STATIC
145
#define STATIC static
146

147
/*
148
  Forward declaractions.
149
*/
150
static unsigned int
151
  WriteDPXImage(const ImageInfo *,Image *);
152
153
typedef char ASCII;
154
typedef magick_uint8_t U8;
155
typedef magick_uint16_t U16;
156
typedef magick_uint32_t U32;
157
typedef union _R32_u
158
{
159
  magick_uint32_t u;
160
  float f;
161
} R32;
162
typedef magick_uint16_t sample_t;
163
164
7.20k
#define SET_UNDEFINED_U8(value)  (value=0xFFU)
165
3.57k
#define SET_UNDEFINED_U16(value) (value=0xFFFFU)
166
15.5k
#define SET_UNDEFINED_U32(value) (value=0xFFFFFFFFU)
167
14.0k
#define SET_UNDEFINED_R32(value) (value.u=~0U);
168
1.07k
#define SET_UNDEFINED_ASCII(value) ((void) memset(value,0,sizeof(value)))
169
170
25.7k
#define IS_UNDEFINED_U8(value) (value == ((U8) 0xFFU))
171
49.8k
#define IS_UNDEFINED_U16(value) (value == ((U16) 0xFFFFU))
172
228k
#define IS_UNDEFINED_U32(value) (value == ((U32) 0xFFFFFFFFU))
173
134k
#define IS_UNDEFINED_R32(value) (value.u == ((U32) ~0U))
174
324k
#define IS_UNDEFINED_ASCII(value) (!(value[0] > 0))
175
176
/*
177
  Round the starting address of pixel data to this offset.  The DPX
178
  specification recommends rounding up to the next 8K boundary past
179
  the file header.
180
*/
181
#define IMAGE_DATA_ROUNDING 8192
182
183
/*
184
  Image element descriptors.
185
*/
186
typedef enum
187
{
188
  ImageElementUnspecified=0,
189
  ImageElementRed=1,
190
  ImageElementGreen=2,
191
  ImageElementBlue=3,
192
  ImageElementAlpha=4,
193
  ImageElementLuma=6,
194
  ImageElementColorDifferenceCbCr=7, /* 4:2:2 */
195
  ImageElementDepth=8,
196
  ImageElementCompositeVideo=9,
197
  ImageElementRGB=50,              /* BGR order */
198
  ImageElementRGBA=51,             /* BGRA order */
199
  ImageElementABGR=52,             /* ARGB order */
200
  ImageElementCbYCrY422=100,       /* SMPTE 125M, 4:2:2 */
201
  ImageElementCbYACrYA4224=101,    /* 4:2:2:4 */
202
  ImageElementCbYCr444=102,        /* 4:4:4 */
203
  ImageElementCbYCrA4444=103,      /* 4:4:4:4 */
204
  ImageElementUserDef2Element=150, /* User-defined 2-component element */
205
  ImageElementUserDef3Element=151, /* User-defined 3-component element */
206
  ImageElementUserDef4Element=152, /* User-defined 4-component element */
207
  ImageElementUserDef5Element=153, /* User-defined 5-component element */
208
  ImageElementUserDef6Element=154, /* User-defined 6-component element */
209
  ImageElementUserDef7Element=155, /* User-defined 7-component element */
210
  ImageElementUserDef8Element=156  /* User-defined 8-component element */
211
} DPXImageElementDescriptor;
212
213
/*
214
  Transfer characteristic enumerations.
215
*/
216
typedef enum
217
{
218
  TransferCharacteristicUserDefined=0,
219
  TransferCharacteristicPrintingDensity=1,
220
  TransferCharacteristicLinear=2,
221
  TransferCharacteristicLogarithmic=3,
222
  TransferCharacteristicUnspecifiedVideo=4,
223
  TransferCharacteristicSMTPE274M=5,     /* 1920x1080 TV */
224
  TransferCharacteristicITU_R709=6,      /* ITU R709 */
225
  TransferCharacteristicITU_R601_625L=7, /* 625 Line */
226
  TransferCharacteristicITU_R601_525L=8, /* 525 Line */
227
  TransferCharacteristicNTSCCompositeVideo=9,
228
  TransferCharacteristicPALCompositeVideo=10,
229
  TransferCharacteristicZDepthLinear=11,
230
  TransferCharacteristicZDepthHomogeneous=12
231
} DPXTransferCharacteristic;
232
233
/*
234
  Colorimetric enumerations.
235
*/
236
typedef enum
237
{
238
  ColorimetricUserDefined=0,       /* User defined */
239
  ColorimetricPrintingDensity=1,   /* Printing density */
240
  ColorimetricLinear=2,            /* Linear */
241
  ColorimetricLogarithmic=3,       /* Logarithmic */
242
  ColorimetricUnspecifiedVideo=4,
243
  ColorimetricSMTPE274M=5,         /* 1920x1080 TV */
244
  ColorimetricITU_R709=6,          /* ITU R709 */
245
  ColorimetricITU_R601_625L=7,     /* 625 Line ITU R601-5 B & G */
246
  ColorimetricITU_R601_525L=8,     /* 525 Line ITU R601-5 M */
247
  ColorimetricNTSCCompositeVideo=9,
248
  ColorimetricPALCompositeVideo=10,
249
  ColorimetricZDepthLinear=11,
250
  ColorimetricZDepthHomogeneous=12
251
} DPXColorimetric;
252
253
/*
254
  Packing methods for filled words.
255
*/
256
typedef enum
257
{
258
  PackingMethodPacked=0,           /* Packed with no padding */
259
  PackingMethodWordsFillLSB=1,     /* Method 'A', padding bits in LSB of 32-bit word */
260
  PackingMethodWordsFillMSB=2      /* Method 'B', padding bits in MSB of 32-bit word (deprecated) */
261
}  ImageComponentPackingMethod;
262
263
typedef struct _DPXFileInfo
264
{
265
  U32   magic;                     /* Magick number (SDPX ASCII) */
266
  U32   image_data_offset;         /* Offset to image data in bytes */
267
  ASCII header_format_version[8];  /* Version number of header format */
268
  U32   file_size;                 /* Total image file size in bytes  */
269
  U32   ditto_key;                 /* (0 = same as previous frame; 1 = new) */
270
  U32   generic_section_length;    /* Generic section header length in bytes */
271
  U32   industry_section_length;   /* Industry specific header length in bytes */
272
  U32   user_defined_length;       /* User defined header length in bytes */
273
  ASCII image_filename[100];       /* Image filename */
274
  ASCII creation_datetime[24];     /* Creation date/time: yyyy:mm:dd:hh:mm:ssLTZ */
275
  ASCII creator[100];              /* Creator */
276
  ASCII project_name[200];         /* Project name */
277
  ASCII copyright[200];            /* Right to use or copyright */
278
  U32   encryption_key;            /* Encryption key (FFFFFFFF unencrypted ) */
279
  ASCII reserved[104];             /* Reserved for future use */
280
} DPXFileInfo;
281
282
typedef struct _DPXImageElement
283
{
284
  U32   data_sign;                 /* Data sign (0 = unsigned; 1 = signed) */
285
  U32   reference_low_data_code;   /* Reference low data code value */
286
  R32   reference_low_quantity;    /* Low quantity represented */
287
  U32   reference_high_data_code;  /* Reference high data code value */
288
  R32   reference_high_quantity;   /* Reference high quantity represented */
289
  U8    descriptor;                /* Descriptor */
290
  U8    transfer_characteristic;   /* Transfer characteristic */
291
  U8    colorimetric;              /* Colorimetric specification */
292
  U8    bits_per_sample;           /* Bit depth */
293
  U16   packing;                   /* Packing */
294
  U16   encoding;                  /* Encoding */
295
  U32   data_offset;               /* Offset to data */
296
  U32   eol_pad;                   /* End of line padding */
297
  U32   eoi_pad;                   /* End of image padding */
298
  ASCII description[32];           /* Description of image element */
299
} DPXImageElement;
300
301
typedef struct _DPXImageInfo
302
{
303
  U16   orientation;               /* Image orientation */
304
  U16   elements;                  /* Number of image elements (1-8) */
305
  U32   pixels_per_line;           /* Pixels per line (columns) */
306
  U32   lines_per_image_element;   /* Lines per image element (rows) */
307
  DPXImageElement element_info[8]; /* Description of elements */
308
  ASCII reserved[52];              /* Reserved for future use */
309
} DPXImageInfo;
310
311
typedef struct _DPXImageSourceBorderValidity
312
{
313
  /*
314
    Border validity indicates portion of border pixels which have been
315
    eroded due to processing.
316
  */
317
  U16   XL;                        /* Border validity XL border */
318
  U16   XR;                        /* Border validity XR border */
319
  U16   YT;                        /* Border validity YT border */
320
  U16   YB;                        /* Border validity YB border */
321
} DPXImageSourceBorderValidity;
322
323
typedef struct _DPXImageSourcePixelAspectRatio
324
{
325
  U32   horizontal;                /* Horizontal */
326
  U32   vertical;                  /* Vertical */
327
} DPXImageSourcePixelAspectRatio;
328
329
typedef struct _DPXImageSourceInfo
330
{
331
  U32   x_offset;                  /* X offset */
332
  U32   y_offset;                  /* Y offset */
333
  R32   x_center;                  /* X center */
334
  R32   y_center;                  /* Y center */
335
  U32   x_original_size;           /* X original size */
336
  U32   y_original_size;           /* Y original size */
337
  ASCII source_image_filename[100];/* Source image filename */
338
  ASCII source_image_datetime[24]; /* Source image date/time: yyyy:mmm:dd:hh:mm:ssLTZ */
339
  ASCII input_device_name[32];     /* Input device name */
340
  ASCII input_device_serialnumber[32]; /* Input device serial number */
341
  DPXImageSourceBorderValidity border_validity; /* Border validity */
342
  DPXImageSourcePixelAspectRatio aspect_ratio; /* Aspect ratio */
343
  R32   x_scanned_size;            /* X scanned size */
344
  R32   y_scanned_size;            /* Y scanned size */
345
  ASCII reserved[20];              /* Reserved for future use */
346
} DPXImageSourceInfo;
347
348
typedef struct _DPXMPFilmInfo
349
{
350
  ASCII film_mfg_id_code[2];       /* Film mfg. ID code (2 digits from film edge code) */
351
  ASCII film_type[2];              /* Film type (2 digits from film edge code) */
352
  ASCII perfs_offset[2];           /* Offset in perfs (2 digits from film edge code) */
353
  ASCII prefix[6];                 /* Prefix (6 digits from film edge code) */
354
  ASCII count[4];                  /* Count (4 digits from film edge code) */
355
  ASCII format[32];                /* Format -- e.g. Academy */
356
  U32   frame_position;            /* Frame position in sequence */
357
  U32   sequence_length;           /* Sequence length (frames) */
358
  U32   held_count;                /* Held count (1 = default) */
359
  R32   frame_rate;                /* Frame rate of original (frames/s) */
360
  R32   shutter_angle;             /* Shutter angle of camera in degrees */
361
  ASCII frame_id[32];              /* Frame identification - e.g. keyframe */
362
  ASCII slate_info[100];           /* Slate information */
363
  ASCII reserved[56];              /* Reserved for future use */
364
} DPXMPFilmInfo;
365
366
typedef struct _DPXTVInfo
367
{
368
  U32   time_code;                 /* SMPTE time code */
369
  U32   user_bits;                 /* SMPTE user bits */
370
  U8    interlace;                 /* Interlace (0 = noninterlaced; 1 = 2:1 interlace */
371
  U8    field_number;              /* Field number */
372
  U8    video_signal;              /* Video signal standard */
373
  U8    zero;                      /* Zero (for byte alignment) */
374
  R32   horizontal_sample;         /* Horizontal sampling rate */
375
  R32   vertical_sample;           /* Vertical sampling rate */
376
  R32   temporal_sample;           /* Temporal sampling rate or frame rate (Hz) */
377
  R32   sync_time;                 /* Time offset from sync to first pixel (ms) */
378
  R32   gamma;                     /* Gamma (applied above breakpoint) */
379
  R32   black_level;               /* Black level code value */
380
  R32   black_gain;                /* Black gain (linear gain applied below breakpoint) */
381
  R32   breakpoint;                /* Breakpoint (point above which gamma is applied) */
382
  R32   white_level;               /* Reference white level code value */
383
  R32   integration_time;          /* Integration time (s) */
384
  ASCII reserved[76];              /* Reserved for future use */
385
} DPXTVInfo;
386
387
typedef struct _DPXUserDefinedData
388
{
389
  ASCII user_id[32];               /* User identification */
390
  /* Up to 1MB of user-defined data after this point */
391
} DPXUserDefinedData;
392
393
typedef struct _DPXHeader
394
{
395
  DPXFileInfo file_info;           /* File information header */
396
  DPXImageInfo image_info;         /* Image information header */
397
  DPXImageSourceInfo source_info; /* Image source information header */
398
  DPXMPFilmInfo mp_info;           /* Motion picture film information header */
399
  DPXTVInfo tv_info;               /* Television information header */
400
} DPXHeader;
401

402
/*
403
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
404
%                                                                             %
405
%                                                                             %
406
%                                                                             %
407
%   I s D P X                                                                 %
408
%                                                                             %
409
%                                                                             %
410
%                                                                             %
411
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
412
%
413
%  Method IsDPX returns True if the image format type, identified by the
414
%  magick string, is DPX.
415
%
416
%  The format of the IsDPX method is:
417
%
418
%      unsigned int IsDPX(const unsigned char *magick,const size_t length)
419
%
420
%  A description of each parameter follows:
421
%
422
%    o status:  Method IsDPX returns True if the image format type is DPX.
423
%
424
%    o magick: This string is generally the first few bytes of an image file
425
%      or blob.
426
%
427
%    o length: Specifies the length of the magick string.
428
%
429
%
430
*/
431
STATIC unsigned int IsDPX(const unsigned char *magick,const size_t length)
432
0
{
433
0
  return ((length >= 4) &&
434
0
          ((memcmp(magick,"SDPX",4) == 0) || (memcmp(magick,"XPDS",4) == 0)));
435
0
}
436

437
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
438
%                                                                             %
439
%                                                                             %
440
%                                                                             %
441
%   R e a d D P X I m a g e                                                   %
442
%                                                                             %
443
%                                                                             %
444
%                                                                             %
445
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
446
%
447
%  Method ReadDPXImage reads an DPX X image file and returns it.  It
448
%  allocates the memory necessary for the new Image structure and returns a
449
%  pointer to the new image.
450
%
451
%  The format of the ReadDPXImage method is:
452
%
453
%      Image *ReadDPXImage(const ImageInfo *image_info,ExceptionInfo *exception)
454
%
455
%  A description of each parameter follows:
456
%
457
%    o image:  Method ReadDPXImage returns a pointer to the image after
458
%      reading. A null image is returned if there is a memory shortage or if
459
%      the image cannot be read.
460
%
461
%    o image_info: Specifies a pointer to a ImageInfo structure.
462
%
463
%    o exception: return any errors or warnings in this structure.
464
%
465
%
466
*/
467
435k
#define LogSetImageAttribute(name,value) \
468
435k
{ \
469
435k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(), \
470
435k
                        "Attribute \"%s\" set to \"%s\"", \
471
435k
                        name,value); \
472
435k
}
473
/* Can't use strlcpy() since strlcpy() only handles NULL terminated
474
   strings.  Note that some fields occupy the full space with no
475
   trailing null so we null terminate one character *after* the
476
   DPX field size.
477
*/
478
323k
#define StringToAttribute(image,name,member) \
479
323k
{ \
480
323k
  char \
481
323k
    buffer_[MaxTextExtent]; \
482
323k
\
483
323k
  if (!IS_UNDEFINED_ASCII(member)) \
484
323k
    { \
485
122k
      (void) memcpy(buffer_,member,Min(sizeof(member),MaxTextExtent)); \
486
122k
      buffer_[Min(sizeof(member),MaxTextExtent-1)]='\0';             \
487
122k
      (void) SetImageAttribute(image,name,buffer_); \
488
122k
      LogSetImageAttribute(name,buffer_); \
489
122k
    } \
490
323k
}
491
25.7k
#define U8ToAttribute(image,name,member) \
492
25.7k
{ \
493
25.7k
  char \
494
25.7k
    buffer_[MaxTextExtent]; \
495
25.7k
\
496
25.7k
  if (!IS_UNDEFINED_U8(member)) \
497
25.7k
    { \
498
24.1k
      FormatString(buffer_,"%u",(unsigned int) member); \
499
24.1k
      (void) SetImageAttribute(image,name,buffer_); \
500
24.1k
      LogSetImageAttribute(name,buffer_); \
501
24.1k
    } \
502
25.7k
}
503
49.8k
#define U16ToAttribute(image,name,member) \
504
49.8k
{ \
505
49.8k
  char \
506
49.8k
    buffer_[MaxTextExtent]; \
507
49.8k
\
508
49.8k
  if (!IS_UNDEFINED_U16(member)) \
509
49.8k
    { \
510
46.5k
      FormatString(buffer_,"%u",(unsigned int) member); \
511
46.5k
      (void) SetImageAttribute(image,name,buffer_); \
512
46.5k
      LogSetImageAttribute(name,buffer_); \
513
46.5k
    } \
514
49.8k
}
515
106k
#define U32ToAttribute(image,name,member) \
516
106k
{ \
517
106k
  char \
518
106k
    buffer_[MaxTextExtent]; \
519
106k
\
520
106k
  if (!IS_UNDEFINED_U32(member)) \
521
106k
    { \
522
99.2k
      FormatString(buffer_,"%u",member); \
523
99.2k
      (void) SetImageAttribute(image,name,buffer_); \
524
99.2k
      LogSetImageAttribute(name,buffer_); \
525
99.2k
    } \
526
106k
}
527
17.1k
#define U32ToBitsAttribute(image,name,member) \
528
17.1k
{ \
529
17.1k
  char \
530
17.1k
    buffer_[MaxTextExtent]; \
531
17.1k
\
532
17.1k
  if (!IS_UNDEFINED_U32(member)) \
533
17.1k
    { \
534
16.3k
      SMPTEBitsToString(member,buffer_,sizeof(buffer_)); \
535
16.3k
      (void) SetImageAttribute(image,name,buffer_); \
536
16.3k
      LogSetImageAttribute(name,buffer_); \
537
16.3k
    } \
538
17.1k
}
539
134k
#define R32ToAttribute(image,name,member) \
540
134k
{ \
541
134k
  char \
542
134k
    buffer_[MaxTextExtent]; \
543
134k
\
544
134k
  if (!IS_UNDEFINED_R32(member)) \
545
134k
    { \
546
127k
      FormatString(buffer_,"%g",member.f); \
547
127k
      (void) SetImageAttribute(image,name,buffer_); \
548
127k
      LogSetImageAttribute(name,buffer_); \
549
127k
    } \
550
134k
}
551
STATIC void SwabDPXFileInfo(DPXFileInfo *file_info)
552
22.2k
{
553
22.2k
  MagickSwabUInt32(&file_info->magic);
554
22.2k
  MagickSwabUInt32(&file_info->image_data_offset);
555
22.2k
  MagickSwabUInt32(&file_info->file_size);
556
22.2k
  MagickSwabUInt32(&file_info->ditto_key);
557
22.2k
  MagickSwabUInt32(&file_info->generic_section_length);
558
22.2k
  MagickSwabUInt32(&file_info->industry_section_length);
559
22.2k
  MagickSwabUInt32(&file_info->user_defined_length);
560
22.2k
  MagickSwabUInt32(&file_info->encryption_key);
561
22.2k
}
562
STATIC void SwabDPXImageInfo(DPXImageInfo *image_info)
563
17.4k
{
564
17.4k
  int
565
17.4k
    i;
566
567
17.4k
  MagickSwabUInt16(&image_info->orientation);
568
17.4k
  MagickSwabUInt16(&image_info->elements);
569
17.4k
  MagickSwabUInt32(&image_info->pixels_per_line);
570
17.4k
  MagickSwabUInt32(&image_info->lines_per_image_element);
571
157k
  for (i=0 ; i < 8 ; i++)
572
139k
    {
573
139k
      MagickSwabUInt32(&image_info->element_info[i].data_sign);
574
139k
      MagickSwabUInt32(&image_info->element_info[i].reference_low_data_code);
575
139k
      MagickSwabFloat(&image_info->element_info[i].reference_low_quantity.f);
576
139k
      MagickSwabUInt32(&image_info->element_info[i].reference_high_data_code);
577
139k
      MagickSwabFloat(&image_info->element_info[i].reference_high_quantity.f);
578
139k
      MagickSwabUInt16(&image_info->element_info[i].packing);
579
139k
      MagickSwabUInt16(&image_info->element_info[i].encoding);
580
139k
      MagickSwabUInt32(&image_info->element_info[i].data_offset);
581
139k
      MagickSwabUInt32(&image_info->element_info[i].eol_pad);
582
139k
      MagickSwabUInt32(&image_info->element_info[i].eoi_pad);
583
139k
    }
584
17.4k
}
585
STATIC void SwabDPXImageSourceInfo(DPXImageSourceInfo *source_info)
586
11.7k
{
587
11.7k
  MagickSwabUInt32(&source_info->x_offset);
588
11.7k
  MagickSwabUInt32(&source_info->y_offset);
589
11.7k
  MagickSwabFloat(&source_info->x_center.f);
590
11.7k
  MagickSwabFloat(&source_info->y_center.f);
591
11.7k
  MagickSwabUInt32(&source_info->x_original_size);
592
11.7k
  MagickSwabUInt32(&source_info->y_original_size);
593
11.7k
  MagickSwabUInt16(&source_info->border_validity.XL);
594
11.7k
  MagickSwabUInt16(&source_info->border_validity.XR);
595
11.7k
  MagickSwabUInt16(&source_info->border_validity.YT);
596
11.7k
  MagickSwabUInt16(&source_info->border_validity.YB);
597
11.7k
  MagickSwabUInt32(&source_info->aspect_ratio.horizontal);
598
11.7k
  MagickSwabUInt32(&source_info->aspect_ratio.vertical);
599
11.7k
  MagickSwabFloat(&source_info->x_scanned_size.f);
600
11.7k
  MagickSwabFloat(&source_info->y_scanned_size.f);
601
11.7k
}
602
STATIC void SwabDPXMPFilmInfo(DPXMPFilmInfo *mp_info)
603
11.5k
{
604
11.5k
  MagickSwabUInt32(&mp_info->frame_position);
605
11.5k
  MagickSwabUInt32(&mp_info->sequence_length);
606
11.5k
  MagickSwabUInt32(&mp_info->held_count);
607
11.5k
  MagickSwabFloat(&mp_info->frame_rate.f);
608
11.5k
  MagickSwabFloat(&mp_info->shutter_angle.f);
609
11.5k
}
610
STATIC void SwabDPXTVInfo(DPXTVInfo *tv_info)
611
10.7k
{
612
10.7k
  MagickSwabUInt32(&tv_info->time_code);
613
10.7k
  MagickSwabUInt32(&tv_info->user_bits);
614
10.7k
  MagickSwabFloat(&tv_info->horizontal_sample.f);
615
10.7k
  MagickSwabFloat(&tv_info->vertical_sample.f);
616
10.7k
  MagickSwabFloat(&tv_info->temporal_sample.f);
617
10.7k
  MagickSwabFloat(&tv_info->sync_time.f);
618
10.7k
  MagickSwabFloat(&tv_info->gamma.f);
619
10.7k
  MagickSwabFloat(&tv_info->black_level.f);
620
10.7k
  MagickSwabFloat(&tv_info->black_gain.f);
621
10.7k
  MagickSwabFloat(&tv_info->breakpoint.f);
622
10.7k
  MagickSwabFloat(&tv_info->white_level.f);
623
10.7k
  MagickSwabFloat(&tv_info->integration_time.f);
624
10.7k
}
625
STATIC void SMPTEBitsToString(const U32 value, char *str, size_t str_length)
626
16.3k
{
627
16.3k
  unsigned int
628
16.3k
    pos,
629
16.3k
    shift = 28;
630
631
147k
  for (pos=8; pos != 0; pos--, shift -= 4)
632
130k
    {
633
130k
      (void) snprintf(str,3,"%01u",(unsigned int) ((value >> shift) & 0x0fU));
634
130k
      str += 1;
635
130k
      if ((pos > 2) && (pos % 2))
636
49.0k
        {
637
49.0k
          (void) strlcat(str,":",str_length);
638
49.0k
          str++;
639
49.0k
        }
640
130k
    }
641
16.3k
  *str='\0';
642
16.3k
}
643
STATIC U32 SMPTEStringToBits(const char *str)
644
237
{
645
237
  U32
646
237
    value=0;
647
648
237
  unsigned int
649
237
    pos = 0,
650
237
    shift = 28;
651
652
237
  char
653
237
    buff[2];
654
655
237
  buff[1]='\0';
656
657
2.65k
  while ((*str != 0) && (pos < 8))
658
2.41k
    {
659
2.41k
      if (!isdigit((int) *str))
660
517
        {
661
517
          str++;
662
517
          continue;
663
517
        }
664
1.89k
      buff[0]=*str++;
665
1.89k
      value |= (U32) ((strtol(buff,(char **)NULL,10)) << shift);
666
1.89k
      shift -= 4;
667
1.89k
      pos++;
668
1.89k
    }
669
237
  return value;
670
237
}
671
/*
672
  Compute the number of octets required to contain the specified number of
673
  rows, with specified samples per row, bits per sample, and packing method.
674
*/
675
STATIC size_t DPXRowOctets(const unsigned long rows,
676
                           const unsigned int samples_per_row,
677
                           const unsigned int bits_per_sample,
678
                           const ImageComponentPackingMethod packing_method)
679
8.85k
{
680
8.85k
  size_t
681
8.85k
    octets = 0;
682
683
8.85k
  switch(bits_per_sample)
684
8.85k
    {
685
3.71k
    case 1:
686
      /* Packed 1-bit samples in 32-bit words. Rows are padded out to 32-bit alignment */
687
3.71k
      octets=rows*(((magick_int64_t) samples_per_row*bits_per_sample+31)/32)*sizeof(U32);
688
3.71k
      break;
689
397
    case 8:
690
      /* C.1 8-bit samples in a 32-bit word. Rows are padded out to 32-bit alignment */
691
397
      octets=rows*(((magick_int64_t) samples_per_row*bits_per_sample+31)/32)*sizeof(U32);
692
397
      break;
693
0
    case 32:
694
      /* 32-bit samples in a 32-bit word */
695
0
      octets=samples_per_row*sizeof(U32)*rows;
696
0
      break;
697
1.91k
    case 10:
698
1.91k
      if ((packing_method == PackingMethodWordsFillLSB) ||
699
879
          (packing_method == PackingMethodWordsFillMSB))
700
1.70k
        {
701
          /* C.3 Three 10-bit samples per 32-bit word */
702
1.70k
          octets=((((((magick_int64_t) rows*samples_per_row+2)/3)* (magick_int64_t)sizeof(U32)*8)+31)/32)*sizeof(U32);
703
1.70k
        }
704
216
      else
705
216
        {
706
          /* C.2 Packed 10-bit samples in a 32-bit word. */
707
216
          octets=rows*(((magick_int64_t) samples_per_row*bits_per_sample+31)/32)*sizeof(U32);
708
216
        }
709
1.91k
      break;
710
1.86k
    case 12:
711
1.86k
      if ((packing_method == PackingMethodWordsFillLSB) ||
712
819
          (packing_method == PackingMethodWordsFillMSB))
713
1.71k
        {
714
          /* C.5: One 12-bit sample per 16-bit word */
715
1.71k
          octets=((((magick_int64_t) rows*samples_per_row*sizeof(U16)*8)+15)/16)*sizeof(U16);
716
1.71k
        }
717
150
      else
718
150
        {
719
          /* C.4: Packed 12-bit samples in a 32-bit word. */
720
150
          octets=rows*(((magick_int64_t) samples_per_row*bits_per_sample+31)/32)*sizeof(U32);
721
150
        }
722
1.86k
      break;
723
960
    case 16:
724
      /* C.6 16-bit samples in 16-bit words. */
725
960
      octets=((((magick_int64_t) rows*samples_per_row*bits_per_sample)+15)/16)*sizeof(U16);
726
960
      break;
727
0
    case 64:
728
      /* 64-bit samples in 64-bit words. */
729
0
      octets=(magick_int64_t) rows*samples_per_row*8;
730
0
      break;
731
8.85k
    }
732
733
8.85k
  return octets;
734
8.85k
}
735
/*
736
  Compute optimum I/O parameters based on all considerations.
737
*/
738
#if 0
739
STATIC size_t DPXIOOctets(const long current_row, /* 0 based */
740
                          const unsigned long image_rows,
741
                          const unsigned int samples_per_row,
742
                          const unsigned int bits_per_sample,
743
                          const ImageComponentPackingMethod packing_method)
744
{
745
  long
746
    rows_remaining;
747
748
  rows_remaining=image_rows-current_row;
749
750
751
752
}
753
#endif
754
STATIC const char *DescribeImageElementDescriptor(char *buffer, const DPXImageElementDescriptor descriptor)
755
13.9k
{
756
13.9k
  const char *
757
13.9k
    description="Unknown";
758
759
13.9k
  switch(descriptor)
760
13.9k
    {
761
3.77k
    case ImageElementUnspecified:
762
3.77k
      description="Generic 1 Element";
763
3.77k
      break;
764
281
    case ImageElementRed:
765
281
      description="Red";
766
281
      break;
767
725
    case ImageElementGreen:
768
725
      description="Green";
769
725
      break;
770
923
    case ImageElementBlue:
771
923
      description="Blue";
772
923
      break;
773
938
    case ImageElementAlpha:
774
938
      description="Alpha";
775
938
      break;
776
1.69k
    case ImageElementLuma:
777
1.69k
      description="Luma";
778
1.69k
      break;
779
271
    case ImageElementColorDifferenceCbCr:
780
271
      description="CbCr";
781
271
      break;
782
132
    case ImageElementDepth:
783
132
      description="Depth(8)";
784
132
      break;
785
57
    case ImageElementCompositeVideo:
786
57
      description="CompositeVideo";
787
57
      break;
788
497
    case ImageElementRGB:
789
497
      description="RGB";
790
497
      break;
791
539
    case ImageElementRGBA:
792
539
      description="RGBA";
793
539
      break;
794
309
    case ImageElementABGR:
795
309
      description="ABGR";
796
309
      break;
797
321
    case ImageElementCbYCrY422:
798
321
      description="CbYCrY 4:2:2";
799
321
      break;
800
134
    case ImageElementCbYACrYA4224:
801
134
      description="CbYACrYA 4:2:2:4";
802
134
      break;
803
551
    case ImageElementCbYCr444:
804
551
      description="CbYCr 4:4:4";
805
551
      break;
806
202
    case ImageElementCbYCrA4444:
807
202
      description="CbYCrA 4:4:4:4";
808
202
      break;
809
11
    case ImageElementUserDef2Element:
810
11
      description="Generic 2 Element";
811
11
      break;
812
12
    case ImageElementUserDef3Element:
813
12
      description="Generic 3 Element";
814
12
      break;
815
7
    case ImageElementUserDef4Element:
816
7
      description="Generic 4 Element";
817
7
      break;
818
53
    case ImageElementUserDef5Element:
819
53
      description="Generic 5 Element";
820
53
      break;
821
10
    case ImageElementUserDef6Element:
822
10
      description="Generic 6 Element";
823
10
      break;
824
20
    case ImageElementUserDef7Element:
825
20
      description="Generic 7 Element";
826
20
      break;
827
17
    case ImageElementUserDef8Element:
828
17
      description="Generic 8 Element";
829
17
      break;
830
2.46k
    default:
831
2.46k
      {
832
2.46k
        FormatString(buffer,"Unknown (%u)",(unsigned int) descriptor);
833
2.46k
        description=buffer;
834
2.46k
      }
835
13.9k
    }
836
837
13.9k
  return description;
838
13.9k
}
839
/*
840
  Describe the element transfer characteristic.
841
*/
842
STATIC const char *DescribeImageTransferCharacteristic(char *buffer, const DPXTransferCharacteristic characteristic)
843
13.7k
{
844
13.7k
  const char
845
13.7k
    *description=buffer;
846
847
13.7k
  buffer[0]='\0';
848
13.7k
  switch(characteristic)
849
13.7k
    {
850
5.52k
    case TransferCharacteristicUserDefined:
851
5.52k
      description="UserDefined";
852
5.52k
      break;
853
441
    case TransferCharacteristicPrintingDensity:
854
441
      description="PrintingDensity";
855
441
      break;
856
628
    case TransferCharacteristicLinear:
857
628
      description="Linear";
858
628
      break;
859
74
    case TransferCharacteristicLogarithmic:
860
74
      description="Logarithmic";
861
74
      break;
862
551
    case TransferCharacteristicUnspecifiedVideo:
863
551
      description="UnspecifiedVideo";
864
551
      break;
865
662
    case TransferCharacteristicSMTPE274M:
866
662
      description="SMTPE274M";
867
662
      break;
868
573
    case TransferCharacteristicITU_R709:
869
573
      description="ITU-R709";
870
573
      break;
871
792
    case TransferCharacteristicITU_R601_625L:
872
792
      description="ITU-R601-625L";
873
792
      break;
874
340
    case TransferCharacteristicITU_R601_525L:
875
340
      description="ITU-R601-525L";
876
340
      break;
877
9
    case TransferCharacteristicNTSCCompositeVideo:
878
9
      description="NTSCCompositeVideo";
879
9
      break;
880
29
    case TransferCharacteristicPALCompositeVideo:
881
29
      description="PALCompositeVideo";
882
29
      break;
883
114
    case TransferCharacteristicZDepthLinear:
884
114
      description="ZDepthLinear";
885
114
      break;
886
30
    case TransferCharacteristicZDepthHomogeneous:
887
30
      description="ZDepthHomogeneous";
888
30
      break;
889
3.93k
    default:
890
3.93k
      {
891
3.93k
        FormatString(buffer,"Reserved(%u)",(unsigned int) characteristic);
892
3.93k
      }
893
13.7k
    }
894
895
13.7k
  return description;
896
13.7k
}
897
/*
898
  Describe the element colorimetric.
899
*/
900
STATIC const char *DescribeImageColorimetric(char *buffer, const DPXColorimetric colorimetric)
901
12.5k
{
902
12.5k
  const char
903
12.5k
    *description=buffer;
904
905
12.5k
  buffer[0]='\0';
906
12.5k
  switch(colorimetric)
907
12.5k
    {
908
5.59k
    case ColorimetricUserDefined:
909
5.59k
      description="UserDefined";
910
5.59k
      break;
911
1.14k
    case ColorimetricPrintingDensity:
912
1.14k
      description="PrintingDensity";
913
1.14k
      break;
914
82
    case ColorimetricLinear:
915
82
      description="NotApplicable";
916
82
      break;
917
76
    case ColorimetricLogarithmic:
918
76
      description="NotApplicable";
919
76
      break;
920
43
    case ColorimetricUnspecifiedVideo:
921
43
      description="UnspecifiedVideo";
922
43
      break;
923
651
    case ColorimetricSMTPE274M:
924
651
      description="SMTPE274M";
925
651
      break;
926
33
    case ColorimetricITU_R709:
927
33
      description="ITU-R709";
928
33
      break;
929
17
    case ColorimetricITU_R601_625L:
930
17
      description="ITU-R601-625L";
931
17
      break;
932
60
    case ColorimetricITU_R601_525L:
933
60
      description="ITU-R601-525L";
934
60
      break;
935
13
    case ColorimetricNTSCCompositeVideo:
936
13
      description="NTSCCompositeVideo";
937
13
      break;
938
25
    case ColorimetricPALCompositeVideo:
939
25
      description="PALCompositeVideo";
940
25
      break;
941
28
    case ColorimetricZDepthLinear:
942
28
      description="NotApplicable";
943
28
      break;
944
36
    case ColorimetricZDepthHomogeneous:
945
36
      description="NotApplicable";
946
36
      break;
947
4.72k
    default:
948
4.72k
      {
949
4.72k
        FormatString(buffer,"Reserved(%u)",(unsigned int) colorimetric);
950
4.72k
      }
951
12.5k
    }
952
953
12.5k
  return description;
954
12.5k
}
955
/*
956
  Describe the image element.
957
*/
958
STATIC void DescribeDPXImageElement(const DPXImageElement *element_info,
959
                                    const unsigned int element)
960
12.5k
{
961
12.5k
  char txt_buffer[MaxTextExtent];
962
963
12.5k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
964
12.5k
                        "Element %u: data_sign=%s",element,
965
12.5k
                        element_info->data_sign == 0 ?
966
6.45k
                        "unsigned(0)" : "signed(1)");
967
12.5k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
968
12.5k
                        "Element %u: reference_low_data_code=%u reference_low_quantity=%g",
969
12.5k
                        element,
970
12.5k
                        element_info->reference_low_data_code,
971
12.5k
                        element_info->reference_low_quantity.f);
972
12.5k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
973
12.5k
                        "Element %u: reference_high_data_code=%u reference_high_quantity=%g",
974
12.5k
                        element,
975
12.5k
                        element_info->reference_high_data_code,
976
12.5k
                        element_info->reference_high_quantity.f);
977
12.5k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
978
12.5k
                        "Element %u: descriptor=%s(%u) transfer_characteristic=%s(%u) colorimetric=%s(%u)",
979
12.5k
                        element,
980
12.5k
                        DescribeImageElementDescriptor(txt_buffer,(DPXImageElementDescriptor) element_info->descriptor),
981
12.5k
                        (unsigned int) element_info->descriptor,
982
12.5k
                        DescribeImageTransferCharacteristic(txt_buffer,(DPXTransferCharacteristic) element_info->transfer_characteristic),
983
12.5k
                        (unsigned int) element_info->transfer_characteristic,
984
12.5k
                        DescribeImageColorimetric(txt_buffer,(DPXColorimetric) element_info->colorimetric),
985
12.5k
                        (unsigned int) element_info->colorimetric);
986
12.5k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
987
12.5k
                        "Element %u: bits-per-sample=%u",
988
12.5k
                        element,
989
12.5k
                        (unsigned int) element_info->bits_per_sample);
990
12.5k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
991
12.5k
                        "Element %u: packing=%s encoding=%s data_offset=%u eol_pad=%u eoi_pad=%u",
992
12.5k
                        element,
993
12.5k
                        (element_info->packing == PackingMethodPacked ? "Packed(0)" :
994
12.5k
                         element_info->packing == PackingMethodWordsFillLSB ? "PadLSB(1)" :
995
7.23k
                         element_info->packing == PackingMethodWordsFillMSB ? "PadMSB(2)" :
996
6.58k
                         "Unknown"),
997
12.5k
                        (element_info->encoding == 0 ? "None(0)" :
998
12.5k
                         element_info->encoding == 1 ? "RLE(1)" :
999
7.84k
                         "Unknown"),
1000
12.5k
                        (unsigned int) element_info->data_offset,
1001
12.5k
                        (unsigned int) element_info->eol_pad,
1002
12.5k
                        (unsigned int) element_info->eoi_pad);
1003
12.5k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1004
12.5k
                        "Element %u: description=\"%.32s\"",
1005
12.5k
                        element,
1006
12.5k
                        element_info->description);
1007
12.5k
}
1008
/*
1009
  Obtain number of element samples required to support one pixel.  For
1010
  example, RGB requires three samples, but if the image organization
1011
  is planar three elements are required to support RGB, and this
1012
  function will therefore return 1 rather than 3.
1013
*/
1014
STATIC unsigned int  DPXSamplesPerPixel(const DPXImageElementDescriptor element_descriptor)
1015
14.7k
{
1016
14.7k
  unsigned int
1017
14.7k
    samples_per_pixel=0;
1018
1019
14.7k
  switch (element_descriptor)
1020
14.7k
    {
1021
94
    case ImageElementUnspecified:
1022
729
    case ImageElementRed:
1023
1.40k
    case ImageElementGreen:
1024
1.83k
    case ImageElementBlue:
1025
3.04k
    case ImageElementAlpha:
1026
8.52k
    case ImageElementLuma:
1027
8.52k
      samples_per_pixel=1;
1028
8.52k
      break;
1029
477
    case ImageElementColorDifferenceCbCr: /* Cb | Cr 4:2:2 sampling ..., even number of columns required.*/
1030
477
      samples_per_pixel=2;
1031
477
      break;
1032
1.29k
    case ImageElementRGB:
1033
1.29k
      samples_per_pixel=3;
1034
1.29k
      break;
1035
875
    case ImageElementRGBA:
1036
1.35k
    case ImageElementABGR:
1037
1.35k
      samples_per_pixel=4;
1038
1.35k
      break;
1039
994
    case ImageElementCbYCrY422:
1040
      /* CbY | CrY | CbY | CrY ..., even number of columns required. */
1041
994
      samples_per_pixel=2;
1042
994
      break;
1043
392
    case ImageElementCbYACrYA4224:
1044
      /* CbYA | CrYA | CbYA | CrYA ..., even number of columns required. */
1045
392
      samples_per_pixel=3;
1046
392
      break;
1047
958
    case ImageElementCbYCr444:
1048
958
      samples_per_pixel=3;
1049
958
      break;
1050
601
    case ImageElementCbYCrA4444:
1051
601
      samples_per_pixel=4;
1052
601
      break;
1053
193
    default:
1054
193
      samples_per_pixel=0;
1055
193
      break;
1056
14.7k
    }
1057
1058
14.7k
  return samples_per_pixel;
1059
14.7k
}
1060
/*
1061
  Set the image primary chromaticities based on the colorimetric.
1062
*/
1063
STATIC void DPXSetPrimaryChromaticities(const DPXColorimetric colorimetric,
1064
                                        ChromaticityInfo *chromaticity_info)
1065
9.34k
{
1066
9.34k
  switch(colorimetric)
1067
9.34k
    {
1068
640
    case ColorimetricSMTPE274M:
1069
651
    case ColorimetricITU_R709:/* ITU R709 */
1070
      /* ITU-R BT.709-5, D65 */
1071
651
      chromaticity_info->red_primary.x=0.640;
1072
651
      chromaticity_info->red_primary.y=0.330;
1073
651
      chromaticity_info->red_primary.z=0.030;
1074
651
      chromaticity_info->green_primary.x=0.300;
1075
651
      chromaticity_info->green_primary.y=0.600;
1076
651
      chromaticity_info->green_primary.z=0.100;
1077
651
      chromaticity_info->blue_primary.x=0.150;
1078
651
      chromaticity_info->blue_primary.y=0.060;
1079
651
      chromaticity_info->blue_primary.z=0.790;
1080
651
      chromaticity_info->white_point.x=0.3127;
1081
651
      chromaticity_info->white_point.y=0.3290;
1082
651
      chromaticity_info->white_point.z=0.3582;
1083
651
      break;
1084
1085
7
    case ColorimetricNTSCCompositeVideo:
1086
      /* Obsolete NTSC primaries, White CIE III. C */
1087
7
      chromaticity_info->red_primary.x=0.67;
1088
7
      chromaticity_info->red_primary.y=0.33;
1089
7
      chromaticity_info->red_primary.z=0.00;
1090
7
      chromaticity_info->green_primary.x=0.21;
1091
7
      chromaticity_info->green_primary.y=0.71;
1092
7
      chromaticity_info->green_primary.z=0.08;
1093
7
      chromaticity_info->blue_primary.x=0.14;
1094
7
      chromaticity_info->blue_primary.y=0.08;
1095
7
      chromaticity_info->blue_primary.z=0.78;
1096
7
      chromaticity_info->white_point.x=0.310;
1097
7
      chromaticity_info->white_point.y=0.316;
1098
7
      chromaticity_info->white_point.z=0.374;
1099
7
      break;
1100
1101
5
    case ColorimetricPALCompositeVideo:
1102
      /* EBU Tech. 3213 primaries, D65 */
1103
5
      chromaticity_info->red_primary.x=0.640;
1104
5
      chromaticity_info->red_primary.y=0.330;
1105
5
      chromaticity_info->red_primary.z=0.030;
1106
5
      chromaticity_info->green_primary.x=0.290;
1107
5
      chromaticity_info->green_primary.y=0.600;
1108
5
      chromaticity_info->green_primary.z=0.110;
1109
5
      chromaticity_info->blue_primary.x=0.150;
1110
5
      chromaticity_info->blue_primary.y=0.060;
1111
5
      chromaticity_info->blue_primary.z=0.790;
1112
5
      chromaticity_info->white_point.x=0.3127;
1113
5
      chromaticity_info->white_point.y=0.3290;
1114
5
      chromaticity_info->white_point.z=0.3582;
1115
5
      break;
1116
1117
#if 0
1118
      /* SMPTE RP 145 / SMPTE 240M primaries (as used for 480i SDTV), D65 */
1119
      chromaticity_info->red_primary.x=0.630;
1120
      chromaticity_info->red_primary.y=0.340;
1121
      chromaticity_info->red_primary.z=0.030;
1122
      chromaticity_info->green_primary.x=0.310;
1123
      chromaticity_info->green_primary.y=0.595;
1124
      chromaticity_info->green_primary.z=0.095;
1125
      chromaticity_info->blue_primary.x=0.155;
1126
      chromaticity_info->blue_primary.y=0.070;
1127
      chromaticity_info->blue_primary.z=0.775;
1128
      chromaticity_info->white_point.x=0.3127;
1129
      chromaticity_info->white_point.y=0.3290;
1130
      chromaticity_info->white_point.z=0.3582;
1131
#endif
1132
1133
1134
3
    case ColorimetricITU_R601_625L: /* 625 Line ITU R601-5 B & G */
1135
35
    case ColorimetricITU_R601_525L: /* 525 Line ITU R601-5 M */
1136
1137
4.15k
    case ColorimetricUserDefined: /* User defined */
1138
5.10k
    case ColorimetricPrintingDensity: /* Printing density */
1139
5.17k
    case ColorimetricLinear: /* Linear */
1140
5.20k
    case ColorimetricLogarithmic: /* Logarithmic */
1141
5.21k
    case ColorimetricUnspecifiedVideo:
1142
8.67k
    default:
1143
8.67k
      {
1144
8.67k
        break;
1145
5.21k
      }
1146
9.34k
    }
1147
9.34k
}
1148
1149
STATIC OrientationType
1150
DPXOrientationToOrientationType(const unsigned int orientation)
1151
11.0k
{
1152
11.0k
  OrientationType
1153
11.0k
    orientation_type = UndefinedOrientation;
1154
1155
11.0k
  switch (orientation)
1156
11.0k
    {
1157
8.94k
    case 0U:
1158
8.94k
      orientation_type=TopLeftOrientation;
1159
8.94k
      break;
1160
499
    case 1U:
1161
499
      orientation_type=TopRightOrientation;
1162
499
      break;
1163
26
    case 2U:
1164
26
      orientation_type=BottomLeftOrientation;
1165
26
      break;
1166
9
    case 3U:
1167
9
      orientation_type=BottomRightOrientation;
1168
9
      break;
1169
1.49k
    case 4U:
1170
1.49k
      orientation_type=LeftTopOrientation;
1171
1.49k
      break;
1172
46
    case 5U:
1173
46
      orientation_type=RightTopOrientation;
1174
46
      break;
1175
45
    case 6U:
1176
45
      orientation_type=LeftBottomOrientation;
1177
45
      break;
1178
18
    case 7U:
1179
18
      orientation_type=RightBottomOrientation;
1180
18
      break;
1181
11.0k
    }
1182
1183
11.0k
  return orientation_type;
1184
11.0k
}
1185
1186
987
#define LSBOctetsToPackedU32Word(scanline,packed_u32) \
1187
987
do { \
1188
987
  packed_u32  = (((magick_uint32_t) *scanline++)); \
1189
987
  packed_u32 |= (((magick_uint32_t) *scanline++) << 8); \
1190
987
  packed_u32 |= (((magick_uint32_t) *scanline++) << 16); \
1191
987
  packed_u32 |= (((magick_uint32_t) *scanline++) << 24); \
1192
987
 } while(0)
1193
130k
#define MSBOctetsToPackedU32Word(scanline,packed_u32) \
1194
130k
do { \
1195
130k
  packed_u32  = (((magick_uint32_t) *scanline++) << 24); \
1196
130k
  packed_u32 |= (((magick_uint32_t) *scanline++) << 16); \
1197
130k
  packed_u32 |= (((magick_uint32_t) *scanline++) << 8); \
1198
130k
  packed_u32 |= (((magick_uint32_t) *scanline++)); \
1199
130k
 } while(0)
1200
1201
/*
1202
  Scale from a video level to a full-range level.
1203
*/
1204
STATIC inline Quantum ScaleFromVideo(const double sample,
1205
                                     const double ref_low,
1206
                                     const double upscale)
1207
16.0M
{
1208
16.0M
  double
1209
16.0M
    result = 0.0;
1210
1211
16.0M
  if (sample > ref_low)
1212
10.2M
    result = (sample - ref_low)*upscale;
1213
16.0M
  return RoundDoubleToQuantum(result);
1214
1215
16.0M
}
1216
1217
/*
1218
  WordStreamLSBRead support
1219
*/
1220
typedef struct _ReadWordU32State
1221
{
1222
  const unsigned char *words;
1223
} ReadWordU32State;
1224
1225
STATIC unsigned long ReadWordU32BE (void *state)
1226
3.12M
{
1227
3.12M
  magick_uint32_t value;
1228
3.12M
  ReadWordU32State *read_state=(ReadWordU32State *) state;
1229
3.12M
  value =  ((magick_uint32_t) *read_state->words++) << 24;
1230
3.12M
  value |= ((magick_uint32_t) *read_state->words++) << 16;
1231
3.12M
  value |= ((magick_uint32_t) *read_state->words++) << 8;
1232
3.12M
  value |= ((magick_uint32_t) *read_state->words++);
1233
3.12M
  return value;
1234
3.12M
}
1235
1236
STATIC unsigned long ReadWordU32LE (void *state)
1237
204
{
1238
204
  magick_uint32_t value;
1239
204
  ReadWordU32State *read_state=(ReadWordU32State *) state;
1240
204
  value = ((magick_uint32_t) *read_state->words++);
1241
204
  value |= ((magick_uint32_t) *read_state->words++) << 8;
1242
204
  value |= ((magick_uint32_t) *read_state->words++) << 16;
1243
204
  value |= ((magick_uint32_t) *read_state->words++) << 24;
1244
204
  return value;
1245
204
}
1246
1247
/*
1248
  Decode row samples. Currently just one row but in the future may be
1249
                      multiple rows (e.g. 3).
1250
1251
  scanline         -- Raw input data (may be 8-bit, 16-bit, 32-bit, or 64-bit types)
1252
                      which represents the encoded pixels for one or more scanlines.
1253
                      Underlying input data type is properly aligned for access.
1254
  samples_per_row  -- Number of samples to decode.
1255
  bits_per_sample  -- Number of bits in one decoded sample.
1256
  packing_method   -- Describes the way that samples are packed into enclosing words.
1257
  endian_type      -- The endian order of the enclosing words.
1258
  swap_word_datums -- Use alternate sample order (BGR vs RGB, CbYCr vs CrYCb) for
1259
                      samples filled into 32 bit words.
1260
  samples          -- Decoded samples (currently unsigned 16-bit).
1261
*/
1262
STATIC void ReadRowSamples(const unsigned char *scanline,
1263
                           const unsigned int samples_per_row,
1264
                           const unsigned int bits_per_sample,
1265
                           const ImageComponentPackingMethod packing_method,
1266
                           const EndianType endian_type,
1267
                           const MagickBool swap_word_datums,
1268
                           sample_t *samples)
1269
208k
{
1270
208k
  register unsigned long
1271
208k
    i;
1272
1273
208k
  sample_t
1274
208k
    *sp;
1275
1276
208k
  register unsigned int
1277
208k
    sample;
1278
1279
208k
  sp=samples;
1280
208k
  if ((packing_method != PackingMethodPacked) &&
1281
125k
      ((bits_per_sample == 10) || (bits_per_sample == 12)))
1282
109k
    {
1283
109k
      MagickBool
1284
109k
        word_pad_lsb=MagickFalse,
1285
109k
        word_pad_msb=MagickFalse;
1286
1287
109k
      if (packing_method == PackingMethodWordsFillLSB)
1288
76.6k
        word_pad_lsb=MagickTrue;
1289
32.6k
      else if (packing_method == PackingMethodWordsFillMSB)
1290
32.6k
        word_pad_msb=MagickTrue;
1291
1292
109k
      if (bits_per_sample == 10)
1293
100k
        {
1294
100k
          register magick_uint32_t
1295
100k
            packed_u32 = 0;
1296
1297
100k
          register unsigned int
1298
100k
            datum;
1299
1300
100k
          unsigned int
1301
100k
            shifts[3] = { 0, 0, 0 };
1302
1303
100k
          if (word_pad_lsb)
1304
73.2k
            {
1305
              /*
1306
                Padding in LSB (Method A)  Standard method.
1307
              */
1308
73.2k
              if (swap_word_datums == MagickFalse)
1309
72.8k
                {
1310
72.8k
                  shifts[0]=2;  /* datum-0 / blue */
1311
72.8k
                  shifts[1]=12; /* datum-1 / green */
1312
72.8k
                  shifts[2]=22; /* datum-2 / red */
1313
72.8k
                }
1314
396
              else
1315
396
                {
1316
396
                  shifts[0]=22; /* datum-2 / red */
1317
396
                  shifts[1]=12; /* datum-1 / green */
1318
396
                  shifts[2]=2;  /* datum-0 / blue */
1319
396
                }
1320
73.2k
            }
1321
26.7k
          else if (word_pad_msb)
1322
26.7k
            {
1323
              /*
1324
                Padding in MSB (Method B)  Deprecated method.
1325
              */
1326
26.7k
              if (swap_word_datums == MagickFalse)
1327
26.4k
                {
1328
26.4k
                  shifts[0]=0;  /* datum-0 / blue */
1329
26.4k
                  shifts[1]=10; /* datum-1 / green */
1330
26.4k
                  shifts[2]=20; /* datum-2 / red */
1331
26.4k
                }
1332
237
              else
1333
237
                {
1334
237
                  shifts[0]=20; /* datum-2 / red */
1335
237
                  shifts[1]=10; /* datum-1 / green */
1336
237
                  shifts[2]=0;  /* datum-0 / blue */
1337
237
                }
1338
26.7k
            }
1339
1340
100k
          if (endian_type == MSBEndian)
1341
99.6k
            {
1342
293k
              for (i=0; i < samples_per_row; i++)
1343
194k
                {
1344
194k
                  datum = i % 3;
1345
194k
                  if (datum == 0)
1346
130k
                    MSBOctetsToPackedU32Word(scanline,packed_u32);
1347
194k
                  *sp++=(packed_u32 >> shifts[datum]) & 0x3FF;
1348
194k
                }
1349
99.6k
            }
1350
317
          else if (endian_type == LSBEndian)
1351
317
            {
1352
2.74k
              for (i=0; i < samples_per_row; i++)
1353
2.43k
                {
1354
2.43k
                  datum = i % 3;
1355
2.43k
                  if (datum == 0)
1356
987
                    LSBOctetsToPackedU32Word(scanline,packed_u32);
1357
2.43k
                  *sp++=(packed_u32 >> shifts[datum]) & 0x3FF;
1358
2.43k
                }
1359
317
            }
1360
100k
          return;
1361
100k
        }
1362
9.34k
      else if (bits_per_sample == 12)
1363
9.34k
        {
1364
9.34k
          if (word_pad_lsb)
1365
3.39k
            {
1366
              /*
1367
                Padding in LSB (Method A)  Standard method.
1368
              */
1369
3.39k
              if (endian_type == MSBEndian)
1370
3.18k
                {
1371
29.2k
                  for (i=samples_per_row; i != 0; i--)
1372
26.0k
                    {
1373
26.0k
                      sample=0;
1374
26.0k
                      sample |= (((sample_t) *scanline++) << 8);
1375
26.0k
                      sample |= ((sample_t) *scanline++);
1376
26.0k
                      sample >>= 4;
1377
26.0k
                      *sp++=sample;
1378
26.0k
                    }
1379
3.18k
                }
1380
211
              else if (endian_type == LSBEndian)
1381
211
                {
1382
634
                  for (i=samples_per_row; i != 0; i--)
1383
423
                    {
1384
423
                      sample=0;
1385
423
                      sample |= ((sample_t) *scanline++);
1386
423
                      sample |= (((sample_t) *scanline++) << 8);
1387
423
                      sample >>= 4;
1388
423
                      *sp++=sample;
1389
423
                    }
1390
211
                }
1391
3.39k
              return;
1392
3.39k
            }
1393
5.95k
          else if (word_pad_msb)
1394
5.95k
            {
1395
              /*
1396
                Padding in MSB (Method B)  Deprecated method.
1397
              */
1398
5.95k
              if (endian_type == MSBEndian)
1399
5.74k
                {
1400
278k
                  for (i=samples_per_row; i != 0; i--)
1401
272k
                    {
1402
272k
                      sample=0;
1403
272k
                      sample |= (((sample_t) *scanline++) << 8);
1404
272k
                      sample |= ((sample_t) *scanline++);
1405
272k
                      sample &= 0xFFF;
1406
272k
                      *sp++=sample;
1407
272k
                    }
1408
5.74k
                }
1409
207
              else if (endian_type == LSBEndian)
1410
207
                {
1411
609
                  for (i=samples_per_row; i != 0; i--)
1412
402
                    {
1413
402
                      sample=0;
1414
402
                      sample |= ((sample_t) *scanline++);
1415
402
                      sample |= (((sample_t) *scanline++) << 8);
1416
402
                      sample &= 0xFFF;
1417
402
                      *sp++=sample;
1418
402
                    }
1419
207
                }
1420
5.95k
              return;
1421
5.95k
            }
1422
9.34k
        }
1423
109k
    }
1424
1425
  /*
1426
    Special fast handling for 8-bit images.
1427
  */
1428
99.6k
  if (bits_per_sample == 8)
1429
8.70k
    {
1430
1.19M
      for (i=samples_per_row; i != 0; i--)
1431
1.19M
        *sp++= (sample_t) *scanline++;
1432
8.70k
      return;
1433
8.70k
    }
1434
1435
  /*
1436
    Special fast handling for 16-bit images.
1437
  */
1438
90.9k
  if (bits_per_sample == 16)
1439
2.33k
    {
1440
2.33k
      if (endian_type == MSBEndian)
1441
2.13k
        {
1442
70.7k
          for (i=samples_per_row; i != 0; i--)
1443
68.5k
            {
1444
68.5k
              sample=0;
1445
68.5k
              sample |= (((sample_t) *scanline++) << 8);
1446
68.5k
              sample |= ((sample_t) *scanline++);
1447
68.5k
              *sp++=sample;
1448
68.5k
            }
1449
2.13k
        }
1450
203
      else if (endian_type == LSBEndian)
1451
203
        {
1452
600
          for (i=samples_per_row; i != 0; i--)
1453
397
            {
1454
397
              sample=0;
1455
397
              sample |= ((sample_t) *scanline++);
1456
397
              sample |= (((sample_t) *scanline++) << 8);
1457
397
              *sp++=sample;
1458
397
            }
1459
203
        }
1460
2.33k
      return;
1461
2.33k
    }
1462
1463
#if 0
1464
  /*
1465
    Special fast handling for 32-bit (float) images.
1466
  */
1467
  if (bits_per_sample == 32)
1468
    {
1469
      register magick_uint32_t
1470
        packed_u32;
1471
1472
      if (endian_type == MSBEndian)
1473
        {
1474
          for (i=samples_per_row; i != 0; i--)
1475
            {
1476
              MSBOctetsToPackedU32Word(scanline,packed_u32);
1477
              *sp++=packed_u32;
1478
            }
1479
        }
1480
      else if (endian_type == LSBEndian)
1481
        {
1482
          for (i=samples_per_row; i != 0; i--)
1483
            {
1484
              LSBOctetsToPackedU32Word(scanline,packed_u32);
1485
              *sp++=packed_u32;
1486
            }
1487
        }
1488
      return;
1489
    }
1490
#endif
1491
1492
  /*
1493
    Packed data.
1494
  */
1495
88.5k
  {
1496
88.5k
    ReadWordU32State
1497
88.5k
      read_state;
1498
1499
88.5k
    WordStreamReadHandle
1500
88.5k
      read_stream;
1501
1502
88.5k
    WordStreamReadFunc
1503
88.5k
      read_func=0;
1504
1505
88.5k
    if (endian_type == LSBEndian)
1506
202
      read_func=ReadWordU32LE;
1507
88.3k
    else
1508
88.3k
      read_func=ReadWordU32BE;
1509
1510
88.5k
    read_state.words=scanline;
1511
88.5k
    MagickWordStreamInitializeRead(&read_stream,read_func, (void *) &read_state);
1512
92.8M
      for (i=samples_per_row; i != 0; i--)
1513
92.7M
        *sp++=MagickWordStreamLSBRead(&read_stream,bits_per_sample);
1514
88.5k
  }
1515
88.5k
}
1516
1517
/*
1518
  Apply a simple "Tent" filter to upsample chroma channels.
1519
*/
1520
STATIC void TentUpsampleChroma(PixelPacket *pixels, unsigned long columns)
1521
27.9k
{
1522
27.9k
  unsigned long
1523
27.9k
    column;
1524
1525
4.35M
  for (column = 1; column < columns-2; column += 2)
1526
4.32M
    {
1527
4.32M
#if QuantumDepth < 32
1528
      /*
1529
        Use integer computations if intermediate result will fit.
1530
      */
1531
4.32M
      pixels->green=((unsigned long) pixels[column-1].green + pixels[column+1].green)/2;
1532
4.32M
      pixels->blue=((unsigned long) pixels[column-1].blue + pixels[column+1].blue)/2;
1533
#else
1534
      /*
1535
        Use floating point computations.
1536
      */
1537
      double
1538
        result;
1539
1540
      result=((double) pixels[column-1].green + pixels[column+1].green)/2;
1541
      pixels->green=RoundDoubleToQuantum(result);
1542
1543
      result=((double) pixels[column-1].blue + pixels[column+1].blue)/2;
1544
      pixels->blue=RoundDoubleToQuantum(result);
1545
#endif
1546
4.32M
    }
1547
27.9k
}
1548
1549
21.6k
#define ThrowDPXReaderException(code_,reason_,image_) \
1550
21.6k
{ \
1551
21.6k
  MagickFreeResourceLimitedMemory(map_Y); \
1552
21.6k
  MagickFreeResourceLimitedMemory(map_CbCr); \
1553
21.6k
  if (samples_set) \
1554
21.6k
    DestroyThreadViewDataSet(samples_set);    \
1555
21.6k
  if (scanline_set) \
1556
21.6k
    DestroyThreadViewDataSet(scanline_set);    \
1557
21.6k
  ThrowReaderException(code_,reason_,image_); \
1558
0
}
1559
1560
STATIC Image *ReadDPXImage(const ImageInfo *image_info,ExceptionInfo *exception)
1561
21.4k
{
1562
21.4k
  char
1563
21.4k
    txt_buffer[MaxTextExtent];
1564
1565
21.4k
  DPXFileInfo
1566
21.4k
    dpx_file_info;
1567
1568
21.4k
  DPXImageInfo
1569
21.4k
    dpx_image_info;
1570
1571
21.4k
  DPXImageSourceInfo
1572
21.4k
    dpx_source_info;
1573
1574
21.4k
  DPXMPFilmInfo
1575
21.4k
    dpx_mp_info;
1576
1577
21.4k
  DPXTVInfo
1578
21.4k
    dpx_tv_info;
1579
1580
21.4k
  Image
1581
21.4k
    *image=0;
1582
1583
21.4k
  long
1584
21.4k
    y;
1585
1586
21.4k
  size_t
1587
21.4k
    offset,
1588
21.4k
    row_octets;
1589
1590
21.4k
  Quantum
1591
21.4k
    *map_Y=0,                     /* value translation map (RGB or Y) */
1592
21.4k
    *map_CbCr=0;                  /* value translation map (CbCr) */
1593
1594
21.4k
  ThreadViewDataSet
1595
21.4k
    *samples_set=0;
1596
1597
21.4k
  ThreadViewDataSet
1598
21.4k
    *scanline_set=0;
1599
1600
21.4k
  size_t
1601
21.4k
    element_size;               /* Number of bytes in an element */
1602
1603
21.4k
  unsigned int
1604
21.4k
    bits_per_sample,            /* number of bits per sample */
1605
21.4k
    element,                    /* current element number */
1606
21.4k
    max_bits_per_sample,        /* maximum number of bits per sample for any element */
1607
21.4k
    max_samples_per_pixel,      /* maximum number of samples comprising one pixel for any element */
1608
21.4k
    samples_per_pixel,          /* number of samples comprising one pixel for this element */
1609
21.4k
    samples_per_row;            /* number of samples in one row */
1610
1611
21.4k
  MagickPassFail
1612
21.4k
    status;
1613
1614
21.4k
  unsigned long
1615
21.4k
    i,
1616
21.4k
    pixels_offset;
1617
1618
21.4k
  MagickBool
1619
21.4k
    is_grayscale=MagickFalse,   /* image is grayscale ? */
1620
21.4k
    is_monochrome=MagickFalse,  /* image is monochrome ? */
1621
21.4k
    matte_init=MagickFalse,     /* Set to True if opacity channel needs init */
1622
21.4k
    swap_endian=MagickFalse;    /* swap endian order */
1623
1624
21.4k
  DPXImageElementDescriptor
1625
21.4k
    element_descriptor;
1626
1627
21.4k
  DPXTransferCharacteristic
1628
21.4k
    transfer_characteristic;
1629
1630
21.4k
  ImageComponentPackingMethod
1631
21.4k
    packing_method;
1632
1633
21.4k
  EndianType
1634
21.4k
    endian_type;
1635
1636
21.4k
  const char
1637
21.4k
    *definition_value;
1638
1639
  /*
1640
    Open image file.
1641
  */
1642
21.4k
  assert(sizeof(DPXHeader) == 2048);
1643
21.4k
  assert(image_info != (const ImageInfo *) NULL);
1644
21.4k
  assert(image_info->signature == MagickSignature);
1645
21.4k
  assert(exception != (ExceptionInfo *) NULL);
1646
21.4k
  assert(exception->signature == MagickSignature);
1647
21.4k
  image=AllocateImage(image_info);
1648
21.4k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1649
21.4k
  if (status == False)
1650
21.4k
    ThrowDPXReaderException(FileOpenError,UnableToOpenFile,image);
1651
  /*
1652
    Read DPX image.
1653
  */
1654
21.4k
  offset=ReadBlob(image,sizeof(dpx_file_info),&dpx_file_info);
1655
21.4k
  if (offset != sizeof(dpx_file_info) ||
1656
20.3k
      ((LocaleNCompare((char *) &dpx_file_info.magic,"SDPX",4) != 0) &&
1657
2.41k
       (LocaleNCompare((char *) &dpx_file_info.magic,"XPDS",4) != 0)))
1658
20.3k
    ThrowDPXReaderException(CorruptImageError,ImproperImageHeader,image);
1659
  /*
1660
    Check for swapped endian order.
1661
  */
1662
20.3k
  if (dpx_file_info.magic != 0x53445058U)
1663
20.0k
    swap_endian=MagickTrue;
1664
1665
#if defined(WORDS_BIGENDIAN)
1666
  endian_type = (swap_endian ? LSBEndian : MSBEndian);
1667
#else
1668
20.3k
  endian_type = (swap_endian ? MSBEndian : LSBEndian);
1669
20.3k
#endif
1670
1671
  /*
1672
    Save original endian to image so that image write will preserve
1673
    original endianness.
1674
  */
1675
20.3k
  image->endian = endian_type;
1676
1677
20.3k
  if (image->logging)
1678
20.3k
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1679
20.3k
                          "%s endian DPX format",
1680
20.3k
                          (endian_type == MSBEndian ? "Big" : "Little"));
1681
1682
20.3k
  if (swap_endian)
1683
20.0k
    SwabDPXFileInfo(&dpx_file_info);
1684
1685
20.3k
  if (image->logging)
1686
20.3k
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1687
20.3k
                          "File size: %u", dpx_file_info.file_size);
1688
1689
20.3k
  StringToAttribute(image,"software",dpx_file_info.creator);
1690
20.3k
  StringToAttribute(image,"comment",dpx_file_info.project_name);
1691
20.3k
  StringToAttribute(image,"copyright",dpx_file_info.copyright);
1692
20.3k
  StringToAttribute(image,"document",dpx_file_info.image_filename);
1693
  /* StringToAttribute(image,"timestamp",dpx_file_info.creation_datetime); */
1694
1695
20.3k
  StringToAttribute(image,"DPX:file.version",dpx_file_info.header_format_version);
1696
20.3k
  StringToAttribute(image,"DPX:file.filename",dpx_file_info.image_filename);
1697
20.3k
  StringToAttribute(image,"DPX:file.creation.datetime",dpx_file_info.creation_datetime);
1698
20.3k
  StringToAttribute(image,"DPX:file.creator",dpx_file_info.creator);
1699
20.3k
  StringToAttribute(image,"DPX:file.project.name",dpx_file_info.project_name);
1700
20.3k
  StringToAttribute(image,"DPX:file.copyright",dpx_file_info.copyright);
1701
20.3k
  U32ToAttribute(image,"DPX:file.encryption.key",dpx_file_info.encryption_key);
1702
1703
  /*
1704
    Obtain offset to pixels.
1705
  */
1706
20.3k
  pixels_offset=dpx_file_info.image_data_offset & 0xffffffff;
1707
20.3k
  if (image->logging)
1708
20.3k
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1709
20.3k
                          "Image data offset %lu",pixels_offset);
1710
20.3k
  if (pixels_offset < 1408)
1711
17.5k
    ThrowDPXReaderException(CorruptImageError,ImproperImageHeader,image);
1712
17.5k
  if (image->logging)
1713
17.5k
    {
1714
17.5k
      char
1715
17.5k
        generic_length_str[MaxTextExtent],
1716
17.5k
        industry_length_str[MaxTextExtent],
1717
17.5k
        user_length_str[MaxTextExtent];
1718
1719
17.5k
      if (IS_UNDEFINED_U32(dpx_file_info.generic_section_length))
1720
2.05k
        (void) strlcpy(generic_length_str,"UNDEFINED",sizeof(generic_length_str));
1721
15.5k
      else
1722
15.5k
        FormatString(generic_length_str,"%u",dpx_file_info.generic_section_length);
1723
1724
17.5k
      if (IS_UNDEFINED_U32(dpx_file_info.industry_section_length))
1725
1.58k
        (void) strlcpy(industry_length_str,"UNDEFINED",sizeof(industry_length_str));
1726
16.0k
      else
1727
16.0k
        FormatString(industry_length_str,"%u",dpx_file_info.industry_section_length);
1728
1729
17.5k
      if (IS_UNDEFINED_U32(dpx_file_info.user_defined_length))
1730
1.84k
        (void) strlcpy(user_length_str,"UNDEFINED",sizeof(user_length_str));
1731
15.7k
      else
1732
15.7k
        FormatString(user_length_str,"%u",dpx_file_info.user_defined_length);
1733
1734
17.5k
      if (image->logging)
1735
17.5k
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1736
17.5k
                              "Generic length %s, Industry length %s, User length %s",
1737
17.5k
                              generic_length_str,industry_length_str,user_length_str);
1738
17.5k
    }
1739
  /*
1740
    Read image information header.
1741
  */
1742
17.5k
  offset += ReadBlob(image,sizeof(dpx_image_info),&dpx_image_info);
1743
17.5k
  if (offset != (size_t) 1408L)
1744
15.6k
    ThrowDPXReaderException(CorruptImageError,UnexpectedEndOfFile,image);
1745
15.6k
  if (swap_endian)
1746
15.3k
    SwabDPXImageInfo(&dpx_image_info);
1747
15.6k
  if (image->logging)
1748
15.6k
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1749
15.6k
                          "Pixels per line %u, Lines per image %u, Elements %u",
1750
15.6k
                          (unsigned int) dpx_image_info.pixels_per_line,
1751
15.6k
                          (unsigned int) dpx_image_info.lines_per_image_element,
1752
15.6k
                          (unsigned int) dpx_image_info.elements);
1753
15.6k
  if (dpx_image_info.orientation > 7U)
1754
13.6k
    ThrowDPXReaderException(CorruptImageError,ImproperImageHeader,image);
1755
13.6k
  if (dpx_image_info.elements >
1756
13.6k
      sizeof(dpx_image_info.element_info)/sizeof(dpx_image_info.element_info[0]))
1757
12.6k
    ThrowDPXReaderException(CorruptImageError,ImproperImageHeader,image);
1758
12.6k
  if (dpx_image_info.elements == 0)
1759
11.0k
    ThrowDPXReaderException(CorruptImageError,ImproperImageHeader,image);
1760
11.0k
  image->columns=dpx_image_info.pixels_per_line & 0xFFFFFFFF;
1761
11.0k
  image->rows=dpx_image_info.lines_per_image_element & 0xFFFFFFFF;
1762
11.0k
  if (image->logging)
1763
11.0k
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1764
11.0k
                          "Geometry: %lux%lu", image->columns, image->rows);
1765
11.0k
  U16ToAttribute(image,"DPX:image.orientation",dpx_image_info.orientation);
1766
11.0k
  image->orientation=DPXOrientationToOrientationType(dpx_image_info.orientation);
1767
1768
11.0k
  if (pixels_offset >= 1664UL)
1769
9.78k
    {
1770
      /*
1771
        Read Image source information header.
1772
      */
1773
9.78k
      offset += ReadBlob(image,sizeof(dpx_source_info),&dpx_source_info);
1774
9.78k
      if (offset != (size_t) 1664L)
1775
9.70k
        ThrowDPXReaderException(CorruptImageError,UnexpectedEndOfFile,image);
1776
9.70k
      if (swap_endian)
1777
9.58k
        SwabDPXImageSourceInfo(&dpx_source_info);
1778
1779
9.70k
      U32ToAttribute(image,"DPX:source.x-offset",dpx_source_info.x_offset);
1780
9.70k
      U32ToAttribute(image,"DPX:source.y-offset",dpx_source_info.y_offset);
1781
9.70k
      R32ToAttribute(image,"DPX:source.x-center",dpx_source_info.x_center);
1782
9.70k
      R32ToAttribute(image,"DPX:source.y-center",dpx_source_info.y_center);
1783
9.70k
      U32ToAttribute(image,"DPX:source.x-original-size",dpx_source_info.x_original_size);
1784
9.70k
      U32ToAttribute(image,"DPX:source.y-original-size",dpx_source_info.y_original_size);
1785
9.70k
      StringToAttribute(image,"DPX:source.filename",dpx_source_info.source_image_filename);
1786
9.70k
      StringToAttribute(image,"DPX:source.creation.datetime",dpx_source_info.source_image_datetime);
1787
9.70k
      StringToAttribute(image,"DPX:source.device.name",dpx_source_info.input_device_name);
1788
9.70k
      StringToAttribute(image,"DPX:source.device.serialnumber",dpx_source_info.input_device_serialnumber);
1789
9.70k
      U16ToAttribute(image,"DPX:source.border.validity.left",dpx_source_info.border_validity.XL);
1790
9.70k
      U16ToAttribute(image,"DPX:source.border.validity.right",dpx_source_info.border_validity.XR);
1791
9.70k
      U16ToAttribute(image,"DPX:source.border.validity.top",dpx_source_info.border_validity.YT);
1792
9.70k
      U16ToAttribute(image,"DPX:source.border.validity.bottom",dpx_source_info.border_validity.YB);
1793
9.70k
      U32ToAttribute(image,"DPX:source.aspect.ratio.horizontal",dpx_source_info.aspect_ratio.horizontal);
1794
9.70k
      U32ToAttribute(image,"DPX:source.aspect.ratio.vertical",dpx_source_info.aspect_ratio.vertical);
1795
9.70k
      R32ToAttribute(image,"DPX:source.scanned.size.x",dpx_source_info.x_scanned_size);
1796
9.70k
      R32ToAttribute(image,"DPX:source.scanned.size.y",dpx_source_info.y_scanned_size);
1797
9.70k
    }
1798
10.9k
  if (pixels_offset >= 1920UL)
1799
9.62k
    {
1800
      /*
1801
        Read Motion-picture film information header.
1802
      */
1803
9.62k
      offset += ReadBlob(image,sizeof(dpx_mp_info),&dpx_mp_info);
1804
9.62k
      if (offset != (size_t) 1920L)
1805
9.47k
        ThrowDPXReaderException(CorruptImageError,UnexpectedEndOfFile,image);
1806
9.47k
      if (swap_endian)
1807
9.41k
        SwabDPXMPFilmInfo(&dpx_mp_info);
1808
1809
9.47k
      if (dpx_file_info.industry_section_length != 0)
1810
9.33k
        {
1811
9.33k
          StringToAttribute(image,"DPX:mp.film.manufacturer.id",dpx_mp_info.film_mfg_id_code);
1812
9.33k
          StringToAttribute(image,"DPX:mp.film.type",dpx_mp_info.film_type);
1813
9.33k
          StringToAttribute(image,"DPX:mp.perfs.offset",dpx_mp_info.perfs_offset);
1814
9.33k
          StringToAttribute(image,"DPX:mp.prefix",dpx_mp_info.prefix);
1815
9.33k
          StringToAttribute(image,"DPX:mp.count",dpx_mp_info.count);
1816
9.33k
          StringToAttribute(image,"DPX:mp.format",dpx_mp_info.format);
1817
9.33k
          U32ToAttribute(image,"DPX:mp.frame.position",dpx_mp_info.frame_position);
1818
9.33k
          U32ToAttribute(image,"DPX:mp.sequence.length",dpx_mp_info.sequence_length);
1819
9.33k
          U32ToAttribute(image,"DPX:mp.held.count",dpx_mp_info.held_count);
1820
9.33k
          R32ToAttribute(image,"DPX:mp.frame.rate",dpx_mp_info.frame_rate);
1821
9.33k
          R32ToAttribute(image,"DPX:mp.shutter.angle",dpx_mp_info.shutter_angle);
1822
9.33k
          StringToAttribute(image,"DPX:mp.frame.id",dpx_mp_info.frame_id);
1823
9.33k
          StringToAttribute(image,"DPX:mp.slate.info",dpx_mp_info.slate_info);
1824
9.33k
        }
1825
9.47k
    }
1826
10.8k
  if (pixels_offset >= 2048UL)
1827
9.42k
    {
1828
      /*
1829
        Read Television information header.
1830
      */
1831
9.42k
      offset += ReadBlob(image,sizeof(dpx_tv_info),&dpx_tv_info);
1832
9.42k
      if (offset != (size_t) 2048L)
1833
8.70k
        ThrowDPXReaderException(CorruptImageError,UnexpectedEndOfFile,image);
1834
8.70k
      if (swap_endian)
1835
8.64k
        SwabDPXTVInfo(&dpx_tv_info);
1836
1837
8.70k
      if (dpx_file_info.industry_section_length != 0)
1838
8.57k
        {
1839
8.57k
          U32ToBitsAttribute(image,"DPX:tv.time.code",dpx_tv_info.time_code);
1840
8.57k
          U32ToBitsAttribute(image,"DPX:tv.user.bits",dpx_tv_info.user_bits);
1841
8.57k
          U8ToAttribute(image,"DPX:tv.interlace",dpx_tv_info.interlace);
1842
8.57k
          U8ToAttribute(image,"DPX:tv.field.number",dpx_tv_info.field_number);
1843
8.57k
          U8ToAttribute(image,"DPX:tv.video.signal",dpx_tv_info.video_signal);
1844
8.57k
          R32ToAttribute(image,"DPX:tv.horizontal.sampling.rate",dpx_tv_info.horizontal_sample);
1845
8.57k
          R32ToAttribute(image,"DPX:tv.temporal.sampling.rate",dpx_tv_info.temporal_sample);
1846
8.57k
          R32ToAttribute(image,"DPX:tv.sync.time",dpx_tv_info.sync_time);
1847
8.57k
          R32ToAttribute(image,"DPX:tv.gamma",dpx_tv_info.gamma);
1848
8.57k
          R32ToAttribute(image,"DPX:tv.black.level",dpx_tv_info.black_level);
1849
8.57k
          R32ToAttribute(image,"DPX:tv.black.gain",dpx_tv_info.black_gain);
1850
8.57k
          R32ToAttribute(image,"DPX:tv.breakpoint",dpx_tv_info.breakpoint);
1851
8.57k
          R32ToAttribute(image,"DPX:tv.white.level",dpx_tv_info.white_level);
1852
8.57k
          R32ToAttribute(image,"DPX:tv.integration.time",dpx_tv_info.integration_time);
1853
8.57k
        }
1854
8.70k
    }
1855
10.1k
  if (pixels_offset >= 2080UL)
1856
8.67k
    {
1857
8.67k
      if (!IS_UNDEFINED_U32(dpx_file_info.user_defined_length) &&
1858
8.31k
          (dpx_file_info.user_defined_length >= sizeof(DPXUserDefinedData)))
1859
7.14k
        {
1860
          /*
1861
            Read user header.
1862
          */
1863
7.14k
          unsigned char
1864
7.14k
            *user_data;
1865
1866
7.14k
          const size_t
1867
7.14k
            block_size = 65536UL;
1868
1869
7.14k
          size_t
1870
7.14k
            read_size,
1871
7.14k
            user_data_length;
1872
1873
7.14k
          DPXUserDefinedData
1874
7.14k
            *dpx_user_data;
1875
1876
7.14k
          user_data_length=0UL;
1877
7.14k
          user_data=(unsigned char *) NULL;
1878
1879
14.2k
          while (user_data_length < dpx_file_info.user_defined_length)
1880
7.88k
            {
1881
7.88k
              unsigned char
1882
7.88k
                *new_user_data;
1883
1884
7.88k
              read_size=Min(block_size,dpx_file_info.user_defined_length-user_data_length);
1885
7.88k
              new_user_data=MagickReallocateResourceLimitedMemory(unsigned char *,user_data,user_data_length+read_size);
1886
7.88k
              if (new_user_data == (unsigned char *) NULL)
1887
0
                {
1888
0
                  MagickFreeResourceLimitedMemory(user_data);
1889
0
                  ThrowDPXReaderException(ResourceLimitError,MemoryAllocationFailed,image);
1890
0
                }
1891
7.88k
              user_data=new_user_data;
1892
7.88k
              if (ReadBlob(image,read_size,user_data+user_data_length) != read_size)
1893
791
                {
1894
791
                  MagickFreeResourceLimitedMemory(user_data);
1895
791
                  ThrowDPXReaderException(CorruptImageError,UnexpectedEndOfFile,image);
1896
0
                }
1897
7.09k
              user_data_length += read_size;
1898
7.09k
              offset += read_size;
1899
7.09k
            }
1900
1901
6.35k
          dpx_user_data=(DPXUserDefinedData *) user_data;
1902
6.35k
          StringToAttribute(image,"DPX:user.data.id",dpx_user_data->user_id);
1903
6.35k
          if (!SetImageProfile(image,"DPXUSERDATA",user_data,user_data_length))
1904
0
            {
1905
0
              MagickFreeResourceLimitedMemory(user_data);
1906
0
              ThrowDPXReaderException(ResourceLimitError,MemoryAllocationFailed,image);
1907
0
            }
1908
6.35k
          MagickFreeResourceLimitedMemory(user_data);
1909
6.35k
        }
1910
8.67k
    }
1911
  /*
1912
    Determine the maximum number of bits per sample, samples per element, and colorspace
1913
1914
    If we encounter an element which is not supported (perhaps a
1915
    vendor extension), then update dpx_image_info.elements to stop
1916
    reading before that element.
1917
  */
1918
9.34k
  max_bits_per_sample=0;
1919
9.34k
  max_samples_per_pixel=0;
1920
9.34k
  {
1921
9.34k
    MagickBool
1922
9.34k
      has_cbcr=MagickFalse,
1923
9.34k
      has_luma=MagickFalse,
1924
9.34k
      has_matte=MagickFalse,
1925
9.34k
      has_rgb=MagickFalse;
1926
1927
9.34k
    DPXColorimetric
1928
9.34k
      colorimetric=ColorimetricUserDefined;
1929
1930
9.34k
    transfer_characteristic=TransferCharacteristicUserDefined;
1931
9.34k
    if (image->logging)
1932
9.34k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1933
9.34k
                            "Number of elements: %u",
1934
9.34k
                            dpx_image_info.elements);
1935
1936
12.8k
    for (element=0; element < dpx_image_info.elements; element++)
1937
12.5k
      {
1938
12.5k
        if (image->logging)
1939
12.5k
          DescribeDPXImageElement(&dpx_image_info.element_info[element],element+1);
1940
12.5k
        if (element == 0)
1941
9.34k
          {
1942
9.34k
            colorimetric=
1943
9.34k
              (DPXColorimetric) dpx_image_info.element_info[element].colorimetric;
1944
9.34k
            DPXSetPrimaryChromaticities(colorimetric,&image->chromaticity);
1945
9.34k
          }
1946
12.5k
        element_descriptor=(DPXImageElementDescriptor)
1947
12.5k
          dpx_image_info.element_info[element].descriptor;
1948
12.5k
        bits_per_sample=dpx_image_info.element_info[element].bits_per_sample;
1949
        /*
1950
          Enforce supported bits per sample. Note that 32-bits could
1951
          be supported by the implementation but we don't allow it at
1952
          the moment.
1953
        */
1954
12.5k
        if ((bits_per_sample != 1) &&
1955
10.8k
            (bits_per_sample != 8) &&
1956
10.4k
            (bits_per_sample != 10) &&
1957
9.23k
            (bits_per_sample != 12) &&
1958
8.47k
            (bits_per_sample != 16))
1959
7.90k
          {
1960
7.90k
            if (image->logging)
1961
7.90k
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1962
7.90k
                                    "Unsupported bits per sample %u"
1963
7.90k
                                    " (truncating elements)", bits_per_sample);
1964
7.90k
            dpx_image_info.elements=element;
1965
7.90k
            break;
1966
7.90k
          }
1967
        /*
1968
          Ignore Northlight Scanner "scratch and dust" channel which claims
1969
          to be an Alpha channel, but is not.  Things would not be so bad if
1970
          it was coded according to the DPX standard.  Luckly, it always comes
1971
          after the color channels.
1972
        */
1973
4.62k
        if ((element_descriptor == ImageElementAlpha) &&
1974
806
            (bits_per_sample == 1) &&
1975
108
            (LocaleNCompare(dpx_image_info.element_info[element].description,
1976
108
                            "NL CLEAN MATTE",sizeof("NL CLEAN MATTE")-1) == 0))
1977
0
          {
1978
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1979
0
                                  "Skipping Northlight \"%s\" channel...",
1980
0
                                  dpx_image_info.element_info[element].description);
1981
0
            dpx_image_info.elements=element;
1982
0
            break;
1983
0
          }
1984
        /*
1985
          Validate packing method
1986
        */
1987
4.62k
        packing_method=(ImageComponentPackingMethod) dpx_image_info.element_info[element].packing;
1988
4.62k
        if ((packing_method != PackingMethodPacked) &&
1989
2.59k
            (packing_method != PackingMethodWordsFillLSB) &&
1990
1.99k
            (packing_method != PackingMethodWordsFillMSB))
1991
696
          {
1992
696
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1993
696
                                  "Unsupported packing method %u"
1994
696
                                  " (truncating elements)", packing_method);
1995
696
            dpx_image_info.elements=element;
1996
696
            break;
1997
696
          }
1998
        /*
1999
          Data sign, (0 = unsigned; 1 = signed)
2000
        */
2001
3.92k
        if (dpx_image_info.element_info[element].data_sign != 0)
2002
391
          {
2003
391
            if (image->logging)
2004
391
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2005
391
                                    "Signed pixel data (in element %u) is not supported"
2006
391
                                    " (truncating elements)",
2007
391
                                    element);
2008
391
            dpx_image_info.elements=element;
2009
391
            break;
2010
391
          }
2011
        /*
2012
          Special image width rules for some element descriptors
2013
        */
2014
3.53k
        switch (element_descriptor)
2015
3.53k
          {
2016
153
          case ImageElementColorDifferenceCbCr: /* 4:2:2 */
2017
441
          case ImageElementCbYCrY422:
2018
560
          case ImageElementCbYACrYA4224:
2019
560
            if (image->columns % 2)
2020
7
              {
2021
7
                if (image->logging)
2022
7
                  {
2023
7
                    char txt_buffer[MaxTextExtent];
2024
7
                    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2025
7
                                          "Image width must be evenly divisible"
2026
7
                                          " by 2 for \"%s\" element",
2027
7
                                          DescribeImageElementDescriptor(txt_buffer,
2028
7
                                                                         element_descriptor));
2029
7
                  }
2030
7
                dpx_image_info.elements=element;
2031
7
              }
2032
560
            break;
2033
2.97k
          default:
2034
2.97k
            {
2035
2.97k
            }
2036
3.53k
          }
2037
3.53k
        if (dpx_image_info.elements == element)
2038
7
          break;
2039
        /*
2040
          Validate and set image colorspace
2041
        */
2042
3.53k
        switch (element_descriptor)
2043
3.53k
          {
2044
148
          case ImageElementColorDifferenceCbCr:
2045
435
          case ImageElementCbYCrY422:
2046
553
          case ImageElementCbYACrYA4224:
2047
735
          case ImageElementCbYCr444:
2048
847
          case ImageElementCbYCrA4444:
2049
847
            {
2050
847
              has_cbcr=MagickTrue;
2051
847
              colorimetric=(DPXColorimetric) dpx_image_info.element_info[element].colorimetric;
2052
847
              transfer_characteristic=(DPXTransferCharacteristic)
2053
847
                dpx_image_info.element_info[element].transfer_characteristic;
2054
847
              break;
2055
735
            }
2056
217
          case ImageElementRed:
2057
412
          case ImageElementGreen:
2058
551
          case ImageElementBlue:
2059
785
          case ImageElementRGB:
2060
951
          case ImageElementRGBA:
2061
1.10k
          case ImageElementABGR:
2062
1.10k
            {
2063
1.10k
              has_rgb=MagickTrue;
2064
1.10k
              colorimetric=(DPXColorimetric) dpx_image_info.element_info[element].colorimetric;
2065
1.10k
              transfer_characteristic=(DPXTransferCharacteristic)
2066
1.10k
                dpx_image_info.element_info[element].transfer_characteristic;
2067
1.10k
              break;
2068
951
            }
2069
1.07k
          case ImageElementLuma:
2070
1.07k
            {
2071
1.07k
              has_luma=MagickTrue;
2072
1.07k
              colorimetric=(DPXColorimetric) dpx_image_info.element_info[element].colorimetric;
2073
1.07k
              transfer_characteristic=(DPXTransferCharacteristic)
2074
1.07k
                dpx_image_info.element_info[element].transfer_characteristic;
2075
1.07k
              break;
2076
951
            }
2077
283
          case ImageElementAlpha:
2078
283
            {
2079
283
              break;
2080
951
            }
2081
230
          default:
2082
230
            {
2083
230
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2084
230
                                    "Unhandled element descriptor (%u): %s"
2085
230
                                    " (truncating elements)",
2086
230
                                    element_descriptor,
2087
230
                                    DescribeImageElementDescriptor(txt_buffer,element_descriptor));
2088
230
              dpx_image_info.elements=element;
2089
230
              break;
2090
951
            }
2091
3.53k
          }
2092
        /*
2093
          Check for a matte channel.
2094
        */
2095
3.53k
        switch (element_descriptor)
2096
3.53k
          {
2097
283
          case ImageElementAlpha:
2098
449
          case ImageElementRGBA:
2099
599
          case ImageElementABGR:
2100
717
          case ImageElementCbYACrYA4224:
2101
829
          case ImageElementCbYCrA4444:
2102
829
            has_matte=MagickTrue;
2103
829
            break;
2104
2.70k
          default:
2105
2.70k
            break;
2106
3.53k
          }
2107
3.53k
        max_bits_per_sample=Max(max_bits_per_sample,bits_per_sample);
2108
3.53k
        max_samples_per_pixel=Max(max_samples_per_pixel,
2109
3.53k
                                  DPXSamplesPerPixel(element_descriptor));
2110
2111
2112
3.53k
      } /* for (element=0; element < dpx_image_info.elements; element++) */
2113
2114
    /*
2115
      Check if there were any supported elements
2116
    */
2117
9.34k
    if (dpx_image_info.elements == 0)
2118
7.59k
      {
2119
7.59k
        if (image->logging)
2120
7.59k
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2121
7.59k
                                "No supported image elements were found!");
2122
7.59k
        ThrowDPXReaderException(CorruptImageError,ImproperImageHeader,image);
2123
0
      }
2124
2125
1.74k
    if (image->logging)
2126
1.74k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2127
1.74k
                            "Maximum number of bits per sample in any element: %u",
2128
1.74k
                            max_bits_per_sample);
2129
1.74k
    if (has_cbcr)
2130
531
      {
2131
531
        image->colorspace=Rec709YCbCrColorspace;
2132
531
        if ((transfer_characteristic == TransferCharacteristicITU_R601_625L) ||
2133
483
            (transfer_characteristic == TransferCharacteristicITU_R601_525L))
2134
61
          image->colorspace=Rec601YCbCrColorspace;
2135
531
      }
2136
1.21k
    else if (has_luma)
2137
817
      {
2138
817
        image->colorspace=GRAYColorspace;
2139
817
        if (transfer_characteristic == TransferCharacteristicITU_R709)
2140
144
          image->colorspace=Rec709LumaColorspace;
2141
673
        else if ((transfer_characteristic == TransferCharacteristicITU_R601_625L) ||
2142
504
                 (transfer_characteristic == TransferCharacteristicITU_R601_525L))
2143
242
          image->colorspace=Rec601LumaColorspace;
2144
817
      }
2145
398
    else if (has_rgb)
2146
387
      {
2147
387
        image->colorspace=RGBColorspace;
2148
387
        if (transfer_characteristic == TransferCharacteristicPrintingDensity)
2149
17
          image->colorspace=CineonLogRGBColorspace;
2150
387
      }
2151
2152
1.74k
    image->matte=has_matte;
2153
1.74k
  }
2154
1.74k
  if (image->logging)
2155
1.74k
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2156
1.74k
                          "Image colorspace: %s",
2157
1.74k
                          ColorspaceTypeToString(image->colorspace));
2158
  /*
2159
    Set image depth to maximum bits per sample encountered in any element.
2160
  */
2161
1.74k
  image->depth=max_bits_per_sample;
2162
  /*
2163
    Skip reading pixels if ping requested.
2164
  */
2165
1.74k
  if (image_info->ping)
2166
0
    {
2167
0
      StopTimer(&image->timer);
2168
0
      CloseBlob(image);
2169
0
      return(image);
2170
0
    }
2171
2172
1.74k
  if (CheckImagePixelLimits(image, exception) != MagickPass)
2173
1.60k
    ThrowDPXReaderException(ResourceLimitError,ImagePixelLimitExceeded,image);
2174
2175
  /*
2176
    Validate that the elements provide all of the channels
2177
  */
2178
1.60k
  {
2179
    /* Flags to use when updating channel_bits */
2180
7.19k
#define RED_CHANNEL     (1U)
2181
7.24k
#define GREEN_CHANNEL   (1U << 1U)
2182
7.19k
#define BLUE_CHANNEL    (1U << 2U)
2183
5.20k
#define OPACITY_CHANNEL (1U << 3U)
2184
2185
1.60k
    unsigned int
2186
1.60k
      channel_bits; /* record of channels which were updated by elements */
2187
2188
1.60k
    channel_bits=0;
2189
4.70k
    for (element=0; element < dpx_image_info.elements; element++)
2190
3.09k
      {
2191
3.09k
        element_descriptor=(DPXImageElementDescriptor)
2192
3.09k
          dpx_image_info.element_info[element].descriptor;
2193
2194
        /*
2195
          Tally channels which would be updated by this element.
2196
        */
2197
3.09k
        switch (element_descriptor)
2198
3.09k
          {
2199
152
          case ImageElementRed:
2200
152
            channel_bits |= RED_CHANNEL;
2201
152
            break;
2202
183
          case ImageElementGreen:
2203
183
            channel_bits |= GREEN_CHANNEL;
2204
183
            break;
2205
133
          case ImageElementBlue:
2206
133
            channel_bits |= BLUE_CHANNEL;
2207
133
            break;
2208
259
          case ImageElementAlpha:
2209
259
            channel_bits |= OPACITY_CHANNEL;
2210
259
            break;
2211
0
          case ImageElementUnspecified:
2212
1.03k
          case ImageElementLuma:
2213
1.03k
            if (IsYCbCrColorspace(image->colorspace))
2214
126
              {
2215
126
                channel_bits |= RED_CHANNEL;
2216
126
              }
2217
909
            else
2218
909
              {
2219
909
                channel_bits |= RED_CHANNEL | GREEN_CHANNEL | BLUE_CHANNEL;
2220
909
                if (!image->matte)
2221
680
                  channel_bits |= OPACITY_CHANNEL;
2222
909
              }
2223
1.03k
            break;
2224
145
          case ImageElementColorDifferenceCbCr:
2225
145
            channel_bits |= GREEN_CHANNEL | BLUE_CHANNEL;
2226
145
            break;
2227
220
          case ImageElementRGB:
2228
220
            channel_bits |= RED_CHANNEL | GREEN_CHANNEL | BLUE_CHANNEL;
2229
220
            if (!image->matte)
2230
156
              channel_bits |= OPACITY_CHANNEL;
2231
220
            break;
2232
159
          case ImageElementRGBA:
2233
159
            channel_bits |= RED_CHANNEL | GREEN_CHANNEL | BLUE_CHANNEL | OPACITY_CHANNEL;
2234
159
            break;
2235
143
          case ImageElementABGR:
2236
143
            channel_bits |= RED_CHANNEL | GREEN_CHANNEL | BLUE_CHANNEL | OPACITY_CHANNEL;
2237
143
            break;
2238
277
          case ImageElementCbYCrY422:
2239
277
            channel_bits |= RED_CHANNEL | GREEN_CHANNEL | BLUE_CHANNEL;
2240
277
            if (!image->matte)
2241
240
              channel_bits |= OPACITY_CHANNEL;
2242
277
            break;
2243
105
          case ImageElementCbYACrYA4224:
2244
105
            channel_bits |= RED_CHANNEL | GREEN_CHANNEL | BLUE_CHANNEL | OPACITY_CHANNEL;
2245
105
            break;
2246
178
          case ImageElementCbYCr444:
2247
178
            channel_bits |= RED_CHANNEL | GREEN_CHANNEL | BLUE_CHANNEL;
2248
178
            if (!image->matte)
2249
149
              channel_bits |= OPACITY_CHANNEL;
2250
178
            break;
2251
108
          case ImageElementCbYCrA4444:
2252
108
            channel_bits |= RED_CHANNEL | GREEN_CHANNEL | BLUE_CHANNEL | OPACITY_CHANNEL;
2253
108
            break;
2254
0
          default:
2255
0
            break;
2256
3.09k
          }
2257
3.09k
      }
2258
2259
1.60k
    if (image->logging)
2260
1.60k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2261
1.60k
                            "Channels updated: %s%s%s%s",
2262
1.60k
                            channel_bits & RED_CHANNEL ? "R" : "",
2263
1.60k
                            channel_bits & GREEN_CHANNEL ? "G" : "",
2264
1.60k
                            channel_bits & BLUE_CHANNEL ? "B" : "",
2265
1.60k
                            channel_bits & OPACITY_CHANNEL ? "O" : "");
2266
2267
1.60k
    if (!(channel_bits & OPACITY_CHANNEL))
2268
73
      matte_init = MagickTrue;
2269
2270
1.60k
    if ((channel_bits & (RED_CHANNEL | GREEN_CHANNEL | BLUE_CHANNEL))
2271
1.60k
        != (RED_CHANNEL | GREEN_CHANNEL | BLUE_CHANNEL))
2272
1.58k
      ThrowDPXReaderException(CorruptImageError,MissingImageChannel,image);
2273
1.58k
  }
2274
2275
  /*
2276
    Validate file size if using a seekable blob
2277
  */
2278
1.58k
  if (BlobIsSeekable(image))
2279
1.58k
    {
2280
1.58k
      magick_off_t file_size;
2281
1.58k
      magick_off_t file_size_estimate = dpx_file_info.image_data_offset;
2282
2283
      /*
2284
        Verify that file size claimed by header is matched by file size
2285
      */
2286
1.58k
      file_size = GetBlobSize(image);
2287
1.58k
      if (!IS_UNDEFINED_U32(dpx_file_info.file_size) &&
2288
1.26k
          (file_size < dpx_file_info.file_size))
2289
39
        {
2290
39
          ThrowDPXReaderException(CorruptImageError,UnexpectedEndOfFile,image);
2291
0
        }
2292
1.54k
      if (!IS_UNDEFINED_U32(dpx_file_info.image_data_offset) &&
2293
1.53k
          (file_size < dpx_file_info.image_data_offset))
2294
52
        {
2295
52
          ThrowDPXReaderException(CorruptImageError,ImproperImageHeader,image);
2296
0
        }
2297
1.49k
      if (!IS_UNDEFINED_U32(dpx_file_info.generic_section_length) &&
2298
1.42k
          (file_size < dpx_file_info.generic_section_length))
2299
42
        {
2300
42
          ThrowDPXReaderException(CorruptImageError,ImproperImageHeader,image);
2301
0
        }
2302
1.45k
      if (!IS_UNDEFINED_U32(dpx_file_info.industry_section_length) &&
2303
1.39k
          (file_size < dpx_file_info.industry_section_length))
2304
49
        {
2305
49
          ThrowDPXReaderException(CorruptImageError,ImproperImageHeader,image);
2306
0
        }
2307
1.40k
      if (pixels_offset >= 2080UL)
2308
246
        {
2309
246
          if (!IS_UNDEFINED_U32(dpx_file_info.user_defined_length) &&
2310
240
              (file_size < dpx_file_info.user_defined_length))
2311
0
            {
2312
0
              ThrowDPXReaderException(CorruptImageError,ImproperImageHeader,image);
2313
0
            }
2314
246
        }
2315
2316
      /*
2317
        Estimate the required file size and assure that actual file
2318
        size is at least that size.
2319
      */
2320
3.90k
      for (element=0; element < dpx_image_info.elements; element++)
2321
2.59k
        {
2322
2.59k
          bits_per_sample=dpx_image_info.element_info[element].bits_per_sample;
2323
2.59k
          element_descriptor=(DPXImageElementDescriptor)
2324
2.59k
            dpx_image_info.element_info[element].descriptor;
2325
2.59k
          transfer_characteristic=
2326
2.59k
            (DPXTransferCharacteristic) dpx_image_info.element_info[element].transfer_characteristic;
2327
2.59k
          packing_method=(ImageComponentPackingMethod) dpx_image_info.element_info[element].packing;
2328
2.59k
          if (!IS_UNDEFINED_U32(dpx_image_info.element_info[element].data_offset) &&
2329
2.40k
              !IS_UNDEFINED_U32(dpx_file_info.file_size) &&
2330
1.73k
              (dpx_file_info.file_size != 0) &&
2331
898
              ((dpx_image_info.element_info[element].data_offset & 0xFFFFFFFF) >=
2332
898
               dpx_file_info.file_size))
2333
55
            {
2334
55
              if (image->logging)
2335
55
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2336
55
                                      "Element offset (%u) is outside the bounds of"
2337
55
                                      " file size (%u) indicated by header",
2338
55
                                      dpx_image_info.element_info[element].data_offset,
2339
55
                                      dpx_file_info.file_size);
2340
55
              ThrowDPXReaderException(CorruptImageError,ImproperImageHeader,image);
2341
0
            }
2342
2.53k
          if (!IS_UNDEFINED_U32(dpx_image_info.element_info[element].data_offset) &&
2343
2.35k
              ((dpx_image_info.element_info[element].data_offset & 0xFFFFFFFF) >=
2344
2.35k
               file_size))
2345
36
            {
2346
36
              if (image->logging)
2347
36
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2348
36
                                      "Element offset (%u) is outside the bounds of"
2349
36
                                      " actual file size (%" MAGICK_OFF_F "d)",
2350
36
                                      dpx_image_info.element_info[element].data_offset,
2351
36
                                      (magick_off_t) file_size);
2352
36
              ThrowDPXReaderException(CorruptImageError,ImproperImageHeader,image);
2353
0
            }
2354
2.50k
          samples_per_pixel=DPXSamplesPerPixel(element_descriptor);
2355
2.50k
          samples_per_row=samples_per_pixel*image->columns;
2356
2.50k
          element_size=DPXRowOctets(image->rows,samples_per_row,
2357
2.50k
                                    bits_per_sample,packing_method);
2358
2.50k
          file_size_estimate += element_size;
2359
2.50k
        }
2360
1.31k
      if (image->logging)
2361
1.31k
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2362
1.31k
                              "File size estimate %" MAGICK_OFF_F
2363
1.31k
                              "u bytes (have %" MAGICK_OFF_F "u bytes)",
2364
1.31k
                              file_size_estimate, (magick_off_t) file_size);
2365
1.31k
      if ((file_size_estimate <= 0) || (file_size < file_size_estimate))
2366
1.24k
        ThrowDPXReaderException(CorruptImageError,InsufficientImageDataInFile,image);
2367
1.24k
    }
2368
2369
  /*
2370
    Read remainder of header.
2371
  */
2372
1.54M
  for ( ; offset < pixels_offset ; offset++ )
2373
1.53M
    if (ReadBlobByte(image) == EOF)
2374
1.24k
      ThrowDPXReaderException(CorruptImageError,UnexpectedEndOfFile,image);
2375
2376
  /*
2377
    Allocate sample translation map storage.
2378
  */
2379
1.24k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2380
1.24k
                        "Maximum number of bits per sample in any element: %u",
2381
1.24k
                        max_bits_per_sample);
2382
1.24k
  map_Y=MagickAllocateResourceLimitedArray(Quantum *,
2383
1.24k
                            (size_t)MaxValueGivenBits(max_bits_per_sample)+1,
2384
1.24k
                            sizeof(Quantum));
2385
1.24k
  if (map_Y == (Quantum *) NULL)
2386
1.24k
    ThrowDPXReaderException(ResourceLimitError,MemoryAllocationFailed,image);
2387
2388
1.24k
  map_CbCr=MagickAllocateResourceLimitedArray(Quantum *,
2389
1.24k
                               (size_t)MaxValueGivenBits(max_bits_per_sample)+1,
2390
1.24k
                               sizeof(Quantum));
2391
1.24k
  if (map_CbCr == (Quantum *) NULL)
2392
1.24k
    ThrowDPXReaderException(ResourceLimitError,MemoryAllocationFailed,image);
2393
  /*
2394
    Allocate per-thread-view row samples.
2395
  */
2396
1.24k
  samples_set=AllocateThreadViewDataArray(image,exception,image->columns,
2397
1.24k
                                          MagickArraySize(max_samples_per_pixel,
2398
1.24k
                                                          sizeof(sample_t)));
2399
1.24k
  if (samples_set == (ThreadViewDataSet *) NULL)
2400
1.24k
    ThrowDPXReaderException(ResourceLimitError,MemoryAllocationFailed,image);
2401
  /*
2402
    Allocate per-thread-view scanline storage.
2403
  */
2404
1.24k
  scanline_set=AllocateThreadViewDataArray(image,exception,image->columns,
2405
1.24k
                                           MagickArraySize(max_samples_per_pixel,
2406
1.24k
                                                           sizeof(U32)));
2407
1.24k
  if (scanline_set == (ThreadViewDataSet *) NULL)
2408
1.24k
    ThrowDPXReaderException(ResourceLimitError,MemoryAllocationFailed,image);
2409
  /*
2410
    Allow user to over-ride pixel endianness.
2411
  */
2412
1.24k
  if ((definition_value=AccessDefinition(image_info,"dpx","pixel-endian")))
2413
0
    {
2414
0
      if (LocaleCompare(definition_value,"msb") == 0)
2415
0
        endian_type=MSBEndian;
2416
0
      else if (LocaleCompare(definition_value,"lsb") == 0)
2417
0
        endian_type=LSBEndian;
2418
0
    }
2419
  /*
2420
    Convert DPX raster image to pixel packets.
2421
  */
2422
3.34k
  for (element=0; element < dpx_image_info.elements; element++)
2423
2.13k
    {
2424
2.13k
      unsigned long
2425
2.13k
        row_count=0;
2426
2427
2.13k
      MagickBool
2428
2.13k
        swap_word_datums = MagickFalse;
2429
2430
      /* if (image->logging) */
2431
      /*   DescribeDPXImageElement(&dpx_image_info.element_info[element],element+1); */
2432
      /*
2433
        Move to element data
2434
      */
2435
2.13k
      if (!IS_UNDEFINED_U32(dpx_image_info.element_info[element].data_offset) &&
2436
1.99k
          (dpx_image_info.element_info[element].data_offset != 0U))
2437
1.65k
        {
2438
1.65k
          pixels_offset=dpx_image_info.element_info[element].data_offset & 0xFFFFFFFF;
2439
1.65k
          if (image->logging)
2440
1.65k
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2441
1.65k
                                  "Seek from %" MAGICK_SIZE_T_F "u to %lu...",
2442
1.65k
                                  (MAGICK_SIZE_T) offset, pixels_offset);
2443
1.65k
          if (pixels_offset >= offset)
2444
522
            {
2445
              /* Data is at, or ahead of current position.  Good! */
2446
7.92M
              for ( ; offset < pixels_offset ; offset++ )
2447
7.92M
                if (ReadBlobByte(image) == EOF)
2448
34
                  break;
2449
522
            }
2450
1.13k
          else
2451
1.13k
            {
2452
              /* Data is behind current position.  Bad! */
2453
1.13k
              if (image->logging)
2454
1.13k
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2455
1.13k
                                      "Seek backward to %lu...", pixels_offset);
2456
1.13k
              offset=SeekBlob(image,(magick_off_t) pixels_offset,SEEK_SET);
2457
1.13k
            }
2458
2459
          /* Verify that we reached our offset objective */
2460
1.65k
          if ( pixels_offset != offset)
2461
34
            {
2462
34
              if (image->logging)
2463
34
                (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2464
34
                                      "Failed to seek to data offset %lu"
2465
34
                                      " (have %" MAGICK_SIZE_T_F "u)",
2466
34
                                      pixels_offset, (MAGICK_SIZE_T) offset);
2467
34
              ThrowDPXReaderException(BlobError,UnableToSeekToOffset,image);
2468
0
            }
2469
1.61k
          if (EOFBlob(image))
2470
1.61k
            ThrowDPXReaderException(CorruptImageError,UnexpectedEndOfFile,image);
2471
1.61k
        }
2472
2.10k
      bits_per_sample=dpx_image_info.element_info[element].bits_per_sample;
2473
2.10k
      element_descriptor=(DPXImageElementDescriptor)
2474
2.10k
        dpx_image_info.element_info[element].descriptor;
2475
2.10k
      transfer_characteristic=
2476
2.10k
        (DPXTransferCharacteristic) dpx_image_info.element_info[element].transfer_characteristic;
2477
2.10k
      packing_method=(ImageComponentPackingMethod) dpx_image_info.element_info[element].packing;
2478
      /*
2479
        Allow the user to over-ride the packing method specified by the header.
2480
      */
2481
2.10k
      if ((definition_value=AccessDefinition(image_info,"dpx","packing-method")))
2482
0
        {
2483
0
          if (LocaleCompare(definition_value,"packed") == 0)
2484
0
            {
2485
0
              packing_method=PackingMethodPacked;
2486
0
            }
2487
0
          else if ((bits_per_sample == 10) || (bits_per_sample == 12))
2488
0
            {
2489
0
              if ((LocaleCompare(definition_value,"lsbpad") == 0) ||
2490
0
                  (LocaleCompare(definition_value,"a") == 0))
2491
0
                packing_method=PackingMethodWordsFillLSB;
2492
0
              else if ((LocaleCompare(definition_value,"msbpad") == 0) ||
2493
0
                       (LocaleCompare(definition_value,"b") == 0))
2494
0
                packing_method=PackingMethodWordsFillMSB;
2495
0
            }
2496
0
        }
2497
      /*
2498
        Decide if the image is grayscale and monochrome.
2499
      */
2500
2.10k
      if (IsGrayColorspace(image->colorspace))
2501
1.07k
        {
2502
1.07k
          is_grayscale=MagickTrue;
2503
1.07k
        }
2504
2.10k
      if ((is_grayscale) && (bits_per_sample == 1))
2505
246
        {
2506
246
          is_monochrome=MagickTrue;
2507
246
        }
2508
      /*
2509
        Are datums returned in reverse order when extracted from a
2510
        32-bit word?  This is to support Note 2 in Table 1 which
2511
        describes how RGB/RGBA are returned in reversed order for the
2512
        10-bit "filled" format.  Note 3 refers to Note 2 so presumably
2513
        the same applies for ABGR.  The majority of YCbCr 4:2:2 files
2514
        received have been swapped (but not YCbCr 4:4:4 for some
2515
        reason) so swap the samples for YCbCr as well.
2516
      */
2517
2.10k
      if ((element_descriptor == ImageElementRGB) ||
2518
1.96k
          (element_descriptor == ImageElementRGBA) ||
2519
1.88k
          (element_descriptor == ImageElementABGR) ||
2520
1.81k
          (element_descriptor == ImageElementCbYCrY422) ||
2521
1.62k
          (element_descriptor == ImageElementCbYACrYA4224) ||
2522
1.55k
          (element_descriptor == ImageElementCbYCr444) ||
2523
1.44k
          (element_descriptor == ImageElementCbYCrA4444))
2524
721
        {
2525
721
          if ((bits_per_sample == 10) && (packing_method != PackingMethodPacked))
2526
47
            swap_word_datums = MagickTrue;
2527
721
        }
2528
2.10k
      if ((definition_value=AccessDefinition(image_info,"dpx","swap-samples")) ||
2529
2.10k
          (definition_value=AccessDefinition(image_info,"dpx","swap-samples-read")))
2530
0
        {
2531
0
          if (LocaleCompare(definition_value,"false") != 0)
2532
0
            swap_word_datums = swap_word_datums ? MagickFalse : MagickTrue;
2533
0
        }
2534
      /*
2535
        Determine number of samples per pixel element.
2536
      */
2537
2.10k
      samples_per_pixel=DPXSamplesPerPixel(element_descriptor);
2538
2.10k
      if (samples_per_pixel != 0)
2539
2.10k
        {
2540
2.10k
          double
2541
2.10k
            max_value,
2542
2.10k
            reference_low,
2543
2.10k
            reference_high,
2544
2.10k
            scale_to_quantum;           /* multiplier to scale to Quantum */
2545
2546
2.10k
          max_value = (double) MaxValueGivenBits(bits_per_sample);
2547
2.10k
          reference_low = 0.0;
2548
2.10k
          reference_high = max_value;
2549
2.10k
          scale_to_quantum=MaxRGBDouble/max_value;
2550
2551
          /*
2552
            Is this a video type space?
2553
          */
2554
2.10k
          if (IsYCbCrColorspace(image->colorspace) ||
2555
1.39k
              (image->colorspace == Rec601LumaColorspace) ||
2556
1.08k
              (image->colorspace == Rec709LumaColorspace))
2557
1.22k
            {
2558
1.22k
              double
2559
1.22k
                reference_low_prop,
2560
1.22k
                reference_high_prop,
2561
1.22k
                ScaleY = 0.0,
2562
1.22k
                ScaleCbCr = 0.0;
2563
2564
              /*
2565
                Establish YCbCr video defaults.
2566
                8 bit ==> Luma 16 to 235
2567
                10 bit ==> Luma 64 to 940
2568
              */
2569
1.22k
              reference_low = ((max_value+1.0) * (64.0/1024.0));
2570
1.22k
              reference_high = ((max_value+1.0) * (940.0/1024.0));
2571
2572
1.22k
              reference_low_prop = reference_low;
2573
1.22k
              reference_high_prop = reference_high;
2574
2575
1.22k
              if (!IS_UNDEFINED_U32(dpx_image_info.element_info[element].reference_low_data_code))
2576
1.19k
                reference_low_prop=dpx_image_info.element_info[element].reference_low_data_code;
2577
1.22k
              if ((definition_value=AccessDefinition(image_info,"dpx","reference-low")))
2578
0
                reference_low_prop=(double) strtol(definition_value, (char **)NULL, 10);
2579
2580
1.22k
              if (!IS_UNDEFINED_U32(dpx_image_info.element_info[element].reference_high_data_code))
2581
1.13k
                reference_high_prop=dpx_image_info.element_info[element].reference_high_data_code;
2582
1.22k
              if ((definition_value=AccessDefinition(image_info,"dpx","reference-high")))
2583
0
                reference_high_prop=(double) strtol(definition_value, (char **)NULL, 10);
2584
2585
1.22k
              if ((reference_high_prop > reference_low_prop) &&
2586
658
                  (reference_high_prop > MagickEpsilon))
2587
658
                {
2588
658
                  reference_low = reference_low_prop;
2589
658
                  reference_high = reference_high_prop;
2590
658
                }
2591
2592
1.22k
              ScaleY = ((max_value+1.0)/(reference_high-reference_low));
2593
1.22k
              ScaleCbCr = ScaleY*((940.0-64.0)/(960.0-64.0));
2594
1.22k
              reference_low=reference_low*scale_to_quantum;
2595
2596
8.00M
              for(i=0; i <= (unsigned long) max_value; i++)
2597
8.00M
                {
2598
8.00M
                  map_Y[i] = ScaleFromVideo(i*scale_to_quantum,reference_low,ScaleY);
2599
8.00M
                  map_CbCr[i] = ScaleFromVideo(i*scale_to_quantum,reference_low,ScaleCbCr);
2600
8.00M
                }
2601
1.22k
            }
2602
876
          else
2603
876
            {
2604
6.09M
              for(i=0; i <= (unsigned long) max_value; i++)
2605
6.09M
                map_Y[i]=scale_to_quantum*i+0.5;
2606
876
            }
2607
2608
          /*
2609
            Compute samples per row.
2610
          */
2611
2.10k
          samples_per_row=samples_per_pixel*image->columns;
2612
          /*
2613
            Compute octets per row.
2614
          */
2615
2.10k
          row_octets=DPXRowOctets(1,samples_per_row,bits_per_sample,packing_method);
2616
2.10k
          if (image->logging)
2617
2.10k
            {
2618
              /*
2619
                Compute element size.
2620
              */
2621
2.10k
              element_size=DPXRowOctets(image->rows,samples_per_row,
2622
2.10k
                                        bits_per_sample,packing_method);
2623
2624
2.10k
              (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2625
2.10k
                                    "Samples per row %u, octets per row %lu, element size %lu",
2626
2.10k
                                    samples_per_row, (unsigned long) row_octets,
2627
2.10k
                                    (unsigned long) element_size);
2628
2.10k
            }
2629
2630
          /*
2631
            Read element data.
2632
          */
2633
#if defined(HAVE_OPENMP) && !defined(DisableSlowOpenMP)
2634
#  if defined(TUNE_OPENMP)
2635
#    pragma omp parallel for schedule(runtime)
2636
#  else
2637
#    pragma omp parallel for schedule(static,1)
2638
#  endif
2639
#endif
2640
242k
          for (y=0; y < (long) image->rows; y++)
2641
240k
            {
2642
240k
              MagickBool
2643
240k
                thread_status;
2644
2645
240k
              register long
2646
240k
                x;
2647
2648
240k
              register PixelPacket
2649
240k
                *q;
2650
2651
240k
              sample_t
2652
240k
                *samples_itr;               /* current sample */
2653
2654
240k
              PixelPacket
2655
240k
                *pixels=(PixelPacket *) NULL;
2656
2657
240k
              sample_t
2658
240k
                *samples;                   /* parsed sample array */
2659
2660
240k
              unsigned char
2661
240k
                *scanline;
2662
2663
240k
              unsigned long
2664
240k
                thread_row_count;
2665
2666
#if defined(HAVE_OPENMP) && !defined(DisableSlowOpenMP)
2667
#  pragma omp critical (GM_ReadDPXImage)
2668
#endif
2669
240k
              thread_status=status;
2670
240k
              if (thread_status == MagickFail)
2671
30.9k
                continue;
2672
2673
209k
              samples=AccessThreadViewData(samples_set);
2674
209k
              scanline=AccessThreadViewData(scanline_set);
2675
2676
              /*
2677
                Obtain a row's worth of samples.
2678
              */
2679
209k
              {
2680
209k
                void
2681
209k
                  *scanline_data;
2682
2683
209k
                scanline_data=scanline;
2684
#if defined(HAVE_OPENMP) && !defined(DisableSlowOpenMP)
2685
#  pragma omp critical (GM_ReadDPXImage)
2686
#endif
2687
209k
                {
2688
209k
                  if (ReadBlobZC(image,row_octets,&scanline_data) != row_octets)
2689
132
                    {
2690
132
                      ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,
2691
132
                                     image->filename);
2692
132
                      thread_status=MagickFail;
2693
132
                    }
2694
2695
209k
                  thread_row_count=row_count;
2696
209k
                  row_count++;
2697
209k
                  if (QuantumTick(thread_row_count,image->rows))
2698
40.0k
                    if (!MagickMonitorFormatted(thread_row_count,image->rows,exception,
2699
40.0k
                                                LoadImageText,image->filename,
2700
40.0k
                                                image->columns,image->rows))
2701
0
                      thread_status=MagickFail;
2702
209k
                }
2703
2704
209k
                if (thread_status != MagickFail)
2705
208k
                  ReadRowSamples((const unsigned char*) scanline_data,samples_per_row,bits_per_sample,
2706
208k
                                 packing_method,endian_type,swap_word_datums,samples);
2707
209k
              }
2708
2709
209k
              if (thread_status != MagickFail)
2710
208k
                {
2711
208k
                  if (element == 0)
2712
145k
                    pixels=SetImagePixelsEx(image,0,thread_row_count,image->columns,1,exception);
2713
62.9k
                  else
2714
62.9k
                    pixels=GetImagePixelsEx(image,0,thread_row_count,image->columns,1,exception);
2715
208k
                }
2716
2717
209k
              if (pixels == (PixelPacket *) NULL)
2718
132
                thread_status=MagickFail;
2719
2720
              /*
2721
                The matte channel needs explicit
2722
                initialization if planar image does not
2723
                provide an alpha channel.
2724
              */
2725
209k
              if (thread_status != MagickFail)
2726
208k
                {
2727
208k
                  if (element == 0)
2728
145k
                    {
2729
145k
                      if (matte_init)
2730
796
                        {
2731
796
                          q = pixels;
2732
15.6k
                          for (x=image->columns; x != 0; x--)
2733
14.8k
                            {
2734
14.8k
                              SetOpacitySample(q++,OpaqueOpacity);
2735
14.8k
                            }
2736
796
                        }
2737
145k
                    }
2738
208k
                }
2739
2740
209k
              if (thread_status == MagickFail)
2741
132
                {
2742
#if defined(HAVE_OPENMP) && !defined(DisableSlowOpenMP)
2743
#  pragma omp critical (GM_ReadDPXImage)
2744
#endif
2745
132
                  status=thread_status;
2746
132
                  continue;
2747
132
                }
2748
2749
              /*
2750
                Assign samples to pixels.
2751
              */
2752
208k
              q = pixels;
2753
208k
              samples_itr=samples;
2754
208k
              switch (element_descriptor)
2755
208k
                {
2756
5.21k
                case ImageElementRed:
2757
211k
                  for (x=image->columns; x != 0; x--)
2758
206k
                    {
2759
206k
                      SetRedSample(q++,map_Y[*samples_itr++]);
2760
206k
                    }
2761
5.21k
                  break;
2762
1.31k
                case ImageElementGreen:
2763
17.8k
                  for (x=image->columns; x != 0; x--)
2764
16.5k
                    {
2765
16.5k
                      SetGreenSample(q++,map_Y[*samples_itr++]);
2766
16.5k
                    }
2767
1.31k
                  break;
2768
6.24k
                case ImageElementBlue:
2769
25.8k
                  for (x=image->columns; x != 0; x--)
2770
19.5k
                    {
2771
19.5k
                      SetBlueSample(q++,map_Y[*samples_itr++]);
2772
19.5k
                    }
2773
6.24k
                  break;
2774
45.5k
                case ImageElementAlpha:
2775
257k
                  for (x=image->columns; x != 0; x--)
2776
212k
                    {
2777
212k
                      SetOpacitySample(q++,map_Y[*samples_itr++]);
2778
212k
                    }
2779
45.5k
                  break;
2780
0
                case ImageElementUnspecified:
2781
76.1k
                case ImageElementLuma:
2782
76.1k
                  if (IsYCbCrColorspace(image->colorspace))
2783
693
                    {
2784
                      /* Video Luma (planar) */
2785
18.8k
                      for (x=image->columns; x != 0; x--)
2786
18.1k
                        {
2787
18.1k
                          SetRedSample(q,map_Y[*samples_itr++]);
2788
18.1k
                          q++;
2789
18.1k
                        }
2790
693
                    }
2791
75.4k
                  else
2792
75.4k
                    {
2793
                      /* Video Luma or Linear Grayscale */
2794
10.3M
                      for (x=image->columns; x != 0; x--)
2795
10.2M
                        {
2796
10.2M
                          SetGraySample(q,map_Y[*samples_itr++]);
2797
10.2M
                          if (!image->matte)
2798
9.90M
                            SetOpacitySample(q,OpaqueOpacity);
2799
10.2M
                          q++;
2800
10.2M
                        }
2801
75.4k
                    }
2802
76.1k
                  break;
2803
680
                case ImageElementColorDifferenceCbCr:
2804
680
                  {
2805
                    /* CbCr 4:2:2 sampling */
2806
9.03k
                    for (x=image->columns; x > 0; x -= 2)
2807
8.35k
                      {
2808
8.35k
                        Quantum
2809
8.35k
                          Cb,
2810
8.35k
                          Cr;
2811
2812
8.35k
                        Cb=map_CbCr[*samples_itr++]; /* Cb */
2813
8.35k
                        Cr=map_CbCr[*samples_itr++]; /* Cr */
2814
2815
8.35k
                        SetCbSample(q,Cb);  /* Cb */
2816
8.35k
                        SetCrSample(q,Cr);  /* Cr */
2817
8.35k
                        q++;
2818
2819
8.35k
                        SetCbSample(q,Cb);  /* Cb (false) */
2820
8.35k
                        SetCrSample(q,Cr);  /* Cr (false) */
2821
8.35k
                        q++;
2822
8.35k
                      }
2823
680
                    TentUpsampleChroma(pixels,image->columns);
2824
680
                    break;
2825
0
                  }
2826
1.43k
                case ImageElementRGB:
2827
                  /* RGB order */
2828
468k
                  for (x=image->columns; x != 0; x--)
2829
467k
                    {
2830
467k
                      SetRedSample(q,map_Y[*samples_itr++]);
2831
467k
                      SetGreenSample(q,map_Y[*samples_itr++]);
2832
467k
                      SetBlueSample(q,map_Y[*samples_itr++]);
2833
467k
                      if (!image->matte)
2834
466k
                        SetOpacitySample(q,OpaqueOpacity);
2835
467k
                      q++;
2836
467k
                    }
2837
1.43k
                  break;
2838
5.54k
                case ImageElementRGBA:
2839
                  /* RGB order */
2840
629k
                  for (x=image->columns; x != 0; x--)
2841
623k
                    {
2842
623k
                      SetRedSample(q,map_Y[*samples_itr++]);
2843
623k
                      SetGreenSample(q,map_Y[*samples_itr++]);
2844
623k
                      SetBlueSample(q,map_Y[*samples_itr++]);
2845
623k
                      SetOpacitySample(q,map_Y[*samples_itr++]);
2846
623k
                      q++;
2847
623k
                    }
2848
5.54k
                  break;
2849
273
                case ImageElementABGR:
2850
                  /* ARGB order */
2851
9.53k
                  for (x=image->columns; x != 0; x--)
2852
9.26k
                    {
2853
9.26k
                      SetOpacitySample(q,map_Y[*samples_itr++]);
2854
9.26k
                      SetRedSample(q,map_Y[*samples_itr++]);
2855
9.26k
                      SetGreenSample(q,map_Y[*samples_itr++]);
2856
9.26k
                      SetBlueSample(q,map_Y[*samples_itr++]);
2857
9.26k
                      q++;
2858
9.26k
                    }
2859
273
                  break;
2860
26.0k
                case ImageElementCbYCrY422:
2861
26.0k
                  {
2862
                    /* CbY | CrY | CbY | CrY ..., even number of columns required. */
2863
4.17M
                    for (x=image->columns; x > 0; x -= 2)
2864
4.14M
                      {
2865
4.14M
                        Quantum
2866
4.14M
                          Cb,
2867
4.14M
                          Cr,
2868
4.14M
                          Y0,
2869
4.14M
                          Y1;
2870
2871
4.14M
                        Cb=map_CbCr[*samples_itr++]; /* Cb */
2872
4.14M
                        Y0=map_Y[*samples_itr++];    /* Y0 */
2873
4.14M
                        Cr=map_CbCr[*samples_itr++]; /* Cr */
2874
4.14M
                        Y1=map_Y[*samples_itr++];    /* Y1 */
2875
2876
4.14M
                        SetYSample(q,Y0);   /* Y0 */
2877
4.14M
                        SetCbSample(q,Cb);  /* Cb */
2878
4.14M
                        SetCrSample(q,Cr);  /* Cr */
2879
4.14M
                        if (!image->matte)
2880
4.14M
                          SetOpacitySample(q,OpaqueOpacity);
2881
4.14M
                        q++;
2882
2883
4.14M
                        SetYSample(q,Y1);   /* Y1 */
2884
4.14M
                        SetCbSample(q,Cb) ; /* Cb (false) */
2885
4.14M
                        SetCrSample(q,Cr);  /* Cr (false) */
2886
4.14M
                        if (!image->matte)
2887
4.14M
                          q->opacity=OpaqueOpacity;
2888
4.14M
                        q++;
2889
4.14M
                      }
2890
26.0k
                    TentUpsampleChroma(pixels,image->columns);
2891
26.0k
                    break;
2892
0
                  }
2893
1.14k
                case ImageElementCbYACrYA4224:
2894
1.14k
                  {
2895
                    /* CbYA | CrYA ..., even number of columns required. */
2896
199k
                    for (x=image->columns; x > 0; x -= 2)
2897
198k
                      {
2898
198k
                        Quantum
2899
198k
                          A0,
2900
198k
                          A1,
2901
198k
                          Cb,
2902
198k
                          Cr,
2903
198k
                          Y0,
2904
198k
                          Y1;
2905
2906
198k
                        Cb=map_CbCr[*samples_itr++];
2907
198k
                        Y0=map_Y[*samples_itr++];
2908
198k
                        A0=map_Y[*samples_itr++];
2909
2910
198k
                        Cr=map_CbCr[*samples_itr++];
2911
198k
                        Y1=map_Y[*samples_itr++];
2912
198k
                        A1=map_Y[*samples_itr++];
2913
2914
198k
                        SetYSample(q,Y0);       /* Y0 */
2915
198k
                        SetCbSample(q,Cb);      /* Cb */
2916
198k
                        SetCrSample(q,Cr);      /* Cr */
2917
198k
                        SetOpacitySample(q,A0); /* A0 */
2918
198k
                        q++;
2919
2920
198k
                        SetYSample(q,Y1);       /* Y1 */
2921
198k
                        SetCbSample(q,Cb);      /* Cb (false) */
2922
198k
                        SetCrSample(q,Cr);      /* Cr (false) */
2923
198k
                        SetOpacitySample(q,A1); /* A1 */
2924
198k
                        q++;
2925
198k
                      }
2926
1.14k
                    TentUpsampleChroma(pixels,image->columns);
2927
1.14k
                    break;
2928
0
                  }
2929
32.7k
                case ImageElementCbYCr444:
2930
32.7k
                  {
2931
                    /* red,green,blue = Y, Cb, Cr */
2932
20.1M
                    for (x=image->columns; x != 0; x--)
2933
20.0M
                      {
2934
20.0M
                        SetCbSample(q,map_CbCr[*samples_itr++]); /* Cb */
2935
20.0M
                        SetYSample(q,map_Y[*samples_itr++]);     /* Y */
2936
20.0M
                        SetCrSample(q,map_CbCr[*samples_itr++]); /* Cr */
2937
20.0M
                        if (!image->matte)
2938
20.0M
                          SetOpacitySample(q,OpaqueOpacity);      /* A */
2939
20.0M
                        q++;
2940
20.0M
                      }
2941
32.7k
                    break;
2942
0
                  }
2943
6.63k
                case ImageElementCbYCrA4444:
2944
6.63k
                  {
2945
                    /* red,green,blue = Y, Cb, Cr */
2946
454k
                    for (x=image->columns; x != 0; x--)
2947
447k
                      {
2948
447k
                        SetCbSample(q,map_CbCr[*samples_itr++]);   /* Cb */
2949
447k
                        SetYSample(q,map_Y[*samples_itr++]);       /* Y */
2950
447k
                        SetCrSample(q,map_CbCr[*samples_itr++]);   /* Cr */
2951
447k
                        SetOpacitySample(q,map_Y[*samples_itr++]); /* A */
2952
447k
                        q++;
2953
447k
                      }
2954
6.63k
                    break;
2955
0
                  }
2956
0
                default:
2957
0
                  break;
2958
208k
                }
2959
2960
208k
              if (!SyncImagePixelsEx(image,exception))
2961
0
                thread_status=MagickFail;
2962
2963
              /*
2964
                FIXME: Add support for optional EOL padding.
2965
              */
2966
208k
              if (thread_status == MagickFail)
2967
#if defined(HAVE_OPENMP) && !defined(DisableSlowOpenMP)
2968
#  pragma omp critical (GM_ReadDPXImage)
2969
#endif
2970
0
                status=MagickFail;
2971
#if 0
2972
              if (BlobIsSeekable(image))
2973
                {
2974
                  magick_off_t reported_file_offset = TellBlob(image);
2975
                  if (EOFBlob(image))
2976
                    {
2977
                      (void) fprintf(stderr,"### File length %u, TellBlob says %" MAGICK_OFF_F "d\n",
2978
                                     dpx_file_info.file_size,
2979
                                     (magick_off_t) reported_file_offset);
2980
                      break;
2981
                    }
2982
                }
2983
#endif
2984
208k
            }
2985
          /* break; */
2986
2.10k
        }
2987
0
      else
2988
0
        {
2989
0
          ThrowDPXReaderException(CoderError,ColorTypeNotSupported,image);
2990
0
        }
2991
2.10k
    }
2992
2993
1.20k
  if (status != MagickPass)
2994
1.08k
    ThrowDPXReaderException(CorruptImageError,CorruptImage,image);
2995
2996
1.08k
  if (EOFBlob(image))
2997
0
    ThrowDPXReaderException(CorruptImageError,UnexpectedEndOfFile,
2998
1.08k
                            image);
2999
3000
  /*
3001
    Support explicitly overriding the input file's colorspace.  Mostly
3002
    useful for testing.
3003
  */
3004
1.08k
  if ((definition_value=AccessDefinition(image_info,"dpx","colorspace")))
3005
0
    {
3006
0
      ColorspaceType
3007
0
        colorspace;
3008
3009
0
      colorspace=StringToColorspaceType(definition_value);
3010
0
      if (colorspace != UndefinedColorspace)
3011
0
        {
3012
0
          image->colorspace=colorspace;
3013
0
          if (image->logging)
3014
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3015
0
                                  "Explicitly set colorspace to %s",
3016
0
                                  ColorspaceTypeToString(image->colorspace));
3017
0
        }
3018
0
      else
3019
0
        {
3020
0
          if (image->logging)
3021
0
            (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3022
0
                                  "Unrecognized source colorspace \"%s\"\n",
3023
0
                                  definition_value);
3024
0
          ThrowException(&image->exception,OptionError,UnrecognizedColorspace,
3025
0
                         definition_value);
3026
0
        }
3027
0
    }
3028
3029
  /*
3030
    If image is YCbCr representing Cineon Log RGB, then return the image as
3031
    RGB in CineonLog colorspace.
3032
  */
3033
1.08k
  if (IsYCbCrColorspace(image->colorspace) &&
3034
326
      (transfer_characteristic == TransferCharacteristicPrintingDensity))
3035
137
    {
3036
137
      (void) TransformColorspace(image,RGBColorspace);
3037
137
      image->colorspace=CineonLogRGBColorspace;
3038
137
    }
3039
3040
1.08k
  image->is_monochrome=is_monochrome;
3041
1.08k
  image->is_grayscale=is_grayscale;
3042
1.08k
  image->depth=Min(QuantumDepth,image->depth);
3043
1.08k
  MagickFreeResourceLimitedMemory(map_CbCr);
3044
1.08k
  MagickFreeResourceLimitedMemory(map_Y);
3045
1.08k
  DestroyThreadViewDataSet(scanline_set);
3046
1.08k
  DestroyThreadViewDataSet(samples_set);
3047
1.08k
  StopTimer(&image->timer);
3048
1.08k
  CloseBlob(image);
3049
1.08k
  return(image);
3050
1.08k
}
3051

3052
/*
3053
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3054
%                                                                             %
3055
%                                                                             %
3056
%                                                                             %
3057
%   R e g i s t e r D P X I m a g e                                           %
3058
%                                                                             %
3059
%                                                                             %
3060
%                                                                             %
3061
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3062
%
3063
%  Method RegisterDPXImage adds attributes for the DPX image format to
3064
%  the list of supported formats.  The attributes include the image format
3065
%  tag, a method to read and/or write the format, whether the format
3066
%  supports the saving of more than one frame to the same file or blob,
3067
%  whether the format supports native in-memory I/O, and a brief
3068
%  description of the format.
3069
%
3070
%  The format of the RegisterDPXImage method is:
3071
%
3072
%      RegisterDPXImage(void)
3073
%
3074
*/
3075
ModuleExport void RegisterDPXImage(void)
3076
5
{
3077
5
  MagickInfo
3078
5
    *entry;
3079
3080
5
  entry=SetMagickInfo("DPX");
3081
5
  entry->decoder=(DecoderHandler) ReadDPXImage;
3082
5
  entry->encoder=(EncoderHandler) WriteDPXImage;
3083
5
  entry->magick=(MagickHandler) IsDPX;
3084
5
  entry->description="SMPTE 268M-2003 (DPX 2.0)";
3085
5
  entry->note="See http://www.smtpe.org/ for information on DPX.";
3086
5
  entry->module="DPX";
3087
5
  entry->adjoin=MagickFalse; /* Only one frame per file */
3088
5
  entry->seekable_stream=MagickFalse; /* Does not reqire seek() */
3089
5
  entry->coder_class=PrimaryCoderClass;
3090
5
  (void) RegisterMagickInfo(entry);
3091
5
}
3092

3093
/*
3094
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3095
%                                                                             %
3096
%                                                                             %
3097
%                                                                             %
3098
%   U n r e g i s t e r D P X I m a g e                                       %
3099
%                                                                             %
3100
%                                                                             %
3101
%                                                                             %
3102
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3103
%
3104
%  Method UnregisterDPXImage removes format registrations made by the
3105
%  DPX module from the list of supported formats.
3106
%
3107
%  The format of the UnregisterDPXImage method is:
3108
%
3109
%      UnregisterDPXImage(void)
3110
%
3111
*/
3112
ModuleExport void UnregisterDPXImage(void)
3113
0
{
3114
0
  (void) UnregisterMagickInfo("DPX");
3115
0
}
3116

3117
/*
3118
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3119
%                                                                             %
3120
%                                                                             %
3121
%                                                                             %
3122
%   W r i t e D P X I m a g e                                                 %
3123
%                                                                             %
3124
%                                                                             %
3125
%                                                                             %
3126
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3127
%
3128
%  Method WriteDPXImage writes an image in DPX encoded image format.
3129
%
3130
%  The format of the WriteDPXImage method is:
3131
%
3132
%      unsigned int WriteDPXImage(const ImageInfo *image_info,Image *image)
3133
%
3134
%  A description of each parameter follows.
3135
%
3136
%    o status: Method WriteDPXImage return True if the image is written.
3137
%      False is returned is there is a memory shortage or if the image file
3138
%      fails to write.
3139
%
3140
%    o image_info: Specifies a pointer to a ImageInfo structure.
3141
%
3142
%    o image:  A pointer to an Image structure.
3143
%
3144
%
3145
*/
3146
STATIC void GenerateDPXTimeStamp(char *timestamp, size_t maxsize)
3147
1.07k
{
3148
1.07k
  time_t
3149
1.07k
    current_time;
3150
3151
1.07k
#if defined(HAVE_LOCALTIME_R)
3152
1.07k
  struct tm
3153
1.07k
    tm_buf;
3154
1.07k
#endif /* if defined(HAVE_LOCALTIME_R) */
3155
3156
1.07k
  const struct tm
3157
1.07k
    *t;
3158
3159
1.07k
  char *
3160
1.07k
    p;
3161
3162
1.07k
  current_time=time((time_t *) NULL);
3163
1.07k
#if defined(HAVE_LOCALTIME_R)
3164
1.07k
  t=localtime_r(&current_time, &tm_buf);
3165
#else
3166
  t=localtime(&current_time); /* Thread-unsafe version */
3167
#endif  /* if defined(HAVE_LOCALTIME_R) */
3168
3169
1.07k
  (void) strftime(timestamp,maxsize,"%Y:%m:%d:%H:%M:%S%Z",t);
3170
1.07k
  timestamp[maxsize-1]='\0';
3171
24.7k
  for (p=timestamp ; *p != '\0'; p++)
3172
23.6k
    if (*p == ' ')
3173
0
      *p='0';
3174
1.07k
}
3175
3176
STATIC U16 OrientationTypeToDPXOrientation(const OrientationType orientation_type)
3177
1.07k
{
3178
1.07k
  U16
3179
1.07k
    orientation = 0U;
3180
3181
1.07k
  switch (orientation_type)
3182
1.07k
    {
3183
0
    case UndefinedOrientation:
3184
162
    case TopLeftOrientation:
3185
162
      orientation=0U;
3186
162
      break;
3187
8
    case TopRightOrientation:
3188
8
      orientation=1U;
3189
8
      break;
3190
17
    case BottomLeftOrientation:
3191
17
      orientation=2U;
3192
17
      break;
3193
1
    case BottomRightOrientation:
3194
1
      orientation=3U;
3195
1
      break;
3196
829
    case LeftTopOrientation:
3197
829
      orientation=4U;
3198
829
      break;
3199
32
    case RightTopOrientation:
3200
32
      orientation=5U;
3201
32
      break;
3202
19
    case LeftBottomOrientation:
3203
19
      orientation=6U;
3204
19
      break;
3205
7
    case RightBottomOrientation:
3206
7
      orientation=7U;
3207
7
      break;
3208
1.07k
    }
3209
1.07k
  return orientation;
3210
1.07k
}
3211
3212
0
#define LSBPackedU32WordToOctets(packed_u32,scanline) \
3213
0
do { \
3214
0
  *scanline++=(unsigned char) ((packed_u32) & 0xFF); \
3215
0
  *scanline++=(unsigned char) ((packed_u32 >> 8) & 0xFF); \
3216
0
  *scanline++=(unsigned char) ((packed_u32 >> 16) & 0xFF); \
3217
0
  *scanline++=(unsigned char) ((packed_u32 >> 24) & 0xFF); \
3218
0
 } while(0)
3219
230k
#define MSBPackedU32WordToOctets(packed_u32,scanline) \
3220
230k
do { \
3221
230k
  *scanline++=(unsigned char) ((packed_u32 >> 24) & 0xFF); \
3222
230k
  *scanline++=(unsigned char) ((packed_u32 >> 16) & 0xFF); \
3223
230k
  *scanline++=(unsigned char) ((packed_u32 >> 8) & 0xFF); \
3224
230k
  *scanline++=(unsigned char) ((packed_u32) & 0xFF); \
3225
230k
 } while(0)
3226
3227
/*
3228
  WordStreamLSBWrite support
3229
*/
3230
typedef struct _WriteWordU32State
3231
{
3232
  unsigned char *words;
3233
} WriteWordU32State;
3234
3235
STATIC size_t WriteWordU32BE (void *state, const unsigned long value)
3236
543k
{
3237
543k
  WriteWordU32State *write_state=(WriteWordU32State *) state;
3238
543k
  *write_state->words++ = (unsigned char) ((value >> 24) & 0xff);
3239
543k
  *write_state->words++ = (unsigned char) ((value >> 16) & 0xff);
3240
543k
  *write_state->words++ = (unsigned char) ((value >> 8) & 0xff);
3241
543k
  *write_state->words++ = (unsigned char) (value & 0xff);
3242
543k
  return sizeof(magick_uint32_t);
3243
543k
}
3244
3245
STATIC size_t WriteWordU32LE (void *state, const unsigned long value)
3246
0
{
3247
0
  WriteWordU32State *write_state=(WriteWordU32State *) state;
3248
0
  *write_state->words++ = (unsigned char) (value & 0xff);
3249
0
  *write_state->words++ = (unsigned char) ((value >> 8) & 0xff);
3250
0
  *write_state->words++ = (unsigned char) ((value >> 16) & 0xff);
3251
0
  *write_state->words++ = (unsigned char) ((value >> 24) & 0xff);
3252
0
  return sizeof(magick_uint32_t);
3253
0
}
3254
3255
/*
3256
  Encode row samples. Currently just one row but in the future may be
3257
                      multiple rows (e.g. 3).
3258
3259
  samples          -- unencoded samples (currently unsigned 16-bit).
3260
  samples_per_row  -- Number of samples to encode.
3261
  bits_per_sample  -- Number of bits in one decoded sample.
3262
  packing_method   -- Describes the way that samples are packed into enclosing words.
3263
  endian_type      -- The endian order of the enclosing words.
3264
  swap_word_datums -- Use alternate sample order (BGR vs RGB, CbYCr vs CrYCb) for
3265
                      samples filled into 32 bit words.
3266
  scanline         -- Raw output data (may be 8-bit, 16-bit, 32-bit, or 64-bit types)
3267
                      which represents the encoded pixels for one or more scanlines.
3268
                      Underlying input data type is properly aligned for access.
3269
*/
3270
STATIC void WriteRowSamples(const sample_t *samples,
3271
                            const unsigned int samples_per_row,
3272
                            const unsigned int bits_per_sample,
3273
                            const ImageComponentPackingMethod packing_method,
3274
                            const EndianType endian_type,
3275
                            const MagickBool swap_word_datums,
3276
                            unsigned char *scanline)
3277
114k
{
3278
114k
  register unsigned int
3279
114k
    i;
3280
3281
114k
  BitStreamWriteHandle
3282
114k
    bit_stream;
3283
3284
114k
  register unsigned char
3285
114k
    *sp;
3286
3287
114k
  register unsigned int
3288
114k
    sample;
3289
3290
114k
  sp=scanline;
3291
114k
  MagickBitStreamInitializeWrite(&bit_stream,scanline);
3292
3293
114k
  if ((packing_method != PackingMethodPacked) &&
3294
71.9k
      ((bits_per_sample == 10) || (bits_per_sample == 12)))
3295
71.9k
    {
3296
71.9k
      MagickBool
3297
71.9k
        word_pad_lsb=MagickFalse,
3298
71.9k
        word_pad_msb=MagickFalse;
3299
3300
71.9k
      if (packing_method == PackingMethodWordsFillLSB)
3301
71.9k
        word_pad_lsb=MagickTrue;
3302
0
      else if (packing_method == PackingMethodWordsFillMSB)
3303
0
        word_pad_msb=MagickTrue;
3304
3305
71.9k
      if (bits_per_sample == 10)
3306
63.6k
        {
3307
63.6k
          register magick_uint32_t
3308
63.6k
            packed_u32;
3309
3310
63.6k
          register unsigned int
3311
63.6k
            datum;
3312
3313
63.6k
          unsigned int
3314
63.6k
            shifts[3] = { 0, 0, 0 };
3315
3316
63.6k
          if (word_pad_lsb)
3317
63.6k
            {
3318
              /*
3319
                Padding in LSB (Method A)  Standard method.
3320
              */
3321
63.6k
              if (swap_word_datums == MagickFalse)
3322
54.5k
                {
3323
54.5k
                  shifts[0]=2;  /* datum-0 / blue */
3324
54.5k
                  shifts[1]=12; /* datum-1 / green */
3325
54.5k
                  shifts[2]=22; /* datum-2 / red */
3326
54.5k
                }
3327
9.09k
              else
3328
9.09k
                {
3329
9.09k
                  shifts[0]=22; /* datum-2 / red */
3330
9.09k
                  shifts[1]=12; /* datum-1 / green */
3331
9.09k
                  shifts[2]=2;  /* datum-0 / blue */
3332
9.09k
                }
3333
63.6k
            }
3334
0
          else if (word_pad_msb)
3335
0
            {
3336
              /*
3337
                Padding in MSB (Method B)  Deprecated method.
3338
              */
3339
0
              if (swap_word_datums == MagickFalse)
3340
0
                {
3341
0
                  shifts[0]=0;  /* datum-0 / blue */
3342
0
                  shifts[1]=10; /* datum-1 / green */
3343
0
                  shifts[2]=20; /* datum-2 / red */
3344
0
                }
3345
0
              else
3346
0
                {
3347
0
                  shifts[0]=20; /* datum-2 / red */
3348
0
                  shifts[1]=10; /* datum-1 / green */
3349
0
                  shifts[2]=0;  /* datum-0 / blue */
3350
0
                }
3351
0
            }
3352
3353
63.6k
          datum=0;
3354
63.6k
          packed_u32=0;
3355
63.6k
          if (endian_type == MSBEndian)
3356
63.6k
            {
3357
651k
              for (i=0; i < samples_per_row; i++)
3358
587k
                {
3359
587k
                  if (datum == 2)
3360
168k
                    {
3361
168k
                      MSBPackedU32WordToOctets(packed_u32,scanline);
3362
168k
                      packed_u32=0;
3363
168k
                    }
3364
587k
                  datum = i % 3;
3365
587k
                  packed_u32 |= (((magick_uint32_t) *samples++) << shifts[datum]);
3366
587k
                }
3367
63.6k
              if ((samples_per_row+1) % 3 )
3368
61.1k
                MSBPackedU32WordToOctets(packed_u32,scanline);
3369
63.6k
            }
3370
0
          else if (endian_type == LSBEndian)
3371
0
            {
3372
0
              for (i=0; i < samples_per_row; i++)
3373
0
                {
3374
0
                  if (datum == 2)
3375
0
                    {
3376
0
                      LSBPackedU32WordToOctets(packed_u32,scanline);
3377
0
                      packed_u32=0;
3378
0
                    }
3379
0
                  datum = i % 3;
3380
0
                  packed_u32 |= (((magick_uint32_t) *samples++) << shifts[datum]);
3381
0
                }
3382
0
              if ((samples_per_row+1) % 3 )
3383
0
                LSBPackedU32WordToOctets(packed_u32,scanline);
3384
0
            }
3385
63.6k
          return;
3386
63.6k
        }
3387
8.36k
      else if (bits_per_sample == 12)
3388
8.36k
        {
3389
8.36k
          if (word_pad_lsb)
3390
8.36k
            {
3391
              /*
3392
                Padding in LSB (Method A).
3393
              */
3394
8.36k
              if (endian_type == MSBEndian)
3395
8.36k
                {
3396
557k
                  for (i=samples_per_row; i != 0; i--)
3397
548k
                    {
3398
548k
                      sample=*samples++;
3399
548k
                      sample <<= 4;
3400
548k
                      *sp++=(unsigned char) (((unsigned int) sample) >> 8);
3401
548k
                      *sp++=(unsigned char) sample;
3402
548k
                    }
3403
8.36k
                }
3404
0
              else if (endian_type == LSBEndian)
3405
0
                {
3406
0
                  for (i=samples_per_row; i != 0; i--)
3407
0
                    {
3408
0
                      sample=*samples++;
3409
0
                      sample <<= 4;
3410
0
                      *sp++=(unsigned char) sample;
3411
0
                      *sp++=(unsigned char) (((unsigned int) sample) >> 8);
3412
0
                    }
3413
0
                }
3414
8.36k
            }
3415
0
          else if (word_pad_msb)
3416
0
            {
3417
              /*
3418
                Padding in MSB (Method B).
3419
              */
3420
0
              if (endian_type == MSBEndian)
3421
0
                {
3422
0
                  for (i=samples_per_row; i != 0; i--)
3423
0
                    {
3424
0
                      sample=((*samples++) & 0xFFF);
3425
0
                      *sp++=(unsigned char) (((unsigned int) sample) >> 8);
3426
0
                      *sp++=(unsigned char) sample;
3427
0
                    }
3428
0
                }
3429
0
              else if (endian_type == LSBEndian)
3430
0
                {
3431
0
                  for (i=samples_per_row; i != 0; i--)
3432
0
                    {
3433
0
                      sample=((*samples++) & 0xFFF);
3434
0
                      *sp++=(unsigned char) sample;
3435
0
                      *sp++=(unsigned char) (((unsigned int) sample) >> 8);
3436
0
                    }
3437
0
                }
3438
0
            }
3439
8.36k
          return;
3440
8.36k
        }
3441
71.9k
    }
3442
3443
  /*
3444
    Special fast handling for 8-bit images.
3445
  */
3446
42.8k
  if (bits_per_sample == 8)
3447
1.57k
    {
3448
50.4k
      for (i=samples_per_row; i != 0; i--)
3449
48.8k
        *sp++=(unsigned char) *samples++;
3450
1.57k
      return;
3451
1.57k
    }
3452
3453
  /*
3454
    Special fast handling for 16-bit images.
3455
  */
3456
41.2k
  if (bits_per_sample == 16)
3457
13.8k
    {
3458
13.8k
      if (endian_type == MSBEndian)
3459
13.8k
        {
3460
18.2M
          for (i=samples_per_row; i != 0; i--)
3461
18.1M
            {
3462
18.1M
              *sp++=(unsigned char) (((unsigned int) *samples) >> 8);
3463
18.1M
              *sp++=(unsigned char) *samples;
3464
18.1M
              samples++;
3465
18.1M
            }
3466
13.8k
        }
3467
0
      else if (endian_type == LSBEndian)
3468
0
        {
3469
0
          for (i=samples_per_row; i != 0; i--)
3470
0
            {
3471
0
              *sp++=(unsigned char) *samples;
3472
0
              *sp++=(unsigned char) (((unsigned int) *samples) >> 8);
3473
0
              samples++;
3474
0
            }
3475
0
        }
3476
13.8k
      return;
3477
13.8k
    }
3478
3479
#if 0
3480
  /*
3481
    Special fast handling for 32-bit (float) images.
3482
  */
3483
  if (bits_per_sample == 32)
3484
    {
3485
      register magick_uint32_t
3486
        packed_u32;
3487
3488
      if (endian_type == MSBEndian)
3489
        {
3490
          for (i=samples_per_row; i != 0; i--)
3491
            {
3492
              packed_u32=*samples++;
3493
              MSBPackedU32WordToOctets(packed_u32,scanline);
3494
            }
3495
        }
3496
      else if (endian_type == LSBEndian)
3497
        {
3498
          for (i=samples_per_row; i != 0; i--)
3499
            {
3500
              packed_u32=*samples++;
3501
              LSBPackedU32WordToOctets(packed_u32,scanline);
3502
            }
3503
        }
3504
      return;
3505
    }
3506
#endif
3507
3508
  /*
3509
    Packed data.
3510
  */
3511
27.4k
  {
3512
27.4k
      WriteWordU32State
3513
27.4k
        write_state;
3514
3515
27.4k
      WordStreamWriteHandle
3516
27.4k
        write_stream;
3517
3518
27.4k
      WordStreamWriteFunc
3519
27.4k
        write_func=0;
3520
3521
27.4k
      if (endian_type == LSBEndian)
3522
0
        write_func=WriteWordU32LE;
3523
27.4k
      else
3524
27.4k
        write_func=WriteWordU32BE;
3525
3526
27.4k
      write_state.words=scanline;
3527
27.4k
      MagickWordStreamInitializeWrite(&write_stream,write_func, (void *) &write_state);
3528
3529
17.1M
      for (i=samples_per_row; i != 0; i--)
3530
17.1M
        MagickWordStreamLSBWrite(&write_stream,bits_per_sample,*samples++);
3531
3532
27.4k
      MagickWordStreamLSBWriteFlush(&write_stream);
3533
27.4k
  }
3534
27.4k
}
3535
3536
3.22k
#define AttributeToU8(image_info,image,key,member) \
3537
3.22k
{ \
3538
3.22k
  const ImageAttribute \
3539
3.22k
    *attribute_; \
3540
3.22k
\
3541
3.22k
  const char \
3542
3.22k
    *definition_value_; \
3543
3.22k
\
3544
3.22k
  if ((definition_value_=AccessDefinition(image_info,"dpx",&key[4]))) \
3545
3.22k
    member=(U8) strtol(definition_value_, (char **) NULL, 10); \
3546
3.22k
  else if ((attribute_=GetImageAttribute(image,key))) \
3547
3.22k
    member=(U8) strtol(attribute_->value, (char **) NULL, 10); \
3548
3.22k
  else \
3549
3.22k
    SET_UNDEFINED_U8(member); \
3550
3.22k
}
3551
3552
4.30k
#define AttributeToU16(image_info,image,key,member) \
3553
4.30k
{ \
3554
4.30k
  const ImageAttribute \
3555
4.30k
    *attribute_; \
3556
4.30k
\
3557
4.30k
  const char \
3558
4.30k
    *definition_value_; \
3559
4.30k
\
3560
4.30k
  if ((definition_value_=AccessDefinition(image_info,"dpx",&key[4]))) \
3561
4.30k
    member=(U16) strtol(definition_value_, (char **) NULL, 10); \
3562
4.30k
  else if ((attribute_=GetImageAttribute(image,key))) \
3563
4.30k
    member=(U16) strtol(attribute_->value, (char **) NULL, 10); \
3564
4.30k
  else \
3565
4.30k
    SET_UNDEFINED_U16(member); \
3566
4.30k
}
3567
3568
10.7k
#define AttributeToU32(image_info,image,key,member) \
3569
10.7k
{ \
3570
10.7k
  const ImageAttribute \
3571
10.7k
    *attribute_; \
3572
10.7k
\
3573
10.7k
  const char \
3574
10.7k
    *definition_value_; \
3575
10.7k
\
3576
10.7k
  if ((definition_value_=AccessDefinition(image_info,"dpx",&key[4]))) \
3577
10.7k
    member=(U32) strtol(definition_value_, (char **) NULL, 10); \
3578
10.7k
  else if ((attribute_=GetImageAttribute(image,key))) \
3579
10.7k
    member=(U32) strtol(attribute_->value, (char **) NULL, 10); \
3580
10.7k
  else \
3581
10.7k
    SET_UNDEFINED_U32(member); \
3582
10.7k
}
3583
3584
2.15k
#define AttributeBitsToU32(image_info,image,key,member) \
3585
2.15k
{ \
3586
2.15k
  const ImageAttribute \
3587
2.15k
    *attribute_; \
3588
2.15k
\
3589
2.15k
  const char \
3590
2.15k
    *definition_value_; \
3591
2.15k
\
3592
2.15k
  if ((definition_value_=AccessDefinition(image_info,"dpx",&key[4]))) \
3593
2.15k
    member=SMPTEStringToBits(definition_value_); \
3594
2.15k
  else if ((attribute_=GetImageAttribute(image,key))) \
3595
2.15k
    member=SMPTEStringToBits(attribute_->value); \
3596
2.15k
  else \
3597
2.15k
    SET_UNDEFINED_U32(member); \
3598
2.15k
}
3599
3600
16.1k
#define AttributeToR32(image_info,image,key,member) \
3601
16.1k
{ \
3602
16.1k
  const ImageAttribute \
3603
16.1k
    *attribute_; \
3604
16.1k
\
3605
16.1k
  const char \
3606
16.1k
    *definition_value_; \
3607
16.1k
\
3608
16.1k
  if ((definition_value_=AccessDefinition(image_info,"dpx",&key[4]))) \
3609
16.1k
    member.f=(float) strtod(definition_value_, (char **) NULL); \
3610
16.1k
  else if ((attribute_=GetImageAttribute(image,key))) \
3611
16.1k
    member.f=(float) strtod(attribute_->value, (char **) NULL); \
3612
16.1k
  else \
3613
16.1k
    SET_UNDEFINED_R32(member); \
3614
16.1k
}
3615
3616
/*
3617
  The attribute string is not null terminated, but any unused space
3618
  should be filled with nulls.  Don't even think about using strlcpy
3619
  here because some ASCII fields occupy the full space.  We used to
3620
  use strncpy here but then compilers started to complain about our
3621
  valid code because the result might not be null-terminated.
3622
*/
3623
15.0k
#define AttributeToString(image_info,image,key,member) \
3624
15.0k
{ \
3625
15.0k
  const ImageAttribute \
3626
15.0k
    *attribute_; \
3627
15.0k
\
3628
15.0k
  const char \
3629
15.0k
    *attribute_value_ = NULL; \
3630
15.0k
\
3631
15.0k
  size_t \
3632
15.0k
    attribute_value_length_ = 0; \
3633
15.0k
\
3634
15.0k
  if ((attribute_value_=AccessDefinition(image_info,"dpx",&key[4]))) \
3635
15.0k
    { \
3636
0
    } \
3637
15.0k
  else if ((attribute_=GetImageAttribute(image,key))) \
3638
15.0k
    { \
3639
1.96k
      attribute_value_=attribute_->value; \
3640
1.96k
    } \
3641
15.0k
\
3642
15.0k
  if (attribute_value_) \
3643
15.0k
    { \
3644
1.96k
      attribute_value_length_=strlen(attribute_value_); \
3645
1.96k
      attribute_value_length_=Min(attribute_value_length_,sizeof(member)); \
3646
1.96k
      (void) memcpy(member,attribute_value_,attribute_value_length_);    \
3647
1.96k
    } \
3648
15.0k
    if (sizeof(member) > attribute_value_length_) \
3649
15.0k
      (void) memset(member+attribute_value_length_,0,sizeof(member)-attribute_value_length_); \
3650
15.0k
}
3651
3652
/*
3653
  Round an offset up to specified offset boundary.
3654
*/
3655
#define RoundUpToBoundary(offset,boundary) \
3656
1.07k
  (((offset+boundary-1)/boundary)*boundary);
3657
3658
0
#define ThrowDPXWriterException(code_,reason_,image_)    \
3659
0
{ \
3660
0
  MagickFreeResourceLimitedMemory(map_CbCr);   \
3661
0
  MagickFreeResourceLimitedMemory(map_Y); \
3662
0
  MagickFreeResourceLimitedMemory(samples); \
3663
0
  MagickFreeResourceLimitedMemory(scanline); \
3664
0
  if (chroma_image) \
3665
0
    DestroyImage(chroma_image); \
3666
0
  ThrowWriterException(code_,reason_,image_); \
3667
0
}
3668
3669
STATIC unsigned int WriteDPXImage(const ImageInfo *image_info,Image *image)
3670
1.07k
{
3671
1.07k
  char
3672
1.07k
    txt_buffer[MaxTextExtent];
3673
3674
1.07k
  DPXFileInfo
3675
1.07k
    dpx_file_info;
3676
3677
1.07k
  DPXImageInfo
3678
1.07k
    dpx_image_info;
3679
3680
1.07k
  DPXImageSourceInfo
3681
1.07k
    dpx_source_info;
3682
3683
1.07k
  DPXMPFilmInfo
3684
1.07k
    dpx_mp_info;
3685
3686
1.07k
  DPXTVInfo
3687
1.07k
    dpx_tv_info;
3688
3689
1.07k
  DPXImageElementDescriptor
3690
1.07k
    element_descriptor;
3691
3692
1.07k
  ImageComponentPackingMethod
3693
1.07k
    packing_method;
3694
3695
1.07k
  DPXTransferCharacteristic
3696
1.07k
    transfer_characteristic;
3697
3698
1.07k
  Image
3699
1.07k
    *chroma_image=0;
3700
3701
1.07k
  unsigned long
3702
1.07k
    y;
3703
3704
1.07k
  register const PixelPacket
3705
1.07k
    *p;
3706
3707
1.07k
  register unsigned long
3708
1.07k
    i,
3709
1.07k
    x;
3710
3711
1.07k
  sample_t
3712
1.07k
    *samples=0,
3713
1.07k
    *samples_itr;
3714
3715
1.07k
  sample_t
3716
1.07k
    *map_Y=0,                   /* value translation map (RGB or Y) */
3717
1.07k
    *map_CbCr=0;                /* value translation map (CbCr) */
3718
3719
1.07k
  unsigned char
3720
1.07k
    *scanline=0;
3721
3722
1.07k
  const unsigned char
3723
1.07k
    *user_data;
3724
3725
1.07k
  unsigned int
3726
1.07k
    bits_per_sample=0,
3727
1.07k
    element,
3728
1.07k
    sampling_factor_horizontal,
3729
1.07k
    sampling_factor_vertical,
3730
1.07k
    max_samples_per_pixel,
3731
1.07k
    image_data_offset,
3732
1.07k
    number_of_elements,
3733
1.07k
    row_samples,
3734
1.07k
    samples_per_component,
3735
1.07k
    samples_per_pixel,
3736
1.07k
    samples_per_row,
3737
1.07k
    status;
3738
3739
1.07k
  MagickBool
3740
1.07k
    swap_endian;
3741
3742
1.07k
  size_t
3743
1.07k
    element_size;
3744
3745
1.07k
  const char *
3746
1.07k
    definition_value;
3747
3748
1.07k
  size_t
3749
1.07k
    offset=0,
3750
1.07k
    row_octets,
3751
1.07k
    user_data_length=0;
3752
3753
1.07k
  EndianType
3754
1.07k
    endian_type;
3755
3756
  /*
3757
    Open output image file.
3758
  */
3759
1.07k
  assert(image_info != (const ImageInfo *) NULL);
3760
1.07k
  assert(image_info->signature == MagickSignature);
3761
1.07k
  assert(image != (Image *) NULL);
3762
1.07k
  assert(image->signature == MagickSignature);
3763
1.07k
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
3764
1.07k
  if (status == False)
3765
1.07k
    ThrowWriterException(FileOpenError,UnableToOpenFile,image);
3766
3767
  /*
3768
    Support user-selection of big/little endian output.
3769
  */
3770
1.07k
  endian_type=MSBEndian;
3771
#if defined(WORDS_BIGENDIAN)
3772
  swap_endian=MagickFalse;
3773
  if (image_info->endian == LSBEndian)
3774
    {
3775
      swap_endian=MagickTrue;
3776
      endian_type=LSBEndian;
3777
    }
3778
#else
3779
1.07k
  swap_endian=MagickTrue;
3780
1.07k
  if (image_info->endian == LSBEndian)
3781
0
    {
3782
0
      swap_endian=MagickFalse;
3783
0
      endian_type=LSBEndian;
3784
0
    }
3785
1.07k
#endif
3786
3787
1.07k
  if (image->logging)
3788
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3789
0
                          "%s endian DPX format",
3790
0
                          (endian_type == MSBEndian ? "Big" : "Little"));
3791
3792
  /*
3793
    Adjust image colorspace if necessary.
3794
  */
3795
1.07k
  if ((image_info->colorspace == CineonLogRGBColorspace) &&
3796
0
      (image->colorspace != CineonLogRGBColorspace))
3797
0
    (void) TransformColorspace(image,CineonLogRGBColorspace);
3798
1.07k
  else if ((image_info->colorspace == Rec601LumaColorspace) &&
3799
0
           (image->colorspace != Rec601LumaColorspace))
3800
0
    (void) TransformColorspace(image,Rec601LumaColorspace);
3801
1.07k
  else if ((image_info->colorspace == Rec601YCbCrColorspace) &&
3802
0
           (image->colorspace != Rec601YCbCrColorspace))
3803
0
    (void) TransformColorspace(image,Rec601YCbCrColorspace);
3804
1.07k
  else if ((image_info->colorspace == YCbCrColorspace) &&
3805
0
           (image->colorspace != Rec601YCbCrColorspace))
3806
0
    (void) TransformColorspace(image,Rec601YCbCrColorspace);
3807
1.07k
  else if ((image_info->colorspace == Rec709LumaColorspace) &&
3808
0
           (image->colorspace != Rec709LumaColorspace))
3809
0
    (void) TransformColorspace(image,Rec709LumaColorspace);
3810
1.07k
  else if ((image_info->colorspace == Rec709YCbCrColorspace) &&
3811
0
           (image->colorspace != Rec709YCbCrColorspace))
3812
0
    (void) TransformColorspace(image,Rec709YCbCrColorspace);
3813
1.07k
  else if (IsRGBColorspace(image_info->colorspace) &&
3814
0
           !IsRGBColorspace(image->colorspace))
3815
0
    (void) TransformColorspace(image,RGBColorspace);
3816
1.07k
  else if (!IsRGBColorspace(image->colorspace) &&
3817
339
           (image->colorspace != CineonLogRGBColorspace) &&
3818
189
           (image->colorspace != Rec601YCbCrColorspace) &&
3819
155
           (image->colorspace != Rec709YCbCrColorspace))
3820
0
    (void) TransformColorspace(image,RGBColorspace);
3821
3822
  /*
3823
    Compute desired/necessary number of bits per sample.
3824
  */
3825
1.07k
  if ((definition_value=AccessDefinition(image_info,"dpx","bits-per-sample")))
3826
0
    bits_per_sample=MagickAtoI(definition_value);
3827
3828
1.07k
  if (bits_per_sample == 0)
3829
1.07k
    {
3830
1.07k
      if (image->depth > 12 )
3831
189
        bits_per_sample=16;
3832
886
      else if (image->depth > 10)
3833
263
        bits_per_sample=12;
3834
623
      else if (image->depth > 8)
3835
223
        bits_per_sample=10;
3836
400
      else if (image->depth > 1)
3837
43
        bits_per_sample=8;
3838
357
      else
3839
357
        bits_per_sample=1;
3840
1.07k
    }
3841
3842
1.07k
  if (image->logging)
3843
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3844
0
                          "Bits per sample: %u", bits_per_sample);
3845
3846
  /*
3847
    Obtain requested sampling factors.
3848
  */
3849
1.07k
  sampling_factor_horizontal=2;
3850
1.07k
  sampling_factor_vertical=2;
3851
1.07k
  if (image_info->sampling_factor != (char *) NULL)
3852
0
    {
3853
0
      long
3854
0
        factors;
3855
3856
0
      factors=sscanf(image_info->sampling_factor,"%ux%u",&sampling_factor_horizontal,
3857
0
                     &sampling_factor_vertical);
3858
0
      if (factors != 2)
3859
0
        sampling_factor_vertical=sampling_factor_horizontal;
3860
0
      if ((sampling_factor_horizontal != 1) && (sampling_factor_horizontal != 2) &&
3861
0
          (sampling_factor_vertical != 1) && (sampling_factor_vertical != 2))
3862
0
        ThrowDPXWriterException(OptionError,UnsupportedSamplingFactor,
3863
0
                                image);
3864
3865
      /*
3866
        When subsampling, image width must be evenly divisible by two.
3867
      */
3868
0
      if (((sampling_factor_horizontal / sampling_factor_vertical) == 2) &&
3869
0
          (image->columns %2))
3870
0
        ThrowDPXWriterException(CoderError,SubsamplingRequiresEvenWidth,image);
3871
0
    }
3872
3873
  /*
3874
    Intuit the samples per component and the number of elements.
3875
  */
3876
1.07k
  if (IsYCbCrColorspace(image->colorspace))
3877
189
    {
3878
189
      if ((image_info->interlace == PlaneInterlace) &&
3879
0
          ((sampling_factor_horizontal / sampling_factor_vertical) == 2))
3880
0
        {
3881
          /* YCbCr 4:2:2 planar */
3882
0
          samples_per_component=1;
3883
0
          number_of_elements=2;
3884
0
          if (image->matte)
3885
0
            number_of_elements++;
3886
0
        }
3887
189
      else
3888
189
        {
3889
189
          if ((sampling_factor_horizontal / sampling_factor_vertical) == 2)
3890
0
            {
3891
              /* YCbCr 4:2:2 */
3892
0
              samples_per_component=2;
3893
0
            }
3894
189
          else
3895
189
            {
3896
              /* YCbCr 4:4:4 */
3897
189
              samples_per_component=3;
3898
189
            }
3899
189
          number_of_elements=1;
3900
189
          if (image->matte)
3901
76
            samples_per_component++;
3902
189
        }
3903
189
    }
3904
886
  else if (IsGrayColorspace(image->colorspace))
3905
587
    {
3906
587
      samples_per_component=1;
3907
587
      number_of_elements=1;
3908
587
      if (image->matte)
3909
100
        number_of_elements++;
3910
587
    }
3911
299
  else
3912
299
    {
3913
299
      if (image_info->interlace == PlaneInterlace)
3914
0
        {
3915
0
          samples_per_component=1;
3916
0
          number_of_elements=3;
3917
0
          if (image->matte)
3918
0
            number_of_elements++;
3919
0
        }
3920
299
      else
3921
299
        {
3922
299
          samples_per_component=3;
3923
299
          number_of_elements=1;
3924
299
          if (image->matte)
3925
115
            samples_per_component++;
3926
299
        }
3927
299
    }
3928
3929
  /*
3930
    Choose the default packing method.
3931
  */
3932
1.07k
  if ((bits_per_sample == 10) || (bits_per_sample == 12))
3933
486
    packing_method=PackingMethodWordsFillLSB;
3934
589
  else
3935
589
    packing_method=PackingMethodPacked;
3936
3937
  /*
3938
    Allow the user to over-ride the default packing method.
3939
  */
3940
1.07k
  if ((definition_value=AccessDefinition(image_info,"dpx","packing-method")))
3941
0
    {
3942
0
      if (LocaleCompare(definition_value,"packed") == 0)
3943
0
        {
3944
0
          packing_method=PackingMethodPacked;
3945
0
        }
3946
0
      else if ((bits_per_sample == 10) || (bits_per_sample == 12))
3947
0
        {
3948
0
          if ((LocaleCompare(definition_value,"lsbpad") == 0) ||
3949
0
              (LocaleCompare(definition_value,"a") == 0))
3950
0
            packing_method=PackingMethodWordsFillLSB;
3951
0
          else if ((LocaleCompare(definition_value,"msbpad") == 0) ||
3952
0
                   (LocaleCompare(definition_value,"b") == 0))
3953
0
            packing_method=PackingMethodWordsFillMSB;
3954
0
        }
3955
0
    }
3956
3957
1.07k
  row_samples=((magick_int64_t) image->columns*samples_per_component);
3958
1.07k
  row_octets=DPXRowOctets(1,row_samples,bits_per_sample,packing_method);
3959
1.07k
  element_size=DPXRowOctets(image->rows,row_samples,bits_per_sample,packing_method);
3960
3961
1.07k
  if (image->logging)
3962
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3963
0
                          "Samples per row %u, octets per row %lu, element size %lu",
3964
0
                          row_samples, (unsigned long) row_octets,
3965
0
                          (unsigned long) element_size);
3966
  /*
3967
    Obtain pointer to user data and user data length (if available).
3968
  */
3969
1.07k
  user_data=GetImageProfile(image,"DPXUSERDATA",&user_data_length);
3970
3971
  /*
3972
    Image information header
3973
  */
3974
1.07k
  (void) memset(&dpx_image_info,0,sizeof(dpx_image_info));
3975
  /* Image orientation */
3976
1.07k
  dpx_image_info.orientation=OrientationTypeToDPXOrientation(image->orientation);
3977
  /* Number of image elements described. */
3978
1.07k
  dpx_image_info.elements=number_of_elements;
3979
  /* Number of pixels per line. */
3980
1.07k
  dpx_image_info.pixels_per_line=image->columns;
3981
  /* Number of lines per image element. */
3982
1.07k
  dpx_image_info.lines_per_image_element=image->rows;
3983
  /* Image sample sign. */
3984
1.07k
  dpx_image_info.element_info[0].data_sign=0; /* Unsigned data */
3985
3986
  /* Colorimetic specification. Define the appropriate color reference
3987
     primaries (for additive color systems like television) or color
3988
     responses (for printing density). */
3989
  /* Reference low data code.  For printing density the default is 0
3990
     but for ITU-R 601-5 luma, the default is 16 */
3991
  /* Reference low quantity represented. For printing density the
3992
     default is a density of 0.00. For ITU-R 601-5, the luma default
3993
     is 0 mv */
3994
  /* Reference high data code value. Defines maximum expected code
3995
     value for image data. For 10-bit printing density, the default
3996
     code value is 1023. */
3997
  /* Reference high quantity represented. For printing density, the
3998
     default is a density of 2.048. For ITU-R 601-5 luma, the default
3999
     is 700 mv. */
4000
1.07k
  SET_UNDEFINED_U8(dpx_image_info.element_info[0].transfer_characteristic);
4001
1.07k
  SET_UNDEFINED_U8(dpx_image_info.element_info[0].colorimetric);
4002
1.07k
  SET_UNDEFINED_U8(dpx_image_info.element_info[0].reference_low_data_code);
4003
1.07k
  SET_UNDEFINED_R32(dpx_image_info.element_info[0].reference_low_quantity);
4004
1.07k
  SET_UNDEFINED_U32(dpx_image_info.element_info[0].reference_high_data_code);
4005
1.07k
  SET_UNDEFINED_R32(dpx_image_info.element_info[0].reference_high_quantity);
4006
4007
1.07k
  if (image->colorspace == CineonLogRGBColorspace)
4008
150
    {
4009
150
      transfer_characteristic=TransferCharacteristicPrintingDensity;
4010
150
    }
4011
925
  else if ((image->colorspace == YCbCrColorspace) ||
4012
891
           (image->colorspace == Rec601YCbCrColorspace) ||
4013
891
           (image->colorspace == Rec601LumaColorspace))
4014
211
    {
4015
211
      if (image->rows > 525)
4016
24
        transfer_characteristic=TransferCharacteristicITU_R601_625L;
4017
187
      else
4018
187
        transfer_characteristic=TransferCharacteristicITU_R601_525L;
4019
211
    }
4020
714
  else if ((image->colorspace == Rec709YCbCrColorspace) ||
4021
559
           (image->colorspace == Rec709LumaColorspace))
4022
265
    {
4023
265
      transfer_characteristic=TransferCharacteristicITU_R709;
4024
265
    }
4025
449
  else
4026
449
    {
4027
449
      transfer_characteristic=TransferCharacteristicLinear;
4028
449
    }
4029
4030
  /* Transfer characteristic. Define the amplitude transfer function
4031
     necessary to transform the data to a linear original. */
4032
1.07k
  dpx_image_info.element_info[0].transfer_characteristic=transfer_characteristic;
4033
4034
1.07k
  if (transfer_characteristic == TransferCharacteristicPrintingDensity)
4035
150
    {
4036
      /* Printing density is a log encoding */
4037
150
      dpx_image_info.element_info[0].colorimetric=ColorimetricPrintingDensity;
4038
150
      dpx_image_info.element_info[0].reference_low_data_code=0;
4039
150
      dpx_image_info.element_info[0].reference_high_data_code=
4040
150
        MaxValueGivenBits(bits_per_sample);
4041
150
      dpx_image_info.element_info[0].reference_low_quantity.f=0.00F;
4042
150
      dpx_image_info.element_info[0].reference_high_quantity.f=2.047F;
4043
150
    }
4044
925
  else if ((transfer_characteristic == TransferCharacteristicUnspecifiedVideo) ||
4045
925
           (transfer_characteristic == TransferCharacteristicSMTPE274M) ||
4046
925
           (transfer_characteristic == TransferCharacteristicITU_R709) ||
4047
660
           (transfer_characteristic == TransferCharacteristicITU_R601_625L) ||
4048
636
           (transfer_characteristic == TransferCharacteristicITU_R601_525L) ||
4049
449
           (transfer_characteristic == TransferCharacteristicNTSCCompositeVideo) ||
4050
449
           (transfer_characteristic == TransferCharacteristicPALCompositeVideo))
4051
476
    {
4052
      /*
4053
        Some sort of video.
4054
      */
4055
476
      unsigned int
4056
476
        max_value_given_bits = MaxValueGivenBits(bits_per_sample);
4057
4058
476
      switch (transfer_characteristic)
4059
476
        {
4060
0
        case TransferCharacteristicSMTPE274M:
4061
0
          dpx_image_info.element_info[0].colorimetric=ColorimetricSMTPE274M;
4062
0
          break;
4063
265
        case TransferCharacteristicITU_R709:
4064
265
          dpx_image_info.element_info[0].colorimetric=ColorimetricITU_R709;
4065
265
          break;
4066
24
        case TransferCharacteristicITU_R601_625L:
4067
24
          dpx_image_info.element_info[0].colorimetric=ColorimetricITU_R601_625L;
4068
24
          break;
4069
187
        case TransferCharacteristicITU_R601_525L:
4070
187
          dpx_image_info.element_info[0].colorimetric=ColorimetricITU_R601_525L;
4071
187
          break;
4072
0
        case TransferCharacteristicNTSCCompositeVideo:
4073
0
          dpx_image_info.element_info[0].colorimetric=ColorimetricNTSCCompositeVideo;
4074
0
          break;
4075
0
        case TransferCharacteristicPALCompositeVideo:
4076
0
          dpx_image_info.element_info[0].colorimetric=ColorimetricPALCompositeVideo;
4077
0
          break;
4078
0
        default:
4079
0
          dpx_image_info.element_info[0].colorimetric=ColorimetricUserDefined;
4080
0
          break;
4081
476
        }
4082
4083
476
      dpx_image_info.element_info[0].reference_low_data_code=        /* 16 for 8 bits */
4084
476
        (U32) (max_value_given_bits * (16.0/255.0) + 0.5);
4085
476
      dpx_image_info.element_info[0].reference_high_data_code=       /* 235 for 8 bits */
4086
476
        (U32) (max_value_given_bits * (235.0/255.0) + 0.5);
4087
476
      dpx_image_info.element_info[0].reference_low_quantity.f=0.00F;   /* 0mv */
4088
476
      dpx_image_info.element_info[0].reference_high_quantity.f=0.700F; /* 700mv */
4089
476
    }
4090
449
  else if (transfer_characteristic == TransferCharacteristicLinear)
4091
449
    {
4092
      /* Otherwise we are using linear encoding */
4093
449
      dpx_image_info.element_info[0].colorimetric=ColorimetricLinear;
4094
449
      dpx_image_info.element_info[0].reference_low_data_code=0;
4095
449
      dpx_image_info.element_info[0].reference_high_data_code=
4096
449
        MaxValueGivenBits(bits_per_sample);
4097
449
    }
4098
4099
  /*
4100
    Compute image data offset.  Should be rounded up to next 8K block.
4101
  */
4102
1.07k
  image_data_offset=2048;
4103
1.07k
  if (user_data)
4104
135
    image_data_offset += (unsigned int) user_data_length;
4105
1.07k
  image_data_offset=RoundUpToBoundary(image_data_offset,IMAGE_DATA_ROUNDING);
4106
4107
  /* Element Descriptor */
4108
1.07k
  SET_UNDEFINED_U8(dpx_image_info.element_info[0].descriptor);
4109
  /* Number of bits per sample */
4110
1.07k
  dpx_image_info.element_info[0].bits_per_sample=bits_per_sample;
4111
  /* Packing method */
4112
1.07k
  dpx_image_info.element_info[0].packing=0;
4113
1.07k
  if ((bits_per_sample == 10) || (bits_per_sample == 12))
4114
486
    dpx_image_info.element_info[0].packing=packing_method;
4115
  /* Encoding.  Unencoded or run length encoded */
4116
1.07k
  dpx_image_info.element_info[0].encoding=0; /* No encoding */
4117
  /* Offset to element data from beginning of file. */
4118
1.07k
  dpx_image_info.element_info[0].data_offset=image_data_offset;
4119
  /* Number of padded bytes at the end of each line */
4120
1.07k
  dpx_image_info.element_info[0].eol_pad=0;
4121
  /* Number of padded bytes at the end of image element. */
4122
1.07k
  dpx_image_info.element_info[0].eoi_pad=0;
4123
  /* Element description */
4124
1.07k
  SET_UNDEFINED_ASCII(dpx_image_info.element_info[0].description);
4125
4126
1.17k
  for (i=1; i < number_of_elements; i++)
4127
100
    {
4128
      /* Clone settings from preceding element */
4129
100
      dpx_image_info.element_info[i]=dpx_image_info.element_info[i-1];
4130
      /* Compute offset to data */
4131
100
      dpx_image_info.element_info[i].data_offset=
4132
100
        dpx_image_info.element_info[i-1].data_offset+(U32) element_size;
4133
100
    }
4134
4135
  /*
4136
    Fill out element descriptor.
4137
  */
4138
1.07k
  if (number_of_elements > 1)
4139
100
    {
4140
      /*
4141
        Planar image configuration.
4142
      */
4143
100
      if (IsGrayColorspace(image->colorspace))
4144
100
        {
4145
          /* Luma with alpha channel in second plane */
4146
100
          dpx_image_info.element_info[0].descriptor=ImageElementLuma;
4147
100
          dpx_image_info.element_info[1].descriptor=ImageElementAlpha;
4148
100
        }
4149
0
      else if (IsRGBColorspace(image->colorspace) ||
4150
0
               (image->colorspace == CineonLogRGBColorspace))
4151
0
        {
4152
          /* RGB Planar */
4153
0
          dpx_image_info.element_info[0].descriptor=ImageElementRed;
4154
0
          dpx_image_info.element_info[1].descriptor=ImageElementGreen;
4155
0
          dpx_image_info.element_info[2].descriptor=ImageElementBlue;
4156
0
          if ((image->matte) && (number_of_elements == 4))
4157
0
            {
4158
0
              dpx_image_info.element_info[3].descriptor=ImageElementAlpha;
4159
0
            }
4160
0
        }
4161
0
      else if (IsYCbCrColorspace(image->colorspace))
4162
0
        {
4163
          /* YCbCr 4:2:2 planar */
4164
0
          dpx_image_info.element_info[0].descriptor=ImageElementLuma;
4165
0
          dpx_image_info.element_info[1].descriptor=ImageElementColorDifferenceCbCr;
4166
0
          if (image->matte)
4167
0
            dpx_image_info.element_info[2].descriptor=ImageElementAlpha;
4168
0
        }
4169
100
    }
4170
975
  else
4171
975
    {
4172
975
      if (IsYCbCrColorspace(image->colorspace))
4173
189
        {
4174
          /* CbYCr */
4175
189
          if (samples_per_component == 2)
4176
0
            {
4177
              /* CbYCr 4:2:2 */
4178
0
              dpx_image_info.element_info[0].descriptor=image->matte ?
4179
0
                ImageElementCbYACrYA4224 : ImageElementCbYCrY422;
4180
0
            }
4181
189
          else
4182
189
            {
4183
              /* CbYCr 4:4:4 */
4184
189
              dpx_image_info.element_info[0].descriptor=image->matte ?
4185
113
                ImageElementCbYCrA4444 : ImageElementCbYCr444;
4186
189
            }
4187
189
        }
4188
786
      else if (IsGrayColorspace(image->colorspace))
4189
487
        {
4190
          /* Luma */
4191
487
          dpx_image_info.element_info[0].descriptor=ImageElementLuma;
4192
487
        }
4193
299
      else if (IsRGBColorspace(image->colorspace) ||
4194
150
               (image->colorspace == CineonLogRGBColorspace))
4195
299
        {
4196
          /* RGB */
4197
299
          dpx_image_info.element_info[0].descriptor=image->matte ?
4198
184
            ImageElementRGBA : ImageElementRGB;
4199
299
        }
4200
975
    }
4201
4202
  /*
4203
    Add a textual description for each element.
4204
  */
4205
2.25k
  for (i=0; i < number_of_elements; i++)
4206
1.17k
    {
4207
1.17k
      (void) strlcpy(dpx_image_info.element_info[i].description,
4208
1.17k
                     DescribeImageElementDescriptor(txt_buffer,
4209
1.17k
                     (DPXImageElementDescriptor) dpx_image_info.element_info[i].descriptor),
4210
1.17k
                     sizeof(dpx_image_info.element_info[0].description));
4211
1.17k
      (void) strlcat(dpx_image_info.element_info[i].description," / ",
4212
1.17k
                     sizeof(dpx_image_info.element_info[0].description));
4213
1.17k
      (void) strlcat(dpx_image_info.element_info[i].description,
4214
1.17k
                     DescribeImageTransferCharacteristic(txt_buffer,
4215
1.17k
                     (DPXTransferCharacteristic) dpx_image_info.element_info[i].transfer_characteristic),
4216
1.17k
                     sizeof(dpx_image_info.element_info[0].description));
4217
1.17k
    }
4218
4219
  /*
4220
    File information header.
4221
  */
4222
1.07k
  (void) memset(&dpx_file_info,0,sizeof(dpx_file_info));
4223
1.07k
  dpx_file_info.magic=0x53445058U;
4224
1.07k
  dpx_file_info.image_data_offset=dpx_image_info.element_info[0].data_offset;
4225
1.07k
  (void) strlcpy(dpx_file_info.header_format_version,"V2.0",
4226
1.07k
                 sizeof(dpx_file_info.header_format_version));
4227
1.07k
  dpx_file_info.file_size=
4228
1.07k
    dpx_file_info.image_data_offset+number_of_elements*(U32) element_size;
4229
1.07k
  if (image->logging)
4230
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4231
0
                          "Estimated file length: %u",dpx_file_info.file_size);
4232
1.07k
  dpx_file_info.ditto_key=1; /* new frame */
4233
1.07k
  dpx_file_info.generic_section_length=sizeof(dpx_file_info)+
4234
1.07k
    sizeof(dpx_image_info)+sizeof(dpx_source_info);
4235
1.07k
  dpx_file_info.industry_section_length=sizeof(dpx_mp_info)+sizeof(dpx_tv_info);
4236
1.07k
  dpx_file_info.user_defined_length=(U32) (user_data ? user_data_length : 0);
4237
1.07k
  (void) strlcpy(dpx_file_info.image_filename,image->filename,
4238
1.07k
                 sizeof(dpx_file_info.image_filename));
4239
1.07k
  GenerateDPXTimeStamp(dpx_file_info.creation_datetime,
4240
1.07k
                       sizeof(dpx_file_info.creation_datetime));
4241
#if 0 /* To enable use of original file creator. */
4242
  AttributeToString(image_info,image,"DPX:file.creator",dpx_file_info.creator);
4243
  if (dpx_file_info.creator[0] == '\0')
4244
#endif
4245
1.07k
    (void) strlcpy(dpx_file_info.creator,GetMagickVersion((unsigned long *) NULL),
4246
1.07k
                   sizeof(dpx_file_info.creator));
4247
1.07k
  AttributeToString(image_info,image,"DPX:file.project.name",dpx_file_info.project_name);
4248
1.07k
  AttributeToString(image_info,image,"DPX:file.copyright",dpx_file_info.copyright);
4249
1.07k
  AttributeToU32(image_info,image,"DPX:file.encryption.key",dpx_file_info.encryption_key);
4250
  /*
4251
    Image source information header
4252
  */
4253
1.07k
  (void) memset(&dpx_source_info,0,sizeof(dpx_source_info));
4254
1.07k
  SET_UNDEFINED_U32(dpx_source_info.x_offset);
4255
1.07k
  SET_UNDEFINED_U32(dpx_source_info.y_offset);
4256
1.07k
  SET_UNDEFINED_R32(dpx_source_info.x_center);
4257
1.07k
  SET_UNDEFINED_R32(dpx_source_info.y_center);
4258
1.07k
  SET_UNDEFINED_U32(dpx_source_info.x_original_size);
4259
1.07k
  SET_UNDEFINED_U32(dpx_source_info.y_original_size);
4260
1.07k
  if ((image->rows == image->magick_rows) && (image->columns == image->magick_columns))
4261
1.07k
    {
4262
      /* If image size has not changed from original (magick_columns
4263
         and magick_rows contain original size), then preserve any
4264
         existing source image dimension and offset information. If
4265
         size has changed, then information may be wrong. */
4266
1.07k
      AttributeToU32(image_info,image,"DPX:source.x-offset",dpx_source_info.x_offset);
4267
1.07k
      AttributeToU32(image_info,image,"DPX:source.y-offset",dpx_source_info.y_offset);
4268
1.07k
      AttributeToR32(image_info,image,"DPX:source.x-center",dpx_source_info.x_center);
4269
1.07k
      AttributeToR32(image_info,image,"DPX:source.y-center",dpx_source_info.y_center);
4270
1.07k
      AttributeToU32(image_info,image,"DPX:source.x-original-size",dpx_source_info.x_original_size);
4271
1.07k
      AttributeToU32(image_info,image,"DPX:source.y-original-size",dpx_source_info.y_original_size);
4272
1.07k
    }
4273
1.07k
  AttributeToString(image_info,image,"DPX:source.filename",dpx_source_info.source_image_filename);
4274
1.07k
  if (IS_UNDEFINED_ASCII(dpx_source_info.source_image_filename))
4275
980
    (void) strlcpy(dpx_source_info.source_image_filename,image->magick_filename,
4276
1.07k
                   sizeof(dpx_source_info.source_image_filename));
4277
1.07k
  AttributeToString(image_info,image,"DPX:source.creation.datetime",dpx_source_info.source_image_datetime);
4278
1.07k
  AttributeToString(image_info,image,"DPX:source.device.name",dpx_source_info.input_device_name);
4279
1.07k
  AttributeToString(image_info,image,"DPX:source.device.serialnumber",dpx_source_info.input_device_serialnumber);
4280
1.07k
  AttributeToU16(image_info,image,"DPX:source.border.validity.left",dpx_source_info.border_validity.XL);
4281
1.07k
  AttributeToU16(image_info,image,"DPX:source.border.validity.right",dpx_source_info.border_validity.XR);
4282
1.07k
  AttributeToU16(image_info,image,"DPX:source.border.validity.top",dpx_source_info.border_validity.YT);
4283
1.07k
  AttributeToU16(image_info,image,"DPX:source.border.validity.bottom",dpx_source_info.border_validity.YB);
4284
1.07k
  AttributeToU32(image_info,image,"DPX:source.aspect.ratio.horizontal",dpx_source_info.aspect_ratio.horizontal);
4285
1.07k
  AttributeToU32(image_info,image,"DPX:source.aspect.ratio.vertical",dpx_source_info.aspect_ratio.vertical);
4286
1.07k
  AttributeToR32(image_info,image,"DPX:source.scanned.size.x",dpx_source_info.x_scanned_size);
4287
1.07k
  AttributeToR32(image_info,image,"DPX:source.scanned.size.y",dpx_source_info.y_scanned_size);
4288
  /*
4289
    Motion-picture film information header.
4290
  */
4291
1.07k
  (void) memset(&dpx_mp_info,0,sizeof(dpx_mp_info));
4292
1.07k
  AttributeToString(image_info,image,"DPX:mp.film.manufacturer.id",dpx_mp_info.film_mfg_id_code);
4293
1.07k
  AttributeToString(image_info,image,"DPX:mp.film.type",dpx_mp_info.film_type);
4294
1.07k
  AttributeToString(image_info,image,"DPX:mp.perfs.offset",dpx_mp_info.perfs_offset);
4295
1.07k
  AttributeToString(image_info,image,"DPX:mp.prefix",dpx_mp_info.prefix);
4296
1.07k
  AttributeToString(image_info,image,"DPX:mp.count",dpx_mp_info.count);
4297
1.07k
  AttributeToString(image_info,image,"DPX:mp.format",dpx_mp_info.format);
4298
1.07k
  AttributeToU32(image_info,image,"DPX:mp.frame.position",dpx_mp_info.frame_position);
4299
1.07k
  AttributeToU32(image_info,image,"DPX:mp.sequence.length",dpx_mp_info.sequence_length);
4300
1.07k
  AttributeToU32(image_info,image,"DPX:mp.held.count",dpx_mp_info.held_count);
4301
1.07k
  AttributeToR32(image_info,image,"DPX:mp.frame.rate",dpx_mp_info.frame_rate);
4302
1.07k
  AttributeToR32(image_info,image,"DPX:mp.shutter.angle",dpx_mp_info.shutter_angle);
4303
1.07k
  AttributeToString(image_info,image,"DPX:mp.frame.id",dpx_mp_info.frame_id);
4304
1.07k
  AttributeToString(image_info,image,"DPX:mp.slate.info",dpx_mp_info.slate_info);
4305
  /*
4306
    Television information header.
4307
  */
4308
1.07k
  (void) memset(&dpx_tv_info,0,sizeof(dpx_tv_info));
4309
1.07k
  AttributeBitsToU32(image_info,image,"DPX:tv.time.code",dpx_tv_info.time_code);
4310
1.07k
  AttributeBitsToU32(image_info,image,"DPX:tv.user.bits",dpx_tv_info.user_bits);
4311
1.07k
  AttributeToU8(image_info,image,"DPX:tv.interlace",dpx_tv_info.interlace);
4312
1.07k
  AttributeToU8(image_info,image,"DPX:tv.field.number",dpx_tv_info.field_number);
4313
1.07k
  AttributeToU8(image_info,image,"DPX:tv.video.signal",dpx_tv_info.video_signal);
4314
1.07k
  AttributeToR32(image_info,image,"DPX:tv.horizontal.sampling.rate",dpx_tv_info.horizontal_sample);
4315
1.07k
  AttributeToR32(image_info,image,"DPX:tv.temporal.sampling.rate",dpx_tv_info.temporal_sample);
4316
1.07k
  AttributeToR32(image_info,image,"DPX:tv.sync.time",dpx_tv_info.sync_time);
4317
1.07k
  AttributeToR32(image_info,image,"DPX:tv.gamma",dpx_tv_info.gamma);
4318
1.07k
  AttributeToR32(image_info,image,"DPX:tv.black.level",dpx_tv_info.black_level);
4319
1.07k
  AttributeToR32(image_info,image,"DPX:tv.black.gain",dpx_tv_info.black_gain);
4320
1.07k
  AttributeToR32(image_info,image,"DPX:tv.breakpoint",dpx_tv_info.breakpoint);
4321
1.07k
  AttributeToR32(image_info,image,"DPX:tv.white.level",dpx_tv_info.white_level);
4322
1.07k
  AttributeToR32(image_info,image,"DPX:tv.integration.time",dpx_tv_info.integration_time);
4323
  /*
4324
    Determine the maximum number of samples required for any element.
4325
  */
4326
1.07k
  max_samples_per_pixel=0;
4327
2.25k
  for (element=0; element < dpx_image_info.elements; element++)
4328
1.17k
    {
4329
1.17k
      element_descriptor=(DPXImageElementDescriptor)
4330
1.17k
        dpx_image_info.element_info[element].descriptor;
4331
1.17k
      max_samples_per_pixel=Max(max_samples_per_pixel,
4332
1.17k
                                DPXSamplesPerPixel(element_descriptor));
4333
1.17k
    }
4334
  /*
4335
    Allocate row samples.
4336
  */
4337
1.07k
  samples=MagickAllocateResourceLimitedArray(sample_t *,image->columns,
4338
1.07k
                              max_samples_per_pixel*sizeof(sample_t));
4339
1.07k
  if (samples == (sample_t *) NULL)
4340
1.07k
    ThrowDPXWriterException(ResourceLimitError,MemoryAllocationFailed,image);
4341
1.07k
  (void) memset((void *) samples,0,(size_t) max_samples_per_pixel*image->columns*
4342
1.07k
                sizeof(sample_t));
4343
  /*
4344
    Allocate row scanline.
4345
  */
4346
1.07k
  scanline=MagickAllocateResourceLimitedMemory(unsigned char *,row_octets);
4347
1.07k
  if (scanline == (unsigned char *) NULL)
4348
1.07k
    ThrowDPXWriterException(ResourceLimitError,MemoryAllocationFailed,image);
4349
1.07k
  (void) memset((void *) scanline,0,row_octets);
4350
4351
  /*
4352
    Allocate sample translation map storage.
4353
  */
4354
1.07k
  map_Y=MagickAllocateResourceLimitedArray(sample_t *,MaxMap+1,sizeof(sample_t));
4355
1.07k
  if (map_Y == (sample_t *) NULL)
4356
1.07k
    ThrowDPXWriterException(ResourceLimitError,MemoryAllocationFailed,image);
4357
1.07k
  (void) memset((void *) map_Y,0,(MaxMap+1)*sizeof(sample_t));
4358
4359
1.07k
  map_CbCr=MagickAllocateResourceLimitedArray(sample_t *,MaxMap+1,sizeof(sample_t));
4360
1.07k
  if (map_CbCr == (sample_t *) NULL)
4361
1.07k
    ThrowDPXWriterException(ResourceLimitError,MemoryAllocationFailed,image);
4362
1.07k
  (void) memset((void *) map_CbCr,0,(MaxMap+1)*sizeof(sample_t));
4363
4364
  /*
4365
    Reserve file/blob length if requested.
4366
  */
4367
1.07k
  {
4368
1.07k
    const char
4369
1.07k
      *env;
4370
4371
1.07k
    if (((env=getenv("MAGICK_RESERVE_STORAGE")) != NULL) &&
4372
0
        (LocaleCompare(env,"TRUE") == 0))
4373
0
      (void) BlobReserveSize(image,dpx_file_info.file_size);
4374
1.07k
  }
4375
4376
  /*
4377
    Write file headers.
4378
  */
4379
1.07k
  if (swap_endian)
4380
1.07k
    {
4381
      /*
4382
        Swap byte order.
4383
      */
4384
1.07k
      SwabDPXFileInfo(&dpx_file_info);
4385
1.07k
      SwabDPXImageInfo(&dpx_image_info);
4386
1.07k
      SwabDPXImageSourceInfo(&dpx_source_info);
4387
1.07k
      SwabDPXMPFilmInfo(&dpx_mp_info);
4388
1.07k
      SwabDPXTVInfo(&dpx_tv_info);
4389
1.07k
    }
4390
1.07k
  offset += WriteBlob(image,sizeof(dpx_file_info),&dpx_file_info);
4391
1.07k
  offset += WriteBlob(image,sizeof(dpx_image_info),&dpx_image_info);
4392
1.07k
  offset += WriteBlob(image,sizeof(dpx_source_info),&dpx_source_info);
4393
1.07k
  offset += WriteBlob(image,sizeof(dpx_mp_info),&dpx_mp_info);
4394
1.07k
  offset += WriteBlob(image,sizeof(dpx_tv_info),&dpx_tv_info);
4395
1.07k
  if (user_data)
4396
135
    {
4397
135
      offset += WriteBlob(image,(size_t) user_data_length,user_data);
4398
135
    }
4399
1.07k
  if (swap_endian)
4400
1.07k
    {
4401
      /*
4402
        Swap byte order back to original.
4403
      */
4404
1.07k
      SwabDPXFileInfo(&dpx_file_info);
4405
1.07k
      SwabDPXImageInfo(&dpx_image_info);
4406
1.07k
      SwabDPXImageSourceInfo(&dpx_source_info);
4407
1.07k
      SwabDPXMPFilmInfo(&dpx_mp_info);
4408
1.07k
      SwabDPXTVInfo(&dpx_tv_info);
4409
1.07k
    }
4410
  /*
4411
    Fill to offset.
4412
  */
4413
6.46M
  while (offset < dpx_image_info.element_info[0].data_offset)
4414
6.46M
    {
4415
6.46M
      if (WriteBlobByte(image,0U) != 1)
4416
0
        break;
4417
6.46M
      offset += 1;
4418
6.46M
    }
4419
  /*
4420
    Allow user to over-ride pixel endianness.
4421
  */
4422
1.07k
  if ((definition_value=AccessDefinition(image_info,"dpx","pixel-endian")))
4423
0
    {
4424
0
      if (LocaleCompare(definition_value,"msb") == 0)
4425
0
        endian_type=MSBEndian;
4426
0
      else if (LocaleCompare(definition_value,"lsb") == 0)
4427
0
        endian_type=LSBEndian;
4428
0
    }
4429
  /*
4430
    Write out elements.
4431
  */
4432
2.25k
  for (element=0; element < dpx_image_info.elements; element++)
4433
1.17k
    {
4434
1.17k
      MagickBool
4435
1.17k
        swap_word_datums = MagickFalse;
4436
4437
4438
      /*
4439
        Validate that what we are writing matches the header offsets.
4440
      */
4441
1.17k
      {
4442
1.17k
        magick_off_t
4443
1.17k
          reported_file_offset;
4444
4445
1.17k
        if (((reported_file_offset = TellBlob(image)) != -1) &&
4446
1.17k
            ((magick_off_t) dpx_image_info.element_info[element].data_offset !=
4447
1.17k
             reported_file_offset))
4448
41
          {
4449
41
            (void) fprintf(stderr,"### Descriptor %u offset %u, TellBlob says %" MAGICK_OFF_F "d\n",
4450
41
                           element+1, dpx_image_info.element_info[element].data_offset,
4451
41
                           (magick_off_t) reported_file_offset);
4452
41
          }
4453
1.17k
      }
4454
1.17k
      if (image->logging)
4455
0
        DescribeDPXImageElement(&dpx_image_info.element_info[element],element+1);
4456
4457
1.17k
      bits_per_sample=dpx_image_info.element_info[element].bits_per_sample;
4458
1.17k
      transfer_characteristic=(DPXTransferCharacteristic)
4459
1.17k
        dpx_image_info.element_info[element].transfer_characteristic;
4460
4461
1.17k
      {
4462
1.17k
        double
4463
1.17k
          max_value,
4464
1.17k
          reference_low,
4465
1.17k
          reference_high,
4466
1.17k
          scale_from_maxmap;           /* multiplier to scale from MaxMap */
4467
4468
1.17k
        max_value = (double) MaxValueGivenBits(bits_per_sample);
4469
1.17k
        reference_low = 0.0;
4470
1.17k
        reference_high = max_value;
4471
1.17k
        scale_from_maxmap=max_value/((double) MaxMap);
4472
4473
1.17k
        if ((transfer_characteristic == TransferCharacteristicITU_R709) ||
4474
897
            (transfer_characteristic == TransferCharacteristicITU_R601_625L) ||
4475
863
            (transfer_characteristic == TransferCharacteristicITU_R601_525L))
4476
529
          {
4477
529
            double
4478
529
              ScaleY = 0.0,
4479
529
              ScaleCbCr = 0.0;
4480
4481
529
            reference_low = ((MaxRGBDouble+1.0)*(64.0/1024.0));
4482
529
            reference_high = ((MaxRGBDouble+1.0)*(940.0/1024.0));
4483
529
            ScaleY = (reference_high-reference_low)/(MaxRGBDouble+1.0);
4484
529
            ScaleCbCr = ScaleY*((960.0-64.0)/(940.0-64.0));
4485
4486
34.6M
            for (i=0; i <= MaxMap ; i++)
4487
34.6M
              {
4488
34.6M
                map_Y[i]=(i*ScaleY+reference_low)*scale_from_maxmap+0.5;
4489
34.6M
                map_CbCr[i]=(i*ScaleCbCr+reference_low)*scale_from_maxmap+0.5;
4490
34.6M
              }
4491
529
          }
4492
646
        else
4493
646
          {
4494
42.3M
            for (i=0; i <= MaxMap ; i++)
4495
42.3M
              map_Y[i]=i*scale_from_maxmap+0.5;
4496
646
          }
4497
1.17k
      }
4498
4499
1.17k
      element_descriptor=(DPXImageElementDescriptor)
4500
1.17k
        dpx_image_info.element_info[element].descriptor;
4501
4502
      /*
4503
        Determine component packing method.
4504
      */
4505
1.17k
      packing_method=(ImageComponentPackingMethod) dpx_image_info.element_info[element].packing;
4506
1.17k
      samples_per_pixel=DPXSamplesPerPixel(element_descriptor);
4507
1.17k
      samples_per_row=samples_per_pixel*image->columns;
4508
4509
      /*
4510
        Are datums returned in reverse order when extracted from a
4511
        32-bit word?  This is to support Note 2 in Table 1 which
4512
        describes how RGB/RGBA are returned in reversed order for the
4513
        10-bit "filled" format.  Note 3 refers to Note 2 so presumably
4514
        the same applies for ABGR.  The majority of YCbCr 4:2:2 files
4515
        received have been swapped (but not YCbCr 4:4:4 for some
4516
        reason) so swap the samples for YCbCr as well.
4517
      */
4518
1.17k
      if ((element_descriptor == ImageElementRGB) ||
4519
991
          (element_descriptor == ImageElementRGBA) ||
4520
876
          (element_descriptor == ImageElementABGR) ||
4521
876
          (element_descriptor == ImageElementCbYCrY422) ||
4522
876
          (element_descriptor == ImageElementCbYACrYA4224) ||
4523
876
          (element_descriptor == ImageElementCbYCr444) ||
4524
763
          (element_descriptor == ImageElementCbYCrA4444))
4525
488
        {
4526
488
          if ((bits_per_sample == 10) && (packing_method != PackingMethodPacked))
4527
89
            swap_word_datums = MagickTrue;
4528
488
        }
4529
1.17k
      if ((definition_value=AccessDefinition(image_info,"dpx","swap-samples")) ||
4530
1.17k
          (definition_value=AccessDefinition(image_info,"dpx","swap-samples-write")))
4531
0
        {
4532
0
          if (LocaleCompare(definition_value,"false") != 0)
4533
0
            swap_word_datums = swap_word_datums ? MagickFalse : MagickTrue;
4534
0
        }
4535
      /*
4536
        Create a chroma image if we are subsampling YCbCr.
4537
      */
4538
1.17k
      if (((element_descriptor == ImageElementCbYCrY422) ||
4539
1.17k
           (element_descriptor == ImageElementCbYACrYA4224) ||
4540
1.17k
           (element_descriptor == ImageElementColorDifferenceCbCr)) &&
4541
0
          (chroma_image == (Image *) NULL))
4542
0
        {
4543
0
          chroma_image=ResizeImage(image,image->columns/2,image->rows,
4544
0
                                   LanczosFilter,1.0,&image->exception);
4545
0
          if (chroma_image == (Image *) NULL)
4546
0
            ThrowDPXWriterException(ResourceLimitError,MemoryAllocationFailed,image);
4547
0
        }
4548
4549
115k
      for (y=0; y < image->rows; y++)
4550
114k
        {
4551
114k
          p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
4552
114k
          if (p == (const PixelPacket *) NULL)
4553
0
            break;
4554
4555
114k
          samples_itr=samples;
4556
          /*
4557
            Prepare row samples.
4558
          */
4559
114k
          switch (element_descriptor)
4560
114k
            {
4561
0
            case ImageElementRed:
4562
0
              for (x=image->columns; x != 0; x--)
4563
0
                {
4564
0
                  *samples_itr++=map_Y[ScaleQuantumToMap(GetRedSample(p))];
4565
0
                  p++;
4566
0
                }
4567
0
              break;
4568
0
            case ImageElementGreen:
4569
0
              for (x=image->columns; x != 0; x--)
4570
0
                {
4571
0
                  *samples_itr++=map_Y[ScaleQuantumToMap(GetGreenSample(p))];
4572
0
                  p++;
4573
0
                }
4574
0
              break;
4575
0
            case ImageElementBlue:
4576
0
              for (x=image->columns; x != 0; x--)
4577
0
                {
4578
0
                  *samples_itr++=map_Y[ScaleQuantumToMap(GetBlueSample(p))];
4579
0
                  p++;
4580
0
                }
4581
0
              break;
4582
19.4k
            case ImageElementAlpha:
4583
19.4k
              {
4584
121k
                for (x=image->columns; x != 0; x--)
4585
101k
                  {
4586
101k
                    *samples_itr++=map_Y[ScaleQuantumToMap(GetOpacitySample(p))];
4587
101k
                    p++;
4588
101k
                  }
4589
19.4k
                break;
4590
0
              }
4591
0
            case ImageElementUnspecified:
4592
58.6k
            case ImageElementLuma:
4593
58.6k
              {
4594
58.6k
                if ((transfer_characteristic == TransferCharacteristicITU_R709) ||
4595
54.7k
                    (transfer_characteristic == TransferCharacteristicITU_R601_625L) ||
4596
25.7k
                    (transfer_characteristic == TransferCharacteristicITU_R601_525L))
4597
38.6k
                  {
4598
                    /* Video luma */
4599
3.69M
                    for (x=image->columns; x != 0; x--)
4600
3.65M
                      {
4601
3.65M
                        *samples_itr++=map_Y[ScaleQuantumToMap(GetYSample(p))];
4602
3.65M
                        p++;
4603
3.65M
                      }
4604
38.6k
                  }
4605
19.9k
                else
4606
19.9k
                  {
4607
                    /* Linear gray */
4608
5.45M
                    for (x=image->columns; x != 0; x--)
4609
5.43M
                      {
4610
5.43M
                        *samples_itr++=map_Y[ScaleQuantumToMap(GetGraySample(p))];
4611
5.43M
                        p++;
4612
5.43M
                      }
4613
19.9k
                  }
4614
58.6k
                break;
4615
0
              }
4616
0
            case ImageElementColorDifferenceCbCr:
4617
0
              {
4618
                /* CbCr */
4619
0
                const PixelPacket
4620
0
                  *chroma_pixels;
4621
4622
0
                chroma_pixels=AcquireImagePixels(chroma_image,0,y,chroma_image->columns,1,
4623
0
                                                 &image->exception);
4624
0
                if (chroma_pixels == (const PixelPacket *) NULL)
4625
0
                  break;
4626
4627
0
                for (x=image->columns; x != 0; x -= 2)
4628
0
                  {
4629
0
                    *samples_itr++=map_CbCr[ScaleQuantumToMap(GetCbSample(chroma_pixels))]; /* Cb */
4630
0
                    *samples_itr++=map_CbCr[ScaleQuantumToMap(GetCrSample(chroma_pixels))]; /* Cr */
4631
0
                    chroma_pixels++;
4632
0
                  }
4633
0
                break;
4634
0
              }
4635
15.6k
            case ImageElementRGB:
4636
4.56M
              for (x=image->columns; x != 0; x--)
4637
4.55M
                {
4638
#if 0
4639
                  /* BGR */
4640
                  *samples_itr++=map_Y[ScaleQuantumToMap(GetBlueSample(p))];
4641
                  *samples_itr++=map_Y[ScaleQuantumToMap(GetGreenSample(p))];
4642
                  *samples_itr++=map_Y[ScaleQuantumToMap(GetRedSample(p))];
4643
#else
4644
4.55M
                  *samples_itr++=map_Y[ScaleQuantumToMap(GetRedSample(p))];
4645
4.55M
                  *samples_itr++=map_Y[ScaleQuantumToMap(GetGreenSample(p))];
4646
4.55M
                  *samples_itr++=map_Y[ScaleQuantumToMap(GetBlueSample(p))];
4647
4.55M
#endif
4648
4.55M
                  p++;
4649
4.55M
                }
4650
15.6k
              break;
4651
7.95k
            case ImageElementRGBA:
4652
671k
              for (x=image->columns; x != 0; x--)
4653
663k
                {
4654
#if 0
4655
                  /* BGRA */
4656
                  *samples_itr++=map_Y[ScaleQuantumToMap(GetBlueSample(p))];
4657
                  *samples_itr++=map_Y[ScaleQuantumToMap(GetGreenSample(p))];
4658
                  *samples_itr++=map_Y[ScaleQuantumToMap(GetRedSample(p))];
4659
#else
4660
663k
                  *samples_itr++=map_Y[ScaleQuantumToMap(GetRedSample(p))];
4661
663k
                  *samples_itr++=map_Y[ScaleQuantumToMap(GetGreenSample(p))];
4662
663k
                  *samples_itr++=map_Y[ScaleQuantumToMap(GetBlueSample(p))];
4663
663k
#endif
4664
663k
                  *samples_itr++=map_Y[ScaleQuantumToMap(GetOpacitySample(p))];
4665
663k
                  p++;
4666
663k
                }
4667
7.95k
              break;
4668
0
            case ImageElementCbYCrY422:
4669
0
              {
4670
                /* CbY | CrY | CbY | CrY ..., even number of columns required. */
4671
0
                const PixelPacket
4672
0
                  *chroma_pixels;
4673
4674
0
                chroma_pixels=AcquireImagePixels(chroma_image,0,y,chroma_image->columns,1,
4675
0
                                                 &image->exception);
4676
0
                if (chroma_pixels == (const PixelPacket *) NULL)
4677
0
                  break;
4678
4679
0
                for (x=image->columns; x != 0; x -= 2)
4680
0
                  {
4681
0
                    *samples_itr++=map_CbCr[ScaleQuantumToMap(GetCbSample(chroma_pixels))]; /* Cb */
4682
0
                    *samples_itr++=map_Y[ScaleQuantumToMap(GetYSample(p))];                 /* Y */
4683
0
                    p++;
4684
0
                    *samples_itr++=map_CbCr[ScaleQuantumToMap(GetCrSample(chroma_pixels))]; /* Cr */
4685
0
                    *samples_itr++=map_Y[ScaleQuantumToMap(GetYSample(p))];                 /* Y */
4686
0
                    p++;
4687
0
                    chroma_pixels++;
4688
0
                  }
4689
0
                break;
4690
0
              }
4691
0
            case ImageElementCbYACrYA4224:
4692
0
              {
4693
                /* CbYA | CrYA | CbYA | CrYA ..., even number of columns required. */
4694
0
                const PixelPacket
4695
0
                  *chroma_pixels;
4696
4697
0
                chroma_pixels=AcquireImagePixels(chroma_image,0,y,chroma_image->columns,1,
4698
0
                                                 &image->exception);
4699
0
                if (chroma_pixels == (const PixelPacket *) NULL)
4700
0
                  break;
4701
4702
0
                for (x=image->columns; x != 0; x -= 2)
4703
0
                  {
4704
0
                    *samples_itr++=map_CbCr[ScaleQuantumToMap(GetCbSample(chroma_pixels))]; /* Cb */
4705
0
                    *samples_itr++=map_Y[ScaleQuantumToMap(GetYSample(p))];                 /* Y */
4706
0
                    *samples_itr++=map_Y[ScaleQuantumToMap(GetOpacitySample(p))];           /* A */
4707
0
                    p++;
4708
0
                    *samples_itr++=map_CbCr[ScaleQuantumToMap(GetCrSample(chroma_pixels))]; /* Cr */
4709
0
                    *samples_itr++=map_Y[ScaleQuantumToMap(GetYSample(p))];                 /* Y */
4710
0
                    *samples_itr++=map_Y[ScaleQuantumToMap(GetOpacitySample(p))];           /* A */
4711
0
                    p++;
4712
0
                    chroma_pixels++;
4713
0
                  }
4714
0
                break;
4715
0
              }
4716
11.4k
            case ImageElementCbYCr444:
4717
3.66M
              for (x=image->columns; x != 0; x--)
4718
3.65M
                {
4719
3.65M
                  *samples_itr++=map_CbCr[ScaleQuantumToMap(GetCbSample(p))]; /* Cb */
4720
3.65M
                  *samples_itr++=map_Y[ScaleQuantumToMap(GetYSample(p))];     /* Y */
4721
3.65M
                  *samples_itr++=map_CbCr[ScaleQuantumToMap(GetCrSample(p))]; /* Cr */
4722
3.65M
                  p++;
4723
3.65M
                }
4724
11.4k
              break;
4725
1.69k
            case ImageElementCbYCrA4444:
4726
11.0k
              for (x=image->columns; x != 0; x--)
4727
9.33k
                {
4728
9.33k
                  *samples_itr++=map_CbCr[ScaleQuantumToMap(GetCbSample(p))];   /* Cb */
4729
9.33k
                  *samples_itr++=map_Y[ScaleQuantumToMap(GetYSample(p))];       /* Y */
4730
9.33k
                  *samples_itr++=map_CbCr[ScaleQuantumToMap(GetCrSample(p))];   /* Cr */
4731
9.33k
                  *samples_itr++=map_Y[ScaleQuantumToMap(GetOpacitySample(p))]; /* A */
4732
9.33k
                  p++;
4733
9.33k
                }
4734
1.69k
              break;
4735
4736
0
            default:
4737
0
              break;
4738
114k
            }
4739
4740
          /*
4741
            FIXME: RLE samples.
4742
          */
4743
4744
          /*
4745
            Output samples.
4746
          */
4747
114k
          WriteRowSamples(samples, samples_per_row, bits_per_sample,
4748
114k
                          packing_method,endian_type,swap_word_datums,scanline);
4749
114k
          if (WriteBlob(image,row_octets,(void *) scanline) != row_octets)
4750
22
            {
4751
22
              status=MagickFail;
4752
22
              break;
4753
22
            }
4754
114k
          if (image->previous == (Image *) NULL)
4755
114k
            if (QuantumTick(y,image->rows))
4756
27.1k
              if (!MagickMonitorFormatted(y,image->rows,&image->exception,
4757
27.1k
                                          SaveImageText,image->filename,
4758
27.1k
                                          image->columns,image->rows))
4759
0
                break;
4760
114k
        }
4761
1.17k
    }
4762
4763
  /*
4764
    Validate that what we are writing matches the header offsets.
4765
  */
4766
1.07k
  {
4767
1.07k
    magick_off_t
4768
1.07k
      reported_file_offset;
4769
4770
1.07k
    reported_file_offset = TellBlob(image);
4771
1.07k
    if ((reported_file_offset != -1) &&
4772
1.07k
        ((magick_off_t) dpx_file_info.file_size != reported_file_offset))
4773
148
      {
4774
148
        (void) fprintf(stderr,"### File length %u, TellBlob says %" MAGICK_OFF_F "d\n",
4775
148
                       dpx_file_info.file_size,
4776
148
                       (magick_off_t) reported_file_offset);
4777
148
      }
4778
1.07k
  }
4779
4780
1.07k
  MagickFreeResourceLimitedMemory(map_CbCr);
4781
1.07k
  MagickFreeResourceLimitedMemory(map_Y);
4782
1.07k
  MagickFreeResourceLimitedMemory(samples);
4783
1.07k
  MagickFreeResourceLimitedMemory(scanline);
4784
1.07k
  status &= CloseBlob(image);
4785
1.07k
  if (chroma_image != (Image *) NULL)
4786
0
    {
4787
0
      DestroyImage(chroma_image);
4788
      chroma_image = (Image *) NULL;
4789
0
    }
4790
1.07k
  return(status);
4791
1.07k
}