From 3549783b37a9d831997f9c39a2a8d5affcbf2c50 Mon Sep 17 00:00:00 2001 From: Delio Vicini Date: Wed, 15 Nov 2023 08:38:29 +0100 Subject: [PATCH] Remove error on reads over MemoryStream's size. This makes MemoryStream consistent with FileStream for reads beyond the maximum size. This is needed for the MemoryStream to be compatible with all image file formats. In particular, the JPEG library reads beyond the specified maximum buffer size. Previously, this meant that a JPEG could not easily be deserialized from a MemoryStream. --- src/core/mstream.cpp | 10 +++------- src/core/tests/test_bitmap.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/core/mstream.cpp b/src/core/mstream.cpp index 8d3f73552..d2d155009 100644 --- a/src/core/mstream.cpp +++ b/src/core/mstream.cpp @@ -23,20 +23,16 @@ void MemoryStream::read(void *p, size_t size) { Throw("Attempted to read from a closed stream: %s", to_string()); if (m_pos + size > m_size) { - const auto old_pos = m_pos; // Use signed difference since `m_pos` might be beyond `m_size` int64_t size_read = m_size - static_cast(m_pos); if (size_read > 0) { memcpy(p, m_data + m_pos, static_cast(size_read)); m_pos += static_cast(size_read); } - Log(Error, "Reading over the end of a memory stream!" - " (amount requested = %llu, amount actually read = %llu," - " total size of the stream = %llu, previous position = %llu)", - size, size_read, m_size, old_pos); + } else { + memcpy(p, m_data + m_pos, size); + m_pos += size; } - memcpy(p, m_data + m_pos, size); - m_pos += size; } void MemoryStream::write(const void *p, size_t size) { diff --git a/src/core/tests/test_bitmap.py b/src/core/tests/test_bitmap.py index 831e45f4c..dc3365cc9 100644 --- a/src/core/tests/test_bitmap.py +++ b/src/core/tests/test_bitmap.py @@ -221,6 +221,34 @@ def test_read_tga(variant_scalar_rgb): assert b1 == b2 +@pytest.mark.parametrize('file_format', + [mi.scalar_rgb.Bitmap.FileFormat.JPEG, + mi.scalar_rgb.Bitmap.FileFormat.PPM, + mi.scalar_rgb.Bitmap.FileFormat.PNG]) +def test_read_write_memorystream_uint8(variant_scalar_rgb, np_rng, file_format): + ref = np.uint8(np_rng.random((10, 10, 3)) * 255) + b = mi.Bitmap(ref) + stream = mi.MemoryStream() + b.write(stream, file_format) + stream.seek(0) + b2 = mi.Bitmap(stream) + assert np.sum(np.abs(np.float32(np.array(b2))-ref)) / (3*10*10*255) < 0.2 + + +@pytest.mark.parametrize('file_format', + [mi.scalar_rgb.Bitmap.FileFormat.OpenEXR, + mi.scalar_rgb.Bitmap.FileFormat.RGBE, + mi.scalar_rgb.Bitmap.FileFormat.PFM]) +def test_read_write_memorystream_float32(variant_scalar_rgb, np_rng, file_format): + ref = np.float32(np_rng.random((10, 10, 3))) + b = mi.Bitmap(ref) + stream = mi.MemoryStream() + b.write(stream, file_format) + stream.seek(0) + b2 = mi.Bitmap(stream) + assert np.abs(np.mean(np.array(b2)-ref)) < 1e-2 + + def test_accumulate(variant_scalar_rgb): # ----- Accumulate the whole bitmap b1 = mi.Bitmap(mi.Bitmap.PixelFormat.RGB, mi.Struct.Type.UInt8, [10, 10])