Rustfmt pass
This commit is contained in:
parent
c09613dbc8
commit
8a6de316ce
66
src/gif.rs
66
src/gif.rs
|
@ -1,7 +1,8 @@
|
|||
use std::ffi::CString;
|
||||
use std::os::raw::{c_int, c_void};
|
||||
|
||||
use crate::{CaesiumError, CSParameters};
|
||||
use crate::utils::CaesiumError;
|
||||
use crate::CSParameters;
|
||||
|
||||
pub fn compress(
|
||||
input_path: String,
|
||||
|
@ -9,7 +10,10 @@ pub fn compress(
|
|||
parameters: &CSParameters,
|
||||
) -> Result<(), CaesiumError> {
|
||||
if parameters.width > 0 || parameters.height > 0 {
|
||||
return Err(CaesiumError { message: "GIF resizing is not supported".to_string(), code: 20400 });
|
||||
return Err(CaesiumError {
|
||||
message: "GIF resizing is not supported".to_string(),
|
||||
code: 20400,
|
||||
});
|
||||
}
|
||||
|
||||
if parameters.optimize {
|
||||
|
@ -21,10 +25,22 @@ pub fn compress(
|
|||
|
||||
fn lossless(input_path: String, output_path: String) -> Result<(), CaesiumError> {
|
||||
let args: Vec<CString> = vec![
|
||||
CString::new(format!("{:?}", std::env::current_exe())).map_err(|e| CaesiumError { message: e.to_string(), code: 20401 })?,
|
||||
CString::new(input_path).map_err(|e| CaesiumError { message: e.to_string(), code: 20402 })?,
|
||||
CString::new(format!("--output={}", output_path)).map_err(|e| CaesiumError { message: e.to_string(), code: 20403 })?,
|
||||
CString::new("--optimize=3").map_err(|e| CaesiumError { message: e.to_string(), code: 20404 })?,
|
||||
CString::new(format!("{:?}", std::env::current_exe())).map_err(|e| CaesiumError {
|
||||
message: e.to_string(),
|
||||
code: 20401,
|
||||
})?,
|
||||
CString::new(input_path).map_err(|e| CaesiumError {
|
||||
message: e.to_string(),
|
||||
code: 20402,
|
||||
})?,
|
||||
CString::new(format!("--output={}", output_path)).map_err(|e| CaesiumError {
|
||||
message: e.to_string(),
|
||||
code: 20403,
|
||||
})?,
|
||||
CString::new("--optimize=3").map_err(|e| CaesiumError {
|
||||
message: e.to_string(),
|
||||
code: 20404,
|
||||
})?,
|
||||
];
|
||||
|
||||
let argv: Vec<_> = args.iter().map(|a| a.as_ptr()).collect();
|
||||
|
@ -34,7 +50,10 @@ fn lossless(input_path: String, output_path: String) -> Result<(), CaesiumError>
|
|||
|
||||
match result {
|
||||
0 => Ok(()),
|
||||
_ => Err(CaesiumError { message: "GIF optimization failed!".to_string(), code: 20405 }),
|
||||
_ => Err(CaesiumError {
|
||||
message: "GIF optimization failed!".to_string(),
|
||||
code: 20405,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -46,12 +65,32 @@ pub fn lossy(
|
|||
) -> Result<(), CaesiumError> {
|
||||
unsafe {
|
||||
let input_file = libc::fopen(
|
||||
CString::new(input_path).map_err(|e| CaesiumError { message: e.to_string(), code: 20406 })?.as_ptr(),
|
||||
CString::new("r").map_err(|e| CaesiumError { message: e.to_string(), code: 20407 })?.as_ptr(),
|
||||
CString::new(input_path)
|
||||
.map_err(|e| CaesiumError {
|
||||
message: e.to_string(),
|
||||
code: 20406,
|
||||
})?
|
||||
.as_ptr(),
|
||||
CString::new("r")
|
||||
.map_err(|e| CaesiumError {
|
||||
message: e.to_string(),
|
||||
code: 20407,
|
||||
})?
|
||||
.as_ptr(),
|
||||
);
|
||||
let output_file = libc::fopen(
|
||||
CString::new(output_path).map_err(|e| CaesiumError { message: e.to_string(), code: 20408 })?.as_ptr(),
|
||||
CString::new("w+").map_err(|e| CaesiumError { message: e.to_string(), code: 20409 })?.as_ptr(),
|
||||
CString::new(output_path)
|
||||
.map_err(|e| CaesiumError {
|
||||
message: e.to_string(),
|
||||
code: 20408,
|
||||
})?
|
||||
.as_ptr(),
|
||||
CString::new("w+")
|
||||
.map_err(|e| CaesiumError {
|
||||
message: e.to_string(),
|
||||
code: 20409,
|
||||
})?
|
||||
.as_ptr(),
|
||||
);
|
||||
let input_stream = gifsicle::Gif_ReadFile(input_file);
|
||||
libc::fclose(input_file);
|
||||
|
@ -69,7 +108,10 @@ pub fn lossy(
|
|||
|
||||
match write_result {
|
||||
1 => Ok(()),
|
||||
_ => Err(CaesiumError { message: "GIF optimization failed!".to_string(), code: 20410 }),
|
||||
_ => Err(CaesiumError {
|
||||
message: "GIF optimization failed!".to_string(),
|
||||
code: 20410,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
64
src/jpeg.rs
64
src/jpeg.rs
|
@ -1,16 +1,17 @@
|
|||
use std::{fs, ptr};
|
||||
use std::{mem};
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::mem;
|
||||
use std::panic::catch_unwind;
|
||||
use std::{fs, ptr};
|
||||
|
||||
use image::ImageOutputFormat::Jpeg;
|
||||
use img_parts::{DynImage, ImageEXIF, ImageICC};
|
||||
use libc::free;
|
||||
use mozjpeg_sys::*;
|
||||
|
||||
use crate::{CaesiumError, CSParameters};
|
||||
use crate::resize::resize;
|
||||
use crate::utils::CaesiumError;
|
||||
use crate::CSParameters;
|
||||
|
||||
static mut JPEG_ERROR: c_int = 0;
|
||||
|
||||
|
@ -28,16 +29,27 @@ pub fn compress(
|
|||
output_path: String,
|
||||
parameters: &CSParameters,
|
||||
) -> Result<(), CaesiumError> {
|
||||
let in_file = fs::read(input_path).map_err(|e| CaesiumError { message: e.to_string(), code: 20100 })?;
|
||||
let in_file = fs::read(input_path).map_err(|e| CaesiumError {
|
||||
message: e.to_string(),
|
||||
code: 20100,
|
||||
})?;
|
||||
|
||||
let out_buffer = compress_to_memory(in_file, parameters)?;
|
||||
let mut out_file = File::create(output_path).map_err(|e| CaesiumError { message: e.to_string(), code: 20101 })?;
|
||||
out_file.write_all(&out_buffer).map_err(|e| CaesiumError { message: e.to_string(), code: 20102 })?;
|
||||
let mut out_file = File::create(output_path).map_err(|e| CaesiumError {
|
||||
message: e.to_string(),
|
||||
code: 20101,
|
||||
})?;
|
||||
out_file.write_all(&out_buffer).map_err(|e| CaesiumError {
|
||||
message: e.to_string(),
|
||||
code: 20102,
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compress_to_memory(mut in_file: Vec<u8>, parameters: &CSParameters) -> Result<Vec<u8>, CaesiumError>
|
||||
{
|
||||
pub fn compress_to_memory(
|
||||
mut in_file: Vec<u8>,
|
||||
parameters: &CSParameters,
|
||||
) -> Result<Vec<u8>, CaesiumError> {
|
||||
if parameters.width > 0 || parameters.height > 0 {
|
||||
if parameters.keep_metadata {
|
||||
let metadata = extract_metadata(in_file.clone());
|
||||
|
@ -55,14 +67,17 @@ pub fn compress_to_memory(mut in_file: Vec<u8>, parameters: &CSParameters) -> Re
|
|||
} else {
|
||||
lossy(in_file, parameters)
|
||||
}
|
||||
}).unwrap_or_else(|_| Err(CaesiumError { message: format!("Internal JPEG error: {}", JPEG_ERROR), code: 20104 }))
|
||||
})
|
||||
.unwrap_or_else(|_| {
|
||||
Err(CaesiumError {
|
||||
message: format!("Internal JPEG error: {}", JPEG_ERROR),
|
||||
code: 20104,
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn lossless(
|
||||
in_file: Vec<u8>,
|
||||
parameters: &CSParameters,
|
||||
) -> Result<Vec<u8>, CaesiumError> {
|
||||
unsafe fn lossless(in_file: Vec<u8>, parameters: &CSParameters) -> Result<Vec<u8>, CaesiumError> {
|
||||
let mut src_info: jpeg_decompress_struct = mem::zeroed();
|
||||
|
||||
let mut src_err = mem::zeroed();
|
||||
|
@ -110,10 +125,7 @@ unsafe fn lossless(
|
|||
jpeg_finish_decompress(&mut src_info);
|
||||
jpeg_destroy_decompress(&mut src_info);
|
||||
|
||||
let slice = std::slice::from_raw_parts(
|
||||
buf,
|
||||
buf_size as usize,
|
||||
);
|
||||
let slice = std::slice::from_raw_parts(buf, buf_size as usize);
|
||||
|
||||
let result = slice.to_vec();
|
||||
|
||||
|
@ -214,10 +226,7 @@ unsafe fn lossy(in_file: Vec<u8>, parameters: &CSParameters) -> Result<Vec<u8>,
|
|||
jpeg_finish_compress(&mut dst_info);
|
||||
jpeg_destroy_compress(&mut dst_info);
|
||||
|
||||
let slice = std::slice::from_raw_parts(
|
||||
buf,
|
||||
buf_size as usize,
|
||||
);
|
||||
let slice = std::slice::from_raw_parts(buf, buf_size as usize);
|
||||
|
||||
let result = slice.to_vec();
|
||||
|
||||
|
@ -265,7 +274,10 @@ fn save_metadata(
|
|||
}
|
||||
}
|
||||
|
||||
unsafe fn write_metadata(src_info: &mut jpeg_decompress_struct, dst_info: &mut jpeg_compress_struct) {
|
||||
unsafe fn write_metadata(
|
||||
src_info: &mut jpeg_decompress_struct,
|
||||
dst_info: &mut jpeg_compress_struct,
|
||||
) {
|
||||
let mut marker = src_info.marker_list;
|
||||
|
||||
while !marker.is_null() {
|
||||
|
@ -279,8 +291,10 @@ unsafe fn write_metadata(src_info: &mut jpeg_decompress_struct, dst_info: &mut j
|
|||
}
|
||||
}
|
||||
|
||||
unsafe fn set_chroma_subsampling(subsampling: ChromaSubsampling, dst_info: &mut jpeg_compress_struct)
|
||||
{
|
||||
unsafe fn set_chroma_subsampling(
|
||||
subsampling: ChromaSubsampling,
|
||||
dst_info: &mut jpeg_compress_struct,
|
||||
) {
|
||||
(*dst_info.comp_info.add(1)).h_samp_factor = 1;
|
||||
(*dst_info.comp_info.add(1)).v_samp_factor = 1;
|
||||
(*dst_info.comp_info.add(2)).h_samp_factor = 1;
|
||||
|
@ -311,4 +325,4 @@ unsafe extern "C" fn error_handler(cinfo: &mut jpeg_common_struct) {
|
|||
panic!("Internal JPEG error: {}", JPEG_ERROR);
|
||||
}
|
||||
|
||||
unsafe extern "C" fn error_message_handler(_cinfo: &mut jpeg_common_struct) {}
|
||||
unsafe extern "C" fn error_message_handler(_cinfo: &mut jpeg_common_struct) {}
|
||||
|
|
148
src/lib.rs
148
src/lib.rs
|
@ -1,30 +1,14 @@
|
|||
extern crate alloc;
|
||||
|
||||
use crate::jpeg::ChromaSubsampling;
|
||||
use crate::utils::{get_filetype_from_memory, get_filetype_from_path, SupportedFileTypes};
|
||||
use alloc::ffi::CString;
|
||||
use std::{cmp, fs};
|
||||
use std::ffi::CStr;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::os::raw::c_char;
|
||||
use crate::jpeg::ChromaSubsampling;
|
||||
|
||||
use crate::utils::{get_filetype_from_memory, get_filetype_from_path, SupportedFileTypes};
|
||||
|
||||
use std::fmt;
|
||||
|
||||
type Result<T> = std::result::Result<T, CaesiumError>;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CaesiumError {
|
||||
pub message: String,
|
||||
pub code: u32,
|
||||
}
|
||||
|
||||
impl fmt::Display for CaesiumError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{} [{}]", self.message, self.code)
|
||||
}
|
||||
}
|
||||
use std::{cmp, fs};
|
||||
use utils::CaesiumError;
|
||||
|
||||
#[cfg(feature = "gif")]
|
||||
mod gif;
|
||||
|
@ -144,7 +128,7 @@ pub unsafe extern "C" fn c_compress_to_size(
|
|||
output_path: *const c_char,
|
||||
params: CCSParameters,
|
||||
max_output_size: usize,
|
||||
return_smallest: bool
|
||||
return_smallest: bool,
|
||||
) -> CCSResult {
|
||||
let mut parameters = c_set_parameters(params);
|
||||
|
||||
|
@ -153,11 +137,11 @@ pub unsafe extern "C" fn c_compress_to_size(
|
|||
CStr::from_ptr(output_path).to_str().unwrap().to_string(),
|
||||
&mut parameters,
|
||||
max_output_size,
|
||||
return_smallest
|
||||
return_smallest,
|
||||
))
|
||||
}
|
||||
|
||||
fn c_return_result(result: Result<()>) -> CCSResult {
|
||||
fn c_return_result(result: utils::Result<()>) -> CCSResult {
|
||||
let mut error_message = CString::new("").unwrap();
|
||||
|
||||
match result {
|
||||
|
@ -201,7 +185,7 @@ fn c_set_parameters(params: CCSParameters) -> CSParameters {
|
|||
422 => ChromaSubsampling::CS422,
|
||||
420 => ChromaSubsampling::CS420,
|
||||
411 => ChromaSubsampling::CS411,
|
||||
_ => ChromaSubsampling::Auto
|
||||
_ => ChromaSubsampling::Auto,
|
||||
};
|
||||
|
||||
parameters
|
||||
|
@ -211,7 +195,7 @@ pub fn compress(
|
|||
input_path: String,
|
||||
output_path: String,
|
||||
parameters: &CSParameters,
|
||||
) -> Result<()> {
|
||||
) -> utils::Result<()> {
|
||||
validate_parameters(parameters)?;
|
||||
let file_type = get_filetype_from_path(&input_path);
|
||||
|
||||
|
@ -232,10 +216,12 @@ pub fn compress(
|
|||
SupportedFileTypes::Gif => {
|
||||
gif::compress(input_path, output_path, parameters)?;
|
||||
}
|
||||
_ => return Err(CaesiumError {
|
||||
message: "Unknown file type".into(),
|
||||
code: 10000,
|
||||
}),
|
||||
_ => {
|
||||
return Err(CaesiumError {
|
||||
message: "Unknown file type".into(),
|
||||
code: 10000,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -244,25 +230,21 @@ pub fn compress(
|
|||
pub fn compress_in_memory(
|
||||
in_file: Vec<u8>,
|
||||
parameters: &mut CSParameters,
|
||||
) -> Result<Vec<u8>> {
|
||||
) -> utils::Result<Vec<u8>> {
|
||||
let file_type = get_filetype_from_memory(in_file.as_slice());
|
||||
let compressed_file = match file_type {
|
||||
#[cfg(feature = "jpg")]
|
||||
SupportedFileTypes::Jpeg => {
|
||||
jpeg::compress_to_memory(in_file, parameters)?
|
||||
}
|
||||
SupportedFileTypes::Jpeg => jpeg::compress_to_memory(in_file, parameters)?,
|
||||
#[cfg(feature = "png")]
|
||||
SupportedFileTypes::Png => {
|
||||
png::compress_to_memory(in_file, parameters)?
|
||||
}
|
||||
SupportedFileTypes::Png => png::compress_to_memory(in_file, parameters)?,
|
||||
#[cfg(feature = "webp")]
|
||||
SupportedFileTypes::WebP => {
|
||||
webp::compress_to_memory(in_file, parameters)?
|
||||
SupportedFileTypes::WebP => webp::compress_to_memory(in_file, parameters)?,
|
||||
_ => {
|
||||
return Err(CaesiumError {
|
||||
message: "Format not supported for compression to size".into(),
|
||||
code: 10200,
|
||||
})
|
||||
}
|
||||
_ => return Err(CaesiumError {
|
||||
message: "Format not supported for compression to size".into(),
|
||||
code: 10200,
|
||||
}),
|
||||
};
|
||||
|
||||
Ok(compressed_file)
|
||||
|
@ -272,8 +254,8 @@ pub fn compress_to_size_in_memory(
|
|||
in_file: Vec<u8>,
|
||||
parameters: &mut CSParameters,
|
||||
max_output_size: usize,
|
||||
return_smallest: bool
|
||||
) -> Result<Vec<u8>> {
|
||||
return_smallest: bool,
|
||||
) -> utils::Result<Vec<u8>> {
|
||||
let file_type = get_filetype_from_memory(&in_file);
|
||||
|
||||
let tolerance_percentage = 2;
|
||||
|
@ -308,15 +290,19 @@ pub fn compress_to_size_in_memory(
|
|||
parameters.webp.quality = quality;
|
||||
webp::compress_to_memory(in_file.clone(), parameters)? //TODO clone
|
||||
}
|
||||
_ => return Err(CaesiumError {
|
||||
message: "Format not supported for compression to size".into(),
|
||||
code: 10200,
|
||||
}),
|
||||
_ => {
|
||||
return Err(CaesiumError {
|
||||
message: "Format not supported for compression to size".into(),
|
||||
code: 10200,
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
let compressed_file_size = compressed_file.len();
|
||||
|
||||
if compressed_file_size <= max_output_size && max_output_size - compressed_file_size < tolerance {
|
||||
if compressed_file_size <= max_output_size
|
||||
&& max_output_size - compressed_file_size < tolerance
|
||||
{
|
||||
break compressed_file;
|
||||
}
|
||||
|
||||
|
@ -332,8 +318,11 @@ pub fn compress_to_size_in_memory(
|
|||
return if return_smallest {
|
||||
Ok(compressed_file)
|
||||
} else {
|
||||
Err(CaesiumError { message: "Cannot compress to desired quality".into(), code: 10202 })
|
||||
}
|
||||
Err(CaesiumError {
|
||||
message: "Cannot compress to desired quality".into(),
|
||||
code: 10202,
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
break compressed_file;
|
||||
|
@ -350,41 +339,70 @@ pub fn compress_to_size(
|
|||
output_path: String,
|
||||
parameters: &mut CSParameters,
|
||||
max_output_size: usize,
|
||||
return_smallest: bool
|
||||
) -> Result<()>
|
||||
{
|
||||
let in_file = fs::read(input_path.clone()).map_err(|e| CaesiumError { message: e.to_string(), code: 10201 })?;
|
||||
return_smallest: bool,
|
||||
) -> utils::Result<()> {
|
||||
let in_file = fs::read(input_path.clone()).map_err(|e| CaesiumError {
|
||||
message: e.to_string(),
|
||||
code: 10201,
|
||||
})?;
|
||||
let original_size = in_file.len();
|
||||
if original_size <= max_output_size {
|
||||
fs::copy(input_path, output_path).map_err(|e| CaesiumError { message: e.to_string(), code: 10202 })?;
|
||||
fs::copy(input_path, output_path).map_err(|e| CaesiumError {
|
||||
message: e.to_string(),
|
||||
code: 10202,
|
||||
})?;
|
||||
return Ok(());
|
||||
}
|
||||
let compressed_file = compress_to_size_in_memory(in_file, parameters, max_output_size, return_smallest)?;
|
||||
let mut out_file = File::create(output_path).map_err(|e| CaesiumError { message: e.to_string(), code: 10203 })?;
|
||||
out_file.write_all(&compressed_file).map_err(|e| CaesiumError { message: e.to_string(), code: 10204 })?;
|
||||
let compressed_file =
|
||||
compress_to_size_in_memory(in_file, parameters, max_output_size, return_smallest)?;
|
||||
let mut out_file = File::create(output_path).map_err(|e| CaesiumError {
|
||||
message: e.to_string(),
|
||||
code: 10203,
|
||||
})?;
|
||||
out_file
|
||||
.write_all(&compressed_file)
|
||||
.map_err(|e| CaesiumError {
|
||||
message: e.to_string(),
|
||||
code: 10204,
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_parameters(parameters: &CSParameters) -> Result<()> {
|
||||
fn validate_parameters(parameters: &CSParameters) -> utils::Result<()> {
|
||||
if parameters.jpeg.quality == 0 || parameters.jpeg.quality > 100 {
|
||||
return Err(CaesiumError { message: "Invalid JPEG quality value".into(), code: 10001 });
|
||||
return Err(CaesiumError {
|
||||
message: "Invalid JPEG quality value".into(),
|
||||
code: 10001,
|
||||
});
|
||||
}
|
||||
|
||||
if parameters.png.quality > 100 {
|
||||
return Err(CaesiumError { message: "Invalid PNG quality value".into(), code: 10002 });
|
||||
return Err(CaesiumError {
|
||||
message: "Invalid PNG quality value".into(),
|
||||
code: 10002,
|
||||
});
|
||||
}
|
||||
|
||||
if parameters.gif.quality > 100 {
|
||||
return Err(CaesiumError { message: "Invalid GIF quality value".into(), code: 10003 });
|
||||
return Err(CaesiumError {
|
||||
message: "Invalid GIF quality value".into(),
|
||||
code: 10003,
|
||||
});
|
||||
}
|
||||
|
||||
if parameters.webp.quality > 100 {
|
||||
return Err(CaesiumError { message: "Invalid WebP quality value".into(), code: 10004 });
|
||||
return Err(CaesiumError {
|
||||
message: "Invalid WebP quality value".into(),
|
||||
code: 10004,
|
||||
});
|
||||
}
|
||||
|
||||
if parameters.optimize && parameters.output_size > 0 {
|
||||
return Err(CaesiumError { message: "Cannot compress to desired size with lossless optimization".into(), code: 10005 });
|
||||
return Err(CaesiumError {
|
||||
message: "Cannot compress to desired size with lossless optimization".into(),
|
||||
code: 10005,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
97
src/png.rs
97
src/png.rs
|
@ -1,4 +1,4 @@
|
|||
use std::{fs};
|
||||
use std::fs;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::num::NonZeroU8;
|
||||
|
@ -6,29 +6,48 @@ use std::num::NonZeroU8;
|
|||
use image::ImageOutputFormat;
|
||||
use oxipng::Deflaters::{Libdeflater, Zopfli};
|
||||
|
||||
use crate::{CaesiumError, CSParameters};
|
||||
use crate::resize::resize;
|
||||
use crate::utils::CaesiumError;
|
||||
use crate::CSParameters;
|
||||
|
||||
pub fn compress(
|
||||
input_path: String,
|
||||
output_path: String,
|
||||
parameters: &CSParameters,
|
||||
) -> Result<(), CaesiumError> {
|
||||
let mut in_file = fs::read(input_path).map_err(|e| CaesiumError { message: e.to_string(), code: 20200 })?;
|
||||
let mut in_file = fs::read(input_path).map_err(|e| CaesiumError {
|
||||
message: e.to_string(),
|
||||
code: 20200,
|
||||
})?;
|
||||
|
||||
if parameters.width > 0 || parameters.height > 0 {
|
||||
in_file = resize(in_file, parameters.width, parameters.height, ImageOutputFormat::Png)?;
|
||||
in_file = resize(
|
||||
in_file,
|
||||
parameters.width,
|
||||
parameters.height,
|
||||
ImageOutputFormat::Png,
|
||||
)?;
|
||||
}
|
||||
|
||||
let optimized_png = compress_to_memory(in_file, parameters)?;
|
||||
let mut output_file_buffer = File::create(output_path).map_err(|e| CaesiumError { message: e.to_string(), code: 20202 })?;
|
||||
output_file_buffer.write_all(optimized_png.as_slice()).map_err(|e| CaesiumError { message: e.to_string(), code: 20203 })?;
|
||||
let mut output_file_buffer = File::create(output_path).map_err(|e| CaesiumError {
|
||||
message: e.to_string(),
|
||||
code: 20202,
|
||||
})?;
|
||||
output_file_buffer
|
||||
.write_all(optimized_png.as_slice())
|
||||
.map_err(|e| CaesiumError {
|
||||
message: e.to_string(),
|
||||
code: 20203,
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compress_to_memory(in_file: Vec<u8>, parameters: &CSParameters) -> Result<Vec<u8>, CaesiumError>
|
||||
{
|
||||
pub fn compress_to_memory(
|
||||
in_file: Vec<u8>,
|
||||
parameters: &CSParameters,
|
||||
) -> Result<Vec<u8>, CaesiumError> {
|
||||
let optimized_png: Vec<u8> = if parameters.optimize {
|
||||
lossless(in_file, parameters)?
|
||||
} else {
|
||||
|
@ -39,25 +58,55 @@ pub fn compress_to_memory(in_file: Vec<u8>, parameters: &CSParameters) -> Result
|
|||
}
|
||||
|
||||
fn lossy(in_file: Vec<u8>, parameters: &CSParameters) -> Result<Vec<u8>, CaesiumError> {
|
||||
let rgba_bitmap = lodepng::decode32(in_file).map_err(|e| CaesiumError { message: e.to_string(), code: 20204 })?;
|
||||
let rgba_bitmap = lodepng::decode32(in_file).map_err(|e| CaesiumError {
|
||||
message: e.to_string(),
|
||||
code: 20204,
|
||||
})?;
|
||||
|
||||
let mut liq = imagequant::new();
|
||||
liq.set_quality(0, parameters.png.quality as u8).map_err(|e| CaesiumError { message: e.to_string(), code: 20205 })?;
|
||||
liq.set_quality(0, parameters.png.quality as u8)
|
||||
.map_err(|e| CaesiumError {
|
||||
message: e.to_string(),
|
||||
code: 20205,
|
||||
})?;
|
||||
|
||||
let mut liq_image = liq.new_image(
|
||||
rgba_bitmap.buffer.as_slice(),
|
||||
rgba_bitmap.width,
|
||||
rgba_bitmap.height,
|
||||
0.0,
|
||||
).map_err(|e| CaesiumError { message: e.to_string(), code: 20206 })?;
|
||||
let mut liq_image = liq
|
||||
.new_image(
|
||||
rgba_bitmap.buffer.as_slice(),
|
||||
rgba_bitmap.width,
|
||||
rgba_bitmap.height,
|
||||
0.0,
|
||||
)
|
||||
.map_err(|e| CaesiumError {
|
||||
message: e.to_string(),
|
||||
code: 20206,
|
||||
})?;
|
||||
|
||||
let mut quantization = liq.quantize(&mut liq_image).map_err(|e| CaesiumError { message: e.to_string(), code: 20207 })?;
|
||||
let mut quantization = liq.quantize(&mut liq_image).map_err(|e| CaesiumError {
|
||||
message: e.to_string(),
|
||||
code: 20207,
|
||||
})?;
|
||||
|
||||
let (palette, pixels) = quantization.remapped(&mut liq_image).map_err(|e| CaesiumError { message: e.to_string(), code: 20208 })?;
|
||||
let (palette, pixels) = quantization
|
||||
.remapped(&mut liq_image)
|
||||
.map_err(|e| CaesiumError {
|
||||
message: e.to_string(),
|
||||
code: 20208,
|
||||
})?;
|
||||
|
||||
let mut encoder = lodepng::Encoder::new();
|
||||
encoder.set_palette(palette.as_slice()).map_err(|e| CaesiumError { message: e.to_string(), code: 20212 })?;
|
||||
let png_vec = encoder.encode(pixels.as_slice(), rgba_bitmap.width, rgba_bitmap.height).map_err(|e| CaesiumError { message: e.to_string(), code: 20209 })?;
|
||||
encoder
|
||||
.set_palette(palette.as_slice())
|
||||
.map_err(|e| CaesiumError {
|
||||
message: e.to_string(),
|
||||
code: 20212,
|
||||
})?;
|
||||
let png_vec = encoder
|
||||
.encode(pixels.as_slice(), rgba_bitmap.width, rgba_bitmap.height)
|
||||
.map_err(|e| CaesiumError {
|
||||
message: e.to_string(),
|
||||
code: 20209,
|
||||
})?;
|
||||
|
||||
Ok(png_vec)
|
||||
}
|
||||
|
@ -77,7 +126,13 @@ fn lossless(in_file: Vec<u8>, parameters: &CSParameters) -> Result<Vec<u8>, Caes
|
|||
oxipng_options.deflate = Libdeflater { compression: 6 };
|
||||
}
|
||||
|
||||
let optimized_png = oxipng::optimize_from_memory(in_file.as_slice(), &oxipng_options).map_err(|e| CaesiumError { message: e.to_string(), code: 20210 })?;
|
||||
let optimized_png =
|
||||
oxipng::optimize_from_memory(in_file.as_slice(), &oxipng_options).map_err(|e| {
|
||||
CaesiumError {
|
||||
message: e.to_string(),
|
||||
code: 20210,
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(optimized_png)
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use std::io::Cursor;
|
||||
|
||||
use image::DynamicImage;
|
||||
use crate::utils::CaesiumError;
|
||||
use image::imageops::FilterType;
|
||||
use image::io::Reader as ImageReader;
|
||||
use crate::CaesiumError;
|
||||
use image::DynamicImage;
|
||||
|
||||
pub fn resize(
|
||||
image_buffer: Vec<u8>,
|
||||
|
@ -13,24 +13,31 @@ pub fn resize(
|
|||
) -> Result<Vec<u8>, CaesiumError> {
|
||||
let mut image = ImageReader::new(Cursor::new(image_buffer))
|
||||
.with_guessed_format()
|
||||
.map_err(|e| CaesiumError { message: e.to_string(), code: 10300 })?
|
||||
.map_err(|e| CaesiumError {
|
||||
message: e.to_string(),
|
||||
code: 10300,
|
||||
})?
|
||||
.decode()
|
||||
.map_err(|e| CaesiumError { message: e.to_string(), code: 10301 })?;
|
||||
.map_err(|e| CaesiumError {
|
||||
message: e.to_string(),
|
||||
code: 10301,
|
||||
})?;
|
||||
|
||||
let dimensions = compute_dimensions(image.width(), image.height(), width, height);
|
||||
image = image.resize_exact(dimensions.0, dimensions.1, FilterType::Lanczos3);
|
||||
|
||||
let mut resized_file: Vec<u8> = vec![];
|
||||
image.write_to(&mut Cursor::new(&mut resized_file), format).map_err(|e| CaesiumError { message: e.to_string(), code: 10302 })?;
|
||||
image
|
||||
.write_to(&mut Cursor::new(&mut resized_file), format)
|
||||
.map_err(|e| CaesiumError {
|
||||
message: e.to_string(),
|
||||
code: 10302,
|
||||
})?;
|
||||
|
||||
Ok(resized_file)
|
||||
}
|
||||
|
||||
pub fn resize_image(
|
||||
image: DynamicImage,
|
||||
width: u32,
|
||||
height: u32,
|
||||
) -> DynamicImage {
|
||||
pub fn resize_image(image: DynamicImage, width: u32, height: u32) -> DynamicImage {
|
||||
let dimensions = compute_dimensions(image.width(), image.height(), width, height);
|
||||
image.resize_exact(dimensions.0, dimensions.1, FilterType::Lanczos3)
|
||||
}
|
||||
|
|
18
src/utils.rs
18
src/utils.rs
|
@ -1,3 +1,4 @@
|
|||
use core::fmt;
|
||||
use infer::Type;
|
||||
|
||||
pub enum SupportedFileTypes {
|
||||
|
@ -12,7 +13,7 @@ pub fn get_filetype_from_path(file_path: &str) -> SupportedFileTypes {
|
|||
match infer::get_from_path(file_path) {
|
||||
Ok(v) => match v {
|
||||
None => SupportedFileTypes::Unkn,
|
||||
Some(ft) => match_supported_filetypes(ft)
|
||||
Some(ft) => match_supported_filetypes(ft),
|
||||
},
|
||||
Err(_) => SupportedFileTypes::Unkn,
|
||||
}
|
||||
|
@ -21,7 +22,7 @@ pub fn get_filetype_from_path(file_path: &str) -> SupportedFileTypes {
|
|||
pub fn get_filetype_from_memory(buf: &[u8]) -> SupportedFileTypes {
|
||||
match infer::get(buf) {
|
||||
None => SupportedFileTypes::Unkn,
|
||||
Some(ft) => match_supported_filetypes(ft)
|
||||
Some(ft) => match_supported_filetypes(ft),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,3 +36,16 @@ fn match_supported_filetypes(ft: Type) -> SupportedFileTypes {
|
|||
}
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, CaesiumError>;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CaesiumError {
|
||||
pub message: String,
|
||||
pub code: u32,
|
||||
}
|
||||
|
||||
impl fmt::Display for CaesiumError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{} [{}]", self.message, self.code)
|
||||
}
|
||||
}
|
||||
|
|
53
src/webp.rs
53
src/webp.rs
|
@ -2,34 +2,55 @@ use std::fs::File;
|
|||
use std::io::{Read, Write};
|
||||
use std::ops::Deref;
|
||||
|
||||
use crate::{CaesiumError, CSParameters};
|
||||
use crate::resize::resize_image;
|
||||
use crate::utils::CaesiumError;
|
||||
use crate::CSParameters;
|
||||
|
||||
pub fn compress(
|
||||
input_path: String,
|
||||
output_path: String,
|
||||
parameters: &CSParameters,
|
||||
) -> Result<(), CaesiumError> {
|
||||
let mut input_file = File::open(input_path).map_err(|e| CaesiumError { message: e.to_string(), code: 20300 })?;
|
||||
let mut input_file = File::open(input_path).map_err(|e| CaesiumError {
|
||||
message: e.to_string(),
|
||||
code: 20300,
|
||||
})?;
|
||||
|
||||
let mut input_data = Vec::new();
|
||||
input_file.read_to_end(&mut input_data).map_err(|e| CaesiumError { message: e.to_string(), code: 20301 })?;
|
||||
input_file
|
||||
.read_to_end(&mut input_data)
|
||||
.map_err(|e| CaesiumError {
|
||||
message: e.to_string(),
|
||||
code: 20301,
|
||||
})?;
|
||||
|
||||
let mut output_file = File::create(output_path).map_err(|e| CaesiumError { message: e.to_string(), code: 20302 })?;
|
||||
let mut output_file = File::create(output_path).map_err(|e| CaesiumError {
|
||||
message: e.to_string(),
|
||||
code: 20302,
|
||||
})?;
|
||||
let compressed_image = compress_to_memory(input_data, parameters)?;
|
||||
output_file.write_all(&compressed_image).map_err(|e| CaesiumError { message: e.to_string(), code: 20303 })?;
|
||||
output_file
|
||||
.write_all(&compressed_image)
|
||||
.map_err(|e| CaesiumError {
|
||||
message: e.to_string(),
|
||||
code: 20303,
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compress_to_memory(in_file: Vec<u8>, parameters: &CSParameters) -> Result<Vec<u8>, CaesiumError>
|
||||
{
|
||||
pub fn compress_to_memory(
|
||||
in_file: Vec<u8>,
|
||||
parameters: &CSParameters,
|
||||
) -> Result<Vec<u8>, CaesiumError> {
|
||||
let decoder = webp::Decoder::new(&in_file);
|
||||
let input_webp = match decoder.decode() {
|
||||
Some(img) => img,
|
||||
None => return Err(CaesiumError {
|
||||
message: "Error decoding WebP image".to_string(),
|
||||
code: 20304,
|
||||
})
|
||||
None => {
|
||||
return Err(CaesiumError {
|
||||
message: "Error decoding WebP image".to_string(),
|
||||
code: 20304,
|
||||
})
|
||||
}
|
||||
};
|
||||
let mut input_image = input_webp.to_image();
|
||||
let must_resize = parameters.width > 0 || parameters.height > 0;
|
||||
|
@ -39,10 +60,12 @@ pub fn compress_to_memory(in_file: Vec<u8>, parameters: &CSParameters) -> Result
|
|||
|
||||
let encoder = match webp::Encoder::from_image(&input_image) {
|
||||
Ok(encoder) => encoder,
|
||||
Err(e) => return Err(CaesiumError {
|
||||
message: e.to_string(),
|
||||
code: 20305,
|
||||
})
|
||||
Err(e) => {
|
||||
return Err(CaesiumError {
|
||||
message: e.to_string(),
|
||||
code: 20305,
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
let encoded_image = if parameters.optimize {
|
||||
|
|
|
@ -4,4 +4,4 @@ pub fn remove_compressed_test_file(file: &str) {
|
|||
if fs::metadata(file).is_ok() {
|
||||
fs::remove_file(file).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::cleanup::remove_compressed_test_file;
|
||||
use std::fs::File;
|
||||
use std::sync::Once;
|
||||
use crate::cleanup::remove_compressed_test_file;
|
||||
|
||||
mod cleanup;
|
||||
|
||||
|
@ -22,8 +22,9 @@ fn compress_to_1_byte() {
|
|||
String::from(output),
|
||||
&mut pars,
|
||||
1,
|
||||
false
|
||||
).expect_err("Cannot compress to desired quality");
|
||||
false,
|
||||
)
|
||||
.expect_err("Cannot compress to desired quality");
|
||||
remove_compressed_test_file(output)
|
||||
}
|
||||
|
||||
|
@ -37,8 +38,9 @@ fn compress_to_1_byte_and_return() {
|
|||
String::from(output),
|
||||
&mut pars,
|
||||
1,
|
||||
true
|
||||
).unwrap();
|
||||
true,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert!(std::path::Path::new(output).exists());
|
||||
assert!(File::open(output).unwrap().metadata().unwrap().len() > 1);
|
||||
|
@ -58,8 +60,9 @@ fn compress_to_10_mb() {
|
|||
String::from(output),
|
||||
&mut pars,
|
||||
max_output_size,
|
||||
false
|
||||
).unwrap();
|
||||
false,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(80, pars.jpeg.quality);
|
||||
assert!(std::path::Path::new(output).exists());
|
||||
|
@ -83,8 +86,9 @@ fn compress_to_range() {
|
|||
String::from(output),
|
||||
&mut pars,
|
||||
max_output_size,
|
||||
false
|
||||
).unwrap();
|
||||
false,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert!(std::path::Path::new(output).exists());
|
||||
assert!(File::open(output).unwrap().metadata().unwrap().len() < max_output_size as u64);
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
use std::sync::Once;
|
||||
use crate::cleanup::remove_compressed_test_file;
|
||||
use std::sync::Once;
|
||||
|
||||
mod cleanup;
|
||||
|
||||
static INIT: Once = Once::new();
|
||||
|
||||
pub fn initialize(file: &str) {
|
||||
INIT.call_once(|| {
|
||||
remove_compressed_test_file(file)
|
||||
});
|
||||
INIT.call_once(|| remove_compressed_test_file(file));
|
||||
}
|
||||
|
||||
// #[test]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::cleanup::remove_compressed_test_file;
|
||||
use dssim::Val;
|
||||
use std::sync::Once;
|
||||
use crate::cleanup::remove_compressed_test_file;
|
||||
|
||||
mod cleanup;
|
||||
|
||||
|
@ -106,7 +106,8 @@ fn compress_corrupted_lossy() {
|
|||
String::from("tests/samples/corrupted.jpg"),
|
||||
String::from(output),
|
||||
&pars,
|
||||
).is_err())
|
||||
)
|
||||
.is_err())
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -142,7 +143,8 @@ fn compress_corrupted_lossless() {
|
|||
String::from("tests/samples/corrupted.jpg"),
|
||||
String::from(output),
|
||||
&pars,
|
||||
).is_err());
|
||||
)
|
||||
.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -86,10 +86,7 @@ fn extract_exif(path: &Path) -> HashMap<String, String> {
|
|||
let exif = exif_reader.read_from_container(&mut bufreader).unwrap();
|
||||
let mut exif_map = HashMap::new();
|
||||
for f in exif.fields() {
|
||||
exif_map.insert(
|
||||
format!("{}", f.tag),
|
||||
f.display_value().to_string(),
|
||||
);
|
||||
exif_map.insert(format!("{}", f.tag), f.display_value().to_string());
|
||||
}
|
||||
|
||||
exif_map
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use std::sync::Once;
|
||||
use crate::cleanup::remove_compressed_test_file;
|
||||
use std::sync::Once;
|
||||
|
||||
mod cleanup;
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ fn compress_20() {
|
|||
String::from(output),
|
||||
¶ms,
|
||||
)
|
||||
.unwrap();
|
||||
.unwrap();
|
||||
assert!(std::path::Path::new(output).exists());
|
||||
assert_eq!(
|
||||
infer::get_from_path(output).unwrap().unwrap().mime_type(),
|
||||
|
@ -43,7 +43,7 @@ fn compress_50() {
|
|||
String::from(output),
|
||||
¶ms,
|
||||
)
|
||||
.unwrap();
|
||||
.unwrap();
|
||||
assert!(std::path::Path::new(output).exists());
|
||||
assert_eq!(
|
||||
infer::get_from_path(output).unwrap().unwrap().mime_type(),
|
||||
|
@ -63,7 +63,7 @@ fn compress_80() {
|
|||
String::from(output),
|
||||
¶ms,
|
||||
)
|
||||
.unwrap();
|
||||
.unwrap();
|
||||
assert!(std::path::Path::new(output).exists());
|
||||
assert_eq!(
|
||||
infer::get_from_path(output).unwrap().unwrap().mime_type(),
|
||||
|
@ -83,7 +83,7 @@ fn compress_100() {
|
|||
String::from(output),
|
||||
¶ms,
|
||||
)
|
||||
.unwrap();
|
||||
.unwrap();
|
||||
assert!(std::path::Path::new(output).exists());
|
||||
assert_eq!(
|
||||
infer::get_from_path(output).unwrap().unwrap().mime_type(),
|
||||
|
@ -103,7 +103,7 @@ fn optimize() {
|
|||
String::from(output),
|
||||
¶ms,
|
||||
)
|
||||
.unwrap();
|
||||
.unwrap();
|
||||
assert!(std::path::Path::new(output).exists());
|
||||
assert_eq!(
|
||||
infer::get_from_path(output).unwrap().unwrap().mime_type(),
|
||||
|
@ -125,7 +125,7 @@ fn downscale_compress_80() {
|
|||
String::from(output),
|
||||
¶ms,
|
||||
)
|
||||
.unwrap();
|
||||
.unwrap();
|
||||
assert!(std::path::Path::new(output).exists());
|
||||
assert_eq!(
|
||||
infer::get_from_path(output).unwrap().unwrap().mime_type(),
|
||||
|
@ -148,7 +148,7 @@ fn downscale_optimize() {
|
|||
String::from(output),
|
||||
¶ms,
|
||||
)
|
||||
.unwrap();
|
||||
.unwrap();
|
||||
assert!(std::path::Path::new(output).exists());
|
||||
assert_eq!(
|
||||
infer::get_from_path(output).unwrap().unwrap().mime_type(),
|
||||
|
|
Loading…
Reference in New Issue