Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@joshuamegnauth54
Copy link
Contributor

@joshuamegnauth54 joshuamegnauth54 commented Sep 10, 2025

Possibly closes: #710

Instead of always decoding as RGBA, I manually convert the image from its real color space to RGBA. I'm not sure if this fixes the issue, but it seems like a good thing to do anyway.

I still have to test this so it's a draft for now.

Possibly closes: woelper#710

Instead of always decoding as RGBA, I manually convert the image from
its real color space to RGBA. I'm not sure if this fixes the issue, but
it seems like a good thing to do anyway.
@joshuamegnauth54 joshuamegnauth54 marked this pull request as ready for review September 12, 2025 05:05
@joshuamegnauth54 joshuamegnauth54 force-pushed the heic-use-correct-chroma-space branch from 3e3ef80 to 1cafbd3 Compare September 12, 2025 05:06
@Stoppedpuma
Copy link
Collaborator

Stoppedpuma commented Sep 12, 2025

This PR seems to break these images. This affects thumbnail generation as well.

image

Upclose:

image

@joshuamegnauth54
Copy link
Contributor Author

Do you have samples of the broken images so I can test locally? This patch was a bit hard to figure out, so I'll have to fiddle with the code more till it works. 😅

I tested it with a few HEIC images but not a large range of them because I couldn't find too many samples.

@Stoppedpuma
Copy link
Collaborator

These photos are a friends and I discovered this issue while they were viewing them on my laptop. As they are not mine, I'll ask for permission to send some of the originals for this PR. Do you have a preferred method I would be able to send a few of these privately to you?

@joshuamegnauth54
Copy link
Contributor Author

To clarify, some HEIC images worked but those specific images failed? If we can figure out the format, I can probably fix it without needing the images. If not, you could probably just email them (I think my email is in the commit).

For reference, I tested with these: https://heic.digital/samples/

@Stoppedpuma
Copy link
Collaborator

I've emailed you some sample images, please feel free to let me know if you need more! I can also send you the raws if needed.

Copy link

@awxkee awxkee left a comment

Choose a reason for hiding this comment

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

This implementation is missing many cases that were previously handled internally by libheif.

It’s necessary to account for the following:

  • 8/10 bit depth ( 12 bit depth HEIC's is possible but rare, AFAIK no opensource tools can encode 12 bit, so it's probably not required for HEIC's)
  • YUV range changes
  • YUV matrix changes
  • GBR (identity matrix), which is technically YUV but slightly different and not especially rare.
  • Monochrome is YUV 4:0:0 that should be handled appropriately

There are also YCgCo images sometimes but as far as I know they are not handled out of the box in libheif so it should not be broken.

This won't help with HDR curves because they are different thing.

let buf = image::ImageBuffer::from_vec(width as u32, height as u32, res)
.context("Can't create HEIC/HEIF ImageBuffer with given res")?;
let i = DynamicImage::ImageRgba8(buf);
Some(ColorSpace::YCbCr(chroma)) => {
Copy link

Choose a reason for hiding this comment

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

I'm not sure if this branch is correct one.

It's missing:

  • Checking the image bit depth, and handling or rejecting unsupported depths. Typically, libheif supports 8-bit and 10-bit for HEIC.
  • Accounting that YUV range is subject to change.
  • Accounting for the YUV matrix, which may vary. For HEIC, it is usually BT.709 rather than BT.601. But it's needed to be queried from libheif.

let img = lib_heif.decode(&handle, ColorSpace::Undefined, None)?;

let i = match img.color_space() {
Some(ColorSpace::Rgb(chroma @ (RgbChroma::Rgb | RgbChroma::Rgba))) => {
Copy link

Choose a reason for hiding this comment

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

libheif can use 10 and 12 bits as well, not only 8 bit images.

let width = img.width();
let height = img.height();

let i = DynamicImage::ImageLuma8(
Copy link

Choose a reason for hiding this comment

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

Monochrome used in HEIC is YUV image with only Y plane, so it's required to handle YUV range and YUV matrix as well and image also could be 10 bit.

@joshuamegnauth54
Copy link
Contributor Author

@awxkee I recently realized that I didn't have to do any of this. libheif seems to convert the image on load so the original code was correct. With that said, do you have any ideas concerning the original issue? I would love to fix it.

@Stoppedpuma Yes, I got them and thank you! I have a slightly busy week, but I'll get back to work on this soon as I can.

@Stoppedpuma
Copy link
Collaborator

@Stoppedpuma Yes, I got them and thank you! I have a slightly busy week, but I'll get back to work on this soon as I can.

No worries, take your time!

@awxkee
Copy link

awxkee commented Sep 16, 2025

@joshuamegnauth54

Typical flow to handle HDR image without gainmaps:

  1. Check CICP in image, if it is not present then exit early.
  2. Check transfer function stored in CICP, if it is not PQ or HLG image is not an HDR, at least for CICP case.
  3. As you determined that stored transfer function is HDR one ( PQ or HLG ) this is the time to start actually handle it.
  4. You need to determine at first if driver + display supports requested color space + transfer function. This is system and driver dependent step. Though, I'm not familiar with framework here. Typically needed something like this in Vulkan or in MacOS/iOS.
  5. If HDR surface is available and you determined somehow that driver and display supports it, you just need create it, that's it.
  6. If HDR surface is not available, then you need to perform a tonemapping. ITU-R has recommendation 2408, but this is recomendation only. Tonemapping itself is not strictly defined. It's kind of idea how to put something big into a something small. Thus, there are many possible approaches, but no single "exact" method. Here some tone mapper examples.
  7. In most cases HDR tranfer function combined with Wide Gamut color spaces, if HDR surface is not available in most cases, wide gamut usually isn’t either. Therefore if you'll likely need along with tonemapping step convert Wide Gamut colorspace into sRGB, or some surface that you can create.

This is not actually as complicated as it may seems, but it does require some attention to details.

@joshuamegnauth54
Copy link
Contributor Author

Hmm, if this is dependent on the renderer then it may be best to wait until Oculante moves off Notan.

@Stoppedpuma
Copy link
Collaborator

Hmm, if this is dependent on the renderer then it may be best to wait until Oculante moves off Notan.

I agree, there's a lot of things that we have to change with our move away from Notan (and even for updating Notan before we move away from it).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

HIF (HEIF) files from Canon R10 HDR PQ mode do not display correctly

3 participants