stb
stb copied to clipboard
stb_image_write: Add writer for OpenEXR images
This writer takes linear float data and losslessly outputs files with the same number of components as the input. The images it writes contain 32-bit full floats from the original data (half floats are not supported) stored with the "ZIP" compression mode which deflates blocks of scan lines.
As with the PNG writer, the files encoded with this writer are a bit bigger than those written by the reference OpenEXR library or by tinyexr. This is because it relies on the same built-in zlib deflate code as the PNG writer (which can therefore be swapped out to mitigate this.)
I realize that there's some hesitancy about adding new image types to the image writer library. However, I would argue that EXR is superior to the existing Radiance HDR format for HDR data:
- It stores the original floating point data unmodified, rather than lossily reducing to RGBE.
- It supports the full range of 1 to 4 components, and with the same interpretation as the PNG writer (Y, YA, RGB, or RGBA).
- It compresses using zlib deflate instead of the more limited RLE.
We definitely don't want new formats for stb_image, but stb_image_write is not as pressing a concern because unlike stb_image, adding new formats does not introduce new exploitation opportunities.
I'll need to have a look at this, but ~100 lines to add EXR support seems fairly reasonable.
Thanks for considering this addition. That's a very reasonable justification regarding stb_image.
One other benefit compared to HDR that I'd forgot to mention is that it should work fine with STBI_WRITE_NO_STDIO
.
I did realize today after looking at pull request #1075, that line 1631 might be of concern to you since I type-punned via a pointer cast. I can easily change that over to use the memcpy()
method and amend the commit if you prefer.
That's the smallest EXR writer I've ever seen! Speaking as one of the OpenEXR authors, I'd definitely use this to feed into a tools pipeline from systems that aren't linking OpenEXR. As a very minor suggestion, I think it would be straight forward to also support fp16 data with the framework you've got in place. It's less critical, but for tiny devices originating exr data, the much smaller file sizes might make a difference where memory and bandwidth are an issue. We get queries from embedded manufacturers from time to time, and with or without fp16, this will be a great thing to point them to.
My biggest concern is that this leads to stb_image_write creating a file format that stb_image can't read, which I can 100% gaurantee will cause friction in the future.
Given there's no way we're going to have an EXR reader, and the issue I raised about reading what we write, I think maybe the best solution is to separate this into its own library. One possibility is to release it yourself, in which case it will be clear that stb_image.h isn't expected to support it. We could release it as stb_image_write_exr.h, but I worry that will still create some expectations.
Random thought - is there an "idiomatic" pattern to extend stb_image in this way outside of the stb repo? i.e. an accepted pattern for extending stb_image by reaching into it's guts? One option might be to pitch the OpenEXR TSC (I'm a TSC member) on the idea of hosting an exr writing stb extension in our OpenEXR/contrib area. If accompanied by a test, it could be added to our CI unit testing to verify that images from this extension are consumable by the full OpenEXR library....
Thanks for the consideration. I had a feeling you'd say that.
I'm not so sure that there's a clean way to extend stb_image_write by reaching into its guts from the outside. If my implementation includes stb_image_write.h with STB_IMAGE_WRITE_IMPLEMENTATION defined so that it can use the zlib, then users would have to be warned not to also include stb_image_write.h with STB_IMAGE_WRITE_IMPLEMENTATION in their code or else they'll get clashes. That's doable, I suppose, but feels a bit odd. It leads me to think that a standalone library may be the best way to go.
Right now, I see one possibility as spinning this out as into separate library, pulling in the minimal zlib stuff from stb_image_write and changing the prefix to avoid clashes (with appropriate credit given, of course). That would have all the usual downsides of a fork. Or I could try my own hand at implementing deflate. I'll have to ponder this. Either way, I'm still keen on the idea of a very tiny stb_image{,_write}-style subset of EXR. It's definitely an itch that I've had in the past.
There's no way to progammatically extend stb_image. I imagine people have probably added requests for extensions to allow adding new formats externally, but it really doesn't make sense.
You can always wrap stbi_load in your own function which tries other loaders before/after trying stbi_load instead. You can even make this function take extra parameters as needed if EXR supports extra stuff that you want to expose.
I don't know if you are still following this, @a-e-k , but I'd love to have a C-only minimalistic OpenEXR loader+writer single-file lib. I'm not aware of any C implementation of OpenEXR, and there are situations where you really need C rather than C++. If this doesn't fit in stb_image[_write] I really encourage you to release your own lib, like Sean suggested. I would use it as soon as you release it.
@cesss OpenEXR is written in C. https://github.com/AcademySoftwareFoundation/openexr/tree/main/src/lib/OpenEXRCore The C++ layer is ... a layer. The nice thing about using the official library code is that it's guaranteed to work properly. There's no reason you couldn't combine the C files into a single C file if you want a minimal number of files ~ honestly if you look at any of the alternative implementations, they aren't any smaller than the actual library, they just tend to be really, really, long header files with an implementation macro guard.
@cesss -- Thanks for the nudge. I actually had been working on a standalone single-file EXR writer lib. But I also have another fun single-header library that I've been working on for a lot longer and wanted to finally get out the door first. I'll definitely remember to comment on this thread, though, once I release the EXR writer.
Thanks a lot, @meshula and @a-e-k . I didn't know that the core of the OpenEXR lib was C. That's very interesting, and it certainly opens many possibilities!