Skip to content

Improved IFF support reading and writing z buffers#4673

Merged
lgritz merged 11 commits intoAcademySoftwareFoundation:mainfrom
mikaelsundell:ms-IFF-250319
May 11, 2025
Merged

Improved IFF support reading and writing z buffers#4673
lgritz merged 11 commits intoAcademySoftwareFoundation:mainfrom
mikaelsundell:ms-IFF-250319

Conversation

@mikaelsundell
Copy link
Copy Markdown
Contributor

Description

Added support for reading and writing ZBUF chunks, also known as Z-buffers or depth maps
Removed noproxy versions, no longer needed

Checklist:

  • I have read the contribution guidelines.
  • I have updated the documentation, if applicable. (Check if there is no
    need to update the documentation, for example if this is a bug fix that
    doesn't change the API.)
  • I have ensured that the change is tested somewhere in the testsuite
    (adding new test cases if necessary).
  • If I added or modified a C++ API call, I have also amended the
    corresponding Python bindings (and if altering ImageBufAlgo functions, also
    exposed the new functionality as oiiotool options).
  • My code follows the prevailing code style of this project. If I haven't
    already run clang-format before submitting, I definitely will look at the CI
    test that runs clang-format and fix anything that it highlights as being
    nonconforming.

@mikaelsundell mikaelsundell changed the title Added support for reading and writing z buffers Improved IFF support reading and writing floating point z buffers Mar 19, 2025
Comment thread src/iff.imageio/iffinput.cpp Outdated
} else {
// skip to the next block.
if (!ioseek(chunksize, SEEK_CUR)) {
errorfmt("IFF error io seek failed");
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ImageInput helper methods ioseek() and ioread() handle calling errorfmt for you. If they fail, you just need to return false, you don't need to clutter with another error message call.

Comment thread src/iff.imageio/iffinput.cpp Outdated
readimg();
if (m_buf.empty()) {
if (!readimg()) {
errorfmt("IFF error could not read image for tile");
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If readimg() itself calls errorfmt for each way that it can fail, you don't need to do it again here.

Comment thread src/iff.imageio/iffoutput.cpp Outdated
Comment on lines +169 to +177
// IFF image files only supports UINT8 and UINT16. If something
// else was requested, revert to the one most likely to be readable
// by any IFF reader: UINT8

TypeDesc base_format = spec.format;
if (base_format != TypeDesc::UINT8 && base_format != TypeDesc::UINT16) {
errorfmt("Unsupported format {}. Converting to UINT8.", base_format);
base_format = TypeDesc::UINT8;
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that most of the readers pick the supported data type that loses the least precision versus the one requested. So if they ask for something at least as big as uint16, we should probably give them uint16 rather than uint8, which is even less fidelity.

@mikaelsundell mikaelsundell changed the title Improved IFF support reading and writing floating point z buffers Improved IFF support reading and writing z buffers Mar 19, 2025
@mikaelsundell
Copy link
Copy Markdown
Contributor Author

There will be an update on this one today!

Comment thread src/iff.imageio/iffinput.cpp Outdated
// skip to the next block
if (!ioseek(chunksize))
if (!ioseek(chunksize, SEEK_CUR)) {
errorfmt("IFF error io seek failed");
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not necessary -- the ioseek method itself calls errorfmt if it fails. All you have to do here is return.

@lgritz
Copy link
Copy Markdown
Collaborator

lgritz commented Mar 28, 2025

Unfortunately, this dumps core on some example iff files I have. It's not something I can send. Let me see if I can at least point you to the part of the code where it crashes.

Comment thread src/iff.imageio/iffinput.cpp Outdated
Comment on lines +846 to +969
for (uint16_t px = xmin; px <= xmax; px++) {
uint8_t* out_p = out_dy + px * m_header.pixel_bytes()
+ m_header.rgba_channels_bytes() + c;
*out_p++ = *in_p++;
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For an RGBAZ iff file (uint8 RGBA channels, float Z channel), I'm getting crashes at line 852 when releasing a std::vector (presumably the "in" vector declared at line 834).

I suspect that this loop may be the culprit. Are you sure about those offets? I believe that here, we are taking the compressed single z channel (stored at this point in scratch and copying it to the right postion in the output buffer. But the

... + m_header.rgba_channels_bytes() + c

looks wrong to me, and also the next line

*outp++ = *in_p++;

These are uint8_t pointers, so you're incrementing them by 1 each here, but isn't the data in "in" really float (the Z channel) and isn't the spacing of the output buffer going to be m_header.pixel_bytes() ?

Or am I misunderstanding what's happening here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason this happens is that each call to uncompress_rle_channel decompresses floats and uint16 values byte by byte, while also handling planar storage and byte order at the same time. That’s why uint8_t is used across uint8, uint16, and float decompression and compression—it's one RLE run per byte, not per channel in this case.

pixel_bytes() is full RGB(A)+Z while rgba_channel_bytes() is RGB(A) only cause RGBA and Z chunks are stored in the actual IFF layout while we store interleaved/ packed.

My guess is that there’s a mismatch between the expected chunk size and what’s actually in the chunk (RLE vs uncompressed etc), which might be causing the issue. Are you able to open your sample files in Nuke without any problems? Or maybe try FCheck on a Windows machine? I could be wrong of course.

I could write out the binary layout if we can't reproduce it with other non-confidential files. May I ask—what software wrote the IFF files, maybe that's an easier way to the issue. After all, you are probably right there is a run over somewhere and a byte is all it needs. There must be a glitch in the code unless the original software you used writes IFF in a different way or with incorrect or non-aligned chunk sizes. If it works in Nuke etc it should work in my code.

This old legacy format is fun—if you had asked me to write it today, I would’ve done things slightly differently. 😄

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The good news is that I have at least 2 different iff files that crash here -- they are RGBAZ (uint8 for RGBA, float for Z), RLE compression. The bad news is that they are production frames and I can't send them out.

They appear to be Maya playblast output. They're from different shows at different times, so I think maybe it won't be difficult for you to reproduce from scratch on your end?

Will try loading with Nuke and report back...

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW, those failing frames do not crash in the mainline OIIO (not using this PR's patch)... but then again, I think it may simply be ignoring the Z channel entirely in that case, so I wouldn't say they are "correct" exactly.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nuke does load it. I'm not sure how to verify that it interprets the depth values correctly.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Must be fixed! if the test files are coming from Maya it should be an easy thing to reproduce. You are able to open the earlier test file from Nicholas, it's also Maya and RGBAZ.

Copy link
Copy Markdown
Contributor Author

@mikaelsundell mikaelsundell Mar 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nuke will scream in red ERROR if the Z buffer reading is off, my code must be off/ wrong somewhere. Let's try to find it, try to open the Nicholas file and see if you get the same problem. I will also switch between a few different configuration and see if I can trigger the issue.

Visualise depth in rgba mode using something like an Expression node putting in (-1/z)/max value in R channel and zero in G and B. Should give you an OK visualisation.

Are you doing something like a RGBAZ channels from iff => exr with oiiotool when testing?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which earlier test file from Nicholas?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I fail just doing a straightforward iconvert foo.iff foo.exr or iinfo -v --stats or oiiotool, yes.

@mikaelsundell
Copy link
Copy Markdown
Contributor Author

mikaelsundell commented Mar 30, 2025

New version in place with both support for uncompressed data (not verified with real IFF/z-buffer files) and the use of spans to avoid buffer runovers. I also removed some redundant error messages. Hopefully this will either fire in debug or switch over to non compressed.

@lgritz
Copy link
Copy Markdown
Collaborator

lgritz commented Apr 7, 2025

Just to make sure we're all on the same page, this PR as it currently stands no longer crashes on my problem iff files, but it does (gracefully) error on the file with a "Could not read : uncompressed span overflow at offset ..."

@lgritz
Copy link
Copy Markdown
Collaborator

lgritz commented Apr 7, 2025

(Mikael and I have been discussing this off-channel, but wanted to be sure people knew progress was being made here.)

@mikaelsundell
Copy link
Copy Markdown
Contributor Author

Thanks Larry, will be back this weekend to finish up, out traveling this week.

@lgritz
Copy link
Copy Markdown
Collaborator

lgritz commented Apr 8, 2025

Excuse my cluttering things up, but I'm using this PR as a guinea pig to request a GH Copilot review just to see what it says. Feel free to ignore any of it, this is just an experiment.

@lgritz lgritz requested a review from Copilot April 8, 2025 19:11
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot reviewed 7 out of 8 changed files in this pull request and generated no comments.

Files not reviewed (1)
  • src/iff.imageio/CMakeLists.txt: Language not supported
Comments suppressed due to low confidence (2)

src/iff.imageio/iffoutput.cpp:165

  • The write_scanline function always returns false after a successful memcpy. Returning true here would indicate the scanline was written successfully.
return false;

src/iff.imageio/iffoutput.cpp:156

  • Verify that the updated check_open parameters (with a maximum channel value of 5) correctly support only RGB, RGBA, and RGBAZ formats as desired.
if (!check_open(mode, spec, { 0, 8192, 0, 8192, 0, 1, 0, 5 }))

@mikaelsundell
Copy link
Copy Markdown
Contributor Author

mikaelsundell commented Apr 12, 2025

Great! I'm back now, will finish this up in the next couple of days, will make sure I copilot my changes before commit. Let the bot battle begin! :-)

…ffers or depth maps

Removed noproxy versions, no longer needed

Signed-off-by: Mikael Sundell <mikael.sundell@gmail.com>
Signed-off-by: Mikael Sundell <mikael.sundell@gmail.com>
Improved format precision handling: now falls back to UINT16 instead of UINT8 for high-precision formats

Signed-off-by: Mikael Sundell <mikael.sundell@gmail.com>
Signed-off-by: Mikael Sundell <mikael.sundell@gmail.com>
Added initial implementation of z-buffer decoding using span
Added support for uncompressed z-buffer tiles

Signed-off-by: Mikael Sundell <mikael.sundell@gmail.com>
Signed-off-by: Mikael Sundell <mikael.sundell@gmail.com>
Fixed channel ordering issues in uncompressed data.

Signed-off-by: Mikael Sundell <mikael.sundell@gmail.com>
Signed-off-by: Mikael Sundell <mikael.sundell@gmail.com>
Signed-off-by: Mikael Sundell <mikael.sundell@gmail.com>
@lgritz lgritz added enhancement Improvement of existing/working features. file formats Image file formats, ImageInput, ImageOutput labels Apr 21, 2025
@mikaelsundell
Copy link
Copy Markdown
Contributor Author

mikaelsundell commented Apr 21, 2025

New commits, spans + reading and writing of uncompressed IFF data verified. I've tested both uncompressed + rle with nuke and photoshop and both works for RGBAZ in 8/16-bit.

Hopefully these are the updates we need to close this PR.

Updated uncompressed z-buffer writing to use spans
Signed-off-by: Mikael Sundell <mikael.sundell@gmail.com>
Copy link
Copy Markdown
Collaborator

@lgritz lgritz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, LGTM and works on my iff files that once had trouble.

I did spot some problems with errorfmt calls getting confused about printf vs the newer format specifiers (throughout OIIO, all formatted string functions ending in "fmt" use the new syntax, not the old printf one). Those will need to get cleaned up, so some searching to be sure to find all of them.

With those changes, I think we are ready to merge this.


// helper to uncompress a rle channel
size_t uncompress_rle_channel(const uint8_t* in, uint8_t* out, int size);
size_t uncompress_rle_channel(span<uint8_t> in, span<uint8_t> out,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make that cspan<uint8_t> in since it's const data?

Comment thread src/iff.imageio/iffinput.cpp Outdated
in_span, tw * th);
if (used > scratch_span.size()) {
errorfmt(
"RLE uncompress exceeds span size (channel byte %d)",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All the functions ending in fmt take the new std::format idioms, so this should be:

Suggested change
"RLE uncompress exceeds span size (channel byte %d)",
"RLE uncompress exceeds span size (channel byte {})",

Comment thread src/iff.imageio/iffinput.cpp Outdated

for (uint16_t px = xmin; px <= xmax; ++px) {
if (offset >= in_span.size()) {
errorfmt("in_span underflow at (%u, %u)",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
errorfmt("in_span underflow at (%u, %u)",
errorfmt("in_span underflow at ({}, {})",

Comment thread src/iff.imageio/iffinput.cpp Outdated

if (sl_span.empty()) {
errorfmt(
"scanline span overflow at (%u, %u)",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"scanline span overflow at (%u, %u)",
"scanline span overflow at ({}, {})",

Comment thread src/iff.imageio/iffinput.cpp Outdated

if (pixel_offset + m_header.zbuffer_bytes()
> scratch_span.size()) {
errorfmt("in span overflow at pixel (%u, %u)", px,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
errorfmt("in span overflow at pixel (%u, %u)", px,
errorfmt("in span overflow at pixel ({}, {})", px,

I'm not going to mark all of them, you can do it as well as I can

Signed-off-by: Mikael Sundell <mikael.sundell@gmail.com>
@mikaelsundell mikaelsundell requested a review from lgritz May 11, 2025 12:34
Copy link
Copy Markdown
Collaborator

@lgritz lgritz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@lgritz lgritz merged commit 946a9d3 into AcademySoftwareFoundation:main May 11, 2025
30 checks passed
lgritz pushed a commit to lgritz/OpenImageIO that referenced this pull request May 11, 2025
…SoftwareFoundation#4673)

Added support for reading and writing ZBUF chunks, also known as
Z-buffers or depth maps.
Removed noproxy versions, no longer needed.

---------

Signed-off-by: Mikael Sundell <mikael.sundell@gmail.com>
@mikaelsundell
Copy link
Copy Markdown
Contributor Author

Awesome 🙂

scott-wilson pushed a commit to scott-wilson/OpenImageIO that referenced this pull request May 17, 2025
…SoftwareFoundation#4673)

Added support for reading and writing ZBUF chunks, also known as
Z-buffers or depth maps.
Removed noproxy versions, no longer needed.

---------

Signed-off-by: Mikael Sundell <mikael.sundell@gmail.com>
Signed-off-by: Scott Wilson <scott@propersquid.com>
scott-wilson pushed a commit to scott-wilson/OpenImageIO that referenced this pull request May 18, 2025
…SoftwareFoundation#4673)

Added support for reading and writing ZBUF chunks, also known as
Z-buffers or depth maps.
Removed noproxy versions, no longer needed.

---------

Signed-off-by: Mikael Sundell <mikael.sundell@gmail.com>
Signed-off-by: Scott Wilson <scott@propersquid.com>
zachlewis pushed a commit to zachlewis/OpenImageIO that referenced this pull request Aug 1, 2025
…SoftwareFoundation#4673)

Added support for reading and writing ZBUF chunks, also known as
Z-buffers or depth maps.
Removed noproxy versions, no longer needed.

---------

Signed-off-by: Mikael Sundell <mikael.sundell@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement Improvement of existing/working features. file formats Image file formats, ImageInput, ImageOutput

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants