]> 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 %                                John 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   offset+=ReadBlob(image,sizeof(cin.origination.serial),(unsigned char *)
609     cin.origination.serial);
610   (void) SetImageProperty(image,"dpx:origination.serial",
611     cin.origination.serial,exception);
612   cin.origination.x_pitch=ReadBlobFloat(image);
613   offset+=4;
614   cin.origination.y_pitch=ReadBlobFloat(image);
615   offset+=4;
616   cin.origination.gamma=ReadBlobFloat(image);
617   offset+=4;
618   if (IsFloatDefined(cin.origination.gamma) != MagickFalse)
619     image->gamma=cin.origination.gamma;
620   offset+=ReadBlob(image,sizeof(cin.origination.reserve),(unsigned char *)
621     cin.origination.reserve);
622   if ((cin.file.image_offset > 2048) && (cin.file.user_length != 0))
623     {
624       int
625         c;
626
627       /*
628         Image film information.
629       */
630       cin.film.id=ReadBlobByte(image);
631       offset++;
632       c=cin.film.id;
633       if (c != ~0)
634         (void) FormatImageProperty(image,"dpx:film.id","%d",cin.film.id);
635       cin.film.type=ReadBlobByte(image);
636       offset++;
637       c=cin.film.type;
638       if (c != ~0)
639         (void) FormatImageProperty(image,"dpx:film.type","%d",cin.film.type);
640       cin.film.offset=ReadBlobByte(image);
641       offset++;
642       c=cin.film.offset;
643       if (c != ~0)
644         (void) FormatImageProperty(image,"dpx:film.offset","%d",
645           cin.film.offset);
646       cin.film.reserve1=ReadBlobByte(image);
647       offset++;
648       cin.film.prefix=ReadBlobLong(image);
649       offset+=4;
650       if (cin.film.prefix != ~0UL)
651         (void) FormatImageProperty(image,"dpx:film.prefix","%.20g",(double)
652           cin.film.prefix);
653       cin.film.count=ReadBlobLong(image);
654       offset+=4;
655       offset+=ReadBlob(image,sizeof(cin.film.format),(unsigned char *)
656         cin.film.format);
657       (void) SetImageProperty(image,"dpx:film.format",cin.film.format,
658         exception);
659       cin.film.frame_position=ReadBlobLong(image);
660       offset+=4;
661       if (cin.film.frame_position != ~0UL)
662         (void) FormatImageProperty(image,"dpx:film.frame_position","%.20g",
663           (double) cin.film.frame_position);
664       cin.film.frame_rate=ReadBlobFloat(image);
665       offset+=4;
666       if (IsFloatDefined(cin.film.frame_rate) != MagickFalse)
667         (void) FormatImageProperty(image,"dpx:film.frame_rate","%g",
668           cin.film.frame_rate);
669       offset+=ReadBlob(image,sizeof(cin.film.frame_id),(unsigned char *)
670         cin.film.frame_id);
671       (void) SetImageProperty(image,"dpx:film.frame_id",cin.film.frame_id,
672         exception);
673       offset+=ReadBlob(image,sizeof(cin.film.slate_info),(unsigned char *)
674         cin.film.slate_info);
675       (void) SetImageProperty(image,"dpx:film.slate_info",cin.film.slate_info,
676         exception);
677       offset+=ReadBlob(image,sizeof(cin.film.reserve),(unsigned char *)
678         cin.film.reserve);
679     }
680   if ((cin.file.image_offset > 2048) && (cin.file.user_length != 0))
681     {
682       StringInfo
683         *profile;
684
685       /*
686         User defined data.
687       */
688       profile=BlobToStringInfo((const void *) NULL,cin.file.user_length);
689       if (profile == (StringInfo *) NULL)
690         ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
691       offset+=ReadBlob(image,GetStringInfoLength(profile),
692         GetStringInfoDatum(profile));
693       (void) SetImageProfile(image,"dpx:user.data",profile,exception);
694       profile=DestroyStringInfo(profile);
695     }
696   for ( ; offset < (MagickOffsetType) cin.file.image_offset; offset++)
697     (void) ReadBlobByte(image);
698   image->depth=cin.image.channel[0].bits_per_pixel;
699   image->columns=cin.image.channel[0].pixels_per_line;
700   image->rows=cin.image.channel[0].lines_per_image;
701   if (image_info->ping)
702     {
703       (void) CloseBlob(image);
704       return(image);
705     }
706   /*
707     Convert CIN raster image to pixel packets.
708   */
709   quantum_info=AcquireQuantumInfo(image_info,image);
710   if (quantum_info == (QuantumInfo *) NULL)
711     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
712   quantum_info->quantum=32;
713   quantum_info->pack=MagickFalse;
714   quantum_type=RGBQuantum;
715   pixels=GetQuantumPixels(quantum_info);
716   length=GetQuantumExtent(image,quantum_info,quantum_type);
717   length=GetBytesPerRow(image->columns,3,image->depth,MagickTrue);
718   if (cin.image.number_channels == 1)
719     {
720       quantum_type=GrayQuantum;
721       length=GetBytesPerRow(image->columns,1,image->depth,MagickTrue);
722     }
723   for (y=0; y < (ssize_t) image->rows; y++)
724   {
725     q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
726     if (q == (Quantum *) NULL)
727       break;
728     count=ReadBlob(image,length,pixels);
729     if ((size_t) count != length)
730       break;
731     (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
732       quantum_type,pixels,exception);
733     if (SyncAuthenticPixels(image,exception) == MagickFalse)
734       break;
735     if (image->previous == (Image *) NULL)
736       {
737         status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
738           image->rows);
739         if (status == MagickFalse)
740           break;
741       }
742   }
743   SetQuantumImageType(image,quantum_type);
744   quantum_info=DestroyQuantumInfo(quantum_info);
745   if (EOFBlob(image) != MagickFalse)
746     ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
747       image->filename);
748   SetImageColorspace(image,LogColorspace,exception);
749   (void) CloseBlob(image);
750   return(GetFirstImageInList(image));
751 }
752 \f
753 /*
754 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
755 %                                                                             %
756 %                                                                             %
757 %                                                                             %
758 %   R e g i s t e r C I N E O N I m a g e                                     %
759 %                                                                             %
760 %                                                                             %
761 %                                                                             %
762 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
763 %
764 %  RegisterCINImage() adds attributes for the CIN image format to the list of
765 %  of supported formats.  The attributes include the image format tag, a method
766 %  to read and/or write the format, whether the format supports the saving of
767 %  more than one frame to the same file or blob, whether the format supports
768 %  native in-memory I/O, and a brief description of the format.
769 %
770 %  The format of the RegisterCINImage method is:
771 %
772 %      size_t RegisterCINImage(void)
773 %
774 */
775 ModuleExport size_t RegisterCINImage(void)
776 {
777   MagickInfo
778     *entry;
779
780   entry=SetMagickInfo("CIN");
781   entry->decoder=(DecodeImageHandler *) ReadCINImage;
782   entry->encoder=(EncodeImageHandler *) WriteCINImage;
783   entry->magick=(IsImageFormatHandler *) IsCIN;
784   entry->adjoin=MagickFalse;
785   entry->description=ConstantString("Cineon Image File");
786   entry->module=ConstantString("CIN");
787   (void) RegisterMagickInfo(entry);
788   return(MagickImageCoderSignature);
789 }
790 \f
791 /*
792 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
793 %                                                                             %
794 %                                                                             %
795 %                                                                             %
796 %   U n r e g i s t e r C I N E O N I m a g e                                 %
797 %                                                                             %
798 %                                                                             %
799 %                                                                             %
800 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
801 %
802 %  UnregisterCINImage() removes format registrations made by the CIN module
803 %  from the list of supported formats.
804 %
805 %  The format of the UnregisterCINImage method is:
806 %
807 %      UnregisterCINImage(void)
808 %
809 */
810 ModuleExport void UnregisterCINImage(void)
811 {
812   (void) UnregisterMagickInfo("CINEON");
813 }
814 \f
815 /*
816 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
817 %                                                                             %
818 %                                                                             %
819 %                                                                             %
820 %   W r i t e C I N E O N I m a g e                                           %
821 %                                                                             %
822 %                                                                             %
823 %                                                                             %
824 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
825 %
826 %  WriteCINImage() writes an image in CIN encoded image format.
827 %
828 %  The format of the WriteCINImage method is:
829 %
830 %      MagickBooleanType WriteCINImage(const ImageInfo *image_info,
831 %        Image *image,ExceptionInfo *exception)
832 %
833 %  A description of each parameter follows.
834 %
835 %    o image_info: the image info.
836 %
837 %    o image:  The image.
838 %
839 %    o exception: return any errors or warnings in this structure.
840 %
841 */
842
843 static inline const char *GetCINProperty(const ImageInfo *image_info,
844   const Image *image,const char *property,ExceptionInfo *exception)
845 {
846   const char
847     *value;
848
849   value=GetImageOption(image_info,property);
850   if (value != (const char *) NULL)
851     return(value);
852   return(GetImageProperty(image,property,exception));
853 }
854
855 static MagickBooleanType WriteCINImage(const ImageInfo *image_info,Image *image,
856   ExceptionInfo *exception)
857 {
858   const char
859     *value;
860
861   CINInfo
862     cin;
863
864   const StringInfo
865     *profile;
866
867   MagickBooleanType
868     status;
869
870   MagickOffsetType
871     offset;
872
873   QuantumInfo
874     *quantum_info;
875
876   QuantumType
877     quantum_type;
878
879   register const Quantum
880     *p;
881
882   register ssize_t
883     i;
884
885   size_t
886     length;
887
888   ssize_t
889     count,
890     y;
891
892   struct tm
893     local_time;
894
895   time_t
896     seconds;
897
898   unsigned char
899     *pixels;
900
901   /*
902     Open output image file.
903   */
904   assert(image_info != (const ImageInfo *) NULL);
905   assert(image_info->signature == MagickSignature);
906   assert(image != (Image *) NULL);
907   assert(image->signature == MagickSignature);
908   if (image->debug != MagickFalse)
909     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
910   assert(exception != (ExceptionInfo *) NULL);
911   assert(exception->signature == MagickSignature);
912   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
913   if (status == MagickFalse)
914     return(status);
915   if (image->colorspace != LogColorspace)
916     (void) TransformImageColorspace(image,LogColorspace,exception);
917   /*
918     Write image information.
919   */
920   (void) ResetMagickMemory(&cin,0,sizeof(cin));
921   offset=0;
922   cin.file.magic=0x802A5FD7UL;
923   offset+=WriteBlobLong(image,(unsigned int) cin.file.magic);
924   cin.file.image_offset=0x800;
925   offset+=WriteBlobLong(image,(unsigned int) cin.file.image_offset);
926   cin.file.generic_length=0x400;
927   offset+=WriteBlobLong(image,(unsigned int) cin.file.generic_length);
928   cin.file.industry_length=0x400;
929   offset+=WriteBlobLong(image,(unsigned int) cin.file.industry_length);
930   cin.file.user_length=0x00;
931   profile=GetImageProfile(image,"dpx:user.data");
932   if (profile != (StringInfo *) NULL)
933     {
934       cin.file.user_length+=(size_t) GetStringInfoLength(profile);
935       cin.file.user_length=(((cin.file.user_length+0x2000-1)/0x2000)*0x2000);
936     }
937   offset+=WriteBlobLong(image,(unsigned int) cin.file.user_length);
938   cin.file.file_size=4*image->columns*image->rows+0x2000;
939   offset+=WriteBlobLong(image,(unsigned int) cin.file.file_size);
940   (void) CopyMagickString(cin.file.version,"V4.5",sizeof(cin.file.version));
941   offset+=WriteBlob(image,sizeof(cin.file.version),(unsigned char *)
942     cin.file.version);
943   value=GetCINProperty(image_info,image,"dpx:file.filename",exception);
944   if (value != (const char *) NULL)
945     (void) CopyMagickString(cin.file.filename,value,sizeof(cin.file.filename));
946   else
947     (void) CopyMagickString(cin.file.filename,image->filename,
948       sizeof(cin.file.filename));
949   offset+=WriteBlob(image,sizeof(cin.file.filename),(unsigned char *)
950     cin.file.filename);
951   seconds=time((time_t *) NULL);
952 #if defined(MAGICKCORE_HAVE_LOCALTIME_R)
953   (void) localtime_r(&seconds,&local_time);
954 #else
955   (void) memcpy(&local_time,localtime(&seconds),sizeof(local_time));
956 #endif
957   (void) strftime(cin.file.create_date,sizeof(cin.file.create_date),"%Y:%m:%d",
958     &local_time);
959   offset+=WriteBlob(image,sizeof(cin.file.create_date),(unsigned char *)
960     cin.file.create_date);
961   (void) strftime(cin.file.create_time,sizeof(cin.file.create_time),
962     "%H:%M:%S%Z",&local_time);
963   offset+=WriteBlob(image,sizeof(cin.file.create_time),(unsigned char *)
964     cin.file.create_time);
965   offset+=WriteBlob(image,sizeof(cin.file.reserve),(unsigned char *)
966     cin.file.reserve);
967   cin.image.orientation=0x00;
968   offset+=WriteBlobByte(image,cin.image.orientation);
969   cin.image.number_channels=3;
970   offset+=WriteBlobByte(image,cin.image.number_channels);
971   offset+=WriteBlob(image,sizeof(cin.image.reserve1),(unsigned char *)
972     cin.image.reserve1);
973   for (i=0; i < 8; i++)
974   {
975     cin.image.channel[i].designator[0]=0; /* universal metric */
976     offset+=WriteBlobByte(image,cin.image.channel[0].designator[0]);
977     cin.image.channel[i].designator[1]=(unsigned char) (i > 3 ? 0 : i+1); /* channel color */;
978     offset+=WriteBlobByte(image,cin.image.channel[1].designator[0]);
979     cin.image.channel[i].bits_per_pixel=(unsigned char) image->depth;
980     offset+=WriteBlobByte(image,cin.image.channel[0].bits_per_pixel);
981     offset+=WriteBlobByte(image,cin.image.channel[0].reserve);
982     cin.image.channel[i].pixels_per_line=image->columns;
983     offset+=WriteBlobLong(image,(unsigned int)
984       cin.image.channel[0].pixels_per_line);
985     cin.image.channel[i].lines_per_image=image->rows;
986     offset+=WriteBlobLong(image,(unsigned int)
987       cin.image.channel[0].lines_per_image);
988     cin.image.channel[i].min_data=0;
989     offset+=WriteBlobFloat(image,cin.image.channel[0].min_data);
990     cin.image.channel[i].min_quantity=0.0;
991     offset+=WriteBlobFloat(image,cin.image.channel[0].min_quantity);
992     cin.image.channel[i].max_data=(float) ((MagickOffsetType)
993       GetQuantumRange(image->depth));
994     offset+=WriteBlobFloat(image,cin.image.channel[0].max_data);
995     cin.image.channel[i].max_quantity=2.048f;
996     offset+=WriteBlobFloat(image,cin.image.channel[0].max_quantity);
997   }
998   offset+=WriteBlobFloat(image,image->chromaticity.white_point.x);
999   offset+=WriteBlobFloat(image,image->chromaticity.white_point.y);
1000   offset+=WriteBlobFloat(image,image->chromaticity.red_primary.x);
1001   offset+=WriteBlobFloat(image,image->chromaticity.red_primary.y);
1002   offset+=WriteBlobFloat(image,image->chromaticity.green_primary.x);
1003   offset+=WriteBlobFloat(image,image->chromaticity.green_primary.y);
1004   offset+=WriteBlobFloat(image,image->chromaticity.blue_primary.x);
1005   offset+=WriteBlobFloat(image,image->chromaticity.blue_primary.y);
1006   value=GetCINProperty(image_info,image,"dpx:image.label",exception);
1007   if (value != (const char *) NULL)
1008     (void) CopyMagickString(cin.image.label,value,sizeof(cin.image.label));
1009   offset+=WriteBlob(image,sizeof(cin.image.label),(unsigned char *)
1010     cin.image.label);
1011   offset+=WriteBlob(image,sizeof(cin.image.reserve),(unsigned char *)
1012     cin.image.reserve);
1013   /*
1014     Write data format information.
1015   */
1016   cin.data_format.interleave=0; /* pixel interleave (rgbrgbr...) */
1017   offset+=WriteBlobByte(image,cin.data_format.interleave);
1018   cin.data_format.packing=5; /* packing ssize_tword (32bit) boundaries */
1019   offset+=WriteBlobByte(image,cin.data_format.packing);
1020   cin.data_format.sign=0; /* unsigned data */
1021   offset+=WriteBlobByte(image,cin.data_format.sign);
1022   cin.data_format.sense=0; /* image sense: positive image */
1023   offset+=WriteBlobByte(image,cin.data_format.sense);
1024   cin.data_format.line_pad=0;
1025   offset+=WriteBlobLong(image,(unsigned int) cin.data_format.line_pad);
1026   cin.data_format.channel_pad=0;
1027   offset+=WriteBlobLong(image,(unsigned int) cin.data_format.channel_pad);
1028   offset+=WriteBlob(image,sizeof(cin.data_format.reserve),(unsigned char *)
1029     cin.data_format.reserve);
1030   /*
1031     Write origination information.
1032   */
1033   cin.origination.x_offset=0UL;
1034   value=GetCINProperty(image_info,image,"dpx:origination.x_offset",exception);
1035   if (value != (const char *) NULL)
1036     cin.origination.x_offset=(ssize_t) StringToLong(value);
1037   offset+=WriteBlobLong(image,(unsigned int) cin.origination.x_offset);
1038   cin.origination.y_offset=0UL;
1039   value=GetCINProperty(image_info,image,"dpx:origination.y_offset",exception);
1040   if (value != (const char *) NULL)
1041     cin.origination.y_offset=(ssize_t) StringToLong(value);
1042   offset+=WriteBlobLong(image,(unsigned int) cin.origination.y_offset);
1043   value=GetCINProperty(image_info,image,"dpx:origination.filename",exception);
1044   if (value != (const char *) NULL)
1045     (void) CopyMagickString(cin.origination.filename,value,
1046       sizeof(cin.origination.filename));
1047   else
1048     (void) CopyMagickString(cin.origination.filename,image->filename,
1049       sizeof(cin.origination.filename));
1050   offset+=WriteBlob(image,sizeof(cin.origination.filename),(unsigned char *)
1051     cin.origination.filename);
1052   seconds=time((time_t *) NULL);
1053   (void) strftime(cin.origination.create_date,
1054     sizeof(cin.origination.create_date),"%Y:%m:%d",&local_time);
1055   offset+=WriteBlob(image,sizeof(cin.origination.create_date),(unsigned char *)
1056     cin.origination.create_date);
1057   (void) strftime(cin.origination.create_time,
1058     sizeof(cin.origination.create_time),"%H:%M:%S%Z",&local_time);
1059   offset+=WriteBlob(image,sizeof(cin.origination.create_time),(unsigned char *)
1060     cin.origination.create_time);
1061   value=GetCINProperty(image_info,image,"dpx:origination.device",exception);
1062   if (value != (const char *) NULL)
1063     (void) CopyMagickString(cin.origination.device,value,
1064       sizeof(cin.origination.device));
1065   offset+=WriteBlob(image,sizeof(cin.origination.device),(unsigned char *)
1066     cin.origination.device);
1067   value=GetCINProperty(image_info,image,"dpx:origination.model",exception);
1068   if (value != (const char *) NULL)
1069     (void) CopyMagickString(cin.origination.model,value,
1070       sizeof(cin.origination.model));
1071   offset+=WriteBlob(image,sizeof(cin.origination.model),(unsigned char *)
1072     cin.origination.model);
1073   value=GetCINProperty(image_info,image,"dpx:origination.serial",exception);
1074   if (value != (const char *) NULL)
1075     (void) CopyMagickString(cin.origination.serial,value,
1076       sizeof(cin.origination.serial));
1077   offset+=WriteBlob(image,sizeof(cin.origination.serial),(unsigned char *)
1078     cin.origination.serial);
1079   cin.origination.x_pitch=0.0f;
1080   value=GetCINProperty(image_info,image,"dpx:origination.x_pitch",exception);
1081   if (value != (const char *) NULL)
1082     cin.origination.x_pitch=StringToDouble(value,(char **) NULL);
1083   offset+=WriteBlobFloat(image,cin.origination.x_pitch);
1084   cin.origination.y_pitch=0.0f;
1085   value=GetCINProperty(image_info,image,"dpx:origination.y_pitch",exception);
1086   if (value != (const char *) NULL)
1087     cin.origination.y_pitch=StringToDouble(value,(char **) NULL);
1088   offset+=WriteBlobFloat(image,cin.origination.y_pitch);
1089   cin.origination.gamma=image->gamma;
1090   offset+=WriteBlobFloat(image,cin.origination.gamma);
1091   offset+=WriteBlob(image,sizeof(cin.origination.reserve),(unsigned char *)
1092     cin.origination.reserve);
1093   /*
1094     Image film information.
1095   */
1096   cin.film.id=0;
1097   value=GetCINProperty(image_info,image,"dpx:film.id",exception);
1098   if (value != (const char *) NULL)
1099     cin.film.id=(char) StringToLong(value);
1100   offset+=WriteBlobByte(image,(unsigned char) cin.film.id);
1101   cin.film.type=0;
1102   value=GetCINProperty(image_info,image,"dpx:film.type",exception);
1103   if (value != (const char *) NULL)
1104     cin.film.type=(char) StringToLong(value);
1105   offset+=WriteBlobByte(image,(unsigned char) cin.film.type);
1106   cin.film.offset=0;
1107   value=GetCINProperty(image_info,image,"dpx:film.offset",exception);
1108   if (value != (const char *) NULL)
1109     cin.film.offset=(char) StringToLong(value);
1110   offset+=WriteBlobByte(image,(unsigned char) cin.film.offset);
1111   offset+=WriteBlobByte(image,(unsigned char) cin.film.reserve1);
1112   cin.film.prefix=0UL;
1113   value=GetCINProperty(image_info,image,"dpx:film.prefix",exception);
1114   if (value != (const char *) NULL)
1115     cin.film.prefix=StringToUnsignedLong(value);
1116   offset+=WriteBlobLong(image,(unsigned int) cin.film.prefix);
1117   cin.film.count=0UL;
1118   value=GetCINProperty(image_info,image,"dpx:film.count",exception);
1119   if (value != (const char *) NULL)
1120     cin.film.count=StringToUnsignedLong(value);
1121   offset+=WriteBlobLong(image,(unsigned int) cin.film.count);
1122   value=GetCINProperty(image_info,image,"dpx:film.format",exception);
1123   if (value != (const char *) NULL)
1124     (void) CopyMagickString(cin.film.format,value,sizeof(cin.film.format));
1125   offset+=WriteBlob(image,sizeof(cin.film.format),(unsigned char *)
1126     cin.film.format);
1127   cin.film.frame_position=0UL;
1128   value=GetCINProperty(image_info,image,"dpx:film.frame_position",exception);
1129   if (value != (const char *) NULL)
1130     cin.film.frame_position=StringToUnsignedLong(value);
1131   offset+=WriteBlobLong(image,(unsigned int) cin.film.frame_position);
1132   cin.film.frame_rate=0.0f;
1133   value=GetCINProperty(image_info,image,"dpx:film.frame_rate",exception);
1134   if (value != (const char *) NULL)
1135     cin.film.frame_rate=StringToDouble(value,(char **) NULL);
1136   offset+=WriteBlobFloat(image,cin.film.frame_rate);
1137   value=GetCINProperty(image_info,image,"dpx:film.frame_id",exception);
1138   if (value != (const char *) NULL)
1139     (void) CopyMagickString(cin.film.frame_id,value,sizeof(cin.film.frame_id));
1140   offset+=WriteBlob(image,sizeof(cin.film.frame_id),(unsigned char *)
1141     cin.film.frame_id);
1142   value=GetCINProperty(image_info,image,"dpx:film.slate_info",exception);
1143   if (value != (const char *) NULL)
1144     (void) CopyMagickString(cin.film.slate_info,value,
1145       sizeof(cin.film.slate_info));
1146   offset+=WriteBlob(image,sizeof(cin.film.slate_info),(unsigned char *)
1147     cin.film.slate_info);
1148   offset+=WriteBlob(image,sizeof(cin.film.reserve),(unsigned char *)
1149     cin.film.reserve);
1150   if (profile != (StringInfo *) NULL)
1151     offset+=WriteBlob(image,GetStringInfoLength(profile),
1152       GetStringInfoDatum(profile));
1153   while (offset < (MagickOffsetType) cin.file.image_offset)
1154     offset+=WriteBlobByte(image,0x00);
1155   /*
1156     Convert pixel packets to CIN raster image.
1157   */
1158   quantum_info=AcquireQuantumInfo(image_info,image);
1159   if (quantum_info == (QuantumInfo *) NULL)
1160     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1161   quantum_info->quantum=32;
1162   quantum_info->pack=MagickFalse;
1163   quantum_type=RGBQuantum;
1164   pixels=GetQuantumPixels(quantum_info);
1165   length=GetBytesPerRow(image->columns,3,image->depth,MagickTrue);
1166 DisableMSCWarning(4127)
1167   if (0)
1168 RestoreMSCWarning
1169     {
1170       quantum_type=GrayQuantum;
1171       length=GetBytesPerRow(image->columns,1,image->depth,MagickTrue);
1172     }
1173   for (y=0; y < (ssize_t) image->rows; y++)
1174   {
1175     p=GetVirtualPixels(image,0,y,image->columns,1,exception);
1176     if (p == (const Quantum *) NULL)
1177       break;
1178     (void) ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1179       quantum_type,pixels,exception);
1180     count=WriteBlob(image,length,pixels);
1181     if (count != (ssize_t) length)
1182       break;
1183     status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1184       image->rows);
1185     if (status == MagickFalse)
1186       break;
1187   }
1188   quantum_info=DestroyQuantumInfo(quantum_info);
1189   (void) CloseBlob(image);
1190   return(status);
1191 }