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