Changed return type of C interface

This commit is contained in:
Matteo Paonessa 2022-04-11 09:58:52 +02:00
parent 5c6da6f755
commit af3556d19d
7 changed files with 69 additions and 53 deletions

6
.idea/markdown.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MarkdownSettings">
<option name="areInjectionsEnabled" value="false" />
</component>
</project>

View File

@ -1,8 +1,8 @@
[package] [package]
name = "libcaesium" name = "libcaesium"
version = "0.7.0" version = "0.8.0"
authors = ["Matteo Paonessa <matteo.paonessa@gmail.com>"] authors = ["Matteo Paonessa <matteo.paonessa@gmail.com>"]
edition = "2018" edition = "2021"
categories = ["multimedia::images"] categories = ["multimedia::images"]
keywords = [ keywords = [
"compression", "compression",
@ -24,17 +24,17 @@ license = "Apache-2.0"
[dependencies] [dependencies]
mozjpeg-sys = "1.0.1" mozjpeg-sys = "1.0.1"
oxipng = "5.0.1" oxipng = "5.0.1"
libc = "0.2.76" libc = "0.2.119"
gifsicle = "1.92.5" gifsicle = "1.92.5"
webp = "0.2.1" webp = "0.2.1"
infer = "0.6.0" infer = "0.7.0"
image = { version = "0.24", default-features = false, features = ["jpeg", "png", "webp", "gif"] } image = { version = "0.24", default-features = false, features = ["jpeg", "png", "webp", "gif"] }
img-parts = "0.2.3" img-parts = "0.2.3"
bytes = "1.1.0" bytes = "1.1.0"
[dev-dependencies] [dev-dependencies]
dssim = "3.2.0" dssim = "3.2.0"
kamadak-exif = "0.5.0" kamadak-exif = "0.5.4"
[lib] [lib]
name = "caesium" name = "caesium"

View File

@ -17,7 +17,7 @@ pub fn compress(
- `output_path` - output file path (full filename) - `output_path` - output file path (full filename)
- `parameters` - options struct, containing compression parameters (see below) - `parameters` - options struct, containing compression parameters (see below)
The output folder where the file is compressed **must** exist. NOTE: The output folder where the file is compressed **must** exist.
### Compression options ### Compression options
Libcaesium supports a few compression parameters for each file it supports. Libcaesium supports a few compression parameters for each file it supports.
They are defined into a top level struct containing each supported file parameters, as follows: They are defined into a top level struct containing each supported file parameters, as follows:
@ -57,7 +57,7 @@ pub struct Parameters {
``` ```
- `oxipng`: oxipng options. Should be left as default unless you want to do something advanced. Refer to [oxipng](https://github.com/shssoichiro/oxipng) for documentation. - `oxipng`: oxipng options. Should be left as default unless you want to do something advanced. Refer to [oxipng](https://github.com/shssoichiro/oxipng) for documentation.
- `level`: level of optimization, from 1 to 7. Increasing the level will result in a smaller file, at the cost of computation time. If the optimization flag is `true`, the level is set to `6`. Default: `3`. - `level`: level of optimization, from 1 to 7. Increasing the level will result in a smaller file, at the cost of computation time. If the optimization flag is `true`, the level is set to `6`. Default: `3`.
- `force_zopfli`: if `optimization` is `true` and this option is also `true`, will use zopfli algorithm for compression, resulting in a smaller image but it may take minutes to finish the process. Default `false`. - `force_zopfli`: if `optimization` is `true` and this option is also `true`, will use zopfli algorithm for compression, resulting in a smaller image, but it may take minutes to finish the process. Default `false`.
#### gif #### gif
GIF support is experimental, has many know issues and does not support optimization. Expect bugs (especially on Windows). GIF support is experimental, has many know issues and does not support optimization. Expect bugs (especially on Windows).
@ -69,7 +69,7 @@ pub struct Parameters {
- `quality`: in a range from 0 to 100, the quality of the resulting image. If the optimization flag is `true`, the level is set to `100`. Default: `80`. - `quality`: in a range from 0 to 100, the quality of the resulting image. If the optimization flag is `true`, the level is set to `100`. Default: `80`.
#### webp #### webp
WebP compression is tricky. The format is already well optimized and using the `optimize` flag will probably result in a bigger image. WebP's compression is tricky. The format is already well optimized and using the `optimize` flag will probably result in a bigger image.
```Rust ```Rust
pub struct Parameters { pub struct Parameters {
pub quality: u32, pub quality: u32,
@ -84,14 +84,23 @@ pub extern fn c_compress(
input_path: *const c_char, input_path: *const c_char,
output_path: *const c_char, output_path: *const c_char,
params: CCSParameters params: CCSParameters
) -> bool ) -> CCSResult
``` ```
#### Parameters #### Parameters
- `input_path` - input file path (full filename) - `input_path` - input file path (full filename)
- `output_path` - output file path (full filename) - `output_path` - output file path (full filename)
- `parameters` - options struct, containing compression parameters (see below) - `parameters` - options struct, containing compression parameters (see below)
#### Return #### Return
`true` if all goes well, `false` otherwise. A `CCSResult` struct
```Rust
#[repr(C)]
pub struct CCSResult {
pub success: bool,
pub error_message: *const c_char,
}
```
If `success` is `true` the compression process ended successfully and `error_message` will be empty.
On failure, the `error_message` will be filled with a string containing a brief explanation of the error.
### Compression options ### Compression options
The C options struct is slightly different from the Rust one: The C options struct is slightly different from the Rust one:
@ -131,4 +140,4 @@ Libcaesium also supports optimization, by setting the _quality_ to 0. This perfo
but with a smaller size (10-12% usually). but with a smaller size (10-12% usually).
PNG is lossless, so libcaesium will always perform optimization rather than compression. PNG is lossless, so libcaesium will always perform optimization rather than compression.
GIF optimization is possible, but currently not supported. GIF optimization is possible, but currently not supported.
WebP optimization is also possible, but it will probably result in a bigger output file as it's well suited to losslessly convert from PNG or JPEG.s WebP's optimization is also possible, but it will probably result in a bigger output file as it's well suited to losslessly convert from PNG or JPEG.s

View File

@ -16,6 +16,7 @@ pub fn compress(input_path: String, output_path: String, parameters: CSParameter
{ {
let mut in_file = fs::read(input_path)?; let mut in_file = fs::read(input_path)?;
if parameters.width > 0 || parameters.height > 0 { if parameters.width > 0 || parameters.height > 0 {
if parameters.keep_metadata { if parameters.keep_metadata {
let metadata = extract_metadata(in_file.clone()); let metadata = extract_metadata(in_file.clone());
@ -27,12 +28,11 @@ pub fn compress(input_path: String, output_path: String, parameters: CSParameter
} }
unsafe { unsafe {
let compression_buffer: (*mut u8, u64); let compression_buffer: (*mut u8, u64) = if parameters.optimize {
if parameters.optimize { lossless(in_file, parameters)?
compression_buffer = lossless(in_file, parameters)?;
} else { } else {
compression_buffer = lossy(in_file, parameters)?; lossy(in_file, parameters)?
} };
let mut output_file_buffer = File::create(output_path)?; let mut output_file_buffer = File::create(output_path)?;
output_file_buffer.write_all(std::slice::from_raw_parts(compression_buffer.0, compression_buffer.1 as usize))?; output_file_buffer.write_all(std::slice::from_raw_parts(compression_buffer.0, compression_buffer.1 as usize))?;
} }

View File

@ -7,7 +7,7 @@ mod resize;
use std::error::Error; use std::error::Error;
use crate::utils::get_filetype; use crate::utils::get_filetype;
use std::ffi::CStr; use std::ffi::{CStr, CString};
use std::os::raw::c_char; use std::os::raw::c_char;
#[repr(C)] #[repr(C)]
@ -23,6 +23,12 @@ pub struct CCSParameters {
pub height: u32, pub height: u32,
} }
#[repr(C)]
pub struct CCSResult {
pub success: bool,
pub error_message: *const c_char,
}
pub struct CSParameters { pub struct CSParameters {
pub jpeg: jpeg::Parameters, pub jpeg: jpeg::Parameters,
pub png: png::Parameters, pub png: png::Parameters,
@ -68,8 +74,9 @@ pub fn initialize_parameters() -> CSParameters
#[no_mangle] #[no_mangle]
#[allow(clippy::missing_safety_doc)] #[allow(clippy::missing_safety_doc)]
pub unsafe extern fn c_compress(input_path: *const c_char, output_path: *const c_char, params: CCSParameters) -> bool { pub unsafe extern fn c_compress(input_path: *const c_char, output_path: *const c_char, params: CCSParameters) -> CCSResult {
let mut parameters = initialize_parameters(); let mut parameters = initialize_parameters();
parameters.jpeg.quality = params.jpeg_quality; parameters.jpeg.quality = params.jpeg_quality;
parameters.png.level = params.png_level; parameters.png.level = params.png_level;
parameters.optimize = params.optimize; parameters.optimize = params.optimize;
@ -80,10 +87,29 @@ pub unsafe extern fn c_compress(input_path: *const c_char, output_path: *const c
parameters.width = params.width; parameters.width = params.width;
parameters.height = params.height; parameters.height = params.height;
let x = compress(CStr::from_ptr(input_path).to_str().unwrap().to_string(), let mut error_message = CString::new("").unwrap();
match compress(CStr::from_ptr(input_path).to_str().unwrap().to_string(),
CStr::from_ptr(output_path).to_str().unwrap().to_string(), CStr::from_ptr(output_path).to_str().unwrap().to_string(),
parameters).is_ok(); parameters) {
x Ok(_) => {
let em_pointer = error_message.as_ptr();
std::mem::forget(error_message);
CCSResult {
success: true,
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,
error_message: em_pointer
}
}
}
} }
pub fn compress(input_path: String, output_path: String, parameters: CSParameters) -> Result<(), Box<dyn Error>> { pub fn compress(input_path: String, output_path: String, parameters: CSParameters) -> Result<(), Box<dyn Error>> {
@ -92,43 +118,21 @@ pub fn compress(input_path: String, output_path: String, parameters: CSParameter
match file_type { match file_type {
utils::SupportedFileTypes::Jpeg => { utils::SupportedFileTypes::Jpeg => {
return match jpeg::compress(input_path, output_path, parameters) { jpeg::compress(input_path, output_path, parameters)?;
Ok(_) => Ok(()),
Err(e) => {
eprintln!("JPEG compression error: {}", e.to_string());
Err(e.into())
}
};
} }
utils::SupportedFileTypes::Png => { utils::SupportedFileTypes::Png => {
return match png::compress(input_path, output_path, parameters) { png::compress(input_path, output_path, parameters)?;
Ok(_) => Ok(()),
Err(e) => {
eprintln!("PNG compression error: {}", e.to_string());
Err(e.into())
}
};
} }
utils::SupportedFileTypes::Gif => { utils::SupportedFileTypes::Gif => {
return match gif::compress(input_path, output_path, parameters) { gif::compress(input_path, output_path, parameters)?;
Ok(_) => Ok(()),
Err(e) => {
eprintln!("GIF compression error: {}", e.to_string());
Err(e.into())
}
};
} }
utils::SupportedFileTypes::WebP => { utils::SupportedFileTypes::WebP => {
return match webp::compress(input_path, output_path, parameters) { webp::compress(input_path, output_path, parameters)?;
Ok(_) => Ok(()),
Err(e) => {
eprintln!("WebP compression error: {}", e.to_string());
Err(e.into())
}
};
} }
_ => return Err("Unknown file type".into()) _ => return Err("Unknown file type".into())
} }
Ok(())
} }
fn validate_parameters(parameters: &CSParameters) -> Result<(), Box<dyn Error>> { fn validate_parameters(parameters: &CSParameters) -> Result<(), Box<dyn Error>> {

View File

@ -1,5 +1,3 @@
use caesium;
#[test] #[test]
fn unknown_file_type() { fn unknown_file_type() {
let output = "tests/samples/output/should_not_be_there"; let output = "tests/samples/output/should_not_be_there";

View File

@ -1,4 +1,3 @@
use caesium;
use std::sync::Once; use std::sync::Once;
use std::fs; use std::fs;