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(¤t_time, &tm_buf);
3165 #else
3166 t=localtime(¤t_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