diff --git a/ext/canvas/image_decoder.rs b/ext/canvas/image_decoder.rs index 4b9e4fa53a..02680da8e3 100644 --- a/ext/canvas/image_decoder.rs +++ b/ext/canvas/image_decoder.rs @@ -16,9 +16,6 @@ use image::DynamicImage; use image::ImageDecoder; use image::ImageError; -use crate::error::image_error_message; -use crate::error::DOMExceptionInvalidStateError; - // // About the animated image // > Blob .4 @@ -32,40 +29,43 @@ use crate::error::DOMExceptionInvalidStateError; // pub(crate) trait ImageDecoderFromReader<'a, R: BufRead + Seek> { - fn to_decoder(reader: R) -> Result + fn to_decoder( + reader: R, + error_fn: fn(ImageError) -> AnyError, + ) -> Result where Self: Sized; - fn to_intermediate_image(self) -> Result; + fn to_intermediate_image( + self, + error_fn: fn(ImageError) -> AnyError, + ) -> Result; fn get_icc_profile(&mut self) -> Option>; } pub(crate) type ImageDecoderFromReaderType<'a> = BufReader>; -pub(crate) fn image_decoding_error( - error: ImageError, -) -> DOMExceptionInvalidStateError { - DOMExceptionInvalidStateError::new(&image_error_message( - "decoding", - &error.to_string(), - )) -} - macro_rules! impl_image_decoder_from_reader { ($decoder:ty, $reader:ty) => { impl<'a, R: BufRead + Seek> ImageDecoderFromReader<'a, R> for $decoder { - fn to_decoder(reader: R) -> Result + fn to_decoder( + reader: R, + error_fn: fn(ImageError) -> AnyError, + ) -> Result where Self: Sized, { match <$decoder>::new(reader) { Ok(decoder) => Ok(decoder), - Err(err) => return Err(image_decoding_error(err).into()), + Err(err) => return Err(error_fn(err)), } } - fn to_intermediate_image(self) -> Result { + fn to_intermediate_image( + self, + error_fn: fn(ImageError) -> AnyError, + ) -> Result { match DynamicImage::from_decoder(self) { Ok(image) => Ok(image), - Err(err) => Err(image_decoding_error(err).into()), + Err(err) => Err(error_fn(err)), } } fn get_icc_profile(&mut self) -> Option> { diff --git a/ext/canvas/image_ops.rs b/ext/canvas/image_ops.rs index 2709df97aa..f984b039be 100644 --- a/ext/canvas/image_ops.rs +++ b/ext/canvas/image_ops.rs @@ -89,7 +89,10 @@ where /// Premultiply the alpha channel of the image. pub(crate) fn premultiply_alpha( image: DynamicImage, - unmatch: Option Result>, + unmatch_color_handler: fn( + ColorType, + DynamicImage, + ) -> Result, ) -> Result { let color = image.color(); match color { @@ -105,10 +108,7 @@ pub(crate) fn premultiply_alpha( ColorType::Rgba16 => Ok(DynamicImage::ImageRgba16( process_premultiply_alpha(&image.to_rgba16()), )), - x => match unmatch { - Some(unmatch) => unmatch(x), - None => Ok(image), - }, + x => unmatch_color_handler(x, image), } } @@ -217,7 +217,10 @@ where /// Invert the premultiplied alpha channel of the image. pub(crate) fn unpremultiply_alpha( image: DynamicImage, - unmatch: Option Result>, + unmatch_color_handler: fn( + ColorType, + DynamicImage, + ) -> Result, ) -> Result { match image.color() { ColorType::La8 => Ok(DynamicImage::ImageLumaA8( @@ -232,10 +235,7 @@ pub(crate) fn unpremultiply_alpha( ColorType::Rgba16 => Ok(DynamicImage::ImageRgba16( process_unpremultiply_alpha(&image.to_rgba16()), )), - x => match unmatch { - Some(unmatch) => unmatch(x), - None => Ok(image), - }, + x => unmatch_color_handler(x, image), } } @@ -387,7 +387,10 @@ where /// Convert the color space of the image from sRGB to Display-P3. pub(crate) fn srgb_to_display_p3( image: DynamicImage, - unmatch: Option Result>, + unmatch_color_handler: fn( + ColorType, + DynamicImage, + ) -> Result, ) -> Result { match image.color() { // The conversion of the lumincance color types to the display-p3 color space is meaningless. @@ -407,10 +410,7 @@ pub(crate) fn srgb_to_display_p3( ColorType::Rgba16 => Ok(DynamicImage::ImageRgba16( process_srgb_to_display_p3(&image.to_rgba16()), )), - x => match unmatch { - Some(unmatch) => unmatch(x), - None => Ok(image), - }, + x => unmatch_color_handler(x, image), } } @@ -551,7 +551,7 @@ where pub(crate) fn to_srgb_from_icc_profile( image: DynamicImage, icc_profile: Option>, - unmatch: Option Result>, + unmatch_color_handler: fn(ColorType, DynamicImage) -> Result, ) -> Result { match icc_profile { // If there is no color profile information, return the image as is. @@ -586,10 +586,7 @@ pub(crate) fn to_srgb_from_icc_profile( ColorType::Rgba16 => { Ok(DynamicImage::ImageRgba16(process_icc_profile_conversion::<_,_,8>(&image,icc_profile,srgb_icc_profile))) } - x => match unmatch { - Some(unmatch) => unmatch(x), - None => Ok(image), - }, + x => unmatch_color_handler(x, image), } } }, diff --git a/ext/canvas/op_create_image_bitmap.rs b/ext/canvas/op_create_image_bitmap.rs index 91cf68a08c..a98469ee26 100644 --- a/ext/canvas/op_create_image_bitmap.rs +++ b/ext/canvas/op_create_image_bitmap.rs @@ -19,6 +19,7 @@ use image::imageops::overlay; use image::imageops::FilterType; use image::ColorType; use image::DynamicImage; +use image::ImageError; use image::RgbaImage; use serde::Deserialize; use serde::Serialize; @@ -111,55 +112,62 @@ fn decode_bitmap_data( ) -> Result { let (image, width, height, icc_profile) = match image_bitmap_source { ImageBitmapSource::Blob => { + fn image_decoding_error(error: ImageError) -> AnyError { + DOMExceptionInvalidStateError::new(&image_error_message( + "decoding", + &error.to_string(), + )) + .into() + } let (image, icc_profile) = match &*mime_type { // Should we support the "image/apng" MIME type here? "image/png" => { let mut decoder: PngDecoder = ImageDecoderFromReader::to_decoder(BufReader::new(Cursor::new( buf, - )))?; + )), image_decoding_error)?; let icc_profile = decoder.get_icc_profile(); - (decoder.to_intermediate_image()?, icc_profile) + (decoder.to_intermediate_image(image_decoding_error)?, icc_profile) } "image/jpeg" => { let mut decoder: JpegDecoder = ImageDecoderFromReader::to_decoder(BufReader::new(Cursor::new( buf, - )))?; + )), image_decoding_error)?; let icc_profile = decoder.get_icc_profile(); - (decoder.to_intermediate_image()?, icc_profile) + (decoder.to_intermediate_image(image_decoding_error)?, icc_profile) } "image/gif" => { let mut decoder: GifDecoder = ImageDecoderFromReader::to_decoder(BufReader::new(Cursor::new( buf, - )))?; + )), image_decoding_error)?; let icc_profile = decoder.get_icc_profile(); - (decoder.to_intermediate_image()?, icc_profile) + (decoder.to_intermediate_image(image_decoding_error)?, icc_profile) } "image/bmp" => { let mut decoder: BmpDecoder = ImageDecoderFromReader::to_decoder(BufReader::new(Cursor::new( buf, - )))?; + )), image_decoding_error)?; let icc_profile = decoder.get_icc_profile(); - (decoder.to_intermediate_image()?, icc_profile) + (decoder.to_intermediate_image(image_decoding_error)?, icc_profile) } "image/x-icon" => { let mut decoder: IcoDecoder = ImageDecoderFromReader::to_decoder(BufReader::new(Cursor::new( buf, - )))?; + )), image_decoding_error)?; let icc_profile = decoder.get_icc_profile(); - (decoder.to_intermediate_image()?, icc_profile) + (decoder.to_intermediate_image(image_decoding_error)?, icc_profile) } "image/webp" => { let mut decoder: WebPDecoder = ImageDecoderFromReader::to_decoder(BufReader::new(Cursor::new( buf, - )))?; + )), image_decoding_error)?; let icc_profile = decoder.get_icc_profile(); - (decoder.to_intermediate_image()?, icc_profile) + (decoder.to_intermediate_image(image_decoding_error)?, icc_profile) } "" => { return Err( @@ -243,25 +251,31 @@ fn apply_color_space_conversion( ColorSpaceConversion::Default => { match image_bitmap_source { ImageBitmapSource::Blob => { - fn color_unmatch(x: ColorType) -> Result { + fn unmatch_color_handler( + x: ColorType, + _: DynamicImage, + ) -> Result { Err(type_error(image_error_message( "apply colorspaceConversion: default", &format!("The color type {:?} is not supported.", x), ))) } - to_srgb_from_icc_profile(image, icc_profile, Some(color_unmatch)) + to_srgb_from_icc_profile(image, icc_profile, unmatch_color_handler) } ImageBitmapSource::ImageData => match predefined_color_space { // If the color space is sRGB, return the image as is. PredefinedColorSpace::Srgb => Ok(image), PredefinedColorSpace::DisplayP3 => { - fn unmatch(x: ColorType) -> Result { + fn unmatch_color_handler( + x: ColorType, + _: DynamicImage, + ) -> Result { Err(type_error(image_error_message( "apply colorspace: display-p3", &format!("The color type {:?} is not supported.", x), ))) } - srgb_to_display_p3(image, Some(unmatch)) + srgb_to_display_p3(image, unmatch_color_handler) } }, } @@ -278,6 +292,12 @@ fn apply_premultiply_alpha( if !color.has_alpha() { Ok(image) } else { + fn unmatch_color_handler( + _: ColorType, + image: DynamicImage, + ) -> Result { + Ok(image) + } match premultiply_alpha { // 1. PremultiplyAlpha::Default => Ok(image), @@ -285,7 +305,9 @@ fn apply_premultiply_alpha( // https://html.spec.whatwg.org/multipage/canvas.html#convert-from-premultiplied // 2. - PremultiplyAlpha::Premultiply => process_premultiply_alpha(image, None), + PremultiplyAlpha::Premultiply => { + process_premultiply_alpha(image, unmatch_color_handler) + } // 3. PremultiplyAlpha::None => { // NOTE: It's not clear how to handle the case of ImageData. @@ -295,7 +317,7 @@ fn apply_premultiply_alpha( return Ok(image); } - unpremultiply_alpha(image, None) + unpremultiply_alpha(image, unmatch_color_handler) } } }