Purge image

This commit is contained in:
asonix 2020-06-16 18:13:22 -05:00
parent 0fef7abc67
commit 6dab3b30e8
9 changed files with 120 additions and 292 deletions

188
Cargo.lock generated
View File

@ -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]]

View File

@ -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"

BIN
client-examples/cat.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 KiB

View File

@ -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()

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -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),

View File

@ -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<ImageOutputFormat, UploadError> {
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();

View File

@ -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<bool, UploadError>;
fn is_whitelisted(whitelist: Option<&HashSet<String>>) -> 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<bool, UploadError> {
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<bool, UploadError> {
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<bool, UploadError> {
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<Option<Bytes>, 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<Option<Bytes>, UploadError>
})
.await?;
Ok(opt)
}

View File

@ -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<String, UploadError> {
pub(crate) fn ptos(p: &PathBuf) -> Result<String, UploadError> {
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");