diff options
| author | 2021-10-01 17:24:39 +0700 | |
|---|---|---|
| committer | 2021-10-01 17:24:39 +0700 | |
| commit | 569aff331f4fd4e9ead1866f56a8a7170de4b7a5 (patch) | |
| tree | 108879d437cf5ef62ef3dc5a190a36b51e8af6a8 /wgpu/src/image | |
| parent | 4d4c61b887e5721d9eff4085052b24722d1aa082 (diff) | |
| parent | 0621da37a50488c0975da86b2615d2e324daa8d9 (diff) | |
| download | iced-569aff331f4fd4e9ead1866f56a8a7170de4b7a5.tar.gz iced-569aff331f4fd4e9ead1866f56a8a7170de4b7a5.tar.bz2 iced-569aff331f4fd4e9ead1866f56a8a7170de4b7a5.zip | |
Merge pull request #1067 from akavel/deorient
Honor Exif orientation in `iced_wgpu::Image`
Diffstat (limited to '')
| -rw-r--r-- | wgpu/src/image/raster.rs | 100 | 
1 files changed, 95 insertions, 5 deletions
| diff --git a/wgpu/src/image/raster.rs b/wgpu/src/image/raster.rs index d5c62545..e13987b4 100644 --- a/wgpu/src/image/raster.rs +++ b/wgpu/src/image/raster.rs @@ -2,6 +2,8 @@ use crate::image::atlas::{self, Atlas};  use iced_native::image;  use std::collections::{HashMap, HashSet}; +use bitflags::bitflags; +  #[derive(Debug)]  pub enum Memory {      Host(::image_rs::ImageBuffer<::image_rs::Bgra<u8>, Vec<u8>>), @@ -42,15 +44,28 @@ impl Cache {          let memory = match handle.data() {              image::Data::Path(path) => { -                if let Ok(image) = ::image_rs::open(path) { -                    Memory::Host(image.to_bgra8()) +                if let Ok(image) = image_rs::open(path) { +                    let operation = std::fs::File::open(path) +                        .ok() +                        .map(std::io::BufReader::new) +                        .and_then(|mut reader| { +                            Operation::from_exif(&mut reader).ok() +                        }) +                        .unwrap_or_else(Operation::empty); + +                    Memory::Host(operation.perform(image.to_bgra8()))                  } else {                      Memory::NotFound                  }              }              image::Data::Bytes(bytes) => { -                if let Ok(image) = ::image_rs::load_from_memory(&bytes) { -                    Memory::Host(image.to_bgra8()) +                if let Ok(image) = image_rs::load_from_memory(&bytes) { +                    let operation = +                        Operation::from_exif(&mut std::io::Cursor::new(bytes)) +                            .ok() +                            .unwrap_or_else(Operation::empty); + +                    Memory::Host(operation.perform(image.to_bgra8()))                  } else {                      Memory::Invalid                  } @@ -60,7 +75,7 @@ impl Cache {                  height,                  pixels,              } => { -                if let Some(image) = ::image_rs::ImageBuffer::from_vec( +                if let Some(image) = image_rs::ImageBuffer::from_vec(                      *width,                      *height,                      pixels.to_vec(), @@ -132,3 +147,78 @@ impl Cache {          self.map.contains_key(&handle.id())      }  } + +bitflags! { +    struct Operation: u8 { +        const FLIP_HORIZONTALLY = 0b001; +        const ROTATE_180 = 0b010; +        const FLIP_DIAGONALLY = 0b100; +    } +} + +impl Operation { +    // Meaning of the returned value is described e.g. at: +    // https://magnushoff.com/articles/jpeg-orientation/ +    fn from_exif<R>(reader: &mut R) -> Result<Self, exif::Error> +    where +        R: std::io::BufRead + std::io::Seek, +    { +        use std::convert::TryFrom; + +        let exif = exif::Reader::new().read_from_container(reader)?; + +        Ok(exif +            .get_field(exif::Tag::Orientation, exif::In::PRIMARY) +            .and_then(|field| field.value.get_uint(0)) +            .and_then(|value| u8::try_from(value).ok()) +            .and_then(|value| Self::from_bits(value.saturating_sub(1))) +            .unwrap_or_else(Self::empty)) +    } + +    fn perform<P>( +        self, +        image: image_rs::ImageBuffer<P, Vec<P::Subpixel>>, +    ) -> image_rs::ImageBuffer<P, Vec<P::Subpixel>> +    where +        P: image_rs::Pixel + 'static, +    { +        use image_rs::imageops; + +        let mut image = if self.contains(Self::FLIP_DIAGONALLY) { +            flip_diagonally(image) +        } else { +            image +        }; + +        if self.contains(Self::ROTATE_180) { +            imageops::rotate180_in_place(&mut image); +        } + +        if self.contains(Self::FLIP_HORIZONTALLY) { +            imageops::flip_horizontal_in_place(&mut image); +        } + +        image +    } +} + +fn flip_diagonally<I>( +    image: I, +) -> image_rs::ImageBuffer<I::Pixel, Vec<<I::Pixel as image_rs::Pixel>::Subpixel>> +where +    I: image_rs::GenericImage, +    I::Pixel: 'static, +{ +    let (width, height) = image.dimensions(); +    let mut out = image_rs::ImageBuffer::new(height, width); + +    for x in 0..width { +        for y in 0..height { +            let p = image.get_pixel(x, y); + +            out.put_pixel(y, x, p); +        } +    } + +    out +} | 
