diff --git a/src/post_process/image_processing.rs b/src/post_process/image_processing.rs index feaee8f..620bc61 100644 --- a/src/post_process/image_processing.rs +++ b/src/post_process/image_processing.rs @@ -58,11 +58,13 @@ pub fn postprocess_webp_image( pub fn postprocess_png_image(data: &[u8], opt: &ImageOptions) -> ImageResult> { 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)?)); } - if opt.static_ == Some(true) { + if apng && opt.static_ == Some(true) { let first_frame = match dec.apng()?.into_frames().next() { Some(Ok(frame)) => frame, _ => return Ok(None), diff --git a/src/post_process/mod.rs b/src/post_process/mod.rs index 7b5771d..f860f55 100644 --- a/src/post_process/mod.rs +++ b/src/post_process/mod.rs @@ -18,7 +18,7 @@ use image::{ gif::{GifEncoder, Repeat}, jpeg::JpegEncoder, }, - Frames, ImageFormat, + Frames, GenericImageView, ImageFormat, }; use sniff::SniffingStream; @@ -312,63 +312,63 @@ where ImageFormat::WebP }; - if options.format.is_none() { - if mime.starts_with("image/png") || mime.starts_with("image/apng") { - let result = sandboxed!(sandbox => - image_processing::postprocess_png_image(&buf, &options) - .map_err(|e| { - ErrorResponse::postprocess_failed(e.to_string().into()) - }))?; + if mime.starts_with("image/png") || mime.starts_with("image/apng") { + let result = sandboxed!(sandbox => + image_processing::postprocess_png_image(&buf, &options) + .map_err(|e| { + ErrorResponse::postprocess_failed(e.to_string().into()) + }))?; - return match result { - Some(img) => { - Ok(MediaResponse::ProcessedStaticImage(StaticImage { - data: img, - format: output_static_format, - compression: options.compression_level(), - is_https, - }) - .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())) - } - None => Ok(MediaResponse::Buffer { - data: buf, - content_type: Some("image/png".into()), - } + 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) => { + Ok(MediaResponse::ProcessedStaticImage(StaticImage { + data: img, + format: output_static_format, + compression: options.compression_level(), + is_https, + }) .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") { - let result = sandboxed!(sandbox => - image_processing::postprocess_webp_image(&buf, &options) - .map_err(|e| { - ErrorResponse::postprocess_failed(e.to_string().into()) - }))?; + .with_timing_info(TIMING_KEY, begin.elapsed())) + } + }; + } + if mime.starts_with("image/webp") { + let result = sandboxed!(sandbox => + image_processing::postprocess_webp_image(&buf, &options) + .map_err(|e| { + ErrorResponse::postprocess_failed(e.to_string().into()) + }))?; - return match result { - Some(img) => { - Ok(MediaResponse::ProcessedStaticImage(StaticImage { - data: img, - format: output_static_format, - compression: options.compression_level(), - is_https, - }) - .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())) - } - None => Ok(MediaResponse::Buffer { - data: buf, - content_type: Some("image/webp".into()), - } + 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) => { + Ok(MediaResponse::ProcessedStaticImage(StaticImage { + data: img, + format: output_static_format, + compression: options.compression_level(), + is_https, + }) .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())), - }; - } + .with_timing_info(TIMING_KEY, begin.elapsed())) + } + }; } 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())); - 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(); } else { match self.format { #[cfg(feature = "lossy-webp")] ImageFormat::WebP => { - let enc = match webp::Encoder::from_image(&self.data) { - Ok(enc) => enc, + match webp::Encoder::from_image(&self.data) { + 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) => { - return ErrorResponse::postprocess_failed(e.to_string().into()) - .into_response(); + log::warn!("webp compression failed: {:?}", e); + 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 => { let mut enc = JpegEncoder::new_with_quality(