Skip to content

Commit

Permalink
Promoting changes from OpenImageIO upstream:
Browse files Browse the repository at this point in the history
* improved 10->16 bit depth conversion
* added CrCbY<->RGB conversion routines
* fixed erratic handling of > 3 channel image reading
* several smaller bugfixes
  • Loading branch information
ineqvation@gmail.com committed May 27, 2011
1 parent 395146d commit 8e9e70b
Show file tree
Hide file tree
Showing 9 changed files with 174 additions and 45 deletions.
34 changes: 30 additions & 4 deletions libdpx/BaseTypeConverter.h
Expand Up @@ -40,20 +40,36 @@
namespace dpx
{
// convert between all of the DPX base types in a controllable way


// Note: These bit depth promotions (low precision -> high) use
// a combination of bitshift and the 'or' operator in order to
// fully populate the output coding space
//
// For example, when converting 8->16 bits, the 'simple' method
// (shifting 8 bits) maps 255 to 65280. This result is not ideal
// (uint16 'max' of 65535 is preferable). Overall, the best conversion
// is one that approximates the 'true' floating-point scale factor.
// 8->16 : 65535.0 / 255.0. 10->16 : 65535.0 / 1023.0.
// For performance considerations, we choose to emulate this
// floating-poing scaling with pure integer math, using a trick
// where we duplicate portions of the MSB in the LSB.
//
// For bit depth demotions, simple truncation is used.
//

inline void BaseTypeConverter(U8 &src, U8 &dst)
{
dst = src;
}

inline void BaseTypeConverter(U8 &src, U16 &dst)
{
dst = src << 8;
dst = (src << 8) | src;
}

inline void BaseTypeConverter(U8 &src, U32 &dst)
{
dst = src << 24;
dst = (src << 24) | (src << 16) | (src << 8) | src;
}

inline void BaseTypeConverter(U8 &src, R32 &dst)
Expand All @@ -78,7 +94,7 @@ namespace dpx

inline void BaseTypeConverter(U16 &src, U32 &dst)
{
dst = src << 16;
dst = (src << 16) | src;
}

inline void BaseTypeConverter(U16 &src, R32 &dst)
Expand Down Expand Up @@ -166,6 +182,16 @@ namespace dpx
dst = src;
}

inline void BaseTypeConvertU10ToU16(U16 &src, U16 &dst)
{
dst = (src << 6) | (src >> 4);
}

inline void BaseTypeConvertU12ToU16(U16 &src, U16 &dst)
{
dst = (src << 4) | (src >> 8);
}

}

#endif
Expand Down
2 changes: 1 addition & 1 deletion libdpx/DPX.cpp
Expand Up @@ -69,7 +69,7 @@ bool dpx::IdentifyFile(InStream *fp)

bool dpx::IdentifyFile(const void *p)
{
U32 magic = *((U32 *) &p);
U32 magic = *((U32 *) p);
return dpx::Header::ValidMagicCookie(magic);

}
Expand Down
9 changes: 6 additions & 3 deletions libdpx/DPX.h
Expand Up @@ -38,6 +38,7 @@
#define _DPX_H 1

#include <cstdio>
#include <limits>

#include "DPXHeader.h"
#include "DPXStream.h"
Expand Down Expand Up @@ -332,9 +333,11 @@ namespace dpx
* \param project project name (200 characters max)
* \param copyright copyright statement (200 characters max)
* \param encryptKey encryption key
* \param swapEndian whether to write the image header in reverse to native endianness
*/
void SetFileInfo(const char *fileName, const char *creationTimeDate = 0, const char *creator = 0,
const char *project = 0, const char *copyright = 0, const U32 encryptKey = ~0);
const char *project = 0, const char *copyright = 0, const U32 encryptKey = ~0,
const bool swapEndian = false);

