Coverage Report

Created: 2026-07-25 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/graphicsmagick/coders/cineon.c
Line
Count
Source
1
/*
2
% Copyright (C) 2003-2026 GraphicsMagick Group
3
%
4
% This program is covered by multiple licenses, which are described in
5
% Copyright.txt. You should have received a copy of Copyright.txt with this
6
% package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
7
%
8
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9
%                                                                             %
10
%                                                                             %
11
%                                                                             %
12
%                   CCCC  IIIII  N   N  EEEEE  OOO   N   N                    %
13
%                  C        I    NN  N  E     O   O  NN  N                    %
14
%                  C        I    N N N  EEEE  O   O  N N N                    %
15
%                  C        I    N  NN  E     O   O  N  NN                    %
16
%                   CCCC  IIIII  N   N  EEEEE  OOO   N   N                    %
17
%                                                                             %
18
%                                                                             %
19
%                    Read/Write Kodak Cineon Image Format.                    %
20
%                 Cineon Image Format is similar to SMTPE DPX                 %
21
%                                                                             %
22
%                                                                             %
23
%                              Software Design                                %
24
%                              Bob Friesenhahn                                %
25
%                                 May 2007                                    %
26
%                                                                             %
27
%                                                                             %
28
%                                                                             %
29
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
30
%
31
%  Cineon image file format draft is available at
32
%  http://www.cineon.com/ff_draft.php.
33
%
34
%
35
*/
36

37
/*
38
  Include declarations.
39
*/
40
#include "magick/studio.h"
41
#include "magick/attribute.h"
42
#include "magick/blob.h"
43
#include "magick/bit_stream.h"
44
#include "magick/colorspace.h"
45
#include "magick/enum_strings.h"
46
#include "magick/pixel_cache.h"
47
#include "magick/magick_endian.h"
48
#include "magick/error.h"
49
#include "magick/list.h"
50
#include "magick/log.h"
51
#include "magick/magick.h"
52
#include "magick/monitor.h"
53
#include "magick/profile.h"
54
#include "magick/utility.h"
55
#include "magick/static.h"
56

57
/*
58
  Forward declaractions.
59
*/
60
static unsigned int
61
  WriteCINEONImage(const ImageInfo *,Image *);
62
63
typedef char ASCII;
64
typedef magick_uint8_t U8;
65
typedef magick_uint32_t U32;
66
typedef magick_int32_t S32;
67
typedef union _R32_u
68
{
69
  magick_uint32_t u;
70
  float f;
71
} R32;
72
73
789
#define SET_UNDEFINED_U8(value)  (value=0xFFU)
74
783
#define SET_UNDEFINED_U32(value) (value=0xFFFFFFFFU)
75
9
#define SET_UNDEFINED_S32(value) (value=0x80000000)
76
77
277
#define SET_UNDEFINED_R32(value) (value.u=0x7F800000U);
78
3.68k
#define SET_UNDEFINED_ASCII(value) ((void) memset(value,0,sizeof(value)))
79
80
29.0k
#define IS_UNDEFINED_U8(value) (value == ((U8) 0xFFU))
81
11.7k
#define IS_UNDEFINED_U32(value) (value == ((U32) 0xFFFFFFFFU))
82
32.3k
#define IS_UNDEFINED_S32(value) (value == ((S32) 0x80000000))
83
191k
#define IS_UNDEFINED_R32(value) (value.u == ((U32) 0x7F800000U))
84
227k
#define IS_UNDEFINED_ASCII(value) (!(value[0] > 0))
85
86
typedef struct _CineonFileInfo
87
{
88
  U32   magic;                     /* Magick number (0x802A5FD7) */
89
  U32   image_data_offset;         /* Offset to image data in bytes */
90
  U32   generic_section_length;    /* Generic section header length in bytes */
91
  U32   industry_section_length;   /* Industry specific header length in bytes */
92
  U32   user_defined_length;       /* User defined header length in bytes */
93
  U32   file_size;                 /* Total image file size in bytes  */
94
  ASCII header_format_version[8];  /* Version number of header format */
95
  ASCII image_filename[100];       /* Image filename */
96
  ASCII creation_date[12];         /* Creation date: yyyy:mm:dd */
97
  ASCII creation_time[12];         /* Creation time: hh:mm:ssLTZ */
98
  ASCII reserved[36];              /* Reserved for future use */
99
} CineonFileInfo;
100
101
typedef struct _CineonImageChannel
102
{
103
  U8    designator_byte_0;         /* 0 = universal metric */
104
  U8    designator_byte_1;         /* */
105
  U8    bits_per_sample;           /* Bit depth */
106
  U8    unused;
107
  U32   pixels_per_line;           /* Pixels per line (columns) */
108
  U32   lines_per_image;           /* Lines per image (rows) */
109
  R32   reference_low_data_code;   /* Reference low data code value */
110
  R32   reference_low_quantity;    /* Low quantity represented */
111
  R32   reference_high_data_code;  /* Reference high data code value */
112
  R32   reference_high_quantity;   /* Reference high quantity represented */
113
} DPXImageChannel;
114
115
typedef struct _CineonImageInfo
116
{
117
  U8    orientation;               /* Image orientation */
118
  U8    channels;                  /* Number of image channels (1-8) */
119
  U8    pad[2];                    /* Unused (2 byte space for word alignment */
120
  DPXImageChannel channel_info[8]; /* Description of channels */
121
  R32   white_point[2];            /* White point (color temperature) - x,y pair */
122
  R32   red_primary_chromaticity[2]; /* Red primary chromaticity - x,y pair */
123
  R32   green_primary_chromaticity[2]; /* Green primary chromaticity - x,y pair */
124
  R32   blue_primary_chromaticity[2]; /* Blue primary chromaticity - x,y pair */
125
  ASCII label_text[200];           /* Label text */
126
  ASCII reserved[28];              /* Reserved for future use */
127
  /* Image Data Format Information */
128
  U8    data_interleave;           /* Data interleave */
129
  U8    packing;                   /* Packing method */
130
  U8    sign;                      /* Data sign: 0=unsigned, 1=signed */
131
  U8    sense;                     /* Image sense: 0=positive, 1=negative */
132
  U32   eol_pad;                   /* End of line padding */
133
  U32   eoc_pad;                   /* End of channel padding */
134
  ASCII reserved2[20];             /* Reserved for future use */
135
} CineonImageInfo;
136
137
typedef struct _CineonImageOriginationInfo
138
{
139
  S32   x_offset;                  /* X offset */
140
  S32   y_offset;                  /* Y offset */
141
  ASCII source_image_filename[100];/* Source image filename */
142
  ASCII creation_date[12];         /* Creation date: yyyy:mm:dd */
143
  ASCII creation_time[12];         /* Creation time: hh:mm:ssLTZ */
144
  ASCII input_device[64];          /* Input device */
145
  ASCII input_device_model[32];    /* Input device model number */
146
  ASCII input_device_serial[32];   /* Input device serial number */
147
  R32   input_device_pitch_x;      /* Input device pitch for X (samples/mm) */
148
  R32   input_device_pitch_y;      /* Input device pitch for Y (samples/mm) */
149
  R32   gamma;                     /* Image gamma of capture device */
150
  ASCII reserved[40];              /* Reserved for future use */
151
} CineonImageOriginationInfo;
152
153
typedef struct _CineonFilmInfo
154
{
155
  U8    film_mfg_id_code;          /* Film mfg. ID code (2 digits from film edge code) */
156
  U8    film_type;                 /* Film type (2 digits from film edge code) */
157
  U8    perfs_offset;              /* Offset in perfs (2 digits from film edge code) */
158
  U8    unused;                    /* Unused, for word alignment */
159
  U32   prefix;                    /* Prefix (6 digits from film edge code) */
160
  U32   count;                     /* Count (4 digits from film edge code) */
161
  ASCII format[32];                /* Format -- e.g. Academy */
162
  U32   frame_position;            /* Frame position in sequence */
163
  R32   frame_rate;                /* Frame rate of original (frames/s) */
164
  ASCII frame_id[32];              /* Frame identification - e.g. keyframe */
165
  ASCII slate_info[200];           /* Slate information */
166
  ASCII reserved[740];             /* Reserved for future use */
167
} CineonFilmInfo;
168
169

170
/*
171
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
172
%                                                                             %
173
%                                                                             %
174
%                                                                             %
175
%   I s C I N E O N                                                           %
176
%                                                                             %
177
%                                                                             %
178
%                                                                             %
179
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
180
%
181
%  IsCINEON() returns True if the image format type, identified by the magick
182
%  string, is CINEON.
183
%
184
%  The format of the IsCINEON method is:
185
%
186
%      unsigned int IsCINEON(const unsigned char *magick,const size_t length)
187
%
188
%  A description of each parameter follows:
189
%
190
%    o magick: This string is generally the first few bytes of an image file
191
%      or blob.
192
%
193
%    o length: Specifies the length of the magick string.
194
%
195
%
196
*/
197
static unsigned int IsCINEON(const unsigned char *magick,const size_t length)
198
0
{
199
0
  if (length < 4)
200
0
    return(False);
201
0
  if (memcmp(magick,"\200\052\137\327",4) == 0)
202
0
    return(True);
203
0
  return(False);
204
0
}
205

