/src/graphicsmagick/coders/cineon.c
Line | Count | Source |
1 | | /* |
2 | | % Copyright (C) 2003-2026 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 | | % CCCC IIIII N N EEEEE OOO N N % |
13 | | % C I NN N E O O NN N % |
14 | | % C I N N N EEEE O O N N N % |
15 | | % C I N NN E O O N NN % |
16 | | % CCCC IIIII N N EEEEE OOO N N % |
17 | | % % |
18 | | % % |
19 | | % Read/Write Kodak Cineon Image Format. % |
20 | | % Cineon Image Format is similar to SMTPE DPX % |
21 | | % % |
22 | | % % |
23 | | % Software Design % |
24 | | % Bob Friesenhahn % |
25 | | % May 2007 % |
26 | | % % |
27 | | % % |
28 | | % % |
29 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
30 | | % |
31 | | % Cineon image file format draft is available at |
32 | | % http://www.cineon.com/ff_draft.php. |
33 | | % |
34 | | % |
35 | | */ |
36 | | |
37 | | /* |
38 | | Include declarations. |
39 | | */ |
40 | | #include "magick/studio.h" |
41 | | #include "magick/attribute.h" |
42 | | #include "magick/blob.h" |
43 | | #include "magick/bit_stream.h" |
44 | | #include "magick/colorspace.h" |
45 | | #include "magick/enum_strings.h" |
46 | | #include "magick/pixel_cache.h" |
47 | | #include "magick/magick_endian.h" |
48 | | #include "magick/error.h" |
49 | | #include "magick/list.h" |
50 | | #include "magick/log.h" |
51 | | #include "magick/magick.h" |
52 | | #include "magick/monitor.h" |
53 | | #include "magick/profile.h" |
54 | | #include "magick/utility.h" |
55 | | #include "magick/static.h" |
56 | | |
57 | | /* |
58 | | Forward declaractions. |
59 | | */ |
60 | | static unsigned int |
61 | | WriteCINEONImage(const ImageInfo *,Image *); |
62 | | |
63 | | typedef char ASCII; |
64 | | typedef magick_uint8_t U8; |
65 | | typedef magick_uint32_t U32; |
66 | | typedef magick_int32_t S32; |
67 | | typedef union _R32_u |
68 | | { |
69 | | magick_uint32_t u; |
70 | | float f; |
71 | | } R32; |
72 | | |
73 | 789 | #define SET_UNDEFINED_U8(value) (value=0xFFU) |
74 | 783 | #define SET_UNDEFINED_U32(value) (value=0xFFFFFFFFU) |
75 | 9 | #define SET_UNDEFINED_S32(value) (value=0x80000000) |
76 | | |
77 | 277 | #define SET_UNDEFINED_R32(value) (value.u=0x7F800000U); |
78 | 3.68k | #define SET_UNDEFINED_ASCII(value) ((void) memset(value,0,sizeof(value))) |
79 | | |
80 | 29.0k | #define IS_UNDEFINED_U8(value) (value == ((U8) 0xFFU)) |
81 | 11.7k | #define IS_UNDEFINED_U32(value) (value == ((U32) 0xFFFFFFFFU)) |
82 | 32.3k | #define IS_UNDEFINED_S32(value) (value == ((S32) 0x80000000)) |
83 | 191k | #define IS_UNDEFINED_R32(value) (value.u == ((U32) 0x7F800000U)) |
84 | 227k | #define IS_UNDEFINED_ASCII(value) (!(value[0] > 0)) |
85 | | |
86 | | typedef struct _CineonFileInfo |
87 | | { |
88 | | U32 magic; /* Magick number (0x802A5FD7) */ |
89 | | U32 image_data_offset; /* Offset to image data in bytes */ |
90 | | U32 generic_section_length; /* Generic section header length in bytes */ |
91 | | U32 industry_section_length; /* Industry specific header length in bytes */ |
92 | | U32 user_defined_length; /* User defined header length in bytes */ |
93 | | U32 file_size; /* Total image file size in bytes */ |
94 | | ASCII header_format_version[8]; /* Version number of header format */ |
95 | | ASCII image_filename[100]; /* Image filename */ |
96 | | ASCII creation_date[12]; /* Creation date: yyyy:mm:dd */ |
97 | | ASCII creation_time[12]; /* Creation time: hh:mm:ssLTZ */ |
98 | | ASCII reserved[36]; /* Reserved for future use */ |
99 | | } CineonFileInfo; |
100 | | |
101 | | typedef struct _CineonImageChannel |
102 | | { |
103 | | U8 designator_byte_0; /* 0 = universal metric */ |
104 | | U8 designator_byte_1; /* */ |
105 | | U8 bits_per_sample; /* Bit depth */ |
106 | | U8 unused; |
107 | | U32 pixels_per_line; /* Pixels per line (columns) */ |
108 | | U32 lines_per_image; /* Lines per image (rows) */ |
109 | | R32 reference_low_data_code; /* Reference low data code value */ |
110 | | R32 reference_low_quantity; /* Low quantity represented */ |
111 | | R32 reference_high_data_code; /* Reference high data code value */ |
112 | | R32 reference_high_quantity; /* Reference high quantity represented */ |
113 | | } DPXImageChannel; |
114 | | |
115 | | typedef struct _CineonImageInfo |
116 | | { |
117 | | U8 orientation; /* Image orientation */ |
118 | | U8 channels; /* Number of image channels (1-8) */ |
119 | | U8 pad[2]; /* Unused (2 byte space for word alignment */ |
120 | | DPXImageChannel channel_info[8]; /* Description of channels */ |
121 | | R32 white_point[2]; /* White point (color temperature) - x,y pair */ |
122 | | R32 red_primary_chromaticity[2]; /* Red primary chromaticity - x,y pair */ |
123 | | R32 green_primary_chromaticity[2]; /* Green primary chromaticity - x,y pair */ |
124 | | R32 blue_primary_chromaticity[2]; /* Blue primary chromaticity - x,y pair */ |
125 | | ASCII label_text[200]; /* Label text */ |
126 | | ASCII reserved[28]; /* Reserved for future use */ |
127 | | /* Image Data Format Information */ |
128 | | U8 data_interleave; /* Data interleave */ |
129 | | U8 packing; /* Packing method */ |
130 | | U8 sign; /* Data sign: 0=unsigned, 1=signed */ |
131 | | U8 sense; /* Image sense: 0=positive, 1=negative */ |
132 | | U32 eol_pad; /* End of line padding */ |
133 | | U32 eoc_pad; /* End of channel padding */ |
134 | | ASCII reserved2[20]; /* Reserved for future use */ |
135 | | } CineonImageInfo; |
136 | | |
137 | | typedef struct _CineonImageOriginationInfo |
138 | | { |
139 | | S32 x_offset; /* X offset */ |
140 | | S32 y_offset; /* Y offset */ |
141 | | ASCII source_image_filename[100];/* Source image filename */ |
142 | | ASCII creation_date[12]; /* Creation date: yyyy:mm:dd */ |
143 | | ASCII creation_time[12]; /* Creation time: hh:mm:ssLTZ */ |
144 | | ASCII input_device[64]; /* Input device */ |
145 | | ASCII input_device_model[32]; /* Input device model number */ |
146 | | ASCII input_device_serial[32]; /* Input device serial number */ |
147 | | R32 input_device_pitch_x; /* Input device pitch for X (samples/mm) */ |
148 | | R32 input_device_pitch_y; /* Input device pitch for Y (samples/mm) */ |
149 | | R32 gamma; /* Image gamma of capture device */ |
150 | | ASCII reserved[40]; /* Reserved for future use */ |
151 | | } CineonImageOriginationInfo; |
152 | | |
153 | | typedef struct _CineonFilmInfo |
154 | | { |
155 | | U8 film_mfg_id_code; /* Film mfg. ID code (2 digits from film edge code) */ |
156 | | U8 film_type; /* Film type (2 digits from film edge code) */ |
157 | | U8 perfs_offset; /* Offset in perfs (2 digits from film edge code) */ |
158 | | U8 unused; /* Unused, for word alignment */ |
159 | | U32 prefix; /* Prefix (6 digits from film edge code) */ |
160 | | U32 count; /* Count (4 digits from film edge code) */ |
161 | | ASCII format[32]; /* Format -- e.g. Academy */ |
162 | | U32 frame_position; /* Frame position in sequence */ |
163 | | R32 frame_rate; /* Frame rate of original (frames/s) */ |
164 | | ASCII frame_id[32]; /* Frame identification - e.g. keyframe */ |
165 | | ASCII slate_info[200]; /* Slate information */ |
166 | | ASCII reserved[740]; /* Reserved for future use */ |
167 | | } CineonFilmInfo; |
168 | | |
169 | | |
170 | | /* |
171 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
172 | | % % |
173 | | % % |
174 | | % % |
175 | | % I s C I N E O N % |
176 | | % % |
177 | | % % |
178 | | % % |
179 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
180 | | % |
181 | | % IsCINEON() returns True if the image format type, identified by the magick |
182 | | % string, is CINEON. |
183 | | % |
184 | | % The format of the IsCINEON method is: |
185 | | % |
186 | | % unsigned int IsCINEON(const unsigned char *magick,const size_t length) |
187 | | % |
188 | | % A description of each parameter follows: |
189 | | % |
190 | | % o magick: This string is generally the first few bytes of an image file |
191 | | % or blob. |
192 | | % |
193 | | % o length: Specifies the length of the magick string. |
194 | | % |
195 | | % |
196 | | */ |
197 | | static unsigned int IsCINEON(const unsigned char *magick,const size_t length) |
198 | 0 | { |
199 | 0 | if (length < 4) |
200 | 0 | return(False); |
201 | 0 | if (memcmp(magick,"\200\052\137\327",4) == 0) |
202 | 0 | return(True); |
203 | 0 | return(False); |
204 | 0 | } |
205 | | |
206 | | /* |
207 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
208 | | % % |
209 | | % % |
210 | | % % |
211 | | % R e a d C I N E O N I m a g e % |
212 | | % % |
213 | | % % |
214 | | % % |
215 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
216 | | % |
217 | | % ReadCINEONImage() reads an CINEON X image file and returns it. It allocates |
218 | | % the memory necessary for the new Image structure and returns a point to the |
219 | | % new image. |
220 | | % |
221 | | % The format of the ReadCINEONImage method is: |
222 | | % |
223 | | % Image *ReadCINEONImage(const ImageInfo *image_info, |
224 | | % ExceptionInfo *exception) |
225 | | % |
226 | | % A description of each parameter follows: |
227 | | % |
228 | | % o image_info: The image info. |
229 | | % |
230 | | % o exception: return any errors or warnings in this structure. |
231 | | % |
232 | | % |
233 | | */ |
234 | 218k | #define LogSetImageAttribute(name,value) \ |
235 | 218k | { \ |
236 | 218k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), \ |
237 | 218k | "Attribute \"%s\" set to \"%s\"", \ |
238 | 218k | name,value); \ |
239 | 218k | } |
240 | | /* |
241 | | Null terminate ASCII fields which provide space for a terminating |
242 | | NULL. |
243 | | */ |
244 | 325k | #define NULLTerminateASCIIField(field) \ |
245 | 325k | { \ |
246 | 325k | field[sizeof(field)-1]='\0'; \ |
247 | 325k | } |
248 | | /* |
249 | | Can't use strlcpy() since strlcpy() only handles NULL terminated |
250 | | strings. This is not so necessary due to use of |
251 | | NULLTerminateASCIIField() above. |
252 | | */ |
253 | 226k | #define StringToAttribute(image,name,member) \ |
254 | 226k | { \ |
255 | 226k | char \ |
256 | 226k | buffer_[MaxTextExtent]; \ |
257 | 226k | \ |
258 | 226k | if (!IS_UNDEFINED_ASCII(member)) \ |
259 | 226k | { \ |
260 | 99.5k | (void) memcpy(buffer_,member,Min(sizeof(member),MaxTextExtent)); \ |
261 | 99.5k | buffer_[Min(sizeof(member),MaxTextExtent-1)]='\0'; \ |
262 | 99.5k | (void) SetImageAttribute(image,name,buffer_); \ |
263 | 99.5k | LogSetImageAttribute(name,buffer_); \ |
264 | 99.5k | } \ |
265 | 226k | } |
266 | 29.0k | #define U8ToAttribute(image,name,member) \ |
267 | 29.0k | { \ |
268 | 29.0k | char \ |
269 | 29.0k | buffer[MaxTextExtent]; \ |
270 | 29.0k | \ |
271 | 29.0k | if (!IS_UNDEFINED_U8(member)) \ |
272 | 29.0k | { \ |
273 | 24.0k | MagickFormatString(buffer,sizeof(buffer),"%u",(unsigned int) member); \ |
274 | 24.0k | (void) SetImageAttribute(image,name,buffer); \ |
275 | 24.0k | LogSetImageAttribute(name,buffer); \ |
276 | 24.0k | } \ |
277 | 29.0k | } |
278 | 11.7k | #define U32ToAttribute(image,name,member) \ |
279 | 11.7k | { \ |
280 | 11.7k | char \ |
281 | 11.7k | buffer[MaxTextExtent]; \ |
282 | 11.7k | \ |
283 | 11.7k | if (!IS_UNDEFINED_U32(member)) \ |
284 | 11.7k | { \ |
285 | 10.4k | MagickFormatString(buffer,sizeof(buffer),"%u",member); \ |
286 | 10.4k | (void) SetImageAttribute(image,name,buffer); \ |
287 | 10.4k | LogSetImageAttribute(name,buffer); \ |
288 | 10.4k | } \ |
289 | 11.7k | } |
290 | 52.4k | #define R32ToAttribute(image,name,member) \ |
291 | 52.4k | { \ |
292 | 52.4k | char \ |
293 | 52.4k | buffer[MaxTextExtent]; \ |
294 | 52.4k | \ |
295 | 52.4k | if (!IS_UNDEFINED_R32(member)) \ |
296 | 52.4k | { \ |
297 | 52.3k | MagickFormatString(buffer,sizeof(buffer),"%g",member.f); \ |
298 | 52.3k | (void) SetImageAttribute(image,name,buffer); \ |
299 | 52.3k | LogSetImageAttribute(name,buffer); \ |
300 | 52.3k | } \ |
301 | 52.4k | } |
302 | 32.3k | #define S32ToAttribute(image,name,member) \ |
303 | 32.3k | { \ |
304 | 32.3k | char \ |
305 | 32.3k | buffer[MaxTextExtent]; \ |
306 | 32.3k | \ |
307 | 32.3k | if (!IS_UNDEFINED_S32(member)) \ |
308 | 32.3k | { \ |
309 | 32.0k | MagickFormatString(buffer,sizeof(buffer),"%d",member); \ |
310 | 32.0k | (void) SetImageAttribute(image,name,buffer); \ |
311 | 32.0k | LogSetImageAttribute(name,buffer); \ |
312 | 32.0k | } \ |
313 | 32.3k | } |
314 | | static void SwabCineonFileInfo(CineonFileInfo *file_info) |
315 | 32.8k | { |
316 | 32.8k | MagickSwabUInt32(&file_info->magic); |
317 | 32.8k | MagickSwabUInt32(&file_info->image_data_offset); |
318 | 32.8k | MagickSwabUInt32(&file_info->generic_section_length); |
319 | 32.8k | MagickSwabUInt32(&file_info->industry_section_length); |
320 | 32.8k | MagickSwabUInt32(&file_info->user_defined_length); |
321 | 32.8k | MagickSwabUInt32(&file_info->file_size); |
322 | 32.8k | } |
323 | | |
324 | | static void SwabCineonImageInfo(CineonImageInfo *image_info) |
325 | 17.9k | { |
326 | 17.9k | size_t |
327 | 17.9k | i; |
328 | | |
329 | 17.9k | for (i=0 ; |
330 | 48.7k | i < Min((size_t) image_info->channels, |
331 | 17.9k | (sizeof(image_info->channel_info) / |
332 | 17.9k | sizeof(image_info->channel_info[0]))); |
333 | 30.7k | i++) |
334 | 30.7k | { |
335 | 30.7k | MagickSwabUInt32(&image_info->channel_info[i].pixels_per_line); |
336 | 30.7k | MagickSwabUInt32(&image_info->channel_info[i].lines_per_image); |
337 | 30.7k | MagickSwabFloat(&image_info->channel_info[i].reference_low_data_code.f); |
338 | 30.7k | MagickSwabFloat(&image_info->channel_info[i].reference_low_quantity.f); |
339 | 30.7k | MagickSwabFloat(&image_info->channel_info[i].reference_high_data_code.f); |
340 | 30.7k | MagickSwabFloat(&image_info->channel_info[i].reference_high_quantity.f); |
341 | 30.7k | } |
342 | | |
343 | 17.9k | MagickSwabFloat(&image_info->white_point[0].f); |
344 | 17.9k | MagickSwabFloat(&image_info->white_point[1].f); |
345 | 17.9k | MagickSwabFloat(&image_info->red_primary_chromaticity[0].f); |
346 | 17.9k | MagickSwabFloat(&image_info->red_primary_chromaticity[1].f); |
347 | 17.9k | MagickSwabFloat(&image_info->green_primary_chromaticity[0].f); |
348 | 17.9k | MagickSwabFloat(&image_info->green_primary_chromaticity[1].f); |
349 | 17.9k | MagickSwabFloat(&image_info->blue_primary_chromaticity[0].f); |
350 | 17.9k | MagickSwabFloat(&image_info->blue_primary_chromaticity[1].f); |
351 | 17.9k | MagickSwabUInt32(&image_info->eol_pad); |
352 | 17.9k | MagickSwabUInt32(&image_info->eoc_pad); |
353 | 17.9k | } |
354 | | |
355 | | static void SwabCineonImageOriginationInfo(CineonImageOriginationInfo *image_info) |
356 | 16.8k | { |
357 | 16.8k | MagickSwabUInt32((U32 *) &image_info->x_offset); |
358 | 16.8k | MagickSwabUInt32((U32 *) &image_info->y_offset); |
359 | 16.8k | MagickSwabFloat(&image_info->input_device_pitch_x.f); |
360 | 16.8k | MagickSwabFloat(&image_info->input_device_pitch_y.f); |
361 | 16.8k | MagickSwabFloat(&image_info->gamma.f); |
362 | 16.8k | } |
363 | | |
364 | | static void SwabCineonFilmInfo(CineonFilmInfo *mp_info) |
365 | 4.59k | { |
366 | 4.59k | MagickSwabUInt32(&mp_info->prefix); |
367 | 4.59k | MagickSwabUInt32(&mp_info->count); |
368 | 4.59k | MagickSwabUInt32(&mp_info->frame_position); |
369 | 4.59k | MagickSwabFloat(&mp_info->frame_rate.f); |
370 | 4.59k | } |
371 | | |
372 | | static OrientationType |
373 | | CineonOrientationToOrientationType(const unsigned int orientation) |
374 | 17.3k | { |
375 | 17.3k | OrientationType |
376 | 17.3k | orientation_type = UndefinedOrientation; |
377 | | |
378 | 17.3k | switch (orientation) |
379 | 17.3k | { |
380 | 9.30k | case 0: |
381 | 9.30k | orientation_type=TopLeftOrientation; |
382 | 9.30k | break; |
383 | 370 | case 1: |
384 | 370 | orientation_type=TopRightOrientation; |
385 | 370 | break; |
386 | 20 | case 2: |
387 | 20 | orientation_type=BottomLeftOrientation; |
388 | 20 | break; |
389 | 49 | case 3: |
390 | 49 | orientation_type=BottomRightOrientation; |
391 | 49 | break; |
392 | 1.44k | case 4: |
393 | 1.44k | orientation_type=LeftTopOrientation; |
394 | 1.44k | break; |
395 | 30 | case 5: |
396 | 30 | orientation_type=RightTopOrientation; |
397 | 30 | break; |
398 | 242 | case 6: |
399 | 242 | orientation_type=LeftBottomOrientation; |
400 | 242 | break; |
401 | 332 | case 7: |
402 | 332 | orientation_type=RightBottomOrientation; |
403 | 332 | break; |
404 | 17.3k | } |
405 | | |
406 | 17.3k | return orientation_type; |
407 | 17.3k | } |
408 | | |
409 | | static U8 OrientationTypeToCineonOrientation(const OrientationType orientation_type) |
410 | 335 | { |
411 | 335 | U8 |
412 | 335 | orientation = 0U; |
413 | | |
414 | 335 | switch (orientation_type) |
415 | 335 | { |
416 | 77 | case UndefinedOrientation: |
417 | 209 | case TopLeftOrientation: |
418 | 209 | orientation=0U; |
419 | 209 | break; |
420 | 81 | case TopRightOrientation: |
421 | 81 | orientation=1U; |
422 | 81 | break; |
423 | 3 | case BottomLeftOrientation: |
424 | 3 | orientation=2U; |
425 | 3 | break; |
426 | 10 | case BottomRightOrientation: |
427 | 10 | orientation=3U; |
428 | 10 | break; |
429 | 13 | case LeftTopOrientation: |
430 | 13 | orientation=4U; |
431 | 13 | break; |
432 | 3 | case RightTopOrientation: |
433 | 3 | orientation=5U; |
434 | 3 | break; |
435 | 12 | case LeftBottomOrientation: |
436 | 12 | orientation=6U; |
437 | 12 | break; |
438 | 4 | case RightBottomOrientation: |
439 | 4 | orientation=7U; |
440 | 4 | break; |
441 | 335 | } |
442 | 335 | return orientation; |
443 | 335 | } |
444 | | |
445 | | static Image *ReadCINEONImage(const ImageInfo *image_info, |
446 | | ExceptionInfo *exception) |
447 | 37.2k | { |
448 | 37.2k | CineonFileInfo |
449 | 37.2k | cin_file_info; |
450 | | |
451 | 37.2k | CineonImageInfo |
452 | 37.2k | cin_image_info; |
453 | | |
454 | 37.2k | CineonImageOriginationInfo |
455 | 37.2k | cin_source_info; |
456 | | |
457 | 37.2k | CineonFilmInfo |
458 | 37.2k | cin_mp_info; |
459 | | |
460 | 37.2k | Image |
461 | 37.2k | *image; |
462 | | |
463 | 37.2k | unsigned long |
464 | 37.2k | y; |
465 | | |
466 | 37.2k | register unsigned long |
467 | 37.2k | x; |
468 | | |
469 | 37.2k | register PixelPacket |
470 | 37.2k | *q; |
471 | | |
472 | 37.2k | register long |
473 | 37.2k | i; |
474 | | |
475 | 37.2k | size_t |
476 | 37.2k | offset; |
477 | | |
478 | 37.2k | unsigned int |
479 | 37.2k | channel, |
480 | 37.2k | max_bits_per_sample, |
481 | 37.2k | max_lines_per_image, |
482 | 37.2k | max_pixels_per_line, |
483 | 37.2k | number_of_channels; |
484 | | |
485 | 37.2k | MagickPassFail |
486 | 37.2k | status; |
487 | | |
488 | 37.2k | MagickBool |
489 | 37.2k | swab=MagickFalse; |
490 | | |
491 | 37.2k | unsigned long |
492 | 37.2k | pixels_offset; |
493 | | |
494 | 37.2k | unsigned char |
495 | 37.2k | *scandata; |
496 | | |
497 | 37.2k | void |
498 | 37.2k | *scanline; |
499 | | |
500 | 37.2k | const char * |
501 | 37.2k | definition_value; |
502 | | |
503 | 37.2k | BitStreamReadHandle |
504 | 37.2k | bit_stream; |
505 | | |
506 | | /* |
507 | | Open image file. |
508 | | */ |
509 | 37.2k | assert(image_info != (const ImageInfo *) NULL); |
510 | 37.2k | assert(image_info->signature == MagickSignature); |
511 | 37.2k | assert(exception != (ExceptionInfo *) NULL); |
512 | 37.2k | assert(exception->signature == MagickSignature); |
513 | 37.2k | #if !defined(WORDS_BIGENDIAN) |
514 | 37.2k | swab=MagickTrue; |
515 | 37.2k | #endif /* !defined(WORDS_BIGENDIAN) */ |
516 | 37.2k | image=AllocateImage(image_info); |
517 | 37.2k | status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); |
518 | 37.2k | if (status == False) |
519 | 0 | { |
520 | 0 | DestroyImageList(image); |
521 | 0 | return((Image *) NULL); |
522 | 0 | } |
523 | | /* |
524 | | Read CINEON image. |
525 | | */ |
526 | 37.2k | offset=(ReadBlob(image,sizeof(cin_file_info),&cin_file_info)); |
527 | 37.2k | if (offset != sizeof(cin_file_info)) |
528 | 32.1k | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
529 | | |
530 | 32.1k | if (swab) |
531 | 32.1k | SwabCineonFileInfo(&cin_file_info); |
532 | 32.1k | NULLTerminateASCIIField(cin_file_info.header_format_version); |
533 | 32.1k | NULLTerminateASCIIField(cin_file_info.image_filename); |
534 | 32.1k | NULLTerminateASCIIField(cin_file_info.creation_date); |
535 | 32.1k | NULLTerminateASCIIField(cin_file_info.creation_time); |
536 | 32.1k | NULLTerminateASCIIField(cin_file_info.reserved); |
537 | 32.1k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
538 | 32.1k | "File magic 0x%04X",cin_file_info.magic); |
539 | | |
540 | 32.1k | if (cin_file_info.magic != 0x802A5FD7U) |
541 | 32.0k | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
542 | | |
543 | 32.0k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
544 | 32.0k | "Image offset %u, Generic length %u, Industry length %u, User length %u, File size %u", |
545 | 32.0k | cin_file_info.image_data_offset, |
546 | 32.0k | cin_file_info.generic_section_length, |
547 | 32.0k | cin_file_info.industry_section_length, |
548 | 32.0k | cin_file_info.user_defined_length, |
549 | 32.0k | cin_file_info.file_size); |
550 | 32.0k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
551 | 32.0k | "Header format version \"%s\"", cin_file_info.header_format_version); |
552 | 32.0k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
553 | 32.0k | "Image file name \"%s\"", cin_file_info.image_filename); |
554 | 32.0k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
555 | 32.0k | "Creation date \"%s\"", cin_file_info.creation_date); |
556 | 32.0k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
557 | 32.0k | "Creation time \"%s\"", cin_file_info.creation_time); |
558 | | /* |
559 | | Place arbitrary limit on user defined length. |
560 | | */ |
561 | 32.0k | if (cin_file_info.user_defined_length > 16777216U) |
562 | 29.2k | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
563 | 29.2k | StringToAttribute(image,"document",cin_file_info.image_filename); |
564 | 29.2k | StringToAttribute(image,"DPX:file.filename",cin_file_info.image_filename); |
565 | 29.2k | { |
566 | 29.2k | char |
567 | 29.2k | creation_datetime[26]; /* 12+1+12+1 */ |
568 | | |
569 | 29.2k | (void) strlcpy(creation_datetime,cin_file_info.creation_date, |
570 | 29.2k | Min(sizeof(creation_datetime),sizeof(cin_file_info.creation_date))); |
571 | 29.2k | if (creation_datetime[0]!='\0') |
572 | 14.5k | (void) strlcat(creation_datetime,":",sizeof(creation_datetime)); |
573 | 29.2k | (void) strlcat(creation_datetime,cin_file_info.creation_time, |
574 | 29.2k | Min(sizeof(creation_datetime),sizeof(creation_datetime))); |
575 | 29.2k | StringToAttribute(image,"timestamp",creation_datetime); |
576 | 29.2k | StringToAttribute(image,"DPX:file.creation.datetime",creation_datetime); |
577 | 29.2k | } |
578 | | |
579 | | /* |
580 | | Obtain offset to pixels. |
581 | | */ |
582 | 29.2k | pixels_offset=cin_file_info.image_data_offset & 0xffffffff; |
583 | 29.2k | if (pixels_offset < 712) |
584 | 23.5k | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
585 | | |
586 | | /* |
587 | | Read image information header. |
588 | | */ |
589 | 23.5k | offset += ReadBlob(image,sizeof(cin_image_info),&cin_image_info); |
590 | 23.5k | if (offset != (size_t) 712L) |
591 | 19.0k | ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
592 | 19.0k | if (cin_image_info.channels > |
593 | 19.0k | (sizeof(cin_image_info.channel_info)/sizeof(cin_image_info.channel_info[0]))) |
594 | 17.3k | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
595 | 17.3k | if (swab) |
596 | 17.3k | SwabCineonImageInfo(&cin_image_info); |
597 | 17.3k | NULLTerminateASCIIField(cin_image_info.label_text); |
598 | 17.3k | NULLTerminateASCIIField(cin_image_info.reserved); |
599 | 17.3k | NULLTerminateASCIIField(cin_image_info.reserved2); |
600 | 17.3k | number_of_channels=cin_image_info.channels; |
601 | 17.3k | if (number_of_channels > |
602 | 17.3k | (sizeof(cin_image_info.channel_info)/sizeof(cin_image_info.channel_info[0]))) |
603 | 17.3k | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
604 | 17.3k | U8ToAttribute(image,"DPX:image.orientation",cin_image_info.orientation); |
605 | 17.3k | image->orientation=CineonOrientationToOrientationType(cin_image_info.orientation); |
606 | 17.3k | max_bits_per_sample=0; |
607 | 17.3k | max_pixels_per_line=0; |
608 | 17.3k | max_lines_per_image=0; |
609 | 46.0k | for (channel=0; channel < number_of_channels; channel++) |
610 | 28.7k | { |
611 | 28.7k | max_bits_per_sample=Max(max_bits_per_sample, |
612 | 28.7k | cin_image_info.channel_info[channel].bits_per_sample); |
613 | 28.7k | max_pixels_per_line=Max(max_pixels_per_line, |
614 | 28.7k | cin_image_info.channel_info[channel].pixels_per_line); |
615 | 28.7k | max_lines_per_image=Max(max_lines_per_image, |
616 | 28.7k | cin_image_info.channel_info[channel].lines_per_image); |
617 | 28.7k | } |
618 | | |
619 | 17.3k | image->depth=max_bits_per_sample; |
620 | 17.3k | image->columns=max_pixels_per_line; |
621 | 17.3k | image->rows=max_lines_per_image; |
622 | 17.3k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
623 | 17.3k | "Columns %ld, Rows %ld, Channels %u", |
624 | 17.3k | image->columns, image->rows, |
625 | 17.3k | (unsigned int) cin_image_info.channels); |
626 | 17.3k | if (!IS_UNDEFINED_R32(cin_image_info.white_point[0])) |
627 | 17.3k | image->chromaticity.white_point.x = cin_image_info.white_point[0].f; |
628 | 17.3k | if (!IS_UNDEFINED_R32(cin_image_info.white_point[1])) |
629 | 17.3k | image->chromaticity.white_point.y = cin_image_info.white_point[1].f; |
630 | 17.3k | if (!IS_UNDEFINED_R32(cin_image_info.red_primary_chromaticity[0])) |
631 | 17.3k | image->chromaticity.red_primary.x = cin_image_info.red_primary_chromaticity[0].f; |
632 | 17.3k | if (!IS_UNDEFINED_R32(cin_image_info.red_primary_chromaticity[1])) |
633 | 17.3k | image->chromaticity.red_primary.y = cin_image_info.red_primary_chromaticity[1].f; |
634 | 17.3k | if (!IS_UNDEFINED_R32(cin_image_info.green_primary_chromaticity[0])) |
635 | 17.3k | image->chromaticity.green_primary.x = cin_image_info.green_primary_chromaticity[0].f; |
636 | 17.3k | if (!IS_UNDEFINED_R32(cin_image_info.green_primary_chromaticity[1])) |
637 | 17.3k | image->chromaticity.green_primary.y = cin_image_info.green_primary_chromaticity[1].f; |
638 | 17.3k | if (!IS_UNDEFINED_R32(cin_image_info.blue_primary_chromaticity[0])) |
639 | 17.3k | image->chromaticity.blue_primary.x = cin_image_info.blue_primary_chromaticity[0].f; |
640 | 17.3k | if (!IS_UNDEFINED_R32(cin_image_info.blue_primary_chromaticity[1])) |
641 | 17.3k | image->chromaticity.blue_primary.y = cin_image_info.blue_primary_chromaticity[1].f; |
642 | 17.3k | StringToAttribute(image,"DPX:file.project.name",cin_image_info.label_text); |
643 | | |
644 | | /* |
645 | | Read image origination header. |
646 | | */ |
647 | 17.3k | offset += ReadBlob(image,sizeof(cin_source_info),&cin_source_info); |
648 | 17.3k | if (offset != (size_t) 1024L) |
649 | 16.1k | ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
650 | 16.1k | if (swab) |
651 | 16.1k | SwabCineonImageOriginationInfo(&cin_source_info); |
652 | 16.1k | NULLTerminateASCIIField(cin_source_info.source_image_filename); |
653 | 16.1k | NULLTerminateASCIIField(cin_source_info.creation_date); |
654 | 16.1k | NULLTerminateASCIIField(cin_source_info.creation_time); |
655 | 16.1k | NULLTerminateASCIIField(cin_source_info.input_device); |
656 | 16.1k | NULLTerminateASCIIField(cin_source_info.input_device_model); |
657 | 16.1k | NULLTerminateASCIIField(cin_source_info.input_device_serial); |
658 | 16.1k | S32ToAttribute(image,"DPX:source.x-offset",cin_source_info.x_offset); |
659 | 16.1k | S32ToAttribute(image,"DPX:source.y-offset",cin_source_info.y_offset); |
660 | 16.1k | StringToAttribute(image,"DPX:source.filename",cin_source_info.source_image_filename); |
661 | 16.1k | { |
662 | 16.1k | char |
663 | 16.1k | source_creation_datetime[MaxTextExtent]; |
664 | | |
665 | 16.1k | source_creation_datetime[0]='\0'; |
666 | 16.1k | (void) strlcat(source_creation_datetime,cin_file_info.creation_date,sizeof(cin_file_info.creation_date)+1); |
667 | 16.1k | if (source_creation_datetime[0]!='\0') |
668 | 7.92k | (void) strlcat(source_creation_datetime,":",sizeof(source_creation_datetime)); |
669 | 16.1k | (void) strlcat(source_creation_datetime,cin_file_info.creation_time,sizeof(source_creation_datetime)); |
670 | 16.1k | StringToAttribute(image,"DPX:source.creation.datetime",source_creation_datetime); |
671 | 16.1k | } |
672 | 16.1k | StringToAttribute(image,"DPX:source.device.name",cin_source_info.input_device); |
673 | 16.1k | StringToAttribute(image,"DPX:source.device.model",cin_source_info.input_device_model); |
674 | 16.1k | StringToAttribute(image,"DPX:source.device.serialnumber",cin_source_info.input_device_serial); |
675 | 16.1k | R32ToAttribute(image,"DPX:source.device.pitch.x",cin_source_info.input_device_pitch_x); |
676 | 16.1k | R32ToAttribute(image,"DPX:source.device.pitch.y",cin_source_info.input_device_pitch_y); |
677 | 16.1k | R32ToAttribute(image,"DPX:source.device.gamma",cin_source_info.gamma); |
678 | | |
679 | 16.1k | if ((pixels_offset >= 1024) && (cin_file_info.industry_section_length > 0)) |
680 | 7.82k | { |
681 | | /* |
682 | | Read Motion-picture film information header. |
683 | | */ |
684 | 7.82k | offset += ReadBlob(image,sizeof(cin_mp_info),&cin_mp_info); |
685 | 7.82k | if (offset != (size_t) 2048L) |
686 | 3.92k | ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
687 | 3.92k | if (swab) |
688 | 3.92k | SwabCineonFilmInfo(&cin_mp_info); |
689 | 3.92k | NULLTerminateASCIIField(cin_mp_info.format); |
690 | 3.92k | NULLTerminateASCIIField(cin_mp_info.frame_id); |
691 | 3.92k | NULLTerminateASCIIField(cin_mp_info.slate_info); |
692 | 3.92k | NULLTerminateASCIIField(cin_mp_info.reserved); |
693 | 3.92k | U8ToAttribute(image,"DPX:mp.film.manufacturer.id",cin_mp_info.film_mfg_id_code); |
694 | 3.92k | U8ToAttribute(image,"DPX:mp.film.type",cin_mp_info.film_type); |
695 | 3.92k | U8ToAttribute(image,"DPX:mp.perfs.offset",cin_mp_info.perfs_offset); |
696 | 3.92k | U32ToAttribute(image,"DPX:mp.prefix",cin_mp_info.prefix); |
697 | 3.92k | U32ToAttribute(image,"DPX:mp.count",cin_mp_info.count); |
698 | 3.92k | StringToAttribute(image,"DPX:mp.format",cin_mp_info.format); |
699 | 3.92k | U32ToAttribute(image,"DPX:mp.frame.position",cin_mp_info.frame_position); |
700 | 3.92k | R32ToAttribute(image,"DPX:mp.frame.rate",cin_mp_info.frame_rate); |
701 | 3.92k | StringToAttribute(image,"DPX:mp.frame.id",cin_mp_info.frame_id); |
702 | 3.92k | StringToAttribute(image,"DPX:mp.slate.info",cin_mp_info.slate_info); |
703 | 3.92k | } |
704 | | |
705 | 12.2k | if ((pixels_offset >= 2048) && (cin_file_info.user_defined_length > 0)) |
706 | 11.4k | { |
707 | 11.4k | unsigned char |
708 | 11.4k | *user_data; |
709 | | |
710 | 11.4k | const size_t |
711 | 11.4k | block_size = 65536UL; |
712 | | |
713 | 11.4k | size_t |
714 | 11.4k | read_size, |
715 | 11.4k | user_data_length; |
716 | | |
717 | 11.4k | user_data_length=0UL; |
718 | 11.4k | user_data=(unsigned char *) NULL; |
719 | 14.2k | while (user_data_length < cin_file_info.user_defined_length) |
720 | 12.2k | { |
721 | 12.2k | unsigned char *new_user_data; |
722 | 12.2k | read_size=Min(block_size,cin_file_info.user_defined_length-user_data_length); |
723 | 12.2k | new_user_data=MagickReallocateResourceLimitedMemory(unsigned char *,user_data,user_data_length+read_size); |
724 | 12.2k | if (new_user_data == (unsigned char *) NULL) |
725 | 0 | { |
726 | 0 | MagickFreeResourceLimitedMemory(unsigned char *,user_data); |
727 | 0 | ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image); |
728 | 0 | } |
729 | 12.2k | user_data=new_user_data; |
730 | 12.2k | if (ReadBlob(image,read_size,user_data+user_data_length) != read_size) |
731 | 9.38k | { |
732 | 9.38k | MagickFreeResourceLimitedMemory(unsigned char *,user_data); |
733 | 9.38k | ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
734 | 0 | } |
735 | 2.83k | user_data_length += read_size; |
736 | 2.83k | offset += read_size; |
737 | 2.83k | } |
738 | 2.03k | if (!SetImageProfile(image,"CINEONUSERDATA",user_data,user_data_length)) |
739 | 0 | { |
740 | 0 | MagickFreeResourceLimitedMemory(unsigned char *,user_data); |
741 | 0 | ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image); |
742 | 0 | } |
743 | 2.03k | MagickFreeResourceLimitedMemory(unsigned char *,user_data); |
744 | 2.03k | } |
745 | | |
746 | 2.88k | if (image_info->ping) |
747 | 0 | { |
748 | 0 | CloseBlob(image); |
749 | 0 | return(image); |
750 | 0 | } |
751 | | |
752 | 2.88k | if (CheckImagePixelLimits(image, exception) != MagickPass) |
753 | 2.13k | ThrowReaderException(ResourceLimitError,ImagePixelLimitExceeded,image); |
754 | | |
755 | | /* |
756 | | Read remainder of header. |
757 | | */ |
758 | 2.13M | for ( ; offset < pixels_offset ; offset++ ) |
759 | 2.13M | if (ReadBlobByte(image) == EOF) |
760 | 659 | ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
761 | | |
762 | | /* |
763 | | Verify that remaining data is sufficient for claimed dimensions. |
764 | | */ |
765 | 659 | if (BlobIsSeekable(image)) |
766 | 659 | { |
767 | 659 | magick_off_t file_size; |
768 | 659 | magick_intmax_t expected_file_size; |
769 | | |
770 | 659 | file_size = GetBlobSize(image); |
771 | | |
772 | 659 | expected_file_size=pixels_offset+ |
773 | 659 | ((((((magick_intmax_t) image->rows*image->columns*number_of_channels+2UL)/3UL) |
774 | 659 | *sizeof(U32)*8UL)+31UL)/32UL)*sizeof(U32); |
775 | 659 | if (image->logging) |
776 | 659 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
777 | 659 | "Expected file size %" MAGICK_UINTMAX_F "u bytes" |
778 | 659 | " (have %" MAGICK_OFF_F "d bytes)", |
779 | 659 | expected_file_size, file_size); |
780 | | |
781 | 659 | if ((file_size > 0) && ((magick_int64_t) file_size < expected_file_size)) |
782 | 620 | ThrowReaderException(CorruptImageError,InsufficientImageDataInFile,image); |
783 | 620 | } |
784 | | |
785 | 620 | if (image->logging) |
786 | 620 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
787 | 620 | "Reading Cineon pixels starting at offset %ld",(long) TellBlob(image)); |
788 | | |
789 | | /* |
790 | | Convert CINEON raster image to pixel packets. |
791 | | */ |
792 | 620 | { |
793 | 620 | size_t |
794 | 620 | scandata_bytes; |
795 | | |
796 | 620 | unsigned int |
797 | 620 | scale_to_short=0; |
798 | | |
799 | 620 | switch (number_of_channels) |
800 | 620 | { |
801 | 406 | case 1: |
802 | 406 | { |
803 | 406 | scandata_bytes=4; |
804 | 406 | scale_to_short=64; |
805 | 406 | scandata=MagickAllocateResourceLimitedMemory(unsigned char *,scandata_bytes); |
806 | 406 | if (scandata == (unsigned char *) NULL) |
807 | 406 | ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image); |
808 | 406 | scanline=scandata; |
809 | 406 | MagickBitStreamInitializeRead(&bit_stream,(const unsigned char*) scanline); |
810 | 137k | for (y=0; y < image->rows; y++) |
811 | 137k | { |
812 | 137k | q=SetImagePixels(image,0,y,image->columns,1); |
813 | 137k | if (q == (PixelPacket *) NULL) |
814 | 2 | break; |
815 | | /* |
816 | | Packed 10 bit samples with 2 bit pad at end of 32-bit word. |
817 | | */ |
818 | 137k | scanline=scandata; |
819 | 137k | i=3; |
820 | 17.2M | for (x=0; x < image->columns; x++, i++) |
821 | 17.1M | { |
822 | 17.1M | if (i > 2) |
823 | 5.77M | { |
824 | 5.77M | scanline=scandata; |
825 | 5.77M | if (ReadBlobZC(image,scandata_bytes,&scanline) != |
826 | 5.77M | scandata_bytes) |
827 | 148 | break; |
828 | 5.77M | MagickBitStreamInitializeRead(&bit_stream,(const unsigned char *) scanline); |
829 | 5.77M | i=0; |
830 | 5.77M | } |
831 | 17.1M | q->red=q->green=q->blue= |
832 | 17.1M | ScaleShortToQuantum(MagickBitStreamMSBRead(&bit_stream,10)*scale_to_short); |
833 | 17.1M | q->opacity=0U; |
834 | 17.1M | q++; |
835 | 17.1M | } |
836 | 137k | if (x < image->columns) |
837 | 148 | break; |
838 | 137k | if (!SyncImagePixels(image)) |
839 | 0 | break; |
840 | 137k | if (image->previous == (Image *) NULL) |
841 | 137k | if (QuantumTick(y,image->rows)) |
842 | 21.7k | if (!MagickMonitorFormatted(y,image->rows,exception, |
843 | 21.7k | LoadImageText,image->filename, |
844 | 21.7k | image->columns,image->rows)) |
845 | 0 | break; |
846 | 137k | } |
847 | 406 | MagickFreeResourceLimitedMemory(unsigned char *,scandata); |
848 | 406 | break; |
849 | 406 | } |
850 | 211 | case 3: |
851 | 211 | { |
852 | 211 | scandata_bytes=MagickArraySize(image->columns,4); |
853 | 211 | scale_to_short=64; |
854 | 211 | scandata=MagickAllocateResourceLimitedMemory(unsigned char *,scandata_bytes); |
855 | 211 | if (scandata == (unsigned char *) NULL) |
856 | 211 | ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image); |
857 | 36.4k | for (y=0; y < image->rows; y++) |
858 | 36.3k | { |
859 | 36.3k | magick_uint32_t red; |
860 | 36.3k | magick_uint32_t green; |
861 | 36.3k | magick_uint32_t blue; |
862 | | |
863 | 36.3k | q=SetImagePixels(image,0,y,image->columns,1); |
864 | 36.3k | if (q == (PixelPacket *) NULL) |
865 | 1 | break; |
866 | 36.3k | scanline=scandata; |
867 | 36.3k | if (ReadBlobZC(image,scandata_bytes,&scanline) != scandata_bytes) |
868 | 113 | break; |
869 | 36.2k | MagickBitStreamInitializeRead(&bit_stream,(const unsigned char*) scanline); |
870 | 906k | for (x=0 ; x < image->columns; x++) |
871 | 870k | { |
872 | | /* |
873 | | Packed 10 bit samples with 2 bit pad at end of 32-bit word. |
874 | | */ |
875 | 870k | red = MagickBitStreamMSBRead(&bit_stream,10); |
876 | 870k | green = MagickBitStreamMSBRead(&bit_stream,10); |
877 | 870k | blue = MagickBitStreamMSBRead(&bit_stream,10); |
878 | 870k | (void) MagickBitStreamMSBRead(&bit_stream,2); |
879 | | |
880 | 870k | q->red = ScaleShortToQuantum(red*scale_to_short); |
881 | 870k | q->green = ScaleShortToQuantum(green*scale_to_short); |
882 | 870k | q->blue = ScaleShortToQuantum(blue*scale_to_short); |
883 | 870k | q->opacity = 0U; |
884 | | |
885 | | /* printf("i:%u,%u,%u --> %u,%u,%u\n", red, green, blue, */ |
886 | | /* (unsigned int)q->red, (unsigned int)q->green, (unsigned int)q->blue); */ |
887 | 870k | q++; |
888 | 870k | } |
889 | 36.2k | if (x < image->columns) |
890 | 0 | break; |
891 | 36.2k | if (!SyncImagePixels(image)) |
892 | 0 | break; |
893 | 36.2k | if (image->previous == (Image *) NULL) |
894 | 36.2k | if (QuantumTick(y,image->rows)) |
895 | 5.71k | if (!MagickMonitorFormatted(y,image->rows,exception, |
896 | 5.71k | LoadImageText,image->filename, |
897 | 5.71k | image->columns,image->rows)) |
898 | 0 | break; |
899 | 36.2k | } |
900 | 211 | MagickFreeResourceLimitedMemory(unsigned char *,scandata); |
901 | 211 | break; |
902 | 211 | } |
903 | 3 | default: |
904 | 3 | ThrowReaderException(CorruptImageError,ImageTypeNotSupported,image); |
905 | 620 | } |
906 | 620 | } |
907 | 617 | if (image->logging) |
908 | 617 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
909 | 617 | "EOF at offset %" MAGICK_OFF_F "d", TellBlob(image)); |
910 | 617 | image->depth=Min(image->depth,QuantumDepth); |
911 | 617 | image->colorspace=CineonLogRGBColorspace; |
912 | | |
913 | 617 | if ((definition_value=AccessDefinition(image_info,"cineon","colorspace"))) |
914 | 0 | { |
915 | 0 | ColorspaceType |
916 | 0 | colorspace; |
917 | |
|
918 | 0 | colorspace=StringToColorspaceType(definition_value); |
919 | 0 | if (colorspace != UndefinedColorspace) |
920 | 0 | { |
921 | 0 | image->colorspace=colorspace; |
922 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
923 | 0 | "Explicitly set colorspace to %s", |
924 | 0 | ColorspaceTypeToString(image->colorspace)); |
925 | 0 | } |
926 | 0 | else |
927 | 0 | { |
928 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
929 | 0 | "Unrecognized source colorspace \"%s\"\n", |
930 | 0 | definition_value); |
931 | 0 | ThrowException(&image->exception,OptionError,UnrecognizedColorspace, |
932 | 0 | definition_value); |
933 | 0 | } |
934 | 0 | } |
935 | | |
936 | 617 | if (EOFBlob(image)) |
937 | 261 | ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,image->filename); |
938 | 617 | CloseBlob(image); |
939 | 617 | StopTimer(&image->timer); |
940 | 617 | return(GetFirstImageInList(image)); |
941 | 620 | } |
942 | | |
943 | | /* |
944 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
945 | | % % |
946 | | % % |
947 | | % % |
948 | | % R e g i s t e r C I N E O N I m a g e % |
949 | | % % |
950 | | % % |
951 | | % % |
952 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
953 | | % |
954 | | % Method RegisterCINEONImage adds attributes for the CINEON image format to |
955 | | % the list of supported formats. The attributes include the image format |
956 | | % tag, a method to read and/or write the format, whether the format |
957 | | % supports the saving of more than one frame to the same file or blob, |
958 | | % whether the format supports native in-memory I/O, and a brief |
959 | | % description of the format. |
960 | | % |
961 | | % The format of the RegisterCINEONImage method is: |
962 | | % |
963 | | % RegisterCINEONImage(void) |
964 | | % |
965 | | */ |
966 | | ModuleExport void RegisterCINEONImage(void) |
967 | 4 | { |
968 | 4 | MagickInfo |
969 | 4 | *entry; |
970 | | |
971 | 4 | entry=SetMagickInfo("CIN"); |
972 | 4 | entry->decoder=(DecoderHandler) ReadCINEONImage; |
973 | 4 | entry->encoder=(EncoderHandler) WriteCINEONImage; |
974 | 4 | entry->magick=(MagickHandler) IsCINEON; |
975 | 4 | entry->description="Cineon Image File"; |
976 | 4 | entry->module="CINEON"; |
977 | 4 | entry->adjoin=MagickFalse; |
978 | 4 | (void) RegisterMagickInfo(entry); |
979 | 4 | } |
980 | | |
981 | | /* |
982 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
983 | | % % |
984 | | % % |
985 | | % % |
986 | | % U n r e g i s t e r C I N E O N I m a g e % |
987 | | % % |
988 | | % % |
989 | | % % |
990 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
991 | | % |
992 | | % Method UnregisterCINEONImage removes format registrations made by the |
993 | | % CINEON module from the list of supported formats. |
994 | | % |
995 | | % The format of the UnregisterCINEONImage method is: |
996 | | % |
997 | | % UnregisterCINEONImage(void) |
998 | | % |
999 | | */ |
1000 | | ModuleExport void UnregisterCINEONImage(void) |
1001 | 0 | { |
1002 | 0 | (void) UnregisterMagickInfo("CIN"); |
1003 | 0 | } |
1004 | | |
1005 | | /* |
1006 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1007 | | % % |
1008 | | % % |
1009 | | % % |
1010 | | % W r i t e C I N E O N I m a g e % |
1011 | | % % |
1012 | | % % |
1013 | | % % |
1014 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1015 | | % |
1016 | | % WriteCINEONImage() writes an image in CINEON encoded image format. |
1017 | | % |
1018 | | % The format of the WriteCINEONImage method is: |
1019 | | % |
1020 | | % unsigned int WriteCINEONImage(const ImageInfo *image_info,Image *image) |
1021 | | % |
1022 | | % A description of each parameter follows. |
1023 | | % |
1024 | | % o image_info: The image info. |
1025 | | % |
1026 | | % o image: The image. |
1027 | | % |
1028 | | % |
1029 | | */ |
1030 | | |
1031 | 1.00k | #define AttributeToU8(image_info,image,key,member) \ |
1032 | 1.00k | { \ |
1033 | 1.00k | const ImageAttribute \ |
1034 | 1.00k | *attribute; \ |
1035 | 1.00k | \ |
1036 | 1.00k | const char \ |
1037 | 1.00k | *definition_value; \ |
1038 | 1.00k | \ |
1039 | 1.00k | if ((definition_value=AccessDefinition(image_info,"dpx",&key[4]))) \ |
1040 | 1.00k | member=(U8) strtol(definition_value, (char **) NULL, 10); \ |
1041 | 1.00k | else if ((attribute=GetImageAttribute(image,key))) \ |
1042 | 1.00k | member=(U8) strtol(attribute->value, (char **) NULL, 10); \ |
1043 | 1.00k | else \ |
1044 | 1.00k | SET_UNDEFINED_U8(member); \ |
1045 | 1.00k | } |
1046 | | |
1047 | 1.00k | #define AttributeToU32(image_info,image,key,member) \ |
1048 | 1.00k | { \ |
1049 | 1.00k | const ImageAttribute \ |
1050 | 1.00k | *attribute; \ |
1051 | 1.00k | \ |
1052 | 1.00k | const char \ |
1053 | 1.00k | *definition_value; \ |
1054 | 1.00k | \ |
1055 | 1.00k | if ((definition_value=AccessDefinition(image_info,"dpx",&key[4]))) \ |
1056 | 1.00k | member=(U32) strtol(definition_value, (char **) NULL, 10); \ |
1057 | 1.00k | else if ((attribute=GetImageAttribute(image,key))) \ |
1058 | 1.00k | member=(U32) strtol(attribute->value, (char **) NULL, 10); \ |
1059 | 1.00k | else \ |
1060 | 1.00k | SET_UNDEFINED_U32(member); \ |
1061 | 1.00k | } |
1062 | | |
1063 | 670 | #define AttributeToS32(image_info,image,key,member) \ |
1064 | 670 | { \ |
1065 | 670 | const ImageAttribute \ |
1066 | 670 | *attribute; \ |
1067 | 670 | \ |
1068 | 670 | const char \ |
1069 | 670 | *definition_value; \ |
1070 | 670 | \ |
1071 | 670 | if ((definition_value=AccessDefinition(image_info,"dpx",&key[4]))) \ |
1072 | 670 | member=(S32) strtol(definition_value, (char **) NULL, 10); \ |
1073 | 670 | else if ((attribute=GetImageAttribute(image,key))) \ |
1074 | 670 | member=(S32) strtol(attribute->value, (char **) NULL, 10); \ |
1075 | 670 | else \ |
1076 | 670 | SET_UNDEFINED_S32(member); \ |
1077 | 670 | } |
1078 | | |
1079 | 1.34k | #define AttributeToR32(image_info,image,key,member) \ |
1080 | 1.34k | { \ |
1081 | 1.34k | const ImageAttribute \ |
1082 | 1.34k | *attribute; \ |
1083 | 1.34k | \ |
1084 | 1.34k | const char \ |
1085 | 1.34k | *definition_value; \ |
1086 | 1.34k | \ |
1087 | 1.34k | if ((definition_value=AccessDefinition(image_info,"dpx",&key[4]))) \ |
1088 | 1.34k | member.f=(float) strtod(definition_value, (char **) NULL); \ |
1089 | 1.34k | else if ((attribute=GetImageAttribute(image,key))) \ |
1090 | 1.34k | member.f=(float) strtod(attribute->value, (char **) NULL); \ |
1091 | 1.34k | else \ |
1092 | 1.34k | SET_UNDEFINED_R32(member); \ |
1093 | 1.34k | } |
1094 | | |
1095 | | /* |
1096 | | Header string values are not required to be null terminated, but any |
1097 | | unused space should be filled with nulls. |
1098 | | */ |
1099 | 3.01k | #define AttributeToString(image_info,image,key,member) \ |
1100 | 3.01k | { \ |
1101 | 3.01k | const ImageAttribute \ |
1102 | 3.01k | *attribute; \ |
1103 | 3.01k | \ |
1104 | 3.01k | const char \ |
1105 | 3.01k | *definition_value; \ |
1106 | 3.01k | \ |
1107 | 3.01k | SET_UNDEFINED_ASCII(member); \ |
1108 | 3.01k | if ((definition_value=AccessDefinition(image_info,"dpx",&key[4]))) \ |
1109 | 3.01k | (void) memcpy(member,definition_value,Min(sizeof(member),strlen(definition_value))); \ |
1110 | 3.01k | else if ((attribute=GetImageAttribute(image,key)) && (attribute->value)) \ |
1111 | 3.01k | (void) memcpy(member,attribute->value,Min(sizeof(member),strlen(attribute->value))); \ |
1112 | 3.01k | } |
1113 | | |
1114 | | static void GenerateCineonTimeStamp(char *date_str, size_t date_str_length, char*time_str, size_t time_str_length) |
1115 | 335 | { |
1116 | 335 | char timestamp[MaxTextExtent]; |
1117 | | |
1118 | 335 | time_t |
1119 | 335 | current_time; |
1120 | | |
1121 | 335 | #if defined(HAVE_LOCALTIME_R) |
1122 | 335 | struct tm |
1123 | 335 | tm_buf; |
1124 | 335 | #endif /* if defined(HAVE_LOCALTIME_R) */ |
1125 | | |
1126 | 335 | const struct tm |
1127 | 335 | *t; |
1128 | | |
1129 | 335 | current_time=time((time_t *) NULL); |
1130 | 335 | #if defined(HAVE_LOCALTIME_R) |
1131 | 335 | t=localtime_r(¤t_time, &tm_buf); |
1132 | | #else |
1133 | | t=localtime(¤t_time); /* Thread-unsafe version */ |
1134 | | #endif /* if defined(HAVE_LOCALTIME_R) */ |
1135 | | |
1136 | 335 | (void) memset(timestamp,0,sizeof(timestamp)); |
1137 | 335 | (void) strftime(timestamp,MaxTextExtent,"%Y:%m:%d:%H:%M:%S%Z",t); |
1138 | 335 | timestamp[MaxTextExtent-1]='\0'; |
1139 | 335 | (void) memset(date_str,0,date_str_length); |
1140 | 335 | (void) strlcpy(date_str,timestamp,date_str_length); |
1141 | 335 | (void) memset(time_str,0,time_str_length); |
1142 | 335 | (void) strlcpy(time_str,timestamp+11,time_str_length); |
1143 | 335 | } |
1144 | | |
1145 | | |
1146 | | static unsigned int WriteCINEONImage(const ImageInfo *image_info,Image *image) |
1147 | 335 | { |
1148 | 335 | CineonFileInfo |
1149 | 335 | cin_file_info; |
1150 | | |
1151 | 335 | CineonImageInfo |
1152 | 335 | cin_image_info; |
1153 | | |
1154 | 335 | CineonImageOriginationInfo |
1155 | 335 | cin_source_info; |
1156 | | |
1157 | 335 | CineonFilmInfo |
1158 | 335 | cin_mp_info; |
1159 | | |
1160 | 335 | const unsigned char |
1161 | 335 | *user_data; |
1162 | | |
1163 | 335 | size_t |
1164 | 335 | user_data_length=0, |
1165 | 335 | offset=0; |
1166 | | |
1167 | 335 | size_t |
1168 | 335 | written=0; |
1169 | | |
1170 | 335 | MagickBool |
1171 | 335 | swab=MagickFalse; |
1172 | | |
1173 | 335 | long |
1174 | 335 | y; |
1175 | | |
1176 | 335 | register const PixelPacket |
1177 | 335 | *p; |
1178 | | |
1179 | 335 | register long |
1180 | 335 | x; |
1181 | | |
1182 | 335 | unsigned int |
1183 | 335 | status; |
1184 | | |
1185 | 335 | assert(image_info != (const ImageInfo *) NULL); |
1186 | 335 | assert(image_info->signature == MagickSignature); |
1187 | 335 | assert(image != (Image *) NULL); |
1188 | 335 | assert(image->signature == MagickSignature); |
1189 | | |
1190 | | /* |
1191 | | Cineon files are written in Cineon Log color space. |
1192 | | */ |
1193 | 335 | if (image->colorspace != CineonLogRGBColorspace) |
1194 | 0 | if (TransformColorspace(image,CineonLogRGBColorspace) == MagickFail) |
1195 | 335 | ThrowWriterException(CoderError,UnableToTransformColorspace,image); |
1196 | | |
1197 | 335 | #if !defined(WORDS_BIGENDIAN) |
1198 | 335 | swab=MagickTrue; |
1199 | 335 | #endif /* !defined(WORDS_BIGENDIAN) */ |
1200 | | |
1201 | | /* |
1202 | | File information header |
1203 | | */ |
1204 | 335 | (void) memset(&cin_file_info,0,sizeof(cin_file_info)); |
1205 | | |
1206 | | /* Magick number (0x802A5FD7) */ |
1207 | 335 | cin_file_info.magic = 0x802A5FD7; |
1208 | | /* Generic section header length in bytes */ |
1209 | 335 | cin_file_info.generic_section_length = sizeof(cin_file_info)+sizeof(cin_image_info)+sizeof(cin_source_info); |
1210 | | /* Industry specific header length in bytes */ |
1211 | 335 | cin_file_info.industry_section_length = sizeof(cin_mp_info); |
1212 | | /* User defined header length in bytes */ |
1213 | 335 | cin_file_info.user_defined_length = 0; |
1214 | 335 | user_data=GetImageProfile(image,"CINEONUSERDATA",&user_data_length); |
1215 | 335 | if (user_data && user_data_length) |
1216 | 102 | cin_file_info.user_defined_length = (U32) user_data_length; |
1217 | | /* Offset to image data in bytes */ |
1218 | 335 | cin_file_info.image_data_offset = |
1219 | 335 | cin_file_info.generic_section_length + |
1220 | 335 | cin_file_info.industry_section_length + |
1221 | 335 | cin_file_info.user_defined_length; |
1222 | | /* Total image file size in bytes */ |
1223 | 335 | cin_file_info.file_size = |
1224 | 335 | cin_file_info.generic_section_length + |
1225 | 335 | cin_file_info.industry_section_length + |
1226 | 335 | cin_file_info.user_defined_length + |
1227 | 335 | image->rows*image->columns*4; |
1228 | | /* Version number of header format */ |
1229 | 335 | (void) strlcpy(cin_file_info.header_format_version,"V4.5",sizeof(cin_file_info.header_format_version)); |
1230 | | /* Image filename */ |
1231 | 335 | (void) strlcpy(cin_file_info.image_filename,image->filename,sizeof(cin_file_info.image_filename)); |
1232 | | /* Creation date "yyyy:mm:dd", and time "hh:mm:ssLTZ" */ |
1233 | 335 | GenerateCineonTimeStamp(cin_file_info.creation_date,sizeof(cin_file_info.creation_date), |
1234 | 335 | cin_file_info.creation_time,sizeof(cin_file_info.creation_time)); |
1235 | | |
1236 | | /* |
1237 | | Image information header |
1238 | | */ |
1239 | 335 | (void) memset(&cin_image_info,0,sizeof(cin_image_info)); |
1240 | | /* Image orientation */ |
1241 | 335 | cin_image_info.orientation = OrientationTypeToCineonOrientation(image->orientation); |
1242 | | /* Number of image channels (1-8) */ |
1243 | 335 | cin_image_info.channels = 3; /* RGB */ |
1244 | | |
1245 | | /* Channel 0 (Red) */ |
1246 | 335 | cin_image_info.channel_info[0].designator_byte_0 = 0; /* 0 = universal metric */ |
1247 | 335 | cin_image_info.channel_info[0].designator_byte_1 = 1; /* Red, Printing Density */ |
1248 | | /* Bit depth */ |
1249 | 335 | cin_image_info.channel_info[0].bits_per_sample = 10; |
1250 | | /* Pixels per line (columns) */ |
1251 | 335 | cin_image_info.channel_info[0].pixels_per_line = image->columns; |
1252 | | /* Lines per image (rows) */ |
1253 | 335 | cin_image_info.channel_info[0].lines_per_image = image->rows; |
1254 | | /* Reference low data code value */ |
1255 | 335 | cin_image_info.channel_info[0].reference_low_data_code.f = 0; |
1256 | | /* Low quantity represented */ |
1257 | 335 | cin_image_info.channel_info[0].reference_low_quantity.f = 0.00; |
1258 | | /* Reference high data code value */ |
1259 | 335 | cin_image_info.channel_info[0].reference_high_data_code.f = 1023; |
1260 | | /* Reference high quantity represented */ |
1261 | 335 | cin_image_info.channel_info[0].reference_high_quantity.f = 2.048F; |
1262 | | |
1263 | | /* Channel 1 (Green) */ |
1264 | 335 | cin_image_info.channel_info[1] = cin_image_info.channel_info[0]; |
1265 | 335 | cin_image_info.channel_info[1].designator_byte_1 = 2; /* Green, Printing Density */ |
1266 | | |
1267 | | /* Channel 2 (Blue) */ |
1268 | 335 | cin_image_info.channel_info[2] = cin_image_info.channel_info[0]; |
1269 | 335 | cin_image_info.channel_info[2].designator_byte_1 = 3; /* Blue, Printing Density */ |
1270 | | |
1271 | | /* White point (color temperature) - x,y pair */ |
1272 | 335 | SET_UNDEFINED_R32(cin_image_info.white_point[0]); |
1273 | 335 | SET_UNDEFINED_R32(cin_image_info.white_point[1]); |
1274 | 335 | if ( image->chromaticity.white_point.x != 0.0 && image->chromaticity.white_point.y != 0.0 ) |
1275 | 266 | { |
1276 | 266 | cin_image_info.white_point[0].f = (float) image->chromaticity.white_point.x; |
1277 | 266 | cin_image_info.white_point[1].f = (float) image->chromaticity.white_point.y; |
1278 | 266 | } |
1279 | | /* Red primary chromaticity - x,y pair */ |
1280 | 335 | SET_UNDEFINED_R32(cin_image_info.red_primary_chromaticity[0]); |
1281 | 335 | SET_UNDEFINED_R32(cin_image_info.red_primary_chromaticity[1]); |
1282 | 335 | if ( image->chromaticity.red_primary.x != 0.0 && image->chromaticity.red_primary.y != 0.0) |
1283 | 238 | { |
1284 | 238 | cin_image_info.red_primary_chromaticity[0].f = (float) image->chromaticity.red_primary.x; |
1285 | 238 | cin_image_info.red_primary_chromaticity[1].f = (float) image->chromaticity.red_primary.y; |
1286 | 238 | } |
1287 | | /* Green primary chromaticity - x,y pair */ |
1288 | 335 | SET_UNDEFINED_R32(cin_image_info.green_primary_chromaticity[0]); |
1289 | 335 | SET_UNDEFINED_R32(cin_image_info.green_primary_chromaticity[1]); |
1290 | 335 | if ( image->chromaticity.green_primary.x != 0.0 && image->chromaticity.green_primary.y != 0.0 ) |
1291 | 250 | { |
1292 | 250 | cin_image_info.green_primary_chromaticity[0].f = (float) image->chromaticity.green_primary.x; |
1293 | 250 | cin_image_info.green_primary_chromaticity[1].f = (float) image->chromaticity.green_primary.y; |
1294 | 250 | } |
1295 | | /* Blue primary chromaticity - x,y pair */ |
1296 | 335 | SET_UNDEFINED_R32(cin_image_info.blue_primary_chromaticity[0]); |
1297 | 335 | SET_UNDEFINED_R32(cin_image_info.blue_primary_chromaticity[1]); |
1298 | 335 | if ( image->chromaticity.blue_primary.x != 0.0 && image->chromaticity.blue_primary.y != 0.0 ) |
1299 | 225 | { |
1300 | 225 | cin_image_info.blue_primary_chromaticity[0].f = (float) image->chromaticity.blue_primary.x; |
1301 | 225 | cin_image_info.blue_primary_chromaticity[1].f = (float) image->chromaticity.blue_primary.y; |
1302 | 225 | } |
1303 | | /* Label text */ |
1304 | 335 | AttributeToString(image_info,image,"DPX:file.project.name",cin_image_info.label_text); |
1305 | | /* Data interleave */ |
1306 | 335 | cin_image_info.data_interleave = 0; /* rgbrgbrgb ... */ |
1307 | | /* Packing method */ |
1308 | 335 | cin_image_info.packing = 5; /* longword (32-bit) boundaries - left justified */ |
1309 | | /* Data sign: 0=unsigned, 1=signed */ |
1310 | 335 | cin_image_info.sign = 0; |
1311 | | /* Image sense: 0=positive, 1=negative */ |
1312 | 335 | cin_image_info.sense = 0; |
1313 | | /* End of line padding */ |
1314 | 335 | cin_image_info.eol_pad = 0; |
1315 | | /* End of channel padding */ |
1316 | 335 | cin_image_info.eoc_pad = 0; |
1317 | | |
1318 | | /* |
1319 | | Image origination header. |
1320 | | */ |
1321 | 335 | (void) memset(&cin_source_info,0,sizeof(cin_source_info)); |
1322 | 335 | AttributeToS32(image_info,image,"DPX:source.x-offset",cin_source_info.x_offset); /* X offset */ |
1323 | 335 | AttributeToS32(image_info,image,"DPX:source.y-offset",cin_source_info.y_offset); /* Y offset */ |
1324 | | /* Source image filename */ |
1325 | 335 | AttributeToString(image_info,image,"DPX:source.filename",cin_source_info.source_image_filename); |
1326 | 335 | { |
1327 | | /* |
1328 | | DPX stores creation date and time in the format |
1329 | | "yyyy:mm:dd:hh:mm:ssLTZ" but Cineon wants date and time to be split into |
1330 | | yyyy:mm:dd & hh:mm:ssLTZ |
1331 | | */ |
1332 | 335 | ASCII date_and_time[25]; |
1333 | 335 | AttributeToString(image_info,image,"DPX:source.creation.datetime",date_and_time); |
1334 | 335 | SET_UNDEFINED_ASCII(cin_source_info.creation_date); |
1335 | 335 | SET_UNDEFINED_ASCII(cin_source_info.creation_time); |
1336 | | |
1337 | 335 | if (!IS_UNDEFINED_ASCII(date_and_time)) |
1338 | 218 | { |
1339 | | /* Creation date: yyyy:mm:dd */ |
1340 | 218 | (void) strlcpy(cin_source_info.creation_date,date_and_time,11); |
1341 | | /* Creation time: hh:mm:ssLTZ */ |
1342 | 218 | (void) strlcpy(cin_source_info.creation_time,date_and_time+11,sizeof(cin_source_info.creation_time)); |
1343 | 218 | } |
1344 | 335 | } |
1345 | | /* Input device */ |
1346 | 335 | AttributeToString(image_info,image,"DPX:source.device.name",cin_source_info.input_device); |
1347 | | /* Input device model number */ |
1348 | 335 | AttributeToString(image_info,image,"DPX:source.device.model",cin_source_info.input_device_model); |
1349 | | /* Input device serial number */ |
1350 | 335 | AttributeToString(image_info,image,"DPX:source.device.serialnumber",cin_source_info.input_device_serial); |
1351 | | /* Input device pitch for X (samples/mm) */ |
1352 | 335 | AttributeToR32(image_info,image,"DPX:source.device.pitch.x",cin_source_info.input_device_pitch_x); |
1353 | | /* Input device pitch for Y (samples/mm) */ |
1354 | 335 | AttributeToR32(image_info,image,"DPX:source.device.pitch.y",cin_source_info.input_device_pitch_y); |
1355 | | /* Image gamma of capture device */ |
1356 | 335 | AttributeToR32(image_info,image,"DPX:source.device.gamma",cin_source_info.gamma); |
1357 | | |
1358 | | /* |
1359 | | Film/Frame Information |
1360 | | */ |
1361 | 335 | (void) memset(&cin_mp_info,0,sizeof(cin_mp_info)); |
1362 | | /* Film mfg. ID code (2 digits from film edge code) */ |
1363 | 335 | AttributeToU8(image_info,image,"DPX:mp.film.manufacturer.id",cin_mp_info.film_mfg_id_code); |
1364 | | /* Film type (2 digits from film edge code) */ |
1365 | 335 | AttributeToU8(image_info,image,"DPX:mp.film.type",cin_mp_info.film_type); |
1366 | | /* Offset in perfs (2 digits from film edge code) */ |
1367 | 335 | AttributeToU8(image_info,image,"DPX:mp.perfs.offset",cin_mp_info.perfs_offset); |
1368 | | /* Prefix (6 digits from film edge code) */ |
1369 | 335 | AttributeToU32(image_info,image,"DPX:mp.prefix",cin_mp_info.prefix); |
1370 | | /* Count (4 digits from film edge code) */ |
1371 | 335 | AttributeToU32(image_info,image,"DPX:mp.count",cin_mp_info.count); |
1372 | | /* Format -- e.g. Academy */ |
1373 | 335 | AttributeToString(image_info,image,"DPX:mp.format",cin_mp_info.format); |
1374 | | /* Frame position in sequence */ |
1375 | 335 | AttributeToU32(image_info,image,"DPX:mp.frame.position",cin_mp_info.frame_position); |
1376 | | /* Frame rate of original (frames/s) */ |
1377 | 335 | AttributeToR32(image_info,image,"DPX:mp.frame.rate",cin_mp_info.frame_rate); |
1378 | | /* Frame identification - e.g. keyframe */ |
1379 | 335 | AttributeToString(image_info,image,"DPX:mp.frame.id",cin_mp_info.frame_id); |
1380 | | /* Slate information */ |
1381 | 335 | AttributeToString(image_info,image,"DPX:mp.slate.info",cin_mp_info.slate_info); |
1382 | | |
1383 | | /* |
1384 | | Open output image file. |
1385 | | */ |
1386 | | |
1387 | 335 | status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception); |
1388 | 335 | if (status == MagickFail) |
1389 | 0 | return (status); |
1390 | | |
1391 | 335 | if (swab) |
1392 | 335 | { |
1393 | | /* |
1394 | | Swap byte order. |
1395 | | */ |
1396 | 335 | SwabCineonFileInfo(&cin_file_info); |
1397 | 335 | SwabCineonImageInfo(&cin_image_info); |
1398 | 335 | SwabCineonImageOriginationInfo(&cin_source_info); |
1399 | 335 | SwabCineonFilmInfo(&cin_mp_info); |
1400 | 335 | } |
1401 | | |
1402 | 335 | written = WriteBlob(image,sizeof(cin_file_info),&cin_file_info); |
1403 | 335 | if (written != sizeof(cin_file_info)) |
1404 | 0 | { |
1405 | 0 | CloseBlob(image); |
1406 | 0 | return (MagickFail); |
1407 | 0 | } |
1408 | 335 | offset += written; |
1409 | | |
1410 | 335 | written = WriteBlob(image,sizeof(cin_image_info),&cin_image_info); |
1411 | 335 | if (written != sizeof(cin_image_info)) |
1412 | 0 | { |
1413 | 0 | CloseBlob(image); |
1414 | 0 | return (MagickFail); |
1415 | 0 | } |
1416 | 335 | offset += written; |
1417 | | |
1418 | 335 | written = WriteBlob(image,sizeof(cin_source_info),&cin_source_info); |
1419 | 335 | if (written != sizeof(cin_source_info)) |
1420 | 0 | { |
1421 | 0 | CloseBlob(image); |
1422 | 0 | return (MagickFail); |
1423 | 0 | } |
1424 | 335 | offset += written; |
1425 | | |
1426 | 335 | written = WriteBlob(image,sizeof(cin_mp_info),&cin_mp_info); |
1427 | 335 | if (written != sizeof(cin_mp_info)) |
1428 | 0 | { |
1429 | 0 | CloseBlob(image); |
1430 | 0 | return (MagickFail); |
1431 | 0 | } |
1432 | 335 | offset += written; |
1433 | | |
1434 | 335 | if (swab) |
1435 | 335 | { |
1436 | | /* |
1437 | | Swap byte order back to original. |
1438 | | */ |
1439 | 335 | SwabCineonFileInfo(&cin_file_info); |
1440 | 335 | SwabCineonImageInfo(&cin_image_info); |
1441 | 335 | SwabCineonImageOriginationInfo(&cin_source_info); |
1442 | 335 | SwabCineonFilmInfo(&cin_mp_info); |
1443 | 335 | } |
1444 | | |
1445 | 335 | if (user_data) |
1446 | 102 | { |
1447 | 102 | written = WriteBlob(image,user_data_length,user_data); |
1448 | 102 | if (written != user_data_length) |
1449 | 0 | { |
1450 | 0 | CloseBlob(image); |
1451 | 0 | return (MagickFail); |
1452 | 0 | } |
1453 | 102 | offset += written; |
1454 | 102 | } |
1455 | | |
1456 | 335 | if (image->logging) |
1457 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1458 | 0 | "Writing Cineon pixels starting at offset %ld",(long) TellBlob(image)); |
1459 | | |
1460 | | /* |
1461 | | Convert pixel packets to CINEON raster image. |
1462 | | */ |
1463 | 335 | { |
1464 | 335 | unsigned char |
1465 | 335 | *scanline; |
1466 | | |
1467 | 335 | size_t |
1468 | 335 | scanline_bytes; |
1469 | | |
1470 | 335 | BitStreamWriteHandle |
1471 | 335 | bit_stream; |
1472 | | |
1473 | 335 | unsigned int |
1474 | 335 | red, |
1475 | 335 | green, |
1476 | 335 | blue; |
1477 | | |
1478 | 335 | unsigned int |
1479 | 335 | bits_per_sample, |
1480 | 335 | scale_from_short; |
1481 | | |
1482 | 335 | bits_per_sample = cin_image_info.channel_info[0].bits_per_sample; |
1483 | 335 | scale_from_short=(65535U / (65535U >> (16-bits_per_sample))); |
1484 | | |
1485 | 335 | scanline_bytes=MagickArraySize(image->columns,4); |
1486 | 335 | scanline=MagickAllocateResourceLimitedMemory(unsigned char *,scanline_bytes); |
1487 | 335 | if (scanline == (unsigned char *) NULL) |
1488 | 335 | ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image); |
1489 | 335 | (void) memset(scanline,0,scanline_bytes); |
1490 | | |
1491 | 111k | for (y=0; y < (long) image->rows; y++) |
1492 | 111k | { |
1493 | 111k | p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception); |
1494 | 111k | if (p == (const PixelPacket *) NULL) |
1495 | 0 | break; |
1496 | | |
1497 | 111k | MagickBitStreamInitializeWrite(&bit_stream,scanline); |
1498 | | |
1499 | 12.6M | for (x=0; x < (long) image->columns; x++) |
1500 | 12.4M | { |
1501 | 12.4M | red = ScaleQuantumToShort(p->red)/scale_from_short; |
1502 | 12.4M | green = ScaleQuantumToShort(p->green)/scale_from_short; |
1503 | 12.4M | blue = ScaleQuantumToShort(p->blue)/scale_from_short; |
1504 | | |
1505 | | /* printf("o:%u,%u,%u --> %u,%u,%u\n",(unsigned int)p->red, (unsigned int) p->green, (unsigned int) p->blue, */ |
1506 | | /* red, green, blue); */ |
1507 | | |
1508 | 12.4M | MagickBitStreamMSBWrite(&bit_stream,10,red); |
1509 | 12.4M | MagickBitStreamMSBWrite(&bit_stream,10,green); |
1510 | 12.4M | MagickBitStreamMSBWrite(&bit_stream,10,blue); |
1511 | 12.4M | MagickBitStreamMSBWrite(&bit_stream,2,0); |
1512 | 12.4M | p++; |
1513 | 12.4M | } |
1514 | 111k | written = WriteBlob(image,scanline_bytes,scanline); |
1515 | 111k | if (written != scanline_bytes) |
1516 | 34 | { |
1517 | 34 | status = MagickFail; |
1518 | 34 | break; |
1519 | 34 | } |
1520 | 111k | offset += written; |
1521 | | |
1522 | 111k | if (image->previous == (Image *) NULL) |
1523 | 111k | if (QuantumTick(y,image->rows)) |
1524 | 19.5k | if (!MagickMonitorFormatted(y,image->rows,&image->exception, |
1525 | 19.5k | SaveImageText,image->filename, |
1526 | 19.5k | image->columns,image->rows)) |
1527 | 0 | break; |
1528 | 111k | } |
1529 | 335 | MagickFreeResourceLimitedMemory(unsigned char *,scanline); |
1530 | 335 | } |
1531 | | |
1532 | 335 | if ((magick_off_t) cin_file_info.file_size != TellBlob(image)) |
1533 | 34 | { |
1534 | 34 | (void) printf("### File length %u, TellBlob says %u\n", |
1535 | 34 | cin_file_info.file_size, |
1536 | 34 | (unsigned int) TellBlob(image)); |
1537 | 34 | } |
1538 | 335 | if ((magick_off_t) offset != TellBlob(image)) |
1539 | 33 | { |
1540 | 33 | (void) printf("### Offset %lu, TellBlob says %u\n", |
1541 | 33 | (unsigned long) offset, |
1542 | 33 | (unsigned int) TellBlob(image)); |
1543 | 33 | } |
1544 | | |
1545 | 335 | status &= CloseBlob(image); |
1546 | 335 | return(status); |
1547 | 335 | } |