optimize image compression conditions and error handling

Signed-off-by: eternal-flame-AD <yume@yumechi.jp>
This commit is contained in:
ゆめ 2024-11-20 05:10:28 -06:00
parent 4c98ae337b
commit 5df98f8f05
No known key found for this signature in database
2 changed files with 73 additions and 69 deletions

View file

@ -58,11 +58,13 @@ pub fn postprocess_webp_image(
pub fn postprocess_png_image(data: &[u8], opt: &ImageOptions) -> ImageResult<Option<DynamicImage>> { pub fn postprocess_png_image(data: &[u8], opt: &ImageOptions) -> ImageResult<Option<DynamicImage>> {
let dec = PngDecoder::new(Cursor::new(data))?; let dec = PngDecoder::new(Cursor::new(data))?;
if !dec.is_apng()? && opt.requested_resize() { let apng = dec.is_apng()?;
if !apng && opt.requested_resize() {
return Ok(Some(postprocess_static_image(data, opt)?)); return Ok(Some(postprocess_static_image(data, opt)?));
} }
if opt.static_ == Some(true) { if apng && opt.static_ == Some(true) {
let first_frame = match dec.apng()?.into_frames().next() { let first_frame = match dec.apng()?.into_frames().next() {
Some(Ok(frame)) => frame, Some(Ok(frame)) => frame,
_ => return Ok(None), _ => return Ok(None),

View file

@ -18,7 +18,7 @@ use image::{
gif::{GifEncoder, Repeat}, gif::{GifEncoder, Repeat},
jpeg::JpegEncoder, jpeg::JpegEncoder,
}, },
Frames, ImageFormat, Frames, GenericImageView, ImageFormat,
}; };
use sniff::SniffingStream; use sniff::SniffingStream;
@ -312,63 +312,63 @@ where
ImageFormat::WebP ImageFormat::WebP
}; };
if options.format.is_none() { if mime.starts_with("image/png") || mime.starts_with("image/apng") {
if mime.starts_with("image/png") || mime.starts_with("image/apng") { let result = sandboxed!(sandbox =>
let result = sandboxed!(sandbox => image_processing::postprocess_png_image(&buf, &options)
image_processing::postprocess_png_image(&buf, &options) .map_err(|e| {
.map_err(|e| { ErrorResponse::postprocess_failed(e.to_string().into())
ErrorResponse::postprocess_failed(e.to_string().into()) }))?;
}))?;
return match result { return match result {
Some(img) => { None => Ok(MediaResponse::Buffer {
Ok(MediaResponse::ProcessedStaticImage(StaticImage { data: buf,
data: img, content_type: Some("image/png".into()),
format: output_static_format, }
compression: options.compression_level(), .with_timing_info(TIME_TO_FIRST_BYTE_KEY, ttfb)
is_https, .with_opt_timing_info(SLURP_TIMING_KEY, Some(slurp_dur))
}) .with_timing_info(TIMING_KEY, begin.elapsed())),
.with_timing_info(TIME_TO_FIRST_BYTE_KEY, ttfb)
.with_opt_timing_info(SLURP_TIMING_KEY, Some(slurp_dur)) Some(img) => {
.with_timing_info(TIMING_KEY, begin.elapsed())) Ok(MediaResponse::ProcessedStaticImage(StaticImage {
} data: img,
None => Ok(MediaResponse::Buffer { format: output_static_format,
data: buf, compression: options.compression_level(),
content_type: Some("image/png".into()), is_https,
} })
.with_timing_info(TIME_TO_FIRST_BYTE_KEY, ttfb) .with_timing_info(TIME_TO_FIRST_BYTE_KEY, ttfb)
.with_opt_timing_info(SLURP_TIMING_KEY, Some(slurp_dur)) .with_opt_timing_info(SLURP_TIMING_KEY, Some(slurp_dur))
.with_timing_info(TIMING_KEY, begin.elapsed())), .with_timing_info(TIMING_KEY, begin.elapsed()))
}; }
} };
if mime.starts_with("image/webp") { }
let result = sandboxed!(sandbox => if mime.starts_with("image/webp") {
image_processing::postprocess_webp_image(&buf, &options) let result = sandboxed!(sandbox =>
.map_err(|e| { image_processing::postprocess_webp_image(&buf, &options)
ErrorResponse::postprocess_failed(e.to_string().into()) .map_err(|e| {
}))?; ErrorResponse::postprocess_failed(e.to_string().into())
}))?;
return match result { return match result {
Some(img) => { None => Ok(MediaResponse::Buffer {
Ok(MediaResponse::ProcessedStaticImage(StaticImage { data: buf,
data: img, content_type: Some("image/webp".into()),
format: output_static_format, }
compression: options.compression_level(), .with_timing_info(TIME_TO_FIRST_BYTE_KEY, ttfb)
is_https, .with_opt_timing_info(SLURP_TIMING_KEY, Some(slurp_dur))
}) .with_timing_info(TIMING_KEY, begin.elapsed())),
.with_timing_info(TIME_TO_FIRST_BYTE_KEY, ttfb)
.with_opt_timing_info(SLURP_TIMING_KEY, Some(slurp_dur)) Some(img) => {
.with_timing_info(TIMING_KEY, begin.elapsed())) Ok(MediaResponse::ProcessedStaticImage(StaticImage {
} data: img,
None => Ok(MediaResponse::Buffer { format: output_static_format,
data: buf, compression: options.compression_level(),
content_type: Some("image/webp".into()), is_https,
} })
.with_timing_info(TIME_TO_FIRST_BYTE_KEY, ttfb) .with_timing_info(TIME_TO_FIRST_BYTE_KEY, ttfb)
.with_opt_timing_info(SLURP_TIMING_KEY, Some(slurp_dur)) .with_opt_timing_info(SLURP_TIMING_KEY, Some(slurp_dur))
.with_timing_info(TIMING_KEY, begin.elapsed())), .with_timing_info(TIMING_KEY, begin.elapsed()))
}; }
} };
} }
let result = sandboxed!(sandbox => image_processing::postprocess_static_image( let result = sandboxed!(sandbox => image_processing::postprocess_static_image(
@ -602,29 +602,31 @@ impl IntoResponse for StaticImage {
let mut buf = BufWriter::new(Cursor::new(Vec::new())); let mut buf = BufWriter::new(Cursor::new(Vec::new()));
if self.compression == CompressionLevel::None { if self.compression == CompressionLevel::None
|| self.data.dimensions().0 * self.data.dimensions().1 <= 256 * 256
{
self.data.write_to(&mut buf, self.format).unwrap(); self.data.write_to(&mut buf, self.format).unwrap();
} else { } else {
match self.format { match self.format {
#[cfg(feature = "lossy-webp")] #[cfg(feature = "lossy-webp")]
ImageFormat::WebP => { ImageFormat::WebP => {
let enc = match webp::Encoder::from_image(&self.data) { match webp::Encoder::from_image(&self.data) {
Ok(enc) => enc, Ok(enc) => {
let webp = match self.compression {
CompressionLevel::Low => enc.encode(80.),
CompressionLevel::Med => enc.encode(60.),
CompressionLevel::High => enc.encode(40.),
CompressionLevel::Max => enc.encode(25.),
_ => enc.encode(100.0),
};
buf.write_all(&webp).unwrap();
}
Err(e) => { Err(e) => {
return ErrorResponse::postprocess_failed(e.to_string().into()) log::warn!("webp compression failed: {:?}", e);
.into_response(); self.data.write_to(&mut buf, self.format).unwrap();
} }
}; };
let webp = match self.compression {
CompressionLevel::Low => enc.encode(80.),
CompressionLevel::Med => enc.encode(60.),
CompressionLevel::High => enc.encode(40.),
CompressionLevel::Max => enc.encode(25.),
_ => enc.encode(100.0),
};
buf.write_all(&webp).unwrap();
} }
ImageFormat::Jpeg => { ImageFormat::Jpeg => {
let mut enc = JpegEncoder::new_with_quality( let mut enc = JpegEncoder::new_with_quality(