206
/*
207
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
208
%                                                                             %
209
%                                                                             %
210
%                                                                             %
211
%   R e a d C I N E O N I m a g e                                             %
212
%                                                                             %
213
%                                                                             %
214
%                                                                             %
215
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
216
%
217
%  ReadCINEONImage() reads an CINEON X image file and returns it.  It allocates
218
%  the memory necessary for the new Image structure and returns a point to the
219
%  new image.
220
%
221
%  The format of the ReadCINEONImage method is:
222
%
223
%      Image *ReadCINEONImage(const ImageInfo *image_info,
224
%        ExceptionInfo *exception)
225
%
226
%  A description of each parameter follows:
227
%
228
%    o image_info: The image info.
229
%
230
%    o exception: return any errors or warnings in this structure.
231
%
232
%
233
*/
234
218k
#define LogSetImageAttribute(name,value) \
235
218k
{ \
236
218k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(), \
237
218k
                        "Attribute \"%s\" set to \"%s\"", \
238
218k
                        name,value); \
239
218k
}
240
/*
241
  Null terminate ASCII fields which provide space for a terminating
242
  NULL.
243
*/
244
325k
#define NULLTerminateASCIIField(field) \
245
325k
{ \
246
325k
    field[sizeof(field)-1]='\0'; \
247
325k
}
248
/*
249
  Can't use strlcpy() since strlcpy() only handles NULL terminated
250
  strings.  This is not so necessary due to use of
251
  NULLTerminateASCIIField() above.
252
*/
253
226k
#define StringToAttribute(image,name,member) \
254
226k
{ \
255
226k
  char \
256
226k
    buffer_[MaxTextExtent]; \
257
226k
\
258
226k
  if (!IS_UNDEFINED_ASCII(member)) \
259
226k
    { \
260
99.5k
      (void) memcpy(buffer_,member,Min(sizeof(member),MaxTextExtent)); \
261
99.5k
      buffer_[Min(sizeof(member),MaxTextExtent-1)]='\0';             \
262
99.5k
      (void) SetImageAttribute(image,name,buffer_); \
263
99.5k
      LogSetImageAttribute(name,buffer_); \
264
99.5k
    } \
265
226k
}
266
29.0k
#define U8ToAttribute(image,name,member) \
267
29.0k
{ \
268
29.0k
  char \
269
29.0k
    buffer[MaxTextExtent]; \
270
29.0k
\
271
29.0k
  if (!IS_UNDEFINED_U8(member)) \
272
29.0k
    { \
273
24.0k
      MagickFormatString(buffer,sizeof(buffer),"%u",(unsigned int) member); \
274
24.0k
      (void) SetImageAttribute(image,name,buffer); \
275
24.0k
      LogSetImageAttribute(name,buffer); \
276
24.0k
    } \
277
29.0k
}
278
11.7k
#define U32ToAttribute(image,name,member) \
279
11.7k
{ \
280
11.7k
  char \
281
11.7k
    buffer[MaxTextExtent]; \
282
11.7k
\
283
11.7k
  if (!IS_UNDEFINED_U32(member)) \
284
11.7k
    { \
285
10.4k
      MagickFormatString(buffer,sizeof(buffer),"%u",member);    \
286
10.4k
      (void) SetImageAttribute(image,name,buffer); \
287
10.4k
      LogSetImageAttribute(name,buffer); \
288
10.4k
    } \
289
11.7k
}
290
52.4k
#define R32ToAttribute(image,name,member) \
291
52.4k
{ \
292
52.4k
  char \
293
52.4k
    buffer[MaxTextExtent]; \
294
52.4k
\
295
52.4k
  if (!IS_UNDEFINED_R32(member)) \
296
52.4k
    { \
297
52.3k
      MagickFormatString(buffer,sizeof(buffer),"%g",member.f);  \
298
52.3k
      (void) SetImageAttribute(image,name,buffer); \
299
52.3k
      LogSetImageAttribute(name,buffer); \
300
52.3k
    } \
301
52.4k
}
302
32.3k
#define S32ToAttribute(image,name,member) \
303
32.3k
{ \
304
32.3k
  char \
305
32.3k
    buffer[MaxTextExtent]; \
306
32.3k
\
307
32.3k
  if (!IS_UNDEFINED_S32(member)) \
308
32.3k
    { \
309
32.0k
      MagickFormatString(buffer,sizeof(buffer),"%d",member);    \
310
32.0k
      (void) SetImageAttribute(image,name,buffer); \
311
32.0k
      LogSetImageAttribute(name,buffer); \
312
32.0k
    } \
313
32.3k
}
314
static void SwabCineonFileInfo(CineonFileInfo *file_info)
315
32.8k
{
316
32.8k
  MagickSwabUInt32(&file_info->magic);
317
32.8k
  MagickSwabUInt32(&file_info->image_data_offset);
318
32.8k
  MagickSwabUInt32(&file_info->generic_section_length);
319
32.8k
  MagickSwabUInt32(&file_info->industry_section_length);
320
32.8k
  MagickSwabUInt32(&file_info->user_defined_length);
321
32.8k
  MagickSwabUInt32(&file_info->file_size);
322
32.8k
}
323
324
static void SwabCineonImageInfo(CineonImageInfo *image_info)
325
17.9k
{
326
17.9k
  size_t
327
17.9k
    i;
328
329
17.9k
  for (i=0 ;
330
48.7k
       i < Min((size_t) image_info->channels,
331
17.9k
               (sizeof(image_info->channel_info) /
332
17.9k
                sizeof(image_info->channel_info[0])));
333
30.7k
       i++)
334
30.7k
    {
335
30.7k
      MagickSwabUInt32(&image_info->channel_info[i].pixels_per_line);
336
30.7k
      MagickSwabUInt32(&image_info->channel_info[i].lines_per_image);
337
30.7k
      MagickSwabFloat(&image_info->channel_info[i].reference_low_data_code.f);
338
30.7k
      MagickSwabFloat(&image_info->channel_info[i].reference_low_quantity.f);
339
30.7k
      MagickSwabFloat(&image_info->channel_info[i].reference_high_data_code.f);
340
30.7k
      MagickSwabFloat(&image_info->channel_info[i].reference_high_quantity.f);
341
30.7k
    }
342
343
17.9k
  MagickSwabFloat(&image_info->white_point[0].f);
344
17.9k
  MagickSwabFloat(&image_info->white_point[1].f);
345
17.9k
  MagickSwabFloat(&image_info->red_primary_chromaticity[0].f);
346
17.9k
  MagickSwabFloat(&image_info->red_primary_chromaticity[1].f);
347
17.9k
  MagickSwabFloat(&image_info->green_primary_chromaticity[0].f);
348
17.9k
  MagickSwabFloat(&image_info->green_primary_chromaticity[1].f);
349
17.9k
  MagickSwabFloat(&image_info->blue_primary_chromaticity[0].f);
350
17.9k
  MagickSwabFloat(&image_info->blue_primary_chromaticity[1].f);
351
17.9k
  MagickSwabUInt32(&image_info->eol_pad);
352
17.9k
  MagickSwabUInt32(&image_info->eoc_pad);
353
17.9k
}
354
355
static void SwabCineonImageOriginationInfo(CineonImageOriginationInfo *image_info)
356
16.8k
{
357
16.8k
  MagickSwabUInt32((U32 *) &image_info->x_offset);
358
16.8k
  MagickSwabUInt32((U32 *) &image_info->y_offset);
359
16.8k
  MagickSwabFloat(&image_info->input_device_pitch_x.f);
360
16.8k
  MagickSwabFloat(&image_info->input_device_pitch_y.f);
361
16.8k
  MagickSwabFloat(&image_info->gamma.f);
362
16.8k
}
363
364
static void SwabCineonFilmInfo(CineonFilmInfo *mp_info)
365
4.59k
{
366
4.59k
  MagickSwabUInt32(&mp_info->prefix);
367
4.59k
  MagickSwabUInt32(&mp_info->count);
368
4.59k
  MagickSwabUInt32(&mp_info->frame_position);
369
4.59k
  MagickSwabFloat(&mp_info->frame_rate.f);
370
4.59k
}
371
372
static OrientationType
373
CineonOrientationToOrientationType(const unsigned int orientation)
374
17.3k
{
375
17.3k
  OrientationType
376
17.3k
    orientation_type = UndefinedOrientation;
377
378
17.3k
  switch (orientation)
379
17.3k
    {
380
9.30k
    case 0:
381
9.30k
      orientation_type=TopLeftOrientation;
382
9.30k
      break;
383
370
    case 1:
384
370
      orientation_type=TopRightOrientation;
385
370
      break;
386
20
    case 2:
387
20
      orientation_type=BottomLeftOrientation;
388
20
      break;
389
49
    case 3:
390
49
      orientation_type=BottomRightOrientation;
391
49
      break;
392
1.44k
    case 4:
393
1.44k
      orientation_type=LeftTopOrientation;
394
1.44k
      break;
395
30
    case 5:
396
30
      orientation_type=RightTopOrientation;
397
30
      break;
398
242
    case 6:
399
242
      orientation_type=LeftBottomOrientation;
400
242
      break;
401
332
    case 7:
402
332
      orientation_type=RightBottomOrientation;
403
332
      break;
404
17.3k
    }
405
406
17.3k
  return orientation_type;
407
17.3k
}
408
409
static U8 OrientationTypeToCineonOrientation(const OrientationType orientation_type)
410
335
{
411
335
  U8
412
335
    orientation = 0U;
413
414
335
  switch (orientation_type)
415
335
    {
416
77
    case UndefinedOrientation:
417
209
    case TopLeftOrientation:
418
209
      orientation=0U;
419
209
      break;
420
81
    case TopRightOrientation:
421
81
      orientation=1U;
422
81
      break;
423
3
    case BottomLeftOrientation:
424
3
      orientation=2U;
425
3
      break;
426
10
    case BottomRightOrientation:
427
10
      orientation=3U;
428
10
      break;
429
13
    case LeftTopOrientation:
430
13
      orientation=4U;
431
13
      break;
432
3
    case RightTopOrientation:
433
3
      orientation=5U;
434
3
      break;
435
12
    case LeftBottomOrientation:
436
12
      orientation=6U;
437
12
      break;
438
4
    case RightBottomOrientation:
439
4
      orientation=7U;
440
4
      break;
441
335
    }
442
335
  return orientation;
443
335
}
444
445
static Image *ReadCINEONImage(const ImageInfo *image_info,
446
  ExceptionInfo *exception)
