From 3f06edac0d4cf88e061256f1613b61c2eb3e9177 Mon Sep 17 00:00:00 2001 From: Chitoku Date: Sat, 19 Oct 2024 18:29:58 +0900 Subject: [PATCH] Use `image::ImageDecoder::orientation()` for image rotation --- api/Cargo.lock | 16 --------- api/crates/thumbnails/Cargo.toml | 3 -- api/crates/thumbnails/src/processor.rs | 45 ++++++++------------------ 3 files changed, 13 insertions(+), 51 deletions(-) diff --git a/api/Cargo.lock b/api/Cargo.lock index 99a20691..daf3130a 100644 --- a/api/Cargo.lock +++ b/api/Cargo.lock @@ -1992,15 +1992,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "kamadak-exif" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef4fc70d0ab7e5b6bafa30216a6b48705ea964cdfc29c050f2412295eba58077" -dependencies = [ - "mutate_once", -] - [[package]] name = "kqueue" version = "1.0.7" @@ -2255,12 +2246,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "mutate_once" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16cf681a23b4d0a43fc35024c176437f9dcd818db34e0f42ab456a0ee5ad497b" - [[package]] name = "nanorand" version = "0.7.0" @@ -3881,7 +3866,6 @@ dependencies = [ "derive_more", "domain", "image", - "kamadak-exif", "tokio", ] diff --git a/api/crates/thumbnails/Cargo.toml b/api/crates/thumbnails/Cargo.toml index fdfe64a1..63476138 100644 --- a/api/crates/thumbnails/Cargo.toml +++ b/api/crates/thumbnails/Cargo.toml @@ -23,9 +23,6 @@ features = ["constructor"] [dependencies.image] version = "0.25.4" -[dependencies.kamadak-exif] -version = "0.5.5" - [dependencies.tokio] version = "1.40.0" features = ["rt-multi-thread"] diff --git a/api/crates/thumbnails/src/processor.rs b/api/crates/thumbnails/src/processor.rs index 80654aaa..e3bd2b45 100644 --- a/api/crates/thumbnails/src/processor.rs +++ b/api/crates/thumbnails/src/processor.rs @@ -1,4 +1,4 @@ -use std::io::{BufRead, Cursor, Seek, SeekFrom}; +use std::io::{BufRead, Cursor, Seek}; use derive_more::Constructor; use domain::{ @@ -6,8 +6,7 @@ use domain::{ error::{Error, ErrorKind, Result}, processor::media::MediumImageProcessor, }; -use exif::{In, Tag}; -use image::{imageops::{flip_horizontal, flip_vertical, rotate180, rotate270, rotate90}, DynamicImage, ImageReader}; +use image::{DynamicImage, ImageDecoder, ImageReader}; use tokio::task; pub use image::{imageops::FilterType, ImageFormat}; @@ -19,24 +18,8 @@ pub struct InMemoryImageProcessor { thumbnail_filter: FilterType, } -fn rotate(image: DynamicImage, orientation: u32) -> Result { - let image = match orientation { - 1 => image, - 2 => DynamicImage::from(flip_horizontal(&image)), - 3 => DynamicImage::from(rotate180(&image)), - 4 => DynamicImage::from(flip_vertical(&image)), - 5 => DynamicImage::from(flip_horizontal(&rotate90(&image))), - 6 => DynamicImage::from(rotate90(&image)), - 7 => DynamicImage::from(flip_horizontal(&rotate270(&image))), - 8 => DynamicImage::from(rotate270(&image)), - _ => return Err(Error::from(ErrorKind::MediumReplicaDecodeFailed)), - }; - - Ok(image) -} - impl MediumImageProcessor for InMemoryImageProcessor { - async fn generate_thumbnail(&self, mut read: R) -> Result<(OriginalImage, ThumbnailImage)> + async fn generate_thumbnail(&self, read: R) -> Result<(OriginalImage, ThumbnailImage)> where R: BufRead + Seek + Send + 'static, { @@ -45,23 +28,21 @@ impl MediumImageProcessor for InMemoryImageProcessor { let thumbnail_format = self.thumbnail_format; task::spawn_blocking(move || { - let orientation = exif::Reader::new() - .read_from_container(&mut read) - .ok() - .and_then(|e| e.get_field(Tag::Orientation, In::PRIMARY).and_then(|f| f.value.get_uint(0))) - .unwrap_or(1); - - read.seek(SeekFrom::Start(0)) - .map_err(|e| Error::new(ErrorKind::MediumReplicaReadFailed, e))?; - let reader = ImageReader::new(read) .with_guessed_format() .map_err(|e| Error::new(ErrorKind::MediumReplicaReadFailed, e))?; let format = reader.format().ok_or(ErrorKind::MediumReplicaUnsupported)?; - let image = reader.decode() - .map_err(|e| Error::new(ErrorKind::MediumReplicaDecodeFailed, e)) - .and_then(|i| rotate(i, orientation))?; + let mut decoder = reader.into_decoder() + .map_err(|e| Error::new(ErrorKind::MediumReplicaDecodeFailed, e))?; + + let orientation = decoder.orientation() + .map_err(|e| Error::new(ErrorKind::MediumReplicaDecodeFailed, e))?; + + let mut image = DynamicImage::from_decoder(decoder) + .map_err(|e| Error::new(ErrorKind::MediumReplicaDecodeFailed, e))?; + + image.apply_orientation(orientation); let mut body = Vec::new(); let thumbnail = image.resize(thumbnail_size.width, thumbnail_size.height, thumbnail_filter);