Use OpenImageIO for loading and saving nearly all image formats #101413

Open
opened 2022-09-27 20:47:14 +02:00 by Jesse Yurkovich · 34 comments

Proposal

Use OpenImageIO (OIIO) to manage our image loading/saving code for nearly all supported formats.

Re-organized this task to better indicate the status now that the groundwork and most formats were completed. See text below the table for the original Plan, Design, and Implementation sequence.

Status
The following table outlines the fate of each format given the Goals and Issues below.

Format Blender R/W OIIO R/W OIIO Memory Proxy Notes
CINEON Yes/Yes Yes/No No Keep Blender's implementation
DPX Yes/Yes Yes/Yes Yes DONE - 3.6
DDS Yes/No Yes/No Yes DONE - 3.6
OpenEXR Yes/Yes Yes/Yes Yes Investigate: extreme complexity and risk
BMP Yes/Yes Yes/Yes Yes DONE - 3.6
Iris Yes/Yes Yes/Yes Yes Investigate
Radiance HDR Yes/Yes Yes/Yes Yes DONE - 3.6
JPEG Yes/Yes Yes/Yes Yes Blocked: thumbnail support
OpenJPEG JP2 Yes/Yes Yes/Yes Yes Blocked: poor support
Photoshop PSD Yes/No Yes/No Yes DONE - 3.6
PNG Yes/Yes Yes/Yes Yes DONE - 3.6
Targa Yes/Yes Yes/Yes Yes DONE - 3.6
TIFF Yes/Yes Yes/Yes Yes DONE - 3.6
WebP Yes/Yes Yes/Yes Yes Blocked: thumbnail support

Original

Pros:

  • Reduce maintenance of error-prone code for all but a few of Blender's supported formats
  • Reduce platform and build complexity by removing several SVN libraries, Cmake code, and #defines for many of the individual file formats (jpeg/tiff/png etc.)
  • Reduce differences between Eevee and Cycles
  • Eliminate binary size waste resulting from the duplication of these dependencies in other shared libraries
  • Provide an easy path for additional format support once this proposal is in place (RAW etc.)
  • Bugs/features found by us will benefit the entire ecosystem of OIIO users and vice versa

Cons:

  • Features and fixes will need to wait for upstream to handle and then for the Blender platform maintainers to pull in the updated library

Unknown:

  • Unclear whose code has been better tested in terms of broken and/or malicious files. Both have had their share of security issues.
  • There may be unknown performance pitfalls

Why now
OIIO 2.4.x introduces complete support for "IO proxies" which allows it to read/write images directly in memory. This is required for fitting in with Blender's current systems and was a key point of contention in the past.

Recent work in the DDS space has caused this topic to surface again: #101405 (DDS image format improvements)

Implementation Goals

Goals

  • Existing image formats, and their options, should remain unchanged
  • Existing features of the current system should remain unchanged (e.g. efficient thumbnail extraction)
  • Limit code churn in neighboring areas unless necessary
  • Commit the code in stages; as much as makes sense

Non-Goals

  • Introduce new image formats or features as part of this initial work
  • Use additional OIIO features beyond what's required for current feature parity

Approach

Each format will retain custom load/save entry points inside the format registration array: ImFileType IMB_FILE_TYPES- [ ] inside filetype.c All the machinery surrounding usage of that system will remain unchanged.

The entry points for each format will use simple, declarative, APIs from OIIO to setup the proper configuration for the operation in question.

They will then call into newly created OIIO read/write routines to handle all the processing in a centralized and standardized way (i.e. common handling of IB_test, IB_mem, IB_metadata flags etc.)

Open Issues

Issue 1 Efficient thumbnail extraction doesn't exist in OIIO
Recent additions to Blender provide efficient thumbnail extraction and generation for JPEG, EXR, and WebP for the file browser. We will extract embedded thumbnails directly from the file if they exist, or will generate them otherwise, and do so as efficiently as possible by making use of size-hints that the low-level APIs can use to prevent the need for additional memory or resizing of images.

OIIO does have a get_thumbnail API, however it is insufficient for our needs due to two reasons. The first is that it doesn't exist for the formats we would need for parity. The second is that it currently doesn't have any size-hinting and adding it would be considered a breaking change which means it wouldn't show up until OIIO 2.5.

Issue 2 JPEG-2000 feature parity
Several of JPEG-2000's options aren't supported by OIIO: Compression quality, YCC colorspace, and OPJ_CINEMA2K_48 are not present. Additionally the "J2K" codec must be saved as .j2k (not .j2c) or otherwise it'll be processed incorrectly.

Closed Issues

