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