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