Issue 3 DDS textures
It turns out that Eevee makes use of the raw DDS compressed data in certain scenarios. Blender will load in the uncompressed data as well as the compressed data. This was very surprising to discover! We can keep doing this but we'll have to step a little bit outside of pure OIIO during loading. Either way we can still maintain parity here with a very small portion of low-level code.

DDS normal map compressed formats are now supported as of recent OIIO 2.4.4.2 and should no longer be an issue

Plan

The code required for each image format is well-insulated and can be checked in individually.

The common reading/writing code will be checked in alongside the first format to be converted.

Possible checkin sequence:

  • Cleanup: Remove IMB_gettile and related support functions as they are dead code and would complicate the TIFF conversion

  • Cleanup: Fix slightly error-prone colorspace handling in the load loop (see note below)

  • Per-Format conversion

    • For a given format, do the entire OIIO conversion in one set of changes and commit (SVN can happen any time afterwards)
    • Repeat for each additional format
  • In Parallel

    • Help design and implement better thumbnail support in OIIO
    • Help implement missing JPEG-2000 support in OIIO

Notes

  • Some of the existing formats do not handle the IB_test flag at all or not optimally. These will be fixed during their conversion.
  • Many formats do not handle IB_mem. We will get this for "free" for all formats during their conversion.
  • The load loop which loops over known formats is slightly error-prone because the effective_colorspace variable is not cleared between iterations. It is possible for a file to load far enough to set a colorspace but then fail shortly afterwards. In practice this probably wouldn't happen though.

Risks

Testing
Image handling is extremely nuanced. Proper review and testing will take time. All of the following must be checked and validated with folks familiar in the matter:

  • Alpha channel handling (associated vs. unassociated)
  • Colorspace handling
  • Correct data type: float vs. byte (images can "look" ok but these details can differ)
  • Correct number of channels / planes (images can "look" ok but these details can differ)
  • Correct GPU buffer format, especially for 1-channel grayscale images (images can "look" ok but these details can differ; this information is only exposed in the UI making automation impossible)

The above items need to be inspected in 2 situations: 1) With an older blender version loading newly saved images and 2) With the new blender version loading previously saved images. (i.e. general cross testing)

Automation to prevent regressions would be nice. I'm not sure what's possible/allowable with our frameworks for verifying that list above. If we want to test all formats and all options we're looking at ~100 separate image files that would need to be verified.

Performance
This is mostly for Blender-specific scenarios as Cycles has always depended on OIIO for bulk load of texture data.

  • Playback caching in the VSE
  • Using the filebrowser in Thumbnail mode to view directories with large amounts of images
  • Loading many images from python (sequential nature of python would amplify any large perf regression)

A quick test of the Playback caching scenario using Timeline->Playback->Play Every Frame to force-load all the images did not show anything outright broken at least for PNGs so far:
100 frame 1080p Image sequence of PNGs
master Took 9.05 seconds
prototype Took 8.94 seconds

100 frame 4k Image sequence of PNGs
master Took 20.1 seconds
prototype Took 20.1 seconds

Q/A
Q. Is it worth doing if we can't convert all the formats?
A. PSD files are already using OIIO and Cycles already uses OIIO for all but a few situations. Even if we don't get all of the formats, we're still looking at thousands of lines of code that can be removed. Considering that the new code would be simpler and more declarative, it makes the proposal worth exploring at least.

Q. What happens if the thumbnail issue isn't solved?
A. There's 2 middle grounds that we could explore:
- Skip those formats entirely but convert all the others
- Use OIIO for Load/Save for those formats but keep the thumbnail code using the low level libraries

The second option has the benefit that we'll still reduce some unneeded code. Both options have the downside that Blender still requires the library to be linked in.

Q. What about perf?
A. Beyond the scenarios mentioned above there's the following:

  • The code paths that use the .is_a check might be slower. OIIO does fast signature checks but if that passes it then proceeds to do more invasive work before returning. I don't know how much this will affect things in practice. The .is_a checks are done in 2 cases -- thumbnails (sigh…) and some packed file scenarios.
  • Loading through OIIO happens with the exact number of channels as the file uses. E.g. a 3-channel file will load into 3 channels worth of memory. However, Blender operates on 4-channel nearly exclusively. This requires a post-load operation to fill the missing channel(s). The current code accounts for this as it goes; and might be faster.

Working examples

Current all-up diff here now: D16640: WIP: Use OpenImageIO for loading and saving nearly all image formats

