imageproc icon indicating copy to clipboard operation
imageproc copied to clipboard

Draw text with outline

Open Fogapod opened this issue 2 years ago • 3 comments

Hello, https://github.com/image-rs/imageproc/pull/157 mentions text outline, but it was not implemented.

How could outline support be added for text drawing? Is it rendering text twice on top of itself with smaller size or something else?

EDIT: actually, drawing text on top of itself with offset would not work because that would create projection. the only solution i see for this is drawing each letter individually, but that is far from ideal.

Fogapod avatar Dec 10 '21 19:12 Fogapod

Found this solution:

// a modified version of:
// https://github.com/silvia-odwyer/gdl/blob/421c8df718ad32f66275d178edec56ec653caff9/crate/src/text.rs#L23
#[allow(clippy::too_many_arguments)]
pub fn draw_text_with_border<'a>(
    canvas: &mut DynamicImage,
    x: u32,
    y: u32,
    scale: Scale,
    font: &'a Font<'a>,
    text: &str,
    color: Rgba<u8>,
    outline_color: Rgba<u8>,
    outline_width: u8,
) {
    let mut image2: DynamicImage = DynamicImage::new_luma8(canvas.width(), canvas.height());

    imageproc::drawing::draw_text_mut(&mut image2, color, x, y, scale, font, text);

    let mut image2 = image2.to_luma8();
    imageproc::morphology::dilate_mut(
        &mut image2,
        imageproc::distance_transform::Norm::LInf,
        outline_width,
    );

    // Add a border to the text.
    for x in 0..image2.width() {
        for y in 0..image2.height() {
            let pixval = 255 - image2.get_pixel(x, y).0[0];
            if pixval != 255 {
                canvas.put_pixel(x, y, outline_color);
            }
        }
    }
    imageproc::drawing::draw_text_mut(canvas, color, x, y, scale, font, text);
}

Would be nice to have somthing similar in the library

Fogapod avatar Dec 11 '21 20:12 Fogapod

Found this solution from: https://github.com/fogleman/gg/blob/master/examples/meme.go Looks better as well

pub fn draw_text_with_outline<'a>(
    canvas: &mut DynamicImage,
    x: i32,
    y: i32,
    scale: Scale,
    font: &'a Font<'a>,
    text: &str,
    color: Rgba<u8>,
    outline_color: Rgba<u8>,
    outline_width: i32,
) {
    for dy in -outline_width..outline_width + 1 {
        for dx in -outline_width..outline_width + 1 {
            if dx * dx + dy * dy >= outline_width * outline_width {
                continue;
            }

            imageproc::drawing::draw_text_mut(
                canvas,
                outline_color,
                x + dx,
                y + dy,
                scale,
                font,
                text,
            );
        }
    }

    imageproc::drawing::draw_text_mut(canvas, color, x, y, scale, font, text);
}

nathanielfernandes avatar Nov 04 '22 01:11 nathanielfernandes

This version does look better but runs 3 times slower in my tests

Fogapod avatar Jun 10 '23 16:06 Fogapod