mooman219 / fontdue

The fastest font renderer in the world, written in pure rust.
Apache License 2.0
1.44k stars 72 forks source link

Wacky text alignment #37

Closed DusterTheFirst closed 4 years ago

DusterTheFirst commented 4 years ago

image Text seems to be top aligned, or not even aligned at all when iterating over the &GlyphPositions and rasterizing them with rasterize_config.

Sample code:

let mut img3 = ImageBuffer::<Pixel, _>::new(WIDTH, HEIGHT);
    // Fontdue
    {
        let canvas = &mut img3;

        let mut layout = Layout::new();
        let mut output = Vec::new();

        let helvetica = Font::from_bytes(HELVETICA_DATA, FontSettings::default()).unwrap();
        let fonts = &[helvetica];

        let (x, y) = (100, 200);
        let color = Pixel::from([Depth::MAX, Depth::MAX / 4, Depth::MAX / 2, Depth::MAX]);

        layout.layout_horizontal(
            fonts,
            &[
                &TextStyle::new("Hello ", 35.0, 0),
                &TextStyle::new("world!", 50.0, 0),
            ],
            &LayoutSettings {
                // max_width: Some(150.0),
                x: x as f32,
                y: y as f32,
                max_height: Some(10.0),
                ..LayoutSettings::default()
            },
            &mut output,
        );

        output.iter().for_each(|c| {
            let (metrics, pixels) = fonts[c.key.font_index].rasterize_config(c.key);

            dbg!(&c);
            draw_filled_rect_mut(
                canvas,
                Rect::at(c.x as _, c.y as i32 + c.height as i32)
                    .of_size(c.width as _, c.height as _),
                Rgba([0, !0, 0, !0]),
            );

            pixels.into_iter().enumerate().for_each(|(i, p)| {
                let p = (p as f32 / u8::MAX as f32);
                let image_x = (c.x as i32 + (i % c.width) as i32);
                let image_y = ((c.y as i32 + (c.height as i32)) + (i / c.width) as i32);

                let image_width = canvas.width() as i32;
                let image_height = canvas.height() as i32;

                if image_x >= 0 && image_x < image_width && image_y >= 0 && image_y < image_height {
                    let pixel = *canvas.get_pixel(image_x as u32, image_y as u32);

                    let weighted_color = weighted_sum(pixel, color, 1.0 - p, p);

                    canvas.draw_pixel(image_x as u32, image_y as u32, weighted_color);
                }
            });
        });
    }

produces: image

mooman219 commented 4 years ago

From your image it's fairly obvious that your code is miss-interpreting the y position and/or height. This is an example of that happening (Note the similarity to your issue): image

And here it is when interpreting the y/height from fontdue correctly: image

Note: The y coordinate is the bottom edge of the glyph, and height expands upwards. These are the relevant docs:

pub struct GlyphPosition {
    /// Hashable key that can be used to uniquely identify a rasterized glyph.
    pub key: GlyphRasterConfig,
    /// The left side of the glyph bounding box. Dimensions are in pixels, and are alawys whole
    /// numebrs.
    pub x: f32,
    /// The bottom side of the glyph bounding box. Dimensions are in pixels and are always whole
    /// numbers.
    pub y: f32,
    /// The width of the glyph. Dimensions are in pixels.
    pub width: usize,
    /// The height of the glyph. Dimensions are in pixels.
    pub height: usize,
}

Feel free to comment on this issue if you have more questions.