Пример #1
0
bool
DPXOutput::open (const std::string &name, const ImageSpec &userspec,
                 OpenMode mode)
{
    close ();  // Close any already-opened file

    if (mode != Create) {
        error ("%s does not support subimages or MIP levels", format_name());
        return false;
    }

    m_spec = userspec;  // Stash the spec

    // open the image
    m_stream = new OutStream();
    if (! m_stream->Open(name.c_str ())) {
        error ("Could not open file \"%s\"", name.c_str ());
        return false;
    }

    // Check for things this format doesn't support
    if (m_spec.width < 1 || m_spec.height < 1) {
        error ("Image resolution must be at least 1x1, you asked for %d x %d",
                       m_spec.width, m_spec.height);
                       return false;
    }

    if (m_spec.depth < 1)
        m_spec.depth = 1;
    else if (m_spec.depth > 1) {
        error ("DPX does not support volume images (depth > 1)");
        return false;
    }

    if (m_spec.format == TypeDesc::UINT8
        || m_spec.format == TypeDesc::INT8)
        m_datasize = dpx::kByte;
    else if (m_spec.format == TypeDesc::UINT16
        || m_spec.format == TypeDesc::INT16)
        m_datasize = dpx::kWord;
    else if (m_spec.format == TypeDesc::FLOAT
        || m_spec.format == TypeDesc::HALF) {
        m_spec.format = TypeDesc::FLOAT;
        m_datasize = dpx::kFloat;
    } else if (m_spec.format == TypeDesc::DOUBLE)
        m_datasize = dpx::kDouble;
    else {
        // use 16-bit unsigned integers as a failsafe
        m_spec.format = TypeDesc::UINT16;
        m_datasize = dpx::kWord;
    }

    // check if the client is giving us raw data to write
    m_wantRaw = m_spec.get_int_attribute ("dpx:RawData", 0) != 0;
    
    // check if the client wants endianness reverse to native
    // assume big endian per Jeremy's request, unless little endian is
    // explicitly specified
    std::string tmpstr = m_spec.get_string_attribute ("oiio:Endian", littleendian() ? "little" : "big");
    m_wantSwap = (littleendian() != Strutil::iequals (tmpstr, "little"));

    m_dpx.SetOutStream (m_stream);

    // start out the file
    m_dpx.Start ();

    // some metadata
    std::string project = m_spec.get_string_attribute ("DocumentName", "");
    std::string copyright = m_spec.get_string_attribute ("Copyright", "");
    tmpstr = m_spec.get_string_attribute ("DateTime", "");
    if (tmpstr.size () >= 19) {
        // libdpx's date/time format is pretty close to OIIO's (libdpx uses
        // %Y:%m:%d:%H:%M:%S%Z)
        // NOTE: the following code relies on the DateTime attribute being properly
        // formatted!
        // assume UTC for simplicity's sake, fix it if someone complains
        tmpstr[10] = ':';
        tmpstr.replace (19, -1, "Z");
    }
    m_dpx.SetFileInfo (name.c_str (),                       // filename
        tmpstr.c_str (),                                    // cr. date
        OIIO_INTRO_STRING,                                  // creator
        project.empty () ? NULL : project.c_str (),         // project
        copyright.empty () ? NULL : copyright.c_str (),     // copyright
        m_spec.get_int_attribute ("dpx:EncryptKey", ~0),    // encryption key
        m_wantSwap);

    // image info
    m_dpx.SetImageInfo (m_spec.width, m_spec.height);

    // determine descriptor
    m_desc = get_descriptor_from_string
        (m_spec.get_string_attribute ("dpx:ImageDescriptor", ""));

    // transfer function
    dpx::Characteristic transfer;
    
    std::string colorspace = m_spec.get_string_attribute ("oiio:ColorSpace", "");
    if (Strutil::iequals (colorspace, "Linear"))  transfer = dpx::kLinear;
    else if (Strutil::iequals (colorspace, "GammaCorrected")) transfer = dpx::kUserDefined;
    else if (Strutil::iequals (colorspace, "Rec709")) transfer = dpx::kITUR709;
    else if (Strutil::iequals (colorspace, "KodakLog")) transfer = dpx::kLogarithmic;
    else {
        std::string dpxtransfer = m_spec.get_string_attribute ("dpx:Transfer", "");
        transfer = get_characteristic_from_string (dpxtransfer);
    }
    
    // colorimetric
    m_cmetr = get_characteristic_from_string
        (m_spec.get_string_attribute ("dpx:Colorimetric", "User defined"));

    // select packing method
    dpx::Packing packing;
    tmpstr = m_spec.get_string_attribute ("dpx:Packing", "Filled, method A");
    if (Strutil::iequals (tmpstr, "Packed"))
        packing = dpx::kPacked;
    else if (Strutil::iequals (tmpstr, "Filled, method B"))
        packing = dpx::kFilledMethodB;
    else
        packing = dpx::kFilledMethodA;

    // calculate target bit depth
    int bitDepth = m_spec.format.size () * 8;
    if (m_spec.format == TypeDesc::UINT16) {
        bitDepth = m_spec.get_int_attribute ("oiio:BitsPerSample", 16);
        if (bitDepth != 10 && bitDepth != 12 && bitDepth != 16) {
            error ("Unsupported bit depth %d", bitDepth);
            return false;
        }
    }
    m_dpx.header.SetBitDepth (0, bitDepth);

    // Bug workaround: libDPX doesn't appear to correctly support
    // "filled method A" for 12 bit data.  Does anybody care what
    // packing/filling we use?  Punt and just use "packed".
    if (bitDepth == 12)
        packing = dpx::kPacked;
    
    // see if we'll need to convert or not
    if (m_desc == dpx::kRGB || m_desc == dpx::kRGBA) {
        // shortcut for RGB(A) that gets the job done
        m_bytes = m_spec.scanline_bytes ();
        m_wantRaw = true;
    } else {
        m_bytes = dpx::QueryNativeBufferSize (m_desc, m_datasize, m_spec.width, 1);
        if (m_bytes == 0 && !m_wantRaw) {
            error ("Unable to deliver native format data from source data");
            return false;
        } else if (m_bytes < 0) {
            // no need to allocate another buffer
            if (!m_wantRaw)
                m_bytes = m_spec.scanline_bytes ();
            else
                m_bytes = -m_bytes;
        }
    }

    if (m_bytes < 0)
        m_bytes = -m_bytes;

    m_dpx.SetElement (0, m_desc, bitDepth, transfer, m_cmetr,
        packing, dpx::kNone, (m_spec.format == TypeDesc::INT8
            || m_spec.format == TypeDesc::INT16) ? 1 : 0,
        m_spec.get_int_attribute ("dpx:LowData", 0xFFFFFFFF),
        m_spec.get_float_attribute ("dpx:LowQuantity", std::numeric_limits<float>::quiet_NaN()),
        m_spec.get_int_attribute ("dpx:HighData", 0xFFFFFFFF),
        m_spec.get_float_attribute ("dpx:HighQuantity", std::numeric_limits<float>::quiet_NaN()),
        m_spec.get_int_attribute ("dpx:EndOfLinePadding", 0),
        m_spec.get_int_attribute ("dpx:EndOfImagePadding", 0));

    m_dpx.header.SetXScannedSize (m_spec.get_float_attribute
        ("dpx:XScannedSize", std::numeric_limits<float>::quiet_NaN()));
    m_dpx.header.SetYScannedSize (m_spec.get_float_attribute
        ("dpx:YScannedSize", std::numeric_limits<float>::quiet_NaN()));
    m_dpx.header.SetFramePosition (m_spec.get_int_attribute
        ("dpx:FramePosition", 0xFFFFFFFF));
    m_dpx.header.SetSequenceLength (m_spec.get_int_attribute
        ("dpx:SequenceLength", 0xFFFFFFFF));
    m_dpx.header.SetHeldCount (m_spec.get_int_attribute
        ("dpx:HeldCount", 0xFFFFFFFF));
    m_dpx.header.SetFrameRate (m_spec.get_float_attribute
        ("dpx:FrameRate", std::numeric_limits<float>::quiet_NaN()));
    m_dpx.header.SetShutterAngle (m_spec.get_float_attribute
        ("dpx:ShutterAngle", std::numeric_limits<float>::quiet_NaN()));
    // FIXME: should we write the input version through or always default to 2.0?
    /*tmpstr = m_spec.get_string_attribute ("dpx:Version", "");
    if (tmpstr.size () > 0)
        m_dpx.header.SetVersion (tmpstr.c_str ());*/
    tmpstr = m_spec.get_string_attribute ("dpx:Format", "");
    if (tmpstr.size () > 0)
        m_dpx.header.SetFormat (tmpstr.c_str ());
    tmpstr = m_spec.get_string_attribute ("dpx:FrameId", "");
    if (tmpstr.size () > 0)
        m_dpx.header.SetFrameId (tmpstr.c_str ());
    tmpstr = m_spec.get_string_attribute ("dpx:SlateInfo", "");
    if (tmpstr.size () > 0)
        m_dpx.header.SetSlateInfo (tmpstr.c_str ());
    tmpstr = m_spec.get_string_attribute ("dpx:SourceImageFileName", "");
    if (tmpstr.size () > 0)
        m_dpx.header.SetSourceImageFileName (tmpstr.c_str ());
    tmpstr = m_spec.get_string_attribute ("dpx:InputDevice", "");
    if (tmpstr.size () > 0)
        m_dpx.header.SetInputDevice (tmpstr.c_str ());
    tmpstr = m_spec.get_string_attribute ("dpx:InputDeviceSerialNumber", "");
    if (tmpstr.size () > 0)
        m_dpx.header.SetInputDeviceSerialNumber (tmpstr.c_str ());
    m_dpx.header.SetInterlace (m_spec.get_int_attribute ("dpx:Interlace", 0xFF));
    m_dpx.header.SetFieldNumber (m_spec.get_int_attribute ("dpx:FieldNumber", 0xFF));
    m_dpx.header.SetHorizontalSampleRate (m_spec.get_float_attribute
        ("dpx:HorizontalSampleRate", std::numeric_limits<float>::quiet_NaN()));
    m_dpx.header.SetVerticalSampleRate (m_spec.get_float_attribute
        ("dpx:VerticalSampleRate", std::numeric_limits<float>::quiet_NaN()));
    m_dpx.header.SetTemporalFrameRate (m_spec.get_float_attribute
        ("dpx:TemporalFrameRate", std::numeric_limits<float>::quiet_NaN()));
    m_dpx.header.SetTimeOffset (m_spec.get_float_attribute
        ("dpx:TimeOffset", std::numeric_limits<float>::quiet_NaN()));
    m_dpx.header.SetBlackLevel (m_spec.get_float_attribute
        ("dpx:BlackLevel", std::numeric_limits<float>::quiet_NaN()));
    m_dpx.header.SetBlackGain (m_spec.get_float_attribute
        ("dpx:BlackGain", std::numeric_limits<float>::quiet_NaN()));
    m_dpx.header.SetBreakPoint (m_spec.get_float_attribute
        ("dpx:BreakPoint", std::numeric_limits<float>::quiet_NaN()));
    m_dpx.header.SetWhiteLevel (m_spec.get_float_attribute
        ("dpx:WhiteLevel", std::numeric_limits<float>::quiet_NaN()));
    m_dpx.header.SetIntegrationTimes (m_spec.get_float_attribute
        ("dpx:IntegrationTimes", std::numeric_limits<float>::quiet_NaN()));
    float aspect = m_spec.get_float_attribute ("PixelAspectRatio", 1.0f);
    int aspect_num, aspect_den;
    float_to_rational (aspect, aspect_num, aspect_den);
    m_dpx.header.SetAspectRatio (0, aspect_num);
    m_dpx.header.SetAspectRatio (1, aspect_den);

    tmpstr = m_spec.get_string_attribute ("dpx:TimeCode", "");
    int tmpint = m_spec.get_int_attribute ("dpx:TimeCode", ~0);
    if (tmpstr.size () > 0)
        m_dpx.header.SetTimeCode (tmpstr.c_str ());
    else if (tmpint != ~0)
        m_dpx.header.timeCode = tmpint;
    m_dpx.header.userBits = m_spec.get_int_attribute ("dpx:UserBits", ~0);
    tmpstr = m_spec.get_string_attribute ("dpx:SourceDateTime", "");
    if (tmpstr.size () >= 19) {
        // libdpx's date/time format is pretty close to OIIO's (libdpx uses
        // %Y:%m:%d:%H:%M:%S%Z)
        // NOTE: the following code relies on the DateTime attribute being properly
        // formatted!
        // assume UTC for simplicity's sake, fix it if someone complains
        tmpstr[10] = ':';
        tmpstr.replace (19, -1, "Z");
        m_dpx.header.SetSourceTimeDate (tmpstr.c_str ());
    }
    
    // commit!
    if (!m_dpx.WriteHeader ()) {
        error ("Failed to write DPX header");
        return false;
    }

    // user data
    ImageIOParameter *user = m_spec.find_attribute ("dpx:UserData");
    if (user && user->datasize () > 0) {
        if (user->datasize () > 1024 * 1024) {
            error ("User data block size exceeds 1 MB");
            return false;
        }
        // FIXME: write the missing libdpx code
        /*m_dpx.SetUserData (user->datasize ());
        if (!m_dpx.WriteUserData ((void *)user->data ())) {
            error ("Failed to write user data");
            return false;
        }*/
    }

    // reserve space for the image data buffer
    m_buf.reserve (m_bytes * m_spec.height);

    return true;
}
Пример #2
0
bool
TGAOutput::close ()
{
    if (m_file) {
        // write out the TGA 2.0 data fields

        // FIXME: write out the developer area; according to Larry,
        // it's probably safe to ignore it altogether until someone complains
        // that it's missing :)

        fseek (m_file, 0, SEEK_END);

        // write out the thumbnail, if there is one
        int ofs_thumb = 0;
        {
            unsigned char tw = m_spec.get_int_attribute ("thumbnail_width", 0);
            if (tw) {
                unsigned char th = m_spec.get_int_attribute ("thumbnail_width",
                                                             0);
                if (th) {
                    int tc = m_spec.get_int_attribute ("thumbnail_nchannels",
                                                       0);
                    if (tc == m_spec.nchannels) {
                        ImageIOParameter *p =
                            m_spec.find_attribute ("thumbnail_image");
                        if (p) {
                            ofs_thumb = ftell (m_file);
                            if (bigendian())
                                swap_endian (&ofs_thumb);
                            // dump thumbnail size
                            fwrite (&tw, 1, 1, m_file);
                            fwrite (&th, 1, 1, m_file);
                            // dump thumbnail data
                            fwrite (p->data(), p->datasize(), 1, m_file);
                        }
                    }
                }
            }
        }
        
        // prepare the footer
        tga_footer foot = {(uint32_t)ftell (m_file), 0, "TRUEVISION-XFILE."};
        if (bigendian()) {
            swap_endian (&foot.ofs_ext);
            swap_endian (&foot.ofs_dev);
        }

        // write out the extension area
        // ext area size
        short tmpint = 495;
        if (bigendian())
            swap_endian (&tmpint);
        fwrite (&tmpint, sizeof (tmpint), 1, m_file);

        tmpint = 0;

        // author
        std::string tmpstr = m_spec.get_string_attribute ("Artist", "");
        fwrite (tmpstr.c_str(), std::min (tmpstr.length (), size_t(40)),
                1, m_file);
        // fill the rest with zeros
        for (int i = 41 - std::min (tmpstr.length (), size_t(40)); i > 0; i--)
            fwrite (&tmpint, 1, 1, m_file);

        // image comment
        tmpstr = m_spec.get_string_attribute ("ImageDescription", "");
        {
            char *p = (char *)tmpstr.c_str ();
            int w = 0;  // number of bytes written
            for (int pos = 0; w < 324 && pos < (int)tmpstr.length ();
                 w++, pos++) {
                // on line breaks, fill the remainder of the line with zeros
                if (p[pos] == '\n') {
                    while ((w + 1) % 81 != 0) {
                        fwrite (&tmpint, 1, 1, m_file);
                        w++;
                    }
                    continue;
                }
                fwrite (&p[pos], 1, 1, m_file);
                // null-terminate each line
                if ((w + 1) % 81 == 0) {
                    fwrite (&tmpint, 1, 1, m_file);
                    w++;
                }
            }
            // fill the rest with zeros
            for (; w < 324; w++)
                fwrite (&tmpint, 1, 1, m_file);
        }

        // timestamp
        tmpstr = m_spec.get_string_attribute ("DateTime", "");
        {
            unsigned short y, m, d, h, i, s;
            if (tmpstr.length () > 0)
                sscanf (tmpstr.c_str (), "%04hu:%02hu:%02hu %02hu:%02hu:%02hu",
                        &y, &m, &d, &h, &i, &s);
            else
                y = m = d = h = i = s = 0;
            if (bigendian()) {
                swap_endian (&y);
                swap_endian (&m);
                swap_endian (&d);
                swap_endian (&h);
                swap_endian (&i);
                swap_endian (&s);
            }
            fwrite (&m, sizeof (m), 1, m_file);
            fwrite (&d, sizeof (d), 1, m_file);
            fwrite (&y, sizeof (y), 1, m_file);
            fwrite (&h, sizeof (h), 1, m_file);
            fwrite (&i, sizeof (i), 1, m_file);
            fwrite (&s, sizeof (s), 1, m_file);
        }

        // job ID
        tmpstr = m_spec.get_string_attribute ("DocumentName", "");
        fwrite (tmpstr.c_str(), std::min (tmpstr.length (), size_t(40)),
                1, m_file);
        // fill the rest with zeros
        for (int i = 41 - std::min (tmpstr.length (), size_t(40)); i > 0; i--)
            fwrite (&tmpint, 1, 1, m_file);

        // job time
        tmpstr = m_spec.get_string_attribute ("targa:JobTime", "");
        {
            unsigned short h, m, s;
            if (tmpstr.length () > 0)
                sscanf (tmpstr.c_str (), "%hu:%02hu:%02hu", &h, &m, &s);
            else
                h = m = s = 0;
            if (bigendian()) {
                swap_endian (&h);
                swap_endian (&m);
                swap_endian (&s);
            }
            fwrite (&h, sizeof (h), 1, m_file);
            fwrite (&m, sizeof (m), 1, m_file);
            fwrite (&s, sizeof (s), 1, m_file);
        }

        // software ID - we advertise ourselves
        tmpstr = OIIO_INTRO_STRING;
        fwrite (tmpstr.c_str(), std::min (tmpstr.length (), size_t(40)),
                1, m_file);
        // fill the rest with zeros
        for (int i = 41 - std::min (tmpstr.length (), size_t(40)); i > 0; i--)
            fwrite (&tmpint, 1, 1, m_file);

        // software version
        {
            short v = OIIO_VERSION_MAJOR * 100
                    + OIIO_VERSION_MINOR * 10
                    + OIIO_VERSION_PATCH;
            if (bigendian())
                swap_endian (&v);
            fwrite (&v, sizeof (v), 1, m_file);
            fwrite (&tmpint, 1, 1, m_file);
        }

        // key colour
        // FIXME: what do we save here?
        fwrite (&tmpint, 2, 1, m_file);
        fwrite (&tmpint, 2, 1, m_file);

        // pixel aspect ratio
        {
            float ratio = m_spec.get_float_attribute ("PixelAspectRatio", 1.f);
            float EPS = 1E-5f;
            if (ratio >= (0.f+EPS) && ((ratio <= (1.f-EPS))||(ratio >= (1.f+EPS)))) {
                // FIXME: invent a smarter way to convert to a vulgar fraction?
                // numerator
                tmpint = (unsigned short)(ratio * 10000.f);
                fwrite (&tmpint, 2, 1, m_file);
                // denominator
                tmpint = 10000;
                fwrite (&tmpint, 2, 1, m_file);
                // reset tmpint value
                tmpint = 0;
            } else {
                // just dump two zeros in there
                fwrite (&tmpint, 2, 1, m_file);
                fwrite (&tmpint, 2, 1, m_file);
            }
        }

        // gamma
        {
            if (iequals (m_spec.get_string_attribute ("oiio:ColorSpace"), "GammaCorrected")) {
                float gamma = m_spec.get_float_attribute ("oiio:Gamma", 1.0);
                
                // FIXME: invent a smarter way to convert to a vulgar fraction?
                // NOTE: the spec states that only 1 decimal place of precision
                // is needed, thus the expansion by 10
                // numerator
                tmpint = (unsigned short)(gamma * 10.f);
                fwrite (&tmpint, 2, 1, m_file);
                // denominator
                tmpint = 10;
                fwrite (&tmpint, 2, 1, m_file);
                // reset tmpint value
                tmpint = 0;
            } else {
                // just dump two zeros in there
                fwrite (&tmpint, 2, 1, m_file);
                fwrite (&tmpint, 2, 1, m_file);
            }
        }

        // offset to colour correction table
        // FIXME: support this once it becomes clear how it's actually supposed
        // to be used... the spec is very unclear about this
        // for the time being just dump four NULL bytes
        fwrite (&tmpint, 2, 1, m_file);
        fwrite (&tmpint, 2, 1, m_file);

        // offset to thumbnail (endiannes has already been accounted for)
        fwrite (&ofs_thumb, 4, 1, m_file);

        // offset to scanline table
        // not used very widely, don't bother unless someone complains
        fwrite (&tmpint, 2, 1, m_file);
        fwrite (&tmpint, 2, 1, m_file);

        // alpha type
        {
            unsigned char at = (m_spec.nchannels % 2 == 0)
                             ? TGA_ALPHA_USEFUL : TGA_ALPHA_NONE;
            fwrite (&at, 1, 1, m_file);
        }

        // write out the TGA footer
        fwrite (&foot.ofs_ext, 1, sizeof (foot.ofs_ext), m_file);
        fwrite (&foot.ofs_dev, 1, sizeof (foot.ofs_dev), m_file);
        fwrite (&foot.signature, 1, sizeof (foot.signature), m_file);

        // close the stream
        fclose (m_file);
        m_file = NULL;
    }

    init ();      // re-initialize
    return true;  // How can we fail?
                  // Epicly. -- IneQuation
}
Пример #3
0
bool
DPXOutput::open (const std::string &name, const ImageSpec &userspec,
                 OpenMode mode)
{
    if (mode == Create) {
        m_subimage = 0;
        if (m_subimage_specs.size() < 1) {
            m_subimage_specs.resize (1);
            m_subimage_specs[0] = userspec;
            m_subimages_to_write = 1;
        }
    } else if (mode == AppendSubimage) {
        if (m_write_pending)
            write_buffer ();
        ++m_subimage;
        if (m_subimage >= m_subimages_to_write) {
            error ("Exceeded the pre-declared number of subimages (%d)",
                   m_subimages_to_write);
            return false;
        }
        return prep_subimage (m_subimage, true);
        // Nothing else to do, the header taken care of when we opened with
        // Create.
    } else if (mode == AppendMIPLevel) {
        error ("DPX does not support MIP-maps");
        return false;
    }

    // From here out, all the heavy lifting is done for Create
    ASSERT (mode == Create);

    if (is_opened())
        close ();  // Close any already-opened file
    m_stream = new OutStream();
    if (! m_stream->Open(name.c_str ())) {
        error ("Could not open file \"%s\"", name.c_str ());
        return false;
    }
    m_dpx.SetOutStream (m_stream);
    m_dpx.Start ();
    m_subimage = 0;

    ImageSpec &m_spec (m_subimage_specs[m_subimage]); // alias the spec

    // Check for things this format doesn't support
    if (m_spec.width < 1 || m_spec.height < 1) {
        error ("Image resolution must be at least 1x1, you asked for %d x %d",
               m_spec.width, m_spec.height);
        return false;
    }

    if (m_spec.depth < 1)
        m_spec.depth = 1;
    else if (m_spec.depth > 1) {
        error ("DPX does not support volume images (depth > 1)");
        return false;
    }

    // some metadata
    std::string software = m_spec.get_string_attribute ("Software", "");
    std::string project = m_spec.get_string_attribute ("DocumentName", "");
    std::string copyright = m_spec.get_string_attribute ("Copyright", "");
    std::string datestr = m_spec.get_string_attribute ("DateTime", "");
    if (datestr.size () >= 19) {
        // libdpx's date/time format is pretty close to OIIO's (libdpx uses
        // %Y:%m:%d:%H:%M:%S%Z)
        // NOTE: the following code relies on the DateTime attribute being properly
        // formatted!
        // assume UTC for simplicity's sake, fix it if someone complains
        datestr[10] = ':';
        datestr.replace (19, -1, "Z");
    }

    // check if the client wants endianness reverse to native
    // assume big endian per Jeremy's request, unless little endian is
    // explicitly specified
    std::string endian = m_spec.get_string_attribute ("oiio:Endian", littleendian() ? "little" : "big");
    m_wantSwap = (littleendian() != Strutil::iequals (endian, "little"));

    m_dpx.SetFileInfo (name.c_str (),                               // filename
        datestr.c_str (),                                           // cr. date
        software.empty () ? OIIO_INTRO_STRING : software.c_str (),  // creator
        project.empty () ? NULL : project.c_str (),                 // project
        copyright.empty () ? NULL : copyright.c_str (),             // copyright
        m_spec.get_int_attribute ("dpx:EncryptKey", ~0),            // encryption key
        m_wantSwap);

    // image info
    m_dpx.SetImageInfo (m_spec.width, m_spec.height);

    for (int s = 0;  s < m_subimages_to_write;  ++s) {
        prep_subimage (s, false);
        m_dpx.header.SetBitDepth (s, m_bitdepth);
        ImageSpec &spec (m_subimage_specs[s]);
        bool datasign = (spec.format == TypeDesc::INT8 ||
                         spec.format == TypeDesc::INT16);
        m_dpx.SetElement (s, m_desc, m_bitdepth, m_transfer, m_cmetr,
                          m_packing, dpx::kNone, datasign,
                          spec.get_int_attribute ("dpx:LowData", 0xFFFFFFFF),
                          spec.get_float_attribute ("dpx:LowQuantity", std::numeric_limits<float>::quiet_NaN()),
                          spec.get_int_attribute ("dpx:HighData", 0xFFFFFFFF),
                          spec.get_float_attribute ("dpx:HighQuantity", std::numeric_limits<float>::quiet_NaN()),
                          spec.get_int_attribute ("dpx:EndOfLinePadding", 0),
                          spec.get_int_attribute ("dpx:EndOfImagePadding", 0));
        std::string desc = spec.get_string_attribute ("ImageDescription", "");
        m_dpx.header.SetDescription (s, desc.c_str());
    }

    m_dpx.header.SetXScannedSize (m_spec.get_float_attribute
        ("dpx:XScannedSize", std::numeric_limits<float>::quiet_NaN()));
    m_dpx.header.SetYScannedSize (m_spec.get_float_attribute
        ("dpx:YScannedSize", std::numeric_limits<float>::quiet_NaN()));
    m_dpx.header.SetFramePosition (m_spec.get_int_attribute
        ("dpx:FramePosition", 0xFFFFFFFF));
    m_dpx.header.SetSequenceLength (m_spec.get_int_attribute
        ("dpx:SequenceLength", 0xFFFFFFFF));
    m_dpx.header.SetHeldCount (m_spec.get_int_attribute
        ("dpx:HeldCount", 0xFFFFFFFF));
    m_dpx.header.SetFrameRate (m_spec.get_float_attribute
        ("dpx:FrameRate", std::numeric_limits<float>::quiet_NaN()));
    m_dpx.header.SetShutterAngle (m_spec.get_float_attribute
        ("dpx:ShutterAngle", std::numeric_limits<float>::quiet_NaN()));
    // FIXME: should we write the input version through or always default to 2.0?
    /*tmpstr = m_spec.get_string_attribute ("dpx:Version", "");
    if (tmpstr.size () > 0)
        m_dpx.header.SetVersion (tmpstr.c_str ());*/
    std::string tmpstr;
    tmpstr = m_spec.get_string_attribute ("dpx:FrameId", "");
    if (tmpstr.size () > 0)
        m_dpx.header.SetFrameId (tmpstr.c_str ());
    tmpstr = m_spec.get_string_attribute ("dpx:SlateInfo", "");
    if (tmpstr.size () > 0)
        m_dpx.header.SetSlateInfo (tmpstr.c_str ());
    tmpstr = m_spec.get_string_attribute ("dpx:SourceImageFileName", "");
    if (tmpstr.size () > 0)
        m_dpx.header.SetSourceImageFileName (tmpstr.c_str ());
    tmpstr = m_spec.get_string_attribute ("dpx:InputDevice", "");
    if (tmpstr.size () > 0)
        m_dpx.header.SetInputDevice (tmpstr.c_str ());
    tmpstr = m_spec.get_string_attribute ("dpx:InputDeviceSerialNumber", "");
    if (tmpstr.size () > 0)
        m_dpx.header.SetInputDeviceSerialNumber (tmpstr.c_str ());
    m_dpx.header.SetInterlace (m_spec.get_int_attribute ("dpx:Interlace", 0xFF));
    m_dpx.header.SetFieldNumber (m_spec.get_int_attribute ("dpx:FieldNumber", 0xFF));
    m_dpx.header.SetHorizontalSampleRate (m_spec.get_float_attribute
        ("dpx:HorizontalSampleRate", std::numeric_limits<float>::quiet_NaN()));
    m_dpx.header.SetVerticalSampleRate (m_spec.get_float_attribute
        ("dpx:VerticalSampleRate", std::numeric_limits<float>::quiet_NaN()));
    m_dpx.header.SetTemporalFrameRate (m_spec.get_float_attribute
        ("dpx:TemporalFrameRate", std::numeric_limits<float>::quiet_NaN()));
    m_dpx.header.SetTimeOffset (m_spec.get_float_attribute
        ("dpx:TimeOffset", std::numeric_limits<float>::quiet_NaN()));
    m_dpx.header.SetBlackLevel (m_spec.get_float_attribute
        ("dpx:BlackLevel", std::numeric_limits<float>::quiet_NaN()));
    m_dpx.header.SetBlackGain (m_spec.get_float_attribute
        ("dpx:BlackGain", std::numeric_limits<float>::quiet_NaN()));
    m_dpx.header.SetBreakPoint (m_spec.get_float_attribute
        ("dpx:BreakPoint", std::numeric_limits<float>::quiet_NaN()));
    m_dpx.header.SetWhiteLevel (m_spec.get_float_attribute
        ("dpx:WhiteLevel", std::numeric_limits<float>::quiet_NaN()));
    m_dpx.header.SetIntegrationTimes (m_spec.get_float_attribute
        ("dpx:IntegrationTimes", std::numeric_limits<float>::quiet_NaN()));
    float aspect = m_spec.get_float_attribute ("PixelAspectRatio", 1.0f);
    int aspect_num, aspect_den;
    float_to_rational (aspect, aspect_num, aspect_den);
    m_dpx.header.SetAspectRatio (0, aspect_num);
    m_dpx.header.SetAspectRatio (1, aspect_den);
    m_dpx.header.SetXOffset ((unsigned int)std::max (0, m_spec.x));
    m_dpx.header.SetYOffset ((unsigned int)std::max (0, m_spec.y));
    m_dpx.header.SetXOriginalSize ((unsigned int)m_spec.full_width);
    m_dpx.header.SetYOriginalSize ((unsigned int)m_spec.full_height);

    static int DpxOrientations[] = { 0,
        dpx::kLeftToRightTopToBottom, dpx::kRightToLeftTopToBottom,
        dpx::kLeftToRightBottomToTop, dpx::kRightToLeftBottomToTop,
        dpx::kTopToBottomLeftToRight, dpx::kTopToBottomRightToLeft,
        dpx::kBottomToTopLeftToRight, dpx::kBottomToTopRightToLeft };
    int orient = m_spec.get_int_attribute ("Orientation", 0);
    orient = DpxOrientations[clamp (orient, 0, 8)];
    m_dpx.header.SetImageOrientation ((dpx::Orientation)orient);

    ImageIOParameter *tc = m_spec.find_attribute("smpte:TimeCode", TypeDesc::TypeTimeCode, false);
    if (tc) {
        unsigned int *timecode = (unsigned int*) tc->data();
        m_dpx.header.timeCode = timecode[0];
        m_dpx.header.userBits = timecode[1];
    }
    else {
        std::string timecode = m_spec.get_string_attribute ("dpx:TimeCode", "");
        int tmpint = m_spec.get_int_attribute ("dpx:TimeCode", ~0);
        if (timecode.size () > 0)
            m_dpx.header.SetTimeCode (timecode.c_str ());
        else if (tmpint != ~0)
        m_dpx.header.timeCode = tmpint;
        m_dpx.header.userBits = m_spec.get_int_attribute ("dpx:UserBits", ~0);
    }

    ImageIOParameter *kc = m_spec.find_attribute("smpte:KeyCode", TypeDesc::TypeKeyCode, false);
    if (kc) {
        int *array = (int*) kc->data();
        set_keycode_values(array);

        // See if there is an overloaded dpx:Format
        std::string format = m_spec.get_string_attribute ("dpx:Format", "");
        if (format.size () > 0)
            m_dpx.header.SetFormat (format.c_str ());
    }

    std::string srcdate = m_spec.get_string_attribute ("dpx:SourceDateTime", "");
    if (srcdate.size () >= 19) {
        // libdpx's date/time format is pretty close to OIIO's (libdpx uses
        // %Y:%m:%d:%H:%M:%S%Z)
        // NOTE: the following code relies on the DateTime attribute being properly
        // formatted!
        // assume UTC for simplicity's sake, fix it if someone complains
        srcdate[10] = ':';
        srcdate.replace (19, -1, "Z");
        m_dpx.header.SetSourceTimeDate (srcdate.c_str ());
    }

    // set the user data size
    ImageIOParameter *user = m_spec.find_attribute ("dpx:UserData");
    if (user && user->datasize () > 0 && user->datasize () <= 1024 * 1024) {
        m_dpx.SetUserData (user->datasize ());
    }

    // commit!
    if (!m_dpx.WriteHeader ()) {
        error ("Failed to write DPX header");
        return false;
    }

    // write the user data
    if (user && user->datasize () > 0 && user->datasize() <= 1024 * 1024) {
        if (!m_dpx.WriteUserData ((void *)user->data ())) {
            error ("Failed to write user data");
            return false;
        }
    }

    m_dither = (m_spec.format == TypeDesc::UINT8) ?
                    m_spec.get_int_attribute ("oiio:dither", 0) : 0;

    // If user asked for tiles -- which this format doesn't support, emulate
    // it by buffering the whole image.
    if (m_spec.tile_width && m_spec.tile_height)
        m_tilebuffer.resize (m_spec.image_bytes());

    return prep_subimage (m_subimage, true);
}
Пример #4
0
bool
DPXOutput::open (const std::string &name, const ImageSpec &userspec,
                 OpenMode mode)
{
    close ();  // Close any already-opened file

    if (mode != Create) {
        error ("%s does not support subimages or MIP levels", format_name());
        return false;
    }

    m_spec = userspec;  // Stash the spec

    // open the image
    m_stream = new OutStream();
    if (! m_stream->Open(name.c_str ())) {
        error ("Could not open file \"%s\"", name.c_str ());
        return false;
    }

    // Check for things this format doesn't support
    if (m_spec.width < 1 || m_spec.height < 1) {
        error ("Image resolution must be at least 1x1, you asked for %d x %d",
                       m_spec.width, m_spec.height);
                       return false;
    }

    if (m_spec.depth < 1)
        m_spec.depth = 1;
    else if (m_spec.depth > 1) {
        error ("DPX does not support volume images (depth > 1)");
        return false;
    }

    if (m_spec.format == TypeDesc::UINT8
        || m_spec.format == TypeDesc::INT8)
        m_datasize = dpx::kByte;
    else if (m_spec.format == TypeDesc::UINT16
        || m_spec.format == TypeDesc::INT16)
        m_datasize = dpx::kWord;
    else if (m_spec.format == TypeDesc::FLOAT
        || m_spec.format == TypeDesc::HALF) {
        m_spec.format = TypeDesc::FLOAT;
        m_datasize = dpx::kFloat;
    } else if (m_spec.format == TypeDesc::DOUBLE)
        m_datasize = dpx::kDouble;
    else {
        // use 16-bit unsigned integers as a failsafe
        m_spec.format = TypeDesc::UINT16;
        m_datasize = dpx::kWord;
    }

    // check if the client is giving us raw data to write
    m_wantRaw = m_spec.get_int_attribute ("dpx:RawData", 0) != 0;

    m_dpx.SetOutStream (m_stream);

    // start out the file
    m_dpx.Start ();

    // some metadata
    std::string project = m_spec.get_string_attribute ("DocumentName", "");
    std::string copyright = m_spec.get_string_attribute ("Copyright", "");
    m_dpx.SetFileInfo (name.c_str (),                       // filename
        NULL,                                               // TODO: cr. date
        OIIO_INTRO_STRING,                                  // creator
        project.empty () ? NULL : project.c_str (),         // project
        copyright.empty () ? NULL : copyright.c_str ());    // copyright

    // image info
    m_dpx.SetImageInfo (m_spec.width, m_spec.height);

    // determine descriptor
    m_desc = get_descriptor_from_string
        (m_spec.get_string_attribute ("dpx:ImageDescriptor", ""));

    // transfer function
    dpx::Characteristic transfer;
    
    std::string colorspace = m_spec.get_string_attribute ("oiio:ColorSpace", "");
    if (iequals (colorspace, "Linear"))  transfer = dpx::kLinear;
    else if (iequals (colorspace, "GammaCorrected")) transfer = dpx::kUserDefined;
    else if (iequals (colorspace, "Rec709")) transfer = dpx::kITUR709;
    else if (iequals (colorspace, "KodakLog")) transfer = dpx::kLogarithmic;
    else {
        std::string dpxtransfer = m_spec.get_string_attribute ("dpx:Transfer", "");
        transfer = get_characteristic_from_string (dpxtransfer);
    }
    
    // colorimetric
    m_cmetr = get_characteristic_from_string
        (m_spec.get_string_attribute ("dpx:Colorimetric", "User defined"));

    // select packing method
    dpx::Packing packing;
    std::string tmpstr = m_spec.get_string_attribute ("dpx:ImagePacking", "Filled, method A");
    if (iequals (tmpstr, "Packed"))
        packing = dpx::kPacked;
    else if (iequals (tmpstr, "Filled, method B"))
        packing = dpx::kFilledMethodB;
    else
        packing = dpx::kFilledMethodA;

    // calculate target bit depth
    int bitDepth = m_spec.get_int_attribute ("oiio:BitsPerSample",
        m_spec.format.size () * 8);
    if (bitDepth % 8 != 0 && bitDepth != 10 && bitDepth != 12) {
        error ("Unsupported bit depth %d", bitDepth);
        return false;
    }
    
    // see if we'll need to convert or not
    if (m_desc == dpx::kRGB || m_desc == dpx::kRGBA) {
        // shortcut for RGB(A) that gets the job done
        m_bytes = m_spec.scanline_bytes ();
        m_wantRaw = true;
    } else {
        m_bytes = dpx::QueryNativeBufferSize (m_desc, m_datasize, m_spec.width, 1);
        if (m_bytes == 0 && !m_wantRaw) {
            error ("Unable to deliver native format data from source data");
            return false;
        } else if (m_bytes < 0) {
            // no need to allocate another buffer
            if (!m_wantRaw)
                m_bytes = m_spec.scanline_bytes ();
            else
                m_bytes = -m_bytes;
        }
    }

    if (m_bytes < 0)
        m_bytes = -m_bytes;

    m_dpx.SetElement (0, m_desc, bitDepth, transfer, m_cmetr,
        packing, dpx::kNone, (m_spec.format == TypeDesc::INT8
            || m_spec.format == TypeDesc::INT16) ? 1 : 0);

    // commit!
    if (!m_dpx.WriteHeader ()) {
        error ("Failed to write DPX header");
        return false;
    }

    // user data
    ImageIOParameter *user = m_spec.find_attribute ("dpx:UserData");
    if (user && user->datasize () > 0) {
        if (user->datasize () > 1024 * 1024) {
            error ("User data block size exceeds 1 MB");
            return false;
        }
        // FIXME: write the missing libdpx code
        /*m_dpx.SetUserData (user->datasize ());
        if (!m_dpx.WriteUserData ((void *)user->data ())) {
            error ("Failed to write user data");
            return false;
        }*/
    }

    // reserve space for the image data buffer
    m_buf.reserve (m_bytes * m_spec.height);

    return true;
}