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