447
37.2k
{
448
37.2k
  CineonFileInfo
449
37.2k
    cin_file_info;
450
451
37.2k
  CineonImageInfo
452
37.2k
    cin_image_info;
453
454
37.2k
  CineonImageOriginationInfo
455
37.2k
    cin_source_info;
456
457
37.2k
  CineonFilmInfo
458
37.2k
    cin_mp_info;
459
460
37.2k
  Image
461
37.2k
    *image;
462
463
37.2k
  unsigned long
464
37.2k
    y;
465
466
37.2k
  register unsigned long
467
37.2k
    x;
468
469
37.2k
  register PixelPacket
470
37.2k
    *q;
471
472
37.2k
  register long
473
37.2k
    i;
474
475
37.2k
  size_t
476
37.2k
    offset;
477
478
37.2k
  unsigned int
479
37.2k
    channel,
480
37.2k
    max_bits_per_sample,
481
37.2k
    max_lines_per_image,
482
37.2k
    max_pixels_per_line,
483
37.2k
    number_of_channels;
484
485
37.2k
  MagickPassFail
486
37.2k
    status;
487
488
37.2k
  MagickBool
489
37.2k
    swab=MagickFalse;
490
491
37.2k
  unsigned long
492
37.2k
    pixels_offset;
493
494
37.2k
  unsigned char
495
37.2k
    *scandata;
496
497
37.2k
  void
498
37.2k
    *scanline;
499
500
37.2k
  const char *
501
37.2k
    definition_value;
502
503
37.2k
  BitStreamReadHandle
504
37.2k
    bit_stream;
505
506
  /*
507
    Open image file.
508
  */
509
37.2k
  assert(image_info != (const ImageInfo *) NULL);
510
37.2k
  assert(image_info->signature == MagickSignature);
511
37.2k
  assert(exception != (ExceptionInfo *) NULL);
512
37.2k
  assert(exception->signature == MagickSignature);
513
37.2k
#if !defined(WORDS_BIGENDIAN)
514
37.2k
  swab=MagickTrue;
515
37.2k
#endif /* !defined(WORDS_BIGENDIAN) */
516
37.2k
  image=AllocateImage(image_info);
517
37.2k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
518
37.2k
  if (status == False)
519
0
    {
520
0
      DestroyImageList(image);
521
0
      return((Image *) NULL);
522
0
    }
523
  /*
524
    Read CINEON image.
525
  */
526
37.2k
  offset=(ReadBlob(image,sizeof(cin_file_info),&cin_file_info));
527
37.2k
  if (offset != sizeof(cin_file_info))
528
32.1k
    ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
529
530
32.1k
  if (swab)
531
32.1k
    SwabCineonFileInfo(&cin_file_info);
532
32.1k
  NULLTerminateASCIIField(cin_file_info.header_format_version);
533
32.1k
  NULLTerminateASCIIField(cin_file_info.image_filename);
534
32.1k
  NULLTerminateASCIIField(cin_file_info.creation_date);
535
32.1k
  NULLTerminateASCIIField(cin_file_info.creation_time);
536
32.1k
  NULLTerminateASCIIField(cin_file_info.reserved);
537
32.1k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
538
32.1k
                        "File magic 0x%04X",cin_file_info.magic);
539
540
32.1k
  if (cin_file_info.magic != 0x802A5FD7U)
541
32.0k
    ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
542
543
32.0k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
544
32.0k
                        "Image offset %u, Generic length %u, Industry length %u, User length %u, File size %u",
545
32.0k
                        cin_file_info.image_data_offset,
546
32.0k
                        cin_file_info.generic_section_length,
547
32.0k
                        cin_file_info.industry_section_length,
548
32.0k
                        cin_file_info.user_defined_length,
549
32.0k
                        cin_file_info.file_size);
550
32.0k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
551
32.0k
                        "Header format version \"%s\"", cin_file_info.header_format_version);
552
32.0k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
553
32.0k
                        "Image file name \"%s\"", cin_file_info.image_filename);
554
32.0k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
555
32.0k
                        "Creation date \"%s\"", cin_file_info.creation_date);
556
32.0k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
557
32.0k
                        "Creation time \"%s\"", cin_file_info.creation_time);
558
  /*
559
    Place arbitrary limit on user defined length.
560
  */
561
32.0k
  if (cin_file_info.user_defined_length > 16777216U)
562
29.2k
    ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
563
29.2k
  StringToAttribute(image,"document",cin_file_info.image_filename);
564
29.2k
  StringToAttribute(image,"DPX:file.filename",cin_file_info.image_filename);
565
29.2k
  {
566
29.2k
    char
567
29.2k
      creation_datetime[26]; /* 12+1+12+1 */
568
569
29.2k
    (void) strlcpy(creation_datetime,cin_file_info.creation_date,
570
29.2k
                   Min(sizeof(creation_datetime),sizeof(cin_file_info.creation_date)));
571
29.2k
    if (creation_datetime[0]!='\0')
572
14.5k
      (void) strlcat(creation_datetime,":",sizeof(creation_datetime));
573
29.2k
    (void) strlcat(creation_datetime,cin_file_info.creation_time,
574
29.2k
                   Min(sizeof(creation_datetime),sizeof(creation_datetime)));
575
29.2k
    StringToAttribute(image,"timestamp",creation_datetime);
576
29.2k
    StringToAttribute(image,"DPX:file.creation.datetime",creation_datetime);
577
29.2k
  }
578
579
  /*
580
    Obtain offset to pixels.
581
  */
582
29.2k
  pixels_offset=cin_file_info.image_data_offset & 0xffffffff;
583
29.2k
  if (pixels_offset < 712)
584
23.5k
    ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
585
586
  /*
587
    Read image information header.
588
  */
589
23.5k
  offset += ReadBlob(image,sizeof(cin_image_info),&cin_image_info);
590
23.5k
  if (offset != (size_t) 712L)
591
19.0k
    ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image);
592
19.0k
  if (cin_image_info.channels >
593
19.0k
      (sizeof(cin_image_info.channel_info)/sizeof(cin_image_info.channel_info[0])))
594
17.3k
    ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
595
17.3k
  if (swab)
596
17.3k
    SwabCineonImageInfo(&cin_image_info);
597
17.3k
  NULLTerminateASCIIField(cin_image_info.label_text);
598
17.3k
  NULLTerminateASCIIField(cin_image_info.reserved);
599
17.3k
  NULLTerminateASCIIField(cin_image_info.reserved2);
600
17.3k
  number_of_channels=cin_image_info.channels;
601
17.3k
  if (number_of_channels >
602
17.3k
      (sizeof(cin_image_info.channel_info)/sizeof(cin_image_info.channel_info[0])))
603
17.3k
    ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
604
17.3k
  U8ToAttribute(image,"DPX:image.orientation",cin_image_info.orientation);
605
17.3k
  image->orientation=CineonOrientationToOrientationType(cin_image_info.orientation);
606
17.3k
  max_bits_per_sample=0;
607
17.3k
  max_pixels_per_line=0;
608
17.3k
  max_lines_per_image=0;
609
46.0k
  for (channel=0; channel < number_of_channels; channel++)
610
28.7k
    {
611
28.7k
      max_bits_per_sample=Max(max_bits_per_sample,
612
28.7k
                              cin_image_info.channel_info[channel].bits_per_sample);
613
28.7k
      max_pixels_per_line=Max(max_pixels_per_line,
614
28.7k
                              cin_image_info.channel_info[channel].pixels_per_line);
615
28.7k
      max_lines_per_image=Max(max_lines_per_image,
616
28.7k
                              cin_image_info.channel_info[channel].lines_per_image);
617
28.7k
    }
618
619
17.3k
  image->depth=max_bits_per_sample;
620
17.3k
  image->columns=max_pixels_per_line;
621
17.3k
  image->rows=max_lines_per_image;
