bool DPXInput::open (const std::string &name, ImageSpec &newspec) { // open the image m_stream = new InStream(); if (! m_stream->Open(name.c_str())) { error ("Could not open file \"%s\"", name.c_str()); return false; } m_dpx.SetInStream(m_stream); if (! m_dpx.ReadHeader()) { error ("Could not read header"); return false; } bool ok = seek_subimage (0, 0, newspec); newspec = spec (); return ok; }
bool DPXInput::read_native_scanline (int y, int z, void *data) { dpx::Block block(0, y, m_dpx.header.Width () - 1, y); if (m_wantRaw) { // fast path - just read the scanline in if (!m_dpx.ReadBlock (m_subimage, (unsigned char *)data, block)) return false; } else { // read the scanline and convert to RGB void *ptr = m_dataPtr == NULL ? data : (void *)m_dataPtr; if (!m_dpx.ReadBlock (m_subimage, (unsigned char *)ptr, block)) return false; if (!dpx::ConvertToRGB (m_dpx.header, m_subimage, ptr, data, block)) return false; } return true; }
bool DPXInput::read_native_scanline (int y, int z, void *data) { dpx::Block block(0, y, m_dpx.header.Width () - 1, y); if (m_wantRaw) { // fast path - just read the scanline in if (!m_dpx.ReadBlock (data, m_dpx.header.ComponentDataSize (m_subimage), block, m_dpx.header.ImageDescriptor (m_subimage))) return false; } else { // read the scanline and convert to RGB void *ptr = m_dataPtr == NULL ? data : (void *)m_dataPtr; if (!m_dpx.ReadBlock (ptr, m_dpx.header.ComponentDataSize (m_subimage), block, m_dpx.header.ImageDescriptor (m_subimage))) return false; if (!dpx::ConvertToRGB (m_dpx.header, m_subimage, ptr, data, block)) return false; } return true; }
bool DPXInput::seek_subimage (int subimage, int miplevel, ImageSpec &newspec) { if (miplevel != 0) return false; if (subimage < 0 || subimage >= m_dpx.header.ImageElementCount ()) return false; m_subimage = subimage; // check if the client asked us for raw data m_wantRaw = newspec.get_int_attribute ("dpx:RawData", 0) != 0; // create imagespec TypeDesc typedesc; switch (m_dpx.header.ComponentDataSize(subimage)) { case dpx::kByte: typedesc = m_dpx.header.DataSign (subimage) ? TypeDesc::INT8 : TypeDesc::UINT8; break; case dpx::kWord: typedesc = m_dpx.header.DataSign (subimage) ? TypeDesc::INT16 : TypeDesc::UINT16; break; case dpx::kInt: typedesc = m_dpx.header.DataSign (subimage) ? TypeDesc::INT32 : TypeDesc::UINT32; break; case dpx::kFloat: typedesc = TypeDesc::FLOAT; break; case dpx::kDouble: typedesc = TypeDesc::DOUBLE; break; default: error ("Invalid component data size"); return false; } m_spec = ImageSpec (m_dpx.header.Width(), m_dpx.header.Height(), m_dpx.header.ImageElementComponentCount(subimage), typedesc); // fill channel names m_spec.channelnames.clear (); switch (m_dpx.header.ImageDescriptor(subimage)) { /*case dpx::kUserDefinedDescriptor: break;*/ case dpx::kRed: m_spec.channelnames.push_back("R"); break; case dpx::kGreen: m_spec.channelnames.push_back("G"); break; case dpx::kBlue: m_spec.channelnames.push_back("B"); break; case dpx::kAlpha: m_spec.channelnames.push_back("A"); m_spec.alpha_channel = 0; break; case dpx::kLuma: // FIXME: do we treat this as intensity or do we use Y' as per // convention to differentiate it from linear luminance? m_spec.channelnames.push_back("Y'"); break; case dpx::kDepth: m_spec.channelnames.push_back("Z"); m_spec.z_channel = 0; break; /*case dpx::kCompositeVideo: break;*/ case dpx::kRGB: case dpx::kRGBA: case dpx::kABGR: // colour converter will swap the bytes for us m_spec.default_channel_names (); break; case dpx::kCbYCrY: if (m_wantRaw) { m_spec.channelnames.push_back("CbCr"); m_spec.channelnames.push_back("Y"); } else { m_spec.nchannels = 3; m_spec.default_channel_names (); } break; case dpx::kCbYACrYA: if (m_wantRaw) { m_spec.channelnames.push_back("CbCr"); m_spec.channelnames.push_back("Y"); m_spec.channelnames.push_back("A"); m_spec.alpha_channel = 2; } else { m_spec.nchannels = 4; m_spec.default_channel_names (); } break; case dpx::kCbYCr: if (m_wantRaw) { m_spec.channelnames.push_back("Cb"); m_spec.channelnames.push_back("Y"); m_spec.channelnames.push_back("Cr"); } else m_spec.default_channel_names (); break; case dpx::kCbYCrA: if (m_wantRaw) { m_spec.channelnames.push_back("Cb"); m_spec.channelnames.push_back("Y"); m_spec.channelnames.push_back("Cr"); m_spec.channelnames.push_back("A"); m_spec.alpha_channel = 3; } else { m_spec.default_channel_names (); } break; default: { for (int i = 0; i < m_dpx.header.ImageElementComponentCount(subimage); i++) { std::string ch = "channel" + i; m_spec.channelnames.push_back(ch); } } } // bits per pixel m_spec.attribute ("oiio:BitsPerSample", m_dpx.header.BitDepth(subimage)); // image orientation - see appendix B.2 of the OIIO documentation int orientation; switch (m_dpx.header.ImageOrientation ()) { case dpx::kLeftToRightTopToBottom: orientation = 1; break; case dpx::kRightToLeftTopToBottom: orientation = 2; break; case dpx::kLeftToRightBottomToTop: orientation = 4; break; case dpx::kRightToLeftBottomToTop: orientation = 3; break; case dpx::kTopToBottomLeftToRight: orientation = 5; break; case dpx::kTopToBottomRightToLeft: orientation = 6; break; case dpx::kBottomToTopLeftToRight: orientation = 8; break; case dpx::kBottomToTopRightToLeft: orientation = 7; break; default: orientation = 0; break; } m_spec.attribute ("Orientation", orientation); // image linearity switch (m_dpx.header.Transfer (subimage)) { case dpx::kLinear: m_spec.attribute ("oiio:ColorSpace", "Linear"); break; case dpx::kLogarithmic: m_spec.attribute ("oiio:ColorSpace", "KodakLog"); break; case dpx::kITUR709: m_spec.attribute ("oiio:ColorSpace", "Rec709"); break; case dpx::kUserDefined: if (! isnan (m_dpx.header.Gamma ()) && m_dpx.header.Gamma () != 0) { m_spec.attribute ("oiio:ColorSpace", "GammaCorrected"); m_spec.attribute ("oiio:Gamma", (float) m_dpx.header.Gamma ()); break; } // intentional fall-through /*case dpx::kPrintingDensity: case dpx::kUnspecifiedVideo: case dpx::kSMPTE274M: case dpx::kITUR601: case dpx::kITUR602: case dpx::kNTSCCompositeVideo: case dpx::kPALCompositeVideo: case dpx::kZLinear: case dpx::kZHomogeneous: case dpx::kUndefinedCharacteristic:*/ default: break; } m_spec.attribute ("dpx:Transfer", get_characteristic_string (m_dpx.header.Transfer (subimage))); // colorimetric characteristic m_spec.attribute ("dpx:Colorimetric", get_characteristic_string (m_dpx.header.Colorimetric (subimage))); // general metadata // some non-compliant writers will dump a field filled with 0xFF rather // than a NULL string termination on the first character, so take that // into account, too if (m_dpx.header.copyright[0] && m_dpx.header.copyright[0] != (char)0xFF) m_spec.attribute ("Copyright", m_dpx.header.copyright); if (m_dpx.header.creator[0] && m_dpx.header.creator[0] != (char)0xFF) m_spec.attribute ("Software", m_dpx.header.creator); if (m_dpx.header.project[0] && m_dpx.header.project[0] != (char)0xFF) m_spec.attribute ("DocumentName", m_dpx.header.project); if (m_dpx.header.creationTimeDate[0]) { // libdpx's date/time format is pretty close to OIIO's (libdpx uses // %Y:%m:%d:%H:%M:%S%Z) char date[24]; strcpy(date, m_dpx.header.creationTimeDate); date[10] = ' '; date[19] = 0; m_spec.attribute ("DateTime", date); } if (m_dpx.header.ImageEncoding (subimage) == dpx::kRLE) m_spec.attribute ("compression", "rle"); char buf[32 + 1]; m_dpx.header.Description (subimage, buf); if (buf[0] && buf[0] != -1) m_spec.attribute ("ImageDescription", buf); m_spec.attribute ("PixelAspectRatio", m_dpx.header.AspectRatio(0) / (float)m_dpx.header.AspectRatio(1)); // DPX-specific metadata m_spec.attribute ("dpx:ImageDescriptor", get_descriptor_string (m_dpx.header.ImageDescriptor (subimage))); // save some typing by using macros // "internal" macros #define DPX_SET_ATTRIB_S(x, n, s) m_spec.attribute (s, \ m_dpx.header.x (n)) #define DPX_SET_ATTRIB(x, n) DPX_SET_ATTRIB_S(x, n, "dpx:" #x) // set without checking for bogus attributes #define DPX_SET_ATTRIB_N(x) DPX_SET_ATTRIB(x, subimage) // set with checking for bogus attributes #define DPX_SET_ATTRIB_BYTE(x) if (m_dpx.header.x () != 0xFF) \ DPX_SET_ATTRIB(x, ) #define DPX_SET_ATTRIB_INT_N(x) if (m_dpx.header.x (subimage) != 0xFFFFFFFF) \ DPX_SET_ATTRIB(x, subimage) #define DPX_SET_ATTRIB_INT(x) if (m_dpx.header.x () != 0xFFFFFFFF) \ DPX_SET_ATTRIB(x, ) #define DPX_SET_ATTRIB_FLOAT_N(x) if (! isnan(m_dpx.header.x (subimage))) \ DPX_SET_ATTRIB(x, subimage) #define DPX_SET_ATTRIB_FLOAT(x) if (! isnan(m_dpx.header.x ())) \ DPX_SET_ATTRIB(x, ) // see comment above Copyright, Software and DocumentName #define DPX_SET_ATTRIB_STR(X, x) if (m_dpx.header.x[0] \ && m_dpx.header.x[0] != -1) \ m_spec.attribute ("dpx:" #X, \ m_dpx.header.x) DPX_SET_ATTRIB_INT(EncryptKey); DPX_SET_ATTRIB_INT(DittoKey); DPX_SET_ATTRIB_INT_N(LowData); DPX_SET_ATTRIB_FLOAT_N(LowQuantity); DPX_SET_ATTRIB_INT_N(HighData); DPX_SET_ATTRIB_FLOAT_N(HighQuantity); DPX_SET_ATTRIB_FLOAT(XScannedSize); DPX_SET_ATTRIB_FLOAT(YScannedSize); DPX_SET_ATTRIB_INT(FramePosition); DPX_SET_ATTRIB_INT(SequenceLength); DPX_SET_ATTRIB_INT(HeldCount); DPX_SET_ATTRIB_FLOAT(FrameRate); DPX_SET_ATTRIB_FLOAT(ShutterAngle); DPX_SET_ATTRIB_STR(Version, version); DPX_SET_ATTRIB_STR(Format, format); DPX_SET_ATTRIB_STR(FrameId, frameId); DPX_SET_ATTRIB_STR(SlateInfo, slateInfo); DPX_SET_ATTRIB_STR(SourceImageFileName, sourceImageFileName); DPX_SET_ATTRIB_STR(InputDevice, inputDevice); DPX_SET_ATTRIB_STR(InputDeviceSerialNumber, inputDeviceSerialNumber); DPX_SET_ATTRIB_BYTE(Interlace); DPX_SET_ATTRIB_BYTE(FieldNumber); DPX_SET_ATTRIB_FLOAT(HorizontalSampleRate); DPX_SET_ATTRIB_FLOAT(VerticalSampleRate); DPX_SET_ATTRIB_FLOAT(TemporalFrameRate); DPX_SET_ATTRIB_FLOAT(TimeOffset); DPX_SET_ATTRIB_FLOAT(BlackLevel); DPX_SET_ATTRIB_FLOAT(BlackGain); DPX_SET_ATTRIB_FLOAT(BreakPoint); DPX_SET_ATTRIB_FLOAT(WhiteLevel); DPX_SET_ATTRIB_FLOAT(IntegrationTimes); #undef DPX_SET_ATTRIB_STR #undef DPX_SET_ATTRIB_FLOAT #undef DPX_SET_ATTRIB_FLOAT_N #undef DPX_SET_ATTRIB_INT #undef DPX_SET_ATTRIB_INT_N #undef DPX_SET_ATTRIB_N #undef DPX_SET_ATTRIB #undef DPX_SET_ATTRIB_S std::string tmpstr; switch (m_dpx.header.ImagePacking (subimage)) { case dpx::kPacked: tmpstr = "Packed"; break; case dpx::kFilledMethodA: tmpstr = "Filled, method A"; break; case dpx::kFilledMethodB: tmpstr = "Filled, method B"; break; } if (!tmpstr.empty ()) m_spec.attribute ("dpx:Packing", tmpstr); if (m_dpx.header.timeCode != 0xFFFFFFFF) m_spec.attribute ("dpx:TimeCode", m_dpx.header.timeCode); if (m_dpx.header.userBits != 0xFFFFFFFF) m_spec.attribute ("dpx:UserBits", m_dpx.header.userBits); if (m_dpx.header.sourceTimeDate[0]) { // libdpx's date/time format is pretty close to OIIO's (libdpx uses // %Y:%m:%d:%H:%M:%S%Z) char date[24]; strcpy(date, m_dpx.header.sourceTimeDate); date[10] = ' '; date[19] = 0; m_spec.attribute ("dpx:SourceDateTime", date); } m_dpx.header.FilmEdgeCode(buf); if (buf[0]) m_spec.attribute ("dpx:FilmEdgeCode", buf); tmpstr.clear (); switch (m_dpx.header.Signal ()) { case dpx::kUndefined: tmpstr = "Undefined"; break; case dpx::kNTSC: tmpstr = "NTSC"; break; case dpx::kPAL: tmpstr = "PAL"; break; case dpx::kPAL_M: tmpstr = "PAL-M"; break; case dpx::kSECAM: tmpstr = "SECAM"; break; case dpx::k525LineInterlace43AR: tmpstr = "YCbCr ITU-R 601-5 525i, 4:3"; break; case dpx::k625LineInterlace43AR: tmpstr = "YCbCr ITU-R 601-5 625i, 4:3"; break; case dpx::k525LineInterlace169AR: tmpstr = "YCbCr ITU-R 601-5 525i, 16:9"; break; case dpx::k625LineInterlace169AR: tmpstr = "YCbCr ITU-R 601-5 625i, 16:9"; break; case dpx::k1050LineInterlace169AR: tmpstr = "YCbCr 1050i, 16:9"; break; case dpx::k1125LineInterlace169AR_274: tmpstr = "YCbCr 1125i, 16:9 (SMPTE 274M)"; break; case dpx::k1250LineInterlace169AR: tmpstr = "YCbCr 1250i, 16:9"; break; case dpx::k1125LineInterlace169AR_240: tmpstr = "YCbCr 1125i, 16:9 (SMPTE 240M)"; break; case dpx::k525LineProgressive169AR: tmpstr = "YCbCr 525p, 16:9"; break; case dpx::k625LineProgressive169AR: tmpstr = "YCbCr 625p, 16:9"; break; case dpx::k750LineProgressive169AR: tmpstr = "YCbCr 750p, 16:9 (SMPTE 296M)"; break; case dpx::k1125LineProgressive169AR: tmpstr = "YCbCr 1125p, 16:9 (SMPTE 274M)"; break; case 0xFF: // don't set the attribute at all break; default: tmpstr = Strutil::format ("Undefined %d", (int)m_dpx.header.Signal ()); break; } if (!tmpstr.empty ()) m_spec.attribute ("dpx:Signal", tmpstr); // read in user data; don't bother if the buffer is already filled (user // data is per-file, not per-element) if (m_userBuf.empty () && m_dpx.header.UserSize () != 0 && m_dpx.header.UserSize () != 0xFFFFFFFF) { m_userBuf.resize (m_dpx.header.UserSize ()); m_dpx.ReadUserData (&m_userBuf[0]); } if (!m_userBuf.empty ()) m_spec.attribute ("dpx:UserData", TypeDesc (TypeDesc::UCHAR, m_dpx.header.UserSize ()), &m_userBuf[0]); dpx::Block block(0, 0, m_dpx.header.Width () - 1, 0); int bufsize = dpx::QueryRGBBufferSize (m_dpx.header, subimage, block); if (bufsize == 0 && !m_wantRaw) { error ("Unable to deliver RGB data from source data"); return false; } else if (!m_wantRaw && bufsize > 0) m_dataPtr = new unsigned char[bufsize]; else // no need to allocate another buffer m_dataPtr = NULL; newspec = m_spec; return true; }