diff --git a/piet-coregraphics/src/lib.rs b/piet-coregraphics/src/lib.rs index 996a04c2..6e1e6c75 100644 --- a/piet-coregraphics/src/lib.rs +++ b/piet-coregraphics/src/lib.rs @@ -391,26 +391,35 @@ impl<'a> RenderContext for CoreGraphicsContext<'a> { fn capture_image_area(&mut self, src_rect: impl Into) -> Result { let src_rect = src_rect.into(); - if src_rect.width() < 1.0 || src_rect.height() < 1.0 { + + // When creating a CoreGraphicsContext, we a transformation matrix is applied to map + // between piet's coordinate system and CoreGraphic's coordinate system + // (see [`CoreGraphicsContext::new_impl`] for details). Since the `src_rect` we receive + // as parameter is in piet's coordinate system, we need to first convert it to the CG one, + // as otherwise our captured image area would be wrong. + let transformation_matrix = self.ctx.get_ctm(); + let src_cgrect = to_cgrect(src_rect).apply_transform(&transformation_matrix); + + if src_cgrect.size.width < 1.0 || src_cgrect.size.height < 1.0 { return Err(Error::InvalidInput); } - if src_rect.width() > self.ctx.width() as f64 - || src_rect.height() > self.ctx.height() as f64 + if src_cgrect.size.width > self.ctx.width() as f64 + || src_cgrect.size.height > self.ctx.height() as f64 { return Err(Error::InvalidInput); } let full_image = self.ctx.create_image().ok_or(Error::InvalidInput)?; - if src_rect.width().round() as usize == self.ctx.width() - && src_rect.height().round() as usize == self.ctx.height() + if src_cgrect.size.width.round() as usize == self.ctx.width() + && src_cgrect.size.height.round() as usize == self.ctx.height() { return Ok(CoreGraphicsImage::NonEmpty(full_image)); } full_image - .cropped(to_cgrect(src_rect)) + .cropped(src_cgrect) .map(CoreGraphicsImage::NonEmpty) .ok_or(Error::InvalidInput) } diff --git a/piet/src/samples/mod.rs b/piet/src/samples/mod.rs index 263a9f4d..31f5d371 100644 --- a/piet/src/samples/mod.rs +++ b/piet/src/samples/mod.rs @@ -27,6 +27,7 @@ mod picture_12; mod picture_13; mod picture_14; mod picture_15; +mod picture_16; type BoxErr = Box; @@ -55,6 +56,7 @@ pub fn get(number: usize) -> Result, BoxErr> 13 => SamplePicture::new(picture_13::SIZE, picture_13::draw), 14 => SamplePicture::new(picture_14::SIZE, picture_14::draw), 15 => SamplePicture::new(picture_15::SIZE, picture_15::draw), + 16 => SamplePicture::new(picture_16::SIZE, picture_16::draw), _ => return Err(format!("No sample #{} exists", number).into()), }) } diff --git a/piet/src/samples/picture_16.rs b/piet/src/samples/picture_16.rs new file mode 100644 index 00000000..910318df --- /dev/null +++ b/piet/src/samples/picture_16.rs @@ -0,0 +1,45 @@ +//! Clipping and clearing. +//! +//! This tests interactions between clipping, transforms, and the clear method. +//! +//! 1. clear ignores clipping and transforms + +use crate::kurbo::{Affine, Circle, Rect, Size}; +use crate::{Color, Error, InterpolationMode, RenderContext}; + +pub const SIZE: Size = Size::new(400., 400.); + +const RED: Color = Color::rgb8(255, 0, 0); +const BLUE: Color = Color::rgb8(0, 0, 255); +const SEMI_TRANSPARENT_GREEN: Color = Color::rgba8(0, 255, 0, 125); +const SEMI_TRANSPARENT_WHITE: Color = Color::rgba8(255, 255, 255, 125); + +pub fn draw(rc: &mut R) -> Result<(), Error> { + rc.clear(None, Color::BLACK); + + let outer_rect = Rect::new(20., 20., 180., 180.); + let inner_rect = Rect::new(21., 21., 179., 179.); + + let top_left_corner = Rect::new(5., 5., 50., 50.); + let top_right_corner = Rect::new(150., 5., 195., 50.); + let bottom_left_corner = Rect::new(5., 150., 50., 195.); + let bottom_right_corner = Rect::new(150., 150., 195., 195.); + + + // Draw a box with a red border + rc.fill(outer_rect, &RED); + rc.fill(inner_rect, &BLUE); + + // Cache the box, clear the image and re-draw the box from the cache + let cache = rc.capture_image_area(outer_rect).unwrap(); + rc.clear(None, Color::WHITE); + rc.draw_image(&cache, outer_rect, InterpolationMode::NearestNeighbor); + + // Draw the cached image, scaled, in all four corners of the image + rc.draw_image(&cache, top_left_corner, InterpolationMode::Bilinear); + rc.draw_image(&cache, top_right_corner, InterpolationMode::Bilinear); + rc.draw_image(&cache, bottom_left_corner, InterpolationMode::Bilinear); + rc.draw_image(&cache, bottom_right_corner, InterpolationMode::Bilinear); + + Ok(()) +}