diff --git a/Cargo.lock b/Cargo.lock index 467759302..e083f7589 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -826,6 +826,7 @@ dependencies = [ "image-meta", "indexmap", "itertools", + "kamadak-exif", "lazy_static", "lettre_email", "libc", @@ -1619,6 +1620,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "kamadak-exif" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a5e66d5b5469321038611f7f0e845a48989e4fd54987b6e5bb4c8ae3adbace7" +dependencies = [ + "mutate_once", +] + [[package]] name = "keccak" version = "0.1.0" @@ -1816,6 +1826,12 @@ dependencies = [ "adler32", ] +[[package]] +name = "mutate_once" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16cf681a23b4d0a43fc35024c176437f9dcd818db34e0f42ab456a0ee5ad497b" + [[package]] name = "native-tls" version = "0.2.4" diff --git a/Cargo.toml b/Cargo.toml index 1a51cd505..cdfefa6eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,7 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" chrono = "0.4.6" indexmap = "1.3.0" +kamadak-exif = "0.5" lazy_static = "1.4.0" regex = "1.1.6" rusqlite = { version = "0.23", features = ["bundled"] } diff --git a/src/blob.rs b/src/blob.rs index c417dd129..e412af7cb 100644 --- a/src/blob.rs +++ b/src/blob.rs @@ -14,6 +14,7 @@ use thiserror::Error; use crate::config::Config; use crate::constants::*; use crate::context::Context; +use crate::error::Error; use crate::events::Event; use crate::message; @@ -408,7 +409,13 @@ impl<'a> BlobObject<'a> { return Ok(()); } - let img = img.thumbnail(img_wh, img_wh); + let mut img = img.thumbnail(img_wh, img_wh); + match self.get_exif_orientation(context) { + Ok(90) => img = img.rotate90(), + Ok(180) => img = img.rotate180(), + Ok(270) => img = img.rotate270(), + _ => {} + } img.save(&blob_abs).map_err(|err| BlobError::WriteFailure { blobdir: context.get_blobdir().to_path_buf(), @@ -418,6 +425,24 @@ impl<'a> BlobObject<'a> { Ok(()) } + + pub fn get_exif_orientation(&self, context: &Context) -> Result { + let file = std::fs::File::open(self.to_abs_path())?; + let mut bufreader = std::io::BufReader::new(&file); + let exifreader = exif::Reader::new(); + let exif = exifreader.read_from_container(&mut bufreader)?; + if let Some(orientation) = exif.get_field(exif::Tag::Orientation, exif::In::PRIMARY) { + // possible orientation values are described at http://sylvana.net/jpegcrop/exif_orientation.html + // we only use rotation, in practise, flipping is not used. + match orientation.value.get_uint(0) { + Some(3) => return Ok(180), + Some(6) => return Ok(90), + Some(8) => return Ok(270), + other => warn!(context, "exif orientation value ignored: {:?}", other), + } + } + Ok(0) + } } impl<'a> fmt::Display for BlobObject<'a> {