Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EXIF rotation information should be addressed #395

Closed
kiyoon opened this issue Jul 9, 2024 · 13 comments · Fixed by #468
Closed

EXIF rotation information should be addressed #395

kiyoon opened this issue Jul 9, 2024 · 13 comments · Fixed by #468

Comments

@kiyoon
Copy link

kiyoon commented Jul 9, 2024

Describe the bug
Some photos (especially from digital cameras) bake EXIF rotation information instead of making the aspect ratio actually vertical. Most image viewers read the information and rotate the view. It seems like Oculante doesn't do this and many of my photos are rotated.

Desktop (please complete the following information):

  • OS: macOS 14
@woelper
Copy link
Owner

woelper commented Jul 9, 2024

This is a very good point. I am using the image library for loading most formats and have hoped for a long time to have exif / rotation support from it. Here are related upstream issues:
image-rs/image#2222
image-rs/image#1045

Maybe it is worth considering to rotate the images manually when loading.

@kiyoon
Copy link
Author

kiyoon commented Jul 9, 2024

In zune-imageprocs there is an auto orient function but I'm not so sure if you can use it with image-rs.

@Shnatsel
Copy link

I'm working on Exif orientation support in image for use in wondermagick.

I should get it working in the next few days, but there's no telling how long will it take to get the changes reviewed and released as part of image. You might have to just copy-paste some code if you need it ASAP.

@Shnatsel
Copy link

I got it working in wondermagick, but my implementation relies on several PRs not yet merged into image:
image-rs/image#2291
image-rs/image#2292

@woelper
Copy link
Owner

woelper commented Jul 28, 2024

Wow! Firstly, wondermagick looks amazing!

Super cool you are adding this to image. Maybe all I have to do is wait then? Do you have experience with the time needed in image to merge PRs like yours? If that is a long time away, I might copy and paste some of your solution first.

Cheers!

@Shnatsel
Copy link

My PRs for Exif support have been merged into image git:
image-rs/image#2299
image-rs/image#2319
image-rs/image#2291

You can now make use of them provided you're OK with depending on a git version of image crate.

@woelper
Copy link
Owner

woelper commented Sep 13, 2024

That is amazing news, thanks!

If I recall correctly I am using some other crates that need to match the image crate I am using, so this might be difficult. Also I think I can't publish on crates.io with git dependencies unfortunately...

@Shnatsel
Copy link

image v0.25.4 with the orientation additions has been released. There is also a built-in function for extracting the orientation metadata, without requiring external crates such as kamadak-exif. See the changelog for more details.

@woelper
Copy link
Owner

woelper commented Oct 18, 2024

You are amazing, and thank you for following up now that is released! I have to check if I can replace exif everywhere as I read maybe exif from more formats than image supports. But I'll update image asap!

@Shnatsel
Copy link

Shnatsel commented Oct 19, 2024

I see you're using kamadak-exif. You can keep using it for extracting Exif metadata and then use image to actually apply rotation, like this:

use image::{metadata::Orientation, DynamicImage, ImageReader, ImageDecoder};
use exif::{In, Tag}; // from `kamadak_exif`

let mut decoder = ImageReader::open("file.jpg")?.into_decoder()?;
let raw_exif = decoder.exif_metadata();
let mut image = DynamicImage::from_decoder(decoder)?;

// Parse Exif chunk (if present) and apply the orientation
if let Ok(Some(raw_exif)) = raw_exif {
    let reader = exif::Reader::new();
    let exif = reader.read_raw(raw_exif)?;
    if let Some(orientation) = exif.get_field(Tag::Orientation, In::PRIMARY) {
       if let Some(value) = orientation.value.get_uint(0) {
           if let Some(orientation) = Orientation::from_exif(value as u8) {
               image.apply_orientation(orientation);
           }
       }
   }
}

@woelper
Copy link
Owner

woelper commented Oct 20, 2024

Wow, there is some other good stuff in the release notes. I can probably get rid of other external libraries such as fast blur. Exif support looks good as well!
I was naively expecting functionality to have some kind of auto rotation on load, but your example is much appreciated. I'll probably use the native exif functionality as I have hopes I can throw out kamadak-exif at some point, reducing the dependencies.

@Shnatsel
Copy link

I was naively expecting functionality to have some kind of auto rotation on load

We couldn't add this in a point release because that would be a breaking change: if someone was already read Exif and rotate accordingly, auto-rotation on load would break their code.

I have hopes I can throw out kamadak-exif at some point, reducing the dependencies.

You still need kamadak-exif to parse the extracted Exif chunk if you need things other than the orientation. But it's a robust library in 100% safe code, so I really don't see a good reason to remove it.

@woelper
Copy link
Owner

woelper commented Oct 20, 2024

Thank you for taking the time to respond so quickly! That makes a lot of sense. I've got the rotation already working, and I actually like the flexibility with manually rotating. For JPG I am still using turbojpeg, so I have to manually rotate anyways. Maybe instead of doing this in all loaders I'll try to do this as a post process or generic step after loading is done.

@woelper woelper linked a pull request Oct 21, 2024 that will close this issue
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 a pull request may close this issue.

3 participants