622
17.3k
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
623
17.3k
                        "Columns %ld, Rows %ld, Channels %u",
624
17.3k
                        image->columns, image->rows,
625
17.3k
                        (unsigned int) cin_image_info.channels);
626
17.3k
  if (!IS_UNDEFINED_R32(cin_image_info.white_point[0]))
627
17.3k
    image->chromaticity.white_point.x = cin_image_info.white_point[0].f;
628
17.3k
  if (!IS_UNDEFINED_R32(cin_image_info.white_point[1]))
629
17.3k
    image->chromaticity.white_point.y = cin_image_info.white_point[1].f;
630
17.3k
  if (!IS_UNDEFINED_R32(cin_image_info.red_primary_chromaticity[0]))
631
17.3k
    image->chromaticity.red_primary.x = cin_image_info.red_primary_chromaticity[0].f;
632
17.3k
  if (!IS_UNDEFINED_R32(cin_image_info.red_primary_chromaticity[1]))
633
17.3k
    image->chromaticity.red_primary.y = cin_image_info.red_primary_chromaticity[1].f;
634
17.3k
  if (!IS_UNDEFINED_R32(cin_image_info.green_primary_chromaticity[0]))
635
17.3k
    image->chromaticity.green_primary.x = cin_image_info.green_primary_chromaticity[0].f;
636
17.3k
  if (!IS_UNDEFINED_R32(cin_image_info.green_primary_chromaticity[1]))
637
17.3k
    image->chromaticity.green_primary.y = cin_image_info.green_primary_chromaticity[1].f;
638
17.3k
  if (!IS_UNDEFINED_R32(cin_image_info.blue_primary_chromaticity[0]))
639
17.3k
    image->chromaticity.blue_primary.x = cin_image_info.blue_primary_chromaticity[0].f;
640
17.3k
  if (!IS_UNDEFINED_R32(cin_image_info.blue_primary_chromaticity[1]))
641
17.3k
    image->chromaticity.blue_primary.y = cin_image_info.blue_primary_chromaticity[1].f;
642
17.3k
  StringToAttribute(image,"DPX:file.project.name",cin_image_info.label_text);
643
644
  /*
645
    Read image origination header.
646
  */
647
17.3k
  offset += ReadBlob(image,sizeof(cin_source_info),&cin_source_info);
648
17.3k
  if (offset != (size_t) 1024L)
649
16.1k
    ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image);
650
16.1k
  if (swab)
651
16.1k
    SwabCineonImageOriginationInfo(&cin_source_info);
652
16.1k
  NULLTerminateASCIIField(cin_source_info.source_image_filename);
653
16.1k
  NULLTerminateASCIIField(cin_source_info.creation_date);
654
16.1k
  NULLTerminateASCIIField(cin_source_info.creation_time);
655
16.1k
  NULLTerminateASCIIField(cin_source_info.input_device);
656
16.1k
  NULLTerminateASCIIField(cin_source_info.input_device_model);
657
16.1k
  NULLTerminateASCIIField(cin_source_info.input_device_serial);
658
16.1k
  S32ToAttribute(image,"DPX:source.x-offset",cin_source_info.x_offset);
659
16.1k
  S32ToAttribute(image,"DPX:source.y-offset",cin_source_info.y_offset);
660
16.1k
  StringToAttribute(image,"DPX:source.filename",cin_source_info.source_image_filename);
661
16.1k
  {
662
16.1k
    char
663
16.1k
      source_creation_datetime[MaxTextExtent];
664
665
16.1k
    source_creation_datetime[0]='\0';
666
16.1k
    (void) strlcat(source_creation_datetime,cin_file_info.creation_date,sizeof(cin_file_info.creation_date)+1);
667
16.1k
    if (source_creation_datetime[0]!='\0')
668
7.92k
      (void) strlcat(source_creation_datetime,":",sizeof(source_creation_datetime));
669
16.1k
    (void) strlcat(source_creation_datetime,cin_file_info.creation_time,sizeof(source_creation_datetime));
670
16.1k
    StringToAttribute(image,"DPX:source.creation.datetime",source_creation_datetime);
671
16.1k
  }
672
16.1k
  StringToAttribute(image,"DPX:source.device.name",cin_source_info.input_device);
673
16.1k
  StringToAttribute(image,"DPX:source.device.model",cin_source_info.input_device_model);
674
16.1k
  StringToAttribute(image,"DPX:source.device.serialnumber",cin_source_info.input_device_serial);
675
16.1k
  R32ToAttribute(image,"DPX:source.device.pitch.x",cin_source_info.input_device_pitch_x);
676
16.1k
  R32ToAttribute(image,"DPX:source.device.pitch.y",cin_source_info.input_device_pitch_y);
677
16.1k
  R32ToAttribute(image,"DPX:source.device.gamma",cin_source_info.gamma);
678
679
16.1k
  if ((pixels_offset >= 1024) && (cin_file_info.industry_section_length > 0))
680
7.82k
    {
681
      /*
682
        Read Motion-picture film information header.
683
      */
684
7.82k
      offset += ReadBlob(image,sizeof(cin_mp_info),&cin_mp_info);
685
7.82k
      if (offset != (size_t) 2048L)
686
3.92k
        ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image);
687
3.92k
      if (swab)
688
3.92k
        SwabCineonFilmInfo(&cin_mp_info);
689
3.92k
      NULLTerminateASCIIField(cin_mp_info.format);
690
3.92k
      NULLTerminateASCIIField(cin_mp_info.frame_id);
691
3.92k
      NULLTerminateASCIIField(cin_mp_info.slate_info);
692
3.92k
      NULLTerminateASCIIField(cin_mp_info.reserved);
693
3.92k
      U8ToAttribute(image,"DPX:mp.film.manufacturer.id",cin_mp_info.film_mfg_id_code);
694
3.92k
      U8ToAttribute(image,"DPX:mp.film.type",cin_mp_info.film_type);
695
3.92k
      U8ToAttribute(image,"DPX:mp.perfs.offset",cin_mp_info.perfs_offset);
696
3.92k
      U32ToAttribute(image,"DPX:mp.prefix",cin_mp_info.prefix);
697
3.92k
      U32ToAttribute(image,"DPX:mp.count",cin_mp_info.count);
698
3.92k
      StringToAttribute(image,"DPX:mp.format",cin_mp_info.format);
699
3.92k
      U32ToAttribute(image,"DPX:mp.frame.position",cin_mp_info.frame_position);
700
3.92k
      R32ToAttribute(image,"DPX:mp.frame.rate",cin_mp_info.frame_rate);
701
3.92k
      StringToAttribute(image,"DPX:mp.frame.id",cin_mp_info.frame_id);
702
3.92k
      StringToAttribute(image,"DPX:mp.slate.info",cin_mp_info.slate_info);
703
3.92k
    }
704
705
12.2k
  if ((pixels_offset >= 2048) && (cin_file_info.user_defined_length > 0))
706
11.4k
    {
707
11.4k
      unsigned char
708
11.4k
        *user_data;
709
710
11.4k
      const size_t
711
11.4k
        block_size = 65536UL;
712
713
11.4k
      size_t
714
11.4k
        read_size,
715
11.4k
        user_data_length;
716
717
11.4k
      user_data_length=0UL;
718
11.4k
      user_data=(unsigned char *) NULL;
719
14.2k
      while (user_data_length < cin_file_info.user_defined_length)
720
12.2k
        {
721
12.2k
          unsigned char *new_user_data;
722
12.2k
          read_size=Min(block_size,cin_file_info.user_defined_length-user_data_length);
723
12.2k
          new_user_data=MagickReallocateResourceLimitedMemory(unsigned char *,user_data,user_data_length+read_size);
724
12.2k
          if (new_user_data == (unsigned char *) NULL)
725
0
            {
726
0
              MagickFreeResourceLimitedMemory(unsigned char *,user_data);
727
0
              ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
728
0
            }
729
12.2k
          user_data=new_user_data;
730
12.2k
          if (ReadBlob(image,read_size,user_data+user_data_length) != read_size)
731
9.38k
            {
732
9.38k
              MagickFreeResourceLimitedMemory(unsigned char *,user_data);
733
9.38k
              ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image);
734
0
            }
735
2.83k
          user_data_length += read_size;
736
2.83k
          offset += read_size;
737
2.83k
        }
738
2.03k
      if (!SetImageProfile(image,"CINEONUSERDATA",user_data,user_data_length))
739
0
        {
740
0
          MagickFreeResourceLimitedMemory(unsigned char *,user_data);
741
0
          ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
742
0
        }
743
2.03k
      MagickFreeResourceLimitedMemory(unsigned char *,user_data);
744
2.03k
    }
745
746
2.88k
  if (image_info->ping)
747
0
    {
748
0
      CloseBlob(image);
749
0
      return(image);
750
0
    }
751
752
2.88k
  if (CheckImagePixelLimits(image, exception) != MagickPass)
753
2.13k
    ThrowReaderException(ResourceLimitError,ImagePixelLimitExceeded,image);
754
755
  /*
756
    Read remainder of header.
757
  */
758
2.13M
  for ( ; offset < pixels_offset ; offset++ )
759
2.13M
    if (ReadBlobByte(image) == EOF)
