• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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-2020 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/module.h"
63 #include "MagickCore/monitor.h"
64 #include "MagickCore/monitor-private.h"
65 #include "MagickCore/option.h"
66 #include "MagickCore/profile.h"
67 #include "MagickCore/property.h"
68 #include "MagickCore/quantum-private.h"
69 #include "MagickCore/quantum-private.h"
70 #include "MagickCore/static.h"
71 #include "MagickCore/string_.h"
72 #include "MagickCore/string-private.h"
73 #include "MagickCore/timer-private.h"
74 
75 /*
76   Typedef declaration.
77 */
78 typedef struct _CINDataFormatInfo
79 {
80   unsigned char
81     interleave,
82     packing,
83     sign,
84     sense;
85 
86   size_t
87     line_pad,
88     channel_pad;
89 
90   unsigned char
91     reserve[20];
92 } CINDataFormatInfo;
93 
94 typedef struct _CINFileInfo
95 {
96   size_t
97     magic,
98     image_offset,
99     generic_length,
100     industry_length,
101     user_length,
102     file_size;
103 
104   char
105     version[8],
106     filename[100],
107     create_date[12],
108     create_time[12],
109     reserve[36];
110 } CINFileInfo;
111 
112 typedef struct _CINFilmInfo
113 {
114   char
115     id,
116     type,
117     offset,
118     reserve1;
119 
120   size_t
121     prefix,
122     count;
123 
124   char
125     format[32];
126 
127   size_t
128     frame_position;
129 
130   float
131     frame_rate;
132 
133   char
134     frame_id[32],
135     slate_info[200],
136     reserve[740];
137 } CINFilmInfo;
138 
139 typedef struct _CINImageChannel
140 {
141   unsigned char
142     designator[2],
143     bits_per_pixel,
144     reserve;
145 
146   size_t
147     pixels_per_line,
148     lines_per_image;
149 
150   float
151     min_data,
152     min_quantity,
153     max_data,
154     max_quantity;
155 } CINImageChannel;
156 
157 typedef struct _CINImageInfo
158 {
159   unsigned char
160     orientation,
161     number_channels,
162     reserve1[2];
163 
164   CINImageChannel
165     channel[8];
166 
167   float
168     white_point[2],
169     red_primary_chromaticity[2],
170     green_primary_chromaticity[2],
171     blue_primary_chromaticity[2];
172 
173   char
174     label[200],
175     reserve[28];
176 } CINImageInfo;
177 
178 typedef struct _CINOriginationInfo
179 {
180   ssize_t
181     x_offset,
182     y_offset;
183 
184   char
185     filename[100],
186     create_date[12],
187     create_time[12],
188     device[64],
189     model[32],
190     serial[32];
191 
192   float
193     x_pitch,
194     y_pitch,
195     gamma;
196 
197   char
198     reserve[40];
199 } CINOriginationInfo;
200 
201 typedef struct _CINUserInfo
202 {
203   char
204     id[32];
205 } CINUserInfo;
206 
207 typedef struct CINInfo
208 {
209   CINFileInfo
210     file;
211 
212   CINImageInfo
213     image;
214 
215   CINDataFormatInfo
216     data_format;
217 
218   CINOriginationInfo
219     origination;
220 
221   CINFilmInfo
222     film;
223 
224   CINUserInfo
225     user;
226 } CINInfo;
227 
228 /*
229   Forward declaractions.
230 */
231 static MagickBooleanType
232   WriteCINImage(const ImageInfo *,Image *,ExceptionInfo *);
233 
234 /*
235 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
236 %                                                                             %
237 %                                                                             %
238 %                                                                             %
239 %   I s C I N E O N                                                           %
240 %                                                                             %
241 %                                                                             %
242 %                                                                             %
243 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
244 %
245 %  IsCIN() returns MagickTrue if the image format type, identified by the magick
246 %  string, is CIN.
247 %
248 %  The format of the IsCIN method is:
249 %
250 %      MagickBooleanType IsCIN(const unsigned char *magick,const size_t length)
251 %
252 %  A description of each parameter follows:
253 %
254 %    o magick: compare image format pattern against these bytes.
255 %
256 %    o length: Specifies the length of the magick string.
257 %
258 */
IsCIN(const unsigned char * magick,const size_t length)259 static MagickBooleanType IsCIN(const unsigned char *magick,const size_t length)
260 {
261   if (length < 4)
262     return(MagickFalse);
263   if (memcmp(magick,"\200\052\137\327",4) == 0)
264     return(MagickTrue);
265   return(MagickFalse);
266 }
267 
268 /*
269 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
270 %                                                                             %
271 %                                                                             %
272 %                                                                             %
273 %   R e a d C I N E O N I m a g e                                             %
274 %                                                                             %
275 %                                                                             %
276 %                                                                             %
277 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
278 %
279 %  ReadCINImage() reads an CIN X image file and returns it.  It allocates
280 %  the memory necessary for the new Image structure and returns a point to the
281 %  new image.
282 %
283 %  The format of the ReadCINImage method is:
284 %
285 %      Image *ReadCINImage(const ImageInfo *image_info,
286 %        ExceptionInfo *exception)
287 %
288 %  A description of each parameter follows:
289 %
290 %    o image_info: the image info.
291 %
292 %    o exception: return any errors or warnings in this structure.
293 %
294 */
295 
GetBytesPerRow(size_t columns,size_t samples_per_pixel,size_t bits_per_pixel,MagickBooleanType pad)296 static size_t GetBytesPerRow(size_t columns,
297   size_t samples_per_pixel,size_t bits_per_pixel,
298   MagickBooleanType pad)
299 {
300   size_t
301     bytes_per_row;
302 
303   switch (bits_per_pixel)
304   {
305     case 1:
306     {
307       bytes_per_row=4*(((size_t) samples_per_pixel*columns*
308         bits_per_pixel+31)/32);
309       break;
310     }
311     case 8:
312     default:
313     {
314       bytes_per_row=4*(((size_t) samples_per_pixel*columns*
315         bits_per_pixel+31)/32);
316       break;
317     }
318     case 10:
319     {
320       if (pad == MagickFalse)
321         {
322           bytes_per_row=4*(((size_t) samples_per_pixel*columns*
323             bits_per_pixel+31)/32);
324           break;
325         }
326       bytes_per_row=4*(((size_t) (32*((samples_per_pixel*columns+2)/3))+31)/32);
327       break;
328     }
329     case 12:
330     {
331       if (pad == MagickFalse)
332         {
333           bytes_per_row=4*(((size_t) samples_per_pixel*columns*
334             bits_per_pixel+31)/32);
335           break;
336         }
337       bytes_per_row=2*(((size_t) (16*samples_per_pixel*columns)+15)/16);
338       break;
339     }
340     case 16:
341     {
342       bytes_per_row=2*(((size_t) samples_per_pixel*columns*
343         bits_per_pixel+8)/16);
344       break;
345     }
346     case 32:
347     {
348       bytes_per_row=4*(((size_t) samples_per_pixel*columns*
349         bits_per_pixel+31)/32);
350       break;
351     }
352     case 64:
353     {
354       bytes_per_row=8*(((size_t) samples_per_pixel*columns*
355         bits_per_pixel+63)/64);
356       break;
357     }
358   }
359   return(bytes_per_row);
360 }
361 
IsFloatDefined(const float value)362 static inline MagickBooleanType IsFloatDefined(const float value)
363 {
364   union
365   {
366     unsigned int
367       unsigned_value;
368 
369     double
370       float_value;
371   } quantum;
372 
373   quantum.unsigned_value=0U;
374   quantum.float_value=value;
375   if (quantum.unsigned_value == 0U)
376     return(MagickFalse);
377   return(MagickTrue);
378 }
379 
ReadCINImage(const ImageInfo * image_info,ExceptionInfo * exception)380 static Image *ReadCINImage(const ImageInfo *image_info,ExceptionInfo *exception)
381 {
382 #define MonoColorType  1
383 #define RGBColorType  3
384 
385   char
386     property[MagickPathExtent];
387 
388   CINInfo
389     cin;
390 
391   Image
392     *image;
393 
394   MagickBooleanType
395     status;
396 
397   MagickOffsetType
398     offset;
399 
400   QuantumInfo
401     *quantum_info;
402 
403   QuantumType
404     quantum_type;
405 
406   register ssize_t
407     i;
408 
409   register Quantum
410     *q;
411 
412   size_t
413     length;
414 
415   ssize_t
416     count,
417     y;
418 
419   unsigned char
420     magick[4],
421     *pixels;
422 
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   pixels=GetQuantumPixels(quantum_info);
763   for (y=0; y < (ssize_t) image->rows; y++)
764   {
765     const void
766       *stream;
767 
768     q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
769     if (q == (Quantum *) NULL)
770       break;
771     stream=ReadBlobStream(image,length,pixels,&count);
772     if ((size_t) count != length)
773       break;
774     (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
775       quantum_type,(unsigned char *) stream,exception);
776     if (SyncAuthenticPixels(image,exception) == MagickFalse)
777       break;
778     if (image->previous == (Image *) NULL)
779       {
780         status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
781           image->rows);
782         if (status == MagickFalse)
783           break;
784       }
785   }
786   SetQuantumImageType(image,quantum_type);
787   quantum_info=DestroyQuantumInfo(quantum_info);
788   if (EOFBlob(image) != MagickFalse)
789     ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
790       image->filename);
791   SetImageColorspace(image,LogColorspace,exception);
792   (void) CloseBlob(image);
793   return(GetFirstImageInList(image));
794 }
795 
796 /*
797 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
798 %                                                                             %
799 %                                                                             %
800 %                                                                             %
801 %   R e g i s t e r C I N E O N I m a g e                                     %
802 %                                                                             %
803 %                                                                             %
804 %                                                                             %
805 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
806 %
807 %  RegisterCINImage() adds attributes for the CIN image format to the list of
808 %  of supported formats.  The attributes include the image format tag, a method
809 %  to read and/or write the format, whether the format supports the saving of
810 %  more than one frame to the same file or blob, whether the format supports
811 %  native in-memory I/O, and a brief description of the format.
812 %
813 %  The format of the RegisterCINImage method is:
814 %
815 %      size_t RegisterCINImage(void)
816 %
817 */
RegisterCINImage(void)818 ModuleExport size_t RegisterCINImage(void)
819 {
820   MagickInfo
821     *entry;
822 
823   entry=AcquireMagickInfo("CIN","CIN","Cineon Image File");
824   entry->decoder=(DecodeImageHandler *) ReadCINImage;
825   entry->encoder=(EncodeImageHandler *) WriteCINImage;
826   entry->magick=(IsImageFormatHandler *) IsCIN;
827   entry->flags|=CoderDecoderSeekableStreamFlag;
828   entry->flags^=CoderAdjoinFlag;
829   (void) RegisterMagickInfo(entry);
830   return(MagickImageCoderSignature);
831 }
832 
833 /*
834 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
835 %                                                                             %
836 %                                                                             %
837 %                                                                             %
838 %   U n r e g i s t e r C I N E O N I m a g e                                 %
839 %                                                                             %
840 %                                                                             %
841 %                                                                             %
842 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
843 %
844 %  UnregisterCINImage() removes format registrations made by the CIN module
845 %  from the list of supported formats.
846 %
847 %  The format of the UnregisterCINImage method is:
848 %
849 %      UnregisterCINImage(void)
850 %
851 */
UnregisterCINImage(void)852 ModuleExport void UnregisterCINImage(void)
853 {
854   (void) UnregisterMagickInfo("CINEON");
855 }
856 
857 /*
858 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
859 %                                                                             %
860 %                                                                             %
861 %                                                                             %
862 %   W r i t e C I N E O N I m a g e                                           %
863 %                                                                             %
864 %                                                                             %
865 %                                                                             %
866 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
867 %
868 %  WriteCINImage() writes an image in CIN encoded image format.
869 %
870 %  The format of the WriteCINImage method is:
871 %
872 %      MagickBooleanType WriteCINImage(const ImageInfo *image_info,
873 %        Image *image,ExceptionInfo *exception)
874 %
875 %  A description of each parameter follows.
876 %
877 %    o image_info: the image info.
878 %
879 %    o image:  The image.
880 %
881 %    o exception: return any errors or warnings in this structure.
882 %
883 */
884 
GetCINProperty(const ImageInfo * image_info,const Image * image,const char * property,ExceptionInfo * exception)885 static inline const char *GetCINProperty(const ImageInfo *image_info,
886   const Image *image,const char *property,ExceptionInfo *exception)
887 {
888   const char
889     *value;
890 
891   value=GetImageOption(image_info,property);
892   if (value != (const char *) NULL)
893     return(value);
894   return(GetImageProperty(image,property,exception));
895 }
896 
WriteCINImage(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)897 static MagickBooleanType WriteCINImage(const ImageInfo *image_info,Image *image,
898   ExceptionInfo *exception)
899 {
900   char
901     timestamp[MagickPathExtent];
902 
903   const char
904     *value;
905 
906   CINInfo
907     cin;
908 
909   const StringInfo
910     *profile;
911 
912   MagickBooleanType
913     status;
914 
915   MagickOffsetType
916     offset;
917 
918   QuantumInfo
919     *quantum_info;
920 
921   QuantumType
922     quantum_type;
923 
924   register const Quantum
925     *p;
926 
927   register ssize_t
928     i;
929 
930   size_t
931     length;
932 
933   ssize_t
934     count,
935     y;
936 
937   struct tm
938     utc_time;
939 
940   time_t
941     seconds;
942 
943   unsigned char
944     *pixels;
945 
946   /*
947     Open output image file.
948   */
949   assert(image_info != (const ImageInfo *) NULL);
950   assert(image_info->signature == MagickCoreSignature);
951   assert(image != (Image *) NULL);
952   assert(image->signature == MagickCoreSignature);
953   if (image->debug != MagickFalse)
954     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
955   assert(exception != (ExceptionInfo *) NULL);
956   assert(exception->signature == MagickCoreSignature);
957   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
958   if (status == MagickFalse)
959     return(status);
960   if (image->colorspace != LogColorspace)
961     (void) TransformImageColorspace(image,LogColorspace,exception);
962   /*
963     Write image information.
964   */
965   (void) memset(&cin,0,sizeof(cin));
966   offset=0;
967   cin.file.magic=0x802A5FD7UL;
968   offset+=WriteBlobLong(image,(unsigned int) cin.file.magic);
969   cin.file.image_offset=0x800;
970   offset+=WriteBlobLong(image,(unsigned int) cin.file.image_offset);
971   cin.file.generic_length=0x400;
972   offset+=WriteBlobLong(image,(unsigned int) cin.file.generic_length);
973   cin.file.industry_length=0x400;
974   offset+=WriteBlobLong(image,(unsigned int) cin.file.industry_length);
975   cin.file.user_length=0x00;
976   profile=GetImageProfile(image,"dpx:user.data");
977   if (profile != (StringInfo *) NULL)
978     {
979       cin.file.user_length+=(size_t) GetStringInfoLength(profile);
980       cin.file.user_length=(((cin.file.user_length+0x2000-1)/0x2000)*0x2000);
981     }
982   offset+=WriteBlobLong(image,(unsigned int) cin.file.user_length);
983   cin.file.file_size=4*image->columns*image->rows+0x2000;
984   offset+=WriteBlobLong(image,(unsigned int) cin.file.file_size);
985   (void) CopyMagickString(cin.file.version,"V4.5",sizeof(cin.file.version));
986   offset+=WriteBlob(image,sizeof(cin.file.version),(unsigned char *)
987     cin.file.version);
988   value=GetCINProperty(image_info,image,"dpx:file.filename",exception);
989   if (value != (const char *) NULL)
990     (void) CopyMagickString(cin.file.filename,value,sizeof(cin.file.filename));
991   else
992     (void) CopyMagickString(cin.file.filename,image->filename,
993       sizeof(cin.file.filename));
994   offset+=WriteBlob(image,sizeof(cin.file.filename),(unsigned char *)
995     cin.file.filename);
996   seconds=GetMagickTime();
997   GetMagickUTCtime(&seconds,&utc_time);
998   (void) memset(timestamp,0,sizeof(timestamp));
999   (void) strftime(timestamp,MaxTextExtent,"%Y:%m:%d:%H:%M:%SUTC",&utc_time);
1000   (void) memset(cin.file.create_date,0,sizeof(cin.file.create_date));
1001   (void) CopyMagickString(cin.file.create_date,timestamp,11);
1002   offset+=WriteBlob(image,sizeof(cin.file.create_date),(unsigned char *)
1003     cin.file.create_date);
1004   (void) memset(cin.file.create_time,0,sizeof(cin.file.create_time));
1005   (void) CopyMagickString(cin.file.create_time,timestamp+11,11);
1006   offset+=WriteBlob(image,sizeof(cin.file.create_time),(unsigned char *)
1007     cin.file.create_time);
1008   offset+=WriteBlob(image,sizeof(cin.file.reserve),(unsigned char *)
1009     cin.file.reserve);
1010   cin.image.orientation=0x00;
1011   offset+=WriteBlobByte(image,cin.image.orientation);
1012   cin.image.number_channels=3;
1013   offset+=WriteBlobByte(image,cin.image.number_channels);
1014   offset+=WriteBlob(image,sizeof(cin.image.reserve1),(unsigned char *)
1015     cin.image.reserve1);
1016   for (i=0; i < 8; i++)
1017   {
1018     cin.image.channel[i].designator[0]=0; /* universal metric */
1019     offset+=WriteBlobByte(image,cin.image.channel[0].designator[0]);
1020     cin.image.channel[i].designator[1]=(unsigned char) (i > 3 ? 0 : i+1); /* channel color */;
1021     offset+=WriteBlobByte(image,cin.image.channel[1].designator[0]);
1022     cin.image.channel[i].bits_per_pixel=(unsigned char) image->depth;
1023     offset+=WriteBlobByte(image,cin.image.channel[0].bits_per_pixel);
1024     offset+=WriteBlobByte(image,cin.image.channel[0].reserve);
1025     cin.image.channel[i].pixels_per_line=image->columns;
1026     offset+=WriteBlobLong(image,(unsigned int)
1027       cin.image.channel[0].pixels_per_line);
1028     cin.image.channel[i].lines_per_image=image->rows;
1029     offset+=WriteBlobLong(image,(unsigned int)
1030       cin.image.channel[0].lines_per_image);
1031     cin.image.channel[i].min_data=0;
1032     offset+=WriteBlobFloat(image,cin.image.channel[0].min_data);
1033     cin.image.channel[i].min_quantity=0.0;
1034     offset+=WriteBlobFloat(image,cin.image.channel[0].min_quantity);
1035     cin.image.channel[i].max_data=(float) ((MagickOffsetType)
1036       GetQuantumRange(image->depth));
1037     offset+=WriteBlobFloat(image,cin.image.channel[0].max_data);
1038     cin.image.channel[i].max_quantity=2.048f;
1039     offset+=WriteBlobFloat(image,cin.image.channel[0].max_quantity);
1040   }
1041   offset+=WriteBlobFloat(image,image->chromaticity.white_point.x);
1042   offset+=WriteBlobFloat(image,image->chromaticity.white_point.y);
1043   offset+=WriteBlobFloat(image,image->chromaticity.red_primary.x);
1044   offset+=WriteBlobFloat(image,image->chromaticity.red_primary.y);
1045   offset+=WriteBlobFloat(image,image->chromaticity.green_primary.x);
1046   offset+=WriteBlobFloat(image,image->chromaticity.green_primary.y);
1047   offset+=WriteBlobFloat(image,image->chromaticity.blue_primary.x);
1048   offset+=WriteBlobFloat(image,image->chromaticity.blue_primary.y);
1049   value=GetCINProperty(image_info,image,"dpx:image.label",exception);
1050   if (value != (const char *) NULL)
1051     (void) CopyMagickString(cin.image.label,value,sizeof(cin.image.label));
1052   offset+=WriteBlob(image,sizeof(cin.image.label),(unsigned char *)
1053     cin.image.label);
1054   offset+=WriteBlob(image,sizeof(cin.image.reserve),(unsigned char *)
1055     cin.image.reserve);
1056   /*
1057     Write data format information.
1058   */
1059   cin.data_format.interleave=0; /* pixel interleave (rgbrgbr...) */
1060   offset+=WriteBlobByte(image,cin.data_format.interleave);
1061   cin.data_format.packing=5; /* packing ssize_tword (32bit) boundaries */
1062   offset+=WriteBlobByte(image,cin.data_format.packing);
1063   cin.data_format.sign=0; /* unsigned data */
1064   offset+=WriteBlobByte(image,cin.data_format.sign);
1065   cin.data_format.sense=0; /* image sense: positive image */
1066   offset+=WriteBlobByte(image,cin.data_format.sense);
1067   cin.data_format.line_pad=0;
1068   offset+=WriteBlobLong(image,(unsigned int) cin.data_format.line_pad);
1069   cin.data_format.channel_pad=0;
1070   offset+=WriteBlobLong(image,(unsigned int) cin.data_format.channel_pad);
1071   offset+=WriteBlob(image,sizeof(cin.data_format.reserve),(unsigned char *)
1072     cin.data_format.reserve);
1073   /*
1074     Write origination information.
1075   */
1076   cin.origination.x_offset=0UL;
1077   value=GetCINProperty(image_info,image,"dpx:origination.x_offset",exception);
1078   if (value != (const char *) NULL)
1079     cin.origination.x_offset=(ssize_t) StringToLong(value);
1080   offset+=WriteBlobLong(image,(unsigned int) cin.origination.x_offset);
1081   cin.origination.y_offset=0UL;
1082   value=GetCINProperty(image_info,image,"dpx:origination.y_offset",exception);
1083   if (value != (const char *) NULL)
1084     cin.origination.y_offset=(ssize_t) StringToLong(value);
1085   offset+=WriteBlobLong(image,(unsigned int) cin.origination.y_offset);
1086   value=GetCINProperty(image_info,image,"dpx:origination.filename",exception);
1087   if (value != (const char *) NULL)
1088     (void) CopyMagickString(cin.origination.filename,value,
1089       sizeof(cin.origination.filename));
1090   else
1091     (void) CopyMagickString(cin.origination.filename,image->filename,
1092       sizeof(cin.origination.filename));
1093   offset+=WriteBlob(image,sizeof(cin.origination.filename),(unsigned char *)
1094     cin.origination.filename);
1095   (void) memset(timestamp,0,sizeof(timestamp));
1096   (void) strftime(timestamp,MaxTextExtent,"%Y:%m:%d:%H:%M:%SUTC",&utc_time);
1097   (void) memset(cin.origination.create_date,0,
1098     sizeof(cin.origination.create_date));
1099   (void) CopyMagickString(cin.origination.create_date,timestamp,11);
1100   offset+=WriteBlob(image,sizeof(cin.origination.create_date),(unsigned char *)
1101     cin.origination.create_date);
1102   (void) memset(cin.origination.create_time,0,
1103      sizeof(cin.origination.create_time));
1104   (void) CopyMagickString(cin.origination.create_time,timestamp+11,15);
1105   offset+=WriteBlob(image,sizeof(cin.origination.create_time),(unsigned char *)
1106     cin.origination.create_time);
1107   value=GetCINProperty(image_info,image,"dpx:origination.device",exception);
1108   if (value != (const char *) NULL)
1109     (void) CopyMagickString(cin.origination.device,value,
1110       sizeof(cin.origination.device));
1111   offset+=WriteBlob(image,sizeof(cin.origination.device),(unsigned char *)
1112     cin.origination.device);
1113   value=GetCINProperty(image_info,image,"dpx:origination.model",exception);
1114   if (value != (const char *) NULL)
1115     (void) CopyMagickString(cin.origination.model,value,
1116       sizeof(cin.origination.model));
1117   offset+=WriteBlob(image,sizeof(cin.origination.model),(unsigned char *)
1118     cin.origination.model);
1119   value=GetCINProperty(image_info,image,"dpx:origination.serial",exception);
1120   if (value != (const char *) NULL)
1121     (void) CopyMagickString(cin.origination.serial,value,
1122       sizeof(cin.origination.serial));
1123   offset+=WriteBlob(image,sizeof(cin.origination.serial),(unsigned char *)
1124     cin.origination.serial);
1125   cin.origination.x_pitch=0.0f;
1126   value=GetCINProperty(image_info,image,"dpx:origination.x_pitch",exception);
1127   if (value != (const char *) NULL)
1128     cin.origination.x_pitch=StringToDouble(value,(char **) NULL);
1129   offset+=WriteBlobFloat(image,cin.origination.x_pitch);
1130   cin.origination.y_pitch=0.0f;
1131   value=GetCINProperty(image_info,image,"dpx:origination.y_pitch",exception);
1132   if (value != (const char *) NULL)
1133     cin.origination.y_pitch=StringToDouble(value,(char **) NULL);
1134   offset+=WriteBlobFloat(image,cin.origination.y_pitch);
1135   cin.origination.gamma=image->gamma;
1136   offset+=WriteBlobFloat(image,cin.origination.gamma);
1137   offset+=WriteBlob(image,sizeof(cin.origination.reserve),(unsigned char *)
1138     cin.origination.reserve);
1139   /*
1140     Image film information.
1141   */
1142   cin.film.id=0;
1143   value=GetCINProperty(image_info,image,"dpx:film.id",exception);
1144   if (value != (const char *) NULL)
1145     cin.film.id=(char) StringToLong(value);
1146   offset+=WriteBlobByte(image,(unsigned char) cin.film.id);
1147   cin.film.type=0;
1148   value=GetCINProperty(image_info,image,"dpx:film.type",exception);
1149   if (value != (const char *) NULL)
1150     cin.film.type=(char) StringToLong(value);
1151   offset+=WriteBlobByte(image,(unsigned char) cin.film.type);
1152   cin.film.offset=0;
1153   value=GetCINProperty(image_info,image,"dpx:film.offset",exception);
1154   if (value != (const char *) NULL)
1155     cin.film.offset=(char) StringToLong(value);
1156   offset+=WriteBlobByte(image,(unsigned char) cin.film.offset);
1157   offset+=WriteBlobByte(image,(unsigned char) cin.film.reserve1);
1158   cin.film.prefix=0UL;
1159   value=GetCINProperty(image_info,image,"dpx:film.prefix",exception);
1160   if (value != (const char *) NULL)
1161     cin.film.prefix=StringToUnsignedLong(value);
1162   offset+=WriteBlobLong(image,(unsigned int) cin.film.prefix);
1163   cin.film.count=0UL;
1164   value=GetCINProperty(image_info,image,"dpx:film.count",exception);
1165   if (value != (const char *) NULL)
1166     cin.film.count=StringToUnsignedLong(value);
1167   offset+=WriteBlobLong(image,(unsigned int) cin.film.count);
1168   value=GetCINProperty(image_info,image,"dpx:film.format",exception);
1169   if (value != (const char *) NULL)
1170     (void) CopyMagickString(cin.film.format,value,sizeof(cin.film.format));
1171   offset+=WriteBlob(image,sizeof(cin.film.format),(unsigned char *)
1172     cin.film.format);
1173   cin.film.frame_position=0UL;
1174   value=GetCINProperty(image_info,image,"dpx:film.frame_position",exception);
1175   if (value != (const char *) NULL)
1176     cin.film.frame_position=StringToUnsignedLong(value);
1177   offset+=WriteBlobLong(image,(unsigned int) cin.film.frame_position);
1178   cin.film.frame_rate=0.0f;
1179   value=GetCINProperty(image_info,image,"dpx:film.frame_rate",exception);
1180   if (value != (const char *) NULL)
1181     cin.film.frame_rate=StringToDouble(value,(char **) NULL);
1182   offset+=WriteBlobFloat(image,cin.film.frame_rate);
1183   value=GetCINProperty(image_info,image,"dpx:film.frame_id",exception);
1184   if (value != (const char *) NULL)
1185     (void) CopyMagickString(cin.film.frame_id,value,sizeof(cin.film.frame_id));
1186   offset+=WriteBlob(image,sizeof(cin.film.frame_id),(unsigned char *)
1187     cin.film.frame_id);
1188   value=GetCINProperty(image_info,image,"dpx:film.slate_info",exception);
1189   if (value != (const char *) NULL)
1190     (void) CopyMagickString(cin.film.slate_info,value,
1191       sizeof(cin.film.slate_info));
1192   offset+=WriteBlob(image,sizeof(cin.film.slate_info),(unsigned char *)
1193     cin.film.slate_info);
1194   offset+=WriteBlob(image,sizeof(cin.film.reserve),(unsigned char *)
1195     cin.film.reserve);
1196   if (profile != (StringInfo *) NULL)
1197     offset+=WriteBlob(image,GetStringInfoLength(profile),
1198       GetStringInfoDatum(profile));
1199   while (offset < (MagickOffsetType) cin.file.image_offset)
1200     offset+=WriteBlobByte(image,0x00);
1201   /*
1202     Convert pixel packets to CIN raster image.
1203   */
1204   quantum_info=AcquireQuantumInfo(image_info,image);
1205   if (quantum_info == (QuantumInfo *) NULL)
1206     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1207   quantum_info->quantum=32;
1208   quantum_info->pack=MagickFalse;
1209   quantum_type=RGBQuantum;
1210   pixels=(unsigned char *) GetQuantumPixels(quantum_info);
1211   length=GetBytesPerRow(image->columns,3,image->depth,MagickTrue);
1212 DisableMSCWarning(4127)
1213   if (0)
1214 RestoreMSCWarning
1215     {
1216       quantum_type=GrayQuantum;
1217       length=GetBytesPerRow(image->columns,1,image->depth,MagickTrue);
1218     }
1219   for (y=0; y < (ssize_t) image->rows; y++)
1220   {
1221     p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1222     if (p == (const Quantum *) NULL)
1223       break;
1224     (void) ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1225       quantum_type,pixels,exception);
1226     count=WriteBlob(image,length,pixels);
1227     if (count != (ssize_t) length)
1228       break;
1229     status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1230       image->rows);
1231     if (status == MagickFalse)
1232       break;
1233   }
1234   quantum_info=DestroyQuantumInfo(quantum_info);
1235   (void) CloseBlob(image);
1236   return(status);
1237 }
1238