TIFF draft
This commit is contained in:
parent
09eb085bf3
commit
4c958aac64
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "libcaesium"
|
name = "libcaesium"
|
||||||
version = "0.14.1"
|
version = "0.15.0"
|
||||||
authors = ["Matteo Paonessa <matteo.paonessa@gmail.com>"]
|
authors = ["Matteo Paonessa <matteo.paonessa@gmail.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
categories = ["multimedia::images"]
|
categories = ["multimedia::images"]
|
||||||
|
@ -21,11 +21,12 @@ repository = "https://github.com/Lymphatus/libcaesium"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["jpg", "png", "webp", "gif", "parallel"]
|
default = ["jpg", "png", "webp", "gif", "tiff", "parallel"]
|
||||||
jpg = ["dep:mozjpeg-sys", "image/jpeg"]
|
jpg = ["dep:mozjpeg-sys", "image/jpeg"]
|
||||||
png = ["dep:oxipng", "dep:lodepng", "dep:imagequant", "image/png"]
|
png = ["dep:oxipng", "dep:lodepng", "dep:imagequant", "image/png"]
|
||||||
webp = ["dep:webp", "image/webp"]
|
webp = ["dep:webp", "image/webp"]
|
||||||
gif = ["dep:gifsicle", "image/gif"]
|
gif = ["dep:gifsicle", "image/gif"]
|
||||||
|
tiff = ["dep:tiff", "image/tiff"]
|
||||||
parallel = ["oxipng?/parallel", "imagequant?/threads", "dssim/threads"]
|
parallel = ["oxipng?/parallel", "imagequant?/threads", "dssim/threads"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
@ -39,7 +40,8 @@ image = { version = "0.24.8", default-features = false }
|
||||||
img-parts = "0.3"
|
img-parts = "0.3"
|
||||||
bytes = "1.5"
|
bytes = "1.5"
|
||||||
lodepng = { version = "3.10", optional = true }
|
lodepng = { version = "3.10", optional = true }
|
||||||
imagequant = {version = "4.3", optional = true, default-features = false}
|
imagequant = { version = "4.3", optional = true, default-features = false }
|
||||||
|
tiff = { version = "0.9", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
dssim = { version = "3.3", default-features = false, features = ["no-macos-vimage"] }
|
dssim = { version = "3.3", default-features = false, features = ["no-macos-vimage"] }
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
use core::fmt;
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::os::raw::{c_int, c_void};
|
use std::os::raw::{c_int, c_void};
|
||||||
|
|
||||||
use crate::utils::CaesiumError;
|
use crate::error::CaesiumError;
|
||||||
use crate::CSParameters;
|
use crate::CSParameters;
|
||||||
|
|
||||||
pub fn compress(
|
pub fn compress(
|
||||||
|
|
|
@ -0,0 +1,111 @@
|
||||||
|
use crate::jpeg::ChromaSubsampling;
|
||||||
|
use crate::{compress, compress_to_size, error, initialize_parameters, CSParameters};
|
||||||
|
use std::ffi::{CStr, CString};
|
||||||
|
use std::os::raw::c_char;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct CCSParameters {
|
||||||
|
pub keep_metadata: bool,
|
||||||
|
pub jpeg_quality: u32,
|
||||||
|
pub jpeg_chroma_subsampling: u32,
|
||||||
|
pub png_quality: u32,
|
||||||
|
pub png_force_zopfli: bool,
|
||||||
|
pub gif_quality: u32,
|
||||||
|
pub webp_quality: u32,
|
||||||
|
pub optimize: bool,
|
||||||
|
pub width: u32,
|
||||||
|
pub height: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct CCSResult {
|
||||||
|
pub success: bool,
|
||||||
|
pub code: u32,
|
||||||
|
pub error_message: *const c_char,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
#[allow(clippy::missing_safety_doc)]
|
||||||
|
pub unsafe extern "C" fn c_compress(
|
||||||
|
input_path: *const c_char,
|
||||||
|
output_path: *const c_char,
|
||||||
|
params: CCSParameters,
|
||||||
|
) -> CCSResult {
|
||||||
|
let parameters = c_set_parameters(params);
|
||||||
|
|
||||||
|
c_return_result(compress(
|
||||||
|
CStr::from_ptr(input_path).to_str().unwrap().to_string(),
|
||||||
|
CStr::from_ptr(output_path).to_str().unwrap().to_string(),
|
||||||
|
¶meters,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
#[allow(clippy::missing_safety_doc)]
|
||||||
|
pub unsafe extern "C" fn c_compress_to_size(
|
||||||
|
input_path: *const c_char,
|
||||||
|
output_path: *const c_char,
|
||||||
|
params: CCSParameters,
|
||||||
|
max_output_size: usize,
|
||||||
|
return_smallest: bool,
|
||||||
|
) -> CCSResult {
|
||||||
|
let mut parameters = c_set_parameters(params);
|
||||||
|
|
||||||
|
c_return_result(compress_to_size(
|
||||||
|
CStr::from_ptr(input_path).to_str().unwrap().to_string(),
|
||||||
|
CStr::from_ptr(output_path).to_str().unwrap().to_string(),
|
||||||
|
&mut parameters,
|
||||||
|
max_output_size,
|
||||||
|
return_smallest,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn c_return_result(result: error::Result<()>) -> CCSResult {
|
||||||
|
let mut error_message = CString::new("").unwrap();
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(_) => {
|
||||||
|
let em_pointer = error_message.as_ptr();
|
||||||
|
std::mem::forget(error_message);
|
||||||
|
CCSResult {
|
||||||
|
success: true,
|
||||||
|
code: 0,
|
||||||
|
error_message: em_pointer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error_message = CString::new(e.to_string()).unwrap();
|
||||||
|
let em_pointer = error_message.as_ptr();
|
||||||
|
std::mem::forget(error_message);
|
||||||
|
CCSResult {
|
||||||
|
success: false,
|
||||||
|
code: e.code,
|
||||||
|
error_message: em_pointer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn c_set_parameters(params: CCSParameters) -> CSParameters {
|
||||||
|
let mut parameters = initialize_parameters();
|
||||||
|
|
||||||
|
parameters.jpeg.quality = params.jpeg_quality;
|
||||||
|
parameters.png.quality = params.png_quality;
|
||||||
|
parameters.optimize = params.optimize;
|
||||||
|
parameters.keep_metadata = params.keep_metadata;
|
||||||
|
parameters.png.force_zopfli = params.png_force_zopfli;
|
||||||
|
parameters.gif.quality = params.gif_quality;
|
||||||
|
parameters.webp.quality = params.webp_quality;
|
||||||
|
parameters.width = params.width;
|
||||||
|
parameters.height = params.height;
|
||||||
|
|
||||||
|
parameters.jpeg.chroma_subsampling = match params.jpeg_chroma_subsampling {
|
||||||
|
444 => ChromaSubsampling::CS444,
|
||||||
|
422 => ChromaSubsampling::CS422,
|
||||||
|
420 => ChromaSubsampling::CS420,
|
||||||
|
411 => ChromaSubsampling::CS411,
|
||||||
|
_ => ChromaSubsampling::Auto,
|
||||||
|
};
|
||||||
|
|
||||||
|
parameters
|
||||||
|
}
|
|
@ -10,8 +10,8 @@ use img_parts::{ImageEXIF, ImageICC};
|
||||||
use libc::free;
|
use libc::free;
|
||||||
use mozjpeg_sys::*;
|
use mozjpeg_sys::*;
|
||||||
|
|
||||||
|
use crate::error::CaesiumError;
|
||||||
use crate::resize::resize;
|
use crate::resize::resize;
|
||||||
use crate::utils::CaesiumError;
|
|
||||||
use crate::CSParameters;
|
use crate::CSParameters;
|
||||||
|
|
||||||
static mut JPEG_ERROR: c_int = 0;
|
static mut JPEG_ERROR: c_int = 0;
|
||||||
|
|
157
src/lib.rs
157
src/lib.rs
|
@ -1,47 +1,30 @@
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use crate::jpeg::ChromaSubsampling;
|
use crate::jpeg::ChromaSubsampling;
|
||||||
|
use crate::tiff::TiffCompression;
|
||||||
|
use crate::tiff::TiffCompression::Deflate;
|
||||||
use crate::utils::{get_filetype_from_memory, get_filetype_from_path, SupportedFileTypes};
|
use crate::utils::{get_filetype_from_memory, get_filetype_from_path, SupportedFileTypes};
|
||||||
use alloc::ffi::CString;
|
use ::tiff::encoder::compression::DeflateLevel;
|
||||||
use std::ffi::CStr;
|
use error::CaesiumError;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::os::raw::c_char;
|
|
||||||
use std::{cmp, fs};
|
use std::{cmp, fs};
|
||||||
use utils::CaesiumError;
|
|
||||||
|
|
||||||
|
mod error;
|
||||||
#[cfg(feature = "gif")]
|
#[cfg(feature = "gif")]
|
||||||
mod gif;
|
mod gif;
|
||||||
|
mod interface;
|
||||||
#[cfg(feature = "jpg")]
|
#[cfg(feature = "jpg")]
|
||||||
pub mod jpeg;
|
pub mod jpeg;
|
||||||
#[cfg(feature = "png")]
|
#[cfg(feature = "png")]
|
||||||
mod png;
|
mod png;
|
||||||
mod resize;
|
mod resize;
|
||||||
|
#[cfg(feature = "tiff")]
|
||||||
|
mod tiff;
|
||||||
mod utils;
|
mod utils;
|
||||||
#[cfg(feature = "webp")]
|
#[cfg(feature = "webp")]
|
||||||
mod webp;
|
mod webp;
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct CCSParameters {
|
|
||||||
pub keep_metadata: bool,
|
|
||||||
pub jpeg_quality: u32,
|
|
||||||
pub jpeg_chroma_subsampling: u32,
|
|
||||||
pub png_quality: u32,
|
|
||||||
pub png_force_zopfli: bool,
|
|
||||||
pub gif_quality: u32,
|
|
||||||
pub webp_quality: u32,
|
|
||||||
pub optimize: bool,
|
|
||||||
pub width: u32,
|
|
||||||
pub height: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct CCSResult {
|
|
||||||
pub success: bool,
|
|
||||||
pub code: u32,
|
|
||||||
pub error_message: *const c_char,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct JpegParameters {
|
pub struct JpegParameters {
|
||||||
pub quality: u32,
|
pub quality: u32,
|
||||||
|
@ -64,12 +47,19 @@ pub struct WebPParameters {
|
||||||
pub quality: u32,
|
pub quality: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct TiffParameters {
|
||||||
|
pub algorithm: TiffCompression,
|
||||||
|
pub deflate_level: DeflateLevel,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct CSParameters {
|
pub struct CSParameters {
|
||||||
pub jpeg: JpegParameters,
|
pub jpeg: JpegParameters,
|
||||||
pub png: PngParameters,
|
pub png: PngParameters,
|
||||||
pub gif: GifParameters,
|
pub gif: GifParameters,
|
||||||
pub webp: WebPParameters,
|
pub webp: WebPParameters,
|
||||||
|
pub tiff: TiffParameters,
|
||||||
pub keep_metadata: bool,
|
pub keep_metadata: bool,
|
||||||
pub optimize: bool,
|
pub optimize: bool,
|
||||||
pub width: u32,
|
pub width: u32,
|
||||||
|
@ -82,21 +72,23 @@ pub fn initialize_parameters() -> CSParameters {
|
||||||
quality: 80,
|
quality: 80,
|
||||||
chroma_subsampling: ChromaSubsampling::Auto,
|
chroma_subsampling: ChromaSubsampling::Auto,
|
||||||
};
|
};
|
||||||
|
|
||||||
let png = PngParameters {
|
let png = PngParameters {
|
||||||
quality: 80,
|
quality: 80,
|
||||||
force_zopfli: false,
|
force_zopfli: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let gif = GifParameters { quality: 80 };
|
let gif = GifParameters { quality: 80 };
|
||||||
|
|
||||||
let webp = WebPParameters { quality: 80 };
|
let webp = WebPParameters { quality: 80 };
|
||||||
|
let tiff = TiffParameters {
|
||||||
|
algorithm: Deflate,
|
||||||
|
deflate_level: DeflateLevel::Balanced,
|
||||||
|
};
|
||||||
|
|
||||||
CSParameters {
|
CSParameters {
|
||||||
jpeg,
|
jpeg,
|
||||||
png,
|
png,
|
||||||
gif,
|
gif,
|
||||||
webp,
|
webp,
|
||||||
|
tiff,
|
||||||
keep_metadata: false,
|
keep_metadata: false,
|
||||||
optimize: false,
|
optimize: false,
|
||||||
width: 0,
|
width: 0,
|
||||||
|
@ -105,97 +97,11 @@ pub fn initialize_parameters() -> CSParameters {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
#[allow(clippy::missing_safety_doc)]
|
|
||||||
pub unsafe extern "C" fn c_compress(
|
|
||||||
input_path: *const c_char,
|
|
||||||
output_path: *const c_char,
|
|
||||||
params: CCSParameters,
|
|
||||||
) -> CCSResult {
|
|
||||||
let parameters = c_set_parameters(params);
|
|
||||||
|
|
||||||
c_return_result(compress(
|
|
||||||
CStr::from_ptr(input_path).to_str().unwrap().to_string(),
|
|
||||||
CStr::from_ptr(output_path).to_str().unwrap().to_string(),
|
|
||||||
¶meters,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
#[allow(clippy::missing_safety_doc)]
|
|
||||||
pub unsafe extern "C" fn c_compress_to_size(
|
|
||||||
input_path: *const c_char,
|
|
||||||
output_path: *const c_char,
|
|
||||||
params: CCSParameters,
|
|
||||||
max_output_size: usize,
|
|
||||||
return_smallest: bool,
|
|
||||||
) -> CCSResult {
|
|
||||||
let mut parameters = c_set_parameters(params);
|
|
||||||
|
|
||||||
c_return_result(compress_to_size(
|
|
||||||
CStr::from_ptr(input_path).to_str().unwrap().to_string(),
|
|
||||||
CStr::from_ptr(output_path).to_str().unwrap().to_string(),
|
|
||||||
&mut parameters,
|
|
||||||
max_output_size,
|
|
||||||
return_smallest,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn c_return_result(result: utils::Result<()>) -> CCSResult {
|
|
||||||
let mut error_message = CString::new("").unwrap();
|
|
||||||
|
|
||||||
match result {
|
|
||||||
Ok(_) => {
|
|
||||||
let em_pointer = error_message.as_ptr();
|
|
||||||
std::mem::forget(error_message);
|
|
||||||
CCSResult {
|
|
||||||
success: true,
|
|
||||||
code: 0,
|
|
||||||
error_message: em_pointer,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
error_message = CString::new(e.to_string()).unwrap();
|
|
||||||
let em_pointer = error_message.as_ptr();
|
|
||||||
std::mem::forget(error_message);
|
|
||||||
CCSResult {
|
|
||||||
success: false,
|
|
||||||
code: e.code,
|
|
||||||
error_message: em_pointer,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn c_set_parameters(params: CCSParameters) -> CSParameters {
|
|
||||||
let mut parameters = initialize_parameters();
|
|
||||||
|
|
||||||
parameters.jpeg.quality = params.jpeg_quality;
|
|
||||||
parameters.png.quality = params.png_quality;
|
|
||||||
parameters.optimize = params.optimize;
|
|
||||||
parameters.keep_metadata = params.keep_metadata;
|
|
||||||
parameters.png.force_zopfli = params.png_force_zopfli;
|
|
||||||
parameters.gif.quality = params.gif_quality;
|
|
||||||
parameters.webp.quality = params.webp_quality;
|
|
||||||
parameters.width = params.width;
|
|
||||||
parameters.height = params.height;
|
|
||||||
|
|
||||||
parameters.jpeg.chroma_subsampling = match params.jpeg_chroma_subsampling {
|
|
||||||
444 => ChromaSubsampling::CS444,
|
|
||||||
422 => ChromaSubsampling::CS422,
|
|
||||||
420 => ChromaSubsampling::CS420,
|
|
||||||
411 => ChromaSubsampling::CS411,
|
|
||||||
_ => ChromaSubsampling::Auto,
|
|
||||||
};
|
|
||||||
|
|
||||||
parameters
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compress(
|
pub fn compress(
|
||||||
input_path: String,
|
input_path: String,
|
||||||
output_path: String,
|
output_path: String,
|
||||||
parameters: &CSParameters,
|
parameters: &CSParameters,
|
||||||
) -> utils::Result<()> {
|
) -> error::Result<()> {
|
||||||
validate_parameters(parameters)?;
|
validate_parameters(parameters)?;
|
||||||
let file_type = get_filetype_from_path(&input_path);
|
let file_type = get_filetype_from_path(&input_path);
|
||||||
|
|
||||||
|
@ -216,11 +122,15 @@ pub fn compress(
|
||||||
SupportedFileTypes::Gif => {
|
SupportedFileTypes::Gif => {
|
||||||
gif::compress(input_path, output_path, parameters)?;
|
gif::compress(input_path, output_path, parameters)?;
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "tiff")]
|
||||||
|
SupportedFileTypes::Tiff => {
|
||||||
|
tiff::compress(input_path, output_path, parameters)?;
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(CaesiumError {
|
return Err(CaesiumError {
|
||||||
message: "Unknown file type".into(),
|
message: "Unknown file type".into(),
|
||||||
code: 10000,
|
code: 10000,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,7 +140,7 @@ pub fn compress(
|
||||||
pub fn compress_in_memory(
|
pub fn compress_in_memory(
|
||||||
in_file: Vec<u8>,
|
in_file: Vec<u8>,
|
||||||
parameters: &mut CSParameters,
|
parameters: &mut CSParameters,
|
||||||
) -> utils::Result<Vec<u8>> {
|
) -> error::Result<Vec<u8>> {
|
||||||
let file_type = get_filetype_from_memory(in_file.as_slice());
|
let file_type = get_filetype_from_memory(in_file.as_slice());
|
||||||
let compressed_file = match file_type {
|
let compressed_file = match file_type {
|
||||||
#[cfg(feature = "jpg")]
|
#[cfg(feature = "jpg")]
|
||||||
|
@ -239,11 +149,13 @@ pub fn compress_in_memory(
|
||||||
SupportedFileTypes::Png => png::compress_to_memory(in_file, parameters)?,
|
SupportedFileTypes::Png => png::compress_to_memory(in_file, parameters)?,
|
||||||
#[cfg(feature = "webp")]
|
#[cfg(feature = "webp")]
|
||||||
SupportedFileTypes::WebP => webp::compress_to_memory(in_file, parameters)?,
|
SupportedFileTypes::WebP => webp::compress_to_memory(in_file, parameters)?,
|
||||||
|
#[cfg(feature = "tiff")]
|
||||||
|
SupportedFileTypes::Tiff => tiff::compress_to_memory(in_file, parameters)?,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(CaesiumError {
|
return Err(CaesiumError {
|
||||||
message: "Format not supported for compression to size".into(),
|
message: "Format not supported for compression to size".into(),
|
||||||
code: 10200,
|
code: 10200,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -255,7 +167,7 @@ pub fn compress_to_size_in_memory(
|
||||||
parameters: &mut CSParameters,
|
parameters: &mut CSParameters,
|
||||||
max_output_size: usize,
|
max_output_size: usize,
|
||||||
return_smallest: bool,
|
return_smallest: bool,
|
||||||
) -> utils::Result<Vec<u8>> {
|
) -> error::Result<Vec<u8>> {
|
||||||
let file_type = get_filetype_from_memory(&in_file);
|
let file_type = get_filetype_from_memory(&in_file);
|
||||||
|
|
||||||
let tolerance_percentage = 2;
|
let tolerance_percentage = 2;
|
||||||
|
@ -290,11 +202,12 @@ pub fn compress_to_size_in_memory(
|
||||||
parameters.webp.quality = quality;
|
parameters.webp.quality = quality;
|
||||||
webp::compress_to_memory(in_file.clone(), parameters)? //TODO clone
|
webp::compress_to_memory(in_file.clone(), parameters)? //TODO clone
|
||||||
}
|
}
|
||||||
|
//TODO Tiff
|
||||||
_ => {
|
_ => {
|
||||||
return Err(CaesiumError {
|
return Err(CaesiumError {
|
||||||
message: "Format not supported for compression to size".into(),
|
message: "Format not supported for compression to size".into(),
|
||||||
code: 10200,
|
code: 10200,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -340,7 +253,7 @@ pub fn compress_to_size(
|
||||||
parameters: &mut CSParameters,
|
parameters: &mut CSParameters,
|
||||||
max_output_size: usize,
|
max_output_size: usize,
|
||||||
return_smallest: bool,
|
return_smallest: bool,
|
||||||
) -> utils::Result<()> {
|
) -> error::Result<()> {
|
||||||
let in_file = fs::read(input_path.clone()).map_err(|e| CaesiumError {
|
let in_file = fs::read(input_path.clone()).map_err(|e| CaesiumError {
|
||||||
message: e.to_string(),
|
message: e.to_string(),
|
||||||
code: 10201,
|
code: 10201,
|
||||||
|
@ -369,7 +282,7 @@ pub fn compress_to_size(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_parameters(parameters: &CSParameters) -> utils::Result<()> {
|
fn validate_parameters(parameters: &CSParameters) -> error::Result<()> {
|
||||||
if parameters.jpeg.quality == 0 || parameters.jpeg.quality > 100 {
|
if parameters.jpeg.quality == 0 || parameters.jpeg.quality > 100 {
|
||||||
return Err(CaesiumError {
|
return Err(CaesiumError {
|
||||||
message: "Invalid JPEG quality value".into(),
|
message: "Invalid JPEG quality value".into(),
|
||||||
|
|
|
@ -6,8 +6,8 @@ use std::num::NonZeroU8;
|
||||||
use image::ImageOutputFormat;
|
use image::ImageOutputFormat;
|
||||||
use oxipng::Deflaters::{Libdeflater, Zopfli};
|
use oxipng::Deflaters::{Libdeflater, Zopfli};
|
||||||
|
|
||||||
|
use crate::error::CaesiumError;
|
||||||
use crate::resize::resize;
|
use crate::resize::resize;
|
||||||
use crate::utils::CaesiumError;
|
|
||||||
use crate::CSParameters;
|
use crate::CSParameters;
|
||||||
|
|
||||||
pub fn compress(
|
pub fn compress(
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
|
||||||
use crate::utils::CaesiumError;
|
use crate::error::CaesiumError;
|
||||||
use image::imageops::FilterType;
|
use image::imageops::FilterType;
|
||||||
use image::io::Reader as ImageReader;
|
use image::io::Reader as ImageReader;
|
||||||
use image::DynamicImage;
|
use image::DynamicImage;
|
||||||
|
|
|
@ -0,0 +1,164 @@
|
||||||
|
use crate::error::CaesiumError;
|
||||||
|
use crate::CSParameters;
|
||||||
|
use image::ImageFormat::Tiff;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{Cursor, Read, Write};
|
||||||
|
use tiff::encoder::colortype::{RGB8, RGBA8};
|
||||||
|
use tiff::encoder::compression::{Deflate, Lzw, Packbits, Uncompressed};
|
||||||
|
use tiff::encoder::TiffEncoder;
|
||||||
|
use crate::resize::resize_image;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
|
pub enum TiffCompression {
|
||||||
|
Lzw,
|
||||||
|
Deflate,
|
||||||
|
Packbits,
|
||||||
|
Uncompressed,
|
||||||
|
}
|
||||||
|
|
||||||
|
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: 20500,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let mut input_data = Vec::new();
|
||||||
|
input_file
|
||||||
|
.read_to_end(&mut input_data)
|
||||||
|
.map_err(|e| CaesiumError {
|
||||||
|
message: e.to_string(),
|
||||||
|
code: 20501,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let mut output_file = File::create(output_path).map_err(|e| CaesiumError {
|
||||||
|
message: e.to_string(),
|
||||||
|
code: 20502,
|
||||||
|
})?;
|
||||||
|
let compressed_image = compress_to_memory(input_data, parameters)?;
|
||||||
|
output_file
|
||||||
|
.write_all(&compressed_image)
|
||||||
|
.map_err(|e| CaesiumError {
|
||||||
|
message: e.to_string(),
|
||||||
|
code: 20503,
|
||||||
|
})?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compress_to_memory(
|
||||||
|
in_file: Vec<u8>,
|
||||||
|
parameters: &CSParameters,
|
||||||
|
) -> Result<Vec<u8>, CaesiumError> {
|
||||||
|
let mut image = image::load_from_memory_with_format(in_file.as_slice(), Tiff).map_err(|e| {
|
||||||
|
CaesiumError {
|
||||||
|
message: e.to_string(),
|
||||||
|
code: 20504,
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
|
||||||
|
if parameters.width > 0 || parameters.height > 0 {
|
||||||
|
image = resize_image(image, parameters.width, parameters.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
let color_type = image.color();
|
||||||
|
let output_buff = vec![];
|
||||||
|
let mut output_stream = Cursor::new(output_buff);
|
||||||
|
let mut encoder = TiffEncoder::new(&mut output_stream).map_err(|e| CaesiumError {
|
||||||
|
message: e.to_string(),
|
||||||
|
code: 20505,
|
||||||
|
})?;
|
||||||
|
let compression_result = match parameters.tiff.algorithm {
|
||||||
|
TiffCompression::Deflate => match color_type {
|
||||||
|
image::ColorType::Rgb8 => encoder.write_image_with_compression::<RGB8, Deflate>(
|
||||||
|
image.width(),
|
||||||
|
image.height(),
|
||||||
|
Deflate::with_level(parameters.tiff.deflate_level),
|
||||||
|
image.as_bytes(),
|
||||||
|
),
|
||||||
|
image::ColorType::Rgba8 => encoder.write_image_with_compression::<RGBA8, Deflate>(
|
||||||
|
image.width(),
|
||||||
|
image.height(),
|
||||||
|
Deflate::with_level(parameters.tiff.deflate_level),
|
||||||
|
image.as_bytes(),
|
||||||
|
),
|
||||||
|
_ => {
|
||||||
|
return Err(CaesiumError {
|
||||||
|
message: format!("Unsupported TIFF color type ({:?})", color_type).to_string(),
|
||||||
|
code: 20506,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
TiffCompression::Lzw => match color_type {
|
||||||
|
image::ColorType::Rgb8 => encoder.write_image_with_compression::<RGB8, Lzw>(
|
||||||
|
image.width(),
|
||||||
|
image.height(),
|
||||||
|
Lzw,
|
||||||
|
image.as_bytes(),
|
||||||
|
),
|
||||||
|
image::ColorType::Rgba8 => encoder.write_image_with_compression::<RGBA8, Lzw>(
|
||||||
|
image.width(),
|
||||||
|
image.height(),
|
||||||
|
Lzw,
|
||||||
|
image.as_bytes(),
|
||||||
|
),
|
||||||
|
_ => {
|
||||||
|
return Err(CaesiumError {
|
||||||
|
message: format!("Unsupported TIFF color type ({:?})", color_type).to_string(),
|
||||||
|
code: 20506,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
TiffCompression::Packbits => match color_type {
|
||||||
|
image::ColorType::Rgb8 => encoder.write_image_with_compression::<RGB8, Packbits>(
|
||||||
|
image.width(),
|
||||||
|
image.height(),
|
||||||
|
Packbits,
|
||||||
|
image.as_bytes(),
|
||||||
|
),
|
||||||
|
image::ColorType::Rgba8 => encoder.write_image_with_compression::<RGBA8, Packbits>(
|
||||||
|
image.width(),
|
||||||
|
image.height(),
|
||||||
|
Packbits,
|
||||||
|
image.as_bytes(),
|
||||||
|
),
|
||||||
|
_ => {
|
||||||
|
return Err(CaesiumError {
|
||||||
|
message: format!("Unsupported TIFF color type ({:?})", color_type).to_string(),
|
||||||
|
code: 20506,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
TiffCompression::Uncompressed => match color_type {
|
||||||
|
image::ColorType::Rgb8 => encoder.write_image_with_compression::<RGB8, Uncompressed>(
|
||||||
|
image.width(),
|
||||||
|
image.height(),
|
||||||
|
Uncompressed,
|
||||||
|
image.as_bytes(),
|
||||||
|
),
|
||||||
|
image::ColorType::Rgba8 => encoder.write_image_with_compression::<RGBA8, Uncompressed>(
|
||||||
|
image.width(),
|
||||||
|
image.height(),
|
||||||
|
Uncompressed,
|
||||||
|
image.as_bytes(),
|
||||||
|
),
|
||||||
|
_ => {
|
||||||
|
return Err(CaesiumError {
|
||||||
|
message: format!("Unsupported TIFF color type ({:?})", color_type).to_string(),
|
||||||
|
code: 20506,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
match compression_result {
|
||||||
|
Ok(_) => Ok(output_stream.get_ref().to_vec()),
|
||||||
|
Err(e) => Err(CaesiumError {
|
||||||
|
message: e.to_string(),
|
||||||
|
code: 20507,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
17
src/utils.rs
17
src/utils.rs
|
@ -1,4 +1,3 @@
|
||||||
use core::fmt;
|
|
||||||
use infer::Type;
|
use infer::Type;
|
||||||
|
|
||||||
pub enum SupportedFileTypes {
|
pub enum SupportedFileTypes {
|
||||||
|
@ -6,6 +5,7 @@ pub enum SupportedFileTypes {
|
||||||
Png,
|
Png,
|
||||||
Gif,
|
Gif,
|
||||||
WebP,
|
WebP,
|
||||||
|
Tiff,
|
||||||
Unkn,
|
Unkn,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,20 +32,7 @@ fn match_supported_filetypes(ft: Type) -> SupportedFileTypes {
|
||||||
"image/png" => SupportedFileTypes::Png,
|
"image/png" => SupportedFileTypes::Png,
|
||||||
"image/gif" => SupportedFileTypes::Gif,
|
"image/gif" => SupportedFileTypes::Gif,
|
||||||
"image/webp" => SupportedFileTypes::WebP,
|
"image/webp" => SupportedFileTypes::WebP,
|
||||||
|
"image/tiff" => SupportedFileTypes::Tiff,
|
||||||
_ => SupportedFileTypes::Unkn,
|
_ => SupportedFileTypes::Unkn,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,8 +2,8 @@ use std::fs::File;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
use crate::error::CaesiumError;
|
||||||
use crate::resize::resize_image;
|
use crate::resize::resize_image;
|
||||||
use crate::utils::CaesiumError;
|
|
||||||
use crate::CSParameters;
|
use crate::CSParameters;
|
||||||
|
|
||||||
pub fn compress(
|
pub fn compress(
|
||||||
|
|
Binary file not shown.
Loading…
Reference in New Issue