mirror of
https://git.asonix.dog/asonix/pict-rs
synced 2024-12-22 03:11:24 +00:00
Purge image
This commit is contained in:
parent
0fef7abc67
commit
6dab3b30e8
9 changed files with 120 additions and 292 deletions
188
Cargo.lock
generated
188
Cargo.lock
generated
|
@ -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]]
|
||||
|
|
|
@ -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
BIN
client-examples/cat.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 341 KiB |
|
@ -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()
|
||||
|
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
@ -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),
|
||||
|
||||
|
|
46
src/main.rs
46
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<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,36 +203,15 @@ 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?;
|
||||
|
||||
(img, format)
|
||||
};
|
||||
|
||||
debug!("Processing image");
|
||||
let (img, changed) = self::processor::process_image(chain, img).await?;
|
||||
|
||||
if !changed {
|
||||
// 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?;
|
||||
|
||||
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();
|
||||
|
|
|
@ -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> {
|
||||
) -> Result<Option<Bytes>, UploadError> {
|
||||
let original_path_str = ptos(&original_file)?;
|
||||
let span = Span::current();
|
||||
|
||||
let opt = web::block(move || {
|
||||
let entered = span.enter();
|
||||
|
||||
let mut wand = MagickWand::new();
|
||||
debug!("Reading image");
|
||||
wand.op(|w| w.read_image(&original_path_str))?;
|
||||
|
||||
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");
|
||||
let span = Span::current();
|
||||
let tup = web::block(move || {
|
||||
let entered = span.enter();
|
||||
let res = processor.process(img);
|
||||
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);
|
||||
res
|
||||
Ok(None) as Result<Option<Bytes>, UploadError>
|
||||
})
|
||||
.await?;
|
||||
debug!("Step complete");
|
||||
|
||||
img = tup.0;
|
||||
changed |= tup.1;
|
||||
}
|
||||
|
||||
Ok((img, changed))
|
||||
Ok(opt)
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
Loading…
Reference in a new issue