mirror of
https://github.com/storytold/designcraft.git
synced 2026-10-29 12:46:53 -06:00
64 lines
3.2 KiB
Rust
64 lines
3.2 KiB
Rust
//! Stroke behind fill on text: the fill covers the inner half of a double-width stroke.
|
|
use designcraft_color::{Color, swatch::Swatch};
|
|
use designcraft_compose::Cache;
|
|
use designcraft_doc::build::NewDocument;
|
|
use designcraft_doc::{Document, ParaFormat, SpreadRef};
|
|
use designcraft_geom::Rect;
|
|
use designcraft_render::{RenderOptions, Rendered, Renderer};
|
|
|
|
const WHITE: [u8; 4] = [255, 255, 255, 255];
|
|
const RED: [u8; 4] = [255, 0, 0, 255];
|
|
const BLUE: [u8; 4] = [0, 0, 255, 255];
|
|
const WEIGHT: f64 = 12.0;
|
|
|
|
/// A 200 pt "I" filled with `fill`, stroked red at [`WEIGHT`] (none when `stroke` is false).
|
|
fn render(fill: &str, stroke: bool, behind: bool) -> Rendered {
|
|
let mut d = Document::new(&NewDocument { width: 400.0, height: 400.0, facing_pages: false, ..Default::default() });
|
|
d.swatches.push(Swatch::color("Red", Color::rgb8(255, 0, 0)));
|
|
d.swatches.push(Swatch::color("Blue", Color::rgb8(0, 0, 255)));
|
|
let lid = d.default_layer();
|
|
let (_, sid) = d.add_text_frame(SpreadRef::Doc(0), Rect::new(40.0, 0.0, 400.0, 400.0), lid, "I", ParaFormat::default()).unwrap();
|
|
d.story_mut(sid).unwrap().format_chars(0..1, |f| {
|
|
f.over.size = Some(200.0);
|
|
f.over.fill = Some(fill.into());
|
|
f.over.stroke = Some(if stroke { "Red" } else { designcraft_color::swatch::NONE }.into());
|
|
f.over.stroke_weight = Some(WEIGHT);
|
|
f.over.stroke_behind_fill = Some(behind);
|
|
});
|
|
let mut r = Renderer::new();
|
|
r.threads = 0;
|
|
let cache = Cache::new();
|
|
let cs = cache.get(&d, sid, None);
|
|
assert!(!cs.frames[0].lines.is_empty(), "the glyph is set");
|
|
r.render_page(&d, &cache, 0, 1.0, false, &RenderOptions { paper: false, background: Some(WHITE), ..Default::default() }).unwrap()
|
|
}
|
|
|
|
/// The left edge of the stem on a row through the middle of the unstroked glyph.
|
|
fn stem_edge() -> (u32, u32) {
|
|
let img = render("Blue", false, false);
|
|
let blue: Vec<(u32, u32)> = (0..img.height).flat_map(|y| (0..img.width).map(move |x| (x, y))).filter(|&(x, y)| img.pixel(x, y) == BLUE).collect();
|
|
assert!(!blue.is_empty(), "the glyph is drawn");
|
|
let y0 = blue.iter().map(|p| p.1).min().unwrap();
|
|
let y1 = blue.iter().map(|p| p.1).max().unwrap();
|
|
let y = (y0 + y1) / 2;
|
|
let x = (0..img.width).find(|&x| img.pixel(x, y) == BLUE).unwrap();
|
|
(x, y)
|
|
}
|
|
|
|
#[test]
|
|
fn stroke_behind_fill_shows_only_outside_the_letter() {
|
|
let (x, y) = stem_edge();
|
|
let inner = x + 3; // inside the outline, within the inner half of a centred stroke
|
|
let outer = x - 9; // outside the outline, beyond the outer half of a centred stroke
|
|
let over = render("Blue", true, false);
|
|
assert_eq!(over.pixel(inner, y), RED, "a centred stroke covers the fill's edge");
|
|
assert_eq!(over.pixel(outer, y), WHITE, "a centred stroke reaches half its weight outside");
|
|
let behind = render("Blue", true, true);
|
|
assert_eq!(behind.pixel(inner, y), BLUE, "the fill covers the stroke behind it");
|
|
assert_eq!(behind.pixel(outer, y), RED, "the full stroke weight lies outside the letter");
|
|
assert_eq!(behind.pixel(x - 15, y), WHITE, "and no further");
|
|
let hollow = render(designcraft_color::swatch::NONE, true, true);
|
|
assert_eq!(hollow.pixel(inner, y), WHITE, "with no fill the letter stays empty");
|
|
assert_eq!(hollow.pixel(outer, y), RED);
|
|
}
|