bool ImageInput::read_tile (int x, int y, int z, TypeDesc format, void *data, stride_t xstride, stride_t ystride, stride_t zstride) { stride_t native_pixel_bytes = (stride_t) m_spec.pixel_bytes (true); if (format == TypeDesc::UNKNOWN && xstride == AutoStride) xstride = native_pixel_bytes; m_spec.auto_stride (xstride, ystride, zstride, format, m_spec.nchannels, m_spec.tile_width, m_spec.tile_height); bool contiguous = (xstride == native_pixel_bytes && ystride == xstride*m_spec.tile_width && (zstride == ystride*m_spec.tile_height || zstride == 0)); // If user's format and strides are set up to accept the native data // layout, read the tile directly into the user's buffer. bool rightformat = (format == TypeDesc::UNKNOWN) || (format == m_spec.format && m_spec.channelformats.empty()); if (rightformat && contiguous) return read_native_tile (x, y, z, data); // Simple case // Complex case -- either changing data type or stride int tile_values = m_spec.tile_width * m_spec.tile_height * std::max(1,m_spec.tile_depth) * m_spec.nchannels; boost::scoped_array<char> buf (new char [m_spec.tile_bytes(true)]); bool ok = read_native_tile (x, y, z, &buf[0]); if (! ok) return false; if (m_spec.channelformats.empty()) { // No per-channel formats -- do the conversion in one shot ok = contiguous ? convert_types (m_spec.format, &buf[0], format, data, tile_values) : convert_image (m_spec.nchannels, m_spec.tile_width, m_spec.tile_height, m_spec.tile_depth, &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 (size_t c = 0; c < m_spec.channelformats.size(); ++c) { TypeDesc chanformat = m_spec.channelformats[c]; ok = convert_image (1 /* channels */, m_spec.tile_width, m_spec.tile_height, m_spec.tile_depth, &buf[offset], chanformat, native_pixel_bytes, AutoStride, AutoStride, (char *)data + c*m_spec.format.size(), format, xstride, AutoStride, AutoStride); offset += chanformat.size (); } } if (! ok) error ("ImageInput::read_tile : no support for format %s", m_spec.format.c_str()); return ok; }
bool ImageInput::read_native_tiles (int xbegin, int xend, int ybegin, int yend, int zbegin, int zend, void *data) { if (! m_spec.valid_tile_range (xbegin, xend, ybegin, yend, zbegin, zend)) return false; // Base class implementation of read_native_tiles just repeatedly // calls read_native_tile, which is supplied by every plugin that // supports tiles. Only the hardcore ones will overload // read_native_tiles with their own implementation. stride_t pixel_bytes = (stride_t) m_spec.pixel_bytes (true); stride_t tileystride = pixel_bytes * m_spec.tile_width; stride_t tilezstride = tileystride * m_spec.tile_height; stride_t ystride = (xend-xbegin) * pixel_bytes; stride_t zstride = (yend-ybegin) * ystride; std::vector<char> pels (m_spec.tile_bytes(true)); for (int z = zbegin; z < zend; z += m_spec.tile_depth) { for (int y = ybegin; y < yend; y += m_spec.tile_height) { for (int x = xbegin; x < xend; x += m_spec.tile_width) { bool ok = read_native_tile (x, y, z, &pels[0]); if (! ok) return false; copy_image (m_spec.nchannels, m_spec.tile_width, m_spec.tile_height, m_spec.tile_depth, &pels[0], size_t(pixel_bytes), pixel_bytes, tileystride, tilezstride, (char *)data+ (z-zbegin)*zstride + (y-ybegin)*ystride + (x-xbegin)*pixel_bytes, pixel_bytes, ystride, zstride); } } } return true; }
bool ImageInput::read_native_tiles (int xbegin, int xend, int ybegin, int yend, int zbegin, int zend, int chbegin, int chend, void *data) { chend = clamp (chend, chbegin+1, m_spec.nchannels); int nchans = chend - chbegin; // All-channel case just reduces to the simpler read_native_scanlines. if (chbegin == 0 && chend >= m_spec.nchannels) return read_native_tiles (xbegin, xend, ybegin, yend, zbegin, zend, data); if (! m_spec.valid_tile_range (xbegin, xend, ybegin, yend, zbegin, zend)) return false; // Base class implementation of read_native_tiles just repeatedly // calls read_native_tile, which is supplied by every plugin that // supports tiles. Only the hardcore ones will overload // read_native_tiles with their own implementation. stride_t native_pixel_bytes = (stride_t) m_spec.pixel_bytes (true); stride_t native_tileystride = native_pixel_bytes * m_spec.tile_width; stride_t native_tilezstride = native_tileystride * m_spec.tile_height; size_t prefix_bytes = m_spec.pixel_bytes (0,chbegin,true); size_t subset_bytes = m_spec.pixel_bytes (chbegin,chend,true); stride_t subset_ystride = (xend-xbegin) * subset_bytes; stride_t subset_zstride = (yend-ybegin) * subset_ystride; boost::scoped_array<char> pels (new char [m_spec.tile_bytes(true)]); for (int z = zbegin; z < zend; z += m_spec.tile_depth) { for (int y = ybegin; y < yend; y += m_spec.tile_height) { for (int x = xbegin; x < xend; x += m_spec.tile_width) { bool ok = read_native_tile (x, y, z, &pels[0]); if (! ok) return false; copy_image (nchans, m_spec.tile_width, m_spec.tile_height, m_spec.tile_depth, &pels[prefix_bytes], subset_bytes, native_pixel_bytes, native_tileystride, native_tilezstride, (char *)data+ (z-zbegin)*subset_zstride + (y-ybegin)*subset_ystride + (x-xbegin)*subset_bytes, subset_bytes, subset_ystride, subset_zstride); } } } return true; }
bool ImageInput::read_tile (int x, int y, int z, TypeDesc format, void *data, stride_t xstride, stride_t ystride, stride_t zstride) { if (! m_spec.tile_width || ((x-m_spec.x) % m_spec.tile_width) != 0 || ((y-m_spec.y) % m_spec.tile_height) != 0 || ((z-m_spec.z) % m_spec.tile_depth) != 0) return false; // coordinates are not a tile corner // 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 (format == TypeDesc::UNKNOWN && xstride == AutoStride) xstride = native_pixel_bytes; m_spec.auto_stride (xstride, ystride, zstride, format, m_spec.nchannels, m_spec.tile_width, m_spec.tile_height); // 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)); contiguous &= (ystride == xstride*m_spec.tile_width && (zstride == ystride*m_spec.tile_height || zstride == 0)); // If user's format and strides are set up to accept the native data // layout, read the tile directly into the user's buffer. if (native_data && contiguous) return read_native_tile (x, y, z, data); // Simple case // Complex case -- either changing data type or stride size_t tile_values = (size_t)m_spec.tile_pixels() * m_spec.nchannels; std::vector<char> buf (m_spec.tile_bytes(true)); bool ok = read_native_tile (x, y, z, &buf[0]); if (! ok) return false; if (! perchanfile) { // No per-channel formats -- do the conversion in one shot ok = contiguous ? convert_types (m_spec.format, &buf[0], format, data, tile_values) : convert_image (m_spec.nchannels, m_spec.tile_width, m_spec.tile_height, m_spec.tile_depth, &buf[0], m_spec.format, AutoStride, AutoStride, AutoStride, data, format, xstride, ystride, zstride); } else { // Per-channel formats -- have to convert/copy channels individually if (native_data) { ASSERT (contiguous && "Per-channel native input requires contiguous strides"); } ASSERT (format != TypeDesc::UNKNOWN); ASSERT (m_spec.channelformats.size() == (size_t)m_spec.nchannels); size_t offset = 0; for (int c = 0; c < m_spec.nchannels; ++c) { TypeDesc chanformat = m_spec.channelformats[c]; ok = convert_image (1 /* channels */, m_spec.tile_width, m_spec.tile_height, m_spec.tile_depth, &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_tile : no support for format %s", m_spec.format.c_str()); return ok; }