Esempio n. 1
0
inline bool
RLAInput::read_header ()
{
    // Read the image header, which should have the same exact layout as
    // the m_rla structure (except for endianness issues).
    ASSERT (sizeof(m_rla) == 740 && "Bad RLA struct size");
    if (! read (&m_rla)) {
        error ("RLA could not read the image header");
        return false;
    }
    m_rla.rla_swap_endian ();  // fix endianness

    if (m_rla.Revision != (int16_t)0xFFFE &&
        m_rla.Revision != 0 /* for some reason, this can happen */) {
        error ("RLA header Revision number unrecognized: %d", m_rla.Revision);
        return false;   // unknown file revision
    }
    if (m_rla.NumOfChannelBits == 0)
        m_rla.NumOfChannelBits = 8;  // apparently, this can happen

    // Immediately following the header is the scanline offset table --
    // one uint32_t for each scanline, giving absolute offsets (from the
    // beginning of the file) where the RLE records start for each
    // scanline of this subimage.
    m_sot.resize (std::abs (m_rla.ActiveBottom - m_rla.ActiveTop) + 1, 0);
    if (! read (&m_sot[0], m_sot.size())) {
        error ("RLA could not read the scanline offset table");
        return false;
    }
    return true;
}
Esempio n. 2
0
bool
RLAOutput::open (const std::string &name, const ImageSpec &userspec,
                 OpenMode mode)
{
    if (mode != Create) {
        error ("%s does not support subimages or MIP levels", format_name());
        return false;
        // FIXME -- the RLA format supports subimages, but our writer
        // doesn't.  I'm not sure if it's worth worrying about for an
        // old format that is so rarely used.  We'll come back to it if
        // anybody actually encounters a multi-subimage RLA in the wild.
    }

    close ();  // Close any already-opened file
    m_spec = userspec;  // Stash the spec

    m_file = fopen (name.c_str(), "wb");
    if (! m_file) {
        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.width > 65535 || m_spec.height > 65535) {
        error ("Image resolution %d x %d too large for RLA (maxiumum 65535x65535)",
               m_spec.width, m_spec.height);
        return false;
    }

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

    // prepare and write the RLA header
    memset (&m_rla, 0, sizeof (m_rla));
    // frame and window coordinates
    m_rla.WindowLeft = m_spec.full_x;
    m_rla.WindowRight = m_spec.full_x + m_spec.full_width - 1;
    m_rla.WindowBottom = -m_spec.full_y;
    m_rla.WindowTop = m_spec.full_height - m_spec.full_y - 1;
    
    m_rla.ActiveLeft = m_spec.x;
    m_rla.ActiveRight = m_spec.x + m_spec.width - 1;
    m_rla.ActiveBottom = -m_spec.y;
    m_rla.ActiveTop = m_spec.height - m_spec.y - 1;

    m_rla.FrameNumber = m_spec.get_int_attribute ("rla:FrameNumber", 0);

    // figure out what's going on with the channels
    int remaining = m_spec.nchannels;
    if (m_spec.channelformats.size ()) {
        int streak;
        // accomodate first 3 channels of the same type as colour ones
        for (streak = 1; streak <= 3 && remaining > 0; ++streak, --remaining)
            if (m_spec.channelformats[streak] != m_spec.channelformats[0])
                break;
        m_rla.ColorChannelType = m_spec.channelformats[0] == TypeDesc::FLOAT
            ? CT_FLOAT : CT_BYTE;
        int bits = m_spec.get_int_attribute ("oiio:BitsPerSample", 0);
        m_rla.NumOfChannelBits = bits ? bits : m_spec.channelformats[0].size () * 8;
        // limit to 3 in case the loop went further
        m_rla.NumOfColorChannels = std::min (streak, 3);
        // if we have anything left, treat it as alpha
        if (remaining) {
            for (streak = 1; remaining > 0; ++streak, --remaining)
                if (m_spec.channelformats[m_rla.NumOfColorChannels + streak]
                    != m_spec.channelformats[m_rla.NumOfColorChannels])
                    break;
            m_rla.MatteChannelType = m_spec.channelformats[m_rla.NumOfColorChannels]
                == TypeDesc::FLOAT ? CT_FLOAT : CT_BYTE;
            m_rla.NumOfMatteBits = bits ? bits : m_spec.channelformats[m_rla.NumOfColorChannels].size () * 8;
            m_rla.NumOfMatteChannels = streak;
        }
        // and if there's something more left, put it in auxiliary
        if (remaining) {
            for (streak = 1; remaining > 0; ++streak, --remaining)
                if (m_spec.channelformats[m_rla.NumOfColorChannels
                        + m_rla.NumOfMatteChannels + streak]
                    != m_spec.channelformats[m_rla.NumOfColorChannels
                        + m_rla.NumOfMatteChannels])
                    break;
            m_rla.MatteChannelType = m_spec.channelformats[m_rla.NumOfColorChannels
                    + m_rla.NumOfMatteChannels]
                == TypeDesc::FLOAT ? CT_FLOAT : CT_BYTE;
            m_rla.NumOfAuxBits = m_spec.channelformats[m_rla.NumOfColorChannels
                + m_rla.NumOfMatteChannels].size () * 8;
            m_rla.NumOfAuxChannels = streak;
        }
    } else {
        m_rla.ColorChannelType = m_rla.MatteChannelType = m_rla.AuxChannelType =
            m_spec.format == TypeDesc::FLOAT ? CT_FLOAT : CT_BYTE;
        m_rla.NumOfChannelBits = m_rla.NumOfMatteBits = m_rla.NumOfAuxBits =
            m_spec.format.size () * 8;
        if (remaining >= 3) {
            // if we have at least 3 channels, treat them as colour
            m_rla.NumOfColorChannels = 3;
            remaining -= 3;
        } else {
            // otherwise let's say it's luminosity
            m_rla.NumOfColorChannels = 1;
            --remaining;
        }
        // if there's at least 1 more channel, it's alpha
        if (remaining-- > 0)
            ++m_rla.NumOfMatteChannels;
        // anything left is auxiliary
        if (remaining > 0)
            m_rla.NumOfAuxChannels = remaining;
    }
    
    m_rla.Revision = 0xFFFE;
    
    std::string s = m_spec.get_string_attribute ("oiio:ColorSpace", "Unknown");
    if (Strutil::iequals(s, "Linear"))
        strcpy (m_rla.Gamma, "1.0");
    else if (Strutil::iequals(s, "GammaCorrected"))
        snprintf (m_rla.Gamma, sizeof(m_rla.Gamma), "%.10f",
            m_spec.get_float_attribute ("oiio:Gamma", 1.f));
    
    const ImageIOParameter *p;
    // default NTSC chromaticities
    p = m_spec.find_attribute ("rla:RedChroma");
    set_chromaticity (p, m_rla.RedChroma, sizeof (m_rla.RedChroma), "0.67 0.08");
    p = m_spec.find_attribute ("rla:GreenChroma");
    set_chromaticity (p, m_rla.GreenChroma, sizeof (m_rla.GreenChroma), "0.21 0.71");
    p = m_spec.find_attribute ("rla:BlueChroma");
    set_chromaticity (p, m_rla.BlueChroma, sizeof (m_rla.BlueChroma), "0.14 0.33");
    p = m_spec.find_attribute ("rla:WhitePoint");
    set_chromaticity (p, m_rla.WhitePoint, sizeof (m_rla.WhitePoint), "0.31 0.316");

#define STRING_FIELD(rlafield,name)                                     \
    {                                                                   \
        std::string s = m_spec.get_string_attribute (name);             \
        if (s.length()) {                                               \
            strncpy (m_rla.rlafield, s.c_str(), sizeof(m_rla.rlafield));\
            m_rla.rlafield[sizeof(m_rla.rlafield)-1] = 0;               \
        } else {                                                        \
            m_rla.rlafield[0] = 0;                                      \
        }                                                               \
    }

    m_rla.JobNumber = m_spec.get_int_attribute ("rla:JobNumber", 0);
    STRING_FIELD (FileName, "rla:FileName");
    STRING_FIELD (Description, "ImageDescription");
    STRING_FIELD (ProgramName, "Software");
    STRING_FIELD (MachineName, "HostComputer");
    STRING_FIELD (UserName, "Artist");
    
    // the month number will be replaced with the 3-letter abbreviation
    time_t t = time (NULL);
    strftime (m_rla.DateCreated, sizeof (m_rla.DateCreated), "%m  %d %H:%M %Y",
        localtime (&t));
    // nice little trick - atoi() will convert the month number to integer,
    // which we then use to index this array of constants, and copy the
    // abbreviation back into the date string
    static const char months[12][4] = {
        "JAN",
        "FEB",
        "MAR",
        "APR",
        "MAY",
        "JUN",
        "JUL",
        "AUG",
        "SEP",
        "OCT",
        "NOV",
        "DEC"
    };
    memcpy(m_rla.DateCreated, months[atoi (m_rla.DateCreated) - 1], 3);
    
    // FIXME: it appears that Wavefront have defined a set of aspect names;
    // I think it's safe not to care until someone complains
    STRING_FIELD (Aspect, "rla:Aspect");

    snprintf (m_rla.AspectRatio, sizeof(m_rla.AspectRatio), "%.10f",
        m_spec.get_float_attribute ("PixelAspectRatio", 1.f));
    strcpy (m_rla.ColorChannel, m_spec.get_string_attribute ("rla:ColorChannel",
        "rgb").c_str ());
    m_rla.FieldRendered = m_spec.get_int_attribute ("rla:FieldRendered", 0);

    STRING_FIELD (Time, "rla:Time");
    STRING_FIELD (Filter, "rla:Filter");
    STRING_FIELD (AuxData, "rla:AuxData");

    m_rla.rla_swap_endian ();        // RLAs are big-endian
    write (&m_rla);
    m_rla.rla_swap_endian ();        // flip back the endianness to native
    
    // write placeholder values - not all systems may expand the file with
    // zeroes upon seek
    m_sot.resize (m_spec.height, (int32_t)0);
    write (&m_sot[0], m_sot.size());
    
    return true;
}