@@ -211,6 +211,40 @@ ImageInput::spec_dimensions(int subimage, int miplevel)
211211
212212
213213
214+ // Utility: Make sure the provided data span is the right size for the
215+ // image described by spec and datatype. If they don't match, issue an
216+ // error and return false.
217+ static bool
218+ check_span_size (ImageInput* in, string_view caller, const ImageSpec& spec,
219+ TypeDesc datatype, imagesize_t npixels, int chbegin, int chend,
220+ const image_span<std::byte>& data)
221+ {
222+ // One of two things must be correct: Either format is Unknown and the
223+ // total byte size needs to match the "native" size, or the format is
224+ // concrete and the number of value must match (it's ok if the size
225+ // doesn't match, since a data type conversion will occur).
226+ if (datatype.is_unknown ()) { // Unknown assumes native chan types
227+ size_t sz = npixels * spec.pixel_bytes (chbegin, chend, true );
228+ if (sz != data.size_bytes ()) {
229+ in->errorfmt (
230+ " {}: image_span size is incorrect ({} bytes vs {} needed)" ,
231+ caller, data.size_bytes (), sz);
232+ return false ;
233+ }
234+ } else { // single concrete type
235+ size_t nvals = npixels * size_t (chend - chbegin);
236+ if (nvals != data.nvalues ()) {
237+ in->errorfmt (
238+ " {}: image_span size is incorrect ({} values vs {} needed)" ,
239+ caller, data.nvalues (), nvals);
240+ return false ;
241+ }
242+ }
243+ return true ;
244+ }
245+
246+
247+
214248bool
215249ImageInput::read_scanline (int y, int z, TypeDesc format, void * data,
216250 stride_t xstride)
@@ -300,16 +334,10 @@ ImageInput::read_scanlines(int subimage, int miplevel, int ybegin, int yend,
300334 chend);
301335 return false ;
302336 }
303- size_t isize = (format == TypeUnknown
304- ? spec.pixel_bytes (chbegin, chend, true /* native*/ )
305- : format.size () * (chend - chbegin))
306- * size_t (spec.width );
307- if (isize != data.size_bytes ()) {
308- errorfmt (
309- " read_scanlines: Buffer size is incorrect ({} bytes vs {} needed)" ,
310- isize, data.size_bytes ());
337+ if (!check_span_size (this , " read_scanlines" , m_spec, format,
338+ m_spec.width * size_t (yend - ybegin), chbegin, chend,
339+ data))
311340 return false ;
312- }
313341
314342 // Default implementation (for now): call the old pointer+stride
315343 return read_scanlines (subimage, miplevel, ybegin, yend, 0 , chbegin, chend,
@@ -656,16 +684,11 @@ ImageInput::read_tiles(int subimage, int miplevel, int xbegin, int xend,
656684 errorfmt (" read_tiles: invalid channel range [{},{})" , chbegin, chend);
657685 return false ;
658686 }
659- size_t isize = (format == TypeUnknown
660- ? spec.pixel_bytes (chbegin, chend, true /* native*/ )
661- : format.size () * (chend - chbegin))
662- * size_t (xend - xbegin) * size_t (yend - ybegin)
663- * size_t (zend - zbegin);
664- if (isize != data.size_bytes ()) {
665- errorfmt (" read_tiles: Buffer size is incorrect ({} bytes vs {} needed)" ,
666- isize, data.size_bytes ());
687+ if (!check_span_size (this , " read_tiles" , m_spec, format,
688+ size_t (xend - xbegin) * size_t (yend - ybegin)
689+ * size_t (zend - zbegin),
690+ chbegin, chend, data))
667691 return false ;
668- }
669692
670693 // Default implementation (for now): call the old pointer+stride
671694 return read_tiles (subimage, miplevel, ybegin, yend, xbegin, xend, zbegin,
@@ -1164,24 +1187,6 @@ bool
11641187ImageInput::read_image (int subimage, int miplevel, int chbegin, int chend,
11651188 TypeDesc format, const image_span<std::byte>& data)
11661189{
1167- #if 0
1168- ImageSpec spec = spec_dimensions(subimage, miplevel);
1169- if (chend < 0 || chend > spec.nchannels)
1170- chend = spec.nchannels;
1171- size_t isize = (format == TypeUnknown
1172- ? spec.pixel_bytes(chbegin, chend, true /*native*/)
1173- : format.size() * (chend - chbegin))
1174- * spec.image_pixels();
1175- if (isize != data.size_bytes()) {
1176- errorfmt("read_image: Buffer size is incorrect ({} bytes vs {} needed)",
1177- sz, data.size_bytes());
1178- return false;
1179- }
1180-
1181- // Default implementation (for now): call the old pointer+stride
1182- return read_image(subimage, miplevel, chbegin, chend, format, data.data(),
1183- data.xstride(), data.ystride(), data.zstride());
1184- #else
11851190 OIIO::pvt::LoggedTimer logtime (" II::read_image" );
11861191 ImageSpec spec;
11871192 int rps = 0 ;
@@ -1210,16 +1215,9 @@ ImageInput::read_image(int subimage, int miplevel, int chbegin, int chend,
12101215 errorfmt (" read_image: invalid channel range [{},{})" , chbegin, chend);
12111216 return false ;
12121217 }
1213- int nchans = chend - chbegin;
1214- bool native = (format == TypeUnknown);
1215- size_t pixel_bytes = native ? spec.pixel_bytes (chbegin, chend, native)
1216- : (format.size () * nchans);
1217- size_t isize = pixel_bytes * spec.image_pixels ();
1218- if (isize != data.size_bytes ()) {
1219- errorfmt (" read_image: Buffer size is incorrect ({} bytes vs {} needed)" ,
1220- isize, data.size_bytes ());
1218+ if (!check_span_size (this , " read_image" , m_spec, format,
1219+ spec.image_pixels (), chbegin, chend, data))
12211220 return false ;
1222- }
12231221
12241222 bool ok = true ;
12251223 if (spec.tile_width ) { // Tiled image -- rely on read_tiles
@@ -1259,7 +1257,6 @@ ImageInput::read_image(int subimage, int miplevel, int chbegin, int chend,
12591257 }
12601258 }
12611259 return ok;
1262- #endif
12631260}
12641261
12651262
0 commit comments