Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

egui support color emoji ttf fonts #605

Open
kernelkind opened this issue Dec 20, 2024 · 1 comment
Open

egui support color emoji ttf fonts #605

kernelkind opened this issue Dec 20, 2024 · 1 comment

Comments

@kernelkind
Copy link
Member

kernelkind commented Dec 20, 2024

The following is a proposal for getting color emoji font support directly in egui. It's purpose would be to complete

what we have now

What currently happens is in epaint, glyphs are rasterized here. This sets an opacity value for each glyph pixel. Then eventually the wgpu renderer takes the FontImage and converts it to sRGBA pixels here.

The COLR and CPAL tables are used in OpenType fonts to enable coloring of emojis. ttf-parser has a method for checking whether a glyph has coloring data called Face::is_color_glyph(GlyphId). It also has a method called Face::paint_color_glyph (here)

pub fn paint_color_glyph(
	&self,
	glyph_id: GlyphId,
	palette: u16,
	foreground_color: RgbaColor,
	painter: &mut dyn colr::Painter<'a>,
) -> Option<()> {
...
}

This tells the colr::Painter trait how to paint the current glyph.

I propose the following:

We need to make an implementation of Painter called ColorRasterizer. Calling paint_color_glyph using ColorRasterizer will store each method as a command, similar to VecPainter and will also compute the glyph's bounding box. It will support an additional function draw(FnMut(u32, u32, u8, u8, u8, u8)) which will play back the commands to rasterize the glyph within it's bounding box, using the closure to write the RGBa value to the pixel coordinate.

In egui add the following here:

let uv_rect = if self.ab_glyph_font.is_color_glyph(glyph_id) {
	let rasterizer = ColorRasterizer::new();
	let fg_color = RgbaColor::new(0, 0, 0, 255);
	self.ab_glyph_font.paint_color_glyph(glyph_id, 0, fg_color, &mut rasterizer);

	rasterizer.draw(|x, y, r, g, b, a| {
	    let px = glyph_pos.0 + x as usize;
	    let py = glyph_pos.1 + y as usize;
            image[(px, py)] = a;
	    image.with_colors()[(px, py)] = [r, g, b];
	});
	
	Some(rasterizer.get_uv_rect())
} else if self.ab_glyph_font.outline_glyph(glyph).map(|glyph| {
	...
}

Then in FontImage we can add the following:

pub struct FontImage {
    /// width, height
    pub size: [usize; 2],

    /// The coverage value.
    ///
    /// Often you want to use [`Self::srgba_pixels`] instead.
    pub pixels: Vec<f32>,
+ 
+   pub colors: Option<Vec<[u8; 3]>>,
}

This adds an optional colors Vec which holds the rgb values for each pixel in the FontImage. We exclude alpha because that is already captured in pixels.

Then FontImage::srgba_pixels would be modified to check if colors.is_some(), and if so, use them for Color32::from_rgba_premultiplied. Otherwise, use the previous implementation.

@kernelkind kernelkind changed the title support color emoji ttf fonts egui support color emoji ttf fonts Dec 20, 2024
@jb55
Copy link
Contributor

jb55 commented Dec 20, 2024

curious what @emilk thinks of this plan

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants