chickensources 0.1.2

generate chickensources graphics
Documentation
use image::{DynamicImage, Rgba};
use imageproc::drawing;
use rusttype::{Font, Scale};

pub const fn div_ceil(lhs: u32, rhs: u32) -> u32 {
    let d = lhs / rhs;
    let r = lhs % rhs;

    if r > 0 && rhs > 0 {
        d + 1
    } else {
        d
    }
}

pub fn text_size(
    font: &Font,
    desired_width: u32,
    max_height: u32,
    text: &str,
) -> (Scale, u32, u32) {
    if text.trim().is_empty() {
        return (Scale::uniform(0.), 0, 0);
    }

    let iter_limit = 1000;

    let desired_width = i32::try_from(desired_width).unwrap_or(i32::MAX);
    let max_height = i32::try_from(max_height).unwrap_or(i32::MAX);

    let mut scale = Scale::uniform(0.);
    let mut text_w = 0;
    let mut text_h = 0;

    let mut i = 0;

    while text_w < desired_width && text_h < max_height && i < iter_limit {
        scale.x += 1.;
        scale.y += 1.;

        (text_w, text_h) = drawing::text_size(scale, font, text);

        i += 1;
    }

    (
        scale,
        text_w.try_into().unwrap_or_default(),
        text_h.try_into().unwrap_or_default(),
    )
}

pub fn draw_wrapped_text(
    img: &mut DynamicImage,
    color: Rgba<u8>,
    scale: Scale,
    font: &Font,
    y: u32,
    text: &str,
) {
    if text.trim().is_empty() {
        return;
    }

    let side_length = i32::try_from(img.height()).unwrap_or_default();
    let y = i32::try_from(y).unwrap_or_default();

    let lines = {
        let mut lines = Vec::new();
        let mut line = String::new();
        let max_w = 5 * side_length / 6;

        for word in text.split_whitespace() {
            let new_line = if line.is_empty() {
                word.into()
            } else {
                line.clone() + " " + word
            };

            let (line_w, _) = drawing::text_size(scale, font, &new_line);

            if line_w <= max_w {
                line = new_line;
            } else {
                lines.push(line);
                line = word.into();
            }
        }

        lines.push(line);

        lines
    };

    for (n, line) in lines.iter().enumerate() {
        let (line_w, line_h) = drawing::text_size(scale, font, line);

        let line_x = (side_length - line_w) / 2;
        let line_y = y + line_h * i32::try_from(n).unwrap_or_default();

        drawing::draw_text_mut(img, color, line_x, line_y, scale, font, line);
    }
}