]> granicus.if.org Git - imagemagick/blob - coders/cin.c
Accommodate background color index in PLTE chunk
[imagemagick] / coders / cin.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                             CCCC  IIIII  N   N                              %
7 %                            C        I    NN  N                              %
8 %                            C        I    N N N                              %
9 %                            C        I    N  NN                              %
10 %                             CCCC  IIIII  N   N                              %
11 %                                                                             %
12 %                                                                             %
13 %                    Read/Write Kodak Cineon Image Format                     %
14 %                Cineon Image Format is a subset of SMTPE CIN                 %
15 %                                                                             %
16 %                                                                             %
17 %                              Software Design                                %
18 %                                John Cristy                                  %
19 %                             Kelly Bergougnoux                               %
20 %                               October 2003                                  %
21 %                                                                             %
22 %                                                                             %
23 %  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
24 %  dedicated to making software imaging solutions freely available.           %
25 %                                                                             %
26 %  You may not use this file except in compliance with the License.  You may  %
27 %  obtain a copy of the License at                                            %
28 %                                                                             %
29 %    http://www.imagemagick.org/script/license.php                            %
30 %                                                                             %
31 %  Unless required by applicable law or agreed to in writing, software        %
32 %  distributed under the License is distributed on an "AS IS" BASIS,          %
33 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
34 %  See the License for the specific language governing permissions and        %
35 %  limitations under the License.                                             %
36 %                                                                             %
37 %                                                                             %
38 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
39 %
40 %  Cineon image file format draft is available at
41 %  http://www.cineon.com/ff_draft.php.
42 %
43 %
44 */
45 \f
46 /*
47   Include declarations.
48 */
49 #include "MagickCore/studio.h"
50 #include "MagickCore/blob.h"
51 #include "MagickCore/blob-private.h"
52 #include "MagickCore/cache.h"
53 #include "MagickCore/colorspace.h"
54 #include "MagickCore/exception.h"
55 #include "MagickCore/exception-private.h"
56 #include "MagickCore/image.h"
57 #include "MagickCore/image-private.h"
58 #include "MagickCore/list.h"
59 #include "MagickCore/magick.h"
60 #include "MagickCore/memory_.h"
61 #include "MagickCore/monitor.h"
62 #include "MagickCore/monitor-private.h"
63 #include "MagickCore/option.h"
64 #include "MagickCore/profile.h"
65 #include "MagickCore/property.h"
66 #include "MagickCore/quantum-private.h"
67 #include "MagickCore/quantum-private.h"
68 #include "MagickCore/static.h"
69 #include "MagickCore/string_.h"
70 #include "MagickCore/string-private.h"
71 #include "MagickCore/module.h"
72 \f
73 /*
74   Typedef declaration.
75 */
76 typedef struct _CINDataFormatInfo
77 {
78   unsigned char
79     interleave,
80     packing,
81     sign,
82     sense;
83
84   size_t
85     line_pad,
86     channel_pad;
87
88   unsigned char
89     reserve[20];
90 } CINDataFormatInfo;
91
92 typedef struct _CINFileInfo
93 {
94   size_t
95     magic,
96     image_offset,
97     generic_length,
98     industry_length,
99     user_length,
100     file_size;
101
102   char
103     version[8],
104     filename[100],
105     create_date[12],
106     create_time[12],
107     reserve[36];
108 } CINFileInfo;
109
110 typedef struct _CINFilmInfo
111 {
112   char
113     id,
114     type,
115     offset,
116     reserve1;
117
118   size_t
119     prefix,
120     count;
121
122   char
123     format[32];
124
125   size_t
126     frame_position;
127
128   float
129     frame_rate;
130
131   char
132     frame_id[32],
133     slate_info[200],
134     reserve[740];
135 } CINFilmInfo;
136
137 typedef struct _CINImageChannel
138 {
139   unsigned char
140     designator[2],
141     bits_per_pixel,
142     reserve;
143
144   size_t
145     pixels_per_line,
146     lines_per_image;
147
148   float
149     min_data,
150     min_quantity,
151     max_data,
152     max_quantity;
153 } CINImageChannel;
154
155 typedef struct _CINImageInfo
156 {
157   unsigned char
158     orientation,
159     number_channels,
160     reserve1[2];
161
162   CINImageChannel
163     channel[8];
164
165   float
166     white_point[2],
167     red_primary_chromaticity[2],
168     green_primary_chromaticity[2],
169     blue_primary_chromaticity[2];
170
171   char
172     label[200],
173     reserve[28];
174 } CINImageInfo;
175
176 typedef struct _CINOriginationInfo
177 {
178   ssize_t
179     x_offset,
180     y_offset;
181
182   char
183     filename[100],
184     create_date[12],
185     create_time[12],
186     device[64],
187     model[32],
188     serial[32];
189
190   float
191     x_pitch,
192     y_pitch,
193     gamma;
194
195   char
196     reserve[40];
197 } CINOriginationInfo;
198
199 typedef struct _CINUserInfo
200 {
201   char
202     id[32];
203 } CINUserInfo;
204
205 typedef struct CINInfo
206 {
207   CINFileInfo
208     file;
209
210   CINImageInfo
211     image;
212
213   CINDataFormatInfo
214     data_format;
215
216   CINOriginationInfo
217     origination;
218
219   CINFilmInfo
220     film;
221
222   CINUserInfo
223     user;
224 } CINInfo;
225 \f
226 /*
227   Forward declaractions.
228 */
229 static MagickBooleanType
230   WriteCINImage(const ImageInfo *,Image *,ExceptionInfo *);
231 \f
232 /*
233 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
234 %                                                                             %
235 %                                                                             %
236 %                                                                             %
237 %   I s C I N E O N                                                           %
238 %                                                                             %
239 %                                                                             %
240 %                                                                             %
241 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
242 %
243 %  IsCIN() returns MagickTrue if the image format type, identified by the magick
244 %  string, is CIN.
245 %
246 %  The format of the IsCIN method is:
247 %
248 %      MagickBooleanType IsCIN(const unsigned char *magick,const size_t length)
249 %
250 %  A description of each parameter follows:
251 %
252 %    o magick: compare image format pattern against these bytes.
253 %
254 %    o length: Specifies the length of the magick string.
255 %
256 */
257 static MagickBooleanType IsCIN(const unsigned char *magick,const size_t length)
258 {
259   if (length < 4)
260     return(MagickFalse);
261   if (memcmp(magick,"\200\052\137\327",4) == 0)
262     return(MagickTrue);
263   return(MagickFalse);
264 }
265 \f
266 /*
267 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
268 %                                                                             %
269 %                                                                             %
270 %                                                                             %
271 %   R e a d C I N E O N I m a g e                                             %
272 %                                                                             %
273 %                                                                             %
274 %                                                                             %
275 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
276 %
277 %  ReadCINImage() reads an CIN X image file and returns it.  It allocates
278 %  the memory necessary for the new Image structure and returns a point to the
279 %  new image.
280 %
281 %  The format of the ReadCINImage method is:
282 %
283 %      Image *ReadCINImage(const ImageInfo *image_info,
284 %        ExceptionInfo *exception)
285 %
286 %  A description of each parameter follows:
287 %
288 %    o image_info: the image info.
289 %
290 %    o exception: return any errors or warnings in this structure.
291 %
292 */
293
294 static size_t GetBytesPerRow(size_t columns,
295   size_t samples_per_pixel,size_t bits_per_pixel,
296   MagickBooleanType pad)
297 {
298   size_t
299     bytes_per_row;
300
301   switch (bits_per_pixel)
302   {
303     case 1:
304     {
305       bytes_per_row=4*(((size_t) samples_per_pixel*columns*
306         bits_per_pixel+31)/32);
307       break;
308     }
309     case 8:
310     default:
311     {
312       bytes_per_row=4*(((size_t) samples_per_pixel*columns*
313         bits_per_pixel+31)/32);
314       break;
315     }
316     case 10:
317     {
318       if (pad == MagickFalse)
319         {
320           bytes_per_row=4*(((size_t) samples_per_pixel*columns*
321             bits_per_pixel+31)/32);
322           break;
323         }
324       bytes_per_row=4*(((size_t) (32*((samples_per_pixel*columns+2)/3))+31)/32);
325       break;
326     }
327     case 12:
328     {
329       if (pad == MagickFalse)
330         {
331           bytes_per_row=4*(((size_t) samples_per_pixel*columns*
332             bits_per_pixel+31)/32);
333           break;
334         }
335       bytes_per_row=2*(((size_t) (16*samples_per_pixel*columns)+15)/16);
336       break;
337     }
338     case 16:
339     {
340       bytes_per_row=2*(((size_t) samples_per_pixel*columns*
341         bits_per_pixel+8)/16);
342       break;
343     }
344     case 32:
345     {
346       bytes_per_row=4*(((size_t) samples_per_pixel*columns*
347         bits_per_pixel+31)/32);
348       break;
349     }
350     case 64:
351     {
352       bytes_per_row=8*(((size_t) samples_per_pixel*columns*
353         bits_per_pixel+63)/64);
354       break;
355     }
356   }
357   return(bytes_per_row);
358 }
359
360 static inline MagickBooleanType IsFloatDefined(const float value)
361 {
362   union
363   {
364     unsigned int
365       unsigned_value;
366
367     double
368       float_value;
369   } quantum;
370
371   quantum.unsigned_value=0U;
372   quantum.float_value=value;
373   if (quantum.unsigned_value == 0U)
374     return(MagickFalse);
375   return(MagickTrue);
376 }
377
378 static Image *ReadCINImage(const ImageInfo *image_info,ExceptionInfo *exception)
379 {
380 #define MonoColorType  1
381 #define RGBColorType  3
382
383   CINInfo
384     cin;
385
386   Image
387     *image;
388
389   MagickBooleanType
390     status;
391
392   MagickOffsetType
393     offset;
394
395   QuantumInfo
396     *quantum_info;
397
398   QuantumType
399     quantum_type;
400
401   register ssize_t
402     i;
403
404   register Quantum
405     *q;
406
407   size_t
408     length;
409
410   ssize_t
411     count,
412     y;
413
414   unsigned char
415     magick[4],
416     *pixels;
417
418   /*
419     Open image file.
420   */
421   assert(image_info != (const ImageInfo *) NULL);
422   assert(image_info->signature == MagickSignature);
423   if (image_info->debug != MagickFalse)
424     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
425       image_info->filename);
426   assert(exception != (ExceptionInfo *) NULL);
427   assert(exception->signature == MagickSignature);
428   image=AcquireImage(image_info,exception);
429   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
430   if (status == MagickFalse)
431     {
432       image=DestroyImageList(image);
433       return((Image *) NULL);
434     }
435   /*
436     File information.
437   */
438   offset=0;
439   count=ReadBlob(image,4,magick);
440   offset+=count;
441   if ((count != 4) ||
442       ((LocaleNCompare((char *) magick,"\200\052\137\327",4) != 0)))
443     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
444   image->endian=(magick[0] == 0x80) && (magick[1] == 0x2a) &&
445     (magick[2] == 0x5f) && (magick[3] == 0xd7) ? MSBEndian : LSBEndian;
446   cin.file.image_offset=ReadBlobLong(image);
447   offset+=4;
448   cin.file.generic_length=ReadBlobLong(image);
449   offset+=4;
450   cin.file.industry_length=ReadBlobLong(image);
451   offset+=4;
452   cin.file.user_length=ReadBlobLong(image);
453   offset+=4;
454   cin.file.file_size=ReadBlobLong(image);
455   offset+=4;
456   offset+=ReadBlob(image,sizeof(cin.file.version),(unsigned char *)
457     cin.file.version);
458   (void) SetImageProperty(image,"dpx:file.version",cin.file.version,exception);
459   offset+=ReadBlob(image,sizeof(cin.file.filename),(unsigned char *)
460     cin.file.filename);
461   (void) SetImageProperty(image,"dpx:file.filename",cin.file.filename,
462     exception);
463   offset+=ReadBlob(image,sizeof(cin.file.create_date),(unsigned char *)
464     cin.file.create_date);
465   (void) SetImageProperty(image,"dpx:file.create_date",cin.file.create_date,
466     exception);
467   offset+=ReadBlob(image,sizeof(cin.file.create_time),(unsigned char *)
468     cin.file.create_time);
469   (void) SetImageProperty(image,"dpx:file.create_time",cin.file.create_time,
470     exception);
471   offset+=ReadBlob(image,sizeof(cin.file.reserve),(unsigned char *)
472     cin.file.reserve);
473   /*
474     Image information.
475   */
476   cin.image.orientation=(unsigned char) ReadBlobByte(image);
477   offset++;
478   if (cin.image.orientation != (unsigned char) (~0U))
479     (void) FormatImageProperty(image,"dpx:image.orientation","%d",
480       cin.image.orientation);
481   switch (cin.image.orientation)
482   {
483     default:
484     case 0: image->orientation=TopLeftOrientation; break;
485     case 1: image->orientation=TopRightOrientation; break;
486     case 2: image->orientation=BottomLeftOrientation; break;
487     case 3: image->orientation=BottomRightOrientation; break;
488     case 4: image->orientation=LeftTopOrientation; break;
489     case 5: image->orientation=RightTopOrientation; break;
490     case 6: image->orientation=LeftBottomOrientation; break;
491     case 7: image->orientation=RightBottomOrientation; break;
492   }
493   cin.image.number_channels=(unsigned char) ReadBlobByte(image);
494   offset++;
495   offset+=ReadBlob(image,sizeof(cin.image.reserve1),(unsigned char *)
496     cin.image.reserve1);
497   for (i=0; i < 8; i++)
498   {
499     cin.image.channel[i].designator[0]=(unsigned char) ReadBlobByte(image);
500     offset++;
501     cin.image.channel[i].designator[1]=(unsigned char) ReadBlobByte(image);
502     offset++;
503     cin.image.channel[i].bits_per_pixel=(unsigned char) ReadBlobByte(image);
504     offset++;
505     cin.image.channel[i].reserve=(unsigned char) ReadBlobByte(image);
506     offset++;
507     cin.image.channel[i].pixels_per_line=ReadBlobLong(image);
508     offset+=4;
509     cin.image.channel[i].lines_per_image=ReadBlobLong(image);
510     offset+=4;
511     cin.image.channel[i].min_data=ReadBlobFloat(image);
512     offset+=4;
513     cin.image.channel[i].min_quantity=ReadBlobFloat(image);
514     offset+=4;
515     cin.image.channel[i].max_data=ReadBlobFloat(image);
516     offset+=4;
517     cin.image.channel[i].max_quantity=ReadBlobFloat(image);
518     offset+=4;
519   }
520   cin.image.white_point[0]=ReadBlobFloat(image);
521   offset+=4;
522   if (IsFloatDefined(cin.image.white_point[0]) != MagickFalse)
523     image->chromaticity.white_point.x=cin.image.white_point[0];
524   cin.image.white_point[1]=ReadBlobFloat(image);
525   offset+=4;
526   if (IsFloatDefined(cin.image.white_point[1]) != MagickFalse)
527     image->chromaticity.white_point.y=cin.image.white_point[1];
528   cin.image.red_primary_chromaticity[0]=ReadBlobFloat(image);
529   offset+=4;
530   if (IsFloatDefined(cin.image.red_primary_chromaticity[0]) != MagickFalse)
531     image->chromaticity.red_primary.x=cin.image.red_primary_chromaticity[0];
532   cin.image.red_primary_chromaticity[1]=ReadBlobFloat(image);
533   offset+=4;
534   if (IsFloatDefined(cin.image.red_primary_chromaticity[1]) != MagickFalse)
535     image->chromaticity.red_primary.y=cin.image.red_primary_chromaticity[1];
536   cin.image.green_primary_chromaticity[0]=ReadBlobFloat(image);
537   offset+=4;
538   if (IsFloatDefined(cin.image.green_primary_chromaticity[0]) != MagickFalse)
539     image->chromaticity.red_primary.x=cin.image.green_primary_chromaticity[0];
540   cin.image.green_primary_chromaticity[1]=ReadBlobFloat(image);
541   offset+=4;
542   if (IsFloatDefined(cin.image.green_primary_chromaticity[1]) != MagickFalse)
543     image->chromaticity.green_primary.y=cin.image.green_primary_chromaticity[1];
544   cin.image.blue_primary_chromaticity[0]=ReadBlobFloat(image);
545   offset+=4;
546   if (IsFloatDefined(cin.image.blue_primary_chromaticity[0]) != MagickFalse)
547     image->chromaticity.blue_primary.x=cin.image.blue_primary_chromaticity[0];
548   cin.image.blue_primary_chromaticity[1]=ReadBlobFloat(image);
549   offset+=4;
550   if (IsFloatDefined(cin.image.blue_primary_chromaticity[1]) != MagickFalse)
551     image->chromaticity.blue_primary.y=cin.image.blue_primary_chromaticity[1];
552   offset+=ReadBlob(image,sizeof(cin.image.label),(unsigned char *)
553     cin.image.label);
554   (void) SetImageProperty(image,"dpx:image.label",cin.image.label,exception);
555   offset+=ReadBlob(image,sizeof(cin.image.reserve),(unsigned char *)
556     cin.image.reserve);
557   /*
558     Image data format information.
559   */
560   cin.data_format.interleave=(unsigned char) ReadBlobByte(image);
561   offset++;
562   cin.data_format.packing=(unsigned char) ReadBlobByte(image);
563   offset++;
564   cin.data_format.sign=(unsigned char) ReadBlobByte(image);
565   offset++;
566   cin.data_format.sense=(unsigned char) ReadBlobByte(image);
567   offset++;
568   cin.data_format.line_pad=ReadBlobLong(image);
569   offset+=4;
570   cin.data_format.channel_pad=ReadBlobLong(image);
571   offset+=4;
572   offset+=ReadBlob(image,sizeof(cin.data_format.reserve),(unsigned char *)
573     cin.data_format.reserve);
574   /*
575     Image origination information.
576   */
577   cin.origination.x_offset=(int) ReadBlobLong(image);
578   offset+=4;
579   if ((size_t) cin.origination.x_offset != ~0UL)
580     (void) FormatImageProperty(image,"dpx:origination.x_offset","%.20g",
581       (double) cin.origination.x_offset);
582   cin.origination.y_offset=(ssize_t) ReadBlobLong(image);
583   offset+=4;
584   if ((size_t) cin.origination.y_offset != ~0UL)
585     (void) FormatImageProperty(image,"dpx:origination.y_offset","%.20g",
586       (double) cin.origination.y_offset);
587   offset+=ReadBlob(image,sizeof(cin.origination.filename),(unsigned char *)
588     cin.origination.filename);
589   (void) SetImageProperty(image,"dpx:origination.filename",
590     cin.origination.filename,exception);
591   offset+=ReadBlob(image,sizeof(cin.origination.create_date),(unsigned char *)
592     cin.origination.create_date);
593   (void) SetImageProperty(image,"dpx:origination.create_date",
594     cin.origination.create_date,exception);
595   offset+=ReadBlob(image,sizeof(cin.origination.create_time),(unsigned char *)
596     cin.origination.create_time);
597   (void) SetImageProperty(image,"dpx:origination.create_time",
598     cin.origination.create_time,exception);
599   offset+=ReadBlob(image,sizeof(cin.origination.device),(unsigned char *)
600     cin.origination.device);
601   (void) SetImageProperty(image,"dpx:origination.device",
602     cin.origination.device,exception);
603   offset+=ReadBlob(image,sizeof(cin.origination.model),(unsigned char *)
604     cin.origination.model);
605   (void) SetImageProperty(image,"dpx:origination.model",cin.origination.model,
606     exception);
607   offset+=ReadBlob(image,sizeof(cin.origination.serial),(unsigned char *)
608     cin.origination.serial);
609   (void) SetImageProperty(image,"dpx:origination.serial",
610     cin.origination.serial,exception);
611   cin.origination.x_pitch=ReadBlobFloat(image);
612   offset+=4;
613   cin.origination.y_pitch=ReadBlobFloat(image);
614   offset+=4;
615   cin.origination.gamma=ReadBlobFloat(image);
616   offset+=4;
617   if (IsFloatDefined(cin.origination.gamma) != MagickFalse)
618     image->gamma=cin.origination.gamma;
619   offset+=ReadBlob(image,sizeof(cin.origination.reserve),(unsigned char *)
620     cin.origination.reserve);
621   if ((cin.file.image_offset > 2048) && (cin.file.user_length != 0))
622     {
623       int
624         c;
625
626       /*
627         Image film information.
628       */
629       cin.film.id=ReadBlobByte(image);
630       offset++;
631       c=cin.film.id;
632       if (c != ~0)
633         (void) FormatImageProperty(image,"dpx:film.id","%d",cin.film.id);
634       cin.film.type=ReadBlobByte(image);
635       offset++;
636       c=cin.film.type;
637       if (c != ~0)
638         (void) FormatImageProperty(image,"dpx:film.type","%d",cin.film.type);
639       cin.film.offset=ReadBlobByte(image);
640       offset++;
641       c=cin.film.offset;
642       if (c != ~0)
643         (void) FormatImageProperty(image,"dpx:film.offset","%d",
644           cin.film.offset);
645       cin.film.reserve1=ReadBlobByte(image);
646       offset++;
647       cin.film.prefix=ReadBlobLong(image);
648       offset+=4;
649       if (cin.film.prefix != ~0UL)
650         (void) FormatImageProperty(image,"dpx:film.prefix","%.20g",(double)
651           cin.film.prefix);
652       cin.film.count=ReadBlobLong(image);
653       offset+=4;
654       offset+=ReadBlob(image,sizeof(cin.film.format),(unsigned char *)
655         cin.film.format);
656       (void) SetImageProperty(image,"dpx:film.format",cin.film.format,
657         exception);
658       cin.film.frame_position=ReadBlobLong(image);
659       offset+=4;
660       if (cin.film.frame_position != ~0UL)
661         (void) FormatImageProperty(image,"dpx:film.frame_position","%.20g",
662           (double) cin.film.frame_position);
663       cin.film.frame_rate=ReadBlobFloat(image);
664       offset+=4;
665       if (IsFloatDefined(cin.film.frame_rate) != MagickFalse)
666         (void) FormatImageProperty(image,"dpx:film.frame_rate","%g",
667           cin.film.frame_rate);
668       offset+=ReadBlob(image,sizeof(cin.film.frame_id),(unsigned char *)
669         cin.film.frame_id);
670       (void) SetImageProperty(image,"dpx:film.frame_id",cin.film.frame_id,
671         exception);
672       offset+=ReadBlob(image,sizeof(cin.film.slate_info),(unsigned char *)
673         cin.film.slate_info);
674       (void) SetImageProperty(image,"dpx:film.slate_info",cin.film.slate_info,
675         exception);
676       offset+=ReadBlob(image,sizeof(cin.film.reserve),(unsigned char *)
677         cin.film.reserve);
678     }
679   if ((cin.file.image_offset > 2048) && (cin.file.user_length != 0))
680     {
681       StringInfo
682         *profile;
683
684       /*
685         User defined data.
686       */
687       profile=BlobToStringInfo((const void *) NULL,cin.file.user_length);
688       if (profile == (StringInfo *) NULL)
689         ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
690       offset+=ReadBlob(image,GetStringInfoLength(profile),
691         GetStringInfoDatum(profile));
692       (void) SetImageProfile(image,"dpx:user.data",profile,exception);
693       profile=DestroyStringInfo(profile);
694     }
695   for ( ; offset < (MagickOffsetType) cin.file.image_offset; offset++)
696     (void) ReadBlobByte(image);
697   image->depth=cin.image.channel[0].bits_per_pixel;
698   image->columns=cin.image.channel[0].pixels_per_line;
699   image->rows=cin.image.channel[0].lines_per_image;
700   if (image_info->ping)
701     {
702       (void) CloseBlob(image);
703       return(image);
704     }
705   /*
706     Convert CIN raster image to pixel packets.
707   */
708   quantum_info=AcquireQuantumInfo(image_info,image);
709   if (quantum_info == (QuantumInfo *) NULL)
710     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
711   quantum_info->quantum=32;
712   quantum_info->pack=MagickFalse;
713   quantum_type=RGBQuantum;
714   pixels=GetQuantumPixels(quantum_info);
715   length=GetQuantumExtent(image,quantum_info,quantum_type);
716   length=GetBytesPerRow(image->columns,3,image->depth,MagickTrue);
717   if (cin.image.number_channels == 1)
718     {
719       quantum_type=GrayQuantum;
720       length=GetBytesPerRow(image->columns,1,image->depth,MagickTrue);
721     }
722   for (y=0; y < (ssize_t) image->rows; y++)
723   {
724     q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
725     if (q == (Quantum *) NULL)
726       break;
727     count=ReadBlob(image,length,pixels);
728     if ((size_t) count != length)
729       break;
730     (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
731       quantum_type,pixels,exception);
732     if (SyncAuthenticPixels(image,exception) == MagickFalse)
733       break;
734     if (image->previous == (Image *) NULL)
735       {
736         status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
737           image->rows);
738         if (status == MagickFalse)
739           break;
740       }
741   }
742   SetQuantumImageType(image,quantum_type);
743   quantum_info=DestroyQuantumInfo(quantum_info);
744   if (EOFBlob(image) != MagickFalse)
745     ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
746       image->filename);
747   SetImageColorspace(image,LogColorspace,exception);
748   (void) CloseBlob(image);
749   return(GetFirstImageInList(image));
750 }
751 \f
752 /*
753 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
754 %                                                                             %
755 %                                                                             %
756 %                                                                             %
757 %   R e g i s t e r C I N E O N I m a g e                                     %
758 %                                                                             %
759 %                                                                             %
760 %                                                                             %
761 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
762 %
763 %  RegisterCINImage() adds attributes for the CIN image format to the list of
764 %  of supported formats.  The attributes include the image format tag, a method
765 %  to read and/or write the format, whether the format supports the saving of
766 %  more than one frame to the same file or blob, whether the format supports
767 %  native in-memory I/O, and a brief description of the format.
768 %
769 %  The format of the RegisterCINImage method is:
770 %
771 %      size_t RegisterCINImage(void)
772 %
773 */
774 ModuleExport size_t RegisterCINImage(void)
775 {
776   MagickInfo
777     *entry;
778
779   entry=SetMagickInfo("CIN");
780   entry->decoder=(DecodeImageHandler *) ReadCINImage;
781   entry->encoder=(EncodeImageHandler *) WriteCINImage;
782   entry->magick=(IsImageFormatHandler *) IsCIN;
783   entry->adjoin=MagickFalse;
784   entry->description=ConstantString("Cineon Image File");
785   entry->module=ConstantString("CIN");
786   (void) RegisterMagickInfo(entry);
787   return(MagickImageCoderSignature);
788 }
789 \f
790 /*
791 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
792 %                                                                             %
793 %                                                                             %
794 %                                                                             %
795 %   U n r e g i s t e r C I N E O N I m a g e                                 %
796 %                                                                             %
797 %                                                                             %
798 %                                                                             %
799 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
800 %
801 %  UnregisterCINImage() removes format registrations made by the CIN module
802 %  from the list of supported formats.
803 %
804 %  The format of the UnregisterCINImage method is:
805 %
806 %      UnregisterCINImage(void)
807 %
808 */
809 ModuleExport void UnregisterCINImage(void)
810 {
811   (void) UnregisterMagickInfo("CINEON");
812 }
813 \f
814 /*
815 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
816 %                                                                             %
817 %                                                                             %
818 %                                                                             %
819 %   W r i t e C I N E O N I m a g e                                           %
820 %                                                                             %
821 %                                                                             %
822 %                                                                             %
823 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
824 %
825 %  WriteCINImage() writes an image in CIN encoded image format.
826 %
827 %  The format of the WriteCINImage method is:
828 %
829 %      MagickBooleanType WriteCINImage(const ImageInfo *image_info,
830 %        Image *image,ExceptionInfo *exception)
831 %
832 %  A description of each parameter follows.
833 %
834 %    o image_info: the image info.
835 %
836 %    o image:  The image.
837 %
838 %    o exception: return any errors or warnings in this structure.
839 %
840 */
841
842 static inline const char *GetCINProperty(const ImageInfo *image_info,
843   const Image *image,const char *property,ExceptionInfo *exception)
844 {
845   const char
846     *value;
847
848   value=GetImageOption(image_info,property);
849   if (value != (const char *) NULL)
850     return(value);
851   return(GetImageProperty(image,property,exception));
852 }
853
854 static MagickBooleanType WriteCINImage(const ImageInfo *image_info,Image *image,
855   ExceptionInfo *exception)
856 {
857   const char
858     *value;
859
860   CINInfo
861     cin;
862
863   const StringInfo
864     *profile;
865
866   MagickBooleanType
867     status;
868
869   MagickOffsetType
870     offset;
871
872   QuantumInfo
873     *quantum_info;
874
875   QuantumType
876     quantum_type;
877
878   register const Quantum
879     *p;
880
881   register ssize_t
882     i;
883
884   size_t
885     length;
886
887   ssize_t
888     count,
889     y;
890
891   struct tm
892     local_time;
893
894   time_t
895     seconds;
896
897   unsigned char
898     *pixels;
899
900   /*
901     Open output image file.
902   */
903   assert(image_info != (const ImageInfo *) NULL);
904   assert(image_info->signature == MagickSignature);
905   assert(image != (Image *) NULL);
906   assert(image->signature == MagickSignature);
907   if (image->debug != MagickFalse)
908     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
909   assert(exception != (ExceptionInfo *) NULL);
910   assert(exception->signature == MagickSignature);
911   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
912   if (status == MagickFalse)
913     return(status);
914   if (image->colorspace != LogColorspace)
915     (void) TransformImageColorspace(image,LogColorspace,exception);
916   /*
917     Write image information.
918   */
919   (void) ResetMagickMemory(&cin,0,sizeof(cin));
920   offset=0;
921   cin.file.magic=0x802A5FD7UL;
922   offset+=WriteBlobLong(image,(unsigned int) cin.file.magic);
923   cin.file.image_offset=0x800;
924   offset+=WriteBlobLong(image,(unsigned int) cin.file.image_offset);
925   cin.file.generic_length=0x400;
926   offset+=WriteBlobLong(image,(unsigned int) cin.file.generic_length);
927   cin.file.industry_length=0x400;
928   offset+=WriteBlobLong(image,(unsigned int) cin.file.industry_length);
929   cin.file.user_length=0x00;
930   profile=GetImageProfile(image,"dpx:user.data");
931   if (profile != (StringInfo *) NULL)
932     {
933       cin.file.user_length+=(size_t) GetStringInfoLength(profile);
934       cin.file.user_length=(((cin.file.user_length+0x2000-1)/0x2000)*0x2000);
935     }
936   offset+=WriteBlobLong(image,(unsigned int) cin.file.user_length);
937   cin.file.file_size=4*image->columns*image->rows+0x2000;
938   offset+=WriteBlobLong(image,(unsigned int) cin.file.file_size);
939   (void) CopyMagickString(cin.file.version,"V4.5",sizeof(cin.file.version));
940   offset+=WriteBlob(image,sizeof(cin.file.version),(unsigned char *)
941     cin.file.version);
942   value=GetCINProperty(image_info,image,"dpx:file.filename",exception);
943   if (value != (const char *) NULL)
944     (void) CopyMagickString(cin.file.filename,value,sizeof(cin.file.filename));
945   else
946     (void) CopyMagickString(cin.file.filename,image->filename,
947       sizeof(cin.file.filename));
948   offset+=WriteBlob(image,sizeof(cin.file.filename),(unsigned char *)
949     cin.file.filename);
950   seconds=time((time_t *) NULL);
951 #if defined(MAGICKCORE_HAVE_LOCALTIME_R)
952   (void) localtime_r(&seconds,&local_time);
953 #else
954   (void) memcpy(&local_time,localtime(&seconds),sizeof(local_time));
955 #endif
956   (void) strftime(cin.file.create_date,sizeof(cin.file.create_date),"%Y:%m:%d",
957     &local_time);
958   offset+=WriteBlob(image,sizeof(cin.file.create_date),(unsigned char *)
959     cin.file.create_date);
960   (void) strftime(cin.file.create_time,sizeof(cin.file.create_time),
961     "%H:%M:%S%Z",&local_time);
962   offset+=WriteBlob(image,sizeof(cin.file.create_time),(unsigned char *)
963     cin.file.create_time);
964   offset+=WriteBlob(image,sizeof(cin.file.reserve),(unsigned char *)
965     cin.file.reserve);
966   cin.image.orientation=0x00;
967   offset+=WriteBlobByte(image,cin.image.orientation);
968   cin.image.number_channels=3;
969   offset+=WriteBlobByte(image,cin.image.number_channels);
970   offset+=WriteBlob(image,sizeof(cin.image.reserve1),(unsigned char *)
971     cin.image.reserve1);
972   for (i=0; i < 8; i++)
973   {
974     cin.image.channel[i].designator[0]=0; /* universal metric */
975     offset+=WriteBlobByte(image,cin.image.channel[0].designator[0]);
976     cin.image.channel[i].designator[1]=(unsigned char) (i > 3 ? 0 : i+1); /* channel color */;
977     offset+=WriteBlobByte(image,cin.image.channel[1].designator[0]);
978     cin.image.channel[i].bits_per_pixel=(unsigned char) image->depth;
979     offset+=WriteBlobByte(image,cin.image.channel[0].bits_per_pixel);
980     offset+=WriteBlobByte(image,cin.image.channel[0].reserve);
981     cin.image.channel[i].pixels_per_line=image->columns;
982     offset+=WriteBlobLong(image,(unsigned int)
983       cin.image.channel[0].pixels_per_line);
984     cin.image.channel[i].lines_per_image=image->rows;
985     offset+=WriteBlobLong(image,(unsigned int)
986       cin.image.channel[0].lines_per_image);
987     cin.image.channel[i].min_data=0;
988     offset+=WriteBlobFloat(image,cin.image.channel[0].min_data);
989     cin.image.channel[i].min_quantity=0.0;
990     offset+=WriteBlobFloat(image,cin.image.channel[0].min_quantity);
991     cin.image.channel[i].max_data=(float) ((MagickOffsetType)
992       GetQuantumRange(image->depth));
993     offset+=WriteBlobFloat(image,cin.image.channel[0].max_data);
994     cin.image.channel[i].max_quantity=2.048f;
995     offset+=WriteBlobFloat(image,cin.image.channel[0].max_quantity);
996   }
997   offset+=WriteBlobFloat(image,image->chromaticity.white_point.x);
998   offset+=WriteBlobFloat(image,image->chromaticity.white_point.y);
999   offset+=WriteBlobFloat(image,image->chromaticity.red_primary.x);
1000   offset+=WriteBlobFloat(image,image->chromaticity.red_primary.y);
1001   offset+=WriteBlobFloat(image,image->chromaticity.green_primary.x);
1002   offset+=WriteBlobFloat(image,image->chromaticity.green_primary.y);
1003   offset+=WriteBlobFloat(image,image->chromaticity.blue_primary.x);
1004   offset+=WriteBlobFloat(image,image->chromaticity.blue_primary.y);
1005   value=GetCINProperty(image_info,image,"dpx:image.label",exception);
1006   if (value != (const char *) NULL)
1007     (void) CopyMagickString(cin.image.label,value,sizeof(cin.image.label));
1008   offset+=WriteBlob(image,sizeof(cin.image.label),(unsigned char *)
1009     cin.image.label);
1010   offset+=WriteBlob(image,sizeof(cin.image.reserve),(unsigned char *)
1011     cin.image.reserve);
1012   /*
1013     Write data format information.
1014   */
1015   cin.data_format.interleave=0; /* pixel interleave (rgbrgbr...) */
1016   offset+=WriteBlobByte(image,cin.data_format.interleave);
1017   cin.data_format.packing=5; /* packing ssize_tword (32bit) boundaries */
1018   offset+=WriteBlobByte(image,cin.data_format.packing);
1019   cin.data_format.sign=0; /* unsigned data */
1020   offset+=WriteBlobByte(image,cin.data_format.sign);
1021   cin.data_format.sense=0; /* image sense: positive image */
1022   offset+=WriteBlobByte(image,cin.data_format.sense);
1023   cin.data_format.line_pad=0;
1024   offset+=WriteBlobLong(image,(unsigned int) cin.data_format.line_pad);
1025   cin.data_format.channel_pad=0;
1026   offset+=WriteBlobLong(image,(unsigned int) cin.data_format.channel_pad);
1027   offset+=WriteBlob(image,sizeof(cin.data_format.reserve),(unsigned char *)
1028     cin.data_format.reserve);
1029   /*
1030     Write origination information.
1031   */
1032   cin.origination.x_offset=0UL;
1033   value=GetCINProperty(image_info,image,"dpx:origination.x_offset",exception);
1034   if (value != (const char *) NULL)
1035     cin.origination.x_offset=(ssize_t) StringToLong(value);
1036   offset+=WriteBlobLong(image,(unsigned int) cin.origination.x_offset);
1037   cin.origination.y_offset=0UL;
1038   value=GetCINProperty(image_info,image,"dpx:origination.y_offset",exception);
1039   if (value != (const char *) NULL)
1040     cin.origination.y_offset=(ssize_t) StringToLong(value);
1041   offset+=WriteBlobLong(image,(unsigned int) cin.origination.y_offset);
1042   value=GetCINProperty(image_info,image,"dpx:origination.filename",exception);
1043   if (value != (const char *) NULL)
1044     (void) CopyMagickString(cin.origination.filename,value,
1045       sizeof(cin.origination.filename));
1046   else
1047     (void) CopyMagickString(cin.origination.filename,image->filename,
1048       sizeof(cin.origination.filename));
1049   offset+=WriteBlob(image,sizeof(cin.origination.filename),(unsigned char *)
1050     cin.origination.filename);
1051   seconds=time((time_t *) NULL);
1052   (void) strftime(cin.origination.create_date,
1053     sizeof(cin.origination.create_date),"%Y:%m:%d",&local_time);
1054   offset+=WriteBlob(image,sizeof(cin.origination.create_date),(unsigned char *)
1055     cin.origination.create_date);
1056   (void) strftime(cin.origination.create_time,
1057     sizeof(cin.origination.create_time),"%H:%M:%S%Z",&local_time);
1058   offset+=WriteBlob(image,sizeof(cin.origination.create_time),(unsigned char *)
1059     cin.origination.create_time);
1060   value=GetCINProperty(image_info,image,"dpx:origination.device",exception);
1061   if (value != (const char *) NULL)
1062     (void) CopyMagickString(cin.origination.device,value,
1063       sizeof(cin.origination.device));
1064   offset+=WriteBlob(image,sizeof(cin.origination.device),(unsigned char *)
1065     cin.origination.device);
1066   value=GetCINProperty(image_info,image,"dpx:origination.model",exception);
1067   if (value != (const char *) NULL)
1068     (void) CopyMagickString(cin.origination.model,value,
1069       sizeof(cin.origination.model));
1070   offset+=WriteBlob(image,sizeof(cin.origination.model),(unsigned char *)
1071     cin.origination.model);
1072   value=GetCINProperty(image_info,image,"dpx:origination.serial",exception);
1073   if (value != (const char *) NULL)
1074     (void) CopyMagickString(cin.origination.serial,value,
1075       sizeof(cin.origination.serial));
1076   offset+=WriteBlob(image,sizeof(cin.origination.serial),(unsigned char *)
1077     cin.origination.serial);
1078   cin.origination.x_pitch=0.0f;
1079   value=GetCINProperty(image_info,image,"dpx:origination.x_pitch",exception);
1080   if (value != (const char *) NULL)
1081     cin.origination.x_pitch=StringToDouble(value,(char **) NULL);
1082   offset+=WriteBlobFloat(image,cin.origination.x_pitch);
1083   cin.origination.y_pitch=0.0f;
1084   value=GetCINProperty(image_info,image,"dpx:origination.y_pitch",exception);
1085   if (value != (const char *) NULL)
1086     cin.origination.y_pitch=StringToDouble(value,(char **) NULL);
1087   offset+=WriteBlobFloat(image,cin.origination.y_pitch);
1088   cin.origination.gamma=image->gamma;
1089   offset+=WriteBlobFloat(image,cin.origination.gamma);
1090   offset+=WriteBlob(image,sizeof(cin.origination.reserve),(unsigned char *)
1091     cin.origination.reserve);
1092   /*
1093     Image film information.
1094   */
1095   cin.film.id=0;
1096   value=GetCINProperty(image_info,image,"dpx:film.id",exception);
1097   if (value != (const char *) NULL)
1098     cin.film.id=(char) StringToLong(value);
1099   offset+=WriteBlobByte(image,(unsigned char) cin.film.id);
1100   cin.film.type=0;
1101   value=GetCINProperty(image_info,image,"dpx:film.type",exception);
1102   if (value != (const char *) NULL)
1103     cin.film.type=(char) StringToLong(value);
1104   offset+=WriteBlobByte(image,(unsigned char) cin.film.type);
1105   cin.film.offset=0;
1106   value=GetCINProperty(image_info,image,"dpx:film.offset",exception);
1107   if (value != (const char *) NULL)
1108     cin.film.offset=(char) StringToLong(value);
1109   offset+=WriteBlobByte(image,(unsigned char) cin.film.offset);
1110   offset+=WriteBlobByte(image,(unsigned char) cin.film.reserve1);
1111   cin.film.prefix=0UL;
1112   value=GetCINProperty(image_info,image,"dpx:film.prefix",exception);
1113   if (value != (const char *) NULL)
1114     cin.film.prefix=StringToUnsignedLong(value);
1115   offset+=WriteBlobLong(image,(unsigned int) cin.film.prefix);
1116   cin.film.count=0UL;
1117   value=GetCINProperty(image_info,image,"dpx:film.count",exception);
1118   if (value != (const char *) NULL)
1119     cin.film.count=StringToUnsignedLong(value);
1120   offset+=WriteBlobLong(image,(unsigned int) cin.film.count);
1121   value=GetCINProperty(image_info,image,"dpx:film.format",exception);
1122   if (value != (const char *) NULL)
1123     (void) CopyMagickString(cin.film.format,value,sizeof(cin.film.format));
1124   offset+=WriteBlob(image,sizeof(cin.film.format),(unsigned char *)
1125     cin.film.format);
1126   cin.film.frame_position=0UL;
1127   value=GetCINProperty(image_info,image,"dpx:film.frame_position",exception);
1128   if (value != (const char *) NULL)
1129     cin.film.frame_position=StringToUnsignedLong(value);
1130   offset+=WriteBlobLong(image,(unsigned int) cin.film.frame_position);
1131   cin.film.frame_rate=0.0f;
1132   value=GetCINProperty(image_info,image,"dpx:film.frame_rate",exception);
1133   if (value != (const char *) NULL)
1134     cin.film.frame_rate=StringToDouble(value,(char **) NULL);
1135   offset+=WriteBlobFloat(image,cin.film.frame_rate);
1136   value=GetCINProperty(image_info,image,"dpx:film.frame_id",exception);
1137   if (value != (const char *) NULL)
1138     (void) CopyMagickString(cin.film.frame_id,value,sizeof(cin.film.frame_id));
1139   offset+=WriteBlob(image,sizeof(cin.film.frame_id),(unsigned char *)
1140     cin.film.frame_id);
1141   value=GetCINProperty(image_info,image,"dpx:film.slate_info",exception);
1142   if (value != (const char *) NULL)
1143     (void) CopyMagickString(cin.film.slate_info,value,
1144       sizeof(cin.film.slate_info));
1145   offset+=WriteBlob(image,sizeof(cin.film.slate_info),(unsigned char *)
1146     cin.film.slate_info);
1147   offset+=WriteBlob(image,sizeof(cin.film.reserve),(unsigned char *)
1148     cin.film.reserve);
1149   if (profile != (StringInfo *) NULL)
1150     offset+=WriteBlob(image,GetStringInfoLength(profile),
1151       GetStringInfoDatum(profile));
1152   while (offset < (MagickOffsetType) cin.file.image_offset)
1153     offset+=WriteBlobByte(image,0x00);
1154   /*
1155     Convert pixel packets to CIN raster image.
1156   */
1157   quantum_info=AcquireQuantumInfo(image_info,image);
1158   if (quantum_info == (QuantumInfo *) NULL)
1159     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1160   quantum_info->quantum=32;
1161   quantum_info->pack=MagickFalse;
1162   quantum_type=RGBQuantum;
1163   pixels=GetQuantumPixels(quantum_info);
1164   length=GetBytesPerRow(image->columns,3,image->depth,MagickTrue);
1165   if (0)
1166     {
1167       quantum_type=GrayQuantum;
1168       length=GetBytesPerRow(image->columns,1,image->depth,MagickTrue);
1169     }
1170   for (y=0; y < (ssize_t) image->rows; y++)
1171   {
1172     p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1173     if (p == (const Quantum *) NULL)
1174       break;
1175     (void) ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1176       quantum_type,pixels,exception);
1177     count=WriteBlob(image,length,pixels);
1178     if (count != (ssize_t) length)
1179       break;
1180     status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1181       image->rows);
1182     if (status == MagickFalse)
1183       break;
1184   }
1185   quantum_info=DestroyQuantumInfo(quantum_info);
1186   (void) CloseBlob(image);
1187   return(status);
1188 }