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