diff --git a/src/iconvert/iconvert.cpp b/src/iconvert/iconvert.cpp index 2132935e87..56ce9c3e68 100644 --- a/src/iconvert/iconvert.cpp +++ b/src/iconvert/iconvert.cpp @@ -494,7 +494,9 @@ convert_file(const std::string& in_filename, const std::string& out_filename) } while (ok && in->seek_subimage(subimage, miplevel)); } - out->close(); + if (!out->close()) { + errorfmt("Error closing \"{}\" : {}", out_filename, out->geterror()); + } in->close(); // Figure out a time for the input file -- either one supplied by diff --git a/src/include/OpenImageIO/imageio.h b/src/include/OpenImageIO/imageio.h index 27a08b3225..82fa598969 100644 --- a/src/include/OpenImageIO/imageio.h +++ b/src/include/OpenImageIO/imageio.h @@ -2572,11 +2572,11 @@ class OIIO_API ImageOutput { /// append another subimage (`AppendSubimage`), or /// append another MIP level (`AppendMIPLevel`). /// @returns `true` upon success, or `false` upon failure. - virtual bool open (const std::string &filename, const ImageSpec &newspec, + OIIO_NODISCARD_ERROR virtual bool open (const std::string &filename, const ImageSpec &newspec, OpenMode mode=Create) = 0; /// Open an ImageOutput using a UTF-16 encoded wstring filename. - bool open (const std::wstring &filename, const ImageSpec &newspec, + OIIO_NODISCARD_ERROR bool open (const std::wstring &filename, const ImageSpec &newspec, OpenMode mode=Create) { return open(Strutil::utf16_to_utf8(filename), newspec, mode); } @@ -2603,7 +2603,7 @@ class OIIO_API ImageOutput { /// Pointer to an array of `ImageSpec` objects /// describing each of the expected subimages. /// @returns `true` upon success, or `false` upon failure. - virtual bool open (const std::string &filename, + OIIO_NODISCARD_ERROR virtual bool open (const std::string &filename, int subimages OIIO_MAYBE_UNUSED, const ImageSpec *specs) { // Default implementation: just a regular open, assume that @@ -2611,7 +2611,7 @@ class OIIO_API ImageOutput { return open (filename, specs[0]); } - bool open (const std::wstring &filename, int subimages OIIO_MAYBE_UNUSED, + OIIO_NODISCARD_ERROR bool open (const std::wstring &filename, int subimages OIIO_MAYBE_UNUSED, const ImageSpec *specs) { // Default implementation: just a regular open, assume that // appending will work. @@ -2625,7 +2625,7 @@ class OIIO_API ImageOutput { /// Closes the currently open file associated with this ImageOutput and /// frees any memory or resources associated with it. - virtual bool close () = 0; + OIIO_NODISCARD_ERROR virtual bool close () = 0; /// @} // clang-format on @@ -2687,13 +2687,14 @@ class OIIO_API ImageOutput { /// y, and z). /// @returns `true` upon success, or `false` upon failure. /// - virtual bool write_image(TypeDesc format, - const image_span& data); + OIIO_NODISCARD_ERROR virtual bool + write_image(TypeDesc format, const image_span& data); /// A version of `write_image()` taking an `image_span`, where the type /// of the underlying data is `T`. This is a convenience wrapper around /// the `write_image()` that takes an `image_span`. - template bool write_image(const image_span& data) + template + OIIO_NODISCARD_ERROR bool write_image(const image_span& data) { return write_image(TypeDescFromC::value(), as_image_span_bytes(data)); @@ -2702,7 +2703,7 @@ class OIIO_API ImageOutput { /// A version of `write_image()` taking a `cspan`, which assumes /// contiguous strides in all dimensions. This is a convenience wrapper /// around the `write_image()` that takes an `image_span`. - template bool write_image(span data) + template OIIO_NODISCARD_ERROR bool write_image(span data) { auto ispan = image_span(data.data(), m_spec.nchannels, m_spec.width, m_spec.height, @@ -2734,14 +2735,16 @@ class OIIO_API ImageOutput { /// dimension (channel, x, y, z). /// @returns `true` upon success, or `false` upon failure. /// - virtual bool write_scanline(int y, TypeDesc format, - const image_span& data); + OIIO_NODISCARD_ERROR virtual bool + write_scanline(int y, TypeDesc format, + const image_span& data); /// A version of `write_scanline()` taking an `image_span`, where the /// type of the underlying data is `T`. This is a convenience wrapper /// around the `write_scanline()` that takes an `image_span`. - template bool write_scanline(int y, const image_span& data) + template + OIIO_NODISCARD_ERROR bool write_scanline(int y, const image_span& data) { // reduce to type + image_span return write_scanline(y, TypeDescFromC::value(), @@ -2751,7 +2754,8 @@ class OIIO_API ImageOutput { /// A version of `write_scanline()` taking a `cspan`, which assumes /// contiguous strides in all dimensions. This is a convenience wrapper /// around the `write_scanline()` that takes an `image_span`. - template bool write_scanline(int y, span data) + template + OIIO_NODISCARD_ERROR bool write_scanline(int y, span data) { // reduce to type + image_span return write_scanline(y, image_span(data.data(), m_spec.nchannels, @@ -2783,8 +2787,9 @@ class OIIO_API ImageOutput { /// dimension (channel, x, y, z). /// @returns `true` upon success, or `false` upon failure. /// - virtual bool write_scanlines(int ybegin, int yend, TypeDesc format, - const image_span& data); + OIIO_NODISCARD_ERROR virtual bool + write_scanlines(int ybegin, int yend, TypeDesc format, + const image_span& data); /// A version of `write_scanlines()` taking an `image_span`, where the /// type of the underlying data is `T`. This is a convenience wrapper @@ -2802,7 +2807,8 @@ class OIIO_API ImageOutput { /// contiguous strides in all dimensions. This is a convenience wrapper /// around the `write_scanlines()` that takes an `image_span`. template - bool write_scanlines(int ybegin, int yend, span data) + OIIO_NODISCARD_ERROR bool write_scanlines(int ybegin, int yend, + span data) { auto ispan = image_span(data.data(), m_spec.nchannels, m_spec.width, yend - ybegin, 1); @@ -2839,14 +2845,16 @@ class OIIO_API ImageOutput { /// Added in OIIO 3.1, this is the "safe" preferred alternative to /// the version of write_tile that takes raw pointers. /// - virtual bool write_tile(int x, int y, int z, TypeDesc format, - const image_span& data); + OIIO_NODISCARD_ERROR virtual bool + write_tile(int x, int y, int z, TypeDesc format, + const image_span& data); /// A version of `write_tile()` taking an `image_span`, where the type /// of the underlying data is `T`. This is a convenience wrapper around /// the `write_tile()` that takes an `image_span`. template - bool write_tile(int x, int y, int z, const image_span& data) + OIIO_NODISCARD_ERROR bool write_tile(int x, int y, int z, + const image_span& data) { return write_tile(x, y, z, TypeDescFromC::value(), as_image_span_bytes(data)); @@ -2855,7 +2863,8 @@ class OIIO_API ImageOutput { /// A version of `write_tile()` taking a `cspan`, which assumes /// contiguous strides in all dimensions. This is a convenience wrapper /// around the `write_tile()` that takes an `image_span`. - template bool write_tile(int x, int y, int z, span data) + template + OIIO_NODISCARD_ERROR bool write_tile(int x, int y, int z, span data) { auto ispan = image_span(data.data(), m_spec.nchannels, m_spec.tile_width, m_spec.tile_height, @@ -2891,16 +2900,18 @@ class OIIO_API ImageOutput { /// dimension (channel, x, y, z). /// @returns `true` upon success, or `false` upon failure. /// - virtual bool write_tiles(int xbegin, int xend, int ybegin, int yend, - int zbegin, int zend, TypeDesc format, - const image_span& data); + OIIO_NODISCARD_ERROR virtual bool + write_tiles(int xbegin, int xend, int ybegin, int yend, int zbegin, + int zend, TypeDesc format, + const image_span& data); /// A version of `write_tiles()` taking an `image_span`, where the type /// of the underlying data is `T`. This is a convenience wrapper around /// the `write_tiles()` that takes an `image_span`. template - bool write_tiles(int xbegin, int xend, int ybegin, int yend, int zbegin, - int zend, const image_span& data) + OIIO_NODISCARD_ERROR bool write_tiles(int xbegin, int xend, int ybegin, + int yend, int zbegin, int zend, + const image_span& data) { return write_tiles(xbegin, xend, ybegin, yend, zbegin, zend, TypeDescFromC::value(), @@ -2911,8 +2922,9 @@ class OIIO_API ImageOutput { /// contiguous strides in all dimensions. This is a convenience wrapper /// around the `write_tiles()` that takes an `image_span`. template - bool write_tiles(int xbegin, int xend, int ybegin, int yend, int zbegin, - int zend, span data) + OIIO_NODISCARD_ERROR bool write_tiles(int xbegin, int xend, int ybegin, + int yend, int zbegin, int zend, + span data) { auto ispan = image_span(data.data(), m_spec.nchannels, xend - xbegin, yend - ybegin, zend - zbegin); @@ -2946,17 +2958,19 @@ class OIIO_API ImageOutput { /// dimension (channel, x, y, z). /// @returns `true` upon success, or `false` upon failure. /// - virtual bool write_rectangle(int xbegin, int xend, int ybegin, int yend, - int zbegin, int zend, TypeDesc format, - const image_span& data); + OIIO_NODISCARD_ERROR virtual bool + write_rectangle(int xbegin, int xend, int ybegin, int yend, int zbegin, + int zend, TypeDesc format, + const image_span& data); /// A version of `write_rectangle()` taking an `image_span`, where the /// type of the underlying data is `T`. This is a convenience wrapper /// around the `write_rectangle()` that takes an `image_span`. template - bool write_rectangle(int xbegin, int xend, int ybegin, int yend, int zbegin, - int zend, const image_span& data) + OIIO_NODISCARD_ERROR bool write_rectangle(int xbegin, int xend, int ybegin, + int yend, int zbegin, int zend, + const image_span& data) { return write_rectangle(xbegin, xend, ybegin, yend, zbegin, zend, TypeDescFromC::value(), @@ -2967,8 +2981,9 @@ class OIIO_API ImageOutput { /// contiguous strides in all dimensions. This is a convenience wrapper /// around the `write_rectangle()` that takes an `image_span`. template - bool write_rectangle(int xbegin, int xend, int ybegin, int yend, int zbegin, - int zend, span data) + OIIO_NODISCARD_ERROR bool write_rectangle(int xbegin, int xend, int ybegin, + int yend, int zbegin, int zend, + span data) { auto ispan = image_span(data.data(), m_spec.nchannels, xend - xbegin, yend - ybegin, @@ -2989,7 +3004,7 @@ class OIIO_API ImageOutput { /// @param deepdata A `DeepData` object with the data for these /// scanlines. /// @returns `true` upon success, or `false` upon failure. - virtual bool write_deep_scanlines (int ybegin, int yend, int z, + OIIO_NODISCARD_ERROR virtual bool write_deep_scanlines (int ybegin, int yend, int z, const DeepData &deepdata); /// Write the block of deep tiles that include all pixels in @@ -3012,7 +3027,7 @@ class OIIO_API ImageOutput { /// @note The call will fail if the image is not tiled, or if the pixel /// ranges do not fall along tile (or image) boundaries, or if it is not /// a valid tile range. - virtual bool write_deep_tiles (int xbegin, int xend, int ybegin, int yend, + OIIO_NODISCARD_ERROR virtual bool write_deep_tiles (int xbegin, int xend, int ybegin, int yend, int zbegin, int zend, const DeepData &deepdata); @@ -3021,7 +3036,7 @@ class OIIO_API ImageOutput { /// /// @param deepdata A `DeepData` object with the data for the image. /// @returns `true` upon success, or `false` upon failure. - virtual bool write_deep_image (const DeepData &deepdata); + OIIO_NODISCARD_ERROR virtual bool write_deep_image (const DeepData &deepdata); /// Specify a reduced-resolution ("thumbnail") version of the image. /// Note that many image formats may require the thumbnail to be @@ -3103,7 +3118,7 @@ class OIIO_API ImageOutput { /// @param xstride The distance in bytes between successive /// pixels in `data` (or `AutoStride`). /// @returns `true` upon success, or `false` upon failure. - virtual bool write_scanline (int y, int z, TypeDesc format, + OIIO_NODISCARD_ERROR virtual bool write_scanline (int y, int z, TypeDesc format, const void *data, stride_t xstride=AutoStride); /// Write multiple scanlines that include pixels (*,y,z) for all ybegin @@ -3121,7 +3136,7 @@ class OIIO_API ImageOutput { /// The distance in bytes between successive pixels /// and scanlines (or `AutoStride`). /// @returns `true` upon success, or `false` upon failure. - virtual bool write_scanlines (int ybegin, int yend, int z, + OIIO_NODISCARD_ERROR virtual bool write_scanlines (int ybegin, int yend, int z, TypeDesc format, const void *data, stride_t xstride=AutoStride, stride_t ystride=AutoStride); @@ -3147,7 +3162,7 @@ class OIIO_API ImageOutput { /// /// @note This call will fail if the image is not tiled, or if (x,y,z) /// is not the upper left corner coordinates of a tile. - virtual bool write_tile (int x, int y, int z, TypeDesc format, + OIIO_NODISCARD_ERROR virtual bool write_tile (int x, int y, int z, TypeDesc format, const void *data, stride_t xstride=AutoStride, stride_t ystride=AutoStride, stride_t zstride=AutoStride); @@ -3186,7 +3201,7 @@ class OIIO_API ImageOutput { /// @note The call will fail if the image is not tiled, or if the pixel /// ranges do not fall along tile (or image) boundaries, or if it is not /// a valid tile range. - virtual bool write_tiles (int xbegin, int xend, int ybegin, int yend, + OIIO_NODISCARD_ERROR virtual bool write_tiles (int xbegin, int xend, int ybegin, int yend, int zbegin, int zend, TypeDesc format, const void *data, stride_t xstride=AutoStride, stride_t ystride=AutoStride, @@ -3218,7 +3233,7 @@ class OIIO_API ImageOutput { /// /// @note The call will fail for a format plugin that does not return /// true for `supports("rectangles")`. - virtual bool write_rectangle (int xbegin, int xend, int ybegin, int yend, + OIIO_NODISCARD_ERROR virtual bool write_rectangle (int xbegin, int xend, int ybegin, int yend, int zbegin, int zend, TypeDesc format, const void *data, stride_t xstride=AutoStride, stride_t ystride=AutoStride, @@ -3247,7 +3262,7 @@ class OIIO_API ImageOutput { /// @param progress_callback/progress_callback_data /// Optional progress callback. /// @returns `true` upon success, or `false` upon failure. - virtual bool write_image (TypeDesc format, const void *data, + OIIO_NODISCARD_ERROR virtual bool write_image (TypeDesc format, const void *data, stride_t xstride=AutoStride, stride_t ystride=AutoStride, stride_t zstride=AutoStride, @@ -3283,7 +3298,7 @@ class OIIO_API ImageOutput { /// /// @param in A pointer to the open `ImageInput` to read from. /// @returns `true` upon success, or `false` upon failure. - virtual bool copy_image (ImageInput *in); + OIIO_NODISCARD_ERROR virtual bool copy_image (ImageInput *in); // General message passing between client and image output server. This // is currently undefined and is reserved for future use. diff --git a/src/libOpenImageIO/imagebuf.cpp b/src/libOpenImageIO/imagebuf.cpp index abd6f696bf..aa8bd9e8b8 100644 --- a/src/libOpenImageIO/imagebuf.cpp +++ b/src/libOpenImageIO/imagebuf.cpp @@ -1811,7 +1811,10 @@ ImageBuf::write(string_view _filename, TypeDesc dtype, string_view _fileformat, } if (!write(out.get(), progress_callback, progress_callback_data)) return false; - out->close(); + if (!out->close()) { + error(out->geterror()); + return false; + } if (progress_callback) progress_callback(progress_callback_data, 0); return true; diff --git a/src/libOpenImageIO/imagebufalgo_test.cpp b/src/libOpenImageIO/imagebufalgo_test.cpp index e14d511cba..9bfec616f6 100644 --- a/src/libOpenImageIO/imagebufalgo_test.cpp +++ b/src/libOpenImageIO/imagebufalgo_test.cpp @@ -1613,7 +1613,7 @@ test_demosaic_algo(const ImageBuf& src_image, const ImageBuf& mosaiced_image, std::string ext = type.is_floating_point() ? "exr" : "png"; std::string path = file_name + "_" + test_name + "." + ext; auto imageOutput = ImageOutput::create(ext); - imageOutput->open(path, demosaiced_image.spec()); + (void)imageOutput->open(path, demosaiced_image.spec()); demosaiced_image.write(imageOutput.get()); } } @@ -1650,7 +1650,7 @@ test_demosaic(const DemosaicTestConfig& config, const ImageBuf& src_image, std::string path = file_name + "_src." + ext; auto imageOutput = ImageOutput::create(ext); - imageOutput->open(path, mosaiced_image.spec()); + (void)imageOutput->open(path, mosaiced_image.spec()); mosaiced_image.write(imageOutput.get()); } @@ -1741,7 +1741,7 @@ test_demosaic() if (write_files) { auto imageOutput = OIIO::ImageOutput::create("exr"); - imageOutput->open("source.exr", src_image.spec()); + (void)imageOutput->open("source.exr", src_image.spec()); src_image.write(imageOutput.get()); } diff --git a/src/libOpenImageIO/imagespeed_test.cpp b/src/libOpenImageIO/imagespeed_test.cpp index 3e0ad38478..2aff99e690 100644 --- a/src/libOpenImageIO/imagespeed_test.cpp +++ b/src/libOpenImageIO/imagespeed_test.cpp @@ -187,7 +187,8 @@ time_write_image() OIIO_ASSERT(out); bool ok = out->open(output_filename, outspec); OIIO_ASSERT(ok); - out->write_image(bufspec.format, &buffer[0]); + ok = out->write_image(bufspec.format, &buffer[0]); + OIIO_CONTRACT_ASSERT(ok); } @@ -202,9 +203,10 @@ time_write_scanline_at_a_time() size_t pixelsize = outspec.nchannels * sizeof(float); imagesize_t scanlinesize = outspec.width * pixelsize; + bool ok = true; for (int y = 0; y < outspec.height; ++y) { - out->write_scanline(y + outspec.y, outspec.z, bufspec.format, - &buffer[scanlinesize * y]); + ok = out->write_scanline(y + outspec.y, outspec.z, bufspec.format, + &buffer[scanlinesize * y]); } } @@ -221,11 +223,11 @@ time_write_64_scanlines_at_a_time() size_t pixelsize = outspec.nchannels * sizeof(float); imagesize_t scanlinesize = outspec.width * pixelsize; for (int y = 0; y < outspec.height; y += 64) { - out->write_scanlines(y + outspec.y, - std::min(y + outspec.y + 64, - outspec.y + outspec.height), - outspec.z, bufspec.format, - &buffer[scanlinesize * y]); + (void)out->write_scanlines(y + outspec.y, + std::min(y + outspec.y + 64, + outspec.y + outspec.height), + outspec.z, bufspec.format, + &buffer[scanlinesize * y]); } } @@ -242,13 +244,14 @@ time_write_tile_at_a_time() size_t pixelsize = outspec.nchannels * sizeof(float); imagesize_t scanlinesize = outspec.width * pixelsize; imagesize_t planesize = outspec.height * scanlinesize; + bool ok = true; for (int z = 0; z < outspec.depth; z += outspec.tile_depth) { for (int y = 0; y < outspec.height; y += outspec.tile_height) { for (int x = 0; x < outspec.width; x += outspec.tile_width) { - out->write_tile(x + outspec.x, y + outspec.y, z + outspec.z, - bufspec.format, - &buffer[scanlinesize * y + pixelsize * x], - pixelsize, scanlinesize, planesize); + ok = out->write_tile(x + outspec.x, y + outspec.y, + z + outspec.z, bufspec.format, + &buffer[scanlinesize * y + pixelsize * x], + pixelsize, scanlinesize, planesize); } } } @@ -266,13 +269,17 @@ time_write_tiles_row_at_a_time() size_t pixelsize = outspec.nchannels * sizeof(float); imagesize_t scanlinesize = outspec.width * pixelsize; + bool ok = true; for (int z = 0; z < outspec.depth; z += outspec.tile_depth) { for (int y = 0; y < outspec.height; y += outspec.tile_height) { - out->write_tiles(outspec.x, outspec.x + outspec.width, - y + outspec.y, y + outspec.y + outspec.tile_height, - z + outspec.z, z + outspec.z + outspec.tile_depth, - bufspec.format, &buffer[scanlinesize * y], - pixelsize /*xstride*/, scanlinesize /*ystride*/); + ok = out->write_tiles(outspec.x, outspec.x + outspec.width, + y + outspec.y, + y + outspec.y + outspec.tile_height, + z + outspec.z, + z + outspec.z + outspec.tile_depth, + bufspec.format, &buffer[scanlinesize * y], + pixelsize /*xstride*/, + scanlinesize /*ystride*/); } } } diff --git a/src/libOpenImageIO/maketexture.cpp b/src/libOpenImageIO/maketexture.cpp index 533cf7dc61..99ee3d660e 100644 --- a/src/libOpenImageIO/maketexture.cpp +++ b/src/libOpenImageIO/maketexture.cpp @@ -792,7 +792,9 @@ write_mipmap(ImageBufAlgo::MakeTextureMode mode, std::shared_ptr& img, // ImageBuf::write transfers any errors from the ImageOutput to // the ImageBuf. errorfmt("Write failed: {}", img->geterror()); - out->close(); + if (!out->close()) { + errorfmt("Close failed: {}", out->geterror()); + } return false; } @@ -965,7 +967,9 @@ write_mipmap(ImageBufAlgo::MakeTextureMode mode, std::shared_ptr& img, // ImageOutput to the ImageBuf. errorfmt("Error writing \"{}\" : {}", outputfilename, small->geterror()); - out->close(); + if (!out->close()) { + errorfmt("Close failed: {}", out->geterror()); + } return false; } double wtime = writetimer(); diff --git a/src/python/py_imagebuf.cpp b/src/python/py_imagebuf.cpp index a35d9bbd05..540b077185 100644 --- a/src/python/py_imagebuf.cpp +++ b/src/python/py_imagebuf.cpp @@ -273,7 +273,9 @@ ImageBuf_repr_png(const ImageBuf& self) if (!out || !out->open("temp.png", altered_spec)) return py::bytes(); self.write(out.get()); - out->close(); + if (!out->close()) { + return py::bytes(); + } // Cast to const char* and return as python bytes const char* char_ptr = reinterpret_cast(file_buffer.data());