From 4c51f853c1cd5f25a5dc8eca84c3d024da4ee26a Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Wed, 4 Nov 2026 02:06:23 -0800 Subject: [PATCH] Render: node renders follow the anti-aliasing option render_node_with and render_node_thumbnail_with drew into a new context without setting its aliasing threshold, so AntiAlias::None still gave smooth edges. Both now set the threshold from the options, as a page render does. --- crates/render/src/renderer.rs | 2 ++ crates/render/src/tests.rs | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/crates/render/src/renderer.rs b/crates/render/src/renderer.rs index a8a67f270..1e07075e7 100644 --- a/crates/render/src/renderer.rs +++ b/crates/render/src/renderer.rs @@ -321,6 +321,7 @@ impl Renderer { let visible = inv.transform_rect_bbox(Rect::new(0.0, 0.0, w as f64, h as f64)); let px = 1.0 / view.determinant().abs().sqrt().max(1e-12); let mut ctx = single_threaded_context(w, h); + ctx.set_aliasing_threshold(opts.anti_alias.threshold()); let symbols = doc.symbol_boxes().quick(); let frame = Frame { mt: false, doc, symbols: &symbols, view, visible, px, opts, ink: Ink::Display, plates: None }; self.begin_frame(); @@ -361,6 +362,7 @@ impl Renderer { let s = (w as f64 - 2.0).max(1.0) / b.width().max(b.height()).max(1e-6); let view = Affine::translate((w as f64 / 2.0, w as f64 / 2.0)) * Affine::scale(s) * Affine::translate(-b.center().to_vec2()); let mut ctx = single_threaded_context(w, w); + ctx.set_aliasing_threshold(opts.anti_alias.threshold()); if let Some(bg) = background { ctx.set_paint(peniko::Color::from_rgba8(bg[0], bg[1], bg[2], bg[3])); ctx.fill_rect(&kurbo::Rect::new(0.0, 0.0, w as f64, w as f64)); diff --git a/crates/render/src/tests.rs b/crates/render/src/tests.rs index aa16311e0..a723c4da8 100644 --- a/crates/render/src/tests.rs +++ b/crates/render/src/tests.rs @@ -886,6 +886,25 @@ fn node_thumbnail_reports_the_size_it_draws() { } } +/// A node rendered with `AntiAlias::None` has hard edges, as a page render with that option does. +#[test] +fn node_renders_follow_the_anti_alias_option() { + let mut d = Document::new(100.0, 100.0); + let id = d.alloc_id(); + let n = Node::path(id, shapes::ellipse(Rect::new(10.3, 10.3, 60.6, 60.6)), Appearance::basic(Paint::solid(Color::BLACK), Paint::None, 0.0)); + let node = Arc::new(n.clone()); + let hard = RenderOptions { anti_alias: AntiAlias::None, ..Default::default() }; + let partial = |img: &Rendered| img.pixels.chunks(4).any(|p| p[3] != 0 && p[3] != 255); + let drawn = |img: &Rendered| img.pixels.chunks(4).any(|p| p[3] == 255); + let mut r = Renderer::new(); + assert!(partial(&r.render_node(&d, &node, 100, 100, Affine::IDENTITY).unwrap()), "art anti-aliasing has partial edge pixels"); + assert!(partial(&r.render_node_thumbnail(&d, &n, 37, None).unwrap()), "art anti-aliasing has partial edge pixels"); + let img = r.render_node_with(&d, &node, 100, 100, Affine::IDENTITY, &hard).unwrap(); + assert!(drawn(&img) && !partial(&img), "render_node_with: every alpha is 0 or 255"); + let thumb = r.render_node_thumbnail_with(&d, &n, 37, None, &hard).unwrap(); + assert!(drawn(&thumb) && !partial(&thumb), "render_node_thumbnail_with: every alpha is 0 or 255"); +} + #[test] fn opacity_mask_with_undecodable_image_leaves_out_object() { use vectorcraft_doc::{Effect, ImageBlob, ImageObject, NodeKind, OpacityMask};