diff --git a/src/libOpenImageIO/maketexture.cpp b/src/libOpenImageIO/maketexture.cpp index 4b65bb9653..d8e909217e 100644 --- a/src/libOpenImageIO/maketexture.cpp +++ b/src/libOpenImageIO/maketexture.cpp @@ -606,6 +606,13 @@ write_mipmap(ImageBufAlgo::MakeTextureMode mode, std::shared_ptr& img, ImageSpec outspec = outspec_template; outspec.set_format(outputdatatype); + // Going from float to half is prone to generating Inf values if we had + // any floats that were out of the range that half can represent. Nobody + // wants Inf in textures; better to clamp. + bool clamp_half = (outspec.format == TypeHalf + && (img->spec().format == TypeFloat + || img->spec().format == TypeHalf)); + if (mipmap && !out->supports("multiimage") && !out->supports("mipmap")) { outstream << "maketx ERROR: \"" << outputfilename << "\" format does not support multires images\n"; @@ -673,6 +680,11 @@ write_mipmap(ImageBufAlgo::MakeTextureMode mode, std::shared_ptr& img, outstream << " Top level is " << formatres(outspec) << std::endl; } + if (clamp_half) { + std::shared_ptr tmp(new ImageBuf); + ImageBufAlgo::clamp(*tmp, *img, -HALF_MAX, HALF_MAX, true); + std::swap(tmp, img); + } if (!img->write(out)) { // ImageBuf::write transfers any errors from the ImageOutput to // the ImageBuf. @@ -810,6 +822,8 @@ write_mipmap(ImageBufAlgo::MakeTextureMode mode, std::shared_ptr& img, Filter2D::destroy(filter); } } + if (clamp_half) + ImageBufAlgo::clamp(*small, *small, -HALF_MAX, HALF_MAX, true); stat_miptime += miptimer(); outspec = smallspec; diff --git a/testsuite/oiiotool-maketx/ref/out-win.txt b/testsuite/oiiotool-maketx/ref/out-win.txt index 6efce01fbe..47bc37962d 100644 --- a/testsuite/oiiotool-maketx/ref/out-win.txt +++ b/testsuite/oiiotool-maketx/ref/out-win.txt @@ -289,6 +289,48 @@ nan.exr : 64 x 64, 3 channel, half openexr Stats FiniteCount: 4096 4096 4096 Constant: No Monochrome: Yes +Reading bigval.exr +bigval.exr : 2 x 2, 3 channel, half openexr + MIP-map levels: 2x2 1x1 + SHA-1: 9DBE885D25443B9CDDC4BAC5997162861B5B3F15 + channel list: R, G, B + tile size: 64 x 64 + compression: "zip" + fovcot: 1 + Orientation: 1 (normal) + PixelAspectRatio: 1 + screenWindowCenter: 0, 0 + screenWindowWidth: 1 + textureformat: "Plain Texture" + wrapmodes: "black,black" + oiio:AverageColor: "1e+06,1e+06,1e+06" + oiio:ColorSpace: "Linear" + oiio:ConstantColor: "1e+06,1e+06,1e+06" + oiio:SHA-1: "E3D97EED7EE68F1885685F312DDD7D8773C29862" + oiio:subimages: 1 + openexr:roundingmode: 0 + MIP 0 of 2 (2 x 2): + Stats Min: 65504.000000 65504.000000 65504.000000 (float) + Stats Max: 65504.000000 65504.000000 65504.000000 (float) + Stats Avg: 65504.000000 65504.000000 65504.000000 (float) + Stats StdDev: 0.000000 0.000000 0.000000 (float) + Stats NanCount: 0 0 0 + Stats InfCount: 0 0 0 + Stats FiniteCount: 4 4 4 + Constant: Yes + Constant Color: 65504.000000 65504.000000 65504.000000 (float) + Monochrome: Yes + MIP 1 of 2 (1 x 1): + Stats Min: 65504.000000 65504.000000 65504.000000 (float) + Stats Max: 65504.000000 65504.000000 65504.000000 (float) + Stats Avg: 65504.000000 65504.000000 65504.000000 (float) + Stats StdDev: 0.000000 0.000000 0.000000 (float) + Stats NanCount: 0 0 0 + Stats InfCount: 0 0 0 + Stats FiniteCount: 1 1 1 + Constant: Yes + Constant Color: 65504.000000 65504.000000 65504.000000 (float) + Monochrome: Yes Reading checker-exr.pdq checker-exr.pdq : 128 x 128, 4 channel, half openexr MIP-map levels: 128x128 64x64 32x32 16x16 8x8 4x4 2x2 1x1 diff --git a/testsuite/oiiotool-maketx/ref/out.txt b/testsuite/oiiotool-maketx/ref/out.txt index 9ae67d4653..3ab19edca3 100644 --- a/testsuite/oiiotool-maketx/ref/out.txt +++ b/testsuite/oiiotool-maketx/ref/out.txt @@ -289,6 +289,48 @@ nan.exr : 64 x 64, 3 channel, half openexr Stats FiniteCount: 4096 4096 4096 Constant: No Monochrome: Yes +Reading bigval.exr +bigval.exr : 2 x 2, 3 channel, half openexr + MIP-map levels: 2x2 1x1 + SHA-1: 9DBE885D25443B9CDDC4BAC5997162861B5B3F15 + channel list: R, G, B + tile size: 64 x 64 + compression: "zip" + fovcot: 1 + Orientation: 1 (normal) + PixelAspectRatio: 1 + screenWindowCenter: 0, 0 + screenWindowWidth: 1 + textureformat: "Plain Texture" + wrapmodes: "black,black" + oiio:AverageColor: "1e+06,1e+06,1e+06" + oiio:ColorSpace: "Linear" + oiio:ConstantColor: "1e+06,1e+06,1e+06" + oiio:SHA-1: "E3D97EED7EE68F1885685F312DDD7D8773C29862" + oiio:subimages: 1 + openexr:roundingmode: 0 + MIP 0 of 2 (2 x 2): + Stats Min: 65504.000000 65504.000000 65504.000000 (float) + Stats Max: 65504.000000 65504.000000 65504.000000 (float) + Stats Avg: 65504.000000 65504.000000 65504.000000 (float) + Stats StdDev: 0.000000 0.000000 0.000000 (float) + Stats NanCount: 0 0 0 + Stats InfCount: 0 0 0 + Stats FiniteCount: 4 4 4 + Constant: Yes + Constant Color: 65504.000000 65504.000000 65504.000000 (float) + Monochrome: Yes + MIP 1 of 2 (1 x 1): + Stats Min: 65504.000000 65504.000000 65504.000000 (float) + Stats Max: 65504.000000 65504.000000 65504.000000 (float) + Stats Avg: 65504.000000 65504.000000 65504.000000 (float) + Stats StdDev: 0.000000 0.000000 0.000000 (float) + Stats NanCount: 0 0 0 + Stats InfCount: 0 0 0 + Stats FiniteCount: 1 1 1 + Constant: Yes + Constant Color: 65504.000000 65504.000000 65504.000000 (float) + Monochrome: Yes Reading checker-exr.pdq checker-exr.pdq : 128 x 128, 4 channel, half openexr MIP-map levels: 128x128 64x64 32x32 16x16 8x8 4x4 2x2 1x1 diff --git a/testsuite/oiiotool-maketx/run.py b/testsuite/oiiotool-maketx/run.py index b026179411..12a3333379 100755 --- a/testsuite/oiiotool-maketx/run.py +++ b/testsuite/oiiotool-maketx/run.py @@ -97,6 +97,13 @@ def omaketx_command (infile, outfile, extraargs="", "--fixnan box3", options=":nomipmap=1", showinfo=True, showinfo_extra="--stats") +# Test that when outputting half textures, we clamp large float values +# rather than inadvertetly turning into Inf in the process of output to +# half. +command += oiiotool (" --pattern constant:color=1.0e6,1.0e6,1.0e6 2x2 3 -d float -o million.tif") +command += omaketx_command ("million.tif", "bigval.exr", + "-d half", showinfo_extra="--stats") + # Test --format to force exr even though it can't be deduced from the name. command += omaketx_command ("checker.tif", "checker-exr.pdq", options=":fileformatname=exr")