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,7 +312,6 @@ 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)
@ -321,6 +320,14 @@ where
}))?; }))?;
return match result { return match result {
None => Ok(MediaResponse::Buffer {
data: buf,
content_type: Some("image/png".into()),
}
.with_timing_info(TIME_TO_FIRST_BYTE_KEY, ttfb)
.with_opt_timing_info(SLURP_TIMING_KEY, Some(slurp_dur))
.with_timing_info(TIMING_KEY, begin.elapsed())),
Some(img) => { Some(img) => {
Ok(MediaResponse::ProcessedStaticImage(StaticImage { Ok(MediaResponse::ProcessedStaticImage(StaticImage {
data: img, data: img,
@ -332,13 +339,6 @@ where
.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()))
} }
None => Ok(MediaResponse::Buffer {
data: buf,
content_type: Some("image/png".into()),
}
.with_timing_info(TIME_TO_FIRST_BYTE_KEY, ttfb)
.with_opt_timing_info(SLURP_TIMING_KEY, Some(slurp_dur))
.with_timing_info(TIMING_KEY, begin.elapsed())),
}; };
} }
if mime.starts_with("image/webp") { if mime.starts_with("image/webp") {
@ -349,6 +349,14 @@ where
}))?; }))?;
return match result { return match result {
None => Ok(MediaResponse::Buffer {
data: buf,
content_type: Some("image/webp".into()),
}
.with_timing_info(TIME_TO_FIRST_BYTE_KEY, ttfb)
.with_opt_timing_info(SLURP_TIMING_KEY, Some(slurp_dur))
.with_timing_info(TIMING_KEY, begin.elapsed())),
Some(img) => { Some(img) => {
Ok(MediaResponse::ProcessedStaticImage(StaticImage { Ok(MediaResponse::ProcessedStaticImage(StaticImage {
data: img, data: img,
@ -360,16 +368,8 @@ where
.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()))
} }
None => Ok(MediaResponse::Buffer {
data: buf,
content_type: Some("image/webp".into()),
}
.with_timing_info(TIME_TO_FIRST_BYTE_KEY, ttfb)
.with_opt_timing_info(SLURP_TIMING_KEY, Some(slurp_dur))
.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(
&buf, &options &buf, &options
@ -602,20 +602,16 @@ 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) => {
Err(e) => {
return ErrorResponse::postprocess_failed(e.to_string().into())
.into_response();
}
};
let webp = match self.compression { let webp = match self.compression {
CompressionLevel::Low => enc.encode(80.), CompressionLevel::Low => enc.encode(80.),
CompressionLevel::Med => enc.encode(60.), CompressionLevel::Med => enc.encode(60.),
@ -626,6 +622,12 @@ impl IntoResponse for StaticImage {
buf.write_all(&webp).unwrap(); buf.write_all(&webp).unwrap();
} }
Err(e) => {
log::warn!("webp compression failed: {:?}", e);
self.data.write_to(&mut buf, self.format).unwrap();
}
};
}
ImageFormat::Jpeg => { ImageFormat::Jpeg => {
let mut enc = JpegEncoder::new_with_quality( let mut enc = JpegEncoder::new_with_quality(
&mut buf, &mut buf,