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