mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-10 03:01:33 +00:00
Character: type with color glyphs is drawn as Sharp
Color glyphs (bitmap glyphs in sbix or CBDT, and COLR layers) paint their own pixels and layers. The renderer draws them unchanged in the black drawing that measures coverage, so their own opacity counted as the characters' coverage: Strong made a half-transparent pixel inside a glyph opaque, and Crisp could erase faint detail. draw_type_edges now returns false for type with color glyphs, as it does for type with inline graphics, and docs/mcp.md lists them.
This commit is contained in:
@@ -1958,11 +1958,12 @@ impl Renderer {
|
||||
/// the type is drawn offscreen again.
|
||||
///
|
||||
/// Returns false, having drawn nothing, for type that is drawn as Sharp draws it: type with
|
||||
/// inline graphics, type whose own fills or strokes include a brush stroke or a blend mode
|
||||
/// other than Normal, type that overprints while Overprint Preview is on, and type that shows a
|
||||
/// substitution highlight on screen. Drawn offscreen, those would blend with nothing or take
|
||||
/// the method on art that is not the characters'. It also returns false for type whose
|
||||
/// offscreen drawing would be more than [`MAX_RASTER_SIDE`] pixels a side.
|
||||
/// inline graphics, type with color glyphs (bitmap or COLR), type whose own fills or strokes
|
||||
/// include a brush stroke or a blend mode other than Normal, type that overprints while
|
||||
/// Overprint Preview is on, and type that shows a substitution highlight on screen. Drawn
|
||||
/// offscreen, those would blend with nothing or take the method on art that is not the
|
||||
/// characters'. It also returns false for type whose offscreen drawing would be more than
|
||||
/// [`MAX_RASTER_SIDE`] pixels a side.
|
||||
fn draw_type_edges(&mut self, ctx: &mut RenderContext, f: &Frame, n: &Node, t: &TextObject, g: &TextGeom) -> bool {
|
||||
if proof::overprints(f.opts) && t.runs.iter().any(|r| r.style.overprint_fill || r.style.overprint_stroke) {
|
||||
return false;
|
||||
@@ -1972,6 +1973,10 @@ impl Renderer {
|
||||
if t.runs.iter().any(|r| r.inline.is_some()) || n.appearance.items.iter().any(|i| i.visible() && (i.blend() != normal || brush(i))) {
|
||||
return false;
|
||||
}
|
||||
// Color glyphs paint their own pixels and layers, whose opacity is not the characters' coverage.
|
||||
if !g.images.is_empty() || !g.colours.is_empty() {
|
||||
return false;
|
||||
}
|
||||
if f.opts.highlight_substitutions {
|
||||
let setup = &f.doc.setup;
|
||||
let shows = |on: bool, path: &BezPath| on && !path.elements().is_empty();
|
||||
|
||||
@@ -201,6 +201,39 @@ fn type_with_an_inline_graphic_is_drawn_as_sharp() {
|
||||
}
|
||||
}
|
||||
|
||||
/// Type with a color glyph (a bitmap in `sbix` or `CBDT`, or COLR v0 or v1 layers) is drawn as
|
||||
/// Sharp draws it, so the glyph's own opacity is kept.
|
||||
#[test]
|
||||
fn type_with_a_color_glyph_is_drawn_as_sharp() {
|
||||
use vectorcraft_text::test_fonts::{COLOUR_CHAR, colour_bitmap_family, colour_bitmap_font, colr_family, colr_font};
|
||||
let _adding = crate::tests_fontchange::adding_fonts();
|
||||
let fonts = [
|
||||
(colour_bitmap_family(true), colour_bitmap_font(true)),
|
||||
(colour_bitmap_family(false), colour_bitmap_font(false)),
|
||||
(colr_family(false), colr_font(false)),
|
||||
(colr_family(true), colr_font(true)),
|
||||
];
|
||||
for (family, font) in fonts {
|
||||
let Some(font) = font else { panic!("{family}: the test font is built") };
|
||||
vectorcraft_text::FontDb::global().add_font(font);
|
||||
let draw = |m: TypeAntiAlias| {
|
||||
let mut d = Document::new(160.0, 160.0);
|
||||
let style = CharStyle { font_family: family.into(), size: 100.0, ..Default::default() };
|
||||
let mut t = TextObject::point(Point::new(20.3, 120.4), &COLOUR_CHAR.to_string(), style);
|
||||
t.anti_alias = m;
|
||||
let n = Node::new(d.alloc_id(), NodeKind::Text(Box::new(t)));
|
||||
let l = d.layers[0].id;
|
||||
d.insert(Some(l), 0, n).unwrap();
|
||||
Renderer::new().render(&d, 160, 160, Affine::IDENTITY, &RenderOptions::default()).pixels
|
||||
};
|
||||
let sharp = draw(TypeAntiAlias::Sharp);
|
||||
assert!(sharp.chunks(4).any(|p| p[3] > 0), "{family}: the glyph is drawn");
|
||||
for m in [TypeAntiAlias::None, TypeAntiAlias::Crisp, TypeAntiAlias::Strong] {
|
||||
assert!(draw(m) == sharp, "{family}, {m:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// In a supersampled export, None type in a group drawn offscreen (it isolates art that blends)
|
||||
/// still has hard edges on the exported pixels, wherever the group's layer starts.
|
||||
#[test]
|
||||
|
||||
+3
-2
@@ -4251,8 +4251,9 @@ method does, on the pixels of the picture being drawn (the canvas at its zoom, a
|
||||
- `strong` draws a pixel the type covers by a share c at `2c`, at most 1, so the type looks heavier.
|
||||
|
||||
The opacity of the type's paints stays as it is inside the characters. Type is drawn as Sharp draws it when it holds
|
||||
inline graphics, when its own fills or strokes in the Appearance panel include a brush stroke or a blend mode other than
|
||||
Normal, when it overprints while Overprint Preview is on, and on the canvas while it shows a substitution highlight.
|
||||
inline graphics or color glyphs (bitmap or COLR), when its own fills or strokes in the Appearance panel include a brush
|
||||
stroke or a blend mode other than Normal, when it overprints while Overprint Preview is on, and on the canvas while it
|
||||
shows a substitution highlight.
|
||||
With Preferences › General › Anti-aliased Artwork off, the canvas draws all its art with hard edges, type included, and
|
||||
so does an export whose own Anti-aliasing option is None. SVG, PDF and EPS export are unchanged and carry no setting.
|
||||
Reset Panel sets Sharp. Saved as `antiAlias` only when not `sharp`. One undo step.
|
||||
|
||||
Reference in New Issue
Block a user