1 /*
2 % Copyright (C) 2005-2020 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 ammended 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 #define SET_UNDEFINED_U8(value)  (value=0xFFU)
165 #define SET_UNDEFINED_U16(value) (value=0xFFFFU)
166 #define SET_UNDEFINED_U32(value) (value=0xFFFFFFFFU)
167 #define SET_UNDEFINED_R32(value) (value.u=~0U);
168 #define SET_UNDEFINED_ASCII(value) ((void) memset(value,0,sizeof(value)))
169 
170 #define IS_UNDEFINED_U8(value) (value == ((U8) 0xFFU))
171 #define IS_UNDEFINED_U16(value) (value == ((U16) 0xFFFFU))
172 #define IS_UNDEFINED_U32(value) (value == ((U32) 0xFFFFFFFFU))
173 #define IS_UNDEFINED_R32(value) (value.u == ((U32) ~0U))
174 #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 */
IsDPX(const unsigned char * magick,const size_t length)431 STATIC unsigned int IsDPX(const unsigned char *magick,const size_t length)
432 {
433   return ((length >= 4) &&
434           ((memcmp(magick,"SDPX",4) == 0) || (memcmp(magick,"XPDS",4) == 0)));
435 }
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 #define LogSetImageAttribute(name,value) \
468 { \
469   (void) LogMagickEvent(CoderEvent,GetMagickModule(), \
470                         "Attribute \"%s\" set to \"%s\"", \
471                         name,value); \
472 }
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 #define StringToAttribute(image,name,member) \
479 { \
480   char \
481     buffer_[MaxTextExtent]; \
482 \
483   if (!IS_UNDEFINED_ASCII(member)) \
484     { \
485       (void) memcpy(buffer_,member,Min(sizeof(member),MaxTextExtent)); \
486       buffer_[Min(sizeof(member),MaxTextExtent-1)]='\0';             \
487       (void) SetImageAttribute(image,name,buffer_); \
488       LogSetImageAttribute(name,buffer_); \
489     } \
490 }
491 #define U8ToAttribute(image,name,member) \
492 { \
493   char \
494     buffer_[MaxTextExtent]; \
495 \
496   if (!IS_UNDEFINED_U8(member)) \
497     { \
498       FormatString(buffer_,"%u",(unsigned int) member); \
499       (void) SetImageAttribute(image,name,buffer_); \
500       LogSetImageAttribute(name,buffer_); \
501     } \
502 }
503 #define U16ToAttribute(image,name,member) \
504 { \
505   char \
506     buffer_[MaxTextExtent]; \
507 \
508   if (!IS_UNDEFINED_U16(member)) \
509     { \
510       FormatString(buffer_,"%u",(unsigned int) member); \
511       (void) SetImageAttribute(image,name,buffer_); \
512       LogSetImageAttribute(name,buffer_); \
513     } \
514 }
515 #define U32ToAttribute(image,name,member) \
516 { \
517   char \
518     buffer_[MaxTextExtent]; \
519 \
520   if (!IS_UNDEFINED_U32(member)) \
521     { \
522       FormatString(buffer_,"%u",member); \
523       (void) SetImageAttribute(image,name,buffer_); \
524       LogSetImageAttribute(name,buffer_); \
525     } \
526 }
527 #define U32ToBitsAttribute(image,name,member) \
528 { \
529   char \
530     buffer_[MaxTextExtent]; \
531 \
532   if (!IS_UNDEFINED_U32(member)) \
533     { \
534       SMPTEBitsToString(member,buffer_); \
535       (void) SetImageAttribute(image,name,buffer_); \
536       LogSetImageAttribute(name,buffer_); \
537     } \
538 }
539 #define R32ToAttribute(image,name,member) \
540 { \
541   char \
542     buffer_[MaxTextExtent]; \
543 \
544   if (!IS_UNDEFINED_R32(member)) \
545     { \
546       FormatString(buffer_,"%g",member.f); \
547       (void) SetImageAttribute(image,name,buffer_); \
548       LogSetImageAttribute(name,buffer_); \
549     } \
550 }
SwabDPXFileInfo(DPXFileInfo * file_info)551 STATIC void SwabDPXFileInfo(DPXFileInfo *file_info)
552 {
553   MagickSwabUInt32(&file_info->magic);
554   MagickSwabUInt32(&file_info->image_data_offset);
555   MagickSwabUInt32(&file_info->file_size);
556   MagickSwabUInt32(&file_info->ditto_key);
557   MagickSwabUInt32(&file_info->generic_section_length);
558   MagickSwabUInt32(&file_info->industry_section_length);
559   MagickSwabUInt32(&file_info->user_defined_length);
560   MagickSwabUInt32(&file_info->encryption_key);
561 }
SwabDPXImageInfo(DPXImageInfo * image_info)562 STATIC void SwabDPXImageInfo(DPXImageInfo *image_info)
563 {
564   int
565     i;
566 
567   MagickSwabUInt16(&image_info->orientation);
568   MagickSwabUInt16(&image_info->elements);
569   MagickSwabUInt32(&image_info->pixels_per_line);
570   MagickSwabUInt32(&image_info->lines_per_image_element);
571   for (i=0 ; i < 8 ; i++)
572     {
573       MagickSwabUInt32(&image_info->element_info[i].data_sign);
574       MagickSwabUInt32(&image_info->element_info[i].reference_low_data_code);
575       MagickSwabFloat(&image_info->element_info[i].reference_low_quantity.f);
576       MagickSwabUInt32(&image_info->element_info[i].reference_high_data_code);
577       MagickSwabFloat(&image_info->element_info[i].reference_high_quantity.f);
578       MagickSwabUInt16(&image_info->element_info[i].packing);
579       MagickSwabUInt16(&image_info->element_info[i].encoding);
580       MagickSwabUInt32(&image_info->element_info[i].data_offset);
581       MagickSwabUInt32(&image_info->element_info[i].eol_pad);
582       MagickSwabUInt32(&image_info->element_info[i].eoi_pad);
583     }
584 }
SwabDPXImageSourceInfo(DPXImageSourceInfo * source_info)585 STATIC void SwabDPXImageSourceInfo(DPXImageSourceInfo *source_info)
586 {
587   MagickSwabUInt32(&source_info->x_offset);
588   MagickSwabUInt32(&source_info->y_offset);
589   MagickSwabFloat(&source_info->x_center.f);
590   MagickSwabFloat(&source_info->y_center.f);
591   MagickSwabUInt32(&source_info->x_original_size);
592   MagickSwabUInt32(&source_info->y_original_size);
593   MagickSwabUInt16(&source_info->border_validity.XL);
594   MagickSwabUInt16(&source_info->border_validity.XR);
595   MagickSwabUInt16(&source_info->border_validity.YT);
596   MagickSwabUInt16(&source_info->border_validity.YB);
597   MagickSwabUInt32(&source_info->aspect_ratio.horizontal);
598   MagickSwabUInt32(&source_info->aspect_ratio.vertical);
599   MagickSwabFloat(&source_info->x_scanned_size.f);
600   MagickSwabFloat(&source_info->y_scanned_size.f);
601 }
SwabDPXMPFilmInfo(DPXMPFilmInfo * mp_info)602 STATIC void SwabDPXMPFilmInfo(DPXMPFilmInfo *mp_info)
603 {
604   MagickSwabUInt32(&mp_info->frame_position);
605   MagickSwabUInt32(&mp_info->sequence_length);
606   MagickSwabUInt32(&mp_info->held_count);
607   MagickSwabFloat(&mp_info->frame_rate.f);
608   MagickSwabFloat(&mp_info->shutter_angle.f);
609 }
SwabDPXTVInfo(DPXTVInfo * tv_info)610 STATIC void SwabDPXTVInfo(DPXTVInfo *tv_info)
611 {
612   MagickSwabUInt32(&tv_info->time_code);
613   MagickSwabUInt32(&tv_info->user_bits);
614   MagickSwabFloat(&tv_info->horizontal_sample.f);
615   MagickSwabFloat(&tv_info->vertical_sample.f);
616   MagickSwabFloat(&tv_info->temporal_sample.f);
617   MagickSwabFloat(&tv_info->sync_time.f);
618   MagickSwabFloat(&tv_info->gamma.f);
619   MagickSwabFloat(&tv_info->black_level.f);
620   MagickSwabFloat(&tv_info->black_gain.f);
621   MagickSwabFloat(&tv_info->breakpoint.f);
622   MagickSwabFloat(&tv_info->white_level.f);
623   MagickSwabFloat(&tv_info->integration_time.f);
624 }
SMPTEBitsToString(const U32 value,char * str)625 STATIC void SMPTEBitsToString(const U32 value, char *str)
626 {
627   unsigned int
628     pos,
629     shift = 28;
630 
631   for (pos=8; pos != 0; pos--, shift -= 4)
632     {
633       (void) sprintf(str,"%01u",(unsigned int) ((value >> shift) & 0x0fU));
634       str += 1;
635       if ((pos > 2) && (pos % 2))
636         {
637           (void) strcat(str,":");
638           str++;
639         }
640     }
641   *str='\0';
642 }
SMPTEStringToBits(const char * str)643 STATIC U32 SMPTEStringToBits(const char *str)
644 {
645   U32
646     value=0;
647 
648   unsigned int
649     pos = 0,
650     shift = 28;
651 
652   char
653     buff[2];
654 
655   buff[1]='\0';
656 
657   while ((*str != 0) && (pos < 8))
658     {
659       if (!isdigit((int) *str))
660         {
661           str++;
662           continue;
663         }
664       buff[0]=*str++;
665       value |= (U32) ((strtol(buff,(char **)NULL,10)) << shift);
666       shift -= 4;
667       pos++;
668     }
669   return value;
670 }
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 */
DPXRowOctets(const unsigned long rows,const unsigned int samples_per_row,const unsigned int bits_per_sample,const ImageComponentPackingMethod packing_method)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 {
680   size_t
681     octets = 0;
682 
683   switch(bits_per_sample)
684     {
685     case 1:
686       /* Packed 1-bit samples in 32-bit words. Rows are padded out to 32-bit alignment */
687       octets=rows*(((magick_int64_t) samples_per_row*bits_per_sample+31)/32)*sizeof(U32);
688       break;
689     case 8:
690       /* C.1 8-bit samples in a 32-bit word. Rows are padded out to 32-bit alignment */
691       octets=rows*(((magick_int64_t) samples_per_row*bits_per_sample+31)/32)*sizeof(U32);
692       break;
693     case 32:
694       /* 32-bit samples in a 32-bit word */
695       octets=samples_per_row*sizeof(U32)*rows;
696       break;
697     case 10:
698       if ((packing_method == PackingMethodWordsFillLSB) ||
699           (packing_method == PackingMethodWordsFillMSB))
700         {
701           /* C.3 Three 10-bit samples per 32-bit word */
702           octets=(((((magick_int64_t) (rows*samples_per_row+2)/3)*sizeof(U32)*8)+31)/32)*sizeof(U32);
703         }
704       else
705         {
706           /* C.2 Packed 10-bit samples in a 32-bit word. */
707           octets=rows*(((magick_int64_t) samples_per_row*bits_per_sample+31)/32)*sizeof(U32);
708         }
709       break;
710     case 12:
711       if ((packing_method == PackingMethodWordsFillLSB) ||
712           (packing_method == PackingMethodWordsFillMSB))
713         {
714           /* C.5: One 12-bit sample per 16-bit word */
715           octets=((((magick_int64_t) rows*samples_per_row*sizeof(U16)*8)+15)/16)*sizeof(U16);
716         }
717       else
718         {
719           /* C.4: Packed 12-bit samples in a 32-bit word. */
720           octets=rows*(((magick_int64_t) samples_per_row*bits_per_sample+31)/32)*sizeof(U32);
721         }
722       break;
723     case 16:
724       /* C.6 16-bit samples in 16-bit words. */
725       octets=((((magick_int64_t) rows*samples_per_row*bits_per_sample)+15)/16)*sizeof(U16);
726       break;
727     case 64:
728       /* 64-bit samples in 64-bit words. */
729       octets=(magick_int64_t) rows*samples_per_row*8;
730       break;
731     }
732 
733   return octets;
734 }
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
DescribeImageElementDescriptor(char * buffer,const DPXImageElementDescriptor descriptor)754 STATIC const char *DescribeImageElementDescriptor(char *buffer, const DPXImageElementDescriptor descriptor)
755 {
756   const char *
757     description="Unknown";
758 
759   switch(descriptor)
760     {
761     case ImageElementUnspecified:
762       description="Generic 1 Element";
763       break;
764     case ImageElementRed:
765       description="Red";
766       break;
767     case ImageElementGreen:
768       description="Green";
769       break;
770     case ImageElementBlue:
771       description="Blue";
772       break;
773     case ImageElementAlpha:
774       description="Alpha";
775       break;
776     case ImageElementLuma:
777       description="Luma";
778       break;
779     case ImageElementColorDifferenceCbCr:
780       description="CbCr";
781       break;
782     case ImageElementDepth:
783       description="Depth(8)";
784       break;
785     case ImageElementCompositeVideo:
786       description="CompositeVideo";
787       break;
788     case ImageElementRGB:
789       description="RGB";
790       break;
791     case ImageElementRGBA:
792       description="RGBA";
793       break;
794     case ImageElementABGR:
795       description="ABGR";
796       break;
797     case ImageElementCbYCrY422:
798       description="CbYCrY 4:2:2";
799       break;
800     case ImageElementCbYACrYA4224:
801       description="CbYACrYA 4:2:2:4";
802       break;
803     case ImageElementCbYCr444:
804       description="CbYCr 4:4:4";
805       break;
806     case ImageElementCbYCrA4444:
807       description="CbYCrA 4:4:4:4";
808       break;
809     case ImageElementUserDef2Element:
810       description="Generic 2 Element";
811       break;
812     case ImageElementUserDef3Element:
813       description="Generic 3 Element";
814       break;
815     case ImageElementUserDef4Element:
816       description="Generic 4 Element";
817       break;
818     case ImageElementUserDef5Element:
819       description="Generic 5 Element";
820       break;
821     case ImageElementUserDef6Element:
822       description="Generic 6 Element";
823       break;
824     case ImageElementUserDef7Element:
825       description="Generic 7 Element";
826       break;
827     case ImageElementUserDef8Element:
828       description="Generic 8 Element";
829       break;
830     default:
831       {
832         FormatString(buffer,"Unknown (%u)",(unsigned int) descriptor);
833         description=buffer;
834       }
835     }
836 
837   return description;
838 }
839 /*
840   Describe the element transfer characteristic.
841 */
DescribeImageTransferCharacteristic(char * buffer,const DPXTransferCharacteristic characteristic)842 STATIC const char *DescribeImageTransferCharacteristic(char *buffer, const DPXTransferCharacteristic characteristic)
843 {
844   const char
845     *description=buffer;
846 
847   buffer[0]='\0';
848   switch(characteristic)
849     {
850     case TransferCharacteristicUserDefined:
851       description="UserDefined";
852       break;
853     case TransferCharacteristicPrintingDensity:
854       description="PrintingDensity";
855       break;
856     case TransferCharacteristicLinear:
857       description="Linear";
858       break;
859     case TransferCharacteristicLogarithmic:
860       description="Logarithmic";
861       break;
862     case TransferCharacteristicUnspecifiedVideo:
863       description="UnspecifiedVideo";
864       break;
865     case TransferCharacteristicSMTPE274M:
866       description="SMTPE274M";
867       break;
868     case TransferCharacteristicITU_R709:
869       description="ITU-R709";
870       break;
871     case TransferCharacteristicITU_R601_625L:
872       description="ITU-R601-625L";
873       break;
874     case TransferCharacteristicITU_R601_525L:
875       description="ITU-R601-525L";
876       break;
877     case TransferCharacteristicNTSCCompositeVideo:
878       description="NTSCCompositeVideo";
879       break;
880     case TransferCharacteristicPALCompositeVideo:
881       description="PALCompositeVideo";
882       break;
883     case TransferCharacteristicZDepthLinear:
884       description="ZDepthLinear";
885       break;
886     case TransferCharacteristicZDepthHomogeneous:
887       description="ZDepthHomogeneous";
888       break;
889     default:
890       {
891         FormatString(buffer,"Reserved(%u)",(unsigned int) characteristic);
892       }
893     }
894 
895   return description;
896 }
897 /*
898   Describe the element colorimetric.
899 */
DescribeImageColorimetric(char * buffer,const DPXColorimetric colorimetric)900 STATIC const char *DescribeImageColorimetric(char *buffer, const DPXColorimetric colorimetric)
901 {
902   const char
903     *description=buffer;
904 
905   buffer[0]='\0';
906   switch(colorimetric)
907     {
908     case ColorimetricUserDefined:
909       description="UserDefined";
910       break;
911     case ColorimetricPrintingDensity:
912       description="PrintingDensity";
913       break;
914     case ColorimetricLinear:
915       description="NotApplicable";
916       break;
917     case ColorimetricLogarithmic:
918       description="NotApplicable";
919       break;
920     case ColorimetricUnspecifiedVideo:
921       description="UnspecifiedVideo";
922       break;
923     case ColorimetricSMTPE274M:
924       description="SMTPE274M";
925       break;
926     case ColorimetricITU_R709:
927       description="ITU-R709";
928       break;
929     case ColorimetricITU_R601_625L:
930       description="ITU-R601-625L";
931       break;
932     case ColorimetricITU_R601_525L:
933       description="ITU-R601-525L";
934       break;
935     case ColorimetricNTSCCompositeVideo:
936       description="NTSCCompositeVideo";
937       break;
938     case ColorimetricPALCompositeVideo:
939       description="PALCompositeVideo";
940       break;
941     case ColorimetricZDepthLinear:
942       description="NotApplicable";
943       break;
944     case ColorimetricZDepthHomogeneous:
945       description="NotApplicable";
946       break;
947     default:
948       {
949         FormatString(buffer,"Reserved(%u)",(unsigned int) colorimetric);
950       }
951     }
952 
953   return description;
954 }
955 /*
956   Describe the image element.
957 */
DescribeDPXImageElement(const DPXImageElement * element_info,const unsigned int element)958 STATIC void DescribeDPXImageElement(const DPXImageElement *element_info,
959                                     const unsigned int element)
960 {
961   char txt_buffer[MaxTextExtent];
962 
963   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
964                         "Element %u: data_sign=%s",element,
965                         element_info->data_sign == 0 ?
966                         "unsigned(0)" : "signed(1)");
967   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
968                         "Element %u: reference_low_data_code=%u reference_low_quantity=%g",
969                         element,
970                         element_info->reference_low_data_code,
971                         element_info->reference_low_quantity.f);
972   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
973                         "Element %u: reference_high_data_code=%u reference_high_quantity=%g",
974                         element,
975                         element_info->reference_high_data_code,
976                         element_info->reference_high_quantity.f);
977   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
978                         "Element %u: descriptor=%s(%u) transfer_characteristic=%s(%u) colorimetric=%s(%u)",
979                         element,
980                         DescribeImageElementDescriptor(txt_buffer,(DPXImageElementDescriptor) element_info->descriptor),
981                         (unsigned int) element_info->descriptor,
982                         DescribeImageTransferCharacteristic(txt_buffer,(DPXTransferCharacteristic) element_info->transfer_characteristic),
983                         (unsigned int) element_info->transfer_characteristic,
984                         DescribeImageColorimetric(txt_buffer,(DPXColorimetric) element_info->colorimetric),
985                         (unsigned int) element_info->colorimetric);
986   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
987                         "Element %u: bits-per-sample=%u",
988                         element,
989                         (unsigned int) element_info->bits_per_sample);
990   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
991                         "Element %u: packing=%s encoding=%s data_offset=%u eol_pad=%u eoi_pad=%u",
992                         element,
993                         (element_info->packing == PackingMethodPacked ? "Packed(0)" :
994                          element_info->packing == PackingMethodWordsFillLSB ? "PadLSB(1)" :
995                          element_info->packing == PackingMethodWordsFillMSB ? "PadMSB(2)" :
996                          "Unknown"),
997                         (element_info->encoding == 0 ? "None(0)" :
998                          element_info->encoding == 1 ? "RLE(1)" :
999                          "Unknown"),
1000                         (unsigned int) element_info->data_offset,
1001                         (unsigned int) element_info->eol_pad,
1002                         (unsigned int) element_info->eoi_pad);
1003   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1004                         "Element %u: description=\"%.32s\"",
1005                         element,
1006                         element_info->description);
1007 }
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 */
DPXSamplesPerPixel(const DPXImageElementDescriptor element_descriptor)1014 STATIC unsigned int  DPXSamplesPerPixel(const DPXImageElementDescriptor element_descriptor)
1015 {
1016   unsigned int
1017     samples_per_pixel=0;
1018 
1019   switch (element_descriptor)
1020     {
1021     case ImageElementUnspecified:
1022     case ImageElementRed:
1023     case ImageElementGreen:
1024     case ImageElementBlue:
1025     case ImageElementAlpha:
1026     case ImageElementLuma:
1027       samples_per_pixel=1;
1028       break;
1029     case ImageElementColorDifferenceCbCr: /* Cb | Cr 4:2:2 sampling ..., even number of columns required.*/
1030       samples_per_pixel=2;
1031       break;
1032     case ImageElementRGB:
1033       samples_per_pixel=3;
1034       break;
1035     case ImageElementRGBA:
1036     case ImageElementABGR:
1037       samples_per_pixel=4;
1038       break;
1039     case ImageElementCbYCrY422:
1040       /* CbY | CrY | CbY | CrY ..., even number of columns required. */
1041       samples_per_pixel=2;
1042       break;
1043     case ImageElementCbYACrYA4224:
1044       /* CbYA | CrYA | CbYA | CrYA ..., even number of columns required. */
1045       samples_per_pixel=3;
1046       break;
1047     case ImageElementCbYCr444:
1048       samples_per_pixel=3;
1049       break;
1050     case ImageElementCbYCrA4444:
1051       samples_per_pixel=4;
1052       break;
1053     default:
1054       samples_per_pixel=0;
1055       break;
1056     }
1057 
1058   return samples_per_pixel;
1059 }
1060 /*
1061   Set the image primary chromaticities based on the colorimetric.
1062 */
DPXSetPrimaryChromaticities(const DPXColorimetric colorimetric,ChromaticityInfo * chromaticity_info)1063 STATIC void DPXSetPrimaryChromaticities(const DPXColorimetric colorimetric,
1064                                         ChromaticityInfo *chromaticity_info)
1065 {
1066   switch(colorimetric)
1067     {
1068     case ColorimetricSMTPE274M:
1069     case ColorimetricITU_R709:/* ITU R709 */
1070       /* ITU-R BT.709-5, D65 */
1071       chromaticity_info->red_primary.x=0.640;
1072       chromaticity_info->red_primary.y=0.330;
1073       chromaticity_info->red_primary.z=0.030;
1074       chromaticity_info->green_primary.x=0.300;
1075       chromaticity_info->green_primary.y=0.600;
1076       chromaticity_info->green_primary.z=0.100;
1077       chromaticity_info->blue_primary.x=0.150;
1078       chromaticity_info->blue_primary.y=0.060;
1079       chromaticity_info->blue_primary.z=0.790;
1080       chromaticity_info->white_point.x=0.3127;
1081       chromaticity_info->white_point.y=0.3290;
1082       chromaticity_info->white_point.z=0.3582;
1083       break;
1084 
1085     case ColorimetricNTSCCompositeVideo:
1086       /* Obsolete NTSC primaries, White CIE III. C */
1087       chromaticity_info->red_primary.x=0.67;
1088       chromaticity_info->red_primary.y=0.33;
1089       chromaticity_info->red_primary.z=0.00;
1090       chromaticity_info->green_primary.x=0.21;
1091       chromaticity_info->green_primary.y=0.71;
1092       chromaticity_info->green_primary.z=0.08;
1093       chromaticity_info->blue_primary.x=0.14;
1094       chromaticity_info->blue_primary.y=0.08;
1095       chromaticity_info->blue_primary.z=0.78;
1096       chromaticity_info->white_point.x=0.310;
1097       chromaticity_info->white_point.y=0.316;
1098       chromaticity_info->white_point.z=0.374;
1099       break;
1100 
1101     case ColorimetricPALCompositeVideo:
1102       /* EBU Tech. 3213 primaries, D65 */
1103       chromaticity_info->red_primary.x=0.640;
1104       chromaticity_info->red_primary.y=0.330;
1105       chromaticity_info->red_primary.z=0.030;
1106       chromaticity_info->green_primary.x=0.290;
1107       chromaticity_info->green_primary.y=0.600;
1108       chromaticity_info->green_primary.z=0.110;
1109       chromaticity_info->blue_primary.x=0.150;
1110       chromaticity_info->blue_primary.y=0.060;
1111       chromaticity_info->blue_primary.z=0.790;
1112       chromaticity_info->white_point.x=0.3127;
1113       chromaticity_info->white_point.y=0.3290;
1114       chromaticity_info->white_point.z=0.3582;
1115       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     case ColorimetricITU_R601_625L: /* 625 Line ITU R601-5 B & G */
1135     case ColorimetricITU_R601_525L: /* 525 Line ITU R601-5 M */
1136 
1137     case ColorimetricUserDefined: /* User defined */
1138     case ColorimetricPrintingDensity: /* Printing density */
1139     case ColorimetricLinear: /* Linear */
1140     case ColorimetricLogarithmic: /* Logarithmic */
1141     case ColorimetricUnspecifiedVideo:
1142     default:
1143       {
1144         break;
1145       }
1146     }
1147 }
1148 
1149 STATIC OrientationType
DPXOrientationToOrientationType(const unsigned int orientation)1150 DPXOrientationToOrientationType(const unsigned int orientation)
1151 {
1152   OrientationType
1153     orientation_type = UndefinedOrientation;
1154 
1155   switch (orientation)
1156     {
1157     case 0U:
1158       orientation_type=TopLeftOrientation;
1159       break;
1160     case 1U:
1161       orientation_type=TopRightOrientation;
1162       break;
1163     case 2U:
1164       orientation_type=BottomLeftOrientation;
1165       break;
1166     case 3U:
1167       orientation_type=BottomRightOrientation;
1168       break;
1169     case 4U:
1170       orientation_type=LeftTopOrientation;
1171       break;
1172     case 5U:
1173       orientation_type=RightTopOrientation;
1174       break;
1175     case 6U:
1176       orientation_type=LeftBottomOrientation;
1177       break;
1178     case 7U:
1179       orientation_type=RightBottomOrientation;
1180       break;
1181     }
1182 
1183   return orientation_type;
1184 }
1185 
1186 #define LSBOctetsToPackedU32Word(scanline,packed_u32) \
1187 do { \
1188   packed_u32  = (((magick_uint32_t) *scanline++)); \
1189   packed_u32 |= (((magick_uint32_t) *scanline++) << 8); \
1190   packed_u32 |= (((magick_uint32_t) *scanline++) << 16); \
1191   packed_u32 |= (((magick_uint32_t) *scanline++) << 24); \
1192  } while(0)
1193 #define MSBOctetsToPackedU32Word(scanline,packed_u32) \
1194 do { \
1195   packed_u32  = (((magick_uint32_t) *scanline++) << 24); \
1196   packed_u32 |= (((magick_uint32_t) *scanline++) << 16); \
1197   packed_u32 |= (((magick_uint32_t) *scanline++) << 8); \
1198   packed_u32 |= (((magick_uint32_t) *scanline++)); \
1199  } while(0)
1200 
1201 /*
1202   Scale from a video level to a full-range level.
1203 */
ScaleFromVideo(const double sample,const double ref_low,const double upscale)1204 STATIC inline Quantum ScaleFromVideo(const double sample,
1205                                      const double ref_low,
1206                                      const double upscale)
1207 {
1208   double
1209     result = 0.0;
1210 
1211   if (sample > ref_low)
1212     result = (sample - ref_low)*upscale;
1213   return RoundDoubleToQuantum(result);
1214 
1215 }
1216 
1217 /*
1218   WordStreamLSBRead support
1219 */
1220 typedef struct _ReadWordU32State
1221 {
1222   const unsigned char *words;
1223 } ReadWordU32State;
1224 
ReadWordU32BE(void * state)1225 STATIC unsigned long ReadWordU32BE (void *state)
1226 {
1227   magick_uint32_t value;
1228   ReadWordU32State *read_state=(ReadWordU32State *) state;
1229   value =  ((magick_uint32_t) *read_state->words++) << 24;
1230   value |= ((magick_uint32_t) *read_state->words++) << 16;
1231   value |= ((magick_uint32_t) *read_state->words++) << 8;
1232   value |= ((magick_uint32_t) *read_state->words++);
1233   return value;
1234 }
1235 
ReadWordU32LE(void * state)1236 STATIC unsigned long ReadWordU32LE (void *state)
1237 {
1238   magick_uint32_t value;
1239   ReadWordU32State *read_state=(ReadWordU32State *) state;
1240   value = ((magick_uint32_t) *read_state->words++);
1241   value |= ((magick_uint32_t) *read_state->words++) << 8;
1242   value |= ((magick_uint32_t) *read_state->words++) << 16;
1243   value |= ((magick_uint32_t) *read_state->words++) << 24;
1244   return value;
1245 }
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 */
ReadRowSamples(const unsigned char * scanline,const unsigned int samples_per_row,const unsigned int bits_per_sample,const ImageComponentPackingMethod packing_method,const EndianType endian_type,const MagickBool swap_word_datums,sample_t * samples)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 {
1270   register unsigned long
1271     i;
1272 
1273   sample_t
1274     *sp;
1275 
1276   register unsigned int
1277     sample;
1278 
1279   sp=samples;
1280   if ((packing_method != PackingMethodPacked) &&
1281       ((bits_per_sample == 10) || (bits_per_sample == 12)))
1282     {
1283       MagickBool
1284         word_pad_lsb=MagickFalse,
1285         word_pad_msb=MagickFalse;
1286 
1287       if (packing_method == PackingMethodWordsFillLSB)
1288         word_pad_lsb=MagickTrue;
1289       else if (packing_method == PackingMethodWordsFillMSB)
1290         word_pad_msb=MagickTrue;
1291 
1292       if (bits_per_sample == 10)
1293         {
1294           register magick_uint32_t
1295             packed_u32 = 0;
1296 
1297           register unsigned int
1298             datum;
1299 
1300           unsigned int
1301             shifts[3] = { 0, 0, 0 };
1302 
1303           if (word_pad_lsb)
1304             {
1305               /*
1306                 Padding in LSB (Method A)  Standard method.
1307               */
1308               if (swap_word_datums == MagickFalse)
1309                 {
1310                   shifts[0]=2;  /* datum-0 / blue */
1311                   shifts[1]=12; /* datum-1 / green */
1312                   shifts[2]=22; /* datum-2 / red */
1313                 }
1314               else
1315                 {
1316                   shifts[0]=22; /* datum-2 / red */
1317                   shifts[1]=12; /* datum-1 / green */
1318                   shifts[2]=2;  /* datum-0 / blue */
1319                 }
1320             }
1321           else if (word_pad_msb)
1322             {
1323               /*
1324                 Padding in MSB (Method B)  Deprecated method.
1325               */
1326               if (swap_word_datums == MagickFalse)
1327                 {
1328                   shifts[0]=0;  /* datum-0 / blue */
1329                   shifts[1]=10; /* datum-1 / green */
1330                   shifts[2]=20; /* datum-2 / red */
1331                 }
1332               else
1333                 {
1334                   shifts[0]=20; /* datum-2 / red */
1335                   shifts[1]=10; /* datum-1 / green */
1336                   shifts[2]=0;  /* datum-0 / blue */
1337                 }
1338             }
1339 
1340           if (endian_type == MSBEndian)
1341             {
1342               for (i=0; i < samples_per_row; i++)
1343                 {
1344                   datum = i % 3;
1345                   if (datum == 0)
1346                     MSBOctetsToPackedU32Word(scanline,packed_u32);
1347                   *sp++=(packed_u32 >> shifts[datum]) & 0x3FF;
1348                 }
1349             }
1350           else if (endian_type == LSBEndian)
1351             {
1352               for (i=0; i < samples_per_row; i++)
1353                 {
1354                   datum = i % 3;
1355                   if (datum == 0)
1356                     LSBOctetsToPackedU32Word(scanline,packed_u32);
1357                   *sp++=(packed_u32 >> shifts[datum]) & 0x3FF;
1358                 }
1359             }
1360           return;
1361         }
1362       else if (bits_per_sample == 12)
1363         {
1364           if (word_pad_lsb)
1365             {
1366               /*
1367                 Padding in LSB (Method A)  Standard method.
1368               */
1369               if (endian_type == MSBEndian)
1370                 {
1371                   for (i=samples_per_row; i != 0; i--)
1372                     {
1373                       sample=0;
1374                       sample |= (((sample_t) *scanline++) << 8);
1375                       sample |= ((sample_t) *scanline++);
1376                       sample >>= 4;
1377                       *sp++=sample;
1378                     }
1379                 }
1380               else if (endian_type == LSBEndian)
1381                 {
1382                   for (i=samples_per_row; i != 0; i--)
1383                     {
1384                       sample=0;
1385                       sample |= ((sample_t) *scanline++);
1386                       sample |= (((sample_t) *scanline++) << 8);
1387                       sample >>= 4;
1388                       *sp++=sample;
1389                     }
1390                 }
1391               return;
1392             }
1393           else if (word_pad_msb)
1394             {
1395               /*
1396                 Padding in MSB (Method B)  Deprecated method.
1397               */
1398               if (endian_type == MSBEndian)
1399                 {
1400                   for (i=samples_per_row; i != 0; i--)
1401                     {
1402                       sample=0;
1403                       sample |= (((sample_t) *scanline++) << 8);
1404                       sample |= ((sample_t) *scanline++);
1405                       sample &= 0xFFF;
1406                       *sp++=sample;
1407                     }
1408                 }
1409               else if (endian_type == LSBEndian)
1410                 {
1411                   for (i=samples_per_row; i != 0; i--)
1412                     {
1413                       sample=0;
1414                       sample |= ((sample_t) *scanline++);
1415                       sample |= (((sample_t) *scanline++) << 8);
1416                       sample &= 0xFFF;
1417                       *sp++=sample;
1418                     }
1419                 }
1420               return;
1421             }
1422         }
1423     }
1424 
1425   /*
1426     Special fast handling for 8-bit images.
1427   */
1428   if (bits_per_sample == 8)
1429     {
1430       for (i=samples_per_row; i != 0; i--)
1431         *sp++= (sample_t) *scanline++;
1432       return;
1433     }
1434 
1435   /*
1436     Special fast handling for 16-bit images.
1437   */
1438   if (bits_per_sample == 16)
1439     {
1440       if (endian_type == MSBEndian)
1441         {
1442           for (i=samples_per_row; i != 0; i--)
1443             {
1444               sample=0;
1445               sample |= (((sample_t) *scanline++) << 8);
1446               sample |= ((sample_t) *scanline++);
1447               *sp++=sample;
1448             }
1449         }
1450       else if (endian_type == LSBEndian)
1451         {
1452           for (i=samples_per_row; i != 0; i--)
1453             {
1454               sample=0;
1455               sample |= ((sample_t) *scanline++);
1456               sample |= (((sample_t) *scanline++) << 8);
1457               *sp++=sample;
1458             }
1459         }
1460       return;
1461     }
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   {
1496     ReadWordU32State
1497       read_state;
1498 
1499     WordStreamReadHandle
1500       read_stream;
1501 
1502     WordStreamReadFunc
1503       read_func=0;
1504 
1505     if (endian_type == LSBEndian)
1506       read_func=ReadWordU32LE;
1507     else
1508       read_func=ReadWordU32BE;
1509 
1510     read_state.words=scanline;
1511     MagickWordStreamInitializeRead(&read_stream,read_func, (void *) &read_state);
1512       for (i=samples_per_row; i != 0; i--)
1513         *sp++=MagickWordStreamLSBRead(&read_stream,bits_per_sample);
1514   }
1515 }
1516 
1517 /*
1518   Apply a simple "Tent" filter to upsample chroma channels.
1519 */
TentUpsampleChroma(PixelPacket * pixels,unsigned long columns)1520 STATIC void TentUpsampleChroma(PixelPacket *pixels, unsigned long columns)
1521 {
1522   unsigned long
1523     column;
1524 
1525   for (column = 1; column < columns-2; column += 2)
1526     {
1527 #if QuantumDepth < 32
1528       /*
1529         Use integer computations if intermediate result will fit.
1530       */
1531       pixels->green=((unsigned long) pixels[column-1].green + pixels[column+1].green)/2;
1532       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     }
1547 }
1548 
1549 #define ThrowDPXReaderException(code_,reason_,image_) \
1550 { \
1551   MagickFreeResourceLimitedMemory(map_Y); \
1552   MagickFreeResourceLimitedMemory(map_CbCr); \
1553   if (samples_set) \
1554     DestroyThreadViewDataSet(samples_set);    \
1555   if (scanline_set) \
1556     DestroyThreadViewDataSet(scanline_set);    \
1557   ThrowReaderException(code_,reason_,image_); \
1558 }
1559 
ReadDPXImage(const ImageInfo * image_info,ExceptionInfo * exception)1560 STATIC Image *ReadDPXImage(const ImageInfo *image_info,ExceptionInfo *exception)
1561 {
1562   char
1563     txt_buffer[MaxTextExtent];
1564 
1565   DPXFileInfo
1566     dpx_file_info;
1567 
1568   DPXImageInfo
1569     dpx_image_info;
1570 
1571   DPXImageSourceInfo
1572     dpx_source_info;
1573 
1574   DPXMPFilmInfo
1575     dpx_mp_info;
1576 
1577   DPXTVInfo
1578     dpx_tv_info;
1579 
1580   Image
1581     *image=0;
1582 
1583   long
1584     y;
1585 
1586   size_t
1587     offset,
1588     row_octets;
1589 
1590   Quantum
1591     *map_Y=0,                     /* value translation map (RGB or Y) */
1592     *map_CbCr=0;                  /* value translation map (CbCr) */
1593 
1594   ThreadViewDataSet
1595     *samples_set=0;
1596 
1597   ThreadViewDataSet
1598     *scanline_set=0;
1599 
1600   size_t
1601     element_size;               /* Number of bytes in an element */
1602 
1603   unsigned int
1604     bits_per_sample,            /* number of bits per sample */
1605     element,                    /* current element number */
1606     max_bits_per_sample,        /* maximum number of bits per sample for any element */
1607     max_samples_per_pixel,      /* maximum number of samples comprising one pixel for any element */
1608     samples_per_pixel,          /* number of samples comprising one pixel for this element */
1609     samples_per_row;            /* number of samples in one row */
1610 
1611   MagickPassFail
1612     status;
1613 
1614   unsigned long
1615     i,
1616     pixels_offset;
1617 
1618   MagickBool
1619     is_grayscale=MagickFalse,   /* image is grayscale ? */
1620     is_monochrome=MagickFalse,  /* image is monochrome ? */
1621     matte_init=MagickFalse,     /* Set to True if opacity channel needs init */
1622     swap_endian=MagickFalse;    /* swap endian order */
1623 
1624   DPXImageElementDescriptor
1625     element_descriptor;
1626 
1627   DPXTransferCharacteristic
1628     transfer_characteristic;
1629 
1630   ImageComponentPackingMethod
1631     packing_method;
1632 
1633   EndianType
1634     endian_type;
1635 
1636   const char
1637     *definition_value;
1638 
1639   /*
1640     Open image file.
1641   */
1642   assert(sizeof(DPXHeader) == 2048);
1643   assert(image_info != (const ImageInfo *) NULL);
1644   assert(image_info->signature == MagickSignature);
1645   assert(exception != (ExceptionInfo *) NULL);
1646   assert(exception->signature == MagickSignature);
1647   image=AllocateImage(image_info);
1648   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1649   if (status == False)
1650     ThrowDPXReaderException(FileOpenError,UnableToOpenFile,image);
1651   /*
1652     Read DPX image.
1653   */
1654   offset=ReadBlob(image,sizeof(dpx_file_info),&dpx_file_info);
1655   if (offset != sizeof(dpx_file_info) ||
1656       ((LocaleNCompare((char *) &dpx_file_info.magic,"SDPX",4) != 0) &&
1657        (LocaleNCompare((char *) &dpx_file_info.magic,"XPDS",4) != 0)))
1658     ThrowDPXReaderException(CorruptImageError,ImproperImageHeader,image);
1659   /*
1660     Check for swapped endian order.
1661   */
1662   if (dpx_file_info.magic != 0x53445058U)
1663     swap_endian=MagickTrue;
1664 
1665 #if defined(WORDS_BIGENDIAN)
1666   endian_type = (swap_endian ? LSBEndian : MSBEndian);
1667 #else
1668   endian_type = (swap_endian ? MSBEndian : LSBEndian);
1669 #endif
1670 
1671   /*
1672     Save original endian to image so that image write will preserve
1673     original endianness.
1674   */
1675   image->endian = endian_type;
1676 
1677   if (image->logging)
1678     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1679                           "%s endian DPX format",
1680                           (endian_type == MSBEndian ? "Big" : "Little"));
1681 
1682   if (swap_endian)
1683     SwabDPXFileInfo(&dpx_file_info);
1684 
1685   if (image->logging)
1686     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1687                           "File size: %u", dpx_file_info.file_size);
1688 
1689   StringToAttribute(image,"software",dpx_file_info.creator);
1690   StringToAttribute(image,"comment",dpx_file_info.project_name);
1691   StringToAttribute(image,"copyright",dpx_file_info.copyright);
1692   StringToAttribute(image,"document",dpx_file_info.image_filename);
1693   /* StringToAttribute(image,"timestamp",dpx_file_info.creation_datetime); */
1694 
1695   StringToAttribute(image,"DPX:file.version",dpx_file_info.header_format_version);
1696   StringToAttribute(image,"DPX:file.filename",dpx_file_info.image_filename);
1697   StringToAttribute(image,"DPX:file.creation.datetime",dpx_file_info.creation_datetime);
1698   StringToAttribute(image,"DPX:file.creator",dpx_file_info.creator);
1699   StringToAttribute(image,"DPX:file.project.name",dpx_file_info.project_name);
1700   StringToAttribute(image,"DPX:file.copyright",dpx_file_info.copyright);
1701   U32ToAttribute(image,"DPX:file.encryption.key",dpx_file_info.encryption_key);
1702 
1703   /*
1704     Obtain offset to pixels.
1705   */
1706   pixels_offset=dpx_file_info.image_data_offset & 0xffffffff;
1707   if (image->logging)
1708     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1709                           "Image data offset %lu",pixels_offset);
1710   if (pixels_offset < 1408)
1711     ThrowDPXReaderException(CorruptImageError,ImproperImageHeader,image);
1712   if (image->logging)
1713     {
1714       char
1715         generic_length_str[MaxTextExtent],
1716         industry_length_str[MaxTextExtent],
1717         user_length_str[MaxTextExtent];
1718 
1719       if (IS_UNDEFINED_U32(dpx_file_info.generic_section_length))
1720         (void) strlcpy(generic_length_str,"UNDEFINED",sizeof(generic_length_str));
1721       else
1722         FormatString(generic_length_str,"%u",dpx_file_info.generic_section_length);
1723 
1724       if (IS_UNDEFINED_U32(dpx_file_info.industry_section_length))
1725         (void) strlcpy(industry_length_str,"UNDEFINED",sizeof(industry_length_str));
1726       else
1727         FormatString(industry_length_str,"%u",dpx_file_info.industry_section_length);
1728 
1729       if (IS_UNDEFINED_U32(dpx_file_info.user_defined_length))
1730         (void) strlcpy(user_length_str,"UNDEFINED",sizeof(user_length_str));
1731       else
1732         FormatString(user_length_str,"%u",dpx_file_info.user_defined_length);
1733 
1734       if (image->logging)
1735         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1736                               "Generic length %s, Industry length %s, User length %s",
1737                               generic_length_str,industry_length_str,user_length_str);
1738     }
1739   /*
1740     Read image information header.
1741   */
1742   offset += ReadBlob(image,sizeof(dpx_image_info),&dpx_image_info);
1743   if (offset != (size_t) 1408L)
1744     ThrowDPXReaderException(CorruptImageError,UnexpectedEndOfFile,image);
1745   if (swap_endian)
1746     SwabDPXImageInfo(&dpx_image_info);
1747   if (image->logging)
1748     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1749                           "Pixels per line %u, Lines per image %u, Elements %u",
1750                           (unsigned int) dpx_image_info.pixels_per_line,
1751                           (unsigned int) dpx_image_info.lines_per_image_element,
1752                           (unsigned int) dpx_image_info.elements);
1753   if (dpx_image_info.orientation > 7U)
1754     ThrowDPXReaderException(CorruptImageError,ImproperImageHeader,image);
1755   if (dpx_image_info.elements >
1756       sizeof(dpx_image_info.element_info)/sizeof(dpx_image_info.element_info[0]))
1757     ThrowDPXReaderException(CorruptImageError,ImproperImageHeader,image);
1758   if (dpx_image_info.elements == 0)
1759     ThrowDPXReaderException(CorruptImageError,ImproperImageHeader,image);
1760   image->columns=dpx_image_info.pixels_per_line & 0xFFFFFFFF;
1761   image->rows=dpx_image_info.lines_per_image_element & 0xFFFFFFFF;
1762   if (image->logging)
1763     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1764                           "Geometry: %lux%lu", image->columns, image->rows);
1765   U16ToAttribute(image,"DPX:image.orientation",dpx_image_info.orientation);
1766   image->orientation=DPXOrientationToOrientationType(dpx_image_info.orientation);
1767 
1768   if (pixels_offset >= 1664UL)
1769     {
1770       /*
1771         Read Image source information header.
1772       */
1773       offset += ReadBlob(image,sizeof(dpx_source_info),&dpx_source_info);
1774       if (offset != (size_t) 1664L)
1775         ThrowDPXReaderException(CorruptImageError,UnexpectedEndOfFile,image);
1776       if (swap_endian)
1777         SwabDPXImageSourceInfo(&dpx_source_info);
1778 
1779       U32ToAttribute(image,"DPX:source.x-offset",dpx_source_info.x_offset);
1780       U32ToAttribute(image,"DPX:source.y-offset",dpx_source_info.y_offset);
1781       R32ToAttribute(image,"DPX:source.x-center",dpx_source_info.x_center);
1782       R32ToAttribute(image,"DPX:source.y-center",dpx_source_info.y_center);
1783       U32ToAttribute(image,"DPX:source.x-original-size",dpx_source_info.x_original_size);
1784       U32ToAttribute(image,"DPX:source.y-original-size",dpx_source_info.y_original_size);
1785       StringToAttribute(image,"DPX:source.filename",dpx_source_info.source_image_filename);
1786       StringToAttribute(image,"DPX:source.creation.datetime",dpx_source_info.source_image_datetime);
1787       StringToAttribute(image,"DPX:source.device.name",dpx_source_info.input_device_name);
1788       StringToAttribute(image,"DPX:source.device.serialnumber",dpx_source_info.input_device_serialnumber);
1789       U16ToAttribute(image,"DPX:source.border.validity.left",dpx_source_info.border_validity.XL);
1790       U16ToAttribute(image,"DPX:source.border.validity.right",dpx_source_info.border_validity.XR);
1791       U16ToAttribute(image,"DPX:source.border.validity.top",dpx_source_info.border_validity.YT);
1792       U16ToAttribute(image,"DPX:source.border.validity.bottom",dpx_source_info.border_validity.YB);
1793       U32ToAttribute(image,"DPX:source.aspect.ratio.horizontal",dpx_source_info.aspect_ratio.horizontal);
1794       U32ToAttribute(image,"DPX:source.aspect.ratio.vertical",dpx_source_info.aspect_ratio.vertical);
1795       R32ToAttribute(image,"DPX:source.scanned.size.x",dpx_source_info.x_scanned_size);
1796       R32ToAttribute(image,"DPX:source.scanned.size.y",dpx_source_info.y_scanned_size);
1797     }
1798   if (pixels_offset >= 1920UL)
1799     {
1800       /*
1801         Read Motion-picture film information header.
1802       */
1803       offset += ReadBlob(image,sizeof(dpx_mp_info),&dpx_mp_info);
1804       if (offset != (size_t) 1920L)
1805         ThrowDPXReaderException(CorruptImageError,UnexpectedEndOfFile,image);
1806       if (swap_endian)
1807         SwabDPXMPFilmInfo(&dpx_mp_info);
1808 
1809       if (dpx_file_info.industry_section_length != 0)
1810         {
1811           StringToAttribute(image,"DPX:mp.film.manufacturer.id",dpx_mp_info.film_mfg_id_code);
1812           StringToAttribute(image,"DPX:mp.film.type",dpx_mp_info.film_type);
1813           StringToAttribute(image,"DPX:mp.perfs.offset",dpx_mp_info.perfs_offset);
1814           StringToAttribute(image,"DPX:mp.prefix",dpx_mp_info.prefix);
1815           StringToAttribute(image,"DPX:mp.count",dpx_mp_info.count);
1816           StringToAttribute(image,"DPX:mp.format",dpx_mp_info.format);
1817           U32ToAttribute(image,"DPX:mp.frame.position",dpx_mp_info.frame_position);
1818           U32ToAttribute(image,"DPX:mp.sequence.length",dpx_mp_info.sequence_length);
1819           U32ToAttribute(image,"DPX:mp.held.count",dpx_mp_info.held_count);
1820           R32ToAttribute(image,"DPX:mp.frame.rate",dpx_mp_info.frame_rate);
1821           R32ToAttribute(image,"DPX:mp.shutter.angle",dpx_mp_info.shutter_angle);
1822           StringToAttribute(image,"DPX:mp.frame.id",dpx_mp_info.frame_id);
1823           StringToAttribute(image,"DPX:mp.slate.info",dpx_mp_info.slate_info);
1824         }
1825     }
1826   if (pixels_offset >= 2048UL)
1827     {
1828       /*
1829         Read Television information header.
1830       */
1831       offset += ReadBlob(image,sizeof(dpx_tv_info),&dpx_tv_info);
1832       if (offset != (size_t) 2048L)
1833         ThrowDPXReaderException(CorruptImageError,UnexpectedEndOfFile,image);
1834       if (swap_endian)
1835         SwabDPXTVInfo(&dpx_tv_info);
1836 
1837       if (dpx_file_info.industry_section_length != 0)
1838         {
1839           U32ToBitsAttribute(image,"DPX:tv.time.code",dpx_tv_info.time_code);
1840           U32ToBitsAttribute(image,"DPX:tv.user.bits",dpx_tv_info.user_bits);
1841           U8ToAttribute(image,"DPX:tv.interlace",dpx_tv_info.interlace);
1842           U8ToAttribute(image,"DPX:tv.field.number",dpx_tv_info.field_number);
1843           U8ToAttribute(image,"DPX:tv.video.signal",dpx_tv_info.video_signal);
1844           R32ToAttribute(image,"DPX:tv.horizontal.sampling.rate",dpx_tv_info.horizontal_sample);
1845           R32ToAttribute(image,"DPX:tv.temporal.sampling.rate",dpx_tv_info.temporal_sample);
1846           R32ToAttribute(image,"DPX:tv.sync.time",dpx_tv_info.sync_time);
1847           R32ToAttribute(image,"DPX:tv.gamma",dpx_tv_info.gamma);
1848           R32ToAttribute(image,"DPX:tv.black.level",dpx_tv_info.black_level);
1849           R32ToAttribute(image,"DPX:tv.black.gain",dpx_tv_info.black_gain);
1850           R32ToAttribute(image,"DPX:tv.breakpoint",dpx_tv_info.breakpoint);
1851           R32ToAttribute(image,"DPX:tv.white.level",dpx_tv_info.white_level);
1852           R32ToAttribute(image,"DPX:tv.integration.time",dpx_tv_info.integration_time);
1853         }
1854     }
1855   if (pixels_offset >= 2080UL)
1856     {
1857       if (!IS_UNDEFINED_U32(dpx_file_info.user_defined_length) &&
1858           (dpx_file_info.user_defined_length >= sizeof(DPXUserDefinedData)))
1859         {
1860           /*
1861             Read user header.
1862           */
1863           unsigned char
1864             *user_data;
1865 
1866           const size_t
1867             block_size = 65536UL;
1868 
1869           size_t
1870             read_size,
1871             user_data_length;
1872 
1873           DPXUserDefinedData
1874             *dpx_user_data;
1875 
1876           user_data_length=0UL;
1877           user_data=(unsigned char *) NULL;
1878 
1879           while (user_data_length < dpx_file_info.user_defined_length)
1880             {
1881               unsigned char
1882                 *new_user_data;
1883 
1884               read_size=Min(block_size,dpx_file_info.user_defined_length-user_data_length);
1885               new_user_data=MagickReallocateResourceLimitedMemory(unsigned char *,user_data,user_data_length+read_size);
1886               if (new_user_data == (unsigned char *) NULL)
1887                 {
1888                   MagickFreeResourceLimitedMemory(user_data);
1889                   ThrowDPXReaderException(ResourceLimitError,MemoryAllocationFailed,image);
1890                 }
1891               user_data=new_user_data;
1892               if (ReadBlob(image,read_size,user_data+user_data_length) != read_size)
1893                 {
1894                   MagickFreeResourceLimitedMemory(user_data);
1895                   ThrowDPXReaderException(CorruptImageError,UnexpectedEndOfFile,image);
1896                 }
1897               user_data_length += read_size;
1898               offset += read_size;
1899             }
1900 
1901           dpx_user_data=(DPXUserDefinedData *) user_data;
1902           StringToAttribute(image,"DPX:user.data.id",dpx_user_data->user_id);
1903           if (!SetImageProfile(image,"DPXUSERDATA",user_data,user_data_length))
1904             {
1905               MagickFreeResourceLimitedMemory(user_data);
1906               ThrowDPXReaderException(ResourceLimitError,MemoryAllocationFailed,image);
1907             }
1908           MagickFreeResourceLimitedMemory(user_data);
1909         }
1910     }
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   max_bits_per_sample=0;
1919   max_samples_per_pixel=0;
1920   {
1921     MagickBool
1922       has_cbcr=MagickFalse,
1923       has_luma=MagickFalse,
1924       has_matte=MagickFalse,
1925       has_rgb=MagickFalse;
1926 
1927     DPXColorimetric
1928       colorimetric=ColorimetricUserDefined;
1929 
1930     transfer_characteristic=TransferCharacteristicUserDefined;
1931     if (image->logging)
1932       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1933                             "Number of elements: %u",
1934                             dpx_image_info.elements);
1935 
1936     for (element=0; element < dpx_image_info.elements; element++)
1937       {
1938         if (image->logging)
1939           DescribeDPXImageElement(&dpx_image_info.element_info[element],element+1);
1940         if (element == 0)
1941           {
1942             colorimetric=
1943               (DPXColorimetric) dpx_image_info.element_info[element].colorimetric;
1944             DPXSetPrimaryChromaticities(colorimetric,&image->chromaticity);
1945           }
1946         element_descriptor=(DPXImageElementDescriptor)
1947           dpx_image_info.element_info[element].descriptor;
1948         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         if ((bits_per_sample != 1) &&
1955             (bits_per_sample != 8) &&
1956             (bits_per_sample != 10) &&
1957             (bits_per_sample != 12) &&
1958             (bits_per_sample != 16))
1959           {
1960             if (image->logging)
1961               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1962                                     "Unsupported bits per sample %u"
1963                                     " (truncating elements)", bits_per_sample);
1964             dpx_image_info.elements=element;
1965             break;
1966           }
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         if ((element_descriptor == ImageElementAlpha) &&
1974             (bits_per_sample == 1) &&
1975             (LocaleNCompare(dpx_image_info.element_info[element].description,
1976                             "NL CLEAN MATTE",sizeof("NL CLEAN MATTE")-1) == 0))
1977           {
1978             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1979                                   "Skipping Northlight \"%s\" channel...",
1980                                   dpx_image_info.element_info[element].description);
1981             dpx_image_info.elements=element;
1982             break;
1983           }
1984         /*
1985           Validate packing method
1986         */
1987         packing_method=(ImageComponentPackingMethod) dpx_image_info.element_info[element].packing;
1988         if ((packing_method != PackingMethodPacked) &&
1989             (packing_method != PackingMethodWordsFillLSB) &&
1990             (packing_method != PackingMethodWordsFillMSB))
1991           {
1992             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1993                                   "Unsupported packing method %u"
1994                                   " (truncating elements)", packing_method);
1995             dpx_image_info.elements=element;
1996             break;
1997           }
1998         /*
1999           Data sign, (0 = unsigned; 1 = signed)
2000         */
2001         if (dpx_image_info.element_info[element].data_sign != 0)
2002           {
2003             if (image->logging)
2004               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2005                                     "Signed pixel data (in element %u) is not supported"
2006                                     " (truncating elements)",
2007                                     element);
2008             dpx_image_info.elements=element;
2009             break;
2010           }
2011         /*
2012           Special image width rules for some element descriptors
2013         */
2014         switch (element_descriptor)
2015           {
2016           case ImageElementColorDifferenceCbCr: /* 4:2:2 */
2017           case ImageElementCbYCrY422:
2018           case ImageElementCbYACrYA4224:
2019             if (image->columns % 2)
2020               {
2021                 if (image->logging)
2022                   {
2023                     char txt_buffer[MaxTextExtent];
2024                     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2025                                           "Image width must be evenly divisible"
2026                                           " by 2 for \"%s\" element",
2027                                           DescribeImageElementDescriptor(txt_buffer,
2028                                                                          element_descriptor));
2029                   }
2030                 dpx_image_info.elements=element;
2031               }
2032             break;
2033           default:
2034             {
2035             }
2036           }
2037         if (dpx_image_info.elements == element)
2038           break;
2039         /*
2040           Validate and set image colorspace
2041         */
2042         switch (element_descriptor)
2043           {
2044           case ImageElementColorDifferenceCbCr:
2045           case ImageElementCbYCrY422:
2046           case ImageElementCbYACrYA4224:
2047           case ImageElementCbYCr444:
2048           case ImageElementCbYCrA4444:
2049             {
2050               has_cbcr=MagickTrue;
2051               colorimetric=(DPXColorimetric) dpx_image_info.element_info[element].colorimetric;
2052               transfer_characteristic=(DPXTransferCharacteristic)
2053                 dpx_image_info.element_info[element].transfer_characteristic;
2054               break;
2055             }
2056           case ImageElementRed:
2057           case ImageElementGreen:
2058           case ImageElementBlue:
2059           case ImageElementRGB:
2060           case ImageElementRGBA:
2061           case ImageElementABGR:
2062             {
2063               has_rgb=MagickTrue;
2064               colorimetric=(DPXColorimetric) dpx_image_info.element_info[element].colorimetric;
2065               transfer_characteristic=(DPXTransferCharacteristic)
2066                 dpx_image_info.element_info[element].transfer_characteristic;
2067               break;
2068             }
2069           case ImageElementLuma:
2070             {
2071               has_luma=MagickTrue;
2072               colorimetric=(DPXColorimetric) dpx_image_info.element_info[element].colorimetric;
2073               transfer_characteristic=(DPXTransferCharacteristic)
2074                 dpx_image_info.element_info[element].transfer_characteristic;
2075               break;
2076             }
2077           case ImageElementAlpha:
2078             {
2079               break;
2080             }
2081           default:
2082             {
2083               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2084                                     "Unhandled element descriptor (%u): %s"
2085                                     " (truncating elements)",
2086                                     element_descriptor,
2087                                     DescribeImageElementDescriptor(txt_buffer,element_descriptor));
2088               dpx_image_info.elements=element;
2089               break;
2090             }
2091           }
2092         /*
2093           Check for a matte channel.
2094         */
2095         switch (element_descriptor)
2096           {
2097           case ImageElementAlpha:
2098           case ImageElementRGBA:
2099           case ImageElementABGR:
2100           case ImageElementCbYACrYA4224:
2101           case ImageElementCbYCrA4444:
2102             has_matte=MagickTrue;
2103             break;
2104           default:
2105             break;
2106           }
2107         max_bits_per_sample=Max(max_bits_per_sample,bits_per_sample);
2108         max_samples_per_pixel=Max(max_samples_per_pixel,
2109                                   DPXSamplesPerPixel(element_descriptor));
2110 
2111 
2112       } /* for (element=0; element < dpx_image_info.elements; element++) */
2113 
2114     /*
2115       Check if there were any supported elements
2116     */
2117     if (dpx_image_info.elements == 0)
2118       {
2119         if (image->logging)
2120           (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2121                                 "No supported image elements were found!");
2122         ThrowDPXReaderException(CorruptImageError,ImproperImageHeader,image);
2123       }
2124 
2125     if (image->logging)
2126       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2127                             "Maximum number of bits per sample in any element: %u",
2128                             max_bits_per_sample);
2129     if (has_cbcr)
2130       {
2131         image->colorspace=Rec709YCbCrColorspace;
2132         if ((transfer_characteristic == TransferCharacteristicITU_R601_625L) ||
2133             (transfer_characteristic == TransferCharacteristicITU_R601_525L))
2134           image->colorspace=Rec601YCbCrColorspace;
2135       }
2136     else if (has_luma)
2137       {
2138         image->colorspace=GRAYColorspace;
2139         if (transfer_characteristic == TransferCharacteristicITU_R709)
2140           image->colorspace=Rec709LumaColorspace;
2141         else if ((transfer_characteristic == TransferCharacteristicITU_R601_625L) ||
2142                  (transfer_characteristic == TransferCharacteristicITU_R601_525L))
2143           image->colorspace=Rec601LumaColorspace;
2144       }
2145     else if (has_rgb)
2146       {
2147         image->colorspace=RGBColorspace;
2148         if (transfer_characteristic == TransferCharacteristicPrintingDensity)
2149           image->colorspace=CineonLogRGBColorspace;
2150       }
2151 
2152     image->matte=has_matte;
2153   }
2154   if (image->logging)
2155     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2156                           "Image colorspace: %s",
2157                           ColorspaceTypeToString(image->colorspace));
2158   /*
2159     Set image depth to maximum bits per sample encountered in any element.
2160   */
2161   image->depth=max_bits_per_sample;
2162   /*
2163     Skip reading pixels if ping requested.
2164   */
2165   if (image_info->ping)
2166     {
2167       StopTimer(&image->timer);
2168       CloseBlob(image);
2169       return(image);
2170     }
2171 
2172   if (CheckImagePixelLimits(image, exception) != MagickPass)
2173     ThrowDPXReaderException(ResourceLimitError,ImagePixelLimitExceeded,image);
2174 
2175   /*
2176     Validate that the elements provide all of the channels
2177   */
2178   {
2179     /* Flags to use when updating channel_bits */
2180 #define RED_CHANNEL     (1U)
2181 #define GREEN_CHANNEL   (1U << 1U)
2182 #define BLUE_CHANNEL    (1U << 2U)
2183 #define OPACITY_CHANNEL (1U << 3U)
2184 
2185     unsigned int
2186       channel_bits; /* record of channels which were updated by elements */
2187 
2188     channel_bits=0;
2189     for (element=0; element < dpx_image_info.elements; element++)
2190       {
2191         element_descriptor=(DPXImageElementDescriptor)
2192           dpx_image_info.element_info[element].descriptor;
2193 
2194         /*
2195           Tally channels which would be updated by this element.
2196         */
2197         switch (element_descriptor)
2198           {
2199           case ImageElementRed:
2200             channel_bits |= RED_CHANNEL;
2201             break;
2202           case ImageElementGreen:
2203             channel_bits |= GREEN_CHANNEL;
2204             break;
2205           case ImageElementBlue:
2206             channel_bits |= BLUE_CHANNEL;
2207             break;
2208           case ImageElementAlpha:
2209             channel_bits |= OPACITY_CHANNEL;
2210             break;
2211           case ImageElementUnspecified:
2212           case ImageElementLuma:
2213             if (IsYCbCrColorspace(image->colorspace))
2214               {
2215                 channel_bits |= RED_CHANNEL;
2216               }
2217             else
2218               {
2219                 channel_bits |= RED_CHANNEL | GREEN_CHANNEL | BLUE_CHANNEL;
2220                 if (!image->matte)
2221                   channel_bits |= OPACITY_CHANNEL;
2222               }
2223             break;
2224           case ImageElementColorDifferenceCbCr:
2225             channel_bits |= GREEN_CHANNEL | BLUE_CHANNEL;
2226             break;
2227           case ImageElementRGB:
2228             channel_bits |= RED_CHANNEL | GREEN_CHANNEL | BLUE_CHANNEL;
2229             if (!image->matte)
2230               channel_bits |= OPACITY_CHANNEL;
2231             break;
2232           case ImageElementRGBA:
2233             channel_bits |= RED_CHANNEL | GREEN_CHANNEL | BLUE_CHANNEL | OPACITY_CHANNEL;
2234             break;
2235           case ImageElementABGR:
2236             channel_bits |= RED_CHANNEL | GREEN_CHANNEL | BLUE_CHANNEL | OPACITY_CHANNEL;
2237             break;
2238           case ImageElementCbYCrY422:
2239             channel_bits |= RED_CHANNEL | GREEN_CHANNEL | BLUE_CHANNEL;
2240             if (!image->matte)
2241               channel_bits |= OPACITY_CHANNEL;
2242             break;
2243           case ImageElementCbYACrYA4224:
2244             channel_bits |= RED_CHANNEL | GREEN_CHANNEL | BLUE_CHANNEL | OPACITY_CHANNEL;
2245             break;
2246           case ImageElementCbYCr444:
2247             channel_bits |= RED_CHANNEL | GREEN_CHANNEL | BLUE_CHANNEL;
2248             if (!image->matte)
2249               channel_bits |= OPACITY_CHANNEL;
2250             break;
2251           case ImageElementCbYCrA4444:
2252             channel_bits |= RED_CHANNEL | GREEN_CHANNEL | BLUE_CHANNEL | OPACITY_CHANNEL;
2253             break;
2254           default:
2255             break;
2256           }
2257       }
2258 
2259     if (image->logging)
2260       (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2261                             "Channels updated: %s%s%s%s",
2262                             channel_bits & RED_CHANNEL ? "R" : "",
2263                             channel_bits & GREEN_CHANNEL ? "G" : "",
2264                             channel_bits & BLUE_CHANNEL ? "B" : "",
2265                             channel_bits & OPACITY_CHANNEL ? "O" : "");
2266 
2267     if (!(channel_bits & OPACITY_CHANNEL))
2268       matte_init = MagickTrue;
2269 
2270     if ((channel_bits & (RED_CHANNEL | GREEN_CHANNEL | BLUE_CHANNEL))
2271         != (RED_CHANNEL | GREEN_CHANNEL | BLUE_CHANNEL))
2272       ThrowDPXReaderException(CorruptImageError,MissingImageChannel,image);
2273   }
2274 
2275   /*
2276     Validate file size if using a seekable blob
2277   */
2278   if (BlobIsSeekable(image))
2279     {
2280       magick_off_t file_size;
2281       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       file_size = GetBlobSize(image);
2287       if (!IS_UNDEFINED_U32(dpx_file_info.file_size) &&
2288           (file_size < dpx_file_info.file_size))
2289         {
2290           ThrowDPXReaderException(CorruptImageError,UnexpectedEndOfFile,image);
2291         }
2292       if (!IS_UNDEFINED_U32(dpx_file_info.image_data_offset) &&
2293           (file_size < dpx_file_info.image_data_offset))
2294         {
2295           ThrowDPXReaderException(CorruptImageError,ImproperImageHeader,image);
2296         }
2297       if (!IS_UNDEFINED_U32(dpx_file_info.generic_section_length) &&
2298           (file_size < dpx_file_info.generic_section_length))
2299         {
2300           ThrowDPXReaderException(CorruptImageError,ImproperImageHeader,image);
2301         }
2302       if (!IS_UNDEFINED_U32(dpx_file_info.industry_section_length) &&
2303           (file_size < dpx_file_info.industry_section_length))
2304         {
2305           ThrowDPXReaderException(CorruptImageError,ImproperImageHeader,image);
2306         }
2307       if (pixels_offset >= 2080UL)
2308         {
2309           if (!IS_UNDEFINED_U32(dpx_file_info.user_defined_length) &&
2310               (file_size < dpx_file_info.user_defined_length))
2311             {
2312               ThrowDPXReaderException(CorruptImageError,ImproperImageHeader,image);
2313             }
2314         }
2315 
2316       /*
2317         Estimate the required file size and assure that actual file
2318         size is at least that size.
2319       */
2320       for (element=0; element < dpx_image_info.elements; element++)
2321         {
2322           bits_per_sample=dpx_image_info.element_info[element].bits_per_sample;
2323           element_descriptor=(DPXImageElementDescriptor)
2324             dpx_image_info.element_info[element].descriptor;
2325           transfer_characteristic=
2326             (DPXTransferCharacteristic) dpx_image_info.element_info[element].transfer_characteristic;
2327           packing_method=(ImageComponentPackingMethod) dpx_image_info.element_info[element].packing;
2328           if (!IS_UNDEFINED_U32(dpx_image_info.element_info[element].data_offset) &&
2329               !IS_UNDEFINED_U32(dpx_file_info.file_size) &&
2330               (dpx_file_info.file_size != 0) &&
2331               ((dpx_image_info.element_info[element].data_offset & 0xFFFFFFFF) >=
2332                dpx_file_info.file_size))
2333             {
2334               if (image->logging)
2335                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2336                                       "Element offset (%u) is outside the bounds of"
2337                                       " file size (%u) indicated by header",
2338                                       dpx_image_info.element_info[element].data_offset,
2339                                       dpx_file_info.file_size);
2340               ThrowDPXReaderException(CorruptImageError,ImproperImageHeader,image);
2341             }
2342           if (!IS_UNDEFINED_U32(dpx_image_info.element_info[element].data_offset) &&
2343               ((dpx_image_info.element_info[element].data_offset & 0xFFFFFFFF) >=
2344                file_size))
2345             {
2346               if (image->logging)
2347                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2348                                       "Element offset (%u) is outside the bounds of"
2349                                       " actual file size (%" MAGICK_OFF_F "d)",
2350                                       dpx_image_info.element_info[element].data_offset,
2351                                       file_size);
2352               ThrowDPXReaderException(CorruptImageError,ImproperImageHeader,image);
2353             }
2354           samples_per_pixel=DPXSamplesPerPixel(element_descriptor);
2355           samples_per_row=samples_per_pixel*image->columns;
2356           element_size=DPXRowOctets(image->rows,samples_per_row,
2357                                     bits_per_sample,packing_method);
2358           file_size_estimate += element_size;
2359         }
2360       if (image->logging)
2361         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2362                               "File size estimate %" MAGICK_OFF_F
2363                               "u bytes (have %" MAGICK_OFF_F "u bytes)",
2364                               file_size_estimate, file_size);
2365       if ((file_size_estimate <= 0) || (file_size < file_size_estimate))
2366         ThrowDPXReaderException(CorruptImageError,InsufficientImageDataInFile,image);
2367     }
2368 
2369   /*
2370     Read remainder of header.
2371   */
2372   for ( ; offset < pixels_offset ; offset++ )
2373     if (ReadBlobByte(image) == EOF)
2374       ThrowDPXReaderException(CorruptImageError,UnexpectedEndOfFile,image);
2375 
2376   /*
2377     Allocate sample translation map storage.
2378   */
2379   (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2380                         "Maximum number of bits per sample in any element: %u",
2381                         max_bits_per_sample);
2382   map_Y=MagickAllocateResourceLimitedArray(Quantum *,
2383                             MaxValueGivenBits(max_bits_per_sample)+1,
2384                             sizeof(Quantum));
2385   if (map_Y == (Quantum *) NULL)
2386     ThrowDPXReaderException(ResourceLimitError,MemoryAllocationFailed,image);
2387 
2388   map_CbCr=MagickAllocateResourceLimitedArray(Quantum *,
2389                                MaxValueGivenBits(max_bits_per_sample)+1,
2390                                sizeof(Quantum));
2391   if (map_CbCr == (Quantum *) NULL)
2392     ThrowDPXReaderException(ResourceLimitError,MemoryAllocationFailed,image);
2393   /*
2394     Allocate per-thread-view row samples.
2395   */
2396   samples_set=AllocateThreadViewDataArray(image,exception,image->columns,
2397                                           MagickArraySize(max_samples_per_pixel,
2398                                                           sizeof(sample_t)));
2399   if (samples_set == (ThreadViewDataSet *) NULL)
2400     ThrowDPXReaderException(ResourceLimitError,MemoryAllocationFailed,image);
2401   /*
2402     Allocate per-thread-view scanline storage.
2403   */
2404   scanline_set=AllocateThreadViewDataArray(image,exception,image->columns,
2405                                            MagickArraySize(max_samples_per_pixel,
2406                                                            sizeof(U32)));
2407   if (scanline_set == (ThreadViewDataSet *) NULL)
2408     ThrowDPXReaderException(ResourceLimitError,MemoryAllocationFailed,image);
2409   /*
2410     Allow user to over-ride pixel endianness.
2411   */
2412   if ((definition_value=AccessDefinition(image_info,"dpx","pixel-endian")))
2413     {
2414       if (LocaleCompare(definition_value,"msb") == 0)
2415         endian_type=MSBEndian;
2416       else if (LocaleCompare(definition_value,"lsb") == 0)
2417         endian_type=LSBEndian;
2418     }
2419   /*
2420     Convert DPX raster image to pixel packets.
2421   */
2422   for (element=0; element < dpx_image_info.elements; element++)
2423     {
2424       unsigned long
2425         row_count=0;
2426 
2427       MagickBool
2428         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       if (!IS_UNDEFINED_U32(dpx_image_info.element_info[element].data_offset) &&
2436           (dpx_image_info.element_info[element].data_offset != 0U))
2437         {
2438           pixels_offset=dpx_image_info.element_info[element].data_offset & 0xFFFFFFFF;
2439           if (image->logging)
2440             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2441                                   "Seek from %" MAGICK_SIZE_T_F "u to %lu...",
2442                                   (MAGICK_SIZE_T) offset, pixels_offset);
2443           if (pixels_offset >= offset)
2444             {
2445               /* Data is at, or ahead of current position.  Good! */
2446               for ( ; offset < pixels_offset ; offset++ )
2447                 if (ReadBlobByte(image) == EOF)
2448                   break;
2449             }
2450           else
2451             {
2452               /* Data is behind current position.  Bad! */
2453               if (image->logging)
2454                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2455                                       "Seek backward to %lu...", pixels_offset);
2456               offset=SeekBlob(image,(magick_off_t) pixels_offset,SEEK_SET);
2457             }
2458 
2459           /* Verify that we reached our offset objective */
2460           if ( pixels_offset != offset)
2461             {
2462               if (image->logging)
2463                 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2464                                       "Failed to seek to data offset %lu"
2465                                       " (have %" MAGICK_SIZE_T_F "u)",
2466                                       pixels_offset, (MAGICK_SIZE_T) offset);
2467               ThrowDPXReaderException(BlobError,UnableToSeekToOffset,image);
2468             }
2469           if (EOFBlob(image))
2470             ThrowDPXReaderException(CorruptImageError,UnexpectedEndOfFile,image);
2471         }
2472       bits_per_sample=dpx_image_info.element_info[element].bits_per_sample;
2473       element_descriptor=(DPXImageElementDescriptor)
2474         dpx_image_info.element_info[element].descriptor;
2475       transfer_characteristic=
2476         (DPXTransferCharacteristic) dpx_image_info.element_info[element].transfer_characteristic;
2477       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       if ((definition_value=AccessDefinition(image_info,"dpx","packing-method")))
2482         {
2483           if (LocaleCompare(definition_value,"packed") == 0)
2484             {
2485               packing_method=PackingMethodPacked;
2486             }
2487           else if ((bits_per_sample == 10) || (bits_per_sample == 12))
2488             {
2489               if ((LocaleCompare(definition_value,"lsbpad") == 0) ||
2490                   (LocaleCompare(definition_value,"a") == 0))
2491                 packing_method=PackingMethodWordsFillLSB;
2492               else if ((LocaleCompare(definition_value,"msbpad") == 0) ||
2493                        (LocaleCompare(definition_value,"b") == 0))
2494                 packing_method=PackingMethodWordsFillMSB;
2495             }
2496         }
2497       /*
2498         Decide if the image is grayscale and monochrome.
2499       */
2500       if (IsGrayColorspace(image->colorspace))
2501         {
2502           is_grayscale=MagickTrue;
2503         }
2504       if ((is_grayscale) && (bits_per_sample == 1))
2505         {
2506           is_monochrome=MagickTrue;
2507         }
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       if ((element_descriptor == ImageElementRGB) ||
2518           (element_descriptor == ImageElementRGBA) ||
2519           (element_descriptor == ImageElementABGR) ||
2520           (element_descriptor == ImageElementCbYCrY422) ||
2521           (element_descriptor == ImageElementCbYACrYA4224) ||
2522           (element_descriptor == ImageElementCbYCr444) ||
2523           (element_descriptor == ImageElementCbYCrA4444))
2524         {
2525           if ((bits_per_sample == 10) && (packing_method != PackingMethodPacked))
2526             swap_word_datums = MagickTrue;
2527         }
2528       if ((definition_value=AccessDefinition(image_info,"dpx","swap-samples")) ||
2529           (definition_value=AccessDefinition(image_info,"dpx","swap-samples-read")))
2530         {
2531           if (LocaleCompare(definition_value,"false") != 0)
2532             swap_word_datums = swap_word_datums ? MagickFalse : MagickTrue;
2533         }
2534       /*
2535         Determine number of samples per pixel element.
2536       */
2537       samples_per_pixel=DPXSamplesPerPixel(element_descriptor);
2538       if (samples_per_pixel != 0)
2539         {
2540           double
2541             max_value,
2542             reference_low,
2543             reference_high,
2544             scale_to_quantum;           /* multiplier to scale to Quantum */
2545 
2546           max_value = (double) MaxValueGivenBits(bits_per_sample);
2547           reference_low = 0.0;
2548           reference_high = max_value;
2549           scale_to_quantum=MaxRGBDouble/max_value;
2550 
2551           /*
2552             Is this a video type space?
2553           */
2554           if (IsYCbCrColorspace(image->colorspace) ||
2555               (image->colorspace == Rec601LumaColorspace) ||
2556               (image->colorspace == Rec709LumaColorspace))
2557             {
2558               double
2559                 reference_low_prop,
2560                 reference_high_prop,
2561                 ScaleY = 0.0,
2562                 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               reference_low = ((max_value+1.0) * (64.0/1024.0));
2570               reference_high = ((max_value+1.0) * (940.0/1024.0));
2571 
2572               reference_low_prop = reference_low;
2573               reference_high_prop = reference_high;
2574 
2575               if (!IS_UNDEFINED_U32(dpx_image_info.element_info[element].reference_low_data_code))
2576                 reference_low_prop=dpx_image_info.element_info[element].reference_low_data_code;
2577               if ((definition_value=AccessDefinition(image_info,"dpx","reference-low")))
2578                 reference_low_prop=(double) strtol(definition_value, (char **)NULL, 10);
2579 
2580               if (!IS_UNDEFINED_U32(dpx_image_info.element_info[element].reference_high_data_code))
2581                 reference_high_prop=dpx_image_info.element_info[element].reference_high_data_code;
2582               if ((definition_value=AccessDefinition(image_info,"dpx","reference-high")))
2583                 reference_high_prop=(double) strtol(definition_value, (char **)NULL, 10);
2584 
2585               if ((reference_high_prop > reference_low_prop) &&
2586                   (reference_high_prop > MagickEpsilon))
2587                 {
2588                   reference_low = reference_low_prop;
2589                   reference_high = reference_high_prop;
2590                 }
2591 
2592               ScaleY = ((max_value+1.0)/(reference_high-reference_low));
2593               ScaleCbCr = ScaleY*((940.0-64.0)/(960.0-64.0));
2594               reference_low=reference_low*scale_to_quantum;
2595 
2596               for(i=0; i <= (unsigned long) max_value; i++)
2597                 {
2598                   map_Y[i] = ScaleFromVideo(i*scale_to_quantum,reference_low,ScaleY);
2599                   map_CbCr[i] = ScaleFromVideo(i*scale_to_quantum,reference_low,ScaleCbCr);
2600                 }
2601             }
2602           else
2603             {
2604               for(i=0; i <= (unsigned long) max_value; i++)
2605                 map_Y[i]=scale_to_quantum*i+0.5;
2606             }
2607 
2608           /*
2609             Compute samples per row.
2610           */
2611           samples_per_row=samples_per_pixel*image->columns;
2612           /*
2613             Compute octets per row.
2614           */
2615           row_octets=DPXRowOctets(1,samples_per_row,bits_per_sample,packing_method);
2616           if (image->logging)
2617             {
2618               /*
2619                 Compute element size.
2620               */
2621               element_size=DPXRowOctets(image->rows,samples_per_row,
2622                                         bits_per_sample,packing_method);
2623 
2624               (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2625                                     "Samples per row %u, octets per row %lu, element size %lu",
2626                                     samples_per_row, (unsigned long) row_octets,
2627                                     (unsigned long) element_size);
2628             }
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           for (y=0; y < (long) image->rows; y++)
2641             {
2642               MagickBool
2643                 thread_status;
2644 
2645               register long
2646                 x;
2647 
2648               register PixelPacket
2649                 *q;
2650 
2651               sample_t
2652                 *samples_itr;               /* current sample */
2653 
2654               PixelPacket
2655                 *pixels=(PixelPacket *) NULL;
2656 
2657               sample_t
2658                 *samples;                   /* parsed sample array */
2659 
2660               unsigned char
2661                 *scanline;
2662 
2663               unsigned long
2664                 thread_row_count;
2665 
2666 #if defined(HAVE_OPENMP) && !defined(DisableSlowOpenMP)
2667 #  pragma omp critical (GM_ReadDPXImage)
2668 #endif
2669               thread_status=status;
2670               if (thread_status == MagickFail)
2671                 continue;
2672 
2673               samples=AccessThreadViewData(samples_set);
2674               scanline=AccessThreadViewData(scanline_set);
2675 
2676               /*
2677                 Obtain a row's worth of samples.
2678               */
2679               {
2680                 void
2681                   *scanline_data;
2682 
2683                 scanline_data=scanline;
2684 #if defined(HAVE_OPENMP) && !defined(DisableSlowOpenMP)
2685 #  pragma omp critical (GM_ReadDPXImage)
2686 #endif
2687                 {
2688                   if (ReadBlobZC(image,row_octets,&scanline_data) != row_octets)
2689                     {
2690                       ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,
2691                                      image->filename);
2692                       thread_status=MagickFail;
2693                     }
2694 
2695                   thread_row_count=row_count;
2696                   row_count++;
2697                   if (QuantumTick(thread_row_count,image->rows))
2698                     if (!MagickMonitorFormatted(thread_row_count,image->rows,exception,
2699                                                 LoadImageText,image->filename,
2700                                                 image->columns,image->rows))
2701                       thread_status=MagickFail;
2702                 }
2703 
2704                 if (thread_status != MagickFail)
2705                   ReadRowSamples((const unsigned char*) scanline_data,samples_per_row,bits_per_sample,
2706                                  packing_method,endian_type,swap_word_datums,samples);
2707               }
2708 
2709               if (thread_status != MagickFail)
2710                 {
2711                   if (element == 0)
2712                     pixels=SetImagePixelsEx(image,0,thread_row_count,image->columns,1,exception);
2713                   else
2714                     pixels=GetImagePixelsEx(image,0,thread_row_count,image->columns,1,exception);
2715                 }
2716 
2717               if (pixels == (PixelPacket *) NULL)
2718                 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               if (thread_status != MagickFail)
2726                 {
2727                   if (element == 0)
2728                     {
2729                       if (matte_init)
2730                         {
2731                           q = pixels;
2732                           for (x=image->columns; x != 0; x--)
2733                             {
2734                               SetOpacitySample(q++,OpaqueOpacity);
2735                             }
2736                         }
2737                     }
2738                 }
2739 
2740               if (thread_status == MagickFail)
2741                 {
2742 #if defined(HAVE_OPENMP) && !defined(DisableSlowOpenMP)
2743 #  pragma omp critical (GM_ReadDPXImage)
2744 #endif
2745                   status=thread_status;
2746                   continue;
2747                 }
2748 
2749               /*
2750                 Assign samples to pixels.
2751               */
2752               q = pixels;
2753               samples_itr=samples;
2754               switch (element_descriptor)
2755                 {
2756                 case ImageElementRed:
2757                   for (x=image->columns; x != 0; x--)
2758                     {
2759                       SetRedSample(q++,map_Y[*samples_itr++]);
2760                     }
2761                   break;
2762                 case ImageElementGreen:
2763                   for (x=image->columns; x != 0; x--)
2764                     {
2765                       SetGreenSample(q++,map_Y[*samples_itr++]);
2766                     }
2767                   break;
2768                 case ImageElementBlue:
2769                   for (x=image->columns; x != 0; x--)
2770                     {
2771                       SetBlueSample(q++,map_Y[*samples_itr++]);
2772                     }
2773                   break;
2774                 case ImageElementAlpha:
2775                   for (x=image->columns; x != 0; x--)
2776                     {
2777                       SetOpacitySample(q++,map_Y[*samples_itr++]);
2778                     }
2779                   break;
2780                 case ImageElementUnspecified:
2781                 case ImageElementLuma:
2782                   if (IsYCbCrColorspace(image->colorspace))
2783                     {
2784                       /* Video Luma (planar) */
2785                       for (x=image->columns; x != 0; x--)
2786                         {
2787                           SetRedSample(q,map_Y[*samples_itr++]);
2788                           q++;
2789                         }
2790                     }
2791                   else
2792                     {
2793                       /* Video Luma or Linear Grayscale */
2794                       for (x=image->columns; x != 0; x--)
2795                         {
2796                           SetGraySample(q,map_Y[*samples_itr++]);
2797                           if (!image->matte)
2798                             SetOpacitySample(q,OpaqueOpacity);
2799                           q++;
2800                         }
2801                     }
2802                   break;
2803                 case ImageElementColorDifferenceCbCr:
2804                   {
2805                     /* CbCr 4:2:2 sampling */
2806                     for (x=image->columns; x > 0; x -= 2)
2807                       {
2808                         Quantum
2809                           Cb,
2810                           Cr;
2811 
2812                         Cb=map_CbCr[*samples_itr++]; /* Cb */
2813                         Cr=map_CbCr[*samples_itr++]; /* Cr */
2814 
2815                         SetCbSample(q,Cb);  /* Cb */
2816                         SetCrSample(q,Cr);  /* Cr */
2817                         q++;
2818 
2819                         SetCbSample(q,Cb);  /* Cb (false) */
2820                         SetCrSample(q,Cr);  /* Cr (false) */
2821                         q++;
2822                       }
2823                     TentUpsampleChroma(pixels,image->columns);
2824                     break;
2825                   }
2826                 case ImageElementRGB:
2827                   /* RGB order */
2828                   for (x=image->columns; x != 0; x--)
2829                     {
2830                       SetRedSample(q,map_Y[*samples_itr++]);
2831                       SetGreenSample(q,map_Y[*samples_itr++]);
2832                       SetBlueSample(q,map_Y[*samples_itr++]);
2833                       if (!image->matte)
2834                         SetOpacitySample(q,OpaqueOpacity);
2835                       q++;
2836                     }
2837                   break;
2838                 case ImageElementRGBA:
2839                   /* RGB order */
2840                   for (x=image->columns; x != 0; x--)
2841                     {
2842                       SetRedSample(q,map_Y[*samples_itr++]);
2843                       SetGreenSample(q,map_Y[*samples_itr++]);
2844                       SetBlueSample(q,map_Y[*samples_itr++]);
2845                       SetOpacitySample(q,map_Y[*samples_itr++]);
2846                       q++;
2847                     }
2848                   break;
2849                 case ImageElementABGR:
2850                   /* ARGB order */
2851                   for (x=image->columns; x != 0; x--)
2852                     {
2853                       SetOpacitySample(q,map_Y[*samples_itr++]);
2854                       SetRedSample(q,map_Y[*samples_itr++]);
2855                       SetGreenSample(q,map_Y[*samples_itr++]);
2856                       SetBlueSample(q,map_Y[*samples_itr++]);
2857                       q++;
2858                     }
2859                   break;
2860                 case ImageElementCbYCrY422:
2861                   {
2862                     /* CbY | CrY | CbY | CrY ..., even number of columns required. */
2863                     for (x=image->columns; x > 0; x -= 2)
2864                       {
2865                         Quantum
2866                           Cb,
2867                           Cr,
2868                           Y0,
2869                           Y1;
2870 
2871                         Cb=map_CbCr[*samples_itr++]; /* Cb */
2872                         Y0=map_Y[*samples_itr++];    /* Y0 */
2873                         Cr=map_CbCr[*samples_itr++]; /* Cr */
2874                         Y1=map_Y[*samples_itr++];    /* Y1 */
2875 
2876                         SetYSample(q,Y0);   /* Y0 */
2877                         SetCbSample(q,Cb);  /* Cb */
2878                         SetCrSample(q,Cr);  /* Cr */
2879                         if (!image->matte)
2880                           SetOpacitySample(q,OpaqueOpacity);
2881                         q++;
2882 
2883                         SetYSample(q,Y1);   /* Y1 */
2884                         SetCbSample(q,Cb) ; /* Cb (false) */
2885                         SetCrSample(q,Cr);  /* Cr (false) */
2886                         if (!image->matte)
2887                           q->opacity=OpaqueOpacity;
2888                         q++;
2889                       }
2890                     TentUpsampleChroma(pixels,image->columns);
2891                     break;
2892                   }
2893                 case ImageElementCbYACrYA4224:
2894                   {
2895                     /* CbYA | CrYA ..., even number of columns required. */
2896                     for (x=image->columns; x > 0; x -= 2)
2897                       {
2898                         Quantum
2899                           A0,
2900                           A1,
2901                           Cb,
2902                           Cr,
2903                           Y0,
2904                           Y1;
2905 
2906                         Cb=map_CbCr[*samples_itr++];
2907                         Y0=map_Y[*samples_itr++];
2908                         A0=map_Y[*samples_itr++];
2909 
2910                         Cr=map_CbCr[*samples_itr++];
2911                         Y1=map_Y[*samples_itr++];
2912                         A1=map_Y[*samples_itr++];
2913 
2914                         SetYSample(q,Y0);       /* Y0 */
2915                         SetCbSample(q,Cb);      /* Cb */
2916                         SetCrSample(q,Cr);      /* Cr */
2917                         SetOpacitySample(q,A0); /* A0 */
2918                         q++;
2919 
2920                         SetYSample(q,Y1);       /* Y1 */
2921                         SetCbSample(q,Cb);      /* Cb (false) */
2922                         SetCrSample(q,Cr);      /* Cr (false) */
2923                         SetOpacitySample(q,A1); /* A1 */
2924                         q++;
2925                       }
2926                     TentUpsampleChroma(pixels,image->columns);
2927                     break;
2928                   }
2929                 case ImageElementCbYCr444:
2930                   {
2931                     /* red,green,blue = Y, Cb, Cr */
2932                     for (x=image->columns; x != 0; x--)
2933                       {
2934                         SetCbSample(q,map_CbCr[*samples_itr++]); /* Cb */
2935                         SetYSample(q,map_Y[*samples_itr++]);     /* Y */
2936                         SetCrSample(q,map_CbCr[*samples_itr++]); /* Cr */
2937                         if (!image->matte)
2938                           SetOpacitySample(q,OpaqueOpacity);      /* A */
2939                         q++;
2940                       }
2941                     break;
2942                   }
2943                 case ImageElementCbYCrA4444:
2944                   {
2945                     /* red,green,blue = Y, Cb, Cr */
2946                     for (x=image->columns; x != 0; x--)
2947                       {
2948                         SetCbSample(q,map_CbCr[*samples_itr++]);   /* Cb */
2949                         SetYSample(q,map_Y[*samples_itr++]);       /* Y */
2950                         SetCrSample(q,map_CbCr[*samples_itr++]);   /* Cr */
2951                         SetOpacitySample(q,map_Y[*samples_itr++]); /* A */
2952                         q++;
2953                       }
2954                     break;
2955                   }
2956                 default:
2957                   break;
2958                 }
2959 
2960               if (!SyncImagePixelsEx(image,exception))
2961                 thread_status=MagickFail;
2962 
2963               /*
2964                 FIXME: Add support for optional EOL padding.
2965               */
2966               if (thread_status == MagickFail)
2967 #if defined(HAVE_OPENMP) && !defined(DisableSlowOpenMP)
2968 #  pragma omp critical (GM_ReadDPXImage)
2969 #endif
2970                 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                                      reported_file_offset);
2980                       break;
2981                     }
2982                 }
2983 #endif
2984             }
2985           /* break; */
2986         }
2987       else
2988         {
2989           ThrowDPXReaderException(CoderError,ColorTypeNotSupported,image);
2990         }
2991     }
2992 
2993   if (status != MagickPass)
2994     ThrowDPXReaderException(CorruptImageError,CorruptImage,image);
2995 
2996   if (EOFBlob(image))
2997     ThrowDPXReaderException(CorruptImageError,UnexpectedEndOfFile,
2998                             image);
2999 
3000   /*
3001     Support explicitly overriding the input file's colorspace.  Mostly
3002     useful for testing.
3003   */
3004   if ((definition_value=AccessDefinition(image_info,"dpx","colorspace")))
3005     {
3006       ColorspaceType
3007         colorspace;
3008 
3009       colorspace=StringToColorspaceType(definition_value);
3010       if (colorspace != UndefinedColorspace)
3011         {
3012           image->colorspace=colorspace;
3013           if (image->logging)
3014             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3015                                   "Explicitly set colorspace to %s",
3016                                   ColorspaceTypeToString(image->colorspace));
3017         }
3018       else
3019         {
3020           if (image->logging)
3021             (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3022                                   "Unrecognized source colorspace \"%s\"\n",
3023                                   definition_value);
3024           ThrowException(&image->exception,OptionError,UnrecognizedColorspace,
3025                          definition_value);
3026         }
3027     }
3028 
3029   /*
3030     If image is YCbCr representing Cineon Log RGB, then return the image as
3031     RGB in CineonLog colorspace.
3032   */
3033   if (IsYCbCrColorspace(image->colorspace) &&
3034       (transfer_characteristic == TransferCharacteristicPrintingDensity))
3035     {
3036       (void) TransformColorspace(image,RGBColorspace);
3037       image->colorspace=CineonLogRGBColorspace;
3038     }
3039 
3040   image->is_monochrome=is_monochrome;
3041   image->is_grayscale=is_grayscale;
3042   image->depth=Min(QuantumDepth,image->depth);
3043   MagickFreeResourceLimitedMemory(map_CbCr);
3044   MagickFreeResourceLimitedMemory(map_Y);
3045   DestroyThreadViewDataSet(scanline_set);
3046   DestroyThreadViewDataSet(samples_set);
3047   StopTimer(&image->timer);
3048   CloseBlob(image);
3049   return(image);
3050 }
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 */
RegisterDPXImage(void)3075 ModuleExport void RegisterDPXImage(void)
3076 {
3077   MagickInfo
3078     *entry;
3079 
3080   entry=SetMagickInfo("DPX");
3081   entry->decoder=(DecoderHandler) ReadDPXImage;
3082   entry->encoder=(EncoderHandler) WriteDPXImage;
3083   entry->magick=(MagickHandler) IsDPX;
3084   entry->description="SMPTE 268M-2003 (DPX 2.0)";
3085   entry->note="See http://www.smtpe.org/ for information on DPX.";
3086   entry->module="DPX";
3087   entry->adjoin=MagickFalse; /* Only one frame per file */
3088   entry->seekable_stream=MagickFalse; /* Does not reqire seek() */
3089   entry->coder_class=PrimaryCoderClass;
3090   (void) RegisterMagickInfo(entry);
3091 }
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 */
UnregisterDPXImage(void)3112 ModuleExport void UnregisterDPXImage(void)
3113 {
3114   (void) UnregisterMagickInfo("DPX");
3115 }
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 */
GenerateDPXTimeStamp(char * timestamp,size_t maxsize)3146 STATIC void GenerateDPXTimeStamp(char *timestamp, size_t maxsize)
3147 {
3148   time_t
3149     current_time;
3150 
3151 #if defined(HAVE_LOCALTIME_R)
3152   struct tm
3153     tm_buf;
3154 #endif /* if defined(HAVE_LOCALTIME_R) */
3155 
3156   const struct tm
3157     *t;
3158 
3159   char *
3160     p;
3161 
3162   current_time=time((time_t *) NULL);
3163 #if defined(HAVE_LOCALTIME_R)
3164   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   (void) strftime(timestamp,maxsize,"%Y:%m:%d:%H:%M:%S%Z",t);
3170   timestamp[maxsize-1]='\0';
3171   for (p=timestamp ; *p != '\0'; p++)
3172     if (*p == ' ')
3173       *p='0';
3174 }
3175 
OrientationTypeToDPXOrientation(const OrientationType orientation_type)3176 STATIC U16 OrientationTypeToDPXOrientation(const OrientationType orientation_type)
3177 {
3178   U16
3179     orientation = 0U;
3180 
3181   switch (orientation_type)
3182     {
3183     case UndefinedOrientation:
3184     case TopLeftOrientation:
3185       orientation=0U;
3186       break;
3187     case TopRightOrientation:
3188       orientation=1U;
3189       break;
3190     case BottomLeftOrientation:
3191       orientation=2U;
3192       break;
3193     case BottomRightOrientation:
3194       orientation=3U;
3195       break;
3196     case LeftTopOrientation:
3197       orientation=4U;
3198       break;
3199     case RightTopOrientation:
3200       orientation=5U;
3201       break;
3202     case LeftBottomOrientation:
3203       orientation=6U;
3204       break;
3205     case RightBottomOrientation:
3206       orientation=7U;
3207       break;
3208     }
3209   return orientation;
3210 }
3211 
3212 #define LSBPackedU32WordToOctets(packed_u32,scanline) \
3213 do { \
3214   *scanline++=(unsigned char) ((packed_u32) & 0xFF); \
3215   *scanline++=(unsigned char) ((packed_u32 >> 8) & 0xFF); \
3216   *scanline++=(unsigned char) ((packed_u32 >> 16) & 0xFF); \
3217   *scanline++=(unsigned char) ((packed_u32 >> 24) & 0xFF); \
3218  } while(0)
3219 #define MSBPackedU32WordToOctets(packed_u32,scanline) \
3220 do { \
3221   *scanline++=(unsigned char) ((packed_u32 >> 24) & 0xFF); \
3222   *scanline++=(unsigned char) ((packed_u32 >> 16) & 0xFF); \
3223   *scanline++=(unsigned char) ((packed_u32 >> 8) & 0xFF); \
3224   *scanline++=(unsigned char) ((packed_u32) & 0xFF); \
3225  } while(0)
3226 
3227 /*
3228   WordStreamLSBWrite support
3229 */
3230 typedef struct _WriteWordU32State
3231 {
3232   unsigned char *words;
3233 } WriteWordU32State;
3234 
WriteWordU32BE(void * state,const unsigned long value)3235 STATIC size_t WriteWordU32BE (void *state, const unsigned long value)
3236 {
3237   WriteWordU32State *write_state=(WriteWordU32State *) state;
3238   *write_state->words++ = (unsigned char) ((value >> 24) & 0xff);
3239   *write_state->words++ = (unsigned char) ((value >> 16) & 0xff);
3240   *write_state->words++ = (unsigned char) ((value >> 8) & 0xff);
3241   *write_state->words++ = (unsigned char) (value & 0xff);
3242   return sizeof(magick_uint32_t);
3243 }
3244 
WriteWordU32LE(void * state,const unsigned long value)3245 STATIC size_t WriteWordU32LE (void *state, const unsigned long value)
3246 {
3247   WriteWordU32State *write_state=(WriteWordU32State *) state;
3248   *write_state->words++ = (unsigned char) (value & 0xff);
3249   *write_state->words++ = (unsigned char) ((value >> 8) & 0xff);
3250   *write_state->words++ = (unsigned char) ((value >> 16) & 0xff);
3251   *write_state->words++ = (unsigned char) ((value >> 24) & 0xff);
3252   return sizeof(magick_uint32_t);
3253 }
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 */
WriteRowSamples(const sample_t * samples,const unsigned int samples_per_row,const unsigned int bits_per_sample,const ImageComponentPackingMethod packing_method,const EndianType endian_type,const MagickBool swap_word_datums,unsigned char * scanline)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 {
3278   register unsigned int
3279     i;
3280 
3281   BitStreamWriteHandle
3282     bit_stream;
3283 
3284   register unsigned char
3285     *sp;
3286 
3287   register unsigned int
3288     sample;
3289 
3290   sp=scanline;
3291   MagickBitStreamInitializeWrite(&bit_stream,scanline);
3292 
3293   if ((packing_method != PackingMethodPacked) &&
3294       ((bits_per_sample == 10) || (bits_per_sample == 12)))
3295     {
3296       MagickBool
3297         word_pad_lsb=MagickFalse,
3298         word_pad_msb=MagickFalse;
3299 
3300       if (packing_method == PackingMethodWordsFillLSB)
3301         word_pad_lsb=MagickTrue;
3302       else if (packing_method == PackingMethodWordsFillMSB)
3303         word_pad_msb=MagickTrue;
3304 
3305       if (bits_per_sample == 10)
3306         {
3307           register magick_uint32_t
3308             packed_u32;
3309 
3310           register unsigned int
3311             datum;
3312 
3313           unsigned int
3314             shifts[3] = { 0, 0, 0 };
3315 
3316           if (word_pad_lsb)
3317             {
3318               /*
3319                 Padding in LSB (Method A)  Standard method.
3320               */
3321               if (swap_word_datums == MagickFalse)
3322                 {
3323                   shifts[0]=2;  /* datum-0 / blue */
3324                   shifts[1]=12; /* datum-1 / green */
3325                   shifts[2]=22; /* datum-2 / red */
3326                 }
3327               else
3328                 {
3329                   shifts[0]=22; /* datum-2 / red */
3330                   shifts[1]=12; /* datum-1 / green */
3331                   shifts[2]=2;  /* datum-0 / blue */
3332                 }
3333             }
3334           else if (word_pad_msb)
3335             {
3336               /*
3337                 Padding in MSB (Method B)  Deprecated method.
3338               */
3339               if (swap_word_datums == MagickFalse)
3340                 {
3341                   shifts[0]=0;  /* datum-0 / blue */
3342                   shifts[1]=10; /* datum-1 / green */
3343                   shifts[2]=20; /* datum-2 / red */
3344                 }
3345               else
3346                 {
3347                   shifts[0]=20; /* datum-2 / red */
3348                   shifts[1]=10; /* datum-1 / green */
3349                   shifts[2]=0;  /* datum-0 / blue */
3350                 }
3351             }
3352 
3353           datum=0;
3354           packed_u32=0;
3355           if (endian_type == MSBEndian)
3356             {
3357               for (i=0; i < samples_per_row; i++)
3358                 {
3359                   if (datum == 2)
3360                     {
3361                       MSBPackedU32WordToOctets(packed_u32,scanline);
3362                       packed_u32=0;
3363                     }
3364                   datum = i % 3;
3365                   packed_u32 |= (((magick_uint32_t) *samples++) << shifts[datum]);
3366                 }
3367               if ((samples_per_row+1) % 3 )
3368                 MSBPackedU32WordToOctets(packed_u32,scanline);
3369             }
3370           else if (endian_type == LSBEndian)
3371             {
3372               for (i=0; i < samples_per_row; i++)
3373                 {
3374                   if (datum == 2)
3375                     {
3376                       LSBPackedU32WordToOctets(packed_u32,scanline);
3377                       packed_u32=0;
3378                     }
3379                   datum = i % 3;
3380                   packed_u32 |= (((magick_uint32_t) *samples++) << shifts[datum]);
3381                 }
3382               if ((samples_per_row+1) % 3 )
3383                 LSBPackedU32WordToOctets(packed_u32,scanline);
3384             }
3385           return;
3386         }
3387       else if (bits_per_sample == 12)
3388         {
3389           if (word_pad_lsb)
3390             {
3391               /*
3392                 Padding in LSB (Method A).
3393               */
3394               if (endian_type == MSBEndian)
3395                 {
3396                   for (i=samples_per_row; i != 0; i--)
3397                     {
3398                       sample=*samples++;
3399                       sample <<= 4;
3400                       *sp++=(unsigned char) (((unsigned int) sample) >> 8);
3401                       *sp++=(unsigned char) sample;
3402                     }
3403                 }
3404               else if (endian_type == LSBEndian)
3405                 {
3406                   for (i=samples_per_row; i != 0; i--)
3407                     {
3408                       sample=*samples++;
3409                       sample <<= 4;
3410                       *sp++=(unsigned char) sample;
3411                       *sp++=(unsigned char) (((unsigned int) sample) >> 8);
3412                     }
3413                 }
3414             }
3415           else if (word_pad_msb)
3416             {
3417               /*
3418                 Padding in MSB (Method B).
3419               */
3420               if (endian_type == MSBEndian)
3421                 {
3422                   for (i=samples_per_row; i != 0; i--)
3423                     {
3424                       sample=((*samples++) & 0xFFF);
3425                       *sp++=(unsigned char) (((unsigned int) sample) >> 8);
3426                       *sp++=(unsigned char) sample;
3427                     }
3428                 }
3429               else if (endian_type == LSBEndian)
3430                 {
3431                   for (i=samples_per_row; i != 0; i--)
3432                     {
3433                       sample=((*samples++) & 0xFFF);
3434                       *sp++=(unsigned char) sample;
3435                       *sp++=(unsigned char) (((unsigned int) sample) >> 8);
3436                     }
3437                 }
3438             }
3439           return;
3440         }
3441     }
3442 
3443   /*
3444     Special fast handling for 8-bit images.
3445   */
3446   if (bits_per_sample == 8)
3447     {
3448       for (i=samples_per_row; i != 0; i--)
3449         *sp++=(unsigned char) *samples++;
3450       return;
3451     }
3452 
3453   /*
3454     Special fast handling for 16-bit images.
3455   */
3456   if (bits_per_sample == 16)
3457     {
3458       if (endian_type == MSBEndian)
3459         {
3460           for (i=samples_per_row; i != 0; i--)
3461             {
3462               *sp++=(unsigned char) (((unsigned int) *samples) >> 8);
3463               *sp++=(unsigned char) *samples;
3464               samples++;
3465             }
3466         }
3467       else if (endian_type == LSBEndian)
3468         {
3469           for (i=samples_per_row; i != 0; i--)
3470             {
3471               *sp++=(unsigned char) *samples;
3472               *sp++=(unsigned char) (((unsigned int) *samples) >> 8);
3473               samples++;
3474             }
3475         }
3476       return;
3477     }
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   {
3512       WriteWordU32State
3513         write_state;
3514 
3515       WordStreamWriteHandle
3516         write_stream;
3517 
3518       WordStreamWriteFunc
3519         write_func=0;
3520 
3521       if (endian_type == LSBEndian)
3522         write_func=WriteWordU32LE;
3523       else
3524         write_func=WriteWordU32BE;
3525 
3526       write_state.words=scanline;
3527       MagickWordStreamInitializeWrite(&write_stream,write_func, (void *) &write_state);
3528 
3529       for (i=samples_per_row; i != 0; i--)
3530         MagickWordStreamLSBWrite(&write_stream,bits_per_sample,*samples++);
3531 
3532       MagickWordStreamLSBWriteFlush(&write_stream);
3533   }
3534 }
3535 
3536 #define AttributeToU8(image_info,image,key,member) \
3537 { \
3538   const ImageAttribute \
3539     *attribute_; \
3540 \
3541   const char \
3542     *definition_value_; \
3543 \
3544   if ((definition_value_=AccessDefinition(image_info,"dpx",&key[4]))) \
3545     member=(U8) strtol(definition_value_, (char **) NULL, 10); \
3546   else if ((attribute_=GetImageAttribute(image,key))) \
3547     member=(U8) strtol(attribute_->value, (char **) NULL, 10); \
3548   else \
3549     SET_UNDEFINED_U8(member); \
3550 }
3551 
3552 #define AttributeToU16(image_info,image,key,member) \
3553 { \
3554   const ImageAttribute \
3555     *attribute_; \
3556 \
3557   const char \
3558     *definition_value_; \
3559 \
3560   if ((definition_value_=AccessDefinition(image_info,"dpx",&key[4]))) \
3561     member=(U16) strtol(definition_value_, (char **) NULL, 10); \
3562   else if ((attribute_=GetImageAttribute(image,key))) \
3563     member=(U16) strtol(attribute_->value, (char **) NULL, 10); \
3564   else \
3565     SET_UNDEFINED_U16(member); \
3566 }
3567 
3568 #define AttributeToU32(image_info,image,key,member) \
3569 { \
3570   const ImageAttribute \
3571     *attribute_; \
3572 \
3573   const char \
3574     *definition_value_; \
3575 \
3576   if ((definition_value_=AccessDefinition(image_info,"dpx",&key[4]))) \
3577     member=(U32) strtol(definition_value_, (char **) NULL, 10); \
3578   else if ((attribute_=GetImageAttribute(image,key))) \
3579     member=(U32) strtol(attribute_->value, (char **) NULL, 10); \
3580   else \
3581     SET_UNDEFINED_U32(member); \
3582 }
3583 
3584 #define AttributeBitsToU32(image_info,image,key,member) \
3585 { \
3586   const ImageAttribute \
3587     *attribute_; \
3588 \
3589   const char \
3590     *definition_value_; \
3591 \
3592   if ((definition_value_=AccessDefinition(image_info,"dpx",&key[4]))) \
3593     member=SMPTEStringToBits(definition_value_); \
3594   else if ((attribute_=GetImageAttribute(image,key))) \
3595     member=SMPTEStringToBits(attribute_->value); \
3596   else \
3597     SET_UNDEFINED_U32(member); \
3598 }
3599 
3600 #define AttributeToR32(image_info,image,key,member) \
3601 { \
3602   const ImageAttribute \
3603     *attribute_; \
3604 \
3605   const char \
3606     *definition_value_; \
3607 \
3608   if ((definition_value_=AccessDefinition(image_info,"dpx",&key[4]))) \
3609     member.f=strtod(definition_value_, (char **) NULL); \
3610   else if ((attribute_=GetImageAttribute(image,key))) \
3611     member.f=strtod(attribute_->value, (char **) NULL); \
3612   else \
3613     SET_UNDEFINED_R32(member); \
3614 }
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 #define AttributeToString(image_info,image,key,member) \
3624 { \
3625   const ImageAttribute \
3626     *attribute_; \
3627 \
3628   const char \
3629     *attribute_value_ = NULL; \
3630 \
3631   size_t \
3632     attribute_value_length_ = 0; \
3633 \
3634   if ((attribute_value_=AccessDefinition(image_info,"dpx",&key[4]))) \
3635     { \
3636     } \
3637   else if ((attribute_=GetImageAttribute(image,key))) \
3638     { \
3639       attribute_value_=attribute_->value; \
3640     } \
3641 \
3642   if (attribute_value_) \
3643     { \
3644       attribute_value_length_=strlen(attribute_value_); \
3645       attribute_value_length_=Min(attribute_value_length_,sizeof(member)); \
3646       (void) memcpy(member,attribute_value_,attribute_value_length_);    \
3647     } \
3648     if (sizeof(member) > attribute_value_length_) \
3649       (void) memset(member+attribute_value_length_,0,sizeof(member)-attribute_value_length_); \
3650 }
3651 
3652 /*
3653   Round an offset up to specified offset boundary.
3654 */
3655 #define RoundUpToBoundary(offset,boundary) \
3656   (((offset+boundary-1)/boundary)*boundary);
3657 
3658 #define ThrowDPXWriterException(code_,reason_,image_)    \
3659 { \
3660   MagickFreeResourceLimitedMemory(map_CbCr);   \
3661   MagickFreeResourceLimitedMemory(map_Y); \
3662   MagickFreeResourceLimitedMemory(samples); \
3663   MagickFreeResourceLimitedMemory(scanline); \
3664   if (chroma_image) \
3665     DestroyImage(chroma_image); \
3666   ThrowWriterException(code_,reason_,image_); \
3667 }
3668 
WriteDPXImage(const ImageInfo * image_info,Image * image)3669 STATIC unsigned int WriteDPXImage(const ImageInfo *image_info,Image *image)
3670 {
3671   char
3672     txt_buffer[MaxTextExtent];
3673 
3674   DPXFileInfo
3675     dpx_file_info;
3676 
3677   DPXImageInfo
3678     dpx_image_info;
3679 
3680   DPXImageSourceInfo
3681     dpx_source_info;
3682 
3683   DPXMPFilmInfo
3684     dpx_mp_info;
3685 
3686   DPXTVInfo
3687     dpx_tv_info;
3688 
3689   DPXImageElementDescriptor
3690     element_descriptor;
3691 
3692   ImageComponentPackingMethod
3693     packing_method;
3694 
3695   DPXTransferCharacteristic
3696     transfer_characteristic;
3697 
3698   Image
3699     *chroma_image=0;
3700 
3701   unsigned long
3702     y;
3703 
3704   register const PixelPacket
3705     *p;
3706 
3707   register unsigned long
3708     i,
3709     x;
3710 
3711   sample_t
3712     *samples=0,
3713     *samples_itr;
3714 
3715   sample_t
3716     *map_Y=0,                   /* value translation map (RGB or Y) */
3717     *map_CbCr=0;                /* value translation map (CbCr) */
3718 
3719   unsigned char
3720     *scanline=0;
3721 
3722   const unsigned char
3723     *user_data;
3724 
3725   unsigned int
3726     bits_per_sample=0,
3727     element,
3728     sampling_factor_horizontal,
3729     sampling_factor_vertical,
3730     max_samples_per_pixel,
3731     image_data_offset,
3732     number_of_elements,
3733     row_samples,
3734     samples_per_component,
3735     samples_per_pixel,
3736     samples_per_row,
3737     status;
3738 
3739   MagickBool
3740     swap_endian;
3741 
3742   size_t
3743     element_size;
3744 
3745   const char *
3746     definition_value;
3747 
3748   size_t
3749     offset=0,
3750     row_octets,
3751     user_data_length=0;
3752 
3753   EndianType
3754     endian_type;
3755 
3756   /*
3757     Open output image file.
3758   */
3759   assert(image_info != (const ImageInfo *) NULL);
3760   assert(image_info->signature == MagickSignature);
3761   assert(image != (Image *) NULL);
3762   assert(image->signature == MagickSignature);
3763   status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
3764   if (status == False)
3765     ThrowWriterException(FileOpenError,UnableToOpenFile,image);
3766 
3767   /*
3768     Support user-selection of big/little endian output.
3769   */
3770   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   swap_endian=MagickTrue;
3780   if (image_info->endian == LSBEndian)
3781     {
3782       swap_endian=MagickFalse;
3783       endian_type=LSBEndian;
3784     }
3785 #endif
3786 
3787   if (image->logging)
3788     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3789                           "%s endian DPX format",
3790                           (endian_type == MSBEndian ? "Big" : "Little"));
3791 
3792   /*
3793     Adjust image colorspace if necessary.
3794   */
3795   if ((image_info->colorspace == CineonLogRGBColorspace) &&
3796       (image->colorspace != CineonLogRGBColorspace))
3797     (void) TransformColorspace(image,CineonLogRGBColorspace);
3798   else if ((image_info->colorspace == Rec601LumaColorspace) &&
3799            (image->colorspace != Rec601LumaColorspace))
3800     (void) TransformColorspace(image,Rec601LumaColorspace);
3801   else if ((image_info->colorspace == Rec601YCbCrColorspace) &&
3802            (image->colorspace != Rec601YCbCrColorspace))
3803     (void) TransformColorspace(image,Rec601YCbCrColorspace);
3804   else if ((image_info->colorspace == YCbCrColorspace) &&
3805            (image->colorspace != Rec601YCbCrColorspace))
3806     (void) TransformColorspace(image,Rec601YCbCrColorspace);
3807   else if ((image_info->colorspace == Rec709LumaColorspace) &&
3808            (image->colorspace != Rec709LumaColorspace))
3809     (void) TransformColorspace(image,Rec709LumaColorspace);
3810   else if ((image_info->colorspace == Rec709YCbCrColorspace) &&
3811            (image->colorspace != Rec709YCbCrColorspace))
3812     (void) TransformColorspace(image,Rec709YCbCrColorspace);
3813   else if (IsRGBColorspace(image_info->colorspace) &&
3814            !IsRGBColorspace(image->colorspace))
3815     (void) TransformColorspace(image,RGBColorspace);
3816   else if (!IsRGBColorspace(image->colorspace) &&
3817            (image->colorspace != CineonLogRGBColorspace) &&
3818            (image->colorspace != Rec601YCbCrColorspace) &&
3819            (image->colorspace != Rec709YCbCrColorspace))
3820     (void) TransformColorspace(image,RGBColorspace);
3821 
3822   /*
3823     Compute desired/necessary number of bits per sample.
3824   */
3825   if ((definition_value=AccessDefinition(image_info,"dpx","bits-per-sample")))
3826     bits_per_sample=MagickAtoI(definition_value);
3827 
3828   if (bits_per_sample == 0)
3829     {
3830       if (image->depth > 12 )
3831         bits_per_sample=16;
3832       else if (image->depth > 10)
3833         bits_per_sample=12;
3834       else if (image->depth > 8)
3835         bits_per_sample=10;
3836       else if (image->depth > 1)
3837         bits_per_sample=8;
3838       else
3839         bits_per_sample=1;
3840     }
3841 
3842   if (image->logging)
3843     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3844                           "Bits per sample: %u", bits_per_sample);
3845 
3846   /*
3847     Obtain requested sampling factors.
3848   */
3849   sampling_factor_horizontal=2;
3850   sampling_factor_vertical=2;
3851   if (image_info->sampling_factor != (char *) NULL)
3852     {
3853       long
3854         factors;
3855 
3856       factors=sscanf(image_info->sampling_factor,"%ux%u",&sampling_factor_horizontal,
3857                      &sampling_factor_vertical);
3858       if (factors != 2)
3859         sampling_factor_vertical=sampling_factor_horizontal;
3860       if ((sampling_factor_horizontal != 1) && (sampling_factor_horizontal != 2) &&
3861           (sampling_factor_vertical != 1) && (sampling_factor_vertical != 2))
3862         ThrowDPXWriterException(OptionError,UnsupportedSamplingFactor,
3863                                 image);
3864 
3865       /*
3866         When subsampling, image width must be evenly divisible by two.
3867       */
3868       if (((sampling_factor_horizontal / sampling_factor_vertical) == 2) &&
3869           (image->columns %2))
3870         ThrowDPXWriterException(CoderError,SubsamplingRequiresEvenWidth,image);
3871     }
3872 
3873   /*
3874     Intuit the samples per component and the number of elements.
3875   */
3876   if (IsYCbCrColorspace(image->colorspace))
3877     {
3878       if ((image_info->interlace == PlaneInterlace) &&
3879           ((sampling_factor_horizontal / sampling_factor_vertical) == 2))
3880         {
3881           /* YCbCr 4:2:2 planar */
3882           samples_per_component=1;
3883           number_of_elements=2;
3884           if (image->matte)
3885             number_of_elements++;
3886         }
3887       else
3888         {
3889           if ((sampling_factor_horizontal / sampling_factor_vertical) == 2)
3890             {
3891               /* YCbCr 4:2:2 */
3892               samples_per_component=2;
3893             }
3894           else
3895             {
3896               /* YCbCr 4:4:4 */
3897               samples_per_component=3;
3898             }
3899           number_of_elements=1;
3900           if (image->matte)
3901             samples_per_component++;
3902         }
3903     }
3904   else if (IsGrayColorspace(image->colorspace))
3905     {
3906       samples_per_component=1;
3907       number_of_elements=1;
3908       if (image->matte)
3909         number_of_elements++;
3910     }
3911   else
3912     {
3913       if (image_info->interlace == PlaneInterlace)
3914         {
3915           samples_per_component=1;
3916           number_of_elements=3;
3917           if (image->matte)
3918             number_of_elements++;
3919         }
3920       else
3921         {
3922           samples_per_component=3;
3923           number_of_elements=1;
3924           if (image->matte)
3925             samples_per_component++;
3926         }
3927     }
3928 
3929   /*
3930     Choose the default packing method.
3931   */
3932   if ((bits_per_sample == 10) || (bits_per_sample == 12))
3933     packing_method=PackingMethodWordsFillLSB;
3934   else
3935     packing_method=PackingMethodPacked;
3936 
3937   /*
3938     Allow the user to over-ride the default packing method.
3939   */
3940   if ((definition_value=AccessDefinition(image_info,"dpx","packing-method")))
3941     {
3942       if (LocaleCompare(definition_value,"packed") == 0)
3943         {
3944           packing_method=PackingMethodPacked;
3945         }
3946       else if ((bits_per_sample == 10) || (bits_per_sample == 12))
3947         {
3948           if ((LocaleCompare(definition_value,"lsbpad") == 0) ||
3949               (LocaleCompare(definition_value,"a") == 0))
3950             packing_method=PackingMethodWordsFillLSB;
3951           else if ((LocaleCompare(definition_value,"msbpad") == 0) ||
3952                    (LocaleCompare(definition_value,"b") == 0))
3953             packing_method=PackingMethodWordsFillMSB;
3954         }
3955     }
3956 
3957   row_samples=((magick_int64_t) image->columns*samples_per_component);
3958   row_octets=DPXRowOctets(1,row_samples,bits_per_sample,packing_method);
3959   element_size=DPXRowOctets(image->rows,row_samples,bits_per_sample,packing_method);
3960 
3961   if (image->logging)
3962     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
3963                           "Samples per row %u, octets per row %lu, element size %lu",
3964                           row_samples, (unsigned long) row_octets,
3965                           (unsigned long) element_size);
3966   /*
3967     Obtain pointer to user data and user data length (if available).
3968   */
3969   user_data=GetImageProfile(image,"DPXUSERDATA",&user_data_length);
3970 
3971   /*
3972     Image information header
3973   */
3974   (void) memset(&dpx_image_info,0,sizeof(dpx_image_info));
3975   /* Image orientation */
3976   dpx_image_info.orientation=OrientationTypeToDPXOrientation(image->orientation);
3977   /* Number of image elements described. */
3978   dpx_image_info.elements=number_of_elements;
3979   /* Number of pixels per line. */
3980   dpx_image_info.pixels_per_line=image->columns;
3981   /* Number of lines per image element. */
3982   dpx_image_info.lines_per_image_element=image->rows;
3983   /* Image sample sign. */
3984   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   SET_UNDEFINED_U8(dpx_image_info.element_info[0].transfer_characteristic);
4001   SET_UNDEFINED_U8(dpx_image_info.element_info[0].colorimetric);
4002   SET_UNDEFINED_U8(dpx_image_info.element_info[0].reference_low_data_code);
4003   SET_UNDEFINED_R32(dpx_image_info.element_info[0].reference_low_quantity);
4004   SET_UNDEFINED_U32(dpx_image_info.element_info[0].reference_high_data_code);
4005   SET_UNDEFINED_R32(dpx_image_info.element_info[0].reference_high_quantity);
4006 
4007   if (image->colorspace == CineonLogRGBColorspace)
4008     {
4009       transfer_characteristic=TransferCharacteristicPrintingDensity;
4010     }
4011   else if ((image->colorspace == YCbCrColorspace) ||
4012            (image->colorspace == Rec601YCbCrColorspace) ||
4013            (image->colorspace == Rec601LumaColorspace))
4014     {
4015       if (image->rows > 525)
4016         transfer_characteristic=TransferCharacteristicITU_R601_625L;
4017       else
4018         transfer_characteristic=TransferCharacteristicITU_R601_525L;
4019     }
4020   else if ((image->colorspace == Rec709YCbCrColorspace) ||
4021            (image->colorspace == Rec709LumaColorspace))
4022     {
4023       transfer_characteristic=TransferCharacteristicITU_R709;
4024     }
4025   else
4026     {
4027       transfer_characteristic=TransferCharacteristicLinear;
4028     }
4029 
4030   /* Transfer characteristic. Define the amplitude transfer function
4031      necessary to transform the data to a linear original. */
4032   dpx_image_info.element_info[0].transfer_characteristic=transfer_characteristic;
4033 
4034   if (transfer_characteristic == TransferCharacteristicPrintingDensity)
4035     {
4036       /* Printing density is a log encoding */
4037       dpx_image_info.element_info[0].colorimetric=ColorimetricPrintingDensity;
4038       dpx_image_info.element_info[0].reference_low_data_code=0;
4039       dpx_image_info.element_info[0].reference_high_data_code=
4040         MaxValueGivenBits(bits_per_sample);
4041       dpx_image_info.element_info[0].reference_low_quantity.f=0.00F;
4042       dpx_image_info.element_info[0].reference_high_quantity.f=2.047F;
4043     }
4044   else if ((transfer_characteristic == TransferCharacteristicUnspecifiedVideo) ||
4045            (transfer_characteristic == TransferCharacteristicSMTPE274M) ||
4046            (transfer_characteristic == TransferCharacteristicITU_R709) ||
4047            (transfer_characteristic == TransferCharacteristicITU_R601_625L) ||
4048            (transfer_characteristic == TransferCharacteristicITU_R601_525L) ||
4049            (transfer_characteristic == TransferCharacteristicNTSCCompositeVideo) ||
4050            (transfer_characteristic == TransferCharacteristicPALCompositeVideo))
4051     {
4052       /*
4053         Some sort of video.
4054       */
4055       unsigned int
4056         max_value_given_bits = MaxValueGivenBits(bits_per_sample);
4057 
4058       switch (transfer_characteristic)
4059         {
4060         case TransferCharacteristicSMTPE274M:
4061           dpx_image_info.element_info[0].colorimetric=ColorimetricSMTPE274M;
4062           break;
4063         case TransferCharacteristicITU_R709:
4064           dpx_image_info.element_info[0].colorimetric=ColorimetricITU_R709;
4065           break;
4066         case TransferCharacteristicITU_R601_625L:
4067           dpx_image_info.element_info[0].colorimetric=ColorimetricITU_R601_625L;
4068           break;
4069         case TransferCharacteristicITU_R601_525L:
4070           dpx_image_info.element_info[0].colorimetric=ColorimetricITU_R601_525L;
4071           break;
4072         case TransferCharacteristicNTSCCompositeVideo:
4073           dpx_image_info.element_info[0].colorimetric=ColorimetricNTSCCompositeVideo;
4074           break;
4075         case TransferCharacteristicPALCompositeVideo:
4076           dpx_image_info.element_info[0].colorimetric=ColorimetricPALCompositeVideo;
4077           break;
4078         default:
4079           dpx_image_info.element_info[0].colorimetric=ColorimetricUserDefined;
4080           break;
4081         }
4082 
4083       dpx_image_info.element_info[0].reference_low_data_code=        /* 16 for 8 bits */
4084         (U32) (max_value_given_bits * (16.0/255.0) + 0.5);
4085       dpx_image_info.element_info[0].reference_high_data_code=       /* 235 for 8 bits */
4086         (U32) (max_value_given_bits * (235.0/255.0) + 0.5);
4087       dpx_image_info.element_info[0].reference_low_quantity.f=0.00F;   /* 0mv */
4088       dpx_image_info.element_info[0].reference_high_quantity.f=0.700F; /* 700mv */
4089     }
4090   else if (transfer_characteristic == TransferCharacteristicLinear)
4091     {
4092       /* Otherwise we are using linear encoding */
4093       dpx_image_info.element_info[0].colorimetric=ColorimetricLinear;
4094       dpx_image_info.element_info[0].reference_low_data_code=0;
4095       dpx_image_info.element_info[0].reference_high_data_code=
4096         MaxValueGivenBits(bits_per_sample);
4097     }
4098 
4099   /*
4100     Compute image data offset.  Should be rounded up to next 8K block.
4101   */
4102   image_data_offset=2048;
4103   if (user_data)
4104     image_data_offset += (unsigned int) user_data_length;
4105   image_data_offset=RoundUpToBoundary(image_data_offset,IMAGE_DATA_ROUNDING);
4106 
4107   /* Element Descriptor */
4108   SET_UNDEFINED_U8(dpx_image_info.element_info[0].descriptor);
4109   /* Number of bits per sample */
4110   dpx_image_info.element_info[0].bits_per_sample=bits_per_sample;
4111   /* Packing method */
4112   dpx_image_info.element_info[0].packing=0;
4113   if ((bits_per_sample == 10) || (bits_per_sample == 12))
4114     dpx_image_info.element_info[0].packing=packing_method;
4115   /* Encoding.  Unencoded or run length encoded */
4116   dpx_image_info.element_info[0].encoding=0; /* No encoding */
4117   /* Offset to element data from beginning of file. */
4118   dpx_image_info.element_info[0].data_offset=image_data_offset;
4119   /* Number of padded bytes at the end of each line */
4120   dpx_image_info.element_info[0].eol_pad=0;
4121   /* Number of padded bytes at the end of image element. */
4122   dpx_image_info.element_info[0].eoi_pad=0;
4123   /* Element description */
4124   SET_UNDEFINED_ASCII(dpx_image_info.element_info[0].description);
4125 
4126   for (i=1; i < number_of_elements; i++)
4127     {
4128       /* Clone settings from preceding element */
4129       dpx_image_info.element_info[i]=dpx_image_info.element_info[i-1];
4130       /* Compute offset to data */
4131       dpx_image_info.element_info[i].data_offset=
4132         dpx_image_info.element_info[i-1].data_offset+(U32) element_size;
4133     }
4134 
4135   /*
4136     Fill out element descriptor.
4137   */
4138   if (number_of_elements > 1)
4139     {
4140       /*
4141         Planar image configuration.
4142       */
4143       if (IsGrayColorspace(image->colorspace))
4144         {
4145           /* Luma with alpha channel in second plane */
4146           dpx_image_info.element_info[0].descriptor=ImageElementLuma;
4147           dpx_image_info.element_info[1].descriptor=ImageElementAlpha;
4148         }
4149       else if (IsRGBColorspace(image->colorspace) ||
4150                (image->colorspace == CineonLogRGBColorspace))
4151         {
4152           /* RGB Planar */
4153           dpx_image_info.element_info[0].descriptor=ImageElementRed;
4154           dpx_image_info.element_info[1].descriptor=ImageElementGreen;
4155           dpx_image_info.element_info[2].descriptor=ImageElementBlue;
4156           if ((image->matte) && (number_of_elements == 4))
4157             {
4158               dpx_image_info.element_info[3].descriptor=ImageElementAlpha;
4159             }
4160         }
4161       else if (IsYCbCrColorspace(image->colorspace))
4162         {
4163           /* YCbCr 4:2:2 planar */
4164           dpx_image_info.element_info[0].descriptor=ImageElementLuma;
4165           dpx_image_info.element_info[1].descriptor=ImageElementColorDifferenceCbCr;
4166           if (image->matte)
4167             dpx_image_info.element_info[2].descriptor=ImageElementAlpha;
4168         }
4169     }
4170   else
4171     {
4172       if (IsYCbCrColorspace(image->colorspace))
4173         {
4174           /* CbYCr */
4175           if (samples_per_component == 2)
4176             {
4177               /* CbYCr 4:2:2 */
4178               dpx_image_info.element_info[0].descriptor=image->matte ?
4179                 ImageElementCbYACrYA4224 : ImageElementCbYCrY422;
4180             }
4181           else
4182             {
4183               /* CbYCr 4:4:4 */
4184               dpx_image_info.element_info[0].descriptor=image->matte ?
4185                 ImageElementCbYCrA4444 : ImageElementCbYCr444;
4186             }
4187         }
4188       else if (IsGrayColorspace(image->colorspace))
4189         {
4190           /* Luma */
4191           dpx_image_info.element_info[0].descriptor=ImageElementLuma;
4192         }
4193       else if (IsRGBColorspace(image->colorspace) ||
4194                (image->colorspace == CineonLogRGBColorspace))
4195         {
4196           /* RGB */
4197           dpx_image_info.element_info[0].descriptor=image->matte ?
4198             ImageElementRGBA : ImageElementRGB;
4199         }
4200     }
4201 
4202   /*
4203     Add a textual description for each element.
4204   */
4205   for (i=0; i < number_of_elements; i++)
4206     {
4207       (void) strlcpy(dpx_image_info.element_info[i].description,
4208                      DescribeImageElementDescriptor(txt_buffer,
4209                      (DPXImageElementDescriptor) dpx_image_info.element_info[i].descriptor),
4210                      sizeof(dpx_image_info.element_info[0].description));
4211       (void) strlcat(dpx_image_info.element_info[i].description," / ",
4212                      sizeof(dpx_image_info.element_info[0].description));
4213       (void) strlcat(dpx_image_info.element_info[i].description,
4214                      DescribeImageTransferCharacteristic(txt_buffer,
4215                      (DPXTransferCharacteristic) dpx_image_info.element_info[i].transfer_characteristic),
4216                      sizeof(dpx_image_info.element_info[0].description));
4217     }
4218 
4219   /*
4220     File information header.
4221   */
4222   (void) memset(&dpx_file_info,0,sizeof(dpx_file_info));
4223   dpx_file_info.magic=0x53445058U;
4224   dpx_file_info.image_data_offset=dpx_image_info.element_info[0].data_offset;
4225   (void) strlcpy(dpx_file_info.header_format_version,"V2.0",
4226                  sizeof(dpx_file_info.header_format_version));
4227   dpx_file_info.file_size=
4228     dpx_file_info.image_data_offset+number_of_elements*(U32) element_size;
4229   if (image->logging)
4230     (void) LogMagickEvent(CoderEvent,GetMagickModule(),
4231                           "Estimated file length: %u",dpx_file_info.file_size);
4232   dpx_file_info.ditto_key=1; /* new frame */
4233   dpx_file_info.generic_section_length=sizeof(dpx_file_info)+
4234     sizeof(dpx_image_info)+sizeof(dpx_source_info);
4235   dpx_file_info.industry_section_length=sizeof(dpx_mp_info)+sizeof(dpx_tv_info);
4236   dpx_file_info.user_defined_length=(U32) (user_data ? user_data_length : 0);
4237   (void) strlcpy(dpx_file_info.image_filename,image->filename,
4238                  sizeof(dpx_file_info.image_filename));
4239   GenerateDPXTimeStamp(dpx_file_info.creation_datetime,
4240                        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     (void) strlcpy(dpx_file_info.creator,GetMagickVersion((unsigned long *) NULL),
4246                    sizeof(dpx_file_info.creator));
4247   AttributeToString(image_info,image,"DPX:file.project.name",dpx_file_info.project_name);
4248   AttributeToString(image_info,image,"DPX:file.copyright",dpx_file_info.copyright);
4249   AttributeToU32(image_info,image,"DPX:file.encryption.key",dpx_file_info.encryption_key);
4250   /*
4251     Image source information header
4252   */
4253   (void) memset(&dpx_source_info,0,sizeof(dpx_source_info));
4254   SET_UNDEFINED_U32(dpx_source_info.x_offset);
4255   SET_UNDEFINED_U32(dpx_source_info.y_offset);
4256   SET_UNDEFINED_R32(dpx_source_info.x_center);
4257   SET_UNDEFINED_R32(dpx_source_info.y_center);
4258   SET_UNDEFINED_U32(dpx_source_info.x_original_size);
4259   SET_UNDEFINED_U32(dpx_source_info.y_original_size);
4260   if ((image->rows == image->magick_rows) && (image->columns == image->magick_columns))
4261     {
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       AttributeToU32(image_info,image,"DPX:source.x-offset",dpx_source_info.x_offset);
4267       AttributeToU32(image_info,image,"DPX:source.y-offset",dpx_source_info.y_offset);
4268       AttributeToR32(image_info,image,"DPX:source.x-center",dpx_source_info.x_center);
4269       AttributeToR32(image_info,image,"DPX:source.y-center",dpx_source_info.y_center);
4270       AttributeToU32(image_info,image,"DPX:source.x-original-size",dpx_source_info.x_original_size);
4271       AttributeToU32(image_info,image,"DPX:source.y-original-size",dpx_source_info.y_original_size);
4272     }
4273   AttributeToString(image_info,image,"DPX:source.filename",dpx_source_info.source_image_filename);
4274   if (IS_UNDEFINED_ASCII(dpx_source_info.source_image_filename))
4275     (void) strlcpy(dpx_source_info.source_image_filename,image->magick_filename,
4276                    sizeof(dpx_source_info.source_image_filename));
4277   AttributeToString(image_info,image,"DPX:source.creation.datetime",dpx_source_info.source_image_datetime);
4278   AttributeToString(image_info,image,"DPX:source.device.name",dpx_source_info.input_device_name);
4279   AttributeToString(image_info,image,"DPX:source.device.serialnumber",dpx_source_info.input_device_serialnumber);
4280   AttributeToU16(image_info,image,"DPX:source.border.validity.left",dpx_source_info.border_validity.XL);
4281   AttributeToU16(image_info,image,"DPX:source.border.validity.right",dpx_source_info.border_validity.XR);
4282   AttributeToU16(image_info,image,"DPX:source.border.validity.top",dpx_source_info.border_validity.YT);
4283   AttributeToU16(image_info,image,"DPX:source.border.validity.bottom",dpx_source_info.border_validity.YB);
4284   AttributeToU32(image_info,image,"DPX:source.aspect.ratio.horizontal",dpx_source_info.aspect_ratio.horizontal);
4285   AttributeToU32(image_info,image,"DPX:source.aspect.ratio.vertical",dpx_source_info.aspect_ratio.vertical);
4286   AttributeToR32(image_info,image,"DPX:source.scanned.size.x",dpx_source_info.x_scanned_size);
4287   AttributeToR32(image_info,image,"DPX:source.scanned.size.y",dpx_source_info.y_scanned_size);
4288   /*
4289     Motion-picture film information header.
4290   */
4291   (void) memset(&dpx_mp_info,0,sizeof(dpx_mp_info));
4292   AttributeToString(image_info,image,"DPX:mp.film.manufacturer.id",dpx_mp_info.film_mfg_id_code);
4293   AttributeToString(image_info,image,"DPX:mp.film.type",dpx_mp_info.film_type);
4294   AttributeToString(image_info,image,"DPX:mp.perfs.offset",dpx_mp_info.perfs_offset);
4295   AttributeToString(image_info,image,"DPX:mp.prefix",dpx_mp_info.prefix);
4296   AttributeToString(image_info,image,"DPX:mp.count",dpx_mp_info.count);
4297   AttributeToString(image_info,image,"DPX:mp.format",dpx_mp_info.format);
4298   AttributeToU32(image_info,image,"DPX:mp.frame.position",dpx_mp_info.frame_position);
4299   AttributeToU32(image_info,image,"DPX:mp.sequence.length",dpx_mp_info.sequence_length);
4300   AttributeToU32(image_info,image,"DPX:mp.held.count",dpx_mp_info.held_count);
4301   AttributeToR32(image_info,image,"DPX:mp.frame.rate",dpx_mp_info.frame_rate);
4302   AttributeToR32(image_info,image,"DPX:mp.shutter.angle",dpx_mp_info.shutter_angle);
4303   AttributeToString(image_info,image,"DPX:mp.frame.id",dpx_mp_info.frame_id);
4304   AttributeToString(image_info,image,"DPX:mp.slate.info",dpx_mp_info.slate_info);
4305   /*
4306     Television information header.
4307   */
4308   (void) memset(&dpx_tv_info,0,sizeof(dpx_tv_info));
4309   AttributeBitsToU32(image_info,image,"DPX:tv.time.code",dpx_tv_info.time_code);
4310   AttributeBitsToU32(image_info,image,"DPX:tv.user.bits",dpx_tv_info.user_bits);
4311   AttributeToU8(image_info,image,"DPX:tv.interlace",dpx_tv_info.interlace);
4312   AttributeToU8(image_info,image,"DPX:tv.field.number",dpx_tv_info.field_number);
4313   AttributeToU8(image_info,image,"DPX:tv.video.signal",dpx_tv_info.video_signal);
4314   AttributeToR32(image_info,image,"DPX:tv.horizontal.sampling.rate",dpx_tv_info.horizontal_sample);
4315   AttributeToR32(image_info,image,"DPX:tv.temporal.sampling.rate",dpx_tv_info.temporal_sample);
4316   AttributeToR32(image_info,image,"DPX:tv.sync.time",dpx_tv_info.sync_time);
4317   AttributeToR32(image_info,image,"DPX:tv.gamma",dpx_tv_info.gamma);
4318   AttributeToR32(image_info,image,"DPX:tv.black.level",dpx_tv_info.black_level);
4319   AttributeToR32(image_info,image,"DPX:tv.black.gain",dpx_tv_info.black_gain);
4320   AttributeToR32(image_info,image,"DPX:tv.breakpoint",dpx_tv_info.breakpoint);
4321   AttributeToR32(image_info,image,"DPX:tv.white.level",dpx_tv_info.white_level);
4322   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   max_samples_per_pixel=0;
4327   for (element=0; element < dpx_image_info.elements; element++)
4328     {
4329       element_descriptor=(DPXImageElementDescriptor)
4330         dpx_image_info.element_info[element].descriptor;
4331       max_samples_per_pixel=Max(max_samples_per_pixel,
4332                                 DPXSamplesPerPixel(element_descriptor));
4333     }
4334   /*
4335     Allocate row samples.
4336   */
4337   samples=MagickAllocateResourceLimitedArray(sample_t *,image->columns,
4338                               max_samples_per_pixel*sizeof(sample_t));
4339   if (samples == (sample_t *) NULL)
4340     ThrowDPXWriterException(ResourceLimitError,MemoryAllocationFailed,image);
4341   (void) memset((void *) samples,0,max_samples_per_pixel*image->columns*
4342                 sizeof(sample_t));
4343   /*
4344     Allocate row scanline.
4345   */
4346   scanline=MagickAllocateResourceLimitedMemory(unsigned char *,row_octets);
4347   if (scanline == (unsigned char *) NULL)
4348     ThrowDPXWriterException(ResourceLimitError,MemoryAllocationFailed,image);
4349   (void) memset((void *) scanline,0,row_octets);
4350 
4351   /*
4352     Allocate sample translation map storage.
4353   */
4354   map_Y=MagickAllocateResourceLimitedArray(sample_t *,MaxMap+1,sizeof(sample_t));
4355   if (map_Y == (sample_t *) NULL)
4356     ThrowDPXWriterException(ResourceLimitError,MemoryAllocationFailed,image);
4357   (void) memset((void *) map_Y,0,(MaxMap+1)*sizeof(sample_t));
4358 
4359   map_CbCr=MagickAllocateResourceLimitedArray(sample_t *,MaxMap+1,sizeof(sample_t));
4360   if (map_CbCr == (sample_t *) NULL)
4361     ThrowDPXWriterException(ResourceLimitError,MemoryAllocationFailed,image);
4362   (void) memset((void *) map_CbCr,0,(MaxMap+1)*sizeof(sample_t));
4363 
4364   /*
4365     Reserve file/blob length if requested.
4366   */
4367   {
4368     const char
4369       *env;
4370 
4371     if (((env=getenv("MAGICK_RESERVE_STORAGE")) != NULL) &&
4372         (LocaleCompare(env,"TRUE") == 0))
4373       (void) BlobReserveSize(image,dpx_file_info.file_size);
4374   }
4375 
4376   /*
4377     Write file headers.
4378   */
4379   if (swap_endian)
4380     {
4381       /*
4382         Swap byte order.
4383       */
4384       SwabDPXFileInfo(&dpx_file_info);
4385       SwabDPXImageInfo(&dpx_image_info);
4386       SwabDPXImageSourceInfo(&dpx_source_info);
4387       SwabDPXMPFilmInfo(&dpx_mp_info);
4388       SwabDPXTVInfo(&dpx_tv_info);
4389     }
4390   offset += WriteBlob(image,sizeof(dpx_file_info),&dpx_file_info);
4391   offset += WriteBlob(image,sizeof(dpx_image_info),&dpx_image_info);
4392   offset += WriteBlob(image,sizeof(dpx_source_info),&dpx_source_info);
4393   offset += WriteBlob(image,sizeof(dpx_mp_info),&dpx_mp_info);
4394   offset += WriteBlob(image,sizeof(dpx_tv_info),&dpx_tv_info);
4395   if (user_data)
4396     {
4397       offset += WriteBlob(image,(size_t) user_data_length,user_data);
4398     }
4399   if (swap_endian)
4400     {
4401       /*
4402         Swap byte order back to original.
4403       */
4404       SwabDPXFileInfo(&dpx_file_info);
4405       SwabDPXImageInfo(&dpx_image_info);
4406       SwabDPXImageSourceInfo(&dpx_source_info);
4407       SwabDPXMPFilmInfo(&dpx_mp_info);
4408       SwabDPXTVInfo(&dpx_tv_info);
4409     }
4410   /*
4411     Fill to offset.
4412   */
4413   while (offset < dpx_image_info.element_info[0].data_offset)
4414     {
4415       if (WriteBlobByte(image,0U) != 1)
4416         break;
4417       offset += 1;
4418     }
4419   /*
4420     Allow user to over-ride pixel endianness.
4421   */
4422   if ((definition_value=AccessDefinition(image_info,"dpx","pixel-endian")))
4423     {
4424       if (LocaleCompare(definition_value,"msb") == 0)
4425         endian_type=MSBEndian;
4426       else if (LocaleCompare(definition_value,"lsb") == 0)
4427         endian_type=LSBEndian;
4428     }
4429   /*
4430     Write out elements.
4431   */
4432   for (element=0; element < dpx_image_info.elements; element++)
4433     {
4434       MagickBool
4435         swap_word_datums = MagickFalse;
4436 
4437 
4438       /*
4439         Validate that what we are writing matches the header offsets.
4440       */
4441       {
4442         magick_off_t
4443           reported_file_offset;
4444 
4445         if (((reported_file_offset = TellBlob(image)) != -1) &&
4446             ((magick_off_t) dpx_image_info.element_info[element].data_offset !=
4447              reported_file_offset))
4448           {
4449             (void) fprintf(stderr,"### Descriptor %u offset %u, TellBlob says %" MAGICK_OFF_F "d\n",
4450                            element+1, dpx_image_info.element_info[element].data_offset,
4451                            reported_file_offset);
4452           }
4453       }
4454       if (image->logging)
4455         DescribeDPXImageElement(&dpx_image_info.element_info[element],element+1);
4456 
4457       bits_per_sample=dpx_image_info.element_info[element].bits_per_sample;
4458       transfer_characteristic=(DPXTransferCharacteristic)
4459         dpx_image_info.element_info[element].transfer_characteristic;
4460 
4461       {
4462         double
4463           max_value,
4464           reference_low,
4465           reference_high,
4466           scale_from_maxmap;           /* multiplier to scale from MaxMap */
4467 
4468         max_value = (double) MaxValueGivenBits(bits_per_sample);
4469         reference_low = 0.0;
4470         reference_high = max_value;
4471         scale_from_maxmap=max_value/((double) MaxMap);
4472 
4473         if ((transfer_characteristic == TransferCharacteristicITU_R709) ||
4474             (transfer_characteristic == TransferCharacteristicITU_R601_625L) ||
4475             (transfer_characteristic == TransferCharacteristicITU_R601_525L))
4476           {
4477             double
4478               ScaleY = 0.0,
4479               ScaleCbCr = 0.0;
4480 
4481             reference_low = ((MaxRGBDouble+1.0)*(64.0/1024.0));
4482             reference_high = ((MaxRGBDouble+1.0)*(940.0/1024.0));
4483             ScaleY = (reference_high-reference_low)/(MaxRGBDouble+1.0);
4484             ScaleCbCr = ScaleY*((960.0-64.0)/(940.0-64.0));
4485 
4486             for (i=0; i <= MaxMap ; i++)
4487               {
4488                 map_Y[i]=(i*ScaleY+reference_low)*scale_from_maxmap+0.5;
4489                 map_CbCr[i]=(i*ScaleCbCr+reference_low)*scale_from_maxmap+0.5;
4490               }
4491           }
4492         else
4493           {
4494             for (i=0; i <= MaxMap ; i++)
4495               map_Y[i]=i*scale_from_maxmap+0.5;
4496           }
4497       }
4498 
4499       element_descriptor=(DPXImageElementDescriptor)
4500         dpx_image_info.element_info[element].descriptor;
4501 
4502       /*
4503         Determine component packing method.
4504       */
4505       packing_method=(ImageComponentPackingMethod) dpx_image_info.element_info[element].packing;
4506       samples_per_pixel=DPXSamplesPerPixel(element_descriptor);
4507       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       if ((element_descriptor == ImageElementRGB) ||
4519           (element_descriptor == ImageElementRGBA) ||
4520           (element_descriptor == ImageElementABGR) ||
4521           (element_descriptor == ImageElementCbYCrY422) ||
4522           (element_descriptor == ImageElementCbYACrYA4224) ||
4523           (element_descriptor == ImageElementCbYCr444) ||
4524           (element_descriptor == ImageElementCbYCrA4444))
4525         {
4526           if ((bits_per_sample == 10) && (packing_method != PackingMethodPacked))
4527             swap_word_datums = MagickTrue;
4528         }
4529       if ((definition_value=AccessDefinition(image_info,"dpx","swap-samples")) ||
4530           (definition_value=AccessDefinition(image_info,"dpx","swap-samples-write")))
4531         {
4532           if (LocaleCompare(definition_value,"false") != 0)
4533             swap_word_datums = swap_word_datums ? MagickFalse : MagickTrue;
4534         }
4535       /*
4536         Create a chroma image if we are subsampling YCbCr.
4537       */
4538       if (((element_descriptor == ImageElementCbYCrY422) ||
4539            (element_descriptor == ImageElementCbYACrYA4224) ||
4540            (element_descriptor == ImageElementColorDifferenceCbCr)) &&
4541           (chroma_image == (Image *) NULL))
4542         {
4543           chroma_image=ResizeImage(image,image->columns/2,image->rows,
4544                                    LanczosFilter,1.0,&image->exception);
4545           if (chroma_image == (Image *) NULL)
4546             ThrowDPXWriterException(ResourceLimitError,MemoryAllocationFailed,image);
4547         }
4548 
4549       for (y=0; y < image->rows; y++)
4550         {
4551           p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
4552           if (p == (const PixelPacket *) NULL)
4553             break;
4554 
4555           samples_itr=samples;
4556           /*
4557             Prepare row samples.
4558           */
4559           switch (element_descriptor)
4560             {
4561             case ImageElementRed:
4562               for (x=image->columns; x != 0; x--)
4563                 {
4564                   *samples_itr++=map_Y[ScaleQuantumToMap(GetRedSample(p))];
4565                   p++;
4566                 }
4567               break;
4568             case ImageElementGreen:
4569               for (x=image->columns; x != 0; x--)
4570                 {
4571                   *samples_itr++=map_Y[ScaleQuantumToMap(GetGreenSample(p))];
4572                   p++;
4573                 }
4574               break;
4575             case ImageElementBlue:
4576               for (x=image->columns; x != 0; x--)
4577                 {
4578                   *samples_itr++=map_Y[ScaleQuantumToMap(GetBlueSample(p))];
4579                   p++;
4580                 }
4581               break;
4582             case ImageElementAlpha:
4583               {
4584                 for (x=image->columns; x != 0; x--)
4585                   {
4586                     *samples_itr++=map_Y[ScaleQuantumToMap(GetOpacitySample(p))];
4587                     p++;
4588                   }
4589                 break;
4590               }
4591             case ImageElementUnspecified:
4592             case ImageElementLuma:
4593               {
4594                 if ((transfer_characteristic == TransferCharacteristicITU_R709) ||
4595                     (transfer_characteristic == TransferCharacteristicITU_R601_625L) ||
4596                     (transfer_characteristic == TransferCharacteristicITU_R601_525L))
4597                   {
4598                     /* Video luma */
4599                     for (x=image->columns; x != 0; x--)
4600                       {
4601                         *samples_itr++=map_Y[ScaleQuantumToMap(GetYSample(p))];
4602                         p++;
4603                       }
4604                   }
4605                 else
4606                   {
4607                     /* Linear gray */
4608                     for (x=image->columns; x != 0; x--)
4609                       {
4610                         *samples_itr++=map_Y[ScaleQuantumToMap(GetGraySample(p))];
4611                         p++;
4612                       }
4613                   }
4614                 break;
4615               }
4616             case ImageElementColorDifferenceCbCr:
4617               {
4618                 /* CbCr */
4619                 const PixelPacket
4620                   *chroma_pixels;
4621 
4622                 chroma_pixels=AcquireImagePixels(chroma_image,0,y,chroma_image->columns,1,
4623                                                  &image->exception);
4624                 if (chroma_pixels == (const PixelPacket *) NULL)
4625                   break;
4626 
4627                 for (x=image->columns; x != 0; x -= 2)
4628                   {
4629                     *samples_itr++=map_CbCr[ScaleQuantumToMap(GetCbSample(chroma_pixels))]; /* Cb */
4630                     *samples_itr++=map_CbCr[ScaleQuantumToMap(GetCrSample(chroma_pixels))]; /* Cr */
4631                     chroma_pixels++;
4632                   }
4633                 break;
4634               }
4635             case ImageElementRGB:
4636               for (x=image->columns; x != 0; x--)
4637                 {
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                   *samples_itr++=map_Y[ScaleQuantumToMap(GetRedSample(p))];
4645                   *samples_itr++=map_Y[ScaleQuantumToMap(GetGreenSample(p))];
4646                   *samples_itr++=map_Y[ScaleQuantumToMap(GetBlueSample(p))];
4647 #endif
4648                   p++;
4649                 }
4650               break;
4651             case ImageElementRGBA:
4652               for (x=image->columns; x != 0; x--)
4653                 {
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                   *samples_itr++=map_Y[ScaleQuantumToMap(GetRedSample(p))];
4661                   *samples_itr++=map_Y[ScaleQuantumToMap(GetGreenSample(p))];
4662                   *samples_itr++=map_Y[ScaleQuantumToMap(GetBlueSample(p))];
4663 #endif
4664                   *samples_itr++=map_Y[ScaleQuantumToMap(GetOpacitySample(p))];
4665                   p++;
4666                 }
4667               break;
4668             case ImageElementCbYCrY422:
4669               {
4670                 /* CbY | CrY | CbY | CrY ..., even number of columns required. */
4671                 const PixelPacket
4672                   *chroma_pixels;
4673 
4674                 chroma_pixels=AcquireImagePixels(chroma_image,0,y,chroma_image->columns,1,
4675                                                  &image->exception);
4676                 if (chroma_pixels == (const PixelPacket *) NULL)
4677                   break;
4678 
4679                 for (x=image->columns; x != 0; x -= 2)
4680                   {
4681                     *samples_itr++=map_CbCr[ScaleQuantumToMap(GetCbSample(chroma_pixels))]; /* Cb */
4682                     *samples_itr++=map_Y[ScaleQuantumToMap(GetYSample(p))];                 /* Y */
4683                     p++;
4684                     *samples_itr++=map_CbCr[ScaleQuantumToMap(GetCrSample(chroma_pixels))]; /* Cr */
4685                     *samples_itr++=map_Y[ScaleQuantumToMap(GetYSample(p))];                 /* Y */
4686                     p++;
4687                     chroma_pixels++;
4688                   }
4689                 break;
4690               }
4691             case ImageElementCbYACrYA4224:
4692               {
4693                 /* CbYA | CrYA | CbYA | CrYA ..., even number of columns required. */
4694                 const PixelPacket
4695                   *chroma_pixels;
4696 
4697                 chroma_pixels=AcquireImagePixels(chroma_image,0,y,chroma_image->columns,1,
4698                                                  &image->exception);
4699                 if (chroma_pixels == (const PixelPacket *) NULL)
4700                   break;
4701 
4702                 for (x=image->columns; x != 0; x -= 2)
4703                   {
4704                     *samples_itr++=map_CbCr[ScaleQuantumToMap(GetCbSample(chroma_pixels))]; /* Cb */
4705                     *samples_itr++=map_Y[ScaleQuantumToMap(GetYSample(p))];                 /* Y */
4706                     *samples_itr++=map_Y[ScaleQuantumToMap(GetOpacitySample(p))];           /* A */
4707                     p++;
4708                     *samples_itr++=map_CbCr[ScaleQuantumToMap(GetCrSample(chroma_pixels))]; /* Cr */
4709                     *samples_itr++=map_Y[ScaleQuantumToMap(GetYSample(p))];                 /* Y */
4710                     *samples_itr++=map_Y[ScaleQuantumToMap(GetOpacitySample(p))];           /* A */
4711                     p++;
4712                     chroma_pixels++;
4713                   }
4714                 break;
4715               }
4716             case ImageElementCbYCr444:
4717               for (x=image->columns; x != 0; x--)
4718                 {
4719                   *samples_itr++=map_CbCr[ScaleQuantumToMap(GetCbSample(p))]; /* Cb */
4720                   *samples_itr++=map_Y[ScaleQuantumToMap(GetYSample(p))];     /* Y */
4721                   *samples_itr++=map_CbCr[ScaleQuantumToMap(GetCrSample(p))]; /* Cr */
4722                   p++;
4723                 }
4724               break;
4725             case ImageElementCbYCrA4444:
4726               for (x=image->columns; x != 0; x--)
4727                 {
4728                   *samples_itr++=map_CbCr[ScaleQuantumToMap(GetCbSample(p))];   /* Cb */
4729                   *samples_itr++=map_Y[ScaleQuantumToMap(GetYSample(p))];       /* Y */
4730                   *samples_itr++=map_CbCr[ScaleQuantumToMap(GetCrSample(p))];   /* Cr */
4731                   *samples_itr++=map_Y[ScaleQuantumToMap(GetOpacitySample(p))]; /* A */
4732                   p++;
4733                 }
4734               break;
4735 
4736             default:
4737               break;
4738             }
4739 
4740           /*
4741             FIXME: RLE samples.
4742           */
4743 
4744           /*
4745             Output samples.
4746           */
4747           WriteRowSamples(samples, samples_per_row, bits_per_sample,
4748                           packing_method,endian_type,swap_word_datums,scanline);
4749           if (WriteBlob(image,row_octets,(void *) scanline) != row_octets)
4750             {
4751               status=MagickFail;
4752               break;
4753             }
4754           if (image->previous == (Image *) NULL)
4755             if (QuantumTick(y,image->rows))
4756               if (!MagickMonitorFormatted(y,image->rows,&image->exception,
4757                                           SaveImageText,image->filename,
4758                                           image->columns,image->rows))
4759                 break;
4760         }
4761     }
4762 
4763   /*
4764     Validate that what we are writing matches the header offsets.
4765   */
4766   {
4767     magick_off_t
4768       reported_file_offset;
4769 
4770     reported_file_offset = TellBlob(image);
4771     if ((reported_file_offset != -1) &&
4772         ((magick_off_t) dpx_file_info.file_size != reported_file_offset))
4773       {
4774         (void) fprintf(stderr,"### File length %u, TellBlob says %" MAGICK_OFF_F "d\n",
4775                        dpx_file_info.file_size,
4776                        reported_file_offset);
4777       }
4778   }
4779 
4780   MagickFreeResourceLimitedMemory(map_CbCr);
4781   MagickFreeResourceLimitedMemory(map_Y);
4782   MagickFreeResourceLimitedMemory(samples);
4783   MagickFreeResourceLimitedMemory(scanline);
4784   CloseBlob(image);
4785   if (chroma_image != (Image *) NULL)
4786     {
4787       DestroyImage(chroma_image);
4788       chroma_image = (Image *) NULL;
4789     }
4790   return(status);
4791 }
4792