1 // -*- mode: C++; tab-width: 4 -*-
2 // vi: ts=4
3
4 /*
5 * Copyright (c) 2009, Patrick A. Palmer.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * - Redistributions of source code must retain the above copyright notice,
12 * this list of conditions and the following disclaimer.
13 *
14 * - Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * - Neither the name of Patrick A. Palmer nor the names of its
19 * contributors may be used to endorse or promote products derived from
20 * this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 */
34
35
36
37 #include <cassert>
38 #include <cstdio>
39 #include <cstring>
40 #include <ctime>
41 #include <limits>
42
43 #include <OpenImageIO/sysutil.h>
44
45 #include "DPXHeader.h"
46 #include "EndianSwap.h"
47
48
49
50 // function prototypes
51 static void EmptyString(char *, const int);
52
53
54
55
Hex(char x)56 char Hex(char x)
57 {
58 if (x >= 10)
59 return (x-10+'A');
60 else
61 return (x+'0');
62 }
63
64
65
Header()66 dpx::Header::Header() : GenericHeader(), IndustryHeader(), datumSwap(true)
67 {
68 }
69
70
71
GenericHeader()72 dpx::GenericHeader::GenericHeader()
73 {
74 this->Reset();
75 }
76
77
Reset()78 void dpx::GenericHeader::Reset()
79 {
80 // File Information
81 this->magicNumber = MAGIC_COOKIE;
82 this->imageOffset = ~0;
83 EmptyString(this->version, sizeof(this->version));
84 OIIO::Strutil::safe_strcpy(this->version, SMPTE_VERSION, sizeof(this->version));
85 fileSize = sizeof(dpx::Header);
86 this->dittoKey = 1; // new
87
88 // genericSize is the size of the file/image/orientation headers
89 // sizeof(dpx::GenericHeader) won't give the correct results because
90 // of compiler padding
91 // file header is 768 bytes
92 // image header is 640 bytes
93 // orientation header 256 bytes
94
95 this->genericSize = 768 + 640 + 256;
96
97 // industrySize is the size of the motion picture/television headers
98 // motion picture header is 256 bytes
99 // television header is 128 bytes
100 this->industrySize = 256 + 128;
101
102 this->userSize = 0;
103 EmptyString(this->fileName, sizeof(this->fileName));
104 EmptyString(this->creationTimeDate, sizeof(this->creationTimeDate));
105 EmptyString(this->creator, sizeof(this->creator));
106 EmptyString(this->project, sizeof(this->project));
107 EmptyString(this->copyright, sizeof(this->copyright));
108 this->encryptKey = 0xffffffff;
109 EmptyString(this->reserved1, sizeof(this->reserved1));
110
111 // Image Information
112 this->imageOrientation = kUndefinedOrientation;
113 this->numberOfElements = 0xffff;
114 this->pixelsPerLine = this->linesPerElement = 0xffffffff;
115 EmptyString(this->reserved2, sizeof(this->reserved2));
116
117 // Image Orientation
118 this->xOffset = this->yOffset = 0xffffffff;
119 this->xCenter = this->yCenter = std::numeric_limits<float>::quiet_NaN();
120 this->xOriginalSize = this->yOriginalSize = 0xffffffff;
121 EmptyString(this->sourceImageFileName, sizeof(this->sourceImageFileName));
122 EmptyString(this->sourceTimeDate, sizeof(this->sourceTimeDate));
123 EmptyString(this->inputDevice, sizeof(this->inputDevice));
124 EmptyString(this->inputDeviceSerialNumber, sizeof(this->inputDeviceSerialNumber));
125 this->border[0] = this->border[1] = this->border[2] = this->border[3] = 0xffff;
126 this->aspectRatio[0] = this->aspectRatio[1] = 0xffffffff;
127 this->xScannedSize = this->yScannedSize = std::numeric_limits<float>::quiet_NaN();
128 EmptyString(this->reserved3, sizeof(this->reserved3));
129 }
130
131
IndustryHeader()132 dpx::IndustryHeader::IndustryHeader()
133 {
134 this->Reset();
135 }
136
137
Reset()138 void dpx::IndustryHeader::Reset()
139 {
140 // Motion Picture Industry Specific
141 EmptyString(this->filmManufacturingIdCode, sizeof(this->filmManufacturingIdCode));
142 EmptyString(this->filmType, sizeof(this->filmType));
143 EmptyString(this->perfsOffset, sizeof(this->perfsOffset));
144 EmptyString(this->prefix, sizeof(this->prefix));
145 EmptyString(this->count, sizeof(this->count));
146 EmptyString(this->format, sizeof(this->format));
147 this->framePosition = this->sequenceLength = this->heldCount = 0xffffffff;
148 this->frameRate = this->shutterAngle = std::numeric_limits<float>::quiet_NaN();
149 EmptyString(this->frameId, sizeof(this->frameId));
150 EmptyString(this->slateInfo, sizeof(this->slateInfo));
151 EmptyString(this->reserved4, sizeof(this->reserved4));
152
153 // Television Industry Specific
154 this->timeCode = this->userBits = 0xffffffff;
155 this->interlace = this->fieldNumber = 0xff;
156 this->videoSignal = kUndefined;
157 this->zero = 0xff;
158 this->horizontalSampleRate = this->verticalSampleRate = this->temporalFrameRate = std::numeric_limits<float>::quiet_NaN();
159 this->timeOffset = this->gamma = std::numeric_limits<float>::quiet_NaN();
160 this->blackLevel = this->blackGain = std::numeric_limits<float>::quiet_NaN();
161 this->breakPoint = this->whiteLevel = this->integrationTimes = std::numeric_limits<float>::quiet_NaN();
162 EmptyString(this->reserved5, sizeof(this->reserved5));
163 }
164
165
ImageElement()166 dpx::ImageElement::ImageElement()
167 {
168 this->dataSign = 0xffffffff;
169 this->lowData = 0xffffffff;
170 this->lowQuantity = R32(0xffffffff);
171 this->highData = 0xffffffff;
172 this->highQuantity = R32(0xffffffff);
173 this->descriptor = kUndefinedDescriptor;
174 this->transfer = kUndefinedCharacteristic;
175 this->colorimetric = kUndefinedCharacteristic;
176 this->bitDepth = 0xff;
177 this->packing = this->encoding = 0xffff;
178 this->dataOffset = this->endOfLinePadding = this->endOfImagePadding = 0xffffffff;
179 EmptyString(this->description, sizeof(this->description));
180 }
181
182
Read(InStream * io)183 bool dpx::Header::Read(InStream *io)
184 {
185 // rewind file
186 io->Rewind();
187
188 // read in the header from the file
189 size_t r = sizeof(GenericHeader) + sizeof(IndustryHeader);
190 if (io->Read(&(this->magicNumber), r) != r)
191 return false;
192
193 // validate
194 return this->Validate();
195 }
196
197
198 // Check to see if the compiler placed the data members in the expected memory offsets
199
Check()200 bool dpx::Header::Check()
201 {
202 // genericSize is the size of the file/image/orientation headers
203 // sizeof(dpx::GenericHeader) won't give the correct results because
204 // of compiler padding
205 // file header is 768 bytes
206 // image header is 640 bytes
207 // orientation header 256 bytes
208
209 if (sizeof(GenericHeader) != (768 + 640 + 256))
210 return false;
211
212 // industrySize is the size of the motion picture/television headers
213 // motion picture header is 256 bytes
214 // television header is 128 bytes
215 if (sizeof(IndustryHeader) != (256 + 128))
216 return false;
217
218 // data size checks
219 if (sizeof(U8) != 1 || sizeof(U16) != 2 || sizeof(U32) != 4 || sizeof(R32) != 4 || sizeof(R64) != 8)
220 return false;
221
222 return true;
223 }
224
225
226
Write(OutStream * io)227 bool dpx::Header::Write(OutStream *io)
228 {
229 // validate and byte swap, if necessary
230 if (!this->Validate())
231 return false;
232
233 // write the header to the file
234 size_t r = sizeof(GenericHeader) + sizeof(IndustryHeader);
235 if (! io->WriteCheck(&(this->magicNumber), r))
236 return false;
237
238 // swap back - data is in file, now we need it native again
239 this->Validate();
240 return true;
241 }
242
243
WriteOffsetData(OutStream * io)244 bool dpx::Header::WriteOffsetData(OutStream *io)
245 {
246 // calculate the number of elements
247 this->CalculateNumberOfElements();
248
249 // write the image offset
250 const long FIELD2 = 4; // offset to image in header
251 if (io->Seek(FIELD2, OutStream::kStart) == false)
252 return false;
253 if (this->RequiresByteSwap())
254 SwapBytes(this->imageOffset);
255 if (!io->WriteCheck(&this->imageOffset, sizeof(U32)))
256 return false;
257 if (this->RequiresByteSwap())
258 SwapBytes(this->imageOffset);
259
260
261 // write the file size
262 const long FIELD4 = 16; // offset to total image file size in header
263 if (io->Seek(FIELD4, OutStream::kStart) == false)
264 return false;
265 if (this->RequiresByteSwap())
266 SwapBytes(this->fileSize);
267 if (! io->WriteCheck(&this->fileSize, sizeof(U32)))
268 return false;
269 if (this->RequiresByteSwap())
270 SwapBytes(this->fileSize);
271
272 // write the number of elements
273 const long FIELD19 = 770; // offset to number of image elements in header
274 if (io->Seek(FIELD19, OutStream::kStart) == false)
275 return false;
276 if (this->RequiresByteSwap())
277 SwapBytes(this->numberOfElements);
278 if (! io->WriteCheck(&this->numberOfElements, sizeof(U16)))
279 return false;
280 if (this->RequiresByteSwap())
281 SwapBytes(this->numberOfElements);
282
283 // write the image offsets
284 const long FIELD21_12 = 808; // offset to image offset in image element data structure
285 const long IMAGE_STRUCTURE = 72; // sizeof the image data structure
286
287 int i;
288 for (i = 0; i < MAX_ELEMENTS; i++)
289 {
290 // only write if there is a defined image description
291 if (this->chan[i].descriptor == kUndefinedDescriptor)
292 continue;
293
294 // seek to the image offset entry in each image element
295 if (io->Seek((FIELD21_12 + (IMAGE_STRUCTURE * i)), OutStream::kStart) == false)
296 return false;
297
298 // write
299 if (this->RequiresByteSwap())
300 SwapBytes(this->chan[i].dataOffset);
301 if (! io->WriteCheck(&this->chan[i].dataOffset, sizeof(U32)))
302 return false;
303 if (this->RequiresByteSwap())
304 SwapBytes(this->chan[i].dataOffset);
305
306 }
307
308 return true;
309 }
310
311
ValidMagicCookie(const U32 magic)312 bool dpx::Header::ValidMagicCookie(const U32 magic)
313 {
314 U32 mc = MAGIC_COOKIE;
315
316 if (magic == mc)
317 return true;
318 else if (magic == SwapBytes(mc))
319 return true;
320 else
321 return false;
322 }
323
324
DetermineByteSwap(const U32 magic) const325 bool dpx::Header::DetermineByteSwap(const U32 magic) const
326 {
327 U32 mc = MAGIC_COOKIE;
328
329 bool byteSwap = false;
330
331 if (magic != mc)
332 byteSwap = true;
333
334 return byteSwap;
335 }
336
337
Validate()338 bool dpx::Header::Validate()
339 {
340 // check magic cookie
341 if (!this->ValidMagicCookie(this->magicNumber))
342 return false;
343
344 // determine if bytes needs to be swapped around
345 if (this->DetermineByteSwap(this->magicNumber))
346 {
347 // File information
348 SwapBytes(this->imageOffset);
349 SwapBytes(this->fileSize);
350 SwapBytes(this->dittoKey);
351 SwapBytes(this->genericSize);
352 SwapBytes(this->industrySize);
353 SwapBytes(this->userSize);
354 SwapBytes(this->encryptKey);
355
356 // Image information
357 SwapBytes(this->imageOrientation);
358 SwapBytes(this->numberOfElements);
359 SwapBytes(this->pixelsPerLine);
360 SwapBytes(this->linesPerElement);
361 for (int i = 0; i < MAX_ELEMENTS; i++)
362 {
363 SwapBytes(this->chan[i].dataSign);
364 SwapBytes(this->chan[i].lowData);
365 SwapBytes(this->chan[i].lowQuantity);
366 SwapBytes(this->chan[i].highData);
367 SwapBytes(this->chan[i].highQuantity);
368 SwapBytes(this->chan[i].descriptor);
369 SwapBytes(this->chan[i].transfer);
370 SwapBytes(this->chan[i].colorimetric);
371 SwapBytes(this->chan[i].bitDepth);
372 SwapBytes(this->chan[i].packing);
373 SwapBytes(this->chan[i].encoding);
374 SwapBytes(this->chan[i].dataOffset);
375 SwapBytes(this->chan[i].endOfLinePadding);
376 SwapBytes(this->chan[i].endOfImagePadding);
377 }
378
379
380 // Image Origination information
381 SwapBytes(this->xOffset);
382 SwapBytes(this->yOffset);
383 SwapBytes(this->xCenter);
384 SwapBytes(this->yCenter);
385 SwapBytes(this->xOriginalSize);
386 SwapBytes(this->yOriginalSize);
387 SwapBytes(this->border[0]);
388 SwapBytes(this->border[1]);
389 SwapBytes(this->border[2]);
390 SwapBytes(this->border[3]);
391 SwapBytes(this->aspectRatio[0]);
392 SwapBytes(this->aspectRatio[1]);
393
394
395 // Motion Picture Industry Specific
396 SwapBytes(this->framePosition);
397 SwapBytes(this->sequenceLength);
398 SwapBytes(this->heldCount);
399 SwapBytes(this->frameRate);
400 SwapBytes(this->shutterAngle);
401
402
403 // Television Industry Specific
404 SwapBytes(this->timeCode);
405 SwapBytes(this->userBits);
406 SwapBytes(this->interlace);
407 SwapBytes(this->fieldNumber);
408 SwapBytes(this->videoSignal);
409 SwapBytes(this->zero);
410 SwapBytes(this->horizontalSampleRate);
411 SwapBytes(this->verticalSampleRate);
412 SwapBytes(this->temporalFrameRate);
413 SwapBytes(this->timeOffset);
414 SwapBytes(this->gamma);
415 SwapBytes(this->blackLevel);
416 SwapBytes(this->blackGain);
417 SwapBytes(this->breakPoint);
418 SwapBytes(this->whiteLevel);
419 SwapBytes(this->integrationTimes);
420 }
421
422 return true;
423 }
424
425
426
Reset()427 void dpx::Header::Reset()
428 {
429 GenericHeader::Reset();
430 IndustryHeader::Reset();
431 }
432
433
ImageElementComponentCount(const int element) const434 int dpx::GenericHeader::ImageElementComponentCount(const int element) const
435 {
436 int count = 1;
437
438 switch (this->chan[element].descriptor)
439 {
440 case kUserDefinedDescriptor:
441 case kRed:
442 case kGreen:
443 case kBlue:
444 case kAlpha:
445 case kLuma:
446 case kColorDifference:
447 case kDepth:
448 count = 1;
449 break;
450 case kCompositeVideo:
451 count = 1;
452 break;
453 case kRGB:
454 count = 3;
455 break;
456 case kRGBA:
457 case kABGR:
458 count = 4;
459 break;
460 case kCbYCrY:
461 count = 2;
462 break;
463 case kCbYACrYA:
464 count = 3;
465 break;
466 case kCbYCr:
467 count = 3;
468 break;
469 case kCbYCrA:
470 count = 4;
471 break;
472 case kUserDefined2Comp:
473 count = 2;
474 break;
475 case kUserDefined3Comp:
476 count = 3;
477 break;
478 case kUserDefined4Comp:
479 count = 4;
480 break;
481 case kUserDefined5Comp:
482 count = 5;
483 break;
484 case kUserDefined6Comp:
485 count = 6;
486 break;
487 case kUserDefined7Comp:
488 count = 7;
489 break;
490 case kUserDefined8Comp:
491 count = 8;
492 break;
493 };
494
495 return count;
496 }
497
498
ImageElementCount() const499 int dpx::GenericHeader::ImageElementCount() const
500 {
501 if(this->numberOfElements>0 && this->numberOfElements<=MAX_ELEMENTS)
502 return this->numberOfElements;
503
504 // If the image header does not list a valid number of elements,
505 // count how many defined image descriptors we have...
506
507 int i = 0;
508
509 while (i < MAX_ELEMENTS )
510 {
511 if (this->ImageDescriptor(i) == kUndefinedDescriptor)
512 break;
513 i++;
514 }
515
516 return i;
517 }
518
519
CalculateNumberOfElements()520 void dpx::GenericHeader::CalculateNumberOfElements()
521 {
522 this->numberOfElements = 0xffff;
523 int i = this->ImageElementCount();
524
525 if (i == 0)
526 this->numberOfElements = 0xffff;
527 else
528 this->numberOfElements = U16(i);
529 }
530
531
CalculateOffsets()532 void dpx::Header::CalculateOffsets()
533 {
534 int i;
535
536 for (i = 0; i < MAX_ELEMENTS; i++)
537 {
538 // only write if there is a defined image description
539 if (this->chan[i].descriptor == kUndefinedDescriptor)
540 continue;
541
542
543 }
544 }
545
546
ComponentDataSize(const int element) const547 dpx::DataSize dpx::GenericHeader::ComponentDataSize(const int element) const
548 {
549 if (element < 0 || element >= MAX_ELEMENTS)
550 return kByte;
551
552 dpx::DataSize ret;
553
554 switch (this->chan[element].bitDepth)
555 {
556 case 8:
557 ret = kByte;
558 break;
559 case 10:
560 case 12:
561 case 16:
562 ret = kWord;
563 break;
564 case 32:
565 ret = kFloat;
566 break;
567 case 64:
568 ret = kDouble;
569 break;
570 default:
571 assert(0 && "Unknown bit depth");
572 ret = kDouble;
573 break;
574 }
575
576 return ret;
577 }
578
579
ComponentByteCount(const int element) const580 int dpx::GenericHeader::ComponentByteCount(const int element) const
581 {
582 if (element < 0 || element >= MAX_ELEMENTS)
583 return kByte;
584
585 int ret;
586
587 switch (this->chan[element].bitDepth)
588 {
589 case 8:
590 ret = sizeof(U8);
591 break;
592 case 10:
593 case 12:
594 case 16:
595 ret = sizeof(U16);
596 break;
597 case 32:
598 ret = sizeof(R32);
599 break;
600 case 64:
601 ret = sizeof(R64);
602 break;
603 default:
604 assert(0 && "Unknown bit depth");
605 ret = sizeof(R64);
606 break;
607 }
608
609 return ret;
610 }
611
612
DataSizeByteCount(const DataSize ds)613 int dpx::GenericHeader::DataSizeByteCount(const DataSize ds)
614 {
615
616 int ret;
617
618 switch (ds)
619 {
620 case kByte:
621 ret = sizeof(U8);
622 break;
623 case kWord:
624 ret = sizeof(U16);
625 break;
626 case kInt:
627 ret = sizeof(U32);
628 break;
629 case kFloat:
630 ret = sizeof(R32);
631 break;
632 case kDouble:
633 ret = sizeof(R64);
634 break;
635 default:
636 assert(0 && "Unknown data size");
637 ret = sizeof(R64);
638 break;
639 }
640
641 return ret;
642 }
643
644
FilmEdgeCode(char * edge) const645 void dpx::IndustryHeader::FilmEdgeCode(char *edge) const
646 {
647 edge[0] = this->filmManufacturingIdCode[0];
648 edge[1] = this->filmManufacturingIdCode[1];
649 edge[2] = this->filmType[0];
650 edge[3] = this->filmType[1];
651 edge[4] = this->perfsOffset[0];
652 edge[5] = this->perfsOffset[1];
653 edge[6] = this->prefix[0];
654 edge[7] = this->prefix[1];
655 edge[8] = this->prefix[2];
656 edge[9] = this->prefix[3];
657 edge[10] = this->prefix[4];
658 edge[11] = this->prefix[5];
659 edge[12] = this->count[0];
660 edge[13] = this->count[1];
661 edge[14] = this->count[2];
662 edge[15] = this->count[3];
663 edge[16] = '\0';
664 }
665
666
SetFileEdgeCode(const char * edge)667 void dpx::IndustryHeader::SetFileEdgeCode(const char *edge)
668 {
669 this->filmManufacturingIdCode[0] = edge[0];
670 this->filmManufacturingIdCode[1] = edge[1];
671 this->filmType[0] = edge[2];
672 this->filmType[1] = edge[3];
673 this->perfsOffset[0] = edge[4];
674 this->perfsOffset[1] = edge[5];
675 this->prefix[0] = edge[6];
676 this->prefix[1] = edge[7];
677 this->prefix[2] = edge[8];
678 this->prefix[3] = edge[9];
679 this->prefix[4] = edge[10];
680 this->prefix[5] = edge[11];
681 this->count[0] = edge[12];
682 this->count[1] = edge[13];
683 this->count[2] = edge[14];
684 this->count[3] = edge[15];
685 }
686
687
TimeCode(char * str) const688 void dpx::IndustryHeader::TimeCode(char *str) const
689 {
690 U32 tc = this->timeCode;
691 ::sprintf(str, "%c%c:%c%c:%c%c:%c%c",
692 Hex((tc & 0xf0000000) >> 28), Hex((tc & 0xf000000) >> 24),
693 Hex((tc & 0xf00000) >> 20), Hex((tc & 0xf0000) >> 16),
694 Hex((tc & 0xf000) >> 12), Hex((tc & 0xf00) >> 8),
695 Hex((tc & 0xf0) >> 4), Hex(tc & 0xf));
696 }
697
698
UserBits(char * str) const699 void dpx::IndustryHeader::UserBits(char *str) const
700 {
701 U32 ub = this->userBits;
702 ::sprintf(str, "%c%c:%c%c:%c%c:%c%c",
703 Hex((ub & 0xf0000000) >> 28), Hex((ub & 0xf000000) >> 24),
704 Hex((ub & 0xf00000) >> 20), Hex((ub & 0xf0000) >> 16),
705 Hex((ub & 0xf000) >> 12), Hex((ub & 0xf00) >> 8),
706 Hex((ub & 0xf0) >> 4), Hex(ub & 0xf));
707 }
708
709
TCFromString(const char * str) const710 dpx::U32 dpx::IndustryHeader::TCFromString(const char *str) const
711 {
712 // make sure the string is the correct length
713 if (::strlen(str) != 11)
714 return U32(~0);
715
716 U32 tc = 0;
717 int i, idx = 0;
718 U8 ch;
719 U32 value, mask;
720
721 for (i = 0; i < 8; i++, idx++)
722 {
723 // determine string index skipping :
724 idx += idx % 3 == 2 ? 1 : 0;
725 ch = str[idx];
726
727 // error check
728 if (ch < '0' || ch > '9')
729 return 0xffffffff;
730
731 value = U32(ch - '0') << (28 - (i*4));
732 mask = 0xf << (28 - (i*4));
733
734 // mask in new value
735 tc = (tc & ~mask) | (value & mask);
736 }
737
738 return tc;
739 }
740
741
SetTimeCode(const char * str)742 void dpx::IndustryHeader::SetTimeCode(const char *str)
743 {
744 U32 tc = this->TCFromString(str);
745 if (tc != 0xffffffff)
746 this->timeCode = tc;
747 }
748
749
SetUserBits(const char * str)750 void dpx::IndustryHeader::SetUserBits(const char *str)
751 {
752 U32 ub = this->TCFromString(str);
753 if (ub != 0xffffffff)
754 this->userBits = ub;
755 }
756
757
758
EmptyString(char * str,const int len)759 static void EmptyString(char *str, const int len)
760 {
761 for (int i = 0; i < len; i++)
762 str[i] = '\0';
763 }
764
765
SetCreationTimeDate(const long sec)766 void dpx::GenericHeader::SetCreationTimeDate(const long sec)
767 {
768 char str[32];
769
770 #ifdef _WIN32
771 _tzset();
772 #endif
773
774 const time_t t = time_t(sec);
775 struct tm localtm;
776 OIIO::Sysutil::get_local_time(&t, &localtm);
777 ::strftime(str, 32, "%Y:%m:%d:%H:%M:%S%Z", &localtm);
778 OIIO::Strutil::safe_strcpy(this->creationTimeDate, str, 24);
779 }
780
781
SetSourceTimeDate(const long sec)782 void dpx::GenericHeader::SetSourceTimeDate(const long sec)
783 {
784 char str[32];
785
786 #ifdef _WIN32
787 _tzset();
788 #endif
789
790 const time_t t = time_t(sec);
791 struct tm localtm;
792 OIIO::Sysutil::get_local_time(&t, &localtm);
793 ::strftime(str, 32, "%Y:%m:%d:%H:%M:%S%Z", &localtm);
794 OIIO::Strutil::safe_strcpy(this->sourceTimeDate, str, 24);
795 }
796
797
798
DatumSwap(const int element) const799 bool dpx::Header::DatumSwap(const int element) const
800 {
801 if (this->datumSwap)
802 {
803 if (this->ImageDescriptor(element) == kRGB || this->ImageDescriptor(element) == kCbYCrY)
804 return true;
805 }
806 return false;
807 }
808
809
SetDatumSwap(const bool swap)810 void dpx::Header::SetDatumSwap(const bool swap)
811 {
812 this->datumSwap = swap;
813 }
814
815 // Height()
816 // this function determines the height of the image taking in account for the image orientation
817 // if an image is 1920x1080 but is oriented top to bottom, left to right then the height stored
818 // in the image is 1920 rather than 1080
819
Height() const820 dpx::U32 dpx::Header::Height() const
821 {
822 U32 h;
823
824 switch (this->ImageOrientation())
825 {
826 case kTopToBottomLeftToRight:
827 case kTopToBottomRightToLeft:
828 case kBottomToTopLeftToRight:
829 case kBottomToTopRightToLeft:
830 h = this->PixelsPerLine();
831 break;
832 default:
833 h = this->LinesPerElement();
834 break;
835 }
836
837 return h;
838 }
839
840
841 // Width()
842 // this function determines the width of the image taking in account for the image orientation
843 // if an image is 1920x1080 but is oriented top to bottom, left to right then the width stored
844 // in the image is 1920 rather than 1080
845
Width() const846 dpx::U32 dpx::Header::Width() const
847 {
848 U32 w;
849
850 switch (this->ImageOrientation())
851 {
852 case kTopToBottomLeftToRight:
853 case kTopToBottomRightToLeft:
854 case kBottomToTopLeftToRight:
855 case kBottomToTopRightToLeft:
856 w = this->LinesPerElement();
857 break;
858 default:
859 w = this->PixelsPerLine();
860 break;
861 }
862
863 return w;
864 }
865
866
867
868