Skip to content

Commit

Permalink
Merge pull request #2299 from Shnatsel/exif-rotation
Browse files Browse the repository at this point in the history
Add a function to apply Exif rotation
  • Loading branch information
Shnatsel authored Sep 13, 2024
2 parents 6f41f72 + 6dad395 commit 98ceb71
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 2 deletions.
54 changes: 52 additions & 2 deletions src/dynimage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ use crate::image::{GenericImage, GenericImageView, ImageDecoder, ImageEncoder, I
use crate::image_reader::free_functions;
use crate::math::resize_dimensions;
use crate::traits::Pixel;
use crate::ImageReader;
use crate::{image, Luma, LumaA};
use crate::{imageops, ExtendedColorType};
use crate::{ImageReader, Orientation};
use crate::{Rgb32FImage, Rgba32FImage};

/// A Dynamic Image
Expand Down Expand Up @@ -873,35 +873,85 @@ impl DynamicImage {
}

/// Flip this image vertically
///
/// Use [`apply_orientation`](Self::apply_orientation) of you want to flip the image in-place instead.
#[must_use]
pub fn flipv(&self) -> DynamicImage {
dynamic_map!(*self, ref p => imageops::flip_vertical(p))
}

/// Flip this image vertically in place
fn flipv_in_place(&mut self) {
dynamic_map!(*self, ref mut p, imageops::flip_vertical_in_place(p))
}

/// Flip this image horizontally
///
/// Use [`apply_orientation`](Self::apply_orientation) of you want to flip the image in-place.
#[must_use]
pub fn fliph(&self) -> DynamicImage {
dynamic_map!(*self, ref p => imageops::flip_horizontal(p))
}

/// Flip this image horizontally in place
fn fliph_in_place(&mut self) {
dynamic_map!(*self, ref mut p, imageops::flip_horizontal_in_place(p))
}

/// Rotate this image 90 degrees clockwise.
#[must_use]
pub fn rotate90(&self) -> DynamicImage {
dynamic_map!(*self, ref p => imageops::rotate90(p))
}

/// Rotate this image 180 degrees clockwise.
/// Rotate this image 180 degrees.
///
/// Use [`apply_orientation`](Self::apply_orientation) of you want to rotate the image in-place.
#[must_use]
pub fn rotate180(&self) -> DynamicImage {
dynamic_map!(*self, ref p => imageops::rotate180(p))
}

/// Rotate this image 180 degrees in place.
fn rotate180_in_place(&mut self) {
dynamic_map!(*self, ref mut p, imageops::rotate180_in_place(p))
}

/// Rotate this image 270 degrees clockwise.
#[must_use]
pub fn rotate270(&self) -> DynamicImage {
dynamic_map!(*self, ref p => imageops::rotate270(p))
}

/// Rotates and/or flips the image as indicated by [Orientation].
///
/// Note that for some orientations cannot be efficiently applied in-place.
/// In that case this function will make a copy of the image internally.
///
/// If this matters to you, please see the documentation on the variants of [Orientation]
/// to learn which orientations can and cannot be applied without copying.
pub fn apply_orientation(&mut self, orientation: Orientation) {
let image = self;
match orientation {
Orientation::NoTransforms => (),
Orientation::Rotate90 => *image = image.rotate90(),
Orientation::Rotate180 => image.rotate180_in_place(),
Orientation::Rotate270 => *image = image.rotate270(),
Orientation::FlipHorizontal => image.fliph_in_place(),
Orientation::FlipVertical => image.flipv_in_place(),
Orientation::Rotate90FlipH => {
let mut new_image = image.rotate90();
new_image.fliph_in_place();
*image = new_image;
}
Orientation::Rotate270FlipH => {
let mut new_image = image.rotate270();
new_image.fliph_in_place();
*image = new_image;
}
}
}

/// Encode this image and write it to ```w```.
///
/// Assumes the writer is buffered. In most cases,
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ pub use crate::image_reader::{ImageReader, LimitSupport, Limits};
pub use crate::dynimage::DynamicImage;

pub use crate::animation::{Delay, Frame, Frames};
pub use crate::metadata::Orientation;

// More detailed error type
pub mod error;
Expand Down Expand Up @@ -290,6 +291,7 @@ mod color;
mod dynimage;
mod image;
mod image_reader;
mod metadata;
//TODO delete this module after a few releases
/// deprecated io module the original io module has been renamed to `image_reader`
pub mod io {
Expand Down
56 changes: 56 additions & 0 deletions src/metadata.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/// Describes the transformations to be applied to the image.
/// Compatible with [Exif orientation](https://web.archive.org/web/20200412005226/https://www.impulseadventure.com/photo/exif-orientation.html).
///
/// Orientation is specified in the Exif metadata, and is often written by cameras.
///
/// You can apply it to an image via [`DynamicImage::apply_orientation`](crate::DynamicImage::apply_orientation).
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum Orientation {
/// Do not perform any transformations.
NoTransforms,
/// Rotate by 90 degrees clockwise.
Rotate90,
/// Rotate by 180 degrees. Can be performed in-place.
Rotate180,
/// Rotate by 270 degrees clockwise. Equivalent to rotating by 90 degrees counter-clockwise.
Rotate270,
/// Flip horizontally. Can be performed in-place.
FlipHorizontal,
/// Flip vertically. Can be performed in-place.
FlipVertical,
/// Rotate by 90 degrees clockwise and flip horizontally.
Rotate90FlipH,
/// Rotate by 270 degrees clockwise and flip horizontally.
Rotate270FlipH,
}

impl Orientation {
/// Converts from [Exif orientation](https://web.archive.org/web/20200412005226/https://www.impulseadventure.com/photo/exif-orientation.html)
pub fn from_exif(exif_orientation: u8) -> Option<Self> {
match exif_orientation {
1 => Some(Self::NoTransforms),
2 => Some(Self::FlipHorizontal),
3 => Some(Self::Rotate180),
4 => Some(Self::FlipVertical),
5 => Some(Self::Rotate90FlipH),
6 => Some(Self::Rotate90),
7 => Some(Self::Rotate270FlipH),
8 => Some(Self::Rotate270),
0 | 9.. => None,
}
}

/// Converts into [Exif orientation](https://web.archive.org/web/20200412005226/https://www.impulseadventure.com/photo/exif-orientation.html)
pub fn to_exif(self) -> u8 {
match self {
Self::NoTransforms => 1,
Self::FlipHorizontal => 2,
Self::Rotate180 => 3,
Self::FlipVertical => 4,
Self::Rotate90FlipH => 5,
Self::Rotate90 => 6,
Self::Rotate270FlipH => 7,
Self::Rotate270 => 8,
}
}
}

0 comments on commit 98ceb71

Please sign in to comment.