### Proposal Use OpenImageIO (OIIO) to manage our image loading/saving code for nearly all supported formats. Re-organized this task to better indicate the status now that the groundwork and most formats were completed. See text below the table for the original Plan, Design, and Implementation sequence. **Status** The following table outlines the fate of each format given the Goals and Issues below. | Format | Blender R/W | OIIO R/W | OIIO Memory Proxy | Notes | | ------------- | ----------- | ---------- | ----------------- | ------| | CINEON | Yes/Yes | Yes/No | No | Keep Blender's implementation | | DPX | Yes/Yes | Yes/Yes | Yes | DONE - 3.6 | | DDS | Yes/No | Yes/No | Yes | DONE - 3.6 | | OpenEXR | Yes/Yes | Yes/Yes | Yes | Investigate: extreme complexity and risk | | BMP | Yes/Yes | Yes/Yes | Yes | DONE - 3.6 | | Iris | Yes/Yes | Yes/Yes | Yes | Investigate | | Radiance HDR | Yes/Yes | Yes/Yes | Yes | DONE - 3.6 | | JPEG | Yes/Yes | Yes/Yes | Yes | Blocked: thumbnail support | | OpenJPEG JP2 | Yes/Yes | Yes/Yes | Yes | Blocked: poor support | | Photoshop PSD | Yes/No | Yes/No | Yes | DONE - 3.6 | | PNG | Yes/Yes | Yes/Yes | Yes | DONE - 3.6 | | Targa | Yes/Yes | Yes/Yes | Yes | DONE - 3.6 | | TIFF | Yes/Yes | Yes/Yes | Yes | DONE - 3.6 | | WebP | Yes/Yes | Yes/Yes | Yes | Blocked: thumbnail support | ---- ### Original Pros: - Reduce maintenance of error-prone code for all but a few of Blender's supported formats - Reduce platform and build complexity by removing several SVN libraries, Cmake code, and #defines for many of the individual file formats (jpeg/tiff/png etc.) - Reduce differences between Eevee and Cycles - Eliminate binary size waste resulting from the duplication of these dependencies in other shared libraries - Provide an easy path for additional format support once this proposal is in place (RAW etc.) - Bugs/features found by us will benefit the entire ecosystem of OIIO users and vice versa Cons: - Features and fixes will need to wait for upstream to handle and then for the Blender platform maintainers to pull in the updated library Unknown: - Unclear whose code has been better tested in terms of broken and/or malicious files. Both have had their share of security issues. - There may be unknown performance pitfalls **Why now** OIIO 2.4.x introduces complete support for "IO proxies" which allows it to read/write images directly in memory. This is required for fitting in with Blender's current systems and was a key point of contention in the past. Recent work in the DDS space has caused this topic to surface again: #101405 (DDS image format improvements) ### Implementation Goals Goals - Existing image formats, and their options, should remain unchanged - Existing features of the current system should remain unchanged (e.g. efficient thumbnail extraction) - Limit code churn in neighboring areas unless necessary - Commit the code in stages; as much as makes sense Non-Goals - Introduce new image formats or features as part of this initial work - Use additional OIIO features beyond what's required for current feature parity ### Approach Each format will retain custom load/save entry points inside the format registration array: `ImFileType IMB_FILE_TYPES- [ ]` inside `filetype.c` All the machinery surrounding usage of that system will remain unchanged. The entry points for each format will use simple, declarative, APIs from OIIO to setup the proper configuration for the operation in question. They will then call into newly created OIIO read/write routines to handle all the processing in a centralized and standardized way (i.e. common handling of `IB_test`, `IB_mem`, `IB_metadata` flags etc.) ### Open Issues **Issue 1** Efficient thumbnail extraction doesn't exist in OIIO Recent additions to Blender provide efficient thumbnail extraction and generation for JPEG, EXR, and WebP for the file browser. We will extract embedded thumbnails directly from the file if they exist, or will generate them otherwise, and do so as efficiently as possible by making use of size-hints that the low-level APIs can use to prevent the need for additional memory or resizing of images. OIIO does have a `get_thumbnail` API, however it is insufficient for our needs due to two reasons. The first is that it doesn't exist for the formats we would need for parity. The second is that it currently doesn't have any size-hinting and adding it would be considered a breaking change which means it wouldn't show up until OIIO 2.5. **Issue 2** JPEG-2000 feature parity Several of JPEG-2000's options aren't supported by OIIO: Compression quality, YCC colorspace, and `OPJ_CINEMA2K_48` are not present. Additionally the "J2K" codec must be saved as .j2k (not .j2c) or otherwise it'll be processed incorrectly. ### Closed Issues **Issue 3** DDS textures It turns out that Eevee makes use of the raw DDS compressed data in certain scenarios. Blender will load in the uncompressed data as well as the compressed data. This was very surprising to discover! We can keep doing this but we'll have to step a little bit outside of pure OIIO during loading. Either way we can still maintain parity here with a very small portion of low-level code. DDS normal map compressed formats are now supported as of recent OIIO 2.4.4.2 and should no longer be an issue ### Plan The code required for each image format is well-insulated and can be checked in individually. The common reading/writing code will be checked in alongside the first format to be converted. **Possible checkin sequence:** - Cleanup: Remove `IMB_gettile` and related support functions as they are dead code and would complicate the TIFF conversion - Cleanup: Fix slightly error-prone colorspace handling in the load loop (see note below) - Per-Format conversion - For a given format, do the entire OIIO conversion in one set of changes and commit (SVN can happen any time afterwards) - Repeat for each additional format - In Parallel - Help design and implement better thumbnail support in OIIO - Help implement missing JPEG-2000 support in OIIO **Notes** - Some of the existing formats do not handle the `IB_test` flag at all or not optimally. These will be fixed during their conversion. - Many formats do not handle `IB_mem`. We will get this for "free" for all formats during their conversion. - The load loop which loops over known formats is slightly error-prone because the `effective_colorspace` variable is not cleared between iterations. It is possible for a file to load far enough to set a colorspace but then fail shortly afterwards. In practice this probably wouldn't happen though. ### Risks **Testing** Image handling is extremely nuanced. Proper review and testing will take time. All of the following must be checked and validated with folks familiar in the matter: - **Alpha** channel handling (associated vs. unassociated) - **Colorspace** handling - **Correct data type**: float vs. byte (images can "look" ok but these details can differ) - **Correct number of `channels` / `planes`** (images can "look" ok but these details can differ) - **Correct GPU buffer format**, especially for 1-channel grayscale images (images can "look" ok but these details can differ; this information is only exposed in the UI making automation impossible) The above items need to be inspected in 2 situations: 1) With an older blender version loading newly saved images and 2) With the new blender version loading previously saved images. (i.e. general cross testing) Automation to prevent regressions would be nice. I'm not sure what's possible/allowable with our frameworks for verifying that list above. If we want to test all formats and all options we're looking at ~100 separate image files that would need to be verified. **Performance** This is mostly for Blender-specific scenarios as Cycles has always depended on OIIO for bulk load of texture data. - Playback caching in the VSE - Using the filebrowser in Thumbnail mode to view directories with large amounts of images - Loading many images from python (sequential nature of python would amplify any large perf regression) A quick test of the Playback caching scenario using `Timeline->Playback->Play Every Frame` to force-load all the images did not show anything outright broken at least for PNGs so far: 100 frame 1080p Image sequence of PNGs master Took 9.05 seconds prototype Took 8.94 seconds 100 frame 4k Image sequence of PNGs master Took 20.1 seconds prototype Took 20.1 seconds **Q/A** Q. Is it worth doing if we can't convert all the formats? A. PSD files are already using OIIO and Cycles already uses OIIO for all but a few situations. Even if we don't get all of the formats, we're still looking at thousands of lines of code that can be removed. Considering that the new code would be simpler and more declarative, it makes the proposal worth exploring at least. Q. What happens if the thumbnail issue isn't solved? A. There's 2 middle grounds that we could explore: - Skip those formats entirely but convert all the others - Use OIIO for Load/Save for those formats but keep the thumbnail code using the low level libraries The second option has the benefit that we'll still reduce some unneeded code. Both options have the downside that Blender still requires the library to be linked in. Q. What about perf? A. Beyond the scenarios mentioned above there's the following: - The code paths that use the `.is_a` check might be slower. OIIO does fast signature checks but if that passes it then proceeds to do more invasive work before returning. I don't know how much this will affect things in practice. The `.is_a` checks are done in 2 cases -- thumbnails (sigh…) and some packed file scenarios. - Loading through OIIO happens with the exact number of channels as the file uses. E.g. a 3-channel file will load into 3 channels worth of memory. However, Blender operates on 4-channel nearly exclusively. This requires a post-load operation to fill the missing channel(s). The current code accounts for this as it goes; and might be faster. ### Working examples Current all-up diff here now: [D16640: WIP: Use OpenImageIO for loading and saving nearly all image formats](https://archive.blender.org/developer/D16640)
Author
Member

