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