bool ImageInput::read_scanline (int y, int z, TypeDesc format, void *data, stride_t xstride) { // native_pixel_bytes is the size of a pixel in the FILE, including // the per-channel format. stride_t native_pixel_bytes = (stride_t) m_spec.pixel_bytes (true); // perchanfile is true if the file has different per-channel formats bool perchanfile = m_spec.channelformats.size(); // native_data is true if the user asking for data in the native format bool native_data = (format == TypeDesc::UNKNOWN || (format == m_spec.format && !perchanfile)); if (native_data && xstride == AutoStride) xstride = native_pixel_bytes; else m_spec.auto_stride (xstride, format, m_spec.nchannels); // Do the strides indicate that the data area is contiguous? bool contiguous = (native_data && xstride == native_pixel_bytes) || (!native_data && xstride == (stride_t)m_spec.pixel_bytes(false)); // If user's format and strides are set up to accept the native data // layout, read the scanline directly into the user's buffer. if (native_data && contiguous) return read_native_scanline (y, z, data); // Complex case -- either changing data type or stride int scanline_values = m_spec.width * m_spec.nchannels; unsigned char *buf = (unsigned char *) alloca (m_spec.scanline_bytes(true)); bool ok = read_native_scanline (y, z, buf); if (! ok) return false; if (! perchanfile) { // No per-channel formats -- do the conversion in one shot ok = contiguous ? convert_types (m_spec.format, buf, format, data, scanline_values) : convert_image (m_spec.nchannels, m_spec.width, 1, 1, buf, m_spec.format, AutoStride, AutoStride, AutoStride, data, format, xstride, AutoStride, AutoStride); } else { // Per-channel formats -- have to convert/copy channels individually ASSERT (m_spec.channelformats.size() == (size_t)m_spec.nchannels); size_t offset = 0; for (int c = 0; ok && c < m_spec.nchannels; ++c) { TypeDesc chanformat = m_spec.channelformats[c]; ok = convert_image (1 /* channels */, m_spec.width, 1, 1, buf+offset, chanformat, native_pixel_bytes, AutoStride, AutoStride, (char *)data + c*format.size(), format, xstride, AutoStride, AutoStride); offset += chanformat.size (); } } if (! ok) error ("ImageInput::read_scanline : no support for format %s", m_spec.format.c_str()); return ok; }
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; }
bool ImageInput::read_native_scanlines (int ybegin, int yend, int z, void *data) { // Base class implementation of read_native_scanlines just repeatedly // calls read_native_scanline, which is supplied by every plugin. // Only the hardcore ones will overload read_native_scanlines with // their own implementation. size_t ystride = m_spec.scanline_bytes (true); yend = std::min (yend, spec().y+spec().height); for (int y = ybegin; y < yend; ++y) { bool ok = read_native_scanline (y, z, data); if (! ok) return false; data = (char *)data + ystride; } return true; }