760
659
      ThrowReaderException(CorruptImageError,UnexpectedEndOfFile,image);
761
762
  /*
763
    Verify that remaining data is sufficient for claimed dimensions.
764
  */
765
659
  if (BlobIsSeekable(image))
766
659
    {
767
659
      magick_off_t file_size;
768
659
      magick_intmax_t expected_file_size;
769
770
659
      file_size = GetBlobSize(image);
771
772
659
      expected_file_size=pixels_offset+
773
659
        ((((((magick_intmax_t) image->rows*image->columns*number_of_channels+2UL)/3UL)
774
659
           *sizeof(U32)*8UL)+31UL)/32UL)*sizeof(U32);
775
659
      if (image->logging)
776
659
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
777
659
                              "Expected file size %" MAGICK_UINTMAX_F "u bytes"
778
659
                              " (have %" MAGICK_OFF_F "d bytes)",
779
659
                              expected_file_size, file_size);
780
781
659
      if ((file_size > 0) && ((magick_int64_t) file_size < expected_file_size))
782
620
        ThrowReaderException(CorruptImageError,InsufficientImageDataInFile,image);
783
620
    }
784
785
620
  if (image->logging)
786
620
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
787
620
                          "Reading Cineon pixels starting at offset %ld",(long) TellBlob(image));
788
789
  /*
790
    Convert CINEON raster image to pixel packets.
791
  */
792
620
  {
793
620
    size_t
794
620
      scandata_bytes;
795
796
620
    unsigned int
797
620
      scale_to_short=0;
798
799
620
    switch (number_of_channels)
800
620
      {
801
406
      case 1:
802
406
        {
803
406
          scandata_bytes=4;
804
406
          scale_to_short=64;
805
406
          scandata=MagickAllocateResourceLimitedMemory(unsigned char *,scandata_bytes);
806
406
          if (scandata == (unsigned char *) NULL)
807
406
            ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
808
406
          scanline=scandata;
809
406
          MagickBitStreamInitializeRead(&bit_stream,(const unsigned char*) scanline);
810
137k
          for (y=0; y < image->rows; y++)
811
137k
            {
812
137k
              q=SetImagePixels(image,0,y,image->columns,1);
813
137k
              if (q == (PixelPacket *) NULL)
814
2
                break;
815
              /*
816
                Packed 10 bit samples with 2 bit pad at end of 32-bit word.
817
              */
818
137k
              scanline=scandata;
819
137k
              i=3;
820
17.2M
              for (x=0; x < image->columns; x++, i++)
821
17.1M
                {
822
17.1M
                  if (i > 2)
823
5.77M
                    {
824
5.77M
                      scanline=scandata;
825
5.77M
                      if (ReadBlobZC(image,scandata_bytes,&scanline) !=
826
5.77M
                          scandata_bytes)
827
148
                        break;
828
5.77M
                      MagickBitStreamInitializeRead(&bit_stream,(const unsigned char *) scanline);
829
5.77M
                      i=0;
830
5.77M
                    }
831
17.1M
                  q->red=q->green=q->blue=
832
17.1M
                    ScaleShortToQuantum(MagickBitStreamMSBRead(&bit_stream,10)*scale_to_short);
833
17.1M
                  q->opacity=0U;
834
17.1M
                  q++;
835
17.1M
                }
836
137k
              if (x < image->columns)
837
148
                break;
838
137k
              if (!SyncImagePixels(image))
839
0
                break;
840
137k
              if (image->previous == (Image *) NULL)
841
137k
                if (QuantumTick(y,image->rows))
842
21.7k
                  if (!MagickMonitorFormatted(y,image->rows,exception,
843
21.7k
                                              LoadImageText,image->filename,
844
21.7k
                                              image->columns,image->rows))
845
0
                    break;
846
137k
            }
847
406
          MagickFreeResourceLimitedMemory(unsigned char *,scandata);
848
406
          break;
849
406
        }
850
211
      case 3:
851
211
        {
852
211
          scandata_bytes=MagickArraySize(image->columns,4);
853
211
          scale_to_short=64;
854
211
          scandata=MagickAllocateResourceLimitedMemory(unsigned char *,scandata_bytes);
855
211
          if (scandata == (unsigned char *) NULL)
856
211
            ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
857
36.4k
          for (y=0; y < image->rows; y++)
858
36.3k
            {
859
36.3k
              magick_uint32_t red;
860
36.3k
              magick_uint32_t green;
861
36.3k
              magick_uint32_t blue;
862
863
36.3k
              q=SetImagePixels(image,0,y,image->columns,1);
864
36.3k
              if (q == (PixelPacket *) NULL)
865
1
                break;
866
36.3k
              scanline=scandata;
867
36.3k
              if (ReadBlobZC(image,scandata_bytes,&scanline) != scandata_bytes)
868
113
                break;
869
36.2k
              MagickBitStreamInitializeRead(&bit_stream,(const unsigned char*) scanline);
870
906k
              for (x=0 ; x < image->columns; x++)
871
870k
                {
872
                  /*
873
                    Packed 10 bit samples with 2 bit pad at end of 32-bit word.
874
                  */
875
870k
                  red   = MagickBitStreamMSBRead(&bit_stream,10);
876
870k
                  green = MagickBitStreamMSBRead(&bit_stream,10);
877
870k
                  blue  = MagickBitStreamMSBRead(&bit_stream,10);
878
870k
                  (void) MagickBitStreamMSBRead(&bit_stream,2);
879
880
870k
                  q->red     = ScaleShortToQuantum(red*scale_to_short);
881
870k
                  q->green   = ScaleShortToQuantum(green*scale_to_short);
882
870k
                  q->blue    = ScaleShortToQuantum(blue*scale_to_short);
883
870k
                  q->opacity = 0U;
884
885
/*                   printf("i:%u,%u,%u --> %u,%u,%u\n", red, green, blue, */
886
/*                          (unsigned int)q->red, (unsigned int)q->green, (unsigned int)q->blue); */
887
870k
                  q++;
888
870k
                }
889
36.2k
              if (x < image->columns)
890
0
                break;
891
36.2k
              if (!SyncImagePixels(image))
892
0
                break;
893
36.2k
              if (image->previous == (Image *) NULL)
894
36.2k
                if (QuantumTick(y,image->rows))
895
5.71k
                  if (!MagickMonitorFormatted(y,image->rows,exception,
896
5.71k
                                              LoadImageText,image->filename,
897
5.71k
                                              image->columns,image->rows))
898
0
                    break;
899
36.2k
            }
900
211
          MagickFreeResourceLimitedMemory(unsigned char *,scandata);
901
211
          break;
902
211
        }
903
3
      default:
904
3
        ThrowReaderException(CorruptImageError,ImageTypeNotSupported,image);
905
620
      }
906
620
  }
907
617
  if (image->logging)
908
617
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
909
617
                          "EOF at offset %" MAGICK_OFF_F "d", TellBlob(image));
910
617
  image->depth=Min(image->depth,QuantumDepth);
911
617
  image->colorspace=CineonLogRGBColorspace;
912
913
617
  if ((definition_value=AccessDefinition(image_info,"cineon","colorspace")))
914
0
    {
915
0
      ColorspaceType
916
0
        colorspace;
917
918
0
      colorspace=StringToColorspaceType(definition_value);
919
0
      if (colorspace != UndefinedColorspace)
920
0
        {
921
0
          image->colorspace=colorspace;
922
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
923
0
                                "Explicitly set colorspace to %s",
924
0
                                ColorspaceTypeToString(image->colorspace));
925
0
        }
926
0
      else
927
0
        {
928
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
929
0
                                "Unrecognized source colorspace \"%s\"\n",
930
0
                                definition_value);
931
0
          ThrowException(&image->exception,OptionError,UnrecognizedColorspace,
932
0
                         definition_value);
933
0
        }
934
0
    }
935
936
617
  if (EOFBlob(image))
937
261
    ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,image->filename);
938
617
  CloseBlob(image);
939
617
  StopTimer(&image->timer);
940
617
  return(GetFirstImageInList(image));
941
620
}
942

943
/*
944
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
945
%                                                                             %
946
%                                                                             %
947
%                                                                             %
948
%   R e g i s t e r C I N E O N I m a g e                                     %
949
%                                                                             %
950
%                                                                             %
951
%                                                                             %
952
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
953
%
954
%  Method RegisterCINEONImage adds attributes for the CINEON image format to
955
%  the list of supported formats.  The attributes include the image format
956
%  tag, a method to read and/or write the format, whether the format
957
%  supports the saving of more than one frame to the same file or blob,
958
%  whether the format supports native in-memory I/O, and a brief
959
%  description of the format.
960
%
961
%  The format of the RegisterCINEONImage method is:
962
%
963
%      RegisterCINEONImage(void)
964
%
965
*/
966
ModuleExport void RegisterCINEONImage(void)
967
4
{
968
4
  MagickInfo
969
4
    *entry;
970
971
4
  entry=SetMagickInfo("CIN");
972
4
  entry->decoder=(DecoderHandler) ReadCINEONImage;
973
4
  entry->encoder=(EncoderHandler) WriteCINEONImage;
974
4
  entry->magick=(MagickHandler) IsCINEON;
975
4
  entry->description="Cineon Image File";
976
4
  entry->module="CINEON";
977
4
  entry->adjoin=MagickFalse;
978
4
  (void) RegisterMagickInfo(entry);
979
4
}
980

