mirror of https://github.com/ChillFish8/lust.git
Fix more encoding bugs
This commit is contained in:
parent
465aeb0265
commit
8ca8094d8d
|
@ -417,16 +417,6 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deflate"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174"
|
||||
dependencies = [
|
||||
"adler32",
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deflate"
|
||||
version = "1.0.0"
|
||||
|
@ -494,7 +484,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "d4badb9489a465cb2c555af1f00f0bfd8cecd6fc12ac11da9d5b40c5dd5f0200"
|
||||
dependencies = [
|
||||
"bit_field",
|
||||
"deflate 1.0.0",
|
||||
"deflate",
|
||||
"flume",
|
||||
"half",
|
||||
"inflate",
|
||||
|
@ -870,25 +860,6 @@ dependencies = [
|
|||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "image"
|
||||
version = "0.23.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24ffcb7e7244a9bf19d35bf2883b9c080c4ced3c07a9895572178cdb8f13f6a1"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"byteorder",
|
||||
"color_quant",
|
||||
"gif",
|
||||
"jpeg-decoder 0.1.22",
|
||||
"num-iter",
|
||||
"num-rational 0.3.2",
|
||||
"num-traits",
|
||||
"png 0.16.8",
|
||||
"scoped_threadpool",
|
||||
"tiff 0.6.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "image"
|
||||
version = "0.24.1"
|
||||
|
@ -902,11 +873,11 @@ dependencies = [
|
|||
"gif",
|
||||
"jpeg-decoder 0.2.2",
|
||||
"num-iter",
|
||||
"num-rational 0.4.0",
|
||||
"num-rational",
|
||||
"num-traits",
|
||||
"png 0.17.5",
|
||||
"png",
|
||||
"scoped_threadpool",
|
||||
"tiff 0.7.1",
|
||||
"tiff",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -957,9 +928,6 @@ name = "jpeg-decoder"
|
|||
version = "0.1.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2"
|
||||
dependencies = [
|
||||
"rayon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jpeg-decoder"
|
||||
|
@ -1053,7 +1021,7 @@ dependencies = [
|
|||
"enum_dispatch",
|
||||
"futures",
|
||||
"hashbrown 0.12.0",
|
||||
"image 0.24.1",
|
||||
"image",
|
||||
"mimalloc",
|
||||
"mime",
|
||||
"once_cell",
|
||||
|
@ -1108,15 +1076,6 @@ version = "0.3.16"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435"
|
||||
dependencies = [
|
||||
"adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.4.4"
|
||||
|
@ -1217,17 +1176,6 @@ dependencies = [
|
|||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-rational"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-rational"
|
||||
version = "0.4.0"
|
||||
|
@ -1369,18 +1317,6 @@ version = "0.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "png"
|
||||
version = "0.16.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"crc32fast",
|
||||
"deflate 0.8.6",
|
||||
"miniz_oxide 0.3.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "png"
|
||||
version = "0.17.5"
|
||||
|
@ -1389,7 +1325,7 @@ checksum = "dc38c0ad57efb786dd57b9864e5b18bae478c00c824dc55a38bbc9da95dde3ba"
|
|||
dependencies = [
|
||||
"bitflags",
|
||||
"crc32fast",
|
||||
"deflate 1.0.0",
|
||||
"deflate",
|
||||
"miniz_oxide 0.5.1",
|
||||
]
|
||||
|
||||
|
@ -1932,17 +1868,6 @@ dependencies = [
|
|||
"num_cpus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiff"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a53f4706d65497df0c4349241deddf35f84cee19c87ed86ea8ca590f4464437"
|
||||
dependencies = [
|
||||
"jpeg-decoder 0.1.22",
|
||||
"miniz_oxide 0.4.4",
|
||||
"weezl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiff"
|
||||
version = "0.7.1"
|
||||
|
@ -2308,9 +2233,9 @@ checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2"
|
|||
name = "webp"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"image 0.23.14",
|
||||
"anyhow",
|
||||
"image",
|
||||
"libwebp-sys",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -32,7 +32,7 @@ crossbeam = "0.8.1"
|
|||
tracing = "0.1.30"
|
||||
tracing-futures = "0.2.5"
|
||||
tracing-subscriber = "0.3.8"
|
||||
image = "0.24.1"
|
||||
image = "0.24"
|
||||
base64 = "0.13.0"
|
||||
bytes = "1"
|
||||
anyhow = "1"
|
||||
|
|
|
@ -23,7 +23,13 @@ impl JustInTimePipeline {
|
|||
|
||||
impl Pipeline for JustInTimePipeline {
|
||||
fn on_upload(&self, kind: ImageKind, data: Vec<u8>) -> anyhow::Result<PipelineResult> {
|
||||
let img = processor::encoder::encode_once(self.formats.original_image_store_format, kind, data.into())?;
|
||||
let webp_config = webp::config(
|
||||
self.formats.webp_config.quality.is_none(),
|
||||
self.formats.webp_config.quality.unwrap_or(50f32),
|
||||
self.formats.webp_config.method.unwrap_or(4) as i32,
|
||||
self.formats.webp_config.threading,
|
||||
);
|
||||
let img = processor::encoder::encode_once(webp_config, self.formats.original_image_store_format, kind, data.into())?;
|
||||
|
||||
Ok(PipelineResult {
|
||||
response: None,
|
||||
|
@ -39,7 +45,13 @@ impl Pipeline for JustInTimePipeline {
|
|||
sizing_id: u32,
|
||||
_custom_size: Option<(u32, u32)>,
|
||||
) -> anyhow::Result<PipelineResult> {
|
||||
let img = processor::encoder::encode_once(desired_kind, data_kind, data)?;
|
||||
let webp_config = webp::config(
|
||||
self.formats.webp_config.quality.is_none(),
|
||||
self.formats.webp_config.quality.unwrap_or(50f32),
|
||||
self.formats.webp_config.method.unwrap_or(4) as i32,
|
||||
self.formats.webp_config.threading,
|
||||
);
|
||||
let img = processor::encoder::encode_once(webp_config, desired_kind, data_kind, data)?;
|
||||
|
||||
let (buff, sizing_id) = if sizing_id != 0 {
|
||||
if let Some(cfg) = self.presets.get(&sizing_id) {
|
||||
|
|
|
@ -23,7 +23,13 @@ impl RealtimePipeline {
|
|||
|
||||
impl Pipeline for RealtimePipeline {
|
||||
fn on_upload(&self, kind: ImageKind, data: Vec<u8>) -> anyhow::Result<PipelineResult> {
|
||||
let img = processor::encoder::encode_once(self.formats.original_image_store_format, kind, data.into())?;
|
||||
let webp_config = webp::config(
|
||||
self.formats.webp_config.quality.is_none(),
|
||||
self.formats.webp_config.quality.unwrap_or(50f32),
|
||||
self.formats.webp_config.method.unwrap_or(4) as i32,
|
||||
self.formats.webp_config.threading,
|
||||
);
|
||||
let img = processor::encoder::encode_once(webp_config, self.formats.original_image_store_format, kind, data.into())?;
|
||||
|
||||
Ok(PipelineResult {
|
||||
response: None,
|
||||
|
@ -39,7 +45,13 @@ impl Pipeline for RealtimePipeline {
|
|||
sizing_id: u32,
|
||||
custom_size: Option<(u32, u32)>,
|
||||
) -> anyhow::Result<PipelineResult> {
|
||||
let img = processor::encoder::encode_once(desired_kind, data_kind, data)?;
|
||||
let webp_config = webp::config(
|
||||
self.formats.webp_config.quality.is_none(),
|
||||
self.formats.webp_config.quality.unwrap_or(50f32),
|
||||
self.formats.webp_config.method.unwrap_or(4) as i32,
|
||||
self.formats.webp_config.threading,
|
||||
);
|
||||
let img = processor::encoder::encode_once(webp_config, desired_kind, data_kind, data)?;
|
||||
|
||||
let (buff, sizing_id) = if sizing_id != 0 {
|
||||
let maybe_resize = match self.presets.get(&sizing_id) {
|
||||
|
|
|
@ -16,6 +16,12 @@ pub fn encode_following_config(
|
|||
data: Bytes,
|
||||
) -> anyhow::Result<Vec<EncodedImage>> {
|
||||
let original_image = Arc::new(load_from_memory_with_format(data.as_ref(), kind.into())?);
|
||||
let webp_config = webp::config(
|
||||
cfg.webp_config.quality.is_none(),
|
||||
cfg.webp_config.quality.unwrap_or(50f32),
|
||||
cfg.webp_config.method.unwrap_or(4) as i32,
|
||||
cfg.webp_config.threading,
|
||||
);
|
||||
|
||||
let (tx, rx) = crossbeam::channel::bounded(4);
|
||||
|
||||
|
@ -24,9 +30,9 @@ pub fn encode_following_config(
|
|||
let tx_local = tx.clone();
|
||||
let local = original_image.clone();
|
||||
rayon::spawn(move || {
|
||||
let result = encode_to(&local, ImageFormat::Png);
|
||||
let result = encode_to(webp_config, &local, (*variant).into());
|
||||
tx_local
|
||||
.send(result.map(|v| EncodedImage { kind: ImageKind::Png, buff: v }))
|
||||
.send(result.map(|v| EncodedImage { kind: *variant, buff: v }))
|
||||
.expect("Failed to respond to encoding request. Sender already closed.");
|
||||
});
|
||||
}
|
||||
|
@ -54,6 +60,7 @@ pub fn encode_following_config(
|
|||
|
||||
|
||||
pub fn encode_once(
|
||||
webp_cfg: webp::WebPConfig,
|
||||
to: ImageKind,
|
||||
from: ImageKind,
|
||||
data: Bytes,
|
||||
|
@ -64,7 +71,7 @@ pub fn encode_once(
|
|||
|
||||
let encoded = if from != to {
|
||||
rayon::spawn(move || {
|
||||
let result = encode_to(&original_image, to.into());
|
||||
let result = encode_to(webp_cfg, &original_image, to.into());
|
||||
tx.send(result.map(|v| EncodedImage { kind: to, buff: v }))
|
||||
.expect("Failed to respond to encoding request. Sender already closed.");
|
||||
});
|
||||
|
@ -82,7 +89,15 @@ pub fn encode_once(
|
|||
|
||||
|
||||
#[inline]
|
||||
pub fn encode_to(img: &DynamicImage, format: ImageFormat) -> anyhow::Result<Bytes> {
|
||||
pub fn encode_to(webp_cfg: webp::WebPConfig, img: &DynamicImage, format: ImageFormat) -> anyhow::Result<Bytes> {
|
||||
if let ImageFormat::WebP = format {
|
||||
let webp_image = webp::Encoder::from_image(webp_cfg, img);
|
||||
let encoded = webp_image.encode();
|
||||
|
||||
return Ok(Bytes::from(encoded?.to_vec()))
|
||||
}
|
||||
|
||||
|
||||
let mut buff = Cursor::new(Vec::new());
|
||||
img.write_to(&mut buff, format)?;
|
||||
Ok(Bytes::from(buff.into_inner()))
|
||||
|
|
|
@ -8,5 +8,5 @@ edition = "2018"
|
|||
|
||||
[dependencies]
|
||||
libwebp-sys = "0.3.2"
|
||||
image = "0.23"
|
||||
once_cell = "1.8.0"
|
||||
image = "0.24"
|
||||
anyhow = "1"
|
|
@ -1,13 +1,13 @@
|
|||
use std::fmt::{Debug, Error, Formatter};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use image::{DynamicImage, GenericImageView, RgbaImage};
|
||||
use anyhow::{Result, anyhow};
|
||||
use image::{DynamicImage, RgbaImage};
|
||||
use libwebp_sys::WebPEncodingError::VP8_ENC_OK;
|
||||
use libwebp_sys::WebPPreset::WEBP_PRESET_DEFAULT;
|
||||
use libwebp_sys::*;
|
||||
use once_cell::sync::OnceCell;
|
||||
pub use libwebp_sys::WebPConfig;
|
||||
|
||||
static CONFIG: OnceCell<WebPConfig> = OnceCell::new();
|
||||
|
||||
/// Inits the global encoder config.
|
||||
///
|
||||
|
@ -21,8 +21,8 @@ static CONFIG: OnceCell<WebPConfig> = OnceCell::new();
|
|||
///
|
||||
/// - multi_threading:
|
||||
/// If the system should to attempt to use in multi-threaded encoding.
|
||||
pub fn init_global(lossless: bool, quality: f32, method: i32, multi_threading: bool) {
|
||||
let cfg = WebPConfig {
|
||||
pub fn config(lossless: bool, quality: f32, method: i32, multi_threading: bool) -> WebPConfig {
|
||||
WebPConfig {
|
||||
lossless: if lossless { 1 } else { 0 },
|
||||
quality,
|
||||
method,
|
||||
|
@ -51,9 +51,7 @@ pub fn init_global(lossless: bool, quality: f32, method: i32, multi_threading: b
|
|||
use_delta_palette: 0,
|
||||
use_sharp_yuv: 0,
|
||||
pad: [100, 100],
|
||||
};
|
||||
|
||||
let _ = CONFIG.set(cfg);
|
||||
}
|
||||
}
|
||||
|
||||
/// Picture is uninitialized.
|
||||
|
@ -118,6 +116,7 @@ pub enum PixelLayout {
|
|||
}
|
||||
|
||||
pub struct Encoder<'a> {
|
||||
cfg: WebPConfig,
|
||||
layout: PixelLayout,
|
||||
image: &'a [u8],
|
||||
width: u32,
|
||||
|
@ -126,30 +125,25 @@ pub struct Encoder<'a> {
|
|||
|
||||
impl<'a> Encoder<'a> {
|
||||
/// Creates a new encoder from the given image.
|
||||
pub fn from_image(image: &'a DynamicImage) -> Self {
|
||||
pub fn from_image(cfg: WebPConfig, image: &'a DynamicImage) -> Self {
|
||||
match image {
|
||||
DynamicImage::ImageRgb8(image) => {
|
||||
Self::from_rgb(image.as_ref(), image.width(), image.height())
|
||||
Self::from_rgb(cfg, image.as_ref(), image.width(), image.height())
|
||||
},
|
||||
DynamicImage::ImageRgba8(image) => {
|
||||
Self::from_rgba(image.as_ref(), image.width(), image.height())
|
||||
},
|
||||
DynamicImage::ImageBgr8(image) => {
|
||||
Self::from_bgr(image.as_ref(), image.width(), image.height())
|
||||
},
|
||||
DynamicImage::ImageBgra8(image) => {
|
||||
Self::from_bgra(image.as_ref(), image.width(), image.height())
|
||||
Self::from_rgba(cfg,image.as_ref(), image.width(), image.height())
|
||||
},
|
||||
other => {
|
||||
let image = other.to_rgba8();
|
||||
Self::from_other(other.as_bytes(), other.width(), other.height(), image)
|
||||
Self::from_other(cfg,other.as_bytes(), other.width(), other.height(), image)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new encoder from the given image data in the RGB pixel layout.
|
||||
pub fn from_rgb(image: &'a [u8], width: u32, height: u32) -> Self {
|
||||
pub fn from_rgb(cfg: WebPConfig, image: &'a [u8], width: u32, height: u32) -> Self {
|
||||
Self {
|
||||
cfg,
|
||||
image,
|
||||
width,
|
||||
height,
|
||||
|
@ -158,8 +152,9 @@ impl<'a> Encoder<'a> {
|
|||
}
|
||||
|
||||
/// Creates a new encoder from the given image data in the RGBA pixel layout.
|
||||
pub fn from_rgba(image: &'a [u8], width: u32, height: u32) -> Self {
|
||||
pub fn from_rgba(cfg: WebPConfig, image: &'a [u8], width: u32, height: u32) -> Self {
|
||||
Self {
|
||||
cfg,
|
||||
image,
|
||||
width,
|
||||
height,
|
||||
|
@ -167,30 +162,11 @@ impl<'a> Encoder<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates a new encoder from the given image data in the BGR pixel layout.
|
||||
pub fn from_bgr(image: &'a [u8], width: u32, height: u32) -> Self {
|
||||
Self {
|
||||
image,
|
||||
width,
|
||||
height,
|
||||
layout: PixelLayout::BGR,
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new encoder from the given image data in the BGRA pixel layout.
|
||||
pub fn from_bgra(image: &'a [u8], width: u32, height: u32) -> Self {
|
||||
Self {
|
||||
image,
|
||||
width,
|
||||
height,
|
||||
layout: PixelLayout::BGRA,
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new encoder from the given image data in the Other layout,
|
||||
/// this creates a copy of the data to convert it to RGBA.
|
||||
pub fn from_other(image: &'a [u8], width: u32, height: u32, other: RgbaImage) -> Self {
|
||||
pub fn from_other(cfg: WebPConfig, image: &'a [u8], width: u32, height: u32, other: RgbaImage) -> Self {
|
||||
Self {
|
||||
cfg,
|
||||
image,
|
||||
width,
|
||||
height,
|
||||
|
@ -199,28 +175,26 @@ impl<'a> Encoder<'a> {
|
|||
}
|
||||
|
||||
/// Encode the image with the given global config.
|
||||
pub fn encode(&self) -> WebPMemory {
|
||||
pub fn encode(self) -> Result<WebPMemory> {
|
||||
let (img, layout) = if let PixelLayout::Other(img) = &self.layout {
|
||||
(img.as_ref(), &PixelLayout::RGBA)
|
||||
} else {
|
||||
(self.image.as_ref(), &self.layout)
|
||||
};
|
||||
|
||||
unsafe { encode(img, layout, self.width, self.height) }
|
||||
unsafe { encode(self.cfg, img, layout, self.width, self.height) }
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! check_ok {
|
||||
( $e:expr, $msg:expr ) => {{
|
||||
if $e == 0 {
|
||||
panic!("{}", $msg);
|
||||
return Err(anyhow!("{}", $msg));
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
unsafe fn encode(image: &[u8], layout: &PixelLayout, width: u32, height: u32) -> WebPMemory {
|
||||
let cfg = CONFIG.get().expect("config un-initialised.").clone();
|
||||
|
||||
unsafe fn encode(cfg: WebPConfig, image: &[u8], layout: &PixelLayout, width: u32, height: u32) -> Result<WebPMemory> {
|
||||
let picture = empty_webp_picture();
|
||||
let writer = WebPMemoryWriter {
|
||||
mem: std::ptr::null_mut::<u8>(),
|
||||
|
@ -283,13 +257,13 @@ unsafe fn encode(image: &[u8], layout: &PixelLayout, width: u32, height: u32) ->
|
|||
WebPPictureFree(picture_ptr);
|
||||
if ok == 0 {
|
||||
WebPMemoryWriterClear(writer_ptr);
|
||||
panic!(
|
||||
return Err(anyhow!(
|
||||
"memory error. libwebp error code: {:?}",
|
||||
(*picture_ptr).error_code
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
WebPMemory((*writer_ptr).mem, (*writer_ptr).size)
|
||||
Ok(WebPMemory((*writer_ptr).mem, (*writer_ptr).size))
|
||||
}
|
||||
|
||||
/// This struct represents a safe wrapper around memory owned by libwebp.
|
||||
|
@ -329,7 +303,7 @@ mod tests {
|
|||
use super::*;
|
||||
|
||||
fn ensure_global() {
|
||||
init_global(true, 50.0, 6, true)
|
||||
config(true, 50.0, 6, true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
Loading…
Reference in New Issue