Example #1
0
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;
}
Example #2
0
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;
}
Example #3
0
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;
}
Example #4
0
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;
}