mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-12 11:13:24 +00:00
Type: None, Crisp and Strong type composite precisely in exports
The offscreen pass that draws type with an anti-aliasing method other than Sharp rendered with the default 8-bit compositing, also in exports that composite with floating point. It now renders with the frame's rasterizer settings, so translucent fills inside the characters draw as Sharp type draws them.
This commit is contained in:
@@ -357,7 +357,7 @@ impl Renderer {
|
||||
r.inside_layer(|r| r.draw_text_geom(&mut off, frame, n, t, g, kept));
|
||||
off.flush();
|
||||
let mut pm = Pixmap::new(w, h);
|
||||
off.render(&mut pm, &mut r.resources);
|
||||
off.render_with(&mut pm, &mut r.resources, r.raster);
|
||||
pm
|
||||
};
|
||||
let sharp = TextObject { anti_alias: TypeAntiAlias::Sharp, ..t.clone() };
|
||||
|
||||
@@ -154,6 +154,36 @@ fn the_methods_keep_the_opacity_of_the_paint() {
|
||||
}
|
||||
}
|
||||
|
||||
/// In an export that composites with floating point, None, Crisp and Strong type composite its
|
||||
/// translucent fills as precisely as Sharp type: inside the characters each method draws the
|
||||
/// pixels Sharp draws, within the one step of rounding that keeping the type's pixels as 8-bit
|
||||
/// values adds.
|
||||
#[test]
|
||||
fn the_methods_keep_precise_compositing() {
|
||||
let fills = [(Color::rgb(0.9, 0.2, 0.1), 0.37), (Color::rgb(0.1, 0.6, 0.8), 0.53), (Color::rgb(0.3, 0.1, 0.7), 0.29)];
|
||||
let opts = RenderOptions { precise: true, ..Default::default() };
|
||||
let draw = |m: TypeAntiAlias| {
|
||||
let mut d = page(m, Some(FillLayer { opacity: 0.41, ..FillLayer::new(Paint::solid(Color::rgb(0.2, 0.7, 0.3))) }));
|
||||
let id = d.layers[0].children().and_then(|c| c.first()).map(|n| n.id).unwrap();
|
||||
let n = d.node_mut(id).unwrap();
|
||||
for (c, o) in fills {
|
||||
n.appearance.items.push(AppearanceItem::Fill(FillLayer { opacity: o, ..FillLayer::new(Paint::solid(c)) }));
|
||||
}
|
||||
Renderer::new().render(&d, W, H, Affine::IDENTITY, &opts).pixels
|
||||
};
|
||||
let sharp = draw(TypeAntiAlias::Sharp);
|
||||
let most = sharp.chunks(4).map(|p| p[3]).max().unwrap_or(0);
|
||||
let inside: Vec<usize> = sharp.chunks(4).enumerate().filter(|(_, p)| p[3] == most).map(|(i, _)| i).collect();
|
||||
assert!(inside.len() > 200, "{} pixels inside the characters", inside.len());
|
||||
for m in [TypeAntiAlias::None, TypeAntiAlias::Crisp, TypeAntiAlias::Strong] {
|
||||
let drawn = draw(m);
|
||||
let px = |p: &[u8], i: usize| [p[i * 4], p[i * 4 + 1], p[i * 4 + 2], p[i * 4 + 3]];
|
||||
let off = |i: usize| px(&drawn, i).iter().zip(px(&sharp, i)).any(|(a, b)| a.abs_diff(b) > 1);
|
||||
let wrong: Vec<_> = inside.iter().filter(|i| off(**i)).take(5).map(|i| (*i, px(&sharp, *i), px(&drawn, *i))).collect();
|
||||
assert!(wrong.is_empty(), "{m:?}: (pixel, Sharp, drawn) {wrong:?}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Type whose own fill multiplies with the art below it is drawn as Sharp draws it, so the fill
|
||||
/// still multiplies with that art.
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user