1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                            DDDD   PPPP   X   X                              %
7 %                            D   D  P   P   X X                               %
8 %                            D   D  PPPP    XXX                               %
9 %                            D   D  P       X X                               %
10 %                            DDDD   P      X   X                              %
11 %                                                                             %
12 %                                                                             %
13 %                     Read/Write SMTPE DPX Image Format                       %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                   Cristy                                    %
17 %                                March 2001                                   %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    https://imagemagick.org/script/license.php                               %
27 %                                                                             %
28 %  Unless required by applicable law or agreed to in writing, software        %
29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31 %  See the License for the specific language governing permissions and        %
32 %  limitations under the License.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38 
39 /*
40   Include declarations.
41 */
42 #include "MagickCore/studio.h"
43 #include "MagickCore/attribute.h"
44 #include "MagickCore/artifact.h"
45 #include "MagickCore/blob.h"
46 #include "MagickCore/blob-private.h"
47 #include "MagickCore/cache.h"
48 #include "MagickCore/colorspace.h"
49 #include "MagickCore/colorspace-private.h"
50 #include "MagickCore/exception.h"
51 #include "MagickCore/exception-private.h"
52 #include "MagickCore/geometry.h"
53 #include "MagickCore/image.h"
54 #include "MagickCore/image-private.h"
55 #include "MagickCore/list.h"
56 #include "MagickCore/magick.h"
57 #include "MagickCore/memory_.h"
58 #include "MagickCore/module.h"
59 #include "MagickCore/monitor.h"
60 #include "MagickCore/monitor-private.h"
61 #include "MagickCore/option.h"
62 #include "MagickCore/pixel-accessor.h"
63 #include "MagickCore/profile.h"
64 #include "MagickCore/property.h"
65 #include "MagickCore/quantum-private.h"
66 #include "MagickCore/static.h"
67 #include "MagickCore/string_.h"
68 #include "MagickCore/string-private.h"
69 #include "MagickCore/timer-private.h"
70 
71 /*
72   Define declaration.
73 */
74 #define MaxNumberImageElements  8
75 
76 /*
77   Typedef declaration.
78 */
79 typedef enum
80 {
81   UserDefinedColorimetric = 0,
82   PrintingDensityColorimetric = 1,
83   LinearColorimetric = 2,
84   LogarithmicColorimetric = 3,
85   UnspecifiedVideoColorimetric = 4,
86   SMTPE_274MColorimetric = 5,
87   ITU_R709Colorimetric = 6,
88   ITU_R601_625LColorimetric = 7,
89   ITU_R601_525LColorimetric = 8,
90   NTSCCompositeVideoColorimetric = 9,
91   PALCompositeVideoColorimetric = 10,
92   ZDepthLinearColorimetric = 11,
93   DepthHomogeneousColorimetric = 12
94 } DPXColorimetric;
95 
96 typedef enum
97 {
98   UndefinedComponentType = 0,
99   RedComponentType = 1,
100   GreenComponentType = 2,
101   BlueComponentType = 3,
102   AlphaComponentType = 4,
103   LumaComponentType = 6,
104   ColorDifferenceCbCrComponentType = 7,
105   DepthComponentType = 8,
106   CompositeVideoComponentType = 9,
107   RGBComponentType = 50,
108   RGBAComponentType = 51,
109   ABGRComponentType = 52,
110   CbYCrY422ComponentType = 100,
111   CbYACrYA4224ComponentType = 101,
112   CbYCr444ComponentType = 102,
113   CbYCrA4444ComponentType = 103,
114   UserDef2ElementComponentType = 150,
115   UserDef3ElementComponentType = 151,
116   UserDef4ElementComponentType = 152,
117   UserDef5ElementComponentType = 153,
118   UserDef6ElementComponentType = 154,
119   UserDef7ElementComponentType = 155,
120   UserDef8ElementComponentType = 156
121 } DPXComponentType;
122 
123 typedef enum
124 {
125   TransferCharacteristicUserDefined = 0,
126   TransferCharacteristicPrintingDensity = 1,
127   TransferCharacteristicLinear = 2,
128   TransferCharacteristicLogarithmic = 3,
129   TransferCharacteristicUnspecifiedVideo = 4,
130   TransferCharacteristicSMTPE274M = 5,     /* 1920x1080 TV */
131   TransferCharacteristicITU_R709 = 6,      /* ITU R709 */
132   TransferCharacteristicITU_R601_625L = 7, /* 625 Line */
133   TransferCharacteristicITU_R601_525L = 8, /* 525 Line */
134   TransferCharacteristicNTSCCompositeVideo = 9,
135   TransferCharacteristicPALCompositeVideo = 10,
136   TransferCharacteristicZDepthLinear = 11,
137   TransferCharacteristicZDepthHomogeneous = 12
138 } DPXTransferCharacteristic;
139 
140 typedef struct _DPXFileInfo
141 {
142   unsigned int
143     magic,
144     image_offset;
145 
146   char
147     version[8];
148 
149   unsigned int
150     file_size,
151     ditto_key,
152     generic_size,
153     industry_size,
154     user_size;
155 
156   char
157     filename[100],
158     timestamp[24],
159     creator[100],
160     project[200],
161     copyright[200];
162 
163   unsigned int
164     encrypt_key;
165 
166   char
167     reserve[104];
168 } DPXFileInfo;
169 
170 typedef struct _DPXFilmInfo
171 {
172   char
173     id[2],
174     type[2],
175     offset[2],
176     prefix[6],
177     count[4],
178     format[32];
179 
180   unsigned int
181     frame_position,
182     sequence_extent,
183     held_count;
184 
185   float
186     frame_rate,
187     shutter_angle;
188 
189   char
190     frame_id[32],
191     slate[100],
192     reserve[56];
193 } DPXFilmInfo;
194 
195 typedef struct _DPXImageElement
196 {
197   unsigned int
198     data_sign,
199     low_data;
200 
201   float
202     low_quantity;
203 
204   unsigned int
205     high_data;
206 
207   float
208     high_quantity;
209 
210   unsigned char
211     descriptor,
212     transfer_characteristic,
213     colorimetric,
214     bit_size;
215 
216   unsigned short
217     packing,
218     encoding;
219 
220   unsigned int
221     data_offset,
222     end_of_line_padding,
223     end_of_image_padding;
224 
225   unsigned char
226     description[32];
227 } DPXImageElement;
228 
229 typedef struct _DPXImageInfo
230 {
231   unsigned short
232     orientation,
233     number_elements;
234 
235   unsigned int
236     pixels_per_line,
237     lines_per_element;
238 
239   DPXImageElement
240     image_element[MaxNumberImageElements];
241 
242   unsigned char
243     reserve[52];
244 } DPXImageInfo;
245 
246 typedef struct _DPXOrientationInfo
247 {
248   unsigned int
249     x_offset,
250     y_offset;
251 
252   float
253     x_center,
254     y_center;
255 
256   unsigned int
257     x_size,
258     y_size;
259 
260   char
261     filename[100],
262     timestamp[24],
263     device[32],
264     serial[32];
265 
266   unsigned short
267     border[4];
268 
269   unsigned int
270     aspect_ratio[2];
271 
272   unsigned char
273     reserve[28];
274 } DPXOrientationInfo;
275 
276 typedef struct _DPXTelevisionInfo
277 {
278   unsigned int
279     time_code,
280     user_bits;
281 
282   unsigned char
283     interlace,
284     field_number,
285     video_signal,
286     padding;
287 
288   float
289     horizontal_sample_rate,
290     vertical_sample_rate,
291     frame_rate,
292     time_offset,
293     gamma,
294     black_level,
295     black_gain,
296     break_point,
297     white_level,
298     integration_times;
299 
300   char
301     reserve[76];
302 } DPXTelevisionInfo;
303 
304 typedef struct _DPXUserInfo
305 {
306   char
307     id[32];
308 } DPXUserInfo;
309 
310 typedef struct DPXInfo
311 {
312   DPXFileInfo
313     file;
314 
315   DPXImageInfo
316     image;
317 
318   DPXOrientationInfo
319     orientation;
320 
321   DPXFilmInfo
322     film;
323 
324   DPXTelevisionInfo
325     television;
326 
327   DPXUserInfo
328     user;
329 } DPXInfo;
330 
331 /*
332   Forward declaractions.
333 */
334 static MagickBooleanType
335   WriteDPXImage(const ImageInfo *,Image *,ExceptionInfo *);
336 
337 /*
338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
339 %                                                                             %
340 %                                                                             %
341 %                                                                             %
342 %   I s D P X                                                                 %
343 %                                                                             %
344 %                                                                             %
345 %                                                                             %
346 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
347 %
348 %  IsDPX() returns MagickTrue if the image format type, identified by the
349 %  magick string, is DPX.
350 %
351 %  The format of the IsDPX method is:
352 %
353 %      MagickBooleanType IsDPX(const unsigned char *magick,const size_t extent)
354 %
355 %  A description of each parameter follows:
356 %
357 %    o magick: compare image format pattern against these bytes.
358 %
359 %    o extent: Specifies the extent of the magick string.
360 %
361 */
IsDPX(const unsigned char * magick,const size_t extent)362 static MagickBooleanType IsDPX(const unsigned char *magick,const size_t extent)
363 {
364   if (extent < 4)
365     return(MagickFalse);
366   if (memcmp(magick,"SDPX",4) == 0)
367     return(MagickTrue);
368   if (memcmp(magick,"XPDS",4) == 0)
369     return(MagickTrue);
370   return(MagickFalse);
371 }
372 
373 /*
374 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
375 %                                                                             %
376 %                                                                             %
377 %                                                                             %
378 %   R e a d D P X I m a g e                                                   %
379 %                                                                             %
380 %                                                                             %
381 %                                                                             %
382 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
383 %
384 %  ReadDPXImage() reads an DPX X image file and returns it.  It
385 %  allocates the memory necessary for the new Image structure and returns a
386 %  pointer to the new image.
387 %
388 %  The format of the ReadDPXImage method is:
389 %
390 %      Image *ReadDPXImage(const ImageInfo *image_info,ExceptionInfo *exception)
391 %
392 %  A description of each parameter follows:
393 %
394 %    o image_info: the image info.
395 %
396 %    o exception: return any errors or warnings in this structure.
397 %
398 */
399 
GetBytesPerRow(const size_t columns,const size_t samples_per_pixel,const size_t bits_per_pixel,const MagickBooleanType pad)400 static size_t GetBytesPerRow(const size_t columns,
401   const size_t samples_per_pixel,const size_t bits_per_pixel,
402   const MagickBooleanType pad)
403 {
404   size_t
405     bytes_per_row;
406 
407   switch (bits_per_pixel)
408   {
409     case 1:
410     {
411       bytes_per_row=4*(((size_t) samples_per_pixel*columns*bits_per_pixel+31)/
412         32);
413       break;
414     }
415     case 8:
416     default:
417     {
418       bytes_per_row=4*(((size_t) samples_per_pixel*columns*bits_per_pixel+31)/
419         32);
420       break;
421     }
422     case 10:
423     {
424       if (pad == MagickFalse)
425         {
426           bytes_per_row=4*(((size_t) samples_per_pixel*columns*bits_per_pixel+
427             31)/32);
428           break;
429         }
430       bytes_per_row=4*(((size_t) (32*((samples_per_pixel*columns+2)/3))+31)/32);
431       break;
432     }
433     case 12:
434     {
435       if (pad == MagickFalse)
436         {
437           bytes_per_row=4*(((size_t) samples_per_pixel*columns*bits_per_pixel+
438             31)/32);
439           break;
440         }
441       bytes_per_row=2*(((size_t) (16*samples_per_pixel*columns)+15)/16);
442       break;
443     }
444     case 16:
445     {
446       if (pad == MagickFalse)
447         {
448           bytes_per_row=2*(((size_t) samples_per_pixel*columns*bits_per_pixel+
449             15)/16);
450           break;
451         }
452       bytes_per_row=4*(((size_t) samples_per_pixel*columns*bits_per_pixel+31)/
453         32);
454       break;
455     }
456     case 32:
457     {
458       bytes_per_row=4*(((size_t) samples_per_pixel*columns*bits_per_pixel+31)/
459         32);
460       break;
461     }
462     case 64:
463     {
464       bytes_per_row=8*(((size_t) samples_per_pixel*columns*bits_per_pixel+63)/
465         64);
466       break;
467     }
468   }
469   return(bytes_per_row);
470 }
471 
GetImageTransferCharacteristic(const DPXTransferCharacteristic characteristic)472 static const char *GetImageTransferCharacteristic(
473   const DPXTransferCharacteristic characteristic)
474 {
475   const char
476     *transfer;
477 
478   /*
479     Get the element transfer characteristic.
480   */
481   switch(characteristic)
482   {
483     case TransferCharacteristicUserDefined:
484     {
485       transfer="UserDefined";
486       break;
487     }
488     case TransferCharacteristicPrintingDensity:
489     {
490       transfer="PrintingDensity";
491       break;
492     }
493     case TransferCharacteristicLinear:
494     {
495       transfer="Linear";
496       break;
497     }
498     case TransferCharacteristicLogarithmic:
499     {
500       transfer="Logarithmic";
501       break;
502     }
503     case TransferCharacteristicUnspecifiedVideo:
504     {
505       transfer="UnspecifiedVideo";
506       break;
507     }
508     case TransferCharacteristicSMTPE274M:
509     {
510       transfer="SMTPE274M";
511       break;
512     }
513     case TransferCharacteristicITU_R709:
514     {
515       transfer="ITU-R709";
516       break;
517     }
518     case TransferCharacteristicITU_R601_625L:
519     {
520       transfer="ITU-R601-625L";
521       break;
522     }
523     case TransferCharacteristicITU_R601_525L:
524     {
525       transfer="ITU-R601-525L";
526       break;
527     }
528     case TransferCharacteristicNTSCCompositeVideo:
529     {
530       transfer="NTSCCompositeVideo";
531       break;
532     }
533     case TransferCharacteristicPALCompositeVideo:
534     {
535       transfer="PALCompositeVideo";
536       break;
537     }
538     case TransferCharacteristicZDepthLinear:
539     {
540       transfer="ZDepthLinear";
541       break;
542     }
543     case TransferCharacteristicZDepthHomogeneous:
544     {
545       transfer="ZDepthHomogeneous";
546       break;
547     }
548     default:
549       transfer="Reserved";
550   }
551   return(transfer);
552 }
553 
IsFloatDefined(const float value)554 static inline MagickBooleanType IsFloatDefined(const float value)
555 {
556   union
557   {
558     unsigned int
559       unsigned_value;
560 
561     float
562       float_value;
563   } quantum;
564 
565   quantum.unsigned_value=0U;
566   quantum.float_value=(float) value;
567   if (quantum.unsigned_value == 0U)
568     return(MagickFalse);
569   return(MagickTrue);
570 }
571 
SetPrimaryChromaticity(const DPXColorimetric colorimetric,ChromaticityInfo * chromaticity_info)572 static void SetPrimaryChromaticity(const DPXColorimetric colorimetric,
573   ChromaticityInfo *chromaticity_info)
574 {
575   switch(colorimetric)
576   {
577     case SMTPE_274MColorimetric:
578     case ITU_R709Colorimetric:
579     {
580       chromaticity_info->red_primary.x=0.640;
581       chromaticity_info->red_primary.y=0.330;
582       chromaticity_info->red_primary.z=0.030;
583       chromaticity_info->green_primary.x=0.300;
584       chromaticity_info->green_primary.y=0.600;
585       chromaticity_info->green_primary.z=0.100;
586       chromaticity_info->blue_primary.x=0.150;
587       chromaticity_info->blue_primary.y=0.060;
588       chromaticity_info->blue_primary.z=0.790;
589       chromaticity_info->white_point.x=0.3127;
590       chromaticity_info->white_point.y=0.3290;
591       chromaticity_info->white_point.z=0.3582;
592       break;
593     }
594     case NTSCCompositeVideoColorimetric:
595     {
596       chromaticity_info->red_primary.x=0.67;
597       chromaticity_info->red_primary.y=0.33;
598       chromaticity_info->red_primary.z=0.00;
599       chromaticity_info->green_primary.x=0.21;
600       chromaticity_info->green_primary.y=0.71;
601       chromaticity_info->green_primary.z=0.08;
602       chromaticity_info->blue_primary.x=0.14;
603       chromaticity_info->blue_primary.y=0.08;
604       chromaticity_info->blue_primary.z=0.78;
605       chromaticity_info->white_point.x=0.310;
606       chromaticity_info->white_point.y=0.316;
607       chromaticity_info->white_point.z=0.374;
608       break;
609     }
610     case PALCompositeVideoColorimetric:
611     {
612       chromaticity_info->red_primary.x=0.640;
613       chromaticity_info->red_primary.y=0.330;
614       chromaticity_info->red_primary.z=0.030;
615       chromaticity_info->green_primary.x=0.290;
616       chromaticity_info->green_primary.y=0.600;
617       chromaticity_info->green_primary.z=0.110;
618       chromaticity_info->blue_primary.x=0.150;
619       chromaticity_info->blue_primary.y=0.060;
620       chromaticity_info->blue_primary.z=0.790;
621       chromaticity_info->white_point.x=0.3127;
622       chromaticity_info->white_point.y=0.3290;
623       chromaticity_info->white_point.z=0.3582;
624       break;
625     }
626     default:
627       break;
628   }
629 }
630 
TimeCodeToString(const size_t timestamp,char * code)631 static void TimeCodeToString(const size_t timestamp,char *code)
632 {
633 #define TimeFields  7
634 
635   unsigned int
636     shift;
637 
638   ssize_t
639     i;
640 
641   *code='\0';
642   shift=4*TimeFields;
643   for (i=0; i <= TimeFields; i++)
644   {
645     (void) FormatLocaleString(code,MagickPathExtent-strlen(code),"%x",
646       (unsigned int) ((timestamp >> shift) & 0x0fU));
647     code++;
648     if (((i % 2) != 0) && (i < TimeFields))
649       *code++=':';
650     shift-=4;
651     *code='\0';
652   }
653 }
654 
ReadDPXImage(const ImageInfo * image_info,ExceptionInfo * exception)655 static Image *ReadDPXImage(const ImageInfo *image_info,ExceptionInfo *exception)
656 {
657   char
658     magick[4],
659     value[MagickPathExtent];
660 
661   DPXInfo
662     dpx;
663 
664   Image
665     *image;
666 
667   MagickBooleanType
668     status;
669 
670   MagickOffsetType
671     offset;
672 
673   QuantumInfo
674     *quantum_info;
675 
676   QuantumType
677     quantum_type;
678 
679   ssize_t
680     i;
681 
682   size_t
683     extent,
684     samples_per_pixel;
685 
686   ssize_t
687     count,
688     n,
689     row,
690     y;
691 
692   unsigned char
693     component_type;
694 
695   /*
696     Open image file.
697   */
698   assert(image_info != (const ImageInfo *) NULL);
699   assert(image_info->signature == MagickCoreSignature);
700   if (image_info->debug != MagickFalse)
701     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
702       image_info->filename);
703   assert(exception != (ExceptionInfo *) NULL);
704   assert(exception->signature == MagickCoreSignature);
705   image=AcquireImage(image_info,exception);
706   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
707   if (status == MagickFalse)
708     {
709       image=DestroyImageList(image);
710       return((Image *) NULL);
711     }
712   /*
713     Read DPX file header.
714   */
715   offset=0;
716   count=ReadBlob(image,4,(unsigned char *) magick);
717   offset+=count;
718   if ((count != 4) || ((LocaleNCompare(magick,"SDPX",4) != 0) &&
719       (LocaleNCompare((char *) magick,"XPDS",4) != 0)))
720     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
721   image->endian=LSBEndian;
722   if (LocaleNCompare(magick,"SDPX",4) == 0)
723     image->endian=MSBEndian;
724   (void) memset(&dpx,0,sizeof(dpx));
725   dpx.file.image_offset=ReadBlobLong(image);
726   offset+=4;
727   offset+=ReadBlob(image,sizeof(dpx.file.version),(unsigned char *)
728     dpx.file.version);
729   (void) FormatImageProperty(image,"dpx:file.version","%.8s",dpx.file.version);
730   dpx.file.file_size=ReadBlobLong(image);
731   offset+=4;
732   dpx.file.ditto_key=ReadBlobLong(image);
733   offset+=4;
734   if (dpx.file.ditto_key != ~0U)
735     (void) FormatImageProperty(image,"dpx:file.ditto.key","%u",
736       dpx.file.ditto_key);
737   dpx.file.generic_size=ReadBlobLong(image);
738   offset+=4;
739   dpx.file.industry_size=ReadBlobLong(image);
740   offset+=4;
741   dpx.file.user_size=ReadBlobLong(image);
742   offset+=4;
743   offset+=ReadBlob(image,sizeof(dpx.file.filename),(unsigned char *)
744     dpx.file.filename);
745   (void) FormatImageProperty(image,"dpx:file.filename","%.100s",
746     dpx.file.filename);
747   (void) FormatImageProperty(image,"document","%.100s",dpx.file.filename);
748   offset+=ReadBlob(image,sizeof(dpx.file.timestamp),(unsigned char *)
749     dpx.file.timestamp);
750   if (*dpx.file.timestamp != '\0')
751     (void) FormatImageProperty(image,"dpx:file.timestamp","%.24s",
752       dpx.file.timestamp);
753   offset+=ReadBlob(image,sizeof(dpx.file.creator),(unsigned char *)
754     dpx.file.creator);
755   if (*dpx.file.creator != '\0')
756     {
757       (void) FormatImageProperty(image,"dpx:file.creator","%.100s",
758         dpx.file.creator);
759       (void) FormatImageProperty(image,"software","%.100s",dpx.file.creator);
760     }
761   offset+=ReadBlob(image,sizeof(dpx.file.project),(unsigned char *)
762     dpx.file.project);
763   if (*dpx.file.project != '\0')
764     {
765       (void) FormatImageProperty(image,"dpx:file.project","%.200s",
766         dpx.file.project);
767       (void) FormatImageProperty(image,"comment","%.100s",dpx.file.project);
768     }
769   offset+=ReadBlob(image,sizeof(dpx.file.copyright),(unsigned char *)
770     dpx.file.copyright);
771   if (*dpx.file.copyright != '\0')
772     {
773       (void) FormatImageProperty(image,"dpx:file.copyright","%.200s",
774         dpx.file.copyright);
775       (void) FormatImageProperty(image,"copyright","%.100s",
776         dpx.file.copyright);
777     }
778   dpx.file.encrypt_key=ReadBlobLong(image);
779   offset+=4;
780   if (dpx.file.encrypt_key != ~0U)
781     (void) FormatImageProperty(image,"dpx:file.encrypt_key","%u",
782       dpx.file.encrypt_key);
783   offset+=ReadBlob(image,sizeof(dpx.file.reserve),(unsigned char *)
784     dpx.file.reserve);
785   /*
786     Read DPX image header.
787   */
788   dpx.image.orientation=ReadBlobShort(image);
789   if (dpx.image.orientation > 7)
790     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
791   offset+=2;
792   if (dpx.image.orientation != (unsigned short) ~0)
793     (void) FormatImageProperty(image,"dpx:image.orientation","%d",
794       dpx.image.orientation);
795   switch (dpx.image.orientation)
796   {
797     default:
798     case 0: image->orientation=TopLeftOrientation; break;
799     case 1: image->orientation=TopRightOrientation; break;
800     case 2: image->orientation=BottomLeftOrientation; break;
801     case 3: image->orientation=BottomRightOrientation; break;
802     case 4: image->orientation=LeftTopOrientation; break;
803     case 5: image->orientation=RightTopOrientation; break;
804     case 6: image->orientation=LeftBottomOrientation; break;
805     case 7: image->orientation=RightBottomOrientation; break;
806   }
807   dpx.image.number_elements=ReadBlobShort(image);
808   if ((dpx.image.number_elements < 1) ||
809       (dpx.image.number_elements > MaxNumberImageElements))
810     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
811   offset+=2;
812   dpx.image.pixels_per_line=ReadBlobLong(image);
813   offset+=4;
814   image->columns=dpx.image.pixels_per_line;
815   dpx.image.lines_per_element=ReadBlobLong(image);
816   offset+=4;
817   image->rows=dpx.image.lines_per_element;
818   for (i=0; i < 8; i++)
819   {
820     char
821       property[MagickPathExtent];
822 
823     dpx.image.image_element[i].data_sign=ReadBlobLong(image);
824     offset+=4;
825     dpx.image.image_element[i].low_data=ReadBlobLong(image);
826     offset+=4;
827     dpx.image.image_element[i].low_quantity=ReadBlobFloat(image);
828     offset+=4;
829     dpx.image.image_element[i].high_data=ReadBlobLong(image);
830     offset+=4;
831     dpx.image.image_element[i].high_quantity=ReadBlobFloat(image);
832     offset+=4;
833     dpx.image.image_element[i].descriptor=(unsigned char) ReadBlobByte(image);
834     offset++;
835     dpx.image.image_element[i].transfer_characteristic=(unsigned char)
836       ReadBlobByte(image);
837     (void) FormatLocaleString(property,MagickPathExtent,
838       "dpx:image.element[%lu].transfer-characteristic",(long) i);
839     (void) FormatImageProperty(image,property,"%s",
840       GetImageTransferCharacteristic((DPXTransferCharacteristic)
841       dpx.image.image_element[i].transfer_characteristic));
842     offset++;
843     dpx.image.image_element[i].colorimetric=(unsigned char) ReadBlobByte(image);
844     offset++;
845     dpx.image.image_element[i].bit_size=(unsigned char) ReadBlobByte(image);
846     offset++;
847     dpx.image.image_element[i].packing=ReadBlobShort(image);
848     offset+=2;
849     dpx.image.image_element[i].encoding=ReadBlobShort(image);
850     offset+=2;
851     dpx.image.image_element[i].data_offset=ReadBlobLong(image);
852     offset+=4;
853     dpx.image.image_element[i].end_of_line_padding=ReadBlobLong(image);
854     offset+=4;
855     dpx.image.image_element[i].end_of_image_padding=ReadBlobLong(image);
856     offset+=4;
857     offset+=ReadBlob(image,sizeof(dpx.image.image_element[i].description),
858       (unsigned char *) dpx.image.image_element[i].description);
859   }
860   (void) SetImageColorspace(image,RGBColorspace,exception);
861   offset+=ReadBlob(image,sizeof(dpx.image.reserve),(unsigned char *)
862     dpx.image.reserve);
863   if (dpx.file.image_offset >= 1664U)
864     {
865       /*
866         Read DPX orientation header.
867       */
868       dpx.orientation.x_offset=ReadBlobLong(image);
869       offset+=4;
870       if (dpx.orientation.x_offset != ~0U)
871         (void) FormatImageProperty(image,"dpx:orientation.x_offset","%u",
872           dpx.orientation.x_offset);
873       dpx.orientation.y_offset=ReadBlobLong(image);
874       offset+=4;
875       if (dpx.orientation.y_offset != ~0U)
876         (void) FormatImageProperty(image,"dpx:orientation.y_offset","%u",
877           dpx.orientation.y_offset);
878       dpx.orientation.x_center=ReadBlobFloat(image);
879       offset+=4;
880       if (IsFloatDefined(dpx.orientation.x_center) != MagickFalse)
881         (void) FormatImageProperty(image,"dpx:orientation.x_center","%g",
882           dpx.orientation.x_center);
883       dpx.orientation.y_center=ReadBlobFloat(image);
884       offset+=4;
885       if (IsFloatDefined(dpx.orientation.y_center) != MagickFalse)
886         (void) FormatImageProperty(image,"dpx:orientation.y_center","%g",
887           dpx.orientation.y_center);
888       dpx.orientation.x_size=ReadBlobLong(image);
889       offset+=4;
890       if (dpx.orientation.x_size != ~0U)
891         (void) FormatImageProperty(image,"dpx:orientation.x_size","%u",
892           dpx.orientation.x_size);
893       dpx.orientation.y_size=ReadBlobLong(image);
894       offset+=4;
895       if (dpx.orientation.y_size != ~0U)
896         (void) FormatImageProperty(image,"dpx:orientation.y_size","%u",
897           dpx.orientation.y_size);
898       offset+=ReadBlob(image,sizeof(dpx.orientation.filename),(unsigned char *)
899         dpx.orientation.filename);
900       if (*dpx.orientation.filename != '\0')
901         (void) FormatImageProperty(image,"dpx:orientation.filename","%.100s",
902           dpx.orientation.filename);
903       offset+=ReadBlob(image,sizeof(dpx.orientation.timestamp),(unsigned char *)
904         dpx.orientation.timestamp);
905       if (*dpx.orientation.timestamp != '\0')
906         (void) FormatImageProperty(image,"dpx:orientation.timestamp","%.24s",
907           dpx.orientation.timestamp);
908       offset+=ReadBlob(image,sizeof(dpx.orientation.device),(unsigned char *)
909         dpx.orientation.device);
910       if (*dpx.orientation.device != '\0')
911         (void) FormatImageProperty(image,"dpx:orientation.device","%.32s",
912           dpx.orientation.device);
913       offset+=ReadBlob(image,sizeof(dpx.orientation.serial),(unsigned char *)
914         dpx.orientation.serial);
915       if (*dpx.orientation.serial != '\0')
916         (void) FormatImageProperty(image,"dpx:orientation.serial","%.32s",
917           dpx.orientation.serial);
918       for (i=0; i < 4; i++)
919       {
920         dpx.orientation.border[i]=ReadBlobShort(image);
921         offset+=2;
922       }
923       if ((dpx.orientation.border[0] != (unsigned short) (~0)) &&
924           (dpx.orientation.border[1] != (unsigned short) (~0)))
925         (void) FormatImageProperty(image,"dpx:orientation.border","%dx%d%+d%+d",
926           dpx.orientation.border[0],dpx.orientation.border[1],
927           dpx.orientation.border[2],dpx.orientation.border[3]);
928       for (i=0; i < 2; i++)
929       {
930         dpx.orientation.aspect_ratio[i]=ReadBlobLong(image);
931         offset+=4;
932       }
933       if ((dpx.orientation.aspect_ratio[0] != ~0U) &&
934           (dpx.orientation.aspect_ratio[1] != ~0U))
935         (void) FormatImageProperty(image,"dpx:orientation.aspect_ratio",
936           "%ux%u",dpx.orientation.aspect_ratio[0],
937           dpx.orientation.aspect_ratio[1]);
938       offset+=ReadBlob(image,sizeof(dpx.orientation.reserve),(unsigned char *)
939         dpx.orientation.reserve);
940     }
941   if (dpx.file.image_offset >= 1920U)
942     {
943       /*
944         Read DPX film header.
945       */
946       offset+=ReadBlob(image,sizeof(dpx.film.id),(unsigned char *) dpx.film.id);
947       if (*dpx.film.id != '\0')
948         (void) FormatImageProperty(image,"dpx:film.id","%.2s",dpx.film.id);
949       offset+=ReadBlob(image,sizeof(dpx.film.type),(unsigned char *)
950         dpx.film.type);
951       if (*dpx.film.type != '\0')
952         (void) FormatImageProperty(image,"dpx:film.type","%.2s",dpx.film.type);
953       offset+=ReadBlob(image,sizeof(dpx.film.offset),(unsigned char *)
954         dpx.film.offset);
955       if (*dpx.film.offset != '\0')
956         (void) FormatImageProperty(image,"dpx:film.offset","%.2s",
957           dpx.film.offset);
958       offset+=ReadBlob(image,sizeof(dpx.film.prefix),(unsigned char *)
959         dpx.film.prefix);
960       if (*dpx.film.prefix != '\0')
961         (void) FormatImageProperty(image,"dpx:film.prefix","%.6s",
962           dpx.film.prefix);
963       offset+=ReadBlob(image,sizeof(dpx.film.count),(unsigned char *)
964         dpx.film.count);
965       if (*dpx.film.count != '\0')
966         (void) FormatImageProperty(image,"dpx:film.count","%.4s",
967           dpx.film.count);
968       offset+=ReadBlob(image,sizeof(dpx.film.format),(unsigned char *)
969         dpx.film.format);
970       if (*dpx.film.format != '\0')
971         (void) FormatImageProperty(image,"dpx:film.format","%.4s",
972           dpx.film.format);
973       dpx.film.frame_position=ReadBlobLong(image);
974       offset+=4;
975       if (dpx.film.frame_position != ~0U)
976         (void) FormatImageProperty(image,"dpx:film.frame_position","%u",
977           dpx.film.frame_position);
978       dpx.film.sequence_extent=ReadBlobLong(image);
979       offset+=4;
980       if (dpx.film.sequence_extent != ~0U)
981         (void) FormatImageProperty(image,"dpx:film.sequence_extent","%u",
982           dpx.film.sequence_extent);
983       dpx.film.held_count=ReadBlobLong(image);
984       offset+=4;
985       if (dpx.film.held_count != ~0U)
986         (void) FormatImageProperty(image,"dpx:film.held_count","%u",
987           dpx.film.held_count);
988       dpx.film.frame_rate=ReadBlobFloat(image);
989       offset+=4;
990       if (IsFloatDefined(dpx.film.frame_rate) != MagickFalse)
991         (void) FormatImageProperty(image,"dpx:film.frame_rate","%g",
992           dpx.film.frame_rate);
993       dpx.film.shutter_angle=ReadBlobFloat(image);
994       offset+=4;
995       if (IsFloatDefined(dpx.film.shutter_angle) != MagickFalse)
996         (void) FormatImageProperty(image,"dpx:film.shutter_angle","%g",
997           dpx.film.shutter_angle);
998       offset+=ReadBlob(image,sizeof(dpx.film.frame_id),(unsigned char *)
999         dpx.film.frame_id);
1000       if (*dpx.film.frame_id != '\0')
1001         (void) FormatImageProperty(image,"dpx:film.frame_id","%.32s",
1002           dpx.film.frame_id);
1003       offset+=ReadBlob(image,sizeof(dpx.film.slate),(unsigned char *)
1004         dpx.film.slate);
1005       if (*dpx.film.slate != '\0')
1006         (void) FormatImageProperty(image,"dpx:film.slate","%.100s",
1007           dpx.film.slate);
1008       offset+=ReadBlob(image,sizeof(dpx.film.reserve),(unsigned char *)
1009         dpx.film.reserve);
1010     }
1011   if (dpx.file.image_offset >= 2048U)
1012     {
1013       /*
1014         Read DPX television header.
1015       */
1016       dpx.television.time_code=(unsigned int) ReadBlobLong(image);
1017       offset+=4;
1018       TimeCodeToString(dpx.television.time_code,value);
1019       (void) SetImageProperty(image,"dpx:television.time.code",value,exception);
1020       dpx.television.user_bits=(unsigned int) ReadBlobLong(image);
1021       offset+=4;
1022       TimeCodeToString(dpx.television.user_bits,value);
1023       (void) SetImageProperty(image,"dpx:television.user.bits",value,exception);
1024       dpx.television.interlace=(unsigned char) ReadBlobByte(image);
1025       offset++;
1026       if (dpx.television.interlace != 0)
1027         (void) FormatImageProperty(image,"dpx:television.interlace","%.20g",
1028           (double) dpx.television.interlace);
1029       dpx.television.field_number=(unsigned char) ReadBlobByte(image);
1030       offset++;
1031       if (dpx.television.field_number != 0)
1032         (void) FormatImageProperty(image,"dpx:television.field_number","%.20g",
1033           (double) dpx.television.field_number);
1034       dpx.television.video_signal=(unsigned char) ReadBlobByte(image);
1035       offset++;
1036       if (dpx.television.video_signal != 0)
1037         (void) FormatImageProperty(image,"dpx:television.video_signal","%.20g",
1038           (double) dpx.television.video_signal);
1039       dpx.television.padding=(unsigned char) ReadBlobByte(image);
1040       offset++;
1041       if (dpx.television.padding != 0)
1042         (void) FormatImageProperty(image,"dpx:television.padding","%d",
1043           dpx.television.padding);
1044       dpx.television.horizontal_sample_rate=ReadBlobFloat(image);
1045       offset+=4;
1046       if (IsFloatDefined(dpx.television.horizontal_sample_rate) != MagickFalse)
1047         (void) FormatImageProperty(image,
1048           "dpx:television.horizontal_sample_rate","%g",
1049           dpx.television.horizontal_sample_rate);
1050       dpx.television.vertical_sample_rate=ReadBlobFloat(image);
1051       offset+=4;
1052       if (IsFloatDefined(dpx.television.vertical_sample_rate) != MagickFalse)
1053         (void) FormatImageProperty(image,"dpx:television.vertical_sample_rate",
1054           "%g",dpx.television.vertical_sample_rate);
1055       dpx.television.frame_rate=ReadBlobFloat(image);
1056       offset+=4;
1057       if (IsFloatDefined(dpx.television.frame_rate) != MagickFalse)
1058         (void) FormatImageProperty(image,"dpx:television.frame_rate","%g",
1059           dpx.television.frame_rate);
1060       dpx.television.time_offset=ReadBlobFloat(image);
1061       offset+=4;
1062       if (IsFloatDefined(dpx.television.time_offset) != MagickFalse)
1063         (void) FormatImageProperty(image,"dpx:television.time_offset","%g",
1064           dpx.television.time_offset);
1065       dpx.television.gamma=ReadBlobFloat(image);
1066       offset+=4;
1067       if (IsFloatDefined(dpx.television.gamma) != MagickFalse)
1068         (void) FormatImageProperty(image,"dpx:television.gamma","%g",
1069           dpx.television.gamma);
1070       dpx.television.black_level=ReadBlobFloat(image);
1071       offset+=4;
1072       if (IsFloatDefined(dpx.television.black_level) != MagickFalse)
1073         (void) FormatImageProperty(image,"dpx:television.black_level","%g",
1074           dpx.television.black_level);
1075       dpx.television.black_gain=ReadBlobFloat(image);
1076       offset+=4;
1077       if (IsFloatDefined(dpx.television.black_gain) != MagickFalse)
1078         (void) FormatImageProperty(image,"dpx:television.black_gain","%g",
1079           dpx.television.black_gain);
1080       dpx.television.break_point=ReadBlobFloat(image);
1081       offset+=4;
1082       if (IsFloatDefined(dpx.television.break_point) != MagickFalse)
1083         (void) FormatImageProperty(image,"dpx:television.break_point","%g",
1084           dpx.television.break_point);
1085       dpx.television.white_level=ReadBlobFloat(image);
1086       offset+=4;
1087       if (IsFloatDefined(dpx.television.white_level) != MagickFalse)
1088         (void) FormatImageProperty(image,"dpx:television.white_level","%g",
1089           dpx.television.white_level);
1090       dpx.television.integration_times=ReadBlobFloat(image);
1091       offset+=4;
1092       if (IsFloatDefined(dpx.television.integration_times) != MagickFalse)
1093         (void) FormatImageProperty(image,"dpx:television.integration_times",
1094           "%g",dpx.television.integration_times);
1095       offset+=ReadBlob(image,sizeof(dpx.television.reserve),(unsigned char *)
1096         dpx.television.reserve);
1097     }
1098   if (dpx.file.image_offset > 2080U)
1099     {
1100       /*
1101         Read DPX user header.
1102       */
1103       offset+=ReadBlob(image,sizeof(dpx.user.id),(unsigned char *) dpx.user.id);
1104       if (*dpx.user.id != '\0')
1105         (void) FormatImageProperty(image,"dpx:user.id","%.32s",dpx.user.id);
1106       if ((dpx.file.user_size != ~0U) &&
1107           ((size_t) dpx.file.user_size > sizeof(dpx.user.id)))
1108         {
1109           StringInfo
1110             *profile;
1111 
1112            if ((MagickSizeType) dpx.file.user_size > GetBlobSize(image))
1113              ThrowReaderException(CorruptImageError,
1114                "InsufficientImageDataInFile");
1115            profile=BlobToStringInfo((const unsigned char *) NULL,
1116              dpx.file.user_size-sizeof(dpx.user.id));
1117            if (profile == (StringInfo *) NULL)
1118              ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1119            offset+=ReadBlob(image,GetStringInfoLength(profile),
1120              GetStringInfoDatum(profile));
1121            if (EOFBlob(image) != MagickFalse)
1122              (void) SetImageProfile(image,"dpx:user-data",profile,exception);
1123            profile=DestroyStringInfo(profile);
1124         }
1125     }
1126   for ( ; offset < (MagickOffsetType) dpx.file.image_offset; offset++)
1127     if (ReadBlobByte(image) == EOF)
1128       break;
1129   if (EOFBlob(image) != MagickFalse)
1130     {
1131       ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
1132         image->filename);
1133       return(DestroyImageList(image));
1134     }
1135   if (image_info->ping != MagickFalse)
1136     {
1137       (void) CloseBlob(image);
1138       return(GetFirstImageInList(image));
1139     }
1140   status=SetImageExtent(image,image->columns,image->rows,exception);
1141   if (status == MagickFalse)
1142     return(DestroyImageList(image));
1143   status=ResetImagePixels(image,exception);
1144   if (status == MagickFalse)
1145     return(DestroyImageList(image));
1146   for (n=0; n < (ssize_t) dpx.image.number_elements; n++)
1147   {
1148     unsigned char
1149       *pixels;
1150 
1151     /*
1152       Convert DPX raster image to pixel packets.
1153     */
1154     if ((dpx.image.image_element[n].data_offset != ~0U) &&
1155         (dpx.image.image_element[n].data_offset != 0U))
1156       {
1157          MagickOffsetType
1158            data_offset;
1159 
1160          data_offset=(MagickOffsetType) dpx.image.image_element[n].data_offset;
1161          if (data_offset < offset)
1162            offset=SeekBlob(image,data_offset,SEEK_SET);
1163          else
1164            for ( ; offset < data_offset; offset++)
1165              if (ReadBlobByte(image) == EOF)
1166                break;
1167           if (offset != data_offset)
1168             ThrowReaderException(CorruptImageError,"UnableToReadImageData");
1169        }
1170     SetPrimaryChromaticity((DPXColorimetric)
1171       dpx.image.image_element[n].colorimetric,&image->chromaticity);
1172     image->depth=dpx.image.image_element[n].bit_size;
1173     if ((image->depth == 0) || (image->depth > 32))
1174       ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1175     samples_per_pixel=1;
1176     quantum_type=GrayQuantum;
1177     component_type=dpx.image.image_element[n].descriptor;
1178     switch (component_type)
1179     {
1180       case CbYCrY422ComponentType:
1181       {
1182         samples_per_pixel=2;
1183         quantum_type=CbYCrYQuantum;
1184         break;
1185       }
1186       case CbYACrYA4224ComponentType:
1187       case CbYCr444ComponentType:
1188       {
1189         samples_per_pixel=3;
1190         quantum_type=CbYCrQuantum;
1191         break;
1192       }
1193       case RGBComponentType:
1194       {
1195         samples_per_pixel=3;
1196         quantum_type=RGBQuantum;
1197         break;
1198       }
1199       case ABGRComponentType:
1200       case RGBAComponentType:
1201       {
1202         image->alpha_trait=BlendPixelTrait;
1203         samples_per_pixel=4;
1204         quantum_type=RGBAQuantum;
1205         break;
1206       }
1207       default:
1208         break;
1209     }
1210     switch (component_type)
1211     {
1212       case CbYCrY422ComponentType:
1213       case CbYACrYA4224ComponentType:
1214       case CbYCr444ComponentType:
1215       {
1216         (void) SetImageColorspace(image,Rec709YCbCrColorspace,exception);
1217         break;
1218       }
1219       case LumaComponentType:
1220       {
1221         (void) SetImageColorspace(image,GRAYColorspace,exception);
1222         break;
1223       }
1224       default:
1225       {
1226         (void) SetImageColorspace(image,sRGBColorspace,exception);
1227         if (dpx.image.image_element[n].transfer_characteristic == LogarithmicColorimetric)
1228           (void) SetImageColorspace(image,LogColorspace,exception);
1229         if (dpx.image.image_element[n].transfer_characteristic == PrintingDensityColorimetric)
1230           (void) SetImageColorspace(image,LogColorspace,exception);
1231         break;
1232       }
1233     }
1234     extent=GetBytesPerRow(image->columns,samples_per_pixel,image->depth,
1235       dpx.image.image_element[n].packing == 0 ? MagickFalse : MagickTrue);
1236     /*
1237       DPX any-bit pixel format.
1238     */
1239     row=0;
1240     quantum_info=AcquireQuantumInfo(image_info,image);
1241     if (quantum_info == (QuantumInfo *) NULL)
1242       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
1243     SetQuantumQuantum(quantum_info,32);
1244     SetQuantumPack(quantum_info,dpx.image.image_element[n].packing == 0 ?
1245       MagickTrue : MagickFalse);
1246     pixels=GetQuantumPixels(quantum_info);
1247     for (y=0; y < (ssize_t) image->rows; y++)
1248     {
1249       const void
1250         *stream;
1251 
1252       MagickBooleanType
1253         sync;
1254 
1255       Quantum
1256         *q;
1257 
1258       size_t
1259         length;
1260 
1261       ssize_t
1262         row_offset;
1263 
1264       stream=ReadBlobStream(image,extent,pixels,&count);
1265       if (count != (ssize_t) extent)
1266         break;
1267       if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
1268           (image->previous == (Image *) NULL))
1269         {
1270           MagickBooleanType
1271             proceed;
1272 
1273           proceed=SetImageProgress(image,LoadImageTag,(MagickOffsetType) row,
1274             image->rows);
1275           if (proceed == MagickFalse)
1276             break;
1277         }
1278       row_offset=row++;
1279       q=QueueAuthenticPixels(image,0,row_offset,image->columns,1,exception);
1280       if (q == (Quantum *) NULL)
1281         break;
1282       length=ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
1283         quantum_type,(unsigned char *) stream,exception);
1284       (void) length;
1285       sync=SyncAuthenticPixels(image,exception);
1286       if (sync == MagickFalse)
1287         break;
1288     }
1289     quantum_info=DestroyQuantumInfo(quantum_info);
1290     if (y < (ssize_t) image->rows)
1291       ThrowReaderException(CorruptImageError,"UnableToReadImageData");
1292     SetQuantumImageType(image,quantum_type);
1293     if (EOFBlob(image) != MagickFalse)
1294       ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
1295         image->filename);
1296     if ((i+1) < (ssize_t) dpx.image.number_elements)
1297       {
1298         /*
1299           Allocate next image structure.
1300         */
1301         AcquireNextImage(image_info,image,exception);
1302         if (GetNextImageInList(image) == (Image *) NULL)
1303           {
1304             status=MagickFalse;
1305             break;
1306           }
1307         image=SyncNextImageInList(image);
1308         status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
1309           GetBlobSize(image));
1310         if (status == MagickFalse)
1311           break;
1312       }
1313   }
1314   (void) CloseBlob(image);
1315   if (status == MagickFalse)
1316     return(DestroyImageList(image));
1317   return(GetFirstImageInList(image));
1318 }
1319 
1320 /*
1321 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1322 %                                                                             %
1323 %                                                                             %
1324 %                                                                             %
1325 %   R e g i s t e r D P X I m a g e                                           %
1326 %                                                                             %
1327 %                                                                             %
1328 %                                                                             %
1329 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1330 %
1331 %  RegisterDPXImage() adds properties for the DPX image format to
1332 %  the list of supported formats.  The properties include the image format
1333 %  tag, a method to read and/or write the format, whether the format
1334 %  supports the saving of more than one frame to the same file or blob,
1335 %  whether the format supports native in-memory I/O, and a brief
1336 %  description of the format.
1337 %
1338 %  The format of the RegisterDPXImage method is:
1339 %
1340 %      size_t RegisterDPXImage(void)
1341 %
1342 */
RegisterDPXImage(void)1343 ModuleExport size_t RegisterDPXImage(void)
1344 {
1345   MagickInfo
1346     *entry;
1347 
1348   static const char
1349     *DPXNote =
1350     {
1351       "Digital Moving Picture Exchange Bitmap, Version 2.0.\n"
1352       "See SMPTE 268M-2003 specification at http://www.smtpe.org\n"
1353     };
1354 
1355   entry=AcquireMagickInfo("DPX","DPX","SMPTE 268M-2003 (DPX 2.0)");
1356   entry->decoder=(DecodeImageHandler *) ReadDPXImage;
1357   entry->encoder=(EncodeImageHandler *) WriteDPXImage;
1358   entry->magick=(IsImageFormatHandler *) IsDPX;
1359   entry->flags^=CoderAdjoinFlag;
1360   entry->flags|=CoderDecoderSeekableStreamFlag;
1361   entry->note=ConstantString(DPXNote);
1362   (void) RegisterMagickInfo(entry);
1363   return(MagickImageCoderSignature);
1364 }
1365 
1366 /*
1367 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1368 %                                                                             %
1369 %                                                                             %
1370 %                                                                             %
1371 %   U n r e g i s t e r D P X I m a g e                                       %
1372 %                                                                             %
1373 %                                                                             %
1374 %                                                                             %
1375 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1376 %
1377 %  UnregisterDPXImage() removes format registrations made by the
1378 %  DPX module from the list of supported formats.
1379 %
1380 %  The format of the UnregisterDPXImage method is:
1381 %
1382 %      UnregisterDPXImage(void)
1383 %
1384 */
UnregisterDPXImage(void)1385 ModuleExport void UnregisterDPXImage(void)
1386 {
1387   (void) UnregisterMagickInfo("DPX");
1388 }
1389 
1390 /*
1391 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1392 %                                                                             %
1393 %                                                                             %
1394 %                                                                             %
1395 %   W r i t e D P X I m a g e                                                 %
1396 %                                                                             %
1397 %                                                                             %
1398 %                                                                             %
1399 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1400 %
1401 %  WriteDPXImage() writes an image in DPX encoded image format.
1402 %
1403 %  The format of the WriteDPXImage method is:
1404 %
1405 %      MagickBooleanType WriteDPXImage(const ImageInfo *image_info,
1406 %        Image *image,ExceptionInfo *exception)
1407 %
1408 %  A description of each parameter follows.
1409 %
1410 %    o image_info: the image info.
1411 %
1412 %    o image:  The image.
1413 %
1414 %    o exception: return any errors or warnings in this structure.
1415 %
1416 */
1417 
StringToTimeCode(const char * key)1418 static unsigned int StringToTimeCode(const char *key)
1419 {
1420   char
1421     buffer[2];
1422 
1423   ssize_t
1424     i;
1425 
1426   unsigned int
1427     shift,
1428     value;
1429 
1430   value=0;
1431   shift=28;
1432   buffer[1]='\0';
1433   for (i=0; (*key != 0) && (i < 11); i++)
1434   {
1435     if (isxdigit((int) ((unsigned char) *key)) == 0)
1436       {
1437         key++;
1438         continue;
1439       }
1440     buffer[0]=(*key++);
1441     value|=(unsigned int) ((strtol(buffer,(char **) NULL,16)) << shift);
1442     shift-=4;
1443   }
1444   return(value);
1445 }
1446 
GetDPXProperty(const Image * image,const char * property,ExceptionInfo * exception)1447 static inline const char *GetDPXProperty(const Image *image,
1448   const char *property,ExceptionInfo *exception)
1449 {
1450   const char
1451     *value;
1452 
1453   value=GetImageArtifact(image,property);
1454   if (value != (const char *) NULL)
1455     return(value);
1456   return(GetImageProperty(image,property,exception));
1457 }
1458 
WriteDPXImage(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)1459 static MagickBooleanType WriteDPXImage(const ImageInfo *image_info,Image *image,
1460   ExceptionInfo *exception)
1461 {
1462   const char
1463     *value;
1464 
1465   const StringInfo
1466     *profile;
1467 
1468   DPXInfo
1469     dpx;
1470 
1471   GeometryInfo
1472     geometry_info;
1473 
1474   MagickBooleanType
1475     status;
1476 
1477   MagickOffsetType
1478     offset;
1479 
1480   MagickStatusType
1481     flags;
1482 
1483   QuantumInfo
1484     *quantum_info;
1485 
1486   QuantumType
1487     quantum_type;
1488 
1489   const Quantum
1490     *p;
1491 
1492   ssize_t
1493     i;
1494 
1495   size_t
1496     channels,
1497     extent,
1498     samples_per_pixel;
1499 
1500   ssize_t
1501     count,
1502     horizontal_factor,
1503     vertical_factor,
1504     y;
1505 
1506   time_t
1507     seconds;
1508 
1509   unsigned char
1510     component_type,
1511     *pixels;
1512 
1513   /*
1514     Open output image file.
1515   */
1516   assert(image_info != (const ImageInfo *) NULL);
1517   assert(image_info->signature == MagickCoreSignature);
1518   assert(image != (Image *) NULL);
1519   assert(image->signature == MagickCoreSignature);
1520   if (image->debug != MagickFalse)
1521     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1522   horizontal_factor=4;
1523   vertical_factor=4;
1524   if (image_info->sampling_factor != (char *) NULL)
1525     {
1526       flags=ParseGeometry(image_info->sampling_factor,&geometry_info);
1527       horizontal_factor=(ssize_t) geometry_info.rho;
1528       vertical_factor=(ssize_t) geometry_info.sigma;
1529       if ((flags & SigmaValue) == 0)
1530         vertical_factor=horizontal_factor;
1531       if ((horizontal_factor != 1) && (horizontal_factor != 2) &&
1532           (horizontal_factor != 4) && (vertical_factor != 1) &&
1533           (vertical_factor != 2) && (vertical_factor != 4))
1534         ThrowWriterException(CorruptImageError,"UnexpectedSamplingFactor");
1535     }
1536   if ((IsYCbCrCompatibleColorspace(image->colorspace) != MagickFalse) &&
1537       ((horizontal_factor == 2) || (vertical_factor == 2)))
1538     if ((image->columns % 2) != 0)
1539       image->columns++;
1540   assert(exception != (ExceptionInfo *) NULL);
1541   assert(exception->signature == MagickCoreSignature);
1542   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1543   if (status == MagickFalse)
1544     return(status);
1545   /*
1546     Write file header.
1547   */
1548   (void) memset(&dpx,0,sizeof(dpx));
1549   offset=0;
1550   dpx.file.magic=0x53445058U;
1551   offset+=WriteBlobLong(image,dpx.file.magic);
1552   dpx.file.image_offset=0x2000U;
1553   profile=GetImageProfile(image,"dpx:user-data");
1554   if (profile != (StringInfo *) NULL)
1555     {
1556       if (GetStringInfoLength(profile) > 1048576)
1557         ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
1558       dpx.file.image_offset+=(unsigned int) GetStringInfoLength(profile);
1559       dpx.file.image_offset=(((dpx.file.image_offset+0x2000-1)/0x2000)*0x2000);
1560     }
1561   offset+=WriteBlobLong(image,dpx.file.image_offset);
1562   (void) CopyMagickString(dpx.file.version,"V2.0",sizeof(dpx.file.version));
1563   offset+=WriteBlob(image,8,(unsigned char *) &dpx.file.version);
1564   channels=1;
1565   if (IsImageGray(image) == MagickFalse)
1566     channels=3;
1567   if (image->alpha_trait != UndefinedPixelTrait)
1568     channels++;
1569   dpx.file.file_size=(unsigned int) (channels*image->columns*image->rows+
1570     dpx.file.image_offset);
1571   offset+=WriteBlobLong(image,dpx.file.file_size);
1572   dpx.file.ditto_key=1U;  /* new frame */
1573   offset+=WriteBlobLong(image,dpx.file.ditto_key);
1574   dpx.file.generic_size=0x00000680U;
1575   offset+=WriteBlobLong(image,dpx.file.generic_size);
1576   dpx.file.industry_size=0x00000180U;
1577   offset+=WriteBlobLong(image,dpx.file.industry_size);
1578   dpx.file.user_size=0;
1579   if (profile != (StringInfo *) NULL)
1580     {
1581       dpx.file.user_size+=(unsigned int) GetStringInfoLength(profile);
1582       dpx.file.user_size=(((dpx.file.user_size+0x2000-1)/0x2000)*0x2000);
1583     }
1584   offset+=WriteBlobLong(image,dpx.file.user_size);
1585   value=GetDPXProperty(image,"dpx:file.filename",exception);
1586   if (value != (const char *) NULL)
1587     (void) CopyMagickString(dpx.file.filename,value,sizeof(dpx.file.filename));
1588   offset+=WriteBlob(image,sizeof(dpx.file.filename),(unsigned char *)
1589     dpx.file.filename);
1590   seconds=GetMagickTime();
1591   (void) FormatMagickTime(seconds,sizeof(dpx.file.timestamp),
1592     dpx.file.timestamp);
1593   offset+=WriteBlob(image,sizeof(dpx.file.timestamp),(unsigned char *)
1594     dpx.file.timestamp);
1595   (void) CopyMagickString(dpx.file.creator,MagickAuthoritativeURL,
1596     sizeof(dpx.file.creator));
1597   value=GetDPXProperty(image,"dpx:file.creator",exception);
1598   if (value != (const char *) NULL)
1599     (void) CopyMagickString(dpx.file.creator,value,sizeof(dpx.file.creator));
1600   offset+=WriteBlob(image,sizeof(dpx.file.creator),(unsigned char *)
1601     dpx.file.creator);
1602   value=GetDPXProperty(image,"dpx:file.project",exception);
1603   if (value != (const char *) NULL)
1604     (void) CopyMagickString(dpx.file.project,value,sizeof(dpx.file.project));
1605   offset+=WriteBlob(image,sizeof(dpx.file.project),(unsigned char *)
1606     dpx.file.project);
1607   value=GetDPXProperty(image,"dpx:file.copyright",exception);
1608   if (value != (const char *) NULL)
1609     (void) CopyMagickString(dpx.file.copyright,value,
1610       sizeof(dpx.file.copyright));
1611   offset+=WriteBlob(image,sizeof(dpx.file.copyright),(unsigned char *)
1612     dpx.file.copyright);
1613   dpx.file.encrypt_key=(~0U);
1614   offset+=WriteBlobLong(image,dpx.file.encrypt_key);
1615   offset+=WriteBlob(image,sizeof(dpx.file.reserve),(unsigned char *)
1616     dpx.file.reserve);
1617   /*
1618     Write image header.
1619   */
1620   switch (image->orientation)
1621   {
1622     default:
1623     case TopLeftOrientation: dpx.image.orientation=0; break;
1624     case TopRightOrientation: dpx.image.orientation=1; break;
1625     case BottomLeftOrientation: dpx.image.orientation=2; break;
1626     case BottomRightOrientation: dpx.image.orientation=3; break;
1627     case LeftTopOrientation: dpx.image.orientation=4; break;
1628     case RightTopOrientation: dpx.image.orientation=5; break;
1629     case LeftBottomOrientation: dpx.image.orientation=6; break;
1630     case RightBottomOrientation: dpx.image.orientation=7; break;
1631   }
1632   offset+=WriteBlobShort(image,dpx.image.orientation);
1633   dpx.image.number_elements=1;
1634   offset+=WriteBlobShort(image,dpx.image.number_elements);
1635   if ((image->columns != (unsigned int) image->columns) ||
1636       (image->rows != (unsigned int) image->rows))
1637     ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");
1638   offset+=WriteBlobLong(image,(unsigned int) image->columns);
1639   offset+=WriteBlobLong(image,(unsigned int) image->rows);
1640   for (i=0; i < 8; i++)
1641   {
1642     dpx.image.image_element[i].data_sign=0U;
1643     offset+=WriteBlobLong(image,dpx.image.image_element[i].data_sign);
1644     dpx.image.image_element[i].low_data=0U;
1645     offset+=WriteBlobLong(image,dpx.image.image_element[i].low_data);
1646     dpx.image.image_element[i].low_quantity=0.0f;
1647     offset+=WriteBlobFloat(image,dpx.image.image_element[i].low_quantity);
1648     dpx.image.image_element[i].high_data=0U;
1649     offset+=WriteBlobLong(image,dpx.image.image_element[i].high_data);
1650     dpx.image.image_element[i].high_quantity=0.0f;
1651     offset+=WriteBlobFloat(image,dpx.image.image_element[i].high_quantity);
1652     dpx.image.image_element[i].descriptor=0;
1653     if (i == 0)
1654       switch (image->colorspace)
1655       {
1656         case Rec601YCbCrColorspace:
1657         case Rec709YCbCrColorspace:
1658         case YCbCrColorspace:
1659         {
1660           dpx.image.image_element[i].descriptor=CbYCr444ComponentType;
1661           if (image->alpha_trait != UndefinedPixelTrait)
1662             dpx.image.image_element[i].descriptor=CbYCrA4444ComponentType;
1663           break;
1664         }
1665         default:
1666         {
1667           dpx.image.image_element[i].descriptor=RGBComponentType;
1668           if (image->alpha_trait != UndefinedPixelTrait)
1669             dpx.image.image_element[i].descriptor=RGBAComponentType;
1670           if ((image_info->type != TrueColorType) &&
1671               (image->alpha_trait == UndefinedPixelTrait) &&
1672               (SetImageGray(image,exception) != MagickFalse))
1673             dpx.image.image_element[i].descriptor=LumaComponentType;
1674           break;
1675         }
1676       }
1677     offset+=WriteBlobByte(image,dpx.image.image_element[i].descriptor);
1678     dpx.image.image_element[i].transfer_characteristic=0;
1679     if (image->colorspace == LogColorspace)
1680       dpx.image.image_element[0].transfer_characteristic=
1681         PrintingDensityColorimetric;
1682     offset+=WriteBlobByte(image,
1683       dpx.image.image_element[i].transfer_characteristic);
1684     dpx.image.image_element[i].colorimetric=0;
1685     offset+=WriteBlobByte(image,dpx.image.image_element[i].colorimetric);
1686     dpx.image.image_element[i].bit_size=0;
1687     if (i == 0)
1688       dpx.image.image_element[i].bit_size=(unsigned char) image->depth;
1689     offset+=WriteBlobByte(image,dpx.image.image_element[i].bit_size);
1690     dpx.image.image_element[i].packing=0;
1691     if ((image->depth == 10) || (image->depth == 12))
1692       dpx.image.image_element[i].packing=1;
1693     offset+=WriteBlobShort(image,dpx.image.image_element[i].packing);
1694     dpx.image.image_element[i].encoding=0;
1695     offset+=WriteBlobShort(image,dpx.image.image_element[i].encoding);
1696     dpx.image.image_element[i].data_offset=0U;
1697     if (i == 0)
1698       dpx.image.image_element[i].data_offset=dpx.file.image_offset;
1699     offset+=WriteBlobLong(image,dpx.image.image_element[i].data_offset);
1700     dpx.image.image_element[i].end_of_line_padding=0U;
1701     offset+=WriteBlobLong(image,dpx.image.image_element[i].end_of_line_padding);
1702     offset+=WriteBlobLong(image,
1703       dpx.image.image_element[i].end_of_image_padding);
1704     offset+=WriteBlob(image,sizeof(dpx.image.image_element[i].description),
1705       (unsigned char *) dpx.image.image_element[i].description);
1706   }
1707   offset+=WriteBlob(image,sizeof(dpx.image.reserve),(unsigned char *)
1708     dpx.image.reserve);
1709   /*
1710     Write orientation header.
1711   */
1712   if ((image->rows != image->magick_rows) ||
1713       (image->columns != image->magick_columns))
1714     {
1715       /*
1716         These properties are not valid if image size changed.
1717       */
1718       (void) DeleteImageProperty(image,"dpx:orientation.x_offset");
1719       (void) DeleteImageProperty(image,"dpx:orientation.y_offset");
1720       (void) DeleteImageProperty(image,"dpx:orientation.x_center");
1721       (void) DeleteImageProperty(image,"dpx:orientation.y_center");
1722       (void) DeleteImageProperty(image,"dpx:orientation.x_size");
1723       (void) DeleteImageProperty(image,"dpx:orientation.y_size");
1724     }
1725   dpx.orientation.x_offset=0U;
1726   value=GetDPXProperty(image,"dpx:orientation.x_offset",exception);
1727   if (value != (const char *) NULL)
1728     dpx.orientation.x_offset=(unsigned int) StringToUnsignedLong(value);
1729   offset+=WriteBlobLong(image,dpx.orientation.x_offset);
1730   dpx.orientation.y_offset=0U;
1731   value=GetDPXProperty(image,"dpx:orientation.y_offset",exception);
1732   if (value != (const char *) NULL)
1733     dpx.orientation.y_offset=(unsigned int) StringToUnsignedLong(value);
1734   offset+=WriteBlobLong(image,dpx.orientation.y_offset);
1735   dpx.orientation.x_center=0.0f;
1736   value=GetDPXProperty(image,"dpx:orientation.x_center",exception);
1737   if (value != (const char *) NULL)
1738     dpx.orientation.x_center=StringToDouble(value,(char **) NULL);
1739   offset+=WriteBlobFloat(image,dpx.orientation.x_center);
1740   dpx.orientation.y_center=0.0f;
1741   value=GetDPXProperty(image,"dpx:orientation.y_center",exception);
1742   if (value != (const char *) NULL)
1743     dpx.orientation.y_center=StringToDouble(value,(char **) NULL);
1744   offset+=WriteBlobFloat(image,dpx.orientation.y_center);
1745   dpx.orientation.x_size=0U;
1746   value=GetDPXProperty(image,"dpx:orientation.x_size",exception);
1747   if (value != (const char *) NULL)
1748     dpx.orientation.x_size=(unsigned int) StringToUnsignedLong(value);
1749   offset+=WriteBlobLong(image,dpx.orientation.x_size);
1750   dpx.orientation.y_size=0U;
1751   value=GetDPXProperty(image,"dpx:orientation.y_size",exception);
1752   if (value != (const char *) NULL)
1753     dpx.orientation.y_size=(unsigned int) StringToUnsignedLong(value);
1754   offset+=WriteBlobLong(image,dpx.orientation.y_size);
1755   value=GetDPXProperty(image,"dpx:orientation.filename",exception);
1756   if (value != (const char *) NULL)
1757     (void) CopyMagickString(dpx.orientation.filename,value,
1758       sizeof(dpx.orientation.filename));
1759   offset+=WriteBlob(image,sizeof(dpx.orientation.filename),(unsigned char *)
1760     dpx.orientation.filename);
1761   offset+=WriteBlob(image,sizeof(dpx.orientation.timestamp),(unsigned char *)
1762     dpx.orientation.timestamp);
1763   value=GetDPXProperty(image,"dpx:orientation.device",exception);
1764   if (value != (const char *) NULL)
1765     (void) CopyMagickString(dpx.orientation.device,value,
1766       sizeof(dpx.orientation.device));
1767   offset+=WriteBlob(image,sizeof(dpx.orientation.device),(unsigned char *)
1768     dpx.orientation.device);
1769   value=GetDPXProperty(image,"dpx:orientation.serial",exception);
1770   if (value != (const char *) NULL)
1771     (void) CopyMagickString(dpx.orientation.serial,value,
1772       sizeof(dpx.orientation.serial));
1773   offset+=WriteBlob(image,sizeof(dpx.orientation.serial),(unsigned char *)
1774     dpx.orientation.serial);
1775   for (i=0; i < 4; i++)
1776     dpx.orientation.border[i]=0;
1777   value=GetDPXProperty(image,"dpx:orientation.border",exception);
1778   if (value != (const char *) NULL)
1779     {
1780       flags=ParseGeometry(value,&geometry_info);
1781       if ((flags & SigmaValue) == 0)
1782         geometry_info.sigma=geometry_info.rho;
1783       dpx.orientation.border[0]=(unsigned short) (geometry_info.rho+0.5);
1784       dpx.orientation.border[1]=(unsigned short) (geometry_info.sigma+0.5);
1785       dpx.orientation.border[2]=(unsigned short) (geometry_info.xi+0.5);
1786       dpx.orientation.border[3]=(unsigned short) (geometry_info.psi+0.5);
1787     }
1788   for (i=0; i < 4; i++)
1789     offset+=WriteBlobShort(image,dpx.orientation.border[i]);
1790   for (i=0; i < 2; i++)
1791     dpx.orientation.aspect_ratio[i]=0U;
1792   value=GetDPXProperty(image,"dpx:orientation.aspect_ratio",exception);
1793   if (value != (const char *) NULL)
1794     {
1795       flags=ParseGeometry(value,&geometry_info);
1796       if ((flags & SigmaValue) == 0)
1797         geometry_info.sigma=geometry_info.rho;
1798       dpx.orientation.aspect_ratio[0]=(unsigned int) (geometry_info.rho+0.5);
1799       dpx.orientation.aspect_ratio[1]=(unsigned int) (geometry_info.sigma+0.5);
1800     }
1801   for (i=0; i < 2; i++)
1802     offset+=WriteBlobLong(image,dpx.orientation.aspect_ratio[i]);
1803   offset+=WriteBlob(image,sizeof(dpx.orientation.reserve),(unsigned char *)
1804     dpx.orientation.reserve);
1805   /*
1806     Write film header.
1807   */
1808   (void) memset(dpx.film.id,0,sizeof(dpx.film.id));
1809   value=GetDPXProperty(image,"dpx:film.id",exception);
1810   if (value != (const char *) NULL)
1811     (void) CopyMagickString(dpx.film.id,value,sizeof(dpx.film.id));
1812   offset+=WriteBlob(image,sizeof(dpx.film.id),(unsigned char *) dpx.film.id);
1813   (void) memset(dpx.film.type,0,sizeof(dpx.film.type));
1814   value=GetDPXProperty(image,"dpx:film.type",exception);
1815   if (value != (const char *) NULL)
1816     (void) CopyMagickString(dpx.film.type,value,sizeof(dpx.film.type));
1817   offset+=WriteBlob(image,sizeof(dpx.film.type),(unsigned char *)
1818     dpx.film.type);
1819   (void) memset(dpx.film.offset,0,sizeof(dpx.film.offset));
1820   value=GetDPXProperty(image,"dpx:film.offset",exception);
1821   if (value != (const char *) NULL)
1822     (void) CopyMagickString(dpx.film.offset,value,sizeof(dpx.film.offset));
1823   offset+=WriteBlob(image,sizeof(dpx.film.offset),(unsigned char *)
1824     dpx.film.offset);
1825   (void) memset(dpx.film.prefix,0,sizeof(dpx.film.prefix));
1826   value=GetDPXProperty(image,"dpx:film.prefix",exception);
1827   if (value != (const char *) NULL)
1828     (void) CopyMagickString(dpx.film.prefix,value,sizeof(dpx.film.prefix));
1829   offset+=WriteBlob(image,sizeof(dpx.film.prefix),(unsigned char *)
1830     dpx.film.prefix);
1831   (void) memset(dpx.film.count,0,sizeof(dpx.film.count));
1832   value=GetDPXProperty(image,"dpx:film.count",exception);
1833   if (value != (const char *) NULL)
1834     (void) CopyMagickString(dpx.film.count,value,sizeof(dpx.film.count));
1835   offset+=WriteBlob(image,sizeof(dpx.film.count),(unsigned char *)
1836     dpx.film.count);
1837   (void) memset(dpx.film.format,0,sizeof(dpx.film.format));
1838   value=GetDPXProperty(image,"dpx:film.format",exception);
1839   if (value != (const char *) NULL)
1840     (void) CopyMagickString(dpx.film.format,value,sizeof(dpx.film.format));
1841   offset+=WriteBlob(image,sizeof(dpx.film.format),(unsigned char *)
1842     dpx.film.format);
1843   dpx.film.frame_position=0U;
1844   value=GetDPXProperty(image,"dpx:film.frame_position",exception);
1845   if (value != (const char *) NULL)
1846     dpx.film.frame_position=(unsigned int) StringToUnsignedLong(value);
1847   offset+=WriteBlobLong(image,dpx.film.frame_position);
1848   dpx.film.sequence_extent=0U;
1849   value=GetDPXProperty(image,"dpx:film.sequence_extent",exception);
1850   if (value != (const char *) NULL)
1851     dpx.film.sequence_extent=(unsigned int) StringToUnsignedLong(value);
1852   offset+=WriteBlobLong(image,dpx.film.sequence_extent);
1853   dpx.film.held_count=0U;
1854   value=GetDPXProperty(image,"dpx:film.held_count",exception);
1855   if (value != (const char *) NULL)
1856     dpx.film.held_count=(unsigned int) StringToUnsignedLong(value);
1857   offset+=WriteBlobLong(image,dpx.film.held_count);
1858   dpx.film.frame_rate=0.0f;
1859   value=GetDPXProperty(image,"dpx:film.frame_rate",exception);
1860   if (value != (const char *) NULL)
1861     dpx.film.frame_rate=StringToDouble(value,(char **) NULL);
1862   offset+=WriteBlobFloat(image,dpx.film.frame_rate);
1863   dpx.film.shutter_angle=0.0f;
1864   value=GetDPXProperty(image,"dpx:film.shutter_angle",exception);
1865   if (value != (const char *) NULL)
1866     dpx.film.shutter_angle=StringToDouble(value,(char **) NULL);
1867   offset+=WriteBlobFloat(image,dpx.film.shutter_angle);
1868   (void) memset(dpx.film.frame_id,0,sizeof(dpx.film.frame_id));
1869   value=GetDPXProperty(image,"dpx:film.frame_id",exception);
1870   if (value != (const char *) NULL)
1871     (void) CopyMagickString(dpx.film.frame_id,value,sizeof(dpx.film.frame_id));
1872   offset+=WriteBlob(image,sizeof(dpx.film.frame_id),(unsigned char *)
1873     dpx.film.frame_id);
1874   value=GetDPXProperty(image,"dpx:film.slate",exception);
1875   if (value != (const char *) NULL)
1876     (void) CopyMagickString(dpx.film.slate,value,sizeof(dpx.film.slate));
1877   offset+=WriteBlob(image,sizeof(dpx.film.slate),(unsigned char *)
1878     dpx.film.slate);
1879   offset+=WriteBlob(image,sizeof(dpx.film.reserve),(unsigned char *)
1880     dpx.film.reserve);
1881   /*
1882     Write television header.
1883   */
1884   value=GetDPXProperty(image,"dpx:television.time.code",exception);
1885   if (value != (const char *) NULL)
1886     dpx.television.time_code=StringToTimeCode(value);
1887   offset+=WriteBlobLong(image,dpx.television.time_code);
1888   value=GetDPXProperty(image,"dpx:television.user.bits",exception);
1889   if (value != (const char *) NULL)
1890     dpx.television.user_bits=StringToTimeCode(value);
1891   offset+=WriteBlobLong(image,dpx.television.user_bits);
1892   value=GetDPXProperty(image,"dpx:television.interlace",exception);
1893   if (value != (const char *) NULL)
1894     dpx.television.interlace=(unsigned char) StringToLong(value);
1895   offset+=WriteBlobByte(image,dpx.television.interlace);
1896   value=GetDPXProperty(image,"dpx:television.field_number",exception);
1897   if (value != (const char *) NULL)
1898     dpx.television.field_number=(unsigned char) StringToLong(value);
1899   offset+=WriteBlobByte(image,dpx.television.field_number);
1900   dpx.television.video_signal=0;
1901   value=GetDPXProperty(image,"dpx:television.video_signal",exception);
1902   if (value != (const char *) NULL)
1903     dpx.television.video_signal=(unsigned char) StringToLong(value);
1904   offset+=WriteBlobByte(image,dpx.television.video_signal);
1905   dpx.television.padding=0;
1906   value=GetDPXProperty(image,"dpx:television.padding",exception);
1907   if (value != (const char *) NULL)
1908     dpx.television.padding=(unsigned char) StringToLong(value);
1909   offset+=WriteBlobByte(image,dpx.television.padding);
1910   dpx.television.horizontal_sample_rate=0.0f;
1911   value=GetDPXProperty(image,"dpx:television.horizontal_sample_rate",
1912     exception);
1913   if (value != (const char *) NULL)
1914     dpx.television.horizontal_sample_rate=StringToDouble(value,(char **) NULL);
1915   offset+=WriteBlobFloat(image,dpx.television.horizontal_sample_rate);
1916   dpx.television.vertical_sample_rate=0.0f;
1917   value=GetDPXProperty(image,"dpx:television.vertical_sample_rate",exception);
1918   if (value != (const char *) NULL)
1919     dpx.television.vertical_sample_rate=StringToDouble(value,(char **) NULL);
1920   offset+=WriteBlobFloat(image,dpx.television.vertical_sample_rate);
1921   dpx.television.frame_rate=0.0f;
1922   value=GetDPXProperty(image,"dpx:television.frame_rate",exception);
1923   if (value != (const char *) NULL)
1924     dpx.television.frame_rate=StringToDouble(value,(char **) NULL);
1925   offset+=WriteBlobFloat(image,dpx.television.frame_rate);
1926   dpx.television.time_offset=0.0f;
1927   value=GetDPXProperty(image,"dpx:television.time_offset",exception);
1928   if (value != (const char *) NULL)
1929     dpx.television.time_offset=StringToDouble(value,(char **) NULL);
1930   offset+=WriteBlobFloat(image,dpx.television.time_offset);
1931   dpx.television.gamma=0.0f;
1932   value=GetDPXProperty(image,"dpx:television.gamma",exception);
1933   if (value != (const char *) NULL)
1934     dpx.television.gamma=StringToDouble(value,(char **) NULL);
1935   offset+=WriteBlobFloat(image,dpx.television.gamma);
1936   dpx.television.black_level=0.0f;
1937   value=GetDPXProperty(image,"dpx:television.black_level",exception);
1938   if (value != (const char *) NULL)
1939     dpx.television.black_level=StringToDouble(value,(char **) NULL);
1940   offset+=WriteBlobFloat(image,dpx.television.black_level);
1941   dpx.television.black_gain=0.0f;
1942   value=GetDPXProperty(image,"dpx:television.black_gain",exception);
1943   if (value != (const char *) NULL)
1944     dpx.television.black_gain=StringToDouble(value,(char **) NULL);
1945   offset+=WriteBlobFloat(image,dpx.television.black_gain);
1946   dpx.television.break_point=0.0f;
1947   value=GetDPXProperty(image,"dpx:television.break_point",exception);
1948   if (value != (const char *) NULL)
1949     dpx.television.break_point=StringToDouble(value,(char **) NULL);
1950   offset+=WriteBlobFloat(image,dpx.television.break_point);
1951   dpx.television.white_level=0.0f;
1952   value=GetDPXProperty(image,"dpx:television.white_level",exception);
1953   if (value != (const char *) NULL)
1954     dpx.television.white_level=StringToDouble(value,(char **) NULL);
1955   offset+=WriteBlobFloat(image,dpx.television.white_level);
1956   dpx.television.integration_times=0.0f;
1957   value=GetDPXProperty(image,"dpx:television.integration_times",exception);
1958   if (value != (const char *) NULL)
1959     dpx.television.integration_times=StringToDouble(value,(char **) NULL);
1960   offset+=WriteBlobFloat(image,dpx.television.integration_times);
1961   offset+=WriteBlob(image,sizeof(dpx.television.reserve),(unsigned char *)
1962     dpx.television.reserve);
1963   /*
1964     Write user header.
1965   */
1966   value=GetDPXProperty(image,"dpx:user.id",exception);
1967   if (value != (const char *) NULL)
1968     (void) CopyMagickString(dpx.user.id,value,sizeof(dpx.user.id));
1969   offset+=WriteBlob(image,sizeof(dpx.user.id),(unsigned char *) dpx.user.id);
1970   if (profile != (StringInfo *) NULL)
1971     offset+=WriteBlob(image,GetStringInfoLength(profile),
1972       GetStringInfoDatum(profile));
1973   while (offset < (MagickOffsetType) dpx.image.image_element[0].data_offset)
1974   {
1975     count=WriteBlobByte(image,0x00);
1976     if (count != 1)
1977       {
1978         ThrowFileException(exception,FileOpenError,"UnableToWriteFile",
1979           image->filename);
1980         break;
1981       }
1982     offset+=count;
1983   }
1984   /*
1985     Convert pixel packets to DPX raster image.
1986   */
1987   quantum_info=AcquireQuantumInfo(image_info,image);
1988   if (quantum_info == (QuantumInfo *) NULL)
1989     ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
1990   SetQuantumQuantum(quantum_info,32);
1991   SetQuantumPack(quantum_info,dpx.image.image_element[0].packing == 0 ?
1992     MagickTrue : MagickFalse);
1993   quantum_type=RGBQuantum;
1994   if (image->alpha_trait != UndefinedPixelTrait)
1995     quantum_type=RGBAQuantum;
1996   if (IsYCbCrCompatibleColorspace(image->colorspace) != MagickFalse)
1997     {
1998       quantum_type=CbYCrQuantum;
1999       if (image->alpha_trait != UndefinedPixelTrait)
2000         quantum_type=CbYCrAQuantum;
2001       if ((horizontal_factor == 2) || (vertical_factor == 2))
2002         quantum_type=CbYCrYQuantum;
2003     }
2004   samples_per_pixel=1;
2005   quantum_type=GrayQuantum;
2006   component_type=dpx.image.image_element[0].descriptor;
2007   switch (component_type)
2008   {
2009     case CbYCrY422ComponentType:
2010     {
2011       samples_per_pixel=2;
2012       quantum_type=CbYCrYQuantum;
2013       break;
2014     }
2015     case CbYACrYA4224ComponentType:
2016     case CbYCr444ComponentType:
2017     {
2018       samples_per_pixel=3;
2019       quantum_type=CbYCrQuantum;
2020       break;
2021     }
2022     case RGBComponentType:
2023     {
2024       samples_per_pixel=3;
2025       quantum_type=RGBQuantum;
2026       break;
2027     }
2028     case ABGRComponentType:
2029     case RGBAComponentType:
2030     {
2031       samples_per_pixel=4;
2032       quantum_type=RGBAQuantum;
2033       break;
2034     }
2035     default:
2036       break;
2037   }
2038   extent=GetBytesPerRow(image->columns,samples_per_pixel,image->depth,
2039     dpx.image.image_element[0].packing == 0 ? MagickFalse : MagickTrue);
2040   pixels=(unsigned char *) GetQuantumPixels(quantum_info);
2041   for (y=0; y < (ssize_t) image->rows; y++)
2042   {
2043     size_t
2044       length;
2045 
2046     p=GetVirtualPixels(image,0,y,image->columns,1,exception);
2047     if (p == (const Quantum *) NULL)
2048       break;
2049     length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
2050       quantum_type,pixels,exception);
2051     if (length == 0)
2052       break;
2053     count=WriteBlob(image,extent,pixels);
2054     if (count != (ssize_t) extent)
2055       break;
2056     status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
2057       image->rows);
2058     if (status == MagickFalse)
2059       break;
2060   }
2061   quantum_info=DestroyQuantumInfo(quantum_info);
2062   if (y < (ssize_t) image->rows)
2063     ThrowWriterException(CorruptImageError,"UnableToWriteImageData");
2064   (void) CloseBlob(image);
2065   return(status);
2066 }
2067