2021-09-14 01:22:42 +00:00
|
|
|
use crate::{
|
2023-07-13 03:12:21 +00:00
|
|
|
formats::ProcessableFormat,
|
2023-07-10 20:29:41 +00:00
|
|
|
process::{Process, ProcessError},
|
|
|
|
store::Store,
|
2021-09-14 01:22:42 +00:00
|
|
|
};
|
2023-07-13 18:48:59 +00:00
|
|
|
use tokio::io::AsyncRead;
|
2023-07-10 20:29:41 +00:00
|
|
|
|
|
|
|
#[derive(Debug, thiserror::Error)]
|
|
|
|
pub(crate) enum MagickError {
|
|
|
|
#[error("Error in imagemagick process")]
|
|
|
|
Process(#[source] ProcessError),
|
|
|
|
|
|
|
|
#[error("Invalid output format")]
|
|
|
|
Json(#[source] serde_json::Error),
|
|
|
|
|
|
|
|
#[error("Error reading bytes")]
|
|
|
|
Read(#[source] std::io::Error),
|
|
|
|
|
|
|
|
#[error("Error writing bytes")]
|
|
|
|
Write(#[source] std::io::Error),
|
|
|
|
|
|
|
|
#[error("Error creating file")]
|
|
|
|
CreateFile(#[source] std::io::Error),
|
|
|
|
|
|
|
|
#[error("Error creating directory")]
|
|
|
|
CreateDir(#[source] crate::store::file_store::FileError),
|
|
|
|
|
|
|
|
#[error("Error closing file")]
|
|
|
|
CloseFile(#[source] std::io::Error),
|
|
|
|
|
|
|
|
#[error("Error removing file")]
|
|
|
|
RemoveFile(#[source] std::io::Error),
|
|
|
|
|
|
|
|
#[error("Invalid file path")]
|
|
|
|
Path,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl MagickError {
|
|
|
|
pub(crate) fn is_client_error(&self) -> bool {
|
|
|
|
// Failing validation or imagemagick bailing probably means bad input
|
2023-07-13 18:48:59 +00:00
|
|
|
matches!(self, Self::Process(ProcessError::Status(_)))
|
2023-07-10 20:29:41 +00:00
|
|
|
}
|
|
|
|
}
|
2021-08-28 22:15:14 +00:00
|
|
|
|
2023-07-13 03:12:21 +00:00
|
|
|
fn process_image(
|
|
|
|
process_args: Vec<String>,
|
|
|
|
format: ProcessableFormat,
|
|
|
|
) -> Result<Process, ProcessError> {
|
2021-09-14 01:22:42 +00:00
|
|
|
let command = "magick";
|
|
|
|
let convert_args = ["convert", "-"];
|
2023-07-13 03:12:21 +00:00
|
|
|
let last_arg = format!("{}:-", format.magick_format());
|
2021-09-14 01:22:42 +00:00
|
|
|
|
2023-07-13 03:12:21 +00:00
|
|
|
let len = if format.coalesce() {
|
|
|
|
process_args.len() + 4
|
|
|
|
} else {
|
|
|
|
process_args.len() + 3
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut args = Vec::with_capacity(len);
|
2023-07-10 20:29:41 +00:00
|
|
|
args.extend_from_slice(&convert_args[..]);
|
|
|
|
args.extend(process_args.iter().map(|s| s.as_str()));
|
2023-07-13 03:12:21 +00:00
|
|
|
if format.coalesce() {
|
|
|
|
args.push("-coalesce");
|
|
|
|
}
|
2023-07-10 20:29:41 +00:00
|
|
|
args.push(&last_arg);
|
|
|
|
|
|
|
|
Process::run(command, &args)
|
2022-09-25 20:17:33 +00:00
|
|
|
}
|
2021-08-31 02:19:47 +00:00
|
|
|
|
2022-09-25 20:17:33 +00:00
|
|
|
pub(crate) fn process_image_store_read<S: Store + 'static>(
|
|
|
|
store: S,
|
|
|
|
identifier: S::Identifier,
|
|
|
|
args: Vec<String>,
|
2023-07-13 03:12:21 +00:00
|
|
|
format: ProcessableFormat,
|
2023-07-10 20:29:41 +00:00
|
|
|
) -> Result<impl AsyncRead + Unpin, MagickError> {
|
|
|
|
Ok(process_image(args, format)
|
|
|
|
.map_err(MagickError::Process)?
|
|
|
|
.store_read(store, identifier))
|
2022-09-25 20:17:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn process_image_async_read<A: AsyncRead + Unpin + 'static>(
|
|
|
|
async_read: A,
|
|
|
|
args: Vec<String>,
|
2023-07-13 03:12:21 +00:00
|
|
|
format: ProcessableFormat,
|
2023-07-10 20:29:41 +00:00
|
|
|
) -> Result<impl AsyncRead + Unpin, MagickError> {
|
|
|
|
Ok(process_image(args, format)
|
|
|
|
.map_err(MagickError::Process)?
|
|
|
|
.pipe_async_read(async_read))
|
|
|
|
}
|