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