Display row of text with servo/font-kit and minifb

In continuing to explore GUI programming and simply displaying text, I have found font-kit to be the easiest API to grok. That said, I'm still struggling with some things. If I have a string "AbCd" I use the following code to rasterize each character and append it to a pixel buffer:

let mut pixel_buffer = vec!();
let mut ht = 0;
let mut wdth = 0;
for c in "AbCd".chars() {
    let glyph_id = font.glyph_for_char(c).unwrap();
    let mut canvas = Canvas::new(&Size2D::new(32,32), Format::A8);
    font.rasterize_glyph(
        &mut canvas,
        glyph_id,
        32.0,
        &FontTransform::identity(),
        &Point2D::new(0.0,32.0),
        HintingOptions::None,
        RasterizationOptions::GrayscaleAa,
    )
    .unwrap();

    if ht < canvas.size.height as usize {
        ht = canvas.size.height as usize
    }

    wdth += canvas.size.width as usize;

    let char_buffer = canvas.pixels
        .iter()
        .map(|i| *i as u32)
        .collect::<Vec<u32>>();

    pixel_buffer.extend(&char_buffer);
}

I then update the minifb window with window.update_with_buffer(&pixel_buffer, ht, wdth).unwrap();.

This displays text like this:

How would I get it to display the text in a row rather than a column? simply inverting height and width does not work.

To understand why it is failing, we need to think about the order in which the bytes should show up: The byte array starts out with the entire top row, then the second row and so on. But this means that if the characters are to be displayed next to each other, their data actually becomes interleaved.

I don't have time to write up an example right now, so if this isn't enough to help you figure it out, please say so, and I'll try to come up with an example tomorrow.

I think I understand. The pixel_buffer needs to be width of sum of individual character widths, height of maximum individual character height, and rather than appending one vec to the other I need to interweave every n items where n = individual character width. Is that right? Thank you for your kind help, as always.

Yeah that's correct.

I couldn't quite get that to work but I've discovered what is likely the "correct" way to use the font-kit API. I need to make a canvas of the full dimensions, then update that canvas with the rasterized glyph data.

let mut canvas = Canvas::new(&Size2D::new(wdt as u32, ht as u32), Format::A8);
for c in "AbCd".char_indices() {
    let glyph_id = font.glyph_for_char(c.1).unwrap();
    font.rasterize_glyph(
        &mut canvas,
        glyph_id,
        32.0, // chosen font size for this example
        &FontTransform::identity(),
        &Point2D::new(c.0 as f32 * 32.0, 32.0),
        HintingOptions::None,
        RasterizationOptions::GrayscaleAa,
    )
    .unwrap();
}

I then need to convert the u8 pixel buffer in the Canvas struct to u32 for minifb

let buf = canvas.pixels.iter().map(|i| *i as u32).collect();
window.update_with_buffer(&buf, width, height).unwrap();

which gives me

Thanks again for setting me on the right path, @alice.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.