pngquant for lossy compression
This commit is contained in:
parent
15e7723477
commit
ec485ce89b
|
@ -31,6 +31,7 @@ infer = "0.8"
|
||||||
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"
|
img-parts = "0.2"
|
||||||
bytes = "1.1"
|
bytes = "1.1"
|
||||||
|
imagequant = "4.0.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
dssim = "3.2.0"
|
dssim = "3.2.0"
|
||||||
|
|
|
@ -51,12 +51,12 @@ pub struct Parameters {
|
||||||
```Rust
|
```Rust
|
||||||
pub struct Parameters {
|
pub struct Parameters {
|
||||||
pub oxipng: oxipng::Options,
|
pub oxipng: oxipng::Options,
|
||||||
pub level: u32,
|
pub quality: u32,
|
||||||
pub force_zopfli: bool
|
pub force_zopfli: bool
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
- `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`.
|
- `quality`: in a range from 1 to 100, the quality of the resulting image. Default `80`.
|
||||||
- `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
|
||||||
|
|
|
@ -18,7 +18,6 @@ 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());
|
||||||
|
|
|
@ -14,7 +14,7 @@ use std::os::raw::c_char;
|
||||||
pub struct CCSParameters {
|
pub struct CCSParameters {
|
||||||
pub keep_metadata: bool,
|
pub keep_metadata: bool,
|
||||||
pub jpeg_quality: u32,
|
pub jpeg_quality: u32,
|
||||||
pub png_level: u32,
|
pub png_quality: u32,
|
||||||
pub png_force_zopfli: bool,
|
pub png_force_zopfli: bool,
|
||||||
pub gif_quality: u32,
|
pub gif_quality: u32,
|
||||||
pub webp_quality: u32,
|
pub webp_quality: u32,
|
||||||
|
@ -48,7 +48,7 @@ pub fn initialize_parameters() -> CSParameters
|
||||||
|
|
||||||
let png = png::Parameters {
|
let png = png::Parameters {
|
||||||
oxipng: oxipng::Options::default(),
|
oxipng: oxipng::Options::default(),
|
||||||
level: 3,
|
quality: 80,
|
||||||
force_zopfli: false,
|
force_zopfli: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ pub unsafe extern fn c_compress(input_path: *const c_char, output_path: *const c
|
||||||
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.quality = params.png_quality;
|
||||||
parameters.optimize = params.optimize;
|
parameters.optimize = params.optimize;
|
||||||
parameters.keep_metadata = params.keep_metadata;
|
parameters.keep_metadata = params.keep_metadata;
|
||||||
parameters.png.force_zopfli = params.png_force_zopfli;
|
parameters.png.force_zopfli = params.png_force_zopfli;
|
||||||
|
@ -140,7 +140,7 @@ fn validate_parameters(parameters: &CSParameters) -> Result<(), Box<dyn Error>>
|
||||||
return Err("Invalid JPEG quality value".into());
|
return Err("Invalid JPEG quality value".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
if parameters.png.level == 0 || parameters.png.level > 7 {
|
if parameters.png.quality > 100 {
|
||||||
return Err("Invalid PNG quality value".into());
|
return Err("Invalid PNG quality value".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
34
src/png.rs
34
src/png.rs
|
@ -7,20 +7,35 @@ use crate::resize::resize;
|
||||||
|
|
||||||
pub struct Parameters {
|
pub struct Parameters {
|
||||||
pub oxipng: oxipng::Options,
|
pub oxipng: oxipng::Options,
|
||||||
pub level: u32,
|
pub quality: u32,
|
||||||
pub force_zopfli: bool,
|
pub force_zopfli: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compress(input_path: String, output_path: String, parameters: CSParameters) -> Result<(), io::Error> {
|
pub fn compress (input_path: String, output_path: String, parameters: CSParameters) -> Result<(), io::Error> {
|
||||||
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 {
|
||||||
in_file = resize(in_file, parameters.width, parameters.height, Png)?;
|
in_file = resize(in_file, parameters.width, parameters.height, Png)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut oxipng_options = parameters.png.oxipng;
|
let optimized_png: Vec<u8> = if parameters.optimize {
|
||||||
oxipng_options.deflate = oxipng::Deflaters::Libdeflater;
|
lossless(in_file, parameters)?
|
||||||
|
} else {
|
||||||
|
lossy(in_file, parameters)?
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut output_file_buffer = File::create(output_path)?;
|
||||||
|
output_file_buffer.write_all(optimized_png.as_slice())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lossy (in_file: Vec<u8>, parameters: CSParameters) -> Result<Vec<u8>, io::Error> {
|
||||||
|
lossless(in_file, parameters)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lossless(in_file: Vec<u8>, parameters: CSParameters) -> Result<Vec<u8>, io::Error> {
|
||||||
|
let mut oxipng_options = parameters.png.oxipng;
|
||||||
if !parameters.keep_metadata {
|
if !parameters.keep_metadata {
|
||||||
oxipng_options.strip = oxipng::Headers::Safe;
|
oxipng_options.strip = oxipng::Headers::Safe;
|
||||||
}
|
}
|
||||||
|
@ -28,11 +43,7 @@ pub fn compress(input_path: String, output_path: String, parameters: CSParameter
|
||||||
if parameters.optimize && parameters.png.force_zopfli {
|
if parameters.optimize && parameters.png.force_zopfli {
|
||||||
oxipng_options.deflate = oxipng::Deflaters::Zopfli;
|
oxipng_options.deflate = oxipng::Deflaters::Zopfli;
|
||||||
} else {
|
} else {
|
||||||
let mut preset = parameters.png.level - 1;
|
oxipng_options = oxipng::Options::from_preset(6);
|
||||||
if parameters.optimize {
|
|
||||||
preset = 6;
|
|
||||||
}
|
|
||||||
oxipng_options = oxipng::Options::from_preset(preset as u8);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let optimized_png = match oxipng::optimize_from_memory(in_file.as_slice(), &oxipng_options) {
|
let optimized_png = match oxipng::optimize_from_memory(in_file.as_slice(), &oxipng_options) {
|
||||||
|
@ -40,8 +51,5 @@ pub fn compress(input_path: String, output_path: String, parameters: CSParameter
|
||||||
Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e))
|
Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e))
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut output_file_buffer = File::create(output_path)?;
|
Ok(optimized_png)
|
||||||
output_file_buffer.write_all(optimized_png.as_slice())?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
|
@ -107,7 +107,7 @@ fn downscale_zopfli_compress_png() {
|
||||||
let mut params = caesium::initialize_parameters();
|
let mut params = caesium::initialize_parameters();
|
||||||
params.width = 150;
|
params.width = 150;
|
||||||
params.height = 150;
|
params.height = 150;
|
||||||
params.png.level = 3;
|
params.png.quality = 80;
|
||||||
params.optimize = true;
|
params.optimize = true;
|
||||||
params.png.force_zopfli = true;
|
params.png.force_zopfli = true;
|
||||||
caesium::compress(String::from("tests/samples/uncompressed_드림캐쳐.png"),
|
caesium::compress(String::from("tests/samples/uncompressed_드림캐쳐.png"),
|
||||||
|
|
Loading…
Reference in New Issue