예제 #1
0
bool
ImageInput::read_native_scanlines (int ybegin, int yend, int z,
                                   int firstchan, int nchans, void *data)
{
    // All-channel case just reduces to the simpler read_native_scanlines.
    if (firstchan == 0 && nchans >= m_spec.nchannels)
        return read_native_scanlines (ybegin, yend, z, data);

    // Base class implementation of read_native_scanlines (with channel
    // subset) just calls read_native_scanlines (all channels), and
    // copies the appropriate subset.
    size_t prefix_bytes = m_spec.pixel_bytes (0,firstchan,true);
    size_t subset_bytes = m_spec.pixel_bytes (firstchan,nchans,true);
    size_t subset_ystride = m_spec.width * subset_bytes;

    size_t native_pixel_bytes = m_spec.pixel_bytes (true);
    size_t native_ystride = m_spec.width * native_pixel_bytes;
    std::vector<char> buf (native_ystride);
    yend = std::min (yend, spec().y+spec().height);
    for (int y = ybegin;  y < yend;  ++y) {
        bool ok = read_native_scanline (y, z, &buf[0]);
        if (! ok)
            return false;
        for (int x = 0;  x < m_spec.width;  ++x)
            memcpy ((char *)data + subset_bytes*x,
                    &buf[prefix_bytes+native_pixel_bytes*x], subset_bytes);
        data = (char *)data + subset_ystride;
    }
    return true;
}
예제 #2
0
파일: exrinput.cpp 프로젝트: gmarcusm/oiio
bool
OpenEXRInput::read_native_scanlines (int ybegin, int yend, int z, void *data)
{
    return read_native_scanlines (ybegin, yend, z, 0, m_spec.nchannels, data);
}
예제 #3
0
파일: exrinput.cpp 프로젝트: gmarcusm/oiio
bool
OpenEXRInput::read_native_scanline (int y, int z, void *data)
{
    return read_native_scanlines (y, y+1, z, 0, m_spec.nchannels, data);
}
예제 #4
0
bool
ImageInput::read_scanlines (int ybegin, int yend, int z,
                            int firstchan, int nchans,
                            TypeDesc format, void *data,
                            stride_t xstride, stride_t ystride)
{
    nchans = std::min (nchans, m_spec.nchannels-firstchan);
    yend = std::min (yend, spec().y+spec().height);
    size_t native_pixel_bytes = m_spec.pixel_bytes (firstchan, nchans, true);
    imagesize_t native_scanline_bytes = clamped_mult64 ((imagesize_t)m_spec.width,
                                                        (imagesize_t)native_pixel_bytes);
    bool native = (format == TypeDesc::UNKNOWN);
    size_t pixel_bytes = native ? native_pixel_bytes : format.size()*nchans;
    if (native && xstride == AutoStride)
        xstride = pixel_bytes;
    stride_t zstride = AutoStride;
    m_spec.auto_stride (xstride, ystride, zstride, format, nchans,
                        m_spec.width, m_spec.height);
    bool contiguous = (xstride == (stride_t) native_pixel_bytes &&
                       ystride == (stride_t) native_scanline_bytes);
    // If user's format and strides are set up to accept the native data
    // layout, read the scanlines directly into the user's buffer.
    bool rightformat = (format == TypeDesc::UNKNOWN) ||
        (format == m_spec.format && m_spec.channelformats.empty());
    if (rightformat && contiguous) {
        if (firstchan == 0 && nchans == m_spec.nchannels)
            return read_native_scanlines (ybegin, yend, z, data);
        else
            return read_native_scanlines (ybegin, yend, z,
                                          firstchan, nchans, data);
    }

    // No such luck.  Read scanlines in chunks.

    const imagesize_t limit = 16*1024*1024;   // Allocate 16 MB, or 1 scanline
    int chunk = std::max (1, int(limit / native_scanline_bytes));
    std::vector<unsigned char> buf (chunk * native_scanline_bytes);

    bool ok = true;
    int scanline_values = m_spec.width * nchans;
    for (;  ok && ybegin < yend;  ybegin += chunk) {
        int y1 = std::min (ybegin+chunk, yend);
        ok &= read_native_scanlines (ybegin, y1, z, firstchan, nchans, &buf[0]);
        if (! ok)
            break;

        int nscanlines = y1 - ybegin;
        int chunkvalues = scanline_values * nscanlines;
        if (m_spec.channelformats.empty()) {
            // No per-channel formats -- do the conversion in one shot
            if (contiguous) {
                ok = convert_types (m_spec.format, &buf[0], format, data, chunkvalues);
            } else {
                ok = convert_image (nchans, m_spec.width, nscanlines, 1, 
                                    &buf[0], m_spec.format, AutoStride, AutoStride, AutoStride,
                                    data, format, xstride, ystride, zstride);
            }
        } else {
            // Per-channel formats -- have to convert/copy channels individually
            size_t offset = 0;
            for (int c = 0;  ok && c < nchans;  ++c) {
                TypeDesc chanformat = m_spec.channelformats[c+firstchan];
                ok = convert_image (1 /* channels */, m_spec.width, nscanlines, 1, 
                                    &buf[offset], chanformat, 
                                    pixel_bytes, AutoStride, AutoStride,
                                    (char *)data + c*m_spec.format.size(),
                                    format, xstride, ystride, zstride);
                offset += chanformat.size ();
            }
        }
        if (! ok)
            error ("ImageInput::read_scanlines : no support for format %s",
                   m_spec.format.c_str());
        data = (char *)data + ystride*nscanlines;
    }
    return ok;
}