Esempio n. 1
0
bool
SgiInput::read_native_scanline (int y, int z, void *data)
{
    if (y < 0 || y > m_spec.height)
        return false;

    y = m_spec.height - y - 1;

    int bpc = m_sgi_header.bpc;
    std::vector<std::vector<unsigned char> > channeldata (m_spec.nchannels);
    if (m_sgi_header.storage == sgi_pvt::RLE) {
        // reading and uncompressing first channel (red in RGBA images)
        for (int c = 0;  c < m_spec.nchannels;  ++c) {
            int off = y + c*m_spec.height;  // offset for this scanline/channel
            int scanline_offset = start_tab[off];
            int scanline_length = length_tab[off];
            channeldata[c].resize (m_spec.width * bpc);
            uncompress_rle_channel (scanline_offset, scanline_length,
                                    &(channeldata[c][0]));
        }
    } else {
        // non-RLE case -- just read directly into our channel data
        for (int c = 0;  c < m_spec.nchannels;  ++c) {
            int off = y + c*m_spec.height;  // offset for this scanline/channel
            int scanline_offset = sgi_pvt::SGI_HEADER_LEN + off * m_spec.width * bpc;
            fseek (m_fd, scanline_offset, SEEK_SET);
            channeldata[c].resize (m_spec.width * bpc);
            if (! fread (&(channeldata[c][0]), 1, m_spec.width * bpc))
                return false;
        }
    }

    if (m_spec.nchannels == 1) {
        // If just one channel, no interleaving is necessary, just memcpy
        memcpy (data, &(channeldata[0][0]), channeldata[0].size());
    } else {
        unsigned char *cdata = (unsigned char *)data;
        for (int x = 0; x < m_spec.width; ++x) {
            for (int c = 0;  c < m_spec.nchannels;  ++c) {
                *cdata++ = channeldata[c][x*bpc];
                if (bpc == 2)
                    *cdata++ = channeldata[c][x*bpc+1];
            }
        }
    }

    // Swap endianness if needed
    if (bpc == 2 && littleendian())
        swap_endian ((unsigned short *)data, m_spec.width*m_spec.nchannels);

    return true;
}
Esempio n. 2
0
bool
SgiOutput::write_scanline (int y, int z, TypeDesc format, const void *data,
                           stride_t xstride)
{
    y = m_spec.height - y - 1;
    data = to_native_scanline (format, data, xstride, m_scratch,
                               m_dither, y, z);

    // In SGI format all channels are saved to file separately: firsty all
    // channel 1 scanlines are saved, then all channel2 scanlines are saved
    // and so on.
    //
    // Note that since SGI images are pretty archaic and most probably
    // people won't be too picky about full flexibility writing them, we
    // content ourselves with only writing uncompressed data, and don't
    // attempt to write with RLE encoding.

    int bpc = m_spec.format.size();  // bytes per channel
    std::vector<unsigned char> channeldata (m_spec.width * bpc);

    for (int c = 0;  c < m_spec.nchannels;  ++c) {
        unsigned char *cdata = (unsigned char *)data + c*bpc;
        for (int x = 0;  x < m_spec.width;  ++x) {
            channeldata[x*bpc] = cdata[0];
            if (bpc == 2)
                channeldata[x*bpc+1] = cdata[1];
            cdata += m_spec.nchannels * bpc;  // advance to next pixel
        }
        if (bpc == 2 && littleendian())
            swap_endian ((unsigned short *)&channeldata[0], m_spec.width);
        long scanline_offset = sgi_pvt::SGI_HEADER_LEN + (c * m_spec.height + y)
                                  * m_spec.width * bpc;
        fseek (m_fd, scanline_offset, SEEK_SET);
        if (!fwrite (&channeldata[0], 1, m_spec.width * bpc)) {
            return false;
        }
    }

    return true;    
}