981
/*
982
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
983
%                                                                             %
984
%                                                                             %
985
%                                                                             %
986
%   U n r e g i s t e r C I N E O N I m a g e                                 %
987
%                                                                             %
988
%                                                                             %
989
%                                                                             %
990
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
991
%
992
%  Method UnregisterCINEONImage removes format registrations made by the
993
%  CINEON module from the list of supported formats.
994
%
995
%  The format of the UnregisterCINEONImage method is:
996
%
997
%      UnregisterCINEONImage(void)
998
%
999
*/
1000
ModuleExport void UnregisterCINEONImage(void)
1001
0
{
1002
0
  (void) UnregisterMagickInfo("CIN");
1003
0
}
1004

1005
/*
1006
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1007
%                                                                             %
1008
%                                                                             %
1009
%                                                                             %
1010
%   W r i t e C I N E O N I m a g e                                           %
1011
%                                                                             %
1012
%                                                                             %
1013
%                                                                             %
1014
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1015
%
1016
%  WriteCINEONImage() writes an image in CINEON encoded image format.
1017
%
1018
%  The format of the WriteCINEONImage method is:
1019
%
1020
%      unsigned int WriteCINEONImage(const ImageInfo *image_info,Image *image)
1021
%
1022
%  A description of each parameter follows.
1023
%
1024
%    o image_info: The image info.
1025
%
1026
%    o image:  The image.
1027
%
1028
%
1029
*/
1030
1031
1.00k
#define AttributeToU8(image_info,image,key,member) \
1032
1.00k
{ \
1033
1.00k
  const ImageAttribute \
1034
1.00k
    *attribute; \
1035
1.00k
\
1036
1.00k
  const char \
1037
1.00k
    *definition_value; \
1038
1.00k
\
1039
1.00k
  if ((definition_value=AccessDefinition(image_info,"dpx",&key[4]))) \
1040
1.00k
    member=(U8) strtol(definition_value, (char **) NULL, 10); \
1041
1.00k
  else if ((attribute=GetImageAttribute(image,key))) \
1042
1.00k
    member=(U8) strtol(attribute->value, (char **) NULL, 10); \
1043
1.00k
  else \
1044
1.00k
    SET_UNDEFINED_U8(member); \
1045
1.00k
}
1046
1047
1.00k
#define AttributeToU32(image_info,image,key,member) \
1048
1.00k
{ \
1049
1.00k
  const ImageAttribute \
1050
1.00k
    *attribute; \
1051
1.00k
\
1052
1.00k
  const char \
1053
1.00k
    *definition_value; \
1054
1.00k
\
1055
1.00k
  if ((definition_value=AccessDefinition(image_info,"dpx",&key[4]))) \
1056
1.00k
    member=(U32) strtol(definition_value, (char **) NULL, 10); \
1057
1.00k
  else if ((attribute=GetImageAttribute(image,key))) \
1058
1.00k
    member=(U32) strtol(attribute->value, (char **) NULL, 10); \
1059
1.00k
  else \
1060
1.00k
    SET_UNDEFINED_U32(member); \
1061
1.00k
}
1062
1063
670
#define AttributeToS32(image_info,image,key,member) \
1064
670
{ \
1065
670
  const ImageAttribute \
1066
670
    *attribute; \
1067
670
\
1068
670
  const char \
1069
670
    *definition_value; \
1070
670
\
1071
670
  if ((definition_value=AccessDefinition(image_info,"dpx",&key[4]))) \
1072
670
    member=(S32) strtol(definition_value, (char **) NULL, 10); \
1073
670
  else if ((attribute=GetImageAttribute(image,key))) \
1074
670
    member=(S32) strtol(attribute->value, (char **) NULL, 10); \
1075
670
  else \
1076
670
    SET_UNDEFINED_S32(member); \
1077
670
}
1078
1079
1.34k
#define AttributeToR32(image_info,image,key,member) \
1080
1.34k
{ \
1081
1.34k
  const ImageAttribute \
1082
1.34k
    *attribute; \
1083
1.34k
\
1084
1.34k
  const char \
1085
1.34k
    *definition_value; \
1086
1.34k
\
1087
1.34k
  if ((definition_value=AccessDefinition(image_info,"dpx",&key[4]))) \
1088
1.34k
    member.f=(float) strtod(definition_value, (char **) NULL); \
1089
1.34k
  else if ((attribute=GetImageAttribute(image,key))) \
1090
1.34k
    member.f=(float) strtod(attribute->value, (char **) NULL); \
1091
1.34k
  else \
1092
1.34k
    SET_UNDEFINED_R32(member); \
1093
1.34k
}
1094
1095
/*
1096
  Header string values are not required to be null terminated, but any
1097
  unused space should be filled with nulls.
1098
*/
1099
3.01k
#define AttributeToString(image_info,image,key,member) \
1100
3.01k
{ \
1101
3.01k
  const ImageAttribute \
1102
3.01k
    *attribute; \
1103
3.01k
\
1104
3.01k
  const char \
1105
3.01k
    *definition_value; \
1106
3.01k
\
1107
3.01k
  SET_UNDEFINED_ASCII(member); \
1108
3.01k
  if ((definition_value=AccessDefinition(image_info,"dpx",&key[4]))) \
1109
3.01k
    (void) memcpy(member,definition_value,Min(sizeof(member),strlen(definition_value))); \
1110
3.01k
  else if ((attribute=GetImageAttribute(image,key)) && (attribute->value)) \
1111
3.01k
    (void) memcpy(member,attribute->value,Min(sizeof(member),strlen(attribute->value))); \
1112
3.01k
}
1113
1114
static void GenerateCineonTimeStamp(char *date_str, size_t date_str_length, char*time_str, size_t time_str_length)
1115
335
{
1116
335
  char timestamp[MaxTextExtent];
1117
1118
335
  time_t
1119
335
    current_time;
1120
1121
335
#if defined(HAVE_LOCALTIME_R)
1122
335
  struct tm
1123
335
    tm_buf;
1124
335
#endif /* if defined(HAVE_LOCALTIME_R) */
1125
1126
335
  const struct tm
1127
335
    *t;
1128
1129
335
  current_time=time((time_t *) NULL);
1130
335
#if defined(HAVE_LOCALTIME_R)
1131
335
  t=localtime_r(&current_time, &tm_buf);
1132
#else
1133
  t=localtime(&current_time); /* Thread-unsafe version */
1134
#endif  /* if defined(HAVE_LOCALTIME_R) */
1135
1136
335
  (void) memset(timestamp,0,sizeof(timestamp));
1137
335
  (void) strftime(timestamp,MaxTextExtent,"%Y:%m:%d:%H:%M:%S%Z",t);
1138
335
  timestamp[MaxTextExtent-1]='\0';
1139
335
  (void) memset(date_str,0,date_str_length);
1140
335
  (void) strlcpy(date_str,timestamp,date_str_length);
1141
335
  (void) memset(time_str,0,time_str_length);
1142
335
  (void) strlcpy(time_str,timestamp+11,time_str_length);
1143
335
}
1144
1145
1146
static unsigned int WriteCINEONImage(const ImageInfo *image_info,Image *image)
1147
335
{
1148
335
  CineonFileInfo
1149
335
    cin_file_info;
1150
1151
335
  CineonImageInfo
1152
335
    cin_image_info;
1153
1154
335
  CineonImageOriginationInfo
1155
335
    cin_source_info;
1156
1157
335
  CineonFilmInfo
1158
335
    cin_mp_info;
1159
1160
335
  const unsigned char
1161
335
    *user_data;
1162
1163
335
  size_t
1164
335
    user_data_length=0,
1165
335
    offset=0;
1166
1167
335
  size_t
1168
335
    written=0;
1169
1170
335
  MagickBool
1171
335
    swab=MagickFalse;
1172
1173
335
  long
1174
335
    y;
1175
1176
335
  register const PixelPacket
1177
335
    *p;
1178
1179
335
  register long
1180
335
    x;
1181
1182
335
  unsigned int
1183
335
    status;
1184
1185
335
  assert(image_info != (const ImageInfo *) NULL);
1186
335
  assert(image_info->signature == MagickSignature);
1187
335
  assert(image != (Image *) NULL);
1188
335
  assert(image->signature == MagickSignature);
1189
1190
  /*
1191
    Cineon files are written in Cineon Log color space.
1192
  */
1193
335
  if (image->colorspace != CineonLogRGBColorspace)
1194
0
    if (TransformColorspace(image,CineonLogRGBColorspace) == MagickFail)
1195
335
      ThrowWriterException(CoderError,UnableToTransformColorspace,image);
1196
1197
335
#if !defined(WORDS_BIGENDIAN)
1198
335
  swab=MagickTrue;
1199
335
#endif /* !defined(WORDS_BIGENDIAN) */
1200
1201
  /*
1202
    File information header
1203
  */
1204
335
  (void) memset(&cin_file_info,0,sizeof(cin_file_info));
1205
1206
  /* Magick number (0x802A5FD7) */
1207
335
  cin_file_info.magic = 0x802A5FD7;
1208
  /* Generic section header length in bytes */
1209
335
  cin_file_info.generic_section_length = sizeof(cin_file_info)+sizeof(cin_image_info)+sizeof(cin_source_info);
1210
  /* Industry specific header length in bytes */
1211
335
  cin_file_info.industry_section_length = sizeof(cin_mp_info);
1212
  /* User defined header length in bytes */
1213
335
  cin_file_info.user_defined_length = 0;
1214
335
  user_data=GetImageProfile(image,"CINEONUSERDATA",&user_data_length);
1215
335
  if (user_data && user_data_length)
1216
102
    cin_file_info.user_defined_length = (U32) user_data_length;
1217
  /* Offset to image data in bytes */
1218
335
  cin_file_info.image_data_offset =
1219
335
    cin_file_info.generic_section_length +
1220
335
    cin_file_info.industry_section_length +
1221
335
    cin_file_info.user_defined_length;
1222
  /* Total image file size in bytes  */
1223
335
  cin_file_info.file_size =
1224
335
    cin_file_info.generic_section_length +
1225
335
    cin_file_info.industry_section_length +
1226
335
    cin_file_info.user_defined_length +
1227
335
    image->rows*image->columns*4;
1228
  /* Version number of header format */
1229
335
  (void) strlcpy(cin_file_info.header_format_version,"V4.5",sizeof(cin_file_info.header_format_version));
1230
  /* Image filename */
1231
335
  (void) strlcpy(cin_file_info.image_filename,image->filename,sizeof(cin_file_info.image_filename));
1232
  /* Creation date "yyyy:mm:dd", and time "hh:mm:ssLTZ" */
1233
335
  GenerateCineonTimeStamp(cin_file_info.creation_date,sizeof(cin_file_info.creation_date),
1234
335
                          cin_file_info.creation_time,sizeof(cin_file_info.creation_time));
1235
1236
  /*
1237
    Image information header
1238
  */
1239
335
  (void) memset(&cin_image_info,0,sizeof(cin_image_info));
1240
  /* Image orientation */
1241
335
  cin_image_info.orientation = OrientationTypeToCineonOrientation(image->orientation);
1242
  /* Number of image channels (1-8) */
1243
335
  cin_image_info.channels = 3; /* RGB */
1244
1245
  /* Channel 0 (Red) */
1246
335
  cin_image_info.channel_info[0].designator_byte_0 = 0;  /* 0 = universal metric */
1247
335
  cin_image_info.channel_info[0].designator_byte_1 = 1;  /* Red, Printing Density */
1248
  /* Bit depth */
1249
335
  cin_image_info.channel_info[0].bits_per_sample = 10;
1250
  /* Pixels per line (columns) */
1251
335
  cin_image_info.channel_info[0].pixels_per_line = image->columns;
1252
  /* Lines per image (rows) */
1253
335
  cin_image_info.channel_info[0].lines_per_image = image->rows;
1254
  /* Reference low data code value */
1255
335
  cin_image_info.channel_info[0].reference_low_data_code.f = 0;
1256
  /* Low quantity represented */
1257
335
  cin_image_info.channel_info[0].reference_low_quantity.f = 0.00;
1258
  /* Reference high data code value */
1259
335
  cin_image_info.channel_info[0].reference_high_data_code.f = 1023;
1260
  /* Reference high quantity represented */
1261
335
  cin_image_info.channel_info[0].reference_high_quantity.f = 2.048F;
1262
1263
  /* Channel 1 (Green) */
1264
335
  cin_image_info.channel_info[1] = cin_image_info.channel_info[0];
1265
335
  cin_image_info.channel_info[1].designator_byte_1 = 2; /* Green, Printing Density */
1266
1267
  /* Channel 2  (Blue) */
1268
335
  cin_image_info.channel_info[2] = cin_image_info.channel_info[0];
1269
335
  cin_image_info.channel_info[2].designator_byte_1 = 3; /* Blue, Printing Density */
1270
1271
  /* White point (color temperature) - x,y pair */
1272
335
  SET_UNDEFINED_R32(cin_image_info.white_point[0]);
1273
335
  SET_UNDEFINED_R32(cin_image_info.white_point[1]);
1274
335
  if ( image->chromaticity.white_point.x != 0.0 && image->chromaticity.white_point.y != 0.0 )
1275
266
    {
1276
266
      cin_image_info.white_point[0].f = (float) image->chromaticity.white_point.x;
1277
266
      cin_image_info.white_point[1].f = (float) image->chromaticity.white_point.y;
1278
266
    }
1279
  /* Red primary chromaticity - x,y pair */
1280
335
  SET_UNDEFINED_R32(cin_image_info.red_primary_chromaticity[0]);
1281
335
  SET_UNDEFINED_R32(cin_image_info.red_primary_chromaticity[1]);
1282
335
  if ( image->chromaticity.red_primary.x != 0.0 &&  image->chromaticity.red_primary.y != 0.0)
1283
238
    {
1284
238
      cin_image_info.red_primary_chromaticity[0].f = (float) image->chromaticity.red_primary.x;
1285
238
      cin_image_info.red_primary_chromaticity[1].f = (float) image->chromaticity.red_primary.y;
1286
238
    }
1287
  /* Green primary chromaticity - x,y pair */
1288
335
  SET_UNDEFINED_R32(cin_image_info.green_primary_chromaticity[0]);
1289
335
  SET_UNDEFINED_R32(cin_image_info.green_primary_chromaticity[1]);
1290
335
  if ( image->chromaticity.green_primary.x != 0.0 && image->chromaticity.green_primary.y != 0.0 )
1291
250
    {
1292
250
      cin_image_info.green_primary_chromaticity[0].f = (float) image->chromaticity.green_primary.x;
1293
250
      cin_image_info.green_primary_chromaticity[1].f = (float) image->chromaticity.green_primary.y;
1294
250
    }
1295
  /* Blue primary chromaticity - x,y pair */
1296
335
  SET_UNDEFINED_R32(cin_image_info.blue_primary_chromaticity[0]);
1297
335
  SET_UNDEFINED_R32(cin_image_info.blue_primary_chromaticity[1]);
1298
335
  if ( image->chromaticity.blue_primary.x != 0.0 && image->chromaticity.blue_primary.y != 0.0 )
1299
225
    {
1300
225
      cin_image_info.blue_primary_chromaticity[0].f = (float) image->chromaticity.blue_primary.x;
1301
225
      cin_image_info.blue_primary_chromaticity[1].f = (float) image->chromaticity.blue_primary.y;
1302
225
    }
1303
  /* Label text */
1304
335
  AttributeToString(image_info,image,"DPX:file.project.name",cin_image_info.label_text);
1305
  /* Data interleave */
1306
335
  cin_image_info.data_interleave = 0; /* rgbrgbrgb ... */
1307
  /* Packing method */
1308
335
  cin_image_info.packing = 5; /* longword (32-bit) boundaries - left justified */
1309
  /* Data sign: 0=unsigned, 1=signed */
1310
335
  cin_image_info.sign = 0;
1311
  /* Image sense: 0=positive, 1=negative */
1312
335
  cin_image_info.sense = 0;
1313
  /* End of line padding */
1314
335
  cin_image_info.eol_pad = 0;
1315
  /* End of channel padding */
1316
335
  cin_image_info.eoc_pad = 0;
1317
1318
  /*
1319
    Image origination header.
1320
  */
1321
335
  (void) memset(&cin_source_info,0,sizeof(cin_source_info));
1322
335
  AttributeToS32(image_info,image,"DPX:source.x-offset",cin_source_info.x_offset); /* X offset */
1323
335
  AttributeToS32(image_info,image,"DPX:source.y-offset",cin_source_info.y_offset); /* Y offset */
1324
  /* Source image filename */
1325
335
  AttributeToString(image_info,image,"DPX:source.filename",cin_source_info.source_image_filename);
1326
335
  {
1327
    /*
1328
      DPX stores creation date and time in the format
1329
      "yyyy:mm:dd:hh:mm:ssLTZ" but Cineon wants date and time to be split into
1330
      yyyy:mm:dd & hh:mm:ssLTZ
1331
    */
1332
335
    ASCII date_and_time[25];
1333
335
    AttributeToString(image_info,image,"DPX:source.creation.datetime",date_and_time);
1334
335
    SET_UNDEFINED_ASCII(cin_source_info.creation_date);
1335
335
    SET_UNDEFINED_ASCII(cin_source_info.creation_time);
1336
1337
335
    if (!IS_UNDEFINED_ASCII(date_and_time))
1338
218
      {
1339
        /* Creation date: yyyy:mm:dd */
1340
218
        (void) strlcpy(cin_source_info.creation_date,date_and_time,11);
1341
        /* Creation time: hh:mm:ssLTZ */
1342
218
        (void) strlcpy(cin_source_info.creation_time,date_and_time+11,sizeof(cin_source_info.creation_time));
1343
218
      }
1344
335
  }
1345
  /* Input device */
1346
335
  AttributeToString(image_info,image,"DPX:source.device.name",cin_source_info.input_device);
1347
  /* Input device model number */
1348
335
  AttributeToString(image_info,image,"DPX:source.device.model",cin_source_info.input_device_model);
1349
  /* Input device serial number */
1350
335
  AttributeToString(image_info,image,"DPX:source.device.serialnumber",cin_source_info.input_device_serial);
1351
  /* Input device pitch for X (samples/mm) */
1352
335
  AttributeToR32(image_info,image,"DPX:source.device.pitch.x",cin_source_info.input_device_pitch_x);
1353
  /* Input device pitch for Y (samples/mm) */
1354
335
  AttributeToR32(image_info,image,"DPX:source.device.pitch.y",cin_source_info.input_device_pitch_y);
1355
  /* Image gamma of capture device */
1356
335
  AttributeToR32(image_info,image,"DPX:source.device.gamma",cin_source_info.gamma);
1357
1358
  /*
1359
    Film/Frame Information
1360
  */
1361
335
  (void) memset(&cin_mp_info,0,sizeof(cin_mp_info));
1362
  /* Film mfg. ID code (2 digits from film edge code) */
1363
335
  AttributeToU8(image_info,image,"DPX:mp.film.manufacturer.id",cin_mp_info.film_mfg_id_code);
1364
  /* Film type (2 digits from film edge code) */
1365
335
  AttributeToU8(image_info,image,"DPX:mp.film.type",cin_mp_info.film_type);
1366
  /* Offset in perfs (2 digits from film edge code) */
1367
335
  AttributeToU8(image_info,image,"DPX:mp.perfs.offset",cin_mp_info.perfs_offset);
1368
  /* Prefix (6 digits from film edge code) */
1369
335
  AttributeToU32(image_info,image,"DPX:mp.prefix",cin_mp_info.prefix);
1370
  /* Count (4 digits from film edge code) */
1371
335
  AttributeToU32(image_info,image,"DPX:mp.count",cin_mp_info.count);
1372
  /* Format -- e.g. Academy */
1373
335
  AttributeToString(image_info,image,"DPX:mp.format",cin_mp_info.format);
1374
  /* Frame position in sequence */
1375
335
  AttributeToU32(image_info,image,"DPX:mp.frame.position",cin_mp_info.frame_position);
1376
  /* Frame rate of original (frames/s) */
1377
335
  AttributeToR32(image_info,image,"DPX:mp.frame.rate",cin_mp_info.frame_rate);
1378
  /* Frame identification - e.g. keyframe */
1379
335
  AttributeToString(image_info,image,"DPX:mp.frame.id",cin_mp_info.frame_id);
1380
  /* Slate information */
1381
335
  AttributeToString(image_info,image,"DPX:mp.slate.info",cin_mp_info.slate_info);
1382
1383
  /*
1384
    Open output image file.
1385
  */
1386
1387
335
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
1388
335
  if (status == MagickFail)
1389
0
    return (status);
1390
1391
335
  if (swab)
1392
335
    {
1393
      /*
1394
        Swap byte order.
1395
      */
1396
335
      SwabCineonFileInfo(&cin_file_info);
1397
335
      SwabCineonImageInfo(&cin_image_info);
1398
335
      SwabCineonImageOriginationInfo(&cin_source_info);
1399
335
      SwabCineonFilmInfo(&cin_mp_info);
1400
335
    }
1401
1402
335
  written = WriteBlob(image,sizeof(cin_file_info),&cin_file_info);
1403
335
  if (written != sizeof(cin_file_info))
1404
0
    {
1405
0
      CloseBlob(image);
1406
0
      return (MagickFail);
1407
0
    }
1408
335
  offset += written;
1409
1410
335
  written = WriteBlob(image,sizeof(cin_image_info),&cin_image_info);
1411
335
  if (written != sizeof(cin_image_info))
1412
0
    {
1413
0
      CloseBlob(image);
1414
0
      return (MagickFail);
1415
0
    }
1416
335
  offset += written;
1417
1418
335
  written = WriteBlob(image,sizeof(cin_source_info),&cin_source_info);
1419
335
  if (written != sizeof(cin_source_info))
1420
0
    {
1421
0
      CloseBlob(image);
1422
0
      return (MagickFail);
1423
0
    }
1424
335
  offset += written;
1425
1426
335
  written = WriteBlob(image,sizeof(cin_mp_info),&cin_mp_info);
1427
335
  if (written != sizeof(cin_mp_info))
1428
0
    {
1429
0
      CloseBlob(image);
1430
0
      return (MagickFail);
1431
0
    }
1432
335
  offset += written;
1433
1434
335
  if (swab)
1435
335
    {
1436
      /*
1437
        Swap byte order back to original.
1438
      */
1439
335
      SwabCineonFileInfo(&cin_file_info);
1440
335
      SwabCineonImageInfo(&cin_image_info);
1441
335
      SwabCineonImageOriginationInfo(&cin_source_info);
1442
335
      SwabCineonFilmInfo(&cin_mp_info);
1443
335
    }
1444
1445
335
  if (user_data)
1446
102
    {
1447
102
      written = WriteBlob(image,user_data_length,user_data);
1448
102
      if (written != user_data_length)
1449
0
        {
1450
0
          CloseBlob(image);
1451
0
          return (MagickFail);
1452
0
        }
1453
102
      offset += written;
1454
102
    }
1455
1456
335
  if (image->logging)
1457
0
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1458
0
                          "Writing Cineon pixels starting at offset %ld",(long) TellBlob(image));
