diff --git a/Cargo.lock b/Cargo.lock index 7ba1ab6..4cfd82d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -79,7 +79,7 @@ dependencies = [ "actix-threadpool", "actix-tls", "actix-utils", - "base64 0.12.1", + "base64 0.12.2", "bitflags", "brotli2", "bytes", @@ -327,9 +327,9 @@ dependencies = [ [[package]] name = "adler32" -version = "1.0.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2" +checksum = "567b077b825e468cc974f0020d4082ee6e03132512f207ef1a02fd5d00d1f32d" [[package]] name = "aho-corasick" @@ -399,7 +399,7 @@ dependencies = [ "actix-http", "actix-rt", "actix-service", - "base64 0.12.1", + "base64 0.12.2", "bytes", "derive_more", "futures-core", @@ -415,13 +415,14 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.48" +version = "0.3.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0df2f85c8a2abbe3b7d7e748052fdd9b76a0458fdeb16ad4223f5eca78c7c130" +checksum = "05100821de9e028f12ae3d189176b41ee198341eb8f369956407fea2f5cc666c" dependencies = [ "addr2line", "cfg-if", "libc", + "miniz_oxide", "object", "rustc-demangle", ] @@ -440,9 +441,9 @@ checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" [[package]] name = "base64" -version = "0.12.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d1ccbaf7d9ec9537465a97bf19edc1a4e158ecb49fc16178202238c569cc42" +checksum = "e223af0dc48c96d4f8342ec01a4974f139df863896b316681efd36742f22cc67" [[package]] name = "bindgen" @@ -539,12 +540,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" -[[package]] -name = "bytemuck" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37fa13df2292ecb479ec23aa06f4507928bef07839be9ef15281411076629431" - [[package]] name = "byteorder" version = "1.3.4" @@ -654,17 +649,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crossbeam-deque" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", - "maybe-uninit", -] - [[package]] name = "crossbeam-epoch" version = "0.8.2" @@ -680,17 +664,6 @@ dependencies = [ "scopeguard", ] -[[package]] -name = "crossbeam-queue" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" -dependencies = [ - "cfg-if", - "crossbeam-utils", - "maybe-uninit", -] - [[package]] name = "crossbeam-utils" version = "0.7.2" @@ -702,21 +675,11 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "deflate" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7e5d2a2273fed52a7f947ee55b092c4057025d7a3e04e5ecdbd25d6c3fb1bd7" -dependencies = [ - "adler32", - "byteorder", -] - [[package]] name = "derive_more" -version = "0.99.7" +version = "0.99.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2127768764f1556535c01b5326ef94bd60ff08dcfbdc544d53e69ed155610f5d" +checksum = "bc655351f820d774679da6cdc23355a93de496867d8203496675162e17b1d671" dependencies = [ "proc-macro2", "quote", @@ -749,9 +712,9 @@ checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" [[package]] name = "dtoa" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4358a9e11b9a09cf52383b451b49a169e8d797b68aa02301ff586d70d9661ea3" +checksum = "134951f4028bdadb9b84baf4232681efbf277da25144b9b0ad65df75946c422b" [[package]] name = "either" @@ -1094,24 +1057,6 @@ dependencies = [ "unicode-normalization", ] -[[package]] -name = "image" -version = "0.23.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d534e95ad8b9d5aa614322d02352b4f1bf962254adcf02ac6f2def8be18498e8" -dependencies = [ - "bytemuck", - "byteorder", - "gif", - "jpeg-decoder", - "num-iter", - "num-rational", - "num-traits", - "png", - "scoped_threadpool", - "tiff", -] - [[package]] name = "indexmap" version = "1.4.0" @@ -1144,19 +1089,9 @@ dependencies = [ [[package]] name = "itoa" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" - -[[package]] -name = "jpeg-decoder" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b47b4c4e017b01abdc5bcc126d2d1002e5a75bbe3ce73f9f4f311a916363704" -dependencies = [ - "byteorder", - "rayon", -] +checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" [[package]] name = "js-sys" @@ -1391,17 +1326,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-iter" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6e6b7c748f995c4c29c5f5ae0248536e04a5739927c74ec0fa564805094b9f" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - [[package]] name = "num-rational" version = "0.2.4" @@ -1434,9 +1358,9 @@ dependencies = [ [[package]] name = "object" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cbca9424c482ee628fa549d9c812e2cd22f1180b9222c9200fdfa6eb31aecb2" +checksum = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5" [[package]] name = "once_cell" @@ -1495,11 +1419,10 @@ dependencies = [ "actix-rt", "actix-web", "anyhow", - "base64 0.12.1", + "base64 0.12.2", "bytes", "futures", "gif", - "image", "magick_rust", "mime", "once_cell", @@ -1555,18 +1478,6 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" -[[package]] -name = "png" -version = "0.16.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34ccdd66f6fe4b2433b07e4728e9a013e43233120427046e93ceb709c3a439bf" -dependencies = [ - "bitflags", - "crc32fast", - "deflate", - "miniz_oxide", -] - [[package]] name = "ppv-lite86" version = "0.2.8" @@ -1676,30 +1587,6 @@ dependencies = [ "rand_core", ] -[[package]] -name = "rayon" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6ce3297f9c85e16621bb8cca38a06779ffc31bb8184e1be4bed2be4678a098" -dependencies = [ - "crossbeam-deque", - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08a89b46efaf957e52b18062fb2f4660f8b8a4dde1807ca002690868ef2c85a9" -dependencies = [ - "crossbeam-deque", - "crossbeam-queue", - "crossbeam-utils", - "lazy_static", - "num_cpus", -] - [[package]] name = "redox_syscall" version = "0.1.56" @@ -1809,12 +1696,6 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" -[[package]] -name = "scoped_threadpool" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" - [[package]] name = "scopeguard" version = "1.1.0" @@ -2057,9 +1938,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] name = "structopt" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "863246aaf5ddd0d6928dfeb1a9ca65f505599e4e1b399935ef7e75107516b4ef" +checksum = "de2f5e239ee807089b62adce73e48c625e0ed80df02c7ab3f068f5db5281065c" dependencies = [ "clap", "lazy_static", @@ -2068,9 +1949,9 @@ dependencies = [ [[package]] name = "structopt-derive" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d239ca4b13aee7a2142e6795cbd69e457665ff8037aed33b3effdc430d2f927a" +checksum = "510413f9de616762a4fbeab62509bf15c729603b72d7cd71280fbca431b1c118" dependencies = [ "heck", "proc-macro-error", @@ -2121,18 +2002,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b13f926965ad00595dd129fa12823b04bbf866e9085ab0a5f2b05b850fbfc344" +checksum = "7dfdd070ccd8ccb78f4ad66bf1982dc37f620ef696c6b5028fe2ed83dd3d0d08" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "893582086c2f98cde18f906265a65b5030a074b1046c674ae898be6519a7f479" +checksum = "bd80fc12f73063ac132ac92aceea36734f04a1d93c1240c6944e23a3b8841793" dependencies = [ "proc-macro2", "quote", @@ -2157,17 +2038,6 @@ dependencies = [ "num_cpus", ] -[[package]] -name = "tiff" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f3b8a87c4da944c3f27e5943289171ac71a6150a79ff6bacfff06d159dfff2f" -dependencies = [ - "byteorder", - "lzw", - "miniz_oxide", -] - [[package]] name = "time" version = "0.1.43" @@ -2438,11 +2308,11 @@ dependencies = [ [[package]] name = "unicode-normalization" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4" +checksum = "6fb19cf769fa8c6a80a162df694621ebeb4dafb606470b2b2fce0be40a98a977" dependencies = [ - "smallvec", + "tinyvec", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index ce711cc..3df8d5c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,6 @@ base64 = "0.12.1" bytes = "0.5" futures = "0.3.4" gif = "0.10.3" -image = "0.23.4" magick_rust = "0.14.0" mime = "0.3.1" once_cell = "1.4.0" diff --git a/client-examples/cat.jpg b/client-examples/cat.jpg new file mode 100644 index 0000000..1e587f8 Binary files /dev/null and b/client-examples/cat.jpg differ diff --git a/client-examples/python/client.py b/client-examples/python/client.py index 6d46abd..9a7a5c3 100755 --- a/client-examples/python/client.py +++ b/client-examples/python/client.py @@ -9,6 +9,8 @@ import aiohttp png_name = '../test.png' gif_name = '../earth.gif' +jpeg_name = '../cat.jpg' +webp_name = '../scene.webp' url = 'http://localhost:8080/image' async def file_sender(file_name=None): @@ -26,6 +28,10 @@ async def req(): data.add_field("images[]", file_sender(file_name=png_name), filename="image2.png", content_type="image/png") data.add_field("images[]", file_sender(file_name=gif_name), filename="image1.gif", content_type="image/gif") data.add_field("images[]", file_sender(file_name=gif_name), filename="image2.gif", content_type="image/gif") + data.add_field("images[]", file_sender(file_name=jpeg_name), filename="image1.jpeg", content_type="image/jpeg") + data.add_field("images[]", file_sender(file_name=jpeg_name), filename="image2.jpeg", content_type="image/jpeg") + data.add_field("images[]", file_sender(file_name=webp_name), filename="image1.webp", content_type="image/webp") + data.add_field("images[]", file_sender(file_name=webp_name), filename="image2.webp", content_type="image/webp") async with session.post(url, data=data) as resp: text = await resp.text() diff --git a/client-examples/1.webp b/client-examples/scene.webp similarity index 100% rename from client-examples/1.webp rename to client-examples/scene.webp diff --git a/src/error.rs b/src/error.rs index 5af73b0..401e4a9 100644 --- a/src/error.rs +++ b/src/error.rs @@ -15,9 +15,6 @@ pub(crate) enum UploadError { #[error("Error parsing string, {0}")] ParseString(#[from] std::string::FromUtf8Error), - #[error("Error processing image, {0}")] - Image(#[from] image::error::ImageError), - #[error("Error interacting with filesystem, {0}")] Io(#[from] std::io::Error), diff --git a/src/main.rs b/src/main.rs index d6e8343..a132dd3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,6 @@ use actix_web::{ web, App, HttpResponse, HttpServer, }; use futures::stream::{Stream, TryStreamExt}; -use image::{ImageFormat, ImageOutputFormat}; use once_cell::sync::Lazy; use std::{collections::HashSet, path::PathBuf, sync::Once}; use structopt::StructOpt; @@ -22,8 +21,8 @@ mod upload_manager; mod validate; use self::{ - config::Config, error::UploadError, middleware::Tracing, upload_manager::UploadManager, - validate::image_webp, + config::Config, error::UploadError, middleware::Tracing, processor::process_image, + upload_manager::UploadManager, validate::image_webp, }; const MEGABYTES: usize = 1024 * 1024; @@ -166,16 +165,6 @@ async fn delete( Ok(HttpResponse::NoContent().finish()) } -fn convert_format(format: ImageFormat) -> Result { - match format { - ImageFormat::Jpeg => Ok(ImageOutputFormat::Jpeg(100)), - ImageFormat::Png => Ok(ImageOutputFormat::Png), - ImageFormat::Gif => Ok(ImageOutputFormat::Gif), - ImageFormat::Bmp => Ok(ImageOutputFormat::Bmp), - _ => Err(UploadError::UnsupportedFormat), - } -} - /// Serve files #[instrument(skip(manager, whitelist))] async fn serve( @@ -214,37 +203,16 @@ async fn serve( let mut original_path = manager.image_dir(); original_path.push(name.clone()); - // Read the image file & produce a DynamicImage - // - // Drop bytes so we don't keep it around in memory longer than we need to - debug!("Reading image"); - let (img, format) = { - let bytes = actix_fs::read(original_path.clone()).await?; - let bytes2 = bytes.clone(); - let format = web::block(move || image::guess_format(&bytes2)).await?; - let img = web::block(move || image::load_from_memory(&bytes)).await?; + // apply chain to the provided image + let img_bytes = match process_image(original_path.clone(), chain).await? { + Some(bytes) => bytes, + None => { + let stream = actix_fs::read_to_stream(original_path).await?; - (img, format) + return Ok(srv_response(stream, ext)); + } }; - debug!("Processing image"); - let (img, changed) = self::processor::process_image(chain, img).await?; - - if !changed { - let stream = actix_fs::read_to_stream(original_path).await?; - - return Ok(srv_response(stream, ext)); - } - - // perform thumbnail operation in a blocking thread - debug!("Exporting image"); - let img_bytes: bytes::Bytes = web::block(move || { - let mut bytes = std::io::Cursor::new(vec![]); - img.write_to(&mut bytes, convert_format(format)?)?; - Ok(bytes::Bytes::from(bytes.into_inner())) as Result<_, UploadError> - }) - .await?; - let path2 = path.clone(); let img_bytes2 = img_bytes.clone(); diff --git a/src/processor.rs b/src/processor.rs index 644a0d6..d6f3328 100644 --- a/src/processor.rs +++ b/src/processor.rs @@ -1,6 +1,10 @@ -use crate::error::UploadError; +use crate::{ + error::UploadError, + validate::{ptos, Op}, +}; use actix_web::web; -use image::{DynamicImage, GenericImageView}; +use bytes::Bytes; +use magick_rust::MagickWand; use std::{collections::HashSet, path::PathBuf}; use tracing::{debug, instrument, Span}; @@ -18,7 +22,7 @@ pub(crate) trait Processor { Self: Sized; fn path(&self, path: PathBuf) -> PathBuf; - fn process(&self, img: DynamicImage) -> Result<(DynamicImage, bool), UploadError>; + fn process(&self, wand: &mut MagickWand) -> Result; fn is_whitelisted(whitelist: Option<&HashSet>) -> bool where @@ -59,12 +63,12 @@ impl Processor for Identity { path } - fn process(&self, img: DynamicImage) -> Result<(DynamicImage, bool), UploadError> { - Ok((img, false)) + fn process(&self, _: &mut MagickWand) -> Result { + Ok(false) } } -pub(crate) struct Thumbnail(u32); +pub(crate) struct Thumbnail(usize); impl Processor for Thumbnail { fn name() -> &'static str @@ -95,17 +99,23 @@ impl Processor for Thumbnail { path } - fn process(&self, img: DynamicImage) -> Result<(DynamicImage, bool), UploadError> { + fn process(&self, wand: &mut MagickWand) -> Result { debug!("Thumbnail"); - if img.width() > self.0 || img.height() > self.0 { - Ok((img.thumbnail(self.0, self.0), true)) + let width = wand.get_image_width(); + let height = wand.get_image_height(); + + if width > self.0 || height > self.0 { + wand.fit(self.0, self.0); + Ok(true) + } else if wand.op(|w| w.get_image_format())? == "GIF" { + Ok(true) } else { - Ok((img, false)) + Ok(false) } } } -pub(crate) struct Blur(f32); +pub(crate) struct Blur(f64); impl Processor for Blur { fn name() -> &'static str @@ -130,12 +140,13 @@ impl Processor for Blur { path } - fn process(&self, img: DynamicImage) -> Result<(DynamicImage, bool), UploadError> { + fn process(&self, wand: &mut MagickWand) -> Result { debug!("Blur"); if self.0 > 0.0 { - Ok((img.blur(self.0), true)) + wand.op(|w| w.gaussian_blur_image(0.0, self.0))?; + Ok(true) } else { - Ok((img, false)) + Ok(false) } } } @@ -188,28 +199,41 @@ pub(crate) fn build_path(base: PathBuf, chain: &ProcessChain, filename: String) path } -#[instrument(skip(img))] +#[instrument] pub(crate) async fn process_image( + original_file: PathBuf, chain: ProcessChain, - mut img: DynamicImage, -) -> Result<(DynamicImage, bool), UploadError> { - let mut changed = false; +) -> Result, UploadError> { + let original_path_str = ptos(&original_file)?; + let span = Span::current(); - for processor in chain.inner.into_iter() { - debug!("Step"); - let span = Span::current(); - let tup = web::block(move || { - let entered = span.enter(); - let res = processor.process(img); - drop(entered); - res - }) - .await?; - debug!("Step complete"); + let opt = web::block(move || { + let entered = span.enter(); - img = tup.0; - changed |= tup.1; - } + let mut wand = MagickWand::new(); + debug!("Reading image"); + wand.op(|w| w.read_image(&original_path_str))?; - Ok((img, changed)) + let format = wand.op(|w| w.get_image_format())?; + + debug!("Processing image"); + let mut changed = false; + + for processor in chain.inner.into_iter() { + debug!("Step"); + changed |= processor.process(&mut wand)?; + debug!("Step complete"); + } + + if changed { + let vec = wand.op(|w| w.write_image_blob(&format))?; + return Ok(Some(Bytes::from(vec))); + } + + drop(entered); + Ok(None) as Result, UploadError> + }) + .await?; + + Ok(opt) } diff --git a/src/validate.rs b/src/validate.rs index aa00a5f..7cbdafd 100644 --- a/src/validate.rs +++ b/src/validate.rs @@ -1,6 +1,5 @@ use crate::{config::Format, error::UploadError, upload_manager::tmp_file}; use actix_web::web; -use image::{io::Reader, ImageFormat}; use magick_rust::MagickWand; use rexiv2::{MediaType, Metadata}; use std::{ @@ -69,10 +68,22 @@ pub(crate) fn image_webp() -> mime::Mime { "image/webp".parse().unwrap() } -fn ptos(p: &PathBuf) -> Result { +pub(crate) fn ptos(p: &PathBuf) -> Result { Ok(p.to_str().ok_or(UploadError::Path)?.to_owned()) } +fn validate_format(file: &str, format: &str) -> Result<(), UploadError> { + let wand = MagickWand::new(); + debug!("reading"); + wand.op(|w| w.read_image(file))?; + + if wand.op(|w| w.get_image_format())? != format { + return Err(UploadError::UnsupportedFormat); + } + + Ok(()) +} + // import & export image using the image crate #[instrument] pub(crate) async fn validate_image( @@ -95,13 +106,7 @@ pub(crate) async fn validate_image( mime::IMAGE_GIF } (Some(Format::Jpeg), MediaType::Jpeg) | (None, MediaType::Jpeg) => { - { - let wand = MagickWand::new(); - debug!("reading: {}", tmpfile_str); - wand.op(|w| w.read_image(&tmpfile_str))?; - - debug!("format: {}", wand.op(|w| w.get_format())?); - } + validate_format(&tmpfile_str, "JPEG")?; meta.clear(); meta.save_to_file(&tmpfile)?; @@ -109,13 +114,7 @@ pub(crate) async fn validate_image( mime::IMAGE_JPEG } (Some(Format::Png), MediaType::Png) | (None, MediaType::Png) => { - { - let wand = MagickWand::new(); - debug!("reading: {}", tmpfile_str); - wand.op(|w| w.read_image(&tmpfile_str))?; - - debug!("format: {}", wand.op(|w| w.get_format())?); - } + validate_format(&tmpfile_str, "PNG")?; meta.clear(); meta.save_to_file(&tmpfile)?; @@ -131,13 +130,12 @@ pub(crate) async fn validate_image( { let wand = MagickWand::new(); - debug!("reading: {}", tmpfile_str); + debug!("reading"); wand.op(|w| w.read_image(&tmpfile_str))?; - debug!("format: {}", wand.op(|w| w.get_format())?); - debug!("image_format: {}", wand.op(|w| w.get_image_format())?); - debug!("type: {}", wand.op(|w| Ok(w.get_type()))?); - debug!("image_type: {}", wand.op(|w| Ok(w.get_image_type()))?); + if wand.op(|w| w.get_image_format())? != "WEBP" { + return Err(UploadError::UnsupportedFormat); + } wand.op(|w| w.write_image(&newfile_str))?; } @@ -155,11 +153,6 @@ pub(crate) async fn validate_image( debug!("reading: {}", tmpfile_str); wand.op(|w| w.read_image(&tmpfile_str))?; - debug!("format: {}", wand.op(|w| w.get_format())?); - debug!("image_format: {}", wand.op(|w| w.get_image_format())?); - debug!("type: {}", wand.op(|w| Ok(w.get_type()))?); - debug!("image_type: {}", wand.op(|w| Ok(w.get_image_type()))?); - wand.op_mut(|w| w.set_image_format(format.to_magick_format()))?; debug!("writing: {}", newfile_str); @@ -184,35 +177,6 @@ pub(crate) async fn validate_image( Ok(content_type) } -#[instrument] -fn convert(from: &PathBuf, to: &PathBuf, format: ImageFormat) -> Result<(), UploadError> { - debug!("Converting"); - let reader = Reader::new(BufReader::new(File::open(from)?)).with_guessed_format()?; - - if reader.format() != Some(format) { - return Err(UploadError::UnsupportedFormat); - } - - let img = reader.decode()?; - - img.save_with_format(to, format)?; - std::fs::rename(to, from)?; - Ok(()) -} - -#[instrument] -fn validate(path: &PathBuf, format: ImageFormat) -> Result<(), UploadError> { - debug!("Validating"); - let reader = Reader::new(BufReader::new(File::open(path)?)).with_guessed_format()?; - - if reader.format() != Some(format) { - return Err(UploadError::UnsupportedFormat); - } - - reader.decode()?; - Ok(()) -} - #[instrument] fn validate_gif(from: &PathBuf, to: &PathBuf) -> Result<(), GifError> { debug!("Transmuting GIF");