root / ImageMagick / trunk / coders / cin.c

Revision 12707, 39.7 kB (checked in by cristy, 2 days ago)
Line 
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-2008 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
46/*
47  Include declarations.
48*/
49#include "magick/studio.h"
50#include "magick/blob.h"
51#include "magick/blob-private.h"
52#include "magick/colorspace.h"
53#include "magick/exception.h"
54#include "magick/exception-private.h"
55#include "magick/image.h"
56#include "magick/image-private.h"
57#include "magick/list.h"
58#include "magick/magick.h"
59#include "magick/memory_.h"
60#include "magick/monitor.h"
61#include "magick/monitor-private.h"
62#include "magick/option.h"
63#include "magick/profile.h"
64#include "magick/property.h"
65#include "magick/quantum-private.h"
66#include "magick/quantum-private.h"
67#include "magick/static.h"
68#include "magick/string_.h"
69#include "magick/module.h"
70
71/*
72  Typedef declaration.
73*/
74typedef struct _CINDataFormatInfo
75{
76  unsigned char
77    interleave,
78    packing,
79    sign,
80    sense;
81
82  unsigned long
83    line_pad,
84    channel_pad;
85
86  unsigned char
87    reserve[20];
88} CINDataFormatInfo;
89
90typedef struct _CINFileInfo
91{
92  unsigned long
93    magic,
94    image_offset,
95    generic_length,
96    industry_length,
97    user_length,
98    file_size;
99
100  char
101    version[8],
102    filename[100],
103    create_date[12],
104    create_time[12],
105    reserve[36];
106} CINFileInfo;
107
108typedef struct _CINFilmInfo
109{
110  char
111    id,
112    type,
113    offset,
114    reserve1;
115
116  unsigned long
117    prefix,
118    count;
119
120  char
121    format[32];
122
123  unsigned long
124    frame_position;
125
126  float
127    frame_rate;
128
129  char
130    frame_id[32],
131    slate_info[200],
132    reserve[740];
133} CINFilmInfo;
134
135typedef struct _CINImageChannel
136{
137  unsigned char
138    designator[2],
139    bits_per_pixel,
140    reserve;
141
142  unsigned long
143    pixels_per_line,
144    lines_per_image;
145
146  float
147    min_data,
148    min_quantity,
149    max_data,
150    max_quantity;
151} CINImageChannel;
152
153typedef struct _CINImageInfo
154{
155  unsigned char
156    orientation,
157    number_channels,
158    reserve1[2];
159
160  CINImageChannel
161    channel[8];
162
163  float
164    white_point[2],
165    red_primary_chromaticity[2],
166    green_primary_chromaticity[2],
167    blue_primary_chromaticity[2];
168
169  char
170    label[200],
171    reserve[28];
172} CINImageInfo;
173
174typedef struct _CINOriginationInfo
175{
176  long
177    x_offset,
178    y_offset;
179
180  char
181    filename[100],
182    create_date[12],
183    create_time[12],
184    device[64],
185    model[32],
186    serial[32];
187
188  float
189    x_pitch,
190    y_pitch,
191    gamma;
192
193  char
194    reserve[40];
195} CINOriginationInfo;
196
197typedef struct _CINUserInfo
198{
199  char
200    id[32];
201} CINUserInfo;
202
203typedef struct CINInfo
204{
205  CINFileInfo
206    file;
207
208  CINImageInfo
209    image;
210
211  CINDataFormatInfo
212    data_format;
213
214  CINOriginationInfo
215    origination;
216
217  CINFilmInfo
218    film;
219
220  CINUserInfo
221    user;
222} CINInfo;
223
224/*
225  Forward declaractions.
226*/
227static MagickBooleanType
228  WriteCINImage(const ImageInfo *,Image *);
229
230/*
231%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
232%                                                                             %
233%                                                                             %
234%                                                                             %
235%   I s C I N E O N                                                           %
236%                                                                             %
237%                                                                             %
238%                                                                             %
239%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
240%
241%  IsCIN() returns MagickTrue if the image format type, identified by the magick
242%  string, is CIN.
243%
244%  The format of the IsCIN method is:
245%
246%      MagickBooleanType IsCIN(const unsigned char *magick,const size_t length)
247%
248%  A description of each parameter follows:
249%
250%    o magick: This string is generally the first few bytes of an image file
251%      or blob.
252%
253%    o length: Specifies the length of the magick string.
254%
255*/
256static MagickBooleanType IsCIN(const unsigned char *magick,const size_t length)
257{
258  if (length < 4)
259    return(MagickFalse);
260  if (memcmp(magick,"\200\052\137\327",4) == 0)
261    return(MagickTrue);
262  return(MagickFalse);
263}
264
265/*
266%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
267%                                                                             %
268%                                                                             %
269%                                                                             %
270%   R e a d C I N E O N I m a g e                                             %
271%                                                                             %
272%                                                                             %
273%                                                                             %
274%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
275%
276%  ReadCINImage() reads an CIN X image file and returns it.  It allocates
277%  the memory necessary for the new Image structure and returns a point to the
278%  new image.
279%
280%  The format of the ReadCINImage method is:
281%
282%      Image *ReadCINImage(const ImageInfo *image_info,
283%        ExceptionInfo *exception)
284%
285%  A description of each parameter follows:
286%
287%    o image_info: the image info.
288%
289%    o exception: return any errors or warnings in this structure.
290%
291*/
292
293static size_t GetBytesPerRow(unsigned long columns,
294  unsigned long samples_per_pixel,unsigned long bits_per_pixel,
295  MagickBooleanType pad)
296{
297  size_t
298    bytes_per_row;
299
300  switch (bits_per_pixel)
301  {
302    case 1:
303    {
304      bytes_per_row=4*(((size_t) samples_per_pixel*columns*
305        bits_per_pixel+31)/32);
306      break;
307    }
308    case 8:
309    default:
310    {
311      bytes_per_row=4*(((size_t) samples_per_pixel*columns*
312        bits_per_pixel+31)/32);
313      break;
314    }
315    case 10:
316    {
317      if (pad == MagickFalse)
318        {
319          bytes_per_row=4*(((size_t) samples_per_pixel*columns*
320            bits_per_pixel+31)/32);
321          break;
322        }
323      bytes_per_row=4*(((size_t) (32*((samples_per_pixel*columns+2)/3))+31)/32);
324      break;
325    }
326    case 12:
327    {
328      if (pad == MagickFalse)
329        {
330          bytes_per_row=4*(((size_t) samples_per_pixel*columns*
331            bits_per_pixel+31)/32);
332          break;
333        }
334      bytes_per_row=2*(((size_t) (16*samples_per_pixel*columns)+15)/16);
335      break;
336    }
337    case 16:
338    {
339      bytes_per_row=2*(((size_t) samples_per_pixel*columns*
340        bits_per_pixel+8)/16);
341      break;
342    }
343    case 32:
344    {
345      bytes_per_row=4*(((size_t) samples_per_pixel*columns*
346        bits_per_pixel+31)/32);
347      break;
348    }
349    case 64:
350    {
351      bytes_per_row=8*(((size_t) samples_per_pixel*columns*
352        bits_per_pixel+63)/64);
353      break;
354    }
355  }
356  return(bytes_per_row);
357}
358
359static inline MagickBooleanType IsFloatDefined(const float value)
360{
361  union
362  {
363    unsigned long
364      unsigned_value;
365
366    double
367      float_value;
368  } quantum;
369
370  quantum.float_value=value;
371  if (quantum.unsigned_value == 0U)
372    return(MagickFalse);
373  return(MagickTrue);
374}
375
376static Image *ReadCINImage(const ImageInfo *image_info,
377  ExceptionInfo *exception)
378{
379#define MonoColorType  1
380#define RGBColorType  3
381
382  char
383    magick[4];
384
385  CINInfo
386    cin;
387
388  Image
389    *image;
390
391  long
392    y;
393
394  MagickBooleanType
395    status;
396
397  MagickOffsetType
398    offset;
399
400  QuantumInfo
401    *quantum_info;
402
403  QuantumType
404    quantum_type;
405
406  register long
407    i;
408
409  register PixelPacket
410    *q;
411
412  size_t
413    length;
414
415  ssize_t
416    count;
417
418  unsigned char
419    *pixels;
420
421  unsigned long
422    lsb_first;
423
424  /*
425    Open image file.
426  */
427  assert(image_info != (const ImageInfo *) NULL);
428  assert(image_info->signature == MagickSignature);
429  if (image_info->debug != MagickFalse)
430    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
431      image_info->filename);
432  assert(exception != (ExceptionInfo *) NULL);
433  assert(exception->signature == MagickSignature);
434  image=AcquireImage(image_info);
435  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
436  if (status == MagickFalse)
437    {
438      image=DestroyImageList(image);
439      return((Image *) NULL);
440    }
441  /*
442    File information.
443  */
444  offset=0;
445  count=ReadBlob(image,4,(unsigned char *) magick);
446  offset+=count;
447  if ((count != 4) ||
448      ((LocaleNCompare((char *) magick,"\200\052\137\327",4) != 0)))
449    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
450  image->endian=LSBEndian;
451  lsb_first=1;
452  if ((int) (*(char *) &lsb_first) != 0)
453    image->endian=MSBEndian;
454  cin.file.image_offset=ReadBlobLong(image);
455  offset+=4;
456  cin.file.generic_length=ReadBlobLong(image);
457  offset+=4;
458  cin.file.industry_length=ReadBlobLong(image);
459  offset+=4;
460  cin.file.user_length=ReadBlobLong(image);
461  offset+=4;
462  cin.file.file_size=ReadBlobLong(image);
463  offset+=4;
464  offset+=ReadBlob(image,sizeof(cin.file.version),(unsigned char *)
465    cin.file.version);
466  (void) SetImageProperty(image,"cin:file.version",cin.file.version);
467  offset+=ReadBlob(image,sizeof(cin.file.filename),(unsigned char *)
468    cin.file.filename);
469  (void) SetImageProperty(image,"cin:file.filename",cin.file.filename);
470  offset+=ReadBlob(image,sizeof(cin.file.create_date),(unsigned char *)
471    cin.file.create_date);
472  (void) SetImageProperty(image,"cin:file.create_date",cin.file.create_date);
473  offset+=ReadBlob(image,sizeof(cin.file.create_time),(unsigned char *)
474    cin.file.create_time);
475  (void) SetImageProperty(image,"cin:file.create_time",cin.file.create_time);
476  offset+=ReadBlob(image,sizeof(cin.file.reserve),(unsigned char *)
477    cin.file.reserve);
478  /*
479    Image information.
480  */
481  cin.image.orientation=(unsigned char) ReadBlobByte(image);
482  offset++;
483  if (cin.image.orientation != (unsigned char) (~0U))
484    (void) FormatImageProperty(image,"cin:image.orientation","%d",
485      cin.image.orientation);
486  switch (cin.image.orientation)
487  {
488    default:
489    case 0:  image->orientation=TopLeftOrientation; break;
490    case 1:  image->orientation=TopRightOrientation; break;
491    case 2:  image->orientation=BottomLeftOrientation; break;
492    case 3:  image->orientation=BottomRightOrientation; break;
493    case 4:  image->orientation=LeftTopOrientation; break;
494    case 5:  image->orientation=RightTopOrientation; break;
495    case 6:  image->orientation=LeftBottomOrientation; break;
496    case 7:  image->orientation=RightBottomOrientation; break;
497  }
498  cin.image.number_channels=(unsigned char) ReadBlobByte(image);
499  offset++;
500  offset+=ReadBlob(image,sizeof(cin.image.reserve1),(unsigned char *)
501    cin.image.reserve1);
502  for (i=0; i < 8; i++)
503  {
504    cin.image.channel[i].designator[0]=(unsigned char) ReadBlobByte(image);
505    offset++;
506    cin.image.channel[i].designator[1]=(unsigned char) ReadBlobByte(image);
507    offset++;
508    cin.image.channel[i].bits_per_pixel=(unsigned char) ReadBlobByte(image);
509    offset++;
510    cin.image.channel[i].reserve=(unsigned char) ReadBlobByte(image);
511    offset++;
512    cin.image.channel[i].pixels_per_line=ReadBlobLong(image);
513    offset+=4;
514    cin.image.channel[i].lines_per_image=ReadBlobLong(image);
515    offset+=4;
516    cin.image.channel[i].min_data=ReadBlobFloat(image);
517    offset+=4;
518    cin.image.channel[i].min_quantity=ReadBlobFloat(image);
519    offset+=4;
520    cin.image.channel[i].max_data=ReadBlobFloat(image);
521    offset+=4;
522    cin.image.channel[i].max_quantity=ReadBlobFloat(image);
523    offset+=4;
524  }
525  cin.image.white_point[0]=ReadBlobFloat(image);
526  offset+=4;
527  if (IsFloatDefined(cin.image.white_point[0]) != MagickFalse)
528    image->chromaticity.white_point.x=cin.image.white_point[0];
529  cin.image.white_point[1]=ReadBlobFloat(image);
530  offset+=4;
531  if (IsFloatDefined(cin.image.white_point[1]) != MagickFalse)
532    image->chromaticity.white_point.y=cin.image.white_point[1];
533  cin.image.red_primary_chromaticity[0]=ReadBlobFloat(image);
534  offset+=4;
535  if (IsFloatDefined(cin.image.red_primary_chromaticity[0]) != MagickFalse)
536    image->chromaticity.red_primary.x=cin.image.red_primary_chromaticity[0];
537  cin.image.red_primary_chromaticity[1]=ReadBlobFloat(image);
538  offset+=4;
539  if (IsFloatDefined(cin.image.red_primary_chromaticity[1]) != MagickFalse)
540    image->chromaticity.red_primary.y=cin.image.red_primary_chromaticity[1];
541  cin.image.green_primary_chromaticity[0]=ReadBlobFloat(image);
542  offset+=4;
543  if (IsFloatDefined(cin.image.green_primary_chromaticity[0]) != MagickFalse)
544    image->chromaticity.red_primary.x=cin.image.green_primary_chromaticity[0];
545  cin.image.green_primary_chromaticity[1]=ReadBlobFloat(image);
546  offset+=4;
547  if (IsFloatDefined(cin.image.green_primary_chromaticity[1]) != MagickFalse)
548    image->chromaticity.green_primary.y=cin.image.green_primary_chromaticity[1];
549  cin.image.blue_primary_chromaticity[0]=ReadBlobFloat(image);
550  offset+=4;
551  if (IsFloatDefined(cin.image.blue_primary_chromaticity[0]) != MagickFalse)
552    image->chromaticity.blue_primary.x=cin.image.blue_primary_chromaticity[0];
553  cin.image.blue_primary_chromaticity[1]=ReadBlobFloat(image);
554  offset+=4;
555  if (IsFloatDefined(cin.image.blue_primary_chromaticity[1]) != MagickFalse)
556    image->chromaticity.blue_primary.y=cin.image.blue_primary_chromaticity[1];
557  offset+=ReadBlob(image,sizeof(cin.image.label),(unsigned char *)
558    cin.image.label);
559  (void) SetImageProperty(image,"cin:image.label",cin.image.label);
560  offset+=ReadBlob(image,sizeof(cin.image.reserve),(unsigned char *)
561    cin.image.reserve);
562  /*
563    Image data format information.
564  */
565  cin.data_format.interleave=(unsigned char) ReadBlobByte(image);
566  offset++;
567  cin.data_format.packing=(unsigned char) ReadBlobByte(image);
568  offset++;
569  cin.data_format.sign=(unsigned char) ReadBlobByte(image);
570  offset++;
571  cin.data_format.sense=(unsigned char) ReadBlobByte(image);
572  offset++;
573  cin.data_format.line_pad=ReadBlobLong(image);
574  offset+=4;
575  cin.data_format.channel_pad=ReadBlobLong(image);
576  offset+=4;
577  offset+=ReadBlob(image,sizeof(cin.data_format.reserve),(unsigned char *)
578    cin.data_format.reserve);
579  /*
580    Image origination information.
581  */
582  cin.origination.x_offset=(long) ReadBlobLong(image);
583  offset+=4;
584  if ((unsigned long) cin.origination.x_offset != ~0UL)
585    (void) FormatImageProperty(image,"cin:origination.x_offset","%ld",
586      cin.origination.x_offset);
587  cin.origination.y_offset=(long) ReadBlobLong(image);
588  offset+=4;
589  if ((unsigned long) cin.origination.y_offset != ~0UL)
590    (void) FormatImageProperty(image,"cin:origination.y_offset","%ld",
591      cin.origination.y_offset);
592  offset+=ReadBlob(image,sizeof(cin.origination.filename),(unsigned char *)
593    cin.origination.filename);
594  (void) SetImageProperty(image,"cin:origination.filename",
595    cin.origination.filename);
596  offset+=ReadBlob(image,sizeof(cin.origination.create_date),(unsigned char *)
597    cin.origination.create_date);
598  (void) SetImageProperty(image,"cin:origination.create_date",
599    cin.origination.create_date);
600  offset+=ReadBlob(image,sizeof(cin.origination.create_time),(unsigned char *)
601    cin.origination.create_time);
602  (void) SetImageProperty(image,"cin:origination.create_time",
603    cin.origination.create_time);
604  offset+=ReadBlob(image,sizeof(cin.origination.device),(unsigned char *)
605    cin.origination.device);
606  (void) SetImageProperty(image,"cin:origination.device",
607    cin.origination.device);
608  offset+=ReadBlob(image,sizeof(cin.origination.model),(unsigned char *)
609    cin.origination.model);
610  (void) SetImageProperty(image,"cin:origination.model",cin.origination.model);
611  offset+=ReadBlob(image,sizeof(cin.origination.serial),(unsigned char *)
612    cin.origination.serial);
613  (void) SetImageProperty(image,"cin:origination.serial",
614    cin.origination.serial);
615  cin.origination.x_pitch=ReadBlobFloat(image);
616  offset+=4;
617  cin.origination.y_pitch=ReadBlobFloat(image);
618  offset+=4;
619  cin.origination.gamma=ReadBlobFloat(image);
620  offset+=4;
621  if (IsFloatDefined(cin.origination.gamma) != MagickFalse)
622    image->gamma=cin.origination.gamma;
623  offset+=ReadBlob(image,sizeof(cin.origination.reserve),(unsigned char *)
624    cin.origination.reserve);
625  if ((cin.file.image_offset > 2048) && (cin.file.user_length != 0))
626    {
627      /*
628        Image film information.
629      */
630      cin.film.id=ReadBlobByte(image);
631      offset++;
632      if ((unsigned long) cin.film.id != ~0UL)
633        (void) FormatImageProperty(image,"cin:film.id","%d",cin.film.id);
634      cin.film.type=ReadBlobByte(image);
635      offset++;
636      if ((unsigned long) cin.film.type != ~0UL)
637        (void) FormatImageProperty(image,"cin:film.type","%d",cin.film.type);
638      cin.film.offset=ReadBlobByte(image);
639      offset++;
640      if ((unsigned long) cin.film.offset != ~0UL)
641        (void) FormatImageProperty(image,"cin:film.offset","%d",
642          cin.film.offset);
643      cin.film.reserve1=ReadBlobByte(image);
644      offset++;
645      cin.film.prefix=ReadBlobLong(image);
646      offset+=4;
647      if (cin.film.prefix != ~0UL)
648        (void) FormatImageProperty(image,"cin:film.prefix","%lu",
649          cin.film.prefix);
650      cin.film.count=ReadBlobLong(image);
651      offset+=4;
652      offset+=ReadBlob(image,sizeof(cin.film.format),(unsigned char *)
653        cin.film.format);
654      (void) SetImageProperty(image,"cin:film.format",cin.film.format);
655      cin.film.frame_position=ReadBlobLong(image);
656      offset+=4;
657      if (cin.film.frame_position != ~0UL)
658        (void) FormatImageProperty(image,"cin:film.frame_position","%lu",
659          cin.film.frame_position);
660      cin.film.frame_rate=ReadBlobFloat(image);
661      offset+=4;
662      if (IsFloatDefined(cin.film.frame_rate) != MagickFalse)
663        (void) FormatImageProperty(image,"cin:film.frame_rate","%g",
664          cin.film.frame_rate);
665      offset+=ReadBlob(image,sizeof(cin.film.frame_id),(unsigned char *)
666        cin.film.frame_id);
667      (void) SetImageProperty(image,"cin:film.frame_id",cin.film.frame_id);
668      offset+=ReadBlob(image,sizeof(cin.film.slate_info),(unsigned char *)
669        cin.film.slate_info);
670      (void) SetImageProperty(image,"cin:film.slate_info",cin.film.slate_info);
671      offset+=ReadBlob(image,sizeof(cin.film.reserve),(unsigned char *)
672        cin.film.reserve);
673    }
674  if ((cin.file.image_offset > 2048) && (cin.file.user_length != 0))
675    {
676      StringInfo
677        *profile;
678
679      /*
680        User defined data.
681      */
682      profile=AcquireStringInfo(cin.file.user_length);
683      offset+=ReadBlob(image,GetStringInfoLength(profile),
684        GetStringInfoDatum(profile));
685      (void) SetImageProfile(image,"cin:user.data",profile);
686      profile=DestroyStringInfo(profile);
687    }
688  for ( ; offset < (long) cin.file.image_offset; offset++)
689    (void) ReadBlobByte(image);
690  image->depth=cin.image.channel[0].bits_per_pixel;
691  image->columns=cin.image.channel[0].pixels_per_line;
692  image->rows=cin.image.channel[0].lines_per_image;
693  if (image_info->ping)
694    {
695      (void) CloseBlob(image);
696      return(image);
697    }
698  if (SetImageExtent(image,0,0) == MagickFalse)
699    {
700      InheritException(exception,&image->exception);
701      return(DestroyImageList(image));
702    }
703  /*
704    Convert CIN raster image to pixel packets.
705  */
706  quantum_info=AcquireQuantumInfo(image_info,image);
707  quantum_info->quantum=32;
708  quantum_info->pack=MagickFalse;
709  quantum_type=RGBQuantum;
710  pixels=GetQuantumPixels(quantum_info);
711  length=GetQuantumExtent(image,quantum_info,quantum_type);
712  length=GetBytesPerRow(image->columns,3,image->depth,MagickTrue);
713  if (cin.image.number_channels == 1)
714    {
715      quantum_type=GrayQuantum;
716      length=GetBytesPerRow(image->columns,1,image->depth,MagickTrue);
717    }
718  for (y=0; y < (long) image->rows; y++)
719  {
720    q=SetImagePixels(image,0,y,image->columns,1);
721    if (q == (PixelPacket *) NULL)
722      break;
723    count=ReadBlob(image,length,pixels);
724    if ((size_t) count != length)
725      break;
726    (void) ImportQuantumPixels(image,quantum_info,quantum_type,pixels);
727    if (SyncImagePixels(image) == 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
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*/
768ModuleExport 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
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*/
802ModuleExport void UnregisterCINImage(void)
803{
804  (void) UnregisterMagickInfo("CINEON");
805}
806
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
832static 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
844static 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  time_t
883    seconds;
884
885  unsigned char
886    *pixels;
887
888  /*
889    Open output image file.
890  */
891  assert(image_info != (const ImageInfo *) NULL);
892  assert(image_info->signature == MagickSignature);
893  assert(image != (Image *) NULL);
894  assert(image->signature == MagickSignature);
895  if (image->debug != MagickFalse)
896    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
897  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
898  if (status == MagickFalse)
899    return(status);
900  if (image->colorspace != LogColorspace)
901    (void) SetImageColorspace(image,LogColorspace);
902  /*
903    Write image information.
904  */
905  (void) ResetMagickMemory(&cin,0,sizeof(cin));
906  offset=0;
907  cin.file.magic=0x802A5FD7UL;
908  offset+=WriteBlobLong(image,cin.file.magic);
909  cin.file.image_offset=0x800;
910  profile=GetImageProfile(image,"cin:user.data");
911  if (profile != (StringInfo *) NULL)
912    {
913      cin.file.image_offset+=(unsigned long) GetStringInfoLength(profile);
914      cin.file.image_offset=(((cin.file.image_offset+0x2000-1)/0x2000)*0x2000);
915    }
916  offset+=WriteBlobLong(image,cin.file.image_offset);
917  cin.file.generic_length=0x400;
918  offset+=WriteBlobLong(image,cin.file.generic_length);
919  cin.file.industry_length=0x400;
920  offset+=WriteBlobLong(image,cin.file.industry_length);
921  cin.file.user_length=0x00;
922  if (profile != (StringInfo *) NULL)
923    {
924      cin.file.user_length+=(unsigned long) GetStringInfoLength(profile);
925      cin.file.user_length=(((cin.file.user_length+0x2000-1)/0x2000)*0x2000);
926    }
927  offset+=WriteBlobLong(image,cin.file.user_length);
928  cin.file.file_size=4*image->columns*image->rows+0x2000;
929  offset+=WriteBlobLong(image,cin.file.file_size);
930  (void) CopyMagickString(cin.file.version,"V4.5",sizeof(cin.file.version));
931  offset+=WriteBlob(image,sizeof(cin.file.version),(unsigned char *)
932    cin.file.version);
933  value=GetCINProperty(image_info,image,"cin:file.filename");
934  if (value != (const char *) NULL)
935    (void) CopyMagickString(cin.file.filename,value,sizeof(cin.file.filename));
936  else
937    (void) CopyMagickString(cin.file.filename,image->filename,
938      sizeof(cin.file.filename));
939  offset+=WriteBlob(image,sizeof(cin.file.filename),(unsigned char *)
940    cin.file.filename);
941  seconds=time((time_t *) NULL);
942  (void) strftime(cin.file.create_date,sizeof(cin.file.create_date),"%Y:%m:%d",
943    localtime(&seconds));
944  offset+=WriteBlob(image,sizeof(cin.file.create_date),(unsigned char *)
945    cin.file.create_date);
946  (void) strftime(cin.file.create_time,sizeof(cin.file.create_time),
947    "%H:%M:%S%Z",localtime(&seconds));
948  offset+=WriteBlob(image,sizeof(cin.file.create_time),(unsigned char *)
949    cin.file.create_time);
950  offset+=WriteBlob(image,sizeof(cin.file.reserve),(unsigned char *)
951    cin.file.reserve);
952  cin.image.orientation=0x00;
953  offset+=WriteBlobByte(image,cin.image.orientation);
954  cin.image.number_channels=3;
955  offset+=WriteBlobByte(image,cin.image.number_channels);
956  offset+=WriteBlob(image,sizeof(cin.image.reserve1),(unsigned char *)
957    cin.image.reserve1);
958  for (i=0; i < 8; i++)
959  {
960    cin.image.channel[i].designator[0]=0; /* universal metric */
961    offset+=WriteBlobByte(image,cin.image.channel[0].designator[0]);
962    cin.image.channel[i].designator[1]=(unsigned char) (i > 3 ? 0 : i+1); /* channel color */;
963    offset+=WriteBlobByte(image,cin.image.channel[1].designator[0]);
964    cin.image.channel[i].bits_per_pixel=(unsigned char) image->depth;
965    offset+=WriteBlobByte(image,cin.image.channel[0].bits_per_pixel);
966    offset+=WriteBlobByte(image,cin.image.channel[0].reserve);
967    cin.image.channel[i].pixels_per_line=image->columns;
968    offset+=WriteBlobLong(image,cin.image.channel[0].pixels_per_line);
969    cin.image.channel[i].lines_per_image=image->rows;
970    offset+=WriteBlobLong(image,cin.image.channel[0].lines_per_image);
971    cin.image.channel[i].min_data=0;
972    offset+=WriteBlobFloat(image,cin.image.channel[0].min_data);
973    cin.image.channel[i].min_quantity=0.0;
974    offset+=WriteBlobFloat(image,cin.image.channel[0].min_quantity);
975    cin.image.channel[i].max_data=(float) ((MagickOffsetType)
976      GetQuantumRange(image->depth));
977    offset+=WriteBlobFloat(image,cin.image.channel[0].max_data);
978    cin.image.channel[i].max_quantity=2.048f;
979    offset+=WriteBlobFloat(image,cin.image.channel[0].max_quantity);
980  }
981  offset+=WriteBlobFloat(image,image->chromaticity.white_point.x);
982  offset+=WriteBlobFloat(image,image->chromaticity.white_point.y);
983  offset+=WriteBlobFloat(image,image->chromaticity.red_primary.x);
984  offset+=WriteBlobFloat(image,image->chromaticity.red_primary.y);
985  offset+=WriteBlobFloat(image,image->chromaticity.green_primary.x);
986  offset+=WriteBlobFloat(image,image->chromaticity.green_primary.y);
987  offset+=WriteBlobFloat(image,image->chromaticity.blue_primary.x);
988  offset+=WriteBlobFloat(image,image->chromaticity.blue_primary.y);
989  value=GetCINProperty(image_info,image,"cin:image.label");
990  if (value != (const char *) NULL)
991    (void) CopyMagickString(cin.image.label,value,sizeof(cin.image.label));
992  offset+=WriteBlob(image,sizeof(cin.image.label),(unsigned char *)
993    cin.image.label);
994  offset+=WriteBlob(image,sizeof(cin.image.reserve),(unsigned char *)
995    cin.image.reserve);
996  /*
997    Write data format information.
998  */
999  cin.data_format.interleave=0; /* pixel interleave (rgbrgbr...) */
1000  offset+=WriteBlobByte(image,cin.data_format.interleave);
1001  cin.data_format.packing=5; /* packing longword (32bit) boundaries */
1002  offset+=WriteBlobByte(image,cin.data_format.packing);
1003  cin.data_format.sign=0; /* unsigned data */
1004  offset+=WriteBlobByte(image,cin.data_format.sign);
1005  cin.data_format.sense=0; /* image sense: positive image */
1006  offset+=WriteBlobByte(image,cin.data_format.sense);
1007  cin.data_format.line_pad=0;
1008  offset+=WriteBlobLong(image,cin.data_format.line_pad);
1009  cin.data_format.channel_pad=0;
1010  offset+=WriteBl