@@ -286,6 +286,37 @@ ImageInput::read_scanline(int y, int z, TypeDesc format, void* data,
286286
287287
288288
289+ bool
290+ ImageInput::read_scanlines (int subimage, int miplevel, int ybegin, int yend,
291+ int chbegin, int chend, TypeDesc format,
292+ const image_span<std::byte>& data)
293+ {
294+ ImageSpec spec = spec_dimensions (subimage, miplevel);
295+ if (chend < 0 || chend > spec.nchannels )
296+ chend = spec.nchannels ;
297+ if (chbegin < 0 || chbegin >= chend) {
298+ errorfmt (" read_scanlines: invalid channel range [{},{})" , chbegin,
299+ chend);
300+ return false ;
301+ }
302+ size_t isize = (format == TypeUnknown
303+ ? spec.pixel_bytes (chbegin, chend, true /* native*/ )
304+ : format.size () * (chend - chbegin))
305+ * size_t (spec.width );
306+ if (isize != data.size_bytes ()) {
307+ errorfmt (
308+ " read_scanlines: Buffer size is incorrect ({} bytes vs {} needed)" ,
309+ isize, data.size_bytes ());
310+ return false ;
311+ }
312+
313+ // Default implementation (for now): call the old pointer+stride
314+ return read_scanlines (subimage, miplevel, ybegin, yend, 0 , chbegin, chend,
315+ format, data.data (), data.xstride ());
316+ }
317+
318+
319+
289320bool
290321ImageInput::read_scanlines (int subimage, int miplevel, int ybegin, int yend,
291322 int z, int chbegin, int chend, TypeDesc format,
@@ -611,6 +642,38 @@ ImageInput::read_tile(int x, int y, int z, TypeDesc format, void* data,
611642
612643
613644
645+ bool
646+ ImageInput::read_tiles (int subimage, int miplevel, int xbegin, int xend,
647+ int ybegin, int yend, int zbegin, int zend, int chbegin,
648+ int chend, TypeDesc format,
649+ const image_span<std::byte>& data)
650+ {
651+ ImageSpec spec = spec_dimensions (subimage, miplevel);
652+ if (chend < 0 || chend > spec.nchannels )
653+ chend = spec.nchannels ;
654+ if (chbegin < 0 || chbegin >= chend) {
655+ errorfmt (" read_tiles: invalid channel range [{},{})" , chbegin, chend);
656+ return false ;
657+ }
658+ size_t isize = (format == TypeUnknown
659+ ? spec.pixel_bytes (chbegin, chend, true /* native*/ )
660+ : format.size () * (chend - chbegin))
661+ * size_t (xend - xbegin) * size_t (yend - ybegin)
662+ * size_t (zend - zbegin);
663+ if (isize != data.size_bytes ()) {
664+ errorfmt (" read_tiles: Buffer size is incorrect ({} bytes vs {} needed)" ,
665+ isize, data.size_bytes ());
666+ return false ;
667+ }
668+
669+ // Default implementation (for now): call the old pointer+stride
670+ return read_tiles (subimage, miplevel, ybegin, yend, xbegin, xend, zbegin,
671+ zend, chbegin, chend, format, data.data (),
672+ data.xstride ());
673+ }
674+
675+
676+
614677bool
615678ImageInput::read_tiles (int subimage, int miplevel, int xbegin, int xend,
616679 int ybegin, int yend, int zbegin, int zend, int chbegin,
@@ -1096,6 +1159,110 @@ ImageInput::read_image(int subimage, int miplevel, int chbegin, int chend,
10961159
10971160
10981161
1162+ bool
1163+ ImageInput::read_image (int subimage, int miplevel, int chbegin, int chend,
1164+ TypeDesc format, const image_span<std::byte>& data)
1165+ {
1166+ #if 0
1167+ ImageSpec spec = spec_dimensions(subimage, miplevel);
1168+ if (chend < 0 || chend > spec.nchannels)
1169+ chend = spec.nchannels;
1170+ size_t isize = (format == TypeUnknown
1171+ ? spec.pixel_bytes(chbegin, chend, true /*native*/)
1172+ : format.size() * (chend - chbegin))
1173+ * spec.image_pixels();
1174+ if (isize != data.size_bytes()) {
1175+ errorfmt("read_image: Buffer size is incorrect ({} bytes vs {} needed)",
1176+ sz, data.size_bytes());
1177+ return false;
1178+ }
1179+
1180+ // Default implementation (for now): call the old pointer+stride
1181+ return read_image(subimage, miplevel, chbegin, chend, format, data.data(),
1182+ data.xstride(), data.ystride(), data.zstride());
1183+ #else
1184+ pvt::LoggedTimer logtime (" II::read_image" );
1185+ ImageSpec spec;
1186+ int rps = 0 ;
1187+ {
1188+ // We need to lock briefly to retrieve rps from the spec
1189+ lock_guard lock (*this );
1190+ if (!seek_subimage (subimage, miplevel))
1191+ return false ;
1192+ // Copying the dimensions of the designated subimage/miplevel to a
1193+ // local `spec` means that we can release the lock! (Calls to
1194+ // read_native_* will internally lock again if necessary.)
1195+ spec.copy_dimensions (m_spec);
1196+ // For scanline files, we also need one piece of metadata
1197+ if (!spec.tile_width )
1198+ rps = m_spec.get_int_attribute (" tiff:RowsPerStrip" , 64 );
1199+ }
1200+ if (spec.image_bytes () < 1 ) {
1201+ errorfmt (" Invalid image size {} x {} ({} chans)" , m_spec.width ,
1202+ m_spec.height , m_spec.nchannels );
1203+ return false ;
1204+ }
1205+
1206+ if (chend < 0 || chend > spec.nchannels )
1207+ chend = spec.nchannels ;
1208+ if (chbegin < 0 || chbegin >= chend) {
1209+ errorfmt (" read_image: invalid channel range [{},{})" , chbegin, chend);
1210+ return false ;
1211+ }
1212+ int nchans = chend - chbegin;
1213+ bool native = (format == TypeUnknown);
1214+ size_t pixel_bytes = native ? spec.pixel_bytes (chbegin, chend, native)
1215+ : (format.size () * nchans);
1216+ size_t isize = pixel_bytes * spec.image_pixels ();
1217+ if (isize != data.size_bytes ()) {
1218+ errorfmt (" read_image: Buffer size is incorrect ({} bytes vs {} needed)" ,
1219+ isize, data.size_bytes ());
1220+ return false ;
1221+ }
1222+
1223+ bool ok = true ;
1224+ if (spec.tile_width ) { // Tiled image -- rely on read_tiles
1225+ // Read in chunks of a whole row of tiles at once. If tiles are
1226+ // 64x64, a 2k image has 32 tiles across. That's fine for now (for
1227+ // parallelization purposes), but as typical core counts increase,
1228+ // we may someday want to revisit this to batch multiple rows.
1229+ for (int z = 0 ; z < spec.depth ; z += spec.tile_depth ) {
1230+ int zend = std::min (z + spec.z + spec.tile_depth ,
1231+ spec.z + spec.depth );
1232+ for (int y = 0 ; y < spec.height && ok; y += spec.tile_height ) {
1233+ int yend = std::min (y + spec.y + spec.tile_height ,
1234+ spec.y + spec.height );
1235+ ok &= read_tiles (subimage, miplevel, spec.x ,
1236+ spec.x + spec.width , y + spec.y , yend,
1237+ z + spec.z , zend, chbegin, chend, format,
1238+ data.subspan (spec.x , spec.x + spec.width ,
1239+ y + spec.y , yend, z + spec.z ,
1240+ zend));
1241+ }
1242+ }
1243+ } else { // Scanline image -- rely on read_scanlines.
1244+ // Split into reasonable chunks -- try to use around 64 MB or the
1245+ // oiio_read_chunk value, which ever is bigger, but also round up to
1246+ // a multiple of the TIFF rows per strip (or 64).
1247+ int chunk = std::max (1 , (1 << 26 ) / int (spec.scanline_bytes (true )));
1248+ chunk = std::max (chunk, int (oiio_read_chunk));
1249+ chunk = round_to_multiple (chunk, rps);
1250+ for (int z = 0 ; z < spec.depth ; ++z) {
1251+ for (int y = 0 ; y < spec.height && ok; y += chunk) {
1252+ int yend = std::min (y + spec.y + chunk, spec.y + spec.height );
1253+ ok &= read_scanlines (subimage, miplevel, y + spec.y , yend,
1254+ chbegin, chend, format,
1255+ data.subspan (spec.x , spec.x + spec.width ,
1256+ y + spec.y , yend));
1257+ }
1258+ }
1259+ }
1260+ return ok;
1261+ #endif
1262+ }
1263+
1264+
1265+
10991266bool
11001267ImageInput::read_native_deep_scanlines (int /* subimage*/ , int /* miplevel*/ ,
11011268 int /* ybegin*/ , int /* yend*/ , int /* z*/ ,
0 commit comments