diff --git a/src/libOpenImageIO/imageinput.cpp b/src/libOpenImageIO/imageinput.cpp index e9b9b78a24..b9bd5c6f4c 100644 --- a/src/libOpenImageIO/imageinput.cpp +++ b/src/libOpenImageIO/imageinput.cpp @@ -32,6 +32,14 @@ static thread_local tsl::robin_map input_error_messages; static std::atomic_int64_t input_next_id(0); +static int +safe_rows_per_strip(const ImageSpec& spec) +{ + int rps = spec.get_int_attribute("tiff:RowsPerStrip", 64); + return rps > 0 ? rps : 64; +} + + class ImageInput::Impl { public: Impl() @@ -365,7 +373,7 @@ ImageInput::read_scanlines(int subimage, int miplevel, int ybegin, int yend, spec.copy_dimensions(m_spec); // For scanline files, we also need one piece of metadata if (!spec.tile_width) - rps = m_spec.get_int_attribute("tiff:RowsPerStrip", 64); + rps = safe_rows_per_strip(m_spec); // FIXME: does the above search of metadata have a significant cost? } if (spec.image_bytes() < 1) { @@ -1108,7 +1116,7 @@ ImageInput::read_image(int subimage, int miplevel, int chbegin, int chend, spec.copy_dimensions(m_spec); // For scanline files, we also need one piece of metadata if (!spec.tile_width) - rps = m_spec.get_int_attribute("tiff:RowsPerStrip", 64); + rps = safe_rows_per_strip(m_spec); } if (spec.image_bytes() < 1) { errorfmt("Invalid image size {} x {} ({} chans)", m_spec.width, @@ -1201,7 +1209,7 @@ ImageInput::read_image(int subimage, int miplevel, int chbegin, int chend, spec.copy_dimensions(m_spec); // For scanline files, we also need one piece of metadata if (!spec.tile_width) - rps = m_spec.get_int_attribute("tiff:RowsPerStrip", 64); + rps = safe_rows_per_strip(m_spec); } if (spec.image_bytes() < 1) { errorfmt("Invalid image size {} x {} ({} chans)", m_spec.width, diff --git a/src/libOpenImageIO/imageoutput.cpp b/src/libOpenImageIO/imageoutput.cpp index 216c2a18f9..e66be4869b 100644 --- a/src/libOpenImageIO/imageoutput.cpp +++ b/src/libOpenImageIO/imageoutput.cpp @@ -26,6 +26,16 @@ OIIO_NAMESPACE_3_1_BEGIN + + +static int +safe_rows_per_strip(const ImageSpec& spec) +{ + int rps = spec.get_int_attribute("tiff:RowsPerStrip", 64); + return rps > 0 ? rps : 64; +} + + using namespace pvt; using namespace OIIO::pvt; @@ -665,7 +675,7 @@ ImageOutput::write_image(TypeDesc format, const void* data, stride_t xstride, } else { // Scanline image // Split into reasonable chunks -- try to use around 64 MB, but // round up to a multiple of the TIFF rows per strip (or 64). - int rps = m_spec.get_int_attribute("tiff:RowsPerStrip", 64); + int rps = safe_rows_per_strip(m_spec); int chunk = std::max(1, (1 << 26) / int(m_spec.scanline_bytes(true))); chunk = round_to_multiple(chunk, rps); diff --git a/testsuite/invalid-rps-metadata/ref/out.txt b/testsuite/invalid-rps-metadata/ref/out.txt new file mode 100644 index 0000000000..a4da6348d0 --- /dev/null +++ b/testsuite/invalid-rps-metadata/ref/out.txt @@ -0,0 +1,14 @@ +Reading negrps.tif +negrps.tif : 1 x 1, 3 channel, float tiff + SHA-1: 2771C32B635C7C7154A48DBE4F54B3449ABC6B50 + channel list: R, G, B + compression: "zip" + DateTime: "2026:07:03 07:11:01" + Orientation: 1 (normal) + planarconfig: "contig" + Software: "OpenImageIO 3.2.0.2dev : 2C50DDDC920616B428C03D5F6786B396201DAF23" + oiio:BitsPerSample: 32 + tiff:Compression: 8 + tiff:PhotometricInterpretation: 2 + tiff:PlanarConfiguration: 1 + tiff:RowsPerStrip: 32 diff --git a/testsuite/invalid-rps-metadata/run.py b/testsuite/invalid-rps-metadata/run.py new file mode 100644 index 0000000000..09d10d4d1f --- /dev/null +++ b/testsuite/invalid-rps-metadata/run.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python + +# Copyright Contributors to the OpenImageIO project. +# SPDX-License-Identifier: Apache-2.0 +# https://github.com/AcademySoftwareFoundation/OpenImageIO + +# save the error output +redirect = " >> out.txt 2>&1 " +failureok = 1 + +# command += oiiotool("-create 2x2 3 -d half -attrib tiff:RowsPerStrip -3 -o negrps.exr") +command += oiiotool("src/rowsperstrip-zero.exr -o negrps.tif") +command += info_command("negrps.tif", verbose=True, hash=True) diff --git a/testsuite/invalid-rps-metadata/src/rowsperstrip-zero.exr b/testsuite/invalid-rps-metadata/src/rowsperstrip-zero.exr new file mode 100644 index 0000000000..2372c31c5a Binary files /dev/null and b/testsuite/invalid-rps-metadata/src/rowsperstrip-zero.exr differ