mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-10 13:32:23 +00:00
Render: the glow pan test checks fractional pans, and background docs say straight alpha
a_coarser_glow_kept_whole_draws_after_a_pan_as_made_again compared only whole-pixel pans with a fresh render. At a fractional pan it now compares the pixels right of the rectangle, where only the glow draws, with a fresh render at the whole pixel nearest the pan (either neighbor on a half pixel). RenderOptions::background and render_node_thumbnail's background are straight-alpha colors, as over_background reads them; their docs said premultiplied.
This commit is contained in:
@@ -3,7 +3,7 @@ use std::sync::Arc;
|
||||
use serde_json::json;
|
||||
use vectorcraft_doc::color::{Color, Paint};
|
||||
use vectorcraft_doc::{Appearance, Document, Effect, Node};
|
||||
use vectorcraft_geom::{Affine, Rect, shapes};
|
||||
use vectorcraft_geom::{Affine, Point, Rect, shapes};
|
||||
|
||||
use super::{DRAG_PIXEL_BUDGET, Drawn, PIXEL_BUDGET, drag_scale, filter_region, filter_region_within, pan_margin};
|
||||
use crate::tests_fontchange::{fonts_steady, with_fonts_unchanged};
|
||||
@@ -214,6 +214,19 @@ fn a_coarser_glow_kept_whole_draws_after_a_pan_as_made_again() {
|
||||
fresh.threads = 2;
|
||||
if pan.0.fract() == 0.0 && pan.1.fract() == 0.0 {
|
||||
assert!(panned.pixels == fresh.render(&d, size.0, size.1, xf, &opts).pixels, "blur {blur}, pan {pan:?}");
|
||||
} else {
|
||||
// Right of the rectangle's soft edge the frame holds only the glow, which the kept raster
|
||||
// places at the whole pixel nearest the pan, where a fresh render draws it too. A pan of
|
||||
// half a pixel is as near to the pixels on both sides, so either one is accepted.
|
||||
let right = (xf * Point::new(rect.x1, rect.y0)).x.ceil() as usize + 3;
|
||||
let row = size.0 as usize * 4;
|
||||
let glow = |p: &[u8]| p.chunks(row).flat_map(|r| r[right * 4..].to_vec()).collect::<Vec<_>>();
|
||||
let nearest = |v: f64| if (v - v.trunc()).abs() == 0.5 { vec![v.floor(), v.ceil()] } else { vec![v.round()] };
|
||||
let found = nearest(pan.0).into_iter().flat_map(|x| nearest(pan.1).into_iter().map(move |y| (x, y))).any(|whole| {
|
||||
let at = Affine::translate(whole) * base;
|
||||
glow(&panned.pixels) == glow(&fresh.render(&d, size.0, size.1, at, &opts).pixels)
|
||||
});
|
||||
assert!(found, "blur {blur}, pan {pan:?}: the glow is drawn at the whole pixel nearest the pan");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ pub fn raster_size(region: Rect, scale: f64) -> Result<(u32, u32), String> {
|
||||
pub struct RenderOptions {
|
||||
/// Outline (wireframe) view: 1 px black paths, no paint.
|
||||
pub outline: bool,
|
||||
/// Pasteboard colour behind everything (premultiplied RGBA8); `None` = transparent.
|
||||
/// Pasteboard color behind everything (straight-alpha RGBA8); `None` = transparent.
|
||||
pub background: Option<[u8; 4]>,
|
||||
/// Draw artboards as white rectangles (screen view). Export sets this to false.
|
||||
pub artboards: bool,
|
||||
|
||||
@@ -375,7 +375,7 @@ impl Renderer {
|
||||
}
|
||||
|
||||
/// Render any node (also one outside the tree, e.g. opacity-mask art) fitted into
|
||||
/// `size`×`size` pixels, optionally over a solid premultiplied background. A symbol instance
|
||||
/// `size`×`size` pixels, optionally over a solid straight-alpha background. A symbol instance
|
||||
/// is fitted by its symbol's art in `doc`.
|
||||
pub fn render_node_thumbnail(&mut self, doc: &Document, n: &Node, size: u32, background: Option<[u8; 4]>) -> Option<Rendered> {
|
||||
self.render_node_thumbnail_with(doc, n, size, background, &RenderOptions::default())
|
||||
|
||||
Reference in New Issue
Block a user