1459
1460
  /*
1461
    Convert pixel packets to CINEON raster image.
1462
  */
1463
335
  {
1464
335
    unsigned char
1465
335
      *scanline;
1466
1467
335
    size_t
1468
335
      scanline_bytes;
1469
1470
335
    BitStreamWriteHandle
1471
335
      bit_stream;
1472
1473
335
    unsigned int
1474
335
      red,
1475
335
      green,
1476
335
      blue;
1477
1478
335
    unsigned int
1479
335
      bits_per_sample,
1480
335
      scale_from_short;
1481
1482
335
    bits_per_sample = cin_image_info.channel_info[0].bits_per_sample;
1483
335
    scale_from_short=(65535U / (65535U >> (16-bits_per_sample)));
1484
1485
335
    scanline_bytes=MagickArraySize(image->columns,4);
1486
335
    scanline=MagickAllocateResourceLimitedMemory(unsigned char *,scanline_bytes);
1487
335
    if (scanline == (unsigned char *) NULL)
1488
335
      ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image);
1489
335
    (void) memset(scanline,0,scanline_bytes);
1490
1491
111k
    for (y=0; y < (long) image->rows; y++)
1492
111k
      {
1493
111k
        p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
1494
111k
        if (p == (const PixelPacket *) NULL)
1495
0
          break;
1496
1497
111k
        MagickBitStreamInitializeWrite(&bit_stream,scanline);
1498
1499
12.6M
        for (x=0; x < (long) image->columns; x++)
1500
12.4M
          {
1501
12.4M
            red   = ScaleQuantumToShort(p->red)/scale_from_short;
1502
12.4M
            green = ScaleQuantumToShort(p->green)/scale_from_short;
1503
12.4M
            blue  = ScaleQuantumToShort(p->blue)/scale_from_short;
1504
1505
/*             printf("o:%u,%u,%u --> %u,%u,%u\n",(unsigned int)p->red, (unsigned int) p->green, (unsigned int) p->blue, */
1506
/*                    red, green, blue); */
1507
1508
12.4M
            MagickBitStreamMSBWrite(&bit_stream,10,red);
1509
12.4M
            MagickBitStreamMSBWrite(&bit_stream,10,green);
1510
12.4M
            MagickBitStreamMSBWrite(&bit_stream,10,blue);
1511
12.4M
            MagickBitStreamMSBWrite(&bit_stream,2,0);
1512
12.4M
            p++;
1513
12.4M
          }
1514
111k
        written = WriteBlob(image,scanline_bytes,scanline);
1515
111k
        if (written != scanline_bytes)
1516
34
          {
1517
34
            status = MagickFail;
1518
34
            break;
1519
34
          }
1520
111k
        offset += written;
1521
1522
111k
        if (image->previous == (Image *) NULL)
1523
111k
          if (QuantumTick(y,image->rows))
1524
19.5k
            if (!MagickMonitorFormatted(y,image->rows,&image->exception,
1525
19.5k
                                        SaveImageText,image->filename,
1526
19.5k
                                        image->columns,image->rows))
1527
0
              break;
1528
111k
      }
1529
335
    MagickFreeResourceLimitedMemory(unsigned char *,scanline);
1530
335
  }
1531
1532
335
  if ((magick_off_t) cin_file_info.file_size != TellBlob(image))
1533
34
    {
1534
34
      (void) printf("### File length %u, TellBlob says %u\n",
1535
34
                    cin_file_info.file_size,
1536
34
                    (unsigned int) TellBlob(image));
1537
34
    }
1538
335
  if ((magick_off_t) offset != TellBlob(image))
1539
33
    {
1540
33
      (void) printf("### Offset %lu, TellBlob says %u\n",
1541
33
                    (unsigned long) offset,
1542
33
                    (unsigned int) TellBlob(image));
1543
33
    }
1544
1545
335
  status &= CloseBlob(image);
1546
335
  return(status);
1547
335
}