Skip to content

Commit

Permalink
Fix capture_image_area testcase on windows
Browse files Browse the repository at this point in the history
  • Loading branch information
x3ro committed Jun 19, 2022
1 parent 860c2a5 commit f24f897
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 13 deletions.
12 changes: 12 additions & 0 deletions piet-direct2d/src/conv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,18 @@ pub(crate) fn affine_to_matrix3x2f(affine: Affine) -> D2D1_MATRIX_3X2_F {
}
}

// TODO: Needs tests
pub(crate) fn matrix3x2f_to_affine(matrix: D2D1_MATRIX_3X2_F) -> Affine {
Affine::new([
matrix.matrix[0][0] as f64,
matrix.matrix[0][1] as f64,
matrix.matrix[1][0] as f64,
matrix.matrix[1][1] as f64,
matrix.matrix[2][0] as f64,
matrix.matrix[2][1] as f64,
])
}

// TODO: consider adding to kurbo.
pub(crate) fn rect_to_rectf(rect: Rect) -> D2D1_RECT_F {
D2D1_RECT_F {
Expand Down
15 changes: 13 additions & 2 deletions piet-direct2d/src/d2d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,16 @@ impl DeviceContext {
}
}

pub fn get_dpi_scale(&self) -> (f32, f32) {
let mut dpi_x = 0.0f32;
let mut dpi_y = 0.0f32;
unsafe {
self.0.GetDpi(&mut dpi_x, &mut dpi_y);
}
// https://docs.microsoft.com/en-us/windows/win32/direct2d/direct2d-and-high-dpi
(dpi_x / 96., dpi_y / 96.)
}

/// Begin drawing.
///
/// This must be done before any piet drawing operations.
Expand Down Expand Up @@ -770,6 +780,7 @@ impl DeviceContext {
width: usize,
height: usize,
alpha_mode: D2D1_ALPHA_MODE,
dpi_scale: f32,
) -> Result<Bitmap, Error> {
// Maybe using TryInto would be more Rust-like.
// Note: value is set so that multiplying by 4 (for pitch) is valid.
Expand All @@ -785,8 +796,8 @@ impl DeviceContext {
};
let props = D2D1_BITMAP_PROPERTIES1 {
pixelFormat: format,
dpiX: 96.0,
dpiY: 96.0,
dpiX: 96.0 * dpi_scale,
dpiY: 96.0 * dpi_scale,
bitmapOptions: D2D1_BITMAP_OPTIONS_NONE,
colorContext: null_mut(),
};
Expand Down
52 changes: 41 additions & 11 deletions piet-direct2d/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ pub use crate::text::{D2DLoadedFonts, D2DText, D2DTextLayout, D2DTextLayoutBuild

use crate::conv::{
affine_to_matrix3x2f, color_to_colorf, convert_stroke_style, gradient_stop_to_d2d,
rect_to_rectf, rect_to_rectu, to_point2f, to_point2u,
matrix3x2f_to_affine, rect_to_rectf, rect_to_rectu, to_point2f, to_point2u,
};
use crate::d2d::{Bitmap, Brush, DeviceContext, FillRule, Geometry};

Expand Down Expand Up @@ -335,6 +335,7 @@ impl<'a> RenderContext for D2DRenderContext<'a> {
// Move this code into impl to avoid duplication with transform?
self.rt
.set_transform(&affine_to_matrix3x2f(self.current_transform()));

Ok(())
}

Expand Down Expand Up @@ -456,21 +457,50 @@ impl<'a> RenderContext for D2DRenderContext<'a> {
fn capture_image_area(&mut self, rect: impl Into<Rect>) -> Result<Self::Image, Error> {
let r = rect.into();

let (dpi_scale_x, _) = self.rt.get_dpi_scale();
let dpi_scale = dpi_scale_x as f64;

let transform_matrix = self.rt.get_transform();
let affine_transform = matrix3x2f_to_affine(transform_matrix);

let device_size = Point {
x: r.width() * dpi_scale,
y: r.height() * dpi_scale,
};
// TODO: This transformation is untested with the current test pictures
let device_size = affine_transform * device_size;

let device_origin = Point {
x: r.x0 * dpi_scale,
y: r.y0 * dpi_scale,
};
// TODO: This transformation is untested with the current test pictures
let device_origin = affine_transform * device_origin;

let mut target_bitmap = self.rt.create_blank_bitmap(
r.width() as usize,
r.height() as usize,
device_size.x as usize,
device_size.y as usize,
D2D1_ALPHA_MODE_PREMULTIPLIED,
dpi_scale_x,
)?;

let dest_point = to_point2u((0.0f32, 0.0f32));
let src_rect = rect_to_rectu(Rect {
x0: r.x0,
y0: r.y0,
x1: r.width(),
y1: r.height(),
});
// TODO: I don't understand why I a src_rect that's 2.0 * dpi_scale * device_size
// in order for `copy_from_render_target` to copy the right portion. Pretty
// sure I'm doing something wrong here. Maybe someone who knows d2d better can
// help out?
let magic_multiplier_why = 2.0;

let src_rect = Rect {
x0: device_origin.x,
y0: device_origin.y,
x1: device_size.x * magic_multiplier_why,
y1: device_size.y * magic_multiplier_why,
};

let d2d_dest_point = to_point2u((0.0f32, 0.0f32));
let d2d_src_rect = rect_to_rectu(src_rect);
target_bitmap.copy_from_render_target(d2d_dest_point, self.rt, d2d_src_rect);

target_bitmap.copy_from_render_target(dest_point, self.rt, src_rect);
Ok(target_bitmap)
}

Expand Down

0 comments on commit f24f897

Please sign in to comment.