Added subscriber: @deadpin

Added subscriber: @deadpin
Author
Member

Changed status from 'Needs Triage' to: 'Confirmed'

Changed status from 'Needs Triage' to: 'Confirmed'
Author
Member

Added subscribers: @aras_p, @Jeroen-Bakker

Added subscribers: @aras_p, @Jeroen-Bakker
Member

Added subscriber: @EAW

Added subscriber: @EAW

Added subscriber: @Dangry

Added subscriber: @Dangry
Member

Added subscriber: @LazyDodo

Added subscriber: @LazyDodo

Added subscriber: @TheRedWaxPolice

Added subscriber: @TheRedWaxPolice
Member

Added subscriber: @Harley

Added subscriber: @Harley

Added subscriber: @Yuro

Added subscriber: @Yuro

Added subscriber: @GeorgiaPacific

Added subscriber: @GeorgiaPacific

Added subscriber: @ThomasDinges

Added subscriber: @ThomasDinges

DDS:

  • I have proposed changes/fixes to OpenImageIO that fix various cases where it does not handle certain DDS correctly, compared to D16087. https://github.com/OpenImageIO/oiio/pull/3573
  • Will do performance measurements next; very initial look does not look terribly good though. Will need to dig more.
DDS: - I have proposed changes/fixes to OpenImageIO that fix various cases where it does not handle certain DDS correctly, compared to [D16087](https://archive.blender.org/developer/D16087). https://github.com/OpenImageIO/oiio/pull/3573 - Will do performance measurements next; *very* initial look does not look terribly good though. Will need to dig more.
Member

Personally wouldn't worry too much about the thumbnailing, except for EXR. That format gave us actual bug reports and needed special treatment. But then I only added same for JPEG and WebP for completeness. Although the thumbnailing code for those latter formats are a (slight) improvement, I doubt anyone would notice if that was removed.

Personally wouldn't worry *too much* about the thumbnailing, except for EXR. That format gave us actual bug reports and needed special treatment. But then I only added same for JPEG and WebP for completeness. Although the thumbnailing code for those latter formats are a (slight) improvement, I doubt anyone would notice if that was removed.

DDS: the various tweaks/fixes for OIIO DDS support as mentioned above have landed to upstream, and were just released as OIIO v2.4.4.2.

DDS: the various [tweaks/fixes](https://github.com/OpenImageIO/oiio/pull/3573) for OIIO DDS support as mentioned above have landed to upstream, and were just released as OIIO v2.4.4.2.

DDS performance: I've done a quick attempt at replacing Blender's DDS ImBuf code with OIIO. Initial results were that OIIO code was about 4x slower at loading DXT/BCn compressed DDS files compared to D16087. I did some low hanging fruit in OIIO itself to speed that up (just landed in master as #3583), but that still leaves OIIO at around 2x slower compared to Blender code. Getting the remaining speedup would be much more involved due to how OIIO is structured (there are some memory copies that are hard to avoid).

Something like this might be an issue for other formats that we'd want to switch to OIIO, particularly the ones that are "fast to decode" and then an extra one or two memory copies done by OIIO are a substantial cost. Would probably have to be evaluated for each and every format.

DDS performance: I've done a quick attempt at replacing Blender's DDS ImBuf code with OIIO. Initial results were that OIIO code was about 4x slower at loading DXT/BCn compressed DDS files compared to [D16087](https://archive.blender.org/developer/D16087). I did some low hanging fruit in OIIO itself to speed that up (just landed in master as [#3583](https://github.com/OpenImageIO/oiio/pull/3583)), but that still leaves OIIO at around 2x slower compared to Blender code. Getting the remaining speedup would be much more involved due to how OIIO is structured (there are some memory copies that are hard to avoid). Something like this might be an issue for other formats that we'd want to switch to OIIO, particularly the ones that are "fast to decode" and then an extra one or two memory copies done by OIIO are a substantial cost. Would probably have to be evaluated for each and every format.
Member

Png and jpg would perhaps be the two formats where performance actually is important. Mainly as these are used as playback caching.

Png and jpg would perhaps be the two formats where performance actually is important. Mainly as these are used as playback caching.
Member

@Jeroen-Bakker - Png and jpg would perhaps be the two formats where performance actually is important. Mainly as these are used as playback caching.

Don't quote me, because it has been a while since I looked at this. But using EXR for that type of use could be worth investigating one day. Depends on the formats and compression, but it might be possible that it can give us both smaller file sizes AND faster reads.

Someone had mentioned (Troy probably) that EXR was fast reading and I looked into the idea of using that for our preview thumbnails. Compared to our current PNGs they were smaller and much faster to read. I was quite surprised.

> @Jeroen-Bakker - Png and jpg would perhaps be the two formats where performance actually is important. Mainly as these are used as playback caching. Don't quote me, because it has been a while since I looked at this. But using EXR for that type of use could be worth investigating one day. Depends on the formats and compression, but it might be possible that it can give us both smaller file sizes AND faster reads. Someone had mentioned (Troy probably) that EXR was fast reading and I looked into the idea of using that for our preview thumbnails. Compared to our current PNGs they were smaller and much faster to read. I was quite surprised.

In #101413#1428643, @Harley wrote:
EXR was fast reading and I looked into the idea of using that for our preview thumbnails. Compared to our current PNGs they were smaller and much faster to read. I was quite surprised.

It's not surprising. PNG is mostly bottlenecked by a completely serial zlib decoding process (which means PNG reading/writing can't be multi-threaded, at all). Whereas EXR splits up the image into chunks of 16-pixel rows and compresses them (when using "zip" aka zlib compression) separately. Which is exactly what allows it to use multi-threading on both reading & writing. This did not use to be a big thing back when disk I/O was the bottleneck, but all that has changed with SSDs.

> In #101413#1428643, @Harley wrote: > EXR was fast reading and I looked into the idea of using that for our preview thumbnails. Compared to our current PNGs they were smaller and much faster to read. I was quite surprised. It's not surprising. PNG is mostly bottlenecked by a completely serial zlib decoding process (which means PNG reading/writing can't be multi-threaded, at all). Whereas EXR splits up the image into chunks of 16-pixel rows and compresses them (when using "zip" aka zlib compression) separately. Which is exactly what allows it to use multi-threading on both reading & writing. This did not use to be a big thing back when disk I/O was the bottleneck, but all that has changed with SSDs.
Member

Added subscriber: @HooglyBoogly

Added subscriber: @HooglyBoogly

Added subscriber: @Baardaap

Added subscriber: @Baardaap

Added subscriber: @brecht

Added subscriber: @brecht

I think this is great for all the reasons listed. Additionally, potential benefits are consistency with Hydra, shipping OIIO python bindings with the same supported file formats, and maybe even replacing our ImBuf with oiio::ImageBuf.

For thumbnails reading we can keep our own code for a bit, but it doesn't have to delay replacing the rest of the JPEG/WebP/OpenEXR code. IRIS support we could consider removing entirely, it's really only there for historical reasons at this point.

I think this is great for all the reasons listed. Additionally, potential benefits are consistency with Hydra, shipping OIIO python bindings with the same supported file formats, and maybe even replacing our `ImBuf` with `oiio::ImageBuf`. For thumbnails reading we can keep our own code for a bit, but it doesn't have to delay replacing the rest of the JPEG/WebP/OpenEXR code. IRIS support we could consider removing entirely, it's really only there for historical reasons at this point.

Added subscriber: @SteffenD

Added subscriber: @SteffenD
Author
Member

@brecht I'm probably at the point where I can start prepping the individual formats for review this week. I'd start with the support code and the PSD format since that already uses oiio. After that, things can go as fast or as slow as we'd like depending on the time of reviewers with higher priority items on their plates. There's a few items remaining to work through though: Testing and dependencies.

Testing
For testing image loading, I'm using the regular python unittest framework to open each file and then compare Image attributes with what I expect (is_float, colorspace, channel count, and alpha_mode). There's no comparison of what the image looks like however. We'd need a picture of what things look like in the Image Editor or similar. I'm not sure what the best option is here.

For save testing, I have a separate script which can create and save the images as necessary. They're created from scratch with a script and each image contains alpha and pixel values either clamped at 1 for 8bit or >1 for float buffers. From there I can use idiff for comparison against the saved references. But this doesn't fit with the render_test system very well actually. Should I just use the unittest framework here too and perform all the idiff calls myself? The main loss would be the nice html report unless I also implement that piece too.

Dependencies
Lastly, when it comes time to do PNG, oiio becomes a de-facto required dependency for Blender (e.g. the icons are loaded through PNG). At minimum we'd need to prevent the ability to disable that cmake option, and require it for building, but maybe this is a larger discussion point?

@brecht I'm probably at the point where I can start prepping the individual formats for review this week. I'd start with the support code and the PSD format since that already uses oiio. After that, things can go as fast or as slow as we'd like depending on the time of reviewers with higher priority items on their plates. There's a few items remaining to work through though: Testing and dependencies. **Testing** For testing image loading, I'm using the regular python unittest framework to open each file and then compare Image attributes with what I expect (is_float, colorspace, channel count, and alpha_mode). There's no comparison of what the image looks like however. We'd need a picture of what things look like in the Image Editor or similar. I'm not sure what the best option is here. For save testing, I have a separate script which can create and save the images as necessary. They're created from scratch with a script and each image contains alpha and pixel values either clamped at 1 for 8bit or >1 for float buffers. From there I can use `idiff` for comparison against the saved references. But this doesn't fit with the `render_test` system very well actually. Should I just use the unittest framework here too and perform all the `idiff` calls myself? The main loss would be the nice html report unless I also implement that piece too. **Dependencies** Lastly, when it comes time to do PNG, oiio becomes a de-facto required dependency for Blender (e.g. the icons are loaded through PNG). At minimum we'd need to prevent the ability to disable that cmake option, and require it for building, but maybe this is a larger discussion point?

I'm not entirely sure what it means to review this per file format, I was imaging it to be one change where a single load/save code replaces a bunch of file formats. But maybe it's more convenient to do it in smaller parts, it's not clear to me.

For testing image loading, I would compare against a saved OpenEXR reference image. I think what we need to test is that the scene linear values match, display is a different concern I think.

If using the render test mechanism doesn't work well, it's fine to use a separate Python script. But it should still use the same BLENDER_TEST_UPDATE=1 environment variable as we have for renders and modifiers to update tests. In general it's convenient to be able to add an extra image for testing to some folder without having to update a Python file along with it.

Our own PNG loading code is something we might want to keep for lite builds, so OIIO is not strictly a required dependency.

I'm not entirely sure what it means to review this per file format, I was imaging it to be one change where a single load/save code replaces a bunch of file formats. But maybe it's more convenient to do it in smaller parts, it's not clear to me. For testing image loading, I would compare against a saved OpenEXR reference image. I think what we need to test is that the scene linear values match, display is a different concern I think. If using the render test mechanism doesn't work well, it's fine to use a separate Python script. But it should still use the same `BLENDER_TEST_UPDATE=1` environment variable as we have for renders and modifiers to update tests. In general it's convenient to be able to add an extra image for testing to some folder without having to update a Python file along with it. Our own PNG loading code is something we might want to keep for lite builds, so OIIO is not strictly a required dependency.
Member

Think we may need to re-evaluate the purpose of the lite build, afaik it was always meant as something that builds fast with minimal features. I wouldn't oppose making oiio a required dep (but that be an admin call to make) leading to a slightly more featured lite, as long as it doesn't impact build time, which i expect would be rather minimal especially compared to some non optional components of a lite build like geometry nodes (seriously, why is this a non-optional component? it's very expensive to build) nor am i expecting any regressions in link time , since we're going dynamic with oiio in 3.5. footprint on disk will be slightly larger, but afaik minimal footprint was never really a goal of a lite build?

Think we may need to re-evaluate the purpose of the lite build, afaik it was always meant as something that builds fast with minimal features. I wouldn't oppose making oiio a required dep (but that be an admin call to make) leading to a slightly more featured lite, as long as it doesn't impact build time, which i expect would be rather minimal especially compared to some non optional components of a lite build like geometry nodes (seriously, why is this a non-optional component? it's *very* expensive to build) nor am i expecting any regressions in link time , since we're going dynamic with oiio in 3.5. footprint on disk will be slightly larger, but afaik minimal footprint was never really a goal of a lite build?

Added subscribers: @mont29, @Sergey, @ideasman42

Added subscribers: @mont29, @Sergey, @ideasman42

I think lite is also about keeping Blender easy to build against system libraries. It's not something I personally care much about, but would like to have opinion of maybe @ideasman42, @Sergey or @mont29 about this.

I think lite is also about keeping Blender easy to build against system libraries. It's not something I personally care much about, but would like to have opinion of maybe @ideasman42, @Sergey or @mont29 about this.
Author
Member

The formats maintain their own is_a, load, and save functions still - so no single loader/saver. This was necessary as the saves are very different, some of the loads require specific ImBuf manipulation, formats like DDS have additional code all to their own, and to aid in the review so folks just need to worry about 1 format at a time. I published the WIP all-up patch here: D16640: WIP: Use OpenImageIO for loading and saving nearly all image formats

For the image load test, I'm not sure how to do the comparison though. During development there were many times the image would load incorrectly (too dark, washed out, or ) due to missing a setting on the ImBuf or oiio etc. Would I load both the format image and the exr reference and do a pixel-by-pixel check in python?

The formats maintain their own is_a, load, and save functions still - so no single loader/saver. This was necessary as the saves are very different, some of the loads require specific ImBuf manipulation, formats like DDS have additional code all to their own, and to aid in the review so folks just need to worry about 1 format at a time. I published the WIP all-up patch here: [D16640: WIP: Use OpenImageIO for loading and saving nearly all image formats](https://archive.blender.org/developer/D16640) For the image load test, I'm not sure how to do the comparison though. During development there were many times the image would load incorrectly (too dark, washed out, or ) due to missing a setting on the ImBuf or oiio etc. Would I load both the format image and the exr reference and do a pixel-by-pixel check in python?

Ok, I see that to keep things strictly compatible some code file format. I think it may be easiest to review this in 3 steps like: add tests, add OIIO utilities, replace file formats. I don't mind having it split up per file format if you prefer, it's just not needed from my side as a reviewer.

For the loading test, I was thinking you load the image, save it as EXR, then compare that to a reference EXR. If the EXR saving code is correct, then I think that should catch cases where the image was too dark, washed out, etc.

Looking at the test in bl_imbuf_load.py, the way I would make that work is to write out both an EXR and a text file (with "is_float" and other metadata), per image. And then compare both to reference files, generated by running tests with BLENDER_TEST_UPDATE=1. That way we can easily add images for testing or add a lot of additional metadata to the text file.

Ok, I see that to keep things strictly compatible some code file format. I think it may be easiest to review this in 3 steps like: add tests, add OIIO utilities, replace file formats. I don't mind having it split up per file format if you prefer, it's just not needed from my side as a reviewer. For the loading test, I was thinking you load the image, save it as EXR, then compare that to a reference EXR. If the EXR saving code is correct, then I think that should catch cases where the image was too dark, washed out, etc. Looking at the test in `bl_imbuf_load.py`, the way I would make that work is to write out both an EXR and a text file (with `"is_float"` and other metadata), per image. And then compare both to reference files, generated by running tests with `BLENDER_TEST_UPDATE=1`. That way we can easily add images for testing or add a lot of additional metadata to the text file.

Sorry, was a bit busy to reply faster.

I do not any issues of making OIIO a required dependency. It is easily available on majority of distros now, and I do not see it as a complication of installing libopenimageio-dev alongside with other dependencies.

In fact, I'd rather see core to be streamlined and the amount of permutations reduced. In my experience, those fine-grained optional features and ifdef are crippling the code, introduce compilation errors and bugs, and overall introduce more issues than they solve.

Sorry, was a bit busy to reply faster. I do not any issues of making OIIO a required dependency. It is easily available on majority of distros now, and I do not see it as a complication of installing libopenimageio-dev alongside with other dependencies. In fact, I'd rather see core to be streamlined and the amount of permutations reduced. In my experience, those fine-grained optional features and ifdef are crippling the code, introduce compilation errors and bugs, and overall introduce more issues than they solve.

Am also totally fine making OIIO a mandatory dependency of Blender, as already said this is an easily available library these days.

Am also totally fine making OIIO a mandatory dependency of Blender, as already said this is an easily available library these days.
Author
Member

Alright, I've implemented the tests with the suggestions above. Thanks for the guidance! D16657: Tests: Add tests for image format saving and loading

The 3 checkin approach of tests, then support code, then all formats is ok with me. It's actually a bit simpler so it's entirely up to what reviewers would like.

Lastly, if push comes to shove, we don't have to rush this in for 3.5. I'll be around and able to make changes but if folks have other higher priority things to do, especially considering the holidays, than by all means this can wait until the next train.

Alright, I've implemented the tests with the suggestions above. Thanks for the guidance! [D16657: Tests: Add tests for image format saving and loading](https://archive.blender.org/developer/D16657) The 3 checkin approach of tests, then support code, then all formats is ok with me. It's actually a bit simpler so it's entirely up to what reviewers would like. Lastly, if push comes to shove, we don't have to rush this in for 3.5. I'll be around and able to make changes but if folks have other higher priority things to do, especially considering the holidays, than by all means this can wait until the next train.
Philipp Oeser removed the
Interest
EEVEE & Viewport
label 2023-02-09 15:12:15 +01:00
Bastien Montagne added this to the Core project 2023-02-09 15:43:54 +01:00
Bastien Montagne removed this from the Core project 2023-02-09 18:20:29 +01:00
Philipp Oeser added the
Interest
Core
label 2023-02-10 11:09:22 +01:00

Glad to see this being worked on. Another issue this will solve is with BMPs. Blender currently only supports this format partially. Only BI_RGB compression seem to be supported. BI_BITFIELDS which is another commonly used method along with RLE isn't supported, also losing support for an alpha channel. OpenImageIO seems to have much wider support for Bitmaps.

Glad to see this being worked on. Another issue this will solve is with BMPs. Blender currently only supports this format partially. Only `BI_RGB` compression seem to be supported. `BI_BITFIELDS` which is another commonly used method along with RLE isn't supported, also losing support for an alpha channel. OpenImageIO seems to have much wider [support for Bitmaps](https://openimageio.readthedocs.io/en/latest/builtinplugins.html#bmp).
Sign in to join this conversation.
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset Browser
Interest
Asset Browser Project Overview
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
EEVEE & Viewport
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
EEVEE & Viewport
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Priority
High
Priority
Low
Priority
Normal
Priority
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No project
No Assignees
18 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: blender/blender#101413
No description provided.