/*!
* \brief Set the Width and Height of the images
Expand Down Expand Up @@ -379,8 +382,8 @@ namespace dpx
const Packing packing = kFilledMethodA,
const Encoding encoding = kNone,
const U32 dataSign = 0,
const U32 lowData = ~0, const R32 lowQuantity = ~0,
const U32 highData = ~0, const R32 highQuantity = ~0,
const U32 lowData = ~0, const R32 lowQuantity = std::numeric_limits<float>::quiet_NaN(),
const U32 highData = ~0, const R32 highQuantity = std::numeric_limits<float>::quiet_NaN(),
const U32 eolnPadding = 0, const U32 eoimPadding = 0);

/*!
Expand Down
58 changes: 51 additions & 7 deletions libdpx/DPXHeader.cpp
Expand Up @@ -34,9 +34,11 @@



#include <cassert>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <limits>


#include "DPXHeader.h"
Expand Down Expand Up @@ -113,15 +115,15 @@ void dpx::GenericHeader::Reset()

// Image Orientation
this->xOffset = this->yOffset = 0xffffffff;
this->xCenter = this->yCenter = 0xffffffff;
this->xCenter = this->yCenter = std::numeric_limits<float>::quiet_NaN();
this->xOriginalSize = this->yOriginalSize = 0xffffffff;
EmptyString(this->sourceImageFileName, 100);
EmptyString(this->sourceTimeDate, 24);
EmptyString(this->inputDevice, 32);
EmptyString(this->inputDeviceSerialNumber, 32);
this->border[0] = this->border[1] = this->border[2] = this->border[3] = 0xffff;
this->aspectRatio[0] = this->aspectRatio[1] = 0xffffffff;
this->xScannedSize = this->yScannedSize = 0xffffffff;
this->xScannedSize = this->yScannedSize = std::numeric_limits<float>::quiet_NaN();
EmptyString(this->reserved3, 28);
}

Expand All @@ -142,7 +144,7 @@ void dpx::IndustryHeader::Reset()
EmptyString(this->count, 4);
EmptyString(this->format, 32);
this->framePosition = this->sequenceLength = this->heldCount = 0xffffffff;
this->frameRate = this->shutterAngle = 0xffffffff;
this->frameRate = this->shutterAngle = std::numeric_limits<float>::quiet_NaN();
EmptyString(this->frameId, 32);
EmptyString(this->slateInfo, 200);
EmptyString(this->reserved4, 56);
Expand All @@ -152,10 +154,10 @@ void dpx::IndustryHeader::Reset()
this->interlace = this->fieldNumber = 0xff;
this->videoSignal = kUndefined;
this->zero = 0xff;
this->horizontalSampleRate = this->verticalSampleRate = this->temporalFrameRate = 0xffffffff;
this->timeOffset = this->gamma = 0xffffffff;
this->blackLevel = this->blackGain = 0xffffffff;
this->breakPoint = this->whiteLevel = this->integrationTimes = 0xffffffff;
this->horizontalSampleRate = this->verticalSampleRate = this->temporalFrameRate = std::numeric_limits<float>::quiet_NaN();
this->timeOffset = this->gamma = std::numeric_limits<float>::quiet_NaN();
this->blackLevel = this->blackGain = std::numeric_limits<float>::quiet_NaN();
this->breakPoint = this->whiteLevel = this->integrationTimes = std::numeric_limits<float>::quiet_NaN();
EmptyString(this->reserved5, 76);
}

Expand Down Expand Up @@ -223,10 +225,17 @@ bool dpx::Header::Check()

bool dpx::Header::Write(OutStream *io)
{
// validate and byte swap, if necessary
if (!this->Validate())
return false;

// write the header to the file
size_t r = sizeof(GenericHeader) + sizeof(IndustryHeader);
if (io->Write(&(this->magicNumber), r) != r)
return false;

// swap back - data is in file, now we need it native again
this->Validate();
return true;
}

Expand All @@ -240,23 +249,35 @@ bool dpx::Header::WriteOffsetData(OutStream *io)
const long FIELD2 = 4; // offset to image in header
if (io->Seek(FIELD2, OutStream::kStart) == false)
return false;
if (this->RequiresByteSwap())
SwapBytes(this->imageOffset);
if (io->Write(&this->imageOffset, sizeof(U32)) == false)
return false;
if (this->RequiresByteSwap())
SwapBytes(this->imageOffset);


// write the file size
const long FIELD4 = 16; // offset to total image file size in header
if (io->Seek(FIELD4, OutStream::kStart) == false)
return false;
if (this->RequiresByteSwap())
SwapBytes(this->fileSize);
if (io->Write(&this->fileSize, sizeof(U32)) == false)
return false;
if (this->RequiresByteSwap())
SwapBytes(this->fileSize);

// write the number of elements
const long FIELD19 = 770; // offset to number of image elements in header
if (io->Seek(FIELD19, OutStream::kStart) == false)
return false;
if (this->RequiresByteSwap())
SwapBytes(this->numberOfElements);
if (io->Write(&this->numberOfElements, sizeof(U16)) == false)
return false;
if (this->RequiresByteSwap())
SwapBytes(this->numberOfElements);

// write the image offsets
const long FIELD21_12 = 808; // offset to image offset in image element data structure
Expand All @@ -274,8 +295,12 @@ bool dpx::Header::WriteOffsetData(OutStream *io)
return false;

// write
if (this->RequiresByteSwap())
SwapBytes(this->chan[i].dataOffset);
if (io->Write(&this->chan[i].dataOffset, sizeof(U32)) == false)
return false;
if (this->RequiresByteSwap())
SwapBytes(this->chan[i].dataOffset);

}

Expand Down Expand Up @@ -472,6 +497,12 @@ int dpx::GenericHeader::ImageElementComponentCount(const int element) const

int dpx::GenericHeader::ImageElementCount() const
{
if(this->numberOfElements>0 && this->numberOfElements<=MAX_ELEMENTS)
return this->numberOfElements;

// If the image header does not list a valid number of elements,
// count how many defined image descriptors we have...

int i = 0;

while (i < MAX_ELEMENTS )
Expand All @@ -487,6 +518,7 @@ int dpx::GenericHeader::ImageElementCount() const

void dpx::GenericHeader::CalculateNumberOfElements()
{
this->numberOfElements = 0xffff;
int i = this->ImageElementCount();

if (i == 0)
Expand Down Expand Up @@ -534,6 +566,10 @@ dpx::DataSize dpx::GenericHeader::ComponentDataSize(const int element) const
case 64:
ret = kDouble;
break;
default:
assert(0 && "Unknown bit depth");
ret = kDouble;
break;
}

return ret;
Expand Down Expand Up @@ -563,6 +599,10 @@ int dpx::GenericHeader::ComponentByteCount(const int element) const
case 64:
ret = sizeof(R64);
break;
default:
assert(0 && "Unknown bit depth");
ret = sizeof(R64);
break;
}

return ret;
Expand Down Expand Up @@ -591,6 +631,10 @@ int dpx::GenericHeader::DataSizeByteCount(const DataSize ds)
case kDouble:
ret = sizeof(R64);
break;
default:
assert(0 && "Unknown data size");
ret = sizeof(R64);
break;
}

return ret;
Expand Down
2 changes: 1 addition & 1 deletion libdpx/InStream.cpp
Expand Up @@ -79,7 +79,7 @@ void InStream::Rewind()

bool InStream::Seek(long offset, Origin origin)
{
int o;
int o = 0;
switch (origin)
{
case kCurrent:
Expand Down
2 changes: 1 addition & 1 deletion libdpx/OutStream.cpp
Expand Up @@ -79,7 +79,7 @@ size_t OutStream::Write(void *buf, const size_t size)

bool OutStream::Seek(long offset, Origin origin)
{
int o;
int o = 0;
switch (origin)
{
case kCurrent:
Expand Down

0 comments on commit 8e9e70b

Please sign in to comment.