]> granicus.if.org Git - imagemagick/blob - coders/cin.c
c04cce3aaa21458e4e8e0ac2cdcbe12f27da6a77
[imagemagick] / coders / cin.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                             CCCC  IIIII  N   N                              %
7 %                            C        I    NN  N                              %
8 %                            C        I    N N N                              %
9 %                            C        I    N  NN                              %
10 %                             CCCC  IIIII  N   N                              %
11 %                                                                             %
12 %                                                                             %
13 %                    Read/Write Kodak Cineon Image Format                     %
14 %                Cineon Image Format is a subset of SMTPE CIN                 %
15 %                                                                             %
16 %                                                                             %
17 %                              Software Design                                %
18 %                                   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 \f
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 \f
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 \f
228 /*
229   Forward declaractions.
230 */
231 static MagickBooleanType
232   WriteCINImage(const ImageInfo *,Image *,ExceptionInfo *);
233 \f
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 */
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 \f
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
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
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
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   const unsigned char
392     *pixels;
393
394   Image
395     *image;
396
397   MagickBooleanType
398     status;
399
400   MagickOffsetType
401     offset;
402
403   QuantumInfo
404     *quantum_info;
405
406   QuantumType
407     quantum_type;
408
409   register ssize_t
410     i;
411
412   register Quantum
413     *q;
414
415   size_t
416     length;
417
418   ssize_t
419     count,
420     y;
421
422   unsigned char
423     magick[4];
424
425   /*
426     Open image file.
427   */
428   assert(image_info != (const ImageInfo *) NULL);
429   assert(image_info->signature == MagickCoreSignature);
430   if (image_info->debug != MagickFalse)
431     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
432       image_info->filename);
433   assert(exception != (ExceptionInfo *) NULL);
434   assert(exception->signature == MagickCoreSignature);
435   image=AcquireImage(image_info,exception);
436   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
437   if (status == MagickFalse)
438     {
439       image=DestroyImageList(image);
440       return((Image *) NULL);
441     }
442   /*
443     File information.
444   */
445   offset=0;
446   count=ReadBlob(image,4,magick);
447   offset+=count;
448   if ((count != 4) ||
449       ((LocaleNCompare((char *) magick,"\200\052\137\327",4) != 0)))
450     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
451   memset(&cin,0,sizeof(cin));
452   image->endian=(magick[0] == 0x80) && (magick[1] == 0x2a) &&
453     (magick[2] == 0x5f) && (magick[3] == 0xd7) ? MSBEndian : LSBEndian;
454   cin.file.image_offset=ReadBlobLong(image);
455   offset+=4;
456   cin.file.generic_length=ReadBlobLong(image);
457   offset+=4;
458   cin.file.industry_length=ReadBlobLong(image);
459   offset+=4;
460   cin.file.user_length=ReadBlobLong(image);
461   offset+=4;
462   cin.file.file_size=ReadBlobLong(image);
463   offset+=4;
464   offset+=ReadBlob(image,sizeof(cin.file.version),(unsigned char *)
465     cin.file.version);
466   (void) CopyMagickString(property,cin.file.version,sizeof(cin.file.version));
467   (void) SetImageProperty(image,"dpx:file.version",property,exception);
468   offset+=ReadBlob(image,sizeof(cin.file.filename),(unsigned char *)
469     cin.file.filename);
470   (void) CopyMagickString(property,cin.file.filename,sizeof(cin.file.filename));
471   (void) SetImageProperty(image,"dpx:file.filename",property,exception);
472   offset+=ReadBlob(image,sizeof(cin.file.create_date),(unsigned char *)
473     cin.file.create_date);
474   (void) CopyMagickString(property,cin.file.create_date,
475     sizeof(cin.file.create_date));
476   (void) SetImageProperty(image,"dpx:file.create_date",property,exception);
477   offset+=ReadBlob(image,sizeof(cin.file.create_time),(unsigned char *)
478     cin.file.create_time);
479   (void) CopyMagickString(property,cin.file.create_time,
480     sizeof(cin.file.create_time));
481   (void) SetImageProperty(image,"dpx:file.create_time",property,exception);
482   offset+=ReadBlob(image,sizeof(cin.file.reserve),(unsigned char *)
483     cin.file.reserve);
484   /*
485     Image information.
486   */
487   cin.image.orientation=(unsigned char) ReadBlobByte(image);
488   offset++;
489   if (cin.image.orientation != (unsigned char) (~0))
490     (void) FormatImageProperty(image,"dpx:image.orientation","%d",
491       cin.image.orientation);
492   switch (cin.image.orientation)
493   {
494     default:
495     case 0: image->orientation=TopLeftOrientation; break;
496     case 1: image->orientation=TopRightOrientation; break;
497     case 2: image->orientation=BottomLeftOrientation; break;
498     case 3: image->orientation=BottomRightOrientation; break;
499     case 4: image->orientation=LeftTopOrientation; break;
500     case 5: image->orientation=RightTopOrientation; break;
501     case 6: image->orientation=LeftBottomOrientation; break;
502     case 7: image->orientation=RightBottomOrientation; break;
503   }
504   cin.image.number_channels=(unsigned char) ReadBlobByte(image);
505   offset++;
506   offset+=ReadBlob(image,sizeof(cin.image.reserve1),(unsigned char *)
507     cin.image.reserve1);
508   for (i=0; i < 8; i++)
509   {
510     cin.image.channel[i].designator[0]=(unsigned char) ReadBlobByte(image);
511     offset++;
512     cin.image.channel[i].designator[1]=(unsigned char) ReadBlobByte(image);
513     offset++;
514     cin.image.channel[i].bits_per_pixel=(unsigned char) ReadBlobByte(image);
515     offset++;
516     cin.image.channel[i].reserve=(unsigned char) ReadBlobByte(image);
517     offset++;
518     cin.image.channel[i].pixels_per_line=ReadBlobLong(image);
519     offset+=4;
520     cin.image.channel[i].lines_per_image=ReadBlobLong(image);
521     offset+=4;
522     cin.image.channel[i].min_data=ReadBlobFloat(image);
523     offset+=4;
524     cin.image.channel[i].min_quantity=ReadBlobFloat(image);
525     offset+=4;
526     cin.image.channel[i].max_data=ReadBlobFloat(image);
527     offset+=4;
528     cin.image.channel[i].max_quantity=ReadBlobFloat(image);
529     offset+=4;
530   }
531   cin.image.white_point[0]=ReadBlobFloat(image);
532   offset+=4;
533   if (IsFloatDefined(cin.image.white_point[0]) != MagickFalse)
534     image->chromaticity.white_point.x=cin.image.white_point[0];
535   cin.image.white_point[1]=ReadBlobFloat(image);
536   offset+=4;
537   if (IsFloatDefined(cin.image.white_point[1]) != MagickFalse)
538     image->chromaticity.white_point.y=cin.image.white_point[1];
539   cin.image.red_primary_chromaticity[0]=ReadBlobFloat(image);
540   offset+=4;
541   if (IsFloatDefined(cin.image.red_primary_chromaticity[0]) != MagickFalse)
542     image->chromaticity.red_primary.x=cin.image.red_primary_chromaticity[0];
543   cin.image.red_primary_chromaticity[1]=ReadBlobFloat(image);
544   offset+=4;
545   if (IsFloatDefined(cin.image.red_primary_chromaticity[1]) != MagickFalse)
546     image->chromaticity.red_primary.y=cin.image.red_primary_chromaticity[1];
547   cin.image.green_primary_chromaticity[0]=ReadBlobFloat(image);
548   offset+=4;
549   if (IsFloatDefined(cin.image.green_primary_chromaticity[0]) != MagickFalse)
550     image->chromaticity.red_primary.x=cin.image.green_primary_chromaticity[0];
551   cin.image.green_primary_chromaticity[1]=ReadBlobFloat(image);
552   offset+=4;
553   if (IsFloatDefined(cin.image.green_primary_chromaticity[1]) != MagickFalse)
554     image->chromaticity.green_primary.y=cin.image.green_primary_chromaticity[1];
555   cin.image.blue_primary_chromaticity[0]=ReadBlobFloat(image);
556   offset+=4;
557   if (IsFloatDefined(cin.image.blue_primary_chromaticity[0]) != MagickFalse)
558     image->chromaticity.blue_primary.x=cin.image.blue_primary_chromaticity[0];
559   cin.image.blue_primary_chromaticity[1]=ReadBlobFloat(image);
560   offset+=4;
561   if (IsFloatDefined(cin.image.blue_primary_chromaticity[1]) != MagickFalse)
562     image->chromaticity.blue_primary.y=cin.image.blue_primary_chromaticity[1];
563   offset+=ReadBlob(image,sizeof(cin.image.label),(unsigned char *)
564     cin.image.label);
565   (void) CopyMagickString(property,cin.image.label,sizeof(cin.image.label));
566   (void) SetImageProperty(image,"dpx:image.label",property,exception);
567   offset+=ReadBlob(image,sizeof(cin.image.reserve),(unsigned char *)
568     cin.image.reserve);
569   /*
570     Image data format information.
571   */
572   cin.data_format.interleave=(unsigned char) ReadBlobByte(image);
573   offset++;
574   cin.data_format.packing=(unsigned char) ReadBlobByte(image);
575   offset++;
576   cin.data_format.sign=(unsigned char) ReadBlobByte(image);
577   offset++;
578   cin.data_format.sense=(unsigned char) ReadBlobByte(image);
579   offset++;
580   cin.data_format.line_pad=ReadBlobLong(image);
581   offset+=4;
582   cin.data_format.channel_pad=ReadBlobLong(image);
583   offset+=4;
584   offset+=ReadBlob(image,sizeof(cin.data_format.reserve),(unsigned char *)
585     cin.data_format.reserve);
586   /*
587     Image origination information.
588   */
589   cin.origination.x_offset=ReadBlobSignedLong(image);
590   offset+=4;
591   if ((size_t) cin.origination.x_offset != ~0UL)
592     (void) FormatImageProperty(image,"dpx:origination.x_offset","%.20g",
593       (double) cin.origination.x_offset);
594   cin.origination.y_offset=(ssize_t) ReadBlobLong(image);
595   offset+=4;
596   if ((size_t) cin.origination.y_offset != ~0UL)
597     (void) FormatImageProperty(image,"dpx:origination.y_offset","%.20g",
598       (double) cin.origination.y_offset);
599   offset+=ReadBlob(image,sizeof(cin.origination.filename),(unsigned char *)
600     cin.origination.filename);
601   (void) CopyMagickString(property,cin.origination.filename,
602     sizeof(cin.origination.filename));
603   (void) SetImageProperty(image,"dpx:origination.filename",property,exception);
604   offset+=ReadBlob(image,sizeof(cin.origination.create_date),(unsigned char *)
605     cin.origination.create_date);
606   (void) CopyMagickString(property,cin.origination.create_date,
607     sizeof(cin.origination.create_date));
608   (void) SetImageProperty(image,"dpx:origination.create_date",property,
609     exception);
610   offset+=ReadBlob(image,sizeof(cin.origination.create_time),(unsigned char *)
611     cin.origination.create_time);
612   (void) CopyMagickString(property,cin.origination.create_time,
613     sizeof(cin.origination.create_time));
614   (void) SetImageProperty(image,"dpx:origination.create_time",property,
615     exception);
616   offset+=ReadBlob(image,sizeof(cin.origination.device),(unsigned char *)
617     cin.origination.device);
618   (void) CopyMagickString(property,cin.origination.device,
619     sizeof(cin.origination.device));
620   (void) SetImageProperty(image,"dpx:origination.device",property,exception);
621   offset+=ReadBlob(image,sizeof(cin.origination.model),(unsigned char *)
622     cin.origination.model);
623   (void) CopyMagickString(property,cin.origination.model,
624     sizeof(cin.origination.model));
625   (void) SetImageProperty(image,"dpx:origination.model",property,exception);
626   (void) memset(cin.origination.serial,0, 
627     sizeof(cin.origination.serial));
628   offset+=ReadBlob(image,sizeof(cin.origination.serial),(unsigned char *)
629     cin.origination.serial);
630   (void) CopyMagickString(property,cin.origination.serial,
631     sizeof(cin.origination.serial));
632   (void) SetImageProperty(image,"dpx:origination.serial",property,exception);
633   cin.origination.x_pitch=ReadBlobFloat(image);
634   offset+=4;
635   cin.origination.y_pitch=ReadBlobFloat(image);
636   offset+=4;
637   cin.origination.gamma=ReadBlobFloat(image);
638   offset+=4;
639   if (IsFloatDefined(cin.origination.gamma) != MagickFalse)
640     image->gamma=cin.origination.gamma;
641   offset+=ReadBlob(image,sizeof(cin.origination.reserve),(unsigned char *)
642     cin.origination.reserve);
643   if ((cin.file.image_offset > 2048) && (cin.file.user_length != 0))
644     {
645       int
646         c;
647
648       /*
649         Image film information.
650       */
651       cin.film.id=ReadBlobByte(image);
652       offset++;
653       c=cin.film.id;
654       if (c != ~0)
655         (void) FormatImageProperty(image,"dpx:film.id","%d",cin.film.id);
656       cin.film.type=ReadBlobByte(image);
657       offset++;
658       c=cin.film.type;
659       if (c != ~0)
660         (void) FormatImageProperty(image,"dpx:film.type","%d",cin.film.type);
661       cin.film.offset=ReadBlobByte(image);
662       offset++;
663       c=cin.film.offset;
664       if (c != ~0)
665         (void) FormatImageProperty(image,"dpx:film.offset","%d",
666           cin.film.offset);
667       cin.film.reserve1=ReadBlobByte(image);
668       offset++;
669       cin.film.prefix=ReadBlobLong(image);
670       offset+=4;
671       if (cin.film.prefix != ~0UL)
672         (void) FormatImageProperty(image,"dpx:film.prefix","%.20g",(double)
673           cin.film.prefix);
674       cin.film.count=ReadBlobLong(image);
675       offset+=4;
676       offset+=ReadBlob(image,sizeof(cin.film.format),(unsigned char *)
677         cin.film.format);
678       (void) CopyMagickString(property,cin.film.format,sizeof(cin.film.format));
679       (void) SetImageProperty(image,"dpx:film.format",property,exception);
680       cin.film.frame_position=ReadBlobLong(image);
681       offset+=4;
682       if (cin.film.frame_position != ~0UL)
683         (void) FormatImageProperty(image,"dpx:film.frame_position","%.20g",
684           (double) cin.film.frame_position);
685       cin.film.frame_rate=ReadBlobFloat(image);
686       offset+=4;
687       if (IsFloatDefined(cin.film.frame_rate) != MagickFalse)
688         (void) FormatImageProperty(image,"dpx:film.frame_rate","%g",
689           cin.film.frame_rate);
690       offset+=ReadBlob(image,sizeof(cin.film.frame_id),(unsigned char *)
691         cin.film.frame_id);
692       (void) CopyMagickString(property,cin.film.frame_id,
693         sizeof(cin.film.frame_id));
694       (void) SetImageProperty(image,"dpx:film.frame_id",property,exception);
695       offset+=ReadBlob(image,sizeof(cin.film.slate_info),(unsigned char *)
696         cin.film.slate_info);
697       (void) CopyMagickString(property,cin.film.slate_info,
698         sizeof(cin.film.slate_info));
699       (void) SetImageProperty(image,"dpx:film.slate_info",property,exception);
700       offset+=ReadBlob(image,sizeof(cin.film.reserve),(unsigned char *)
701         cin.film.reserve);
702     }
703   if ((cin.file.image_offset > 2048) && (cin.file.user_length != 0))
704     {
705       StringInfo
706         *profile;
707
708       /*
709         User defined data.
710       */
711       if (cin.file.user_length > GetBlobSize(image))
712         ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
713       profile=BlobToStringInfo((const unsigned char *) NULL,
714         cin.file.user_length);
715       if (profile == (StringInfo *) NULL)
716         ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
717       offset+=ReadBlob(image,GetStringInfoLength(profile),
718         GetStringInfoDatum(profile));
719       (void) SetImageProfile(image,"dpx:user.data",profile,exception);
720       profile=DestroyStringInfo(profile);
721     }
722   image->depth=cin.image.channel[0].bits_per_pixel;
723   image->columns=cin.image.channel[0].pixels_per_line;
724   image->rows=cin.image.channel[0].lines_per_image;
725   if (image_info->ping != MagickFalse)
726     {
727       (void) CloseBlob(image);
728       return(image);
729     }
730   if (((MagickSizeType) image->columns*image->rows/8) > GetBlobSize(image))
731     ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
732   for ( ; offset < (MagickOffsetType) cin.file.image_offset; offset++)
733   {
734     int
735       c;
736
737     c=ReadBlobByte(image);
738     if (c == EOF)
739       break;
740   }
741   if (offset < (MagickOffsetType) cin.file.image_offset)
742     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
743   status=SetImageExtent(image,image->columns,image->rows,exception);
744   if (status == MagickFalse)
745     return(DestroyImageList(image));
746   (void) SetImageBackgroundColor(image,exception);
747   /*
748     Convert CIN raster image to pixel packets.
749   */
750   quantum_info=AcquireQuantumInfo(image_info,image);
751   if (quantum_info == (QuantumInfo *) NULL)
752     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
753   quantum_info->quantum=32;
754   quantum_info->pack=MagickFalse;
755   quantum_type=RGBQuantum;
756   length=GetQuantumExtent(image,quantum_info,quantum_type);
757   length=GetBytesPerRow(image->columns,3,image->depth,MagickTrue);
758   if (cin.image.number_channels == 1)
759     {
760       quantum_type=GrayQuantum;
761       length=GetBytesPerRow(image->columns,1,image->depth,MagickTrue);
762     }
763   for (y=0; y < (ssize_t) image->rows; y++)
764   {
765     q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
766     if (q == (Quantum *) NULL)
767       break;
768     pixels=(const unsigned char *) ReadBlobStream(image,length,
769       GetQuantumPixels(quantum_info),&count);
770     if ((size_t) count != length)
771       break;
772     (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
773       quantum_type,pixels,exception);
774     if (SyncAuthenticPixels(image,exception) == MagickFalse)
775       break;
776     if (image->previous == (Image *) NULL)
777       {
778         status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
779           image->rows);
780         if (status == MagickFalse)
781           break;
782       }
783   }
784   SetQuantumImageType(image,quantum_type);
785   quantum_info=DestroyQuantumInfo(quantum_info);
786   if (EOFBlob(image) != MagickFalse)
787     ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
788       image->filename);
789   SetImageColorspace(image,LogColorspace,exception);
790   (void) CloseBlob(image);
791   return(GetFirstImageInList(image));
792 }
793 \f
794 /*
795 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
796 %                                                                             %
797 %                                                                             %
798 %                                                                             %
799 %   R e g i s t e r C I N E O N I m a g e                                     %
800 %                                                                             %
801 %                                                                             %
802 %                                                                             %
803 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
804 %
805 %  RegisterCINImage() adds attributes for the CIN image format to the list of
806 %  of supported formats.  The attributes include the image format tag, a method
807 %  to read and/or write the format, whether the format supports the saving of
808 %  more than one frame to the same file or blob, whether the format supports
809 %  native in-memory I/O, and a brief description of the format.
810 %
811 %  The format of the RegisterCINImage method is:
812 %
813 %      size_t RegisterCINImage(void)
814 %
815 */
816 ModuleExport size_t RegisterCINImage(void)
817 {
818   MagickInfo
819     *entry;
820
821   entry=AcquireMagickInfo("CIN","CIN","Cineon Image File");
822   entry->decoder=(DecodeImageHandler *) ReadCINImage;
823   entry->encoder=(EncodeImageHandler *) WriteCINImage;
824   entry->magick=(IsImageFormatHandler *) IsCIN;
825   entry->flags|=CoderDecoderSeekableStreamFlag;
826   entry->flags^=CoderAdjoinFlag;
827   (void) RegisterMagickInfo(entry);
828   return(MagickImageCoderSignature);
829 }
830 \f
831 /*
832 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
833 %                                                                             %
834 %                                                                             %
835 %                                                                             %
836 %   U n r e g i s t e r C I N E O N I m a g e                                 %
837 %                                                                             %
838 %                                                                             %
839 %                                                                             %
840 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
841 %
842 %  UnregisterCINImage() removes format registrations made by the CIN module
843 %  from the list of supported formats.
844 %
845 %  The format of the UnregisterCINImage method is:
846 %
847 %      UnregisterCINImage(void)
848 %
849 */
850 ModuleExport void UnregisterCINImage(void)
851 {
852   (void) UnregisterMagickInfo("CINEON");
853 }
854 \f
855 /*
856 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
857 %                                                                             %
858 %                                                                             %
859 %                                                                             %
860 %   W r i t e C I N E O N I m a g e                                           %
861 %                                                                             %
862 %                                                                             %
863 %                                                                             %
864 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
865 %
866 %  WriteCINImage() writes an image in CIN encoded image format.
867 %
868 %  The format of the WriteCINImage method is:
869 %
870 %      MagickBooleanType WriteCINImage(const ImageInfo *image_info,
871 %        Image *image,ExceptionInfo *exception)
872 %
873 %  A description of each parameter follows.
874 %
875 %    o image_info: the image info.
876 %
877 %    o image:  The image.
878 %
879 %    o exception: return any errors or warnings in this structure.
880 %
881 */
882
883 static inline const char *GetCINProperty(const ImageInfo *image_info,
884   const Image *image,const char *property,ExceptionInfo *exception)
885 {
886   const char
887     *value;
888
889   value=GetImageOption(image_info,property);
890   if (value != (const char *) NULL)
891     return(value);
892   return(GetImageProperty(image,property,exception));
893 }
894
895 static MagickBooleanType WriteCINImage(const ImageInfo *image_info,Image *image,
896   ExceptionInfo *exception)
897 {
898   char
899     timestamp[MagickPathExtent];
900
901   const char
902     *value;
903
904   CINInfo
905     cin;
906
907   const StringInfo
908     *profile;
909
910   MagickBooleanType
911     status;
912
913   MagickOffsetType
914     offset;
915
916   QuantumInfo
917     *quantum_info;
918
919   QuantumType
920     quantum_type;
921
922   register const Quantum
923     *p;
924
925   register ssize_t
926     i;
927
928   size_t
929     length;
930
931   ssize_t
932     count,
933     y;
934
935   struct tm
936     utc_time;
937
938   time_t
939     seconds;
940
941   unsigned char
942     *pixels;
943
944   /*
945     Open output image file.
946   */
947   assert(image_info != (const ImageInfo *) NULL);
948   assert(image_info->signature == MagickCoreSignature);
949   assert(image != (Image *) NULL);
950   assert(image->signature == MagickCoreSignature);
951   if (image->debug != MagickFalse)
952     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
953   assert(exception != (ExceptionInfo *) NULL);
954   assert(exception->signature == MagickCoreSignature);
955   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
956   if (status == MagickFalse)
957     return(status);
958   if (image->colorspace != LogColorspace)
959     (void) TransformImageColorspace(image,LogColorspace,exception);
960   /*
961     Write image information.
962   */
963   (void) memset(&cin,0,sizeof(cin));
964   offset=0;
965   cin.file.magic=0x802A5FD7UL;
966   offset+=WriteBlobLong(image,(unsigned int) cin.file.magic);
967   cin.file.image_offset=0x800;
968   offset+=WriteBlobLong(image,(unsigned int) cin.file.image_offset);
969   cin.file.generic_length=0x400;
970   offset+=WriteBlobLong(image,(unsigned int) cin.file.generic_length);
971   cin.file.industry_length=0x400;
972   offset+=WriteBlobLong(image,(unsigned int) cin.file.industry_length);
973   cin.file.user_length=0x00;
974   profile=GetImageProfile(image,"dpx:user.data");
975   if (profile != (StringInfo *) NULL)
976     {
977       cin.file.user_length+=(size_t) GetStringInfoLength(profile);
978       cin.file.user_length=(((cin.file.user_length+0x2000-1)/0x2000)*0x2000);
979     }
980   offset+=WriteBlobLong(image,(unsigned int) cin.file.user_length);
981   cin.file.file_size=4*image->columns*image->rows+0x2000;
982   offset+=WriteBlobLong(image,(unsigned int) cin.file.file_size);
983   (void) CopyMagickString(cin.file.version,"V4.5",sizeof(cin.file.version));
984   offset+=WriteBlob(image,sizeof(cin.file.version),(unsigned char *)
985     cin.file.version);
986   value=GetCINProperty(image_info,image,"dpx:file.filename",exception);
987   if (value != (const char *) NULL)
988     (void) CopyMagickString(cin.file.filename,value,sizeof(cin.file.filename));
989   else
990     (void) CopyMagickString(cin.file.filename,image->filename,
991       sizeof(cin.file.filename));
992   offset+=WriteBlob(image,sizeof(cin.file.filename),(unsigned char *)
993     cin.file.filename);
994   seconds=GetMagickTime();
995   GetMagickUTCtime(&seconds,&utc_time);
996   (void) memset(timestamp,0,sizeof(timestamp));
997   (void) strftime(timestamp,MaxTextExtent,"%Y:%m:%d:%H:%M:%SUTC",&utc_time);
998   (void) memset(cin.file.create_date,0,sizeof(cin.file.create_date));
999   (void) CopyMagickString(cin.file.create_date,timestamp,11);
1000   offset+=WriteBlob(image,sizeof(cin.file.create_date),(unsigned char *)
1001     cin.file.create_date);
1002   (void) memset(cin.file.create_time,0,sizeof(cin.file.create_time));
1003   (void) CopyMagickString(cin.file.create_time,timestamp+11,11);
1004   offset+=WriteBlob(image,sizeof(cin.file.create_time),(unsigned char *)
1005     cin.file.create_time);
1006   offset+=WriteBlob(image,sizeof(cin.file.reserve),(unsigned char *)
1007     cin.file.reserve);
1008   cin.image.orientation=0x00;
1009   offset+=WriteBlobByte(image,cin.image.orientation);
1010   cin.image.number_channels=3;
1011   offset+=WriteBlobByte(image,cin.image.number_channels);
1012   offset+=WriteBlob(image,sizeof(cin.image.reserve1),(unsigned char *)
1013     cin.image.reserve1);
1014   for (i=0; i < 8; i++)
1015   {
1016     cin.image.channel[i].designator[0]=0; /* universal metric */
1017     offset+=WriteBlobByte(image,cin.image.channel[0].designator[0]);
1018     cin.image.channel[i].designator[1]=(unsigned char) (i > 3 ? 0 : i+1); /* channel color */;
1019     offset+=WriteBlobByte(image,cin.image.channel[1].designator[0]);
1020     cin.image.channel[i].bits_per_pixel=(unsigned char) image->depth;
1021     offset+=WriteBlobByte(image,cin.image.channel[0].bits_per_pixel);
1022     offset+=WriteBlobByte(image,cin.image.channel[0].reserve);
1023     cin.image.channel[i].pixels_per_line=image->columns;
1024     offset+=WriteBlobLong(image,(unsigned int)
1025       cin.image.channel[0].pixels_per_line);
1026     cin.image.channel[i].lines_per_image=image->rows;
1027     offset+=WriteBlobLong(image,(unsigned int)
1028       cin.image.channel[0].lines_per_image);
1029     cin.image.channel[i].min_data=0;
1030     offset+=WriteBlobFloat(image,cin.image.channel[0].min_data);
1031     cin.image.channel[i].min_quantity=0.0;
1032     offset+=WriteBlobFloat(image,cin.image.channel[0].min_quantity);
1033     cin.image.channel[i].max_data=(float) ((MagickOffsetType)
1034       GetQuantumRange(image->depth));
1035     offset+=WriteBlobFloat(image,cin.image.channel[0].max_data);
1036     cin.image.channel[i].max_quantity=2.048f;
1037     offset+=WriteBlobFloat(image,cin.image.channel[0].max_quantity);
1038   }
1039   offset+=WriteBlobFloat(image,image->chromaticity.white_point.x);
1040   offset+=WriteBlobFloat(image,image->chromaticity.white_point.y);
1041   offset+=WriteBlobFloat(image,image->chromaticity.red_primary.x);
1042   offset+=WriteBlobFloat(image,image->chromaticity.red_primary.y);
1043   offset+=WriteBlobFloat(image,image->chromaticity.green_primary.x);
1044   offset+=WriteBlobFloat(image,image->chromaticity.green_primary.y);
1045   offset+=WriteBlobFloat(image,image->chromaticity.blue_primary.x);
1046   offset+=WriteBlobFloat(image,image->chromaticity.blue_primary.y);
1047   value=GetCINProperty(image_info,image,"dpx:image.label",exception);
1048   if (value != (const char *) NULL)
1049     (void) CopyMagickString(cin.image.label,value,sizeof(cin.image.label));
1050   offset+=WriteBlob(image,sizeof(cin.image.label),(unsigned char *)
1051     cin.image.label);
1052   offset+=WriteBlob(image,sizeof(cin.image.reserve),(unsigned char *)
1053     cin.image.reserve);
1054   /*
1055     Write data format information.
1056   */
1057   cin.data_format.interleave=0; /* pixel interleave (rgbrgbr...) */
1058   offset+=WriteBlobByte(image,cin.data_format.interleave);
1059   cin.data_format.packing=5; /* packing ssize_tword (32bit) boundaries */
1060   offset+=WriteBlobByte(image,cin.data_format.packing);
1061   cin.data_format.sign=0; /* unsigned data */
1062   offset+=WriteBlobByte(image,cin.data_format.sign);
1063   cin.data_format.sense=0; /* image sense: positive image */
1064   offset+=WriteBlobByte(image,cin.data_format.sense);
1065   cin.data_format.line_pad=0;
1066   offset+=WriteBlobLong(image,(unsigned int) cin.data_format.line_pad);
1067   cin.data_format.channel_pad=0;
1068   offset+=WriteBlobLong(image,(unsigned int) cin.data_format.channel_pad);
1069   offset+=WriteBlob(image,sizeof(cin.data_format.reserve),(unsigned char *)
1070     cin.data_format.reserve);
1071   /*
1072     Write origination information.
1073   */
1074   cin.origination.x_offset=0UL;
1075   value=GetCINProperty(image_info,image,"dpx:origination.x_offset",exception);
1076   if (value != (const char *) NULL)
1077     cin.origination.x_offset=(ssize_t) StringToLong(value);
1078   offset+=WriteBlobLong(image,(unsigned int) cin.origination.x_offset);
1079   cin.origination.y_offset=0UL;
1080   value=GetCINProperty(image_info,image,"dpx:origination.y_offset",exception);
1081   if (value != (const char *) NULL)
1082     cin.origination.y_offset=(ssize_t) StringToLong(value);
1083   offset+=WriteBlobLong(image,(unsigned int) cin.origination.y_offset);
1084   value=GetCINProperty(image_info,image,"dpx:origination.filename",exception);
1085   if (value != (const char *) NULL)
1086     (void) CopyMagickString(cin.origination.filename,value,
1087       sizeof(cin.origination.filename));
1088   else
1089     (void) CopyMagickString(cin.origination.filename,image->filename,
1090       sizeof(cin.origination.filename));
1091   offset+=WriteBlob(image,sizeof(cin.origination.filename),(unsigned char *)
1092     cin.origination.filename);
1093   (void) memset(timestamp,0,sizeof(timestamp));
1094   (void) strftime(timestamp,MaxTextExtent,"%Y:%m:%d:%H:%M:%SUTC",&utc_time);
1095   (void) memset(cin.origination.create_date,0,
1096     sizeof(cin.origination.create_date));
1097   (void) CopyMagickString(cin.origination.create_date,timestamp,11);
1098   offset+=WriteBlob(image,sizeof(cin.origination.create_date),(unsigned char *)
1099     cin.origination.create_date);
1100   (void) memset(cin.origination.create_time,0,
1101      sizeof(cin.origination.create_time));
1102   (void) CopyMagickString(cin.origination.create_time,timestamp+11,15);
1103   offset+=WriteBlob(image,sizeof(cin.origination.create_time),(unsigned char *)
1104     cin.origination.create_time);
1105   value=GetCINProperty(image_info,image,"dpx:origination.device",exception);
1106   if (value != (const char *) NULL)
1107     (void) CopyMagickString(cin.origination.device,value,
1108       sizeof(cin.origination.device));
1109   offset+=WriteBlob(image,sizeof(cin.origination.device),(unsigned char *)
1110     cin.origination.device);
1111   value=GetCINProperty(image_info,image,"dpx:origination.model",exception);
1112   if (value != (const char *) NULL)
1113     (void) CopyMagickString(cin.origination.model,value,
1114       sizeof(cin.origination.model));
1115   offset+=WriteBlob(image,sizeof(cin.origination.model),(unsigned char *)
1116     cin.origination.model);
1117   value=GetCINProperty(image_info,image,"dpx:origination.serial",exception);
1118   if (value != (const char *) NULL)
1119     (void) CopyMagickString(cin.origination.serial,value,
1120       sizeof(cin.origination.serial));
1121   offset+=WriteBlob(image,sizeof(cin.origination.serial),(unsigned char *)
1122     cin.origination.serial);
1123   cin.origination.x_pitch=0.0f;
1124   value=GetCINProperty(image_info,image,"dpx:origination.x_pitch",exception);
1125   if (value != (const char *) NULL)
1126     cin.origination.x_pitch=StringToDouble(value,(char **) NULL);
1127   offset+=WriteBlobFloat(image,cin.origination.x_pitch);
1128   cin.origination.y_pitch=0.0f;
1129   value=GetCINProperty(image_info,image,"dpx:origination.y_pitch",exception);
1130   if (value != (const char *) NULL)
1131     cin.origination.y_pitch=StringToDouble(value,(char **) NULL);
1132   offset+=WriteBlobFloat(image,cin.origination.y_pitch);
1133   cin.origination.gamma=image->gamma;
1134   offset+=WriteBlobFloat(image,cin.origination.gamma);
1135   offset+=WriteBlob(image,sizeof(cin.origination.reserve),(unsigned char *)
1136     cin.origination.reserve);
1137   /*
1138     Image film information.
1139   */
1140   cin.film.id=0;
1141   value=GetCINProperty(image_info,image,"dpx:film.id",exception);
1142   if (value != (const char *) NULL)
1143     cin.film.id=(char) StringToLong(value);
1144   offset+=WriteBlobByte(image,(unsigned char) cin.film.id);
1145   cin.film.type=0;
1146   value=GetCINProperty(image_info,image,"dpx:film.type",exception);
1147   if (value != (const char *) NULL)
1148     cin.film.type=(char) StringToLong(value);
1149   offset+=WriteBlobByte(image,(unsigned char) cin.film.type);
1150   cin.film.offset=0;
1151   value=GetCINProperty(image_info,image,"dpx:film.offset",exception);
1152   if (value != (const char *) NULL)
1153     cin.film.offset=(char) StringToLong(value);
1154   offset+=WriteBlobByte(image,(unsigned char) cin.film.offset);
1155   offset+=WriteBlobByte(image,(unsigned char) cin.film.reserve1);
1156   cin.film.prefix=0UL;
1157   value=GetCINProperty(image_info,image,"dpx:film.prefix",exception);
1158   if (value != (const char *) NULL)
1159     cin.film.prefix=StringToUnsignedLong(value);
1160   offset+=WriteBlobLong(image,(unsigned int) cin.film.prefix);
1161   cin.film.count=0UL;
1162   value=GetCINProperty(image_info,image,"dpx:film.count",exception);
1163   if (value != (const char *) NULL)
1164     cin.film.count=StringToUnsignedLong(value);
1165   offset+=WriteBlobLong(image,(unsigned int) cin.film.count);
1166   value=GetCINProperty(image_info,image,"dpx:film.format",exception);
1167   if (value != (const char *) NULL)
1168     (void) CopyMagickString(cin.film.format,value,sizeof(cin.film.format));
1169   offset+=WriteBlob(image,sizeof(cin.film.format),(unsigned char *)
1170     cin.film.format);
1171   cin.film.frame_position=0UL;
1172   value=GetCINProperty(image_info,image,"dpx:film.frame_position",exception);
1173   if (value != (const char *) NULL)
1174     cin.film.frame_position=StringToUnsignedLong(value);
1175   offset+=WriteBlobLong(image,(unsigned int) cin.film.frame_position);
1176   cin.film.frame_rate=0.0f;
1177   value=GetCINProperty(image_info,image,"dpx:film.frame_rate",exception);
1178   if (value != (const char *) NULL)
1179     cin.film.frame_rate=StringToDouble(value,(char **) NULL);
1180   offset+=WriteBlobFloat(image,cin.film.frame_rate);
1181   value=GetCINProperty(image_info,image,"dpx:film.frame_id",exception);
1182   if (value != (const char *) NULL)
1183     (void) CopyMagickString(cin.film.frame_id,value,sizeof(cin.film.frame_id));
1184   offset+=WriteBlob(image,sizeof(cin.film.frame_id),(unsigned char *)
1185     cin.film.frame_id);
1186   value=GetCINProperty(image_info,image,"dpx:film.slate_info",exception);
1187   if (value != (const char *) NULL)
1188     (void) CopyMagickString(cin.film.slate_info,value,
1189       sizeof(cin.film.slate_info));
1190   offset+=WriteBlob(image,sizeof(cin.film.slate_info),(unsigned char *)
1191     cin.film.slate_info);
1192   offset+=WriteBlob(image,sizeof(cin.film.reserve),(unsigned char *)
1193     cin.film.reserve);
1194   if (profile != (StringInfo *) NULL)
1195     offset+=WriteBlob(image,GetStringInfoLength(profile),
1196       GetStringInfoDatum(profile));
1197   while (offset < (MagickOffsetType) cin.file.image_offset)
1198     offset+=WriteBlobByte(image,0x00);
1199   /*
1200     Convert pixel packets to CIN raster image.
1201   */
1202   quantum_info=AcquireQuantumInfo(image_info,image);
1203   if (quantum_info == (QuantumInfo *) NULL)
1204     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1205   quantum_info->quantum=32;
1206   quantum_info->pack=MagickFalse;
1207   quantum_type=RGBQuantum;
1208   pixels=(unsigned char *) GetQuantumPixels(quantum_info);
1209   length=GetBytesPerRow(image->columns,3,image->depth,MagickTrue);
1210 DisableMSCWarning(4127)
1211   if (0)
1212 RestoreMSCWarning
1213     {
1214       quantum_type=GrayQuantum;
1215       length=GetBytesPerRow(image->columns,1,image->depth,MagickTrue);
1216     }
1217   for (y=0; y < (ssize_t) image->rows; y++)
1218   {
1219     p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1220     if (p == (const Quantum *) NULL)
1221       break;
1222     (void) ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1223       quantum_type,pixels,exception);
1224     count=WriteBlob(image,length,pixels);
1225     if (count != (ssize_t) length)
1226       break;
1227     status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1228       image->rows);
1229     if (status == MagickFalse)
1230       break;
1231   }
1232   quantum_info=DestroyQuantumInfo(quantum_info);
1233   (void) CloseBlob(image);
1234   return(status);
1235 }