use image::{ImageBuffer, Rgba};
use rusttype::{point, Font, PositionedGlyph, Scale};
use tracing::{debug, warn};
use crate::colours::*;
pub struct FontSizes {
pub title_font_size: f32,
pub axis_font_size: f32,
pub axis_unit_font_size: f32,
pub legend_font_size: f32,
}
impl FontSizes {
pub fn new(canvas_pixel_size: &(u32, u32)) -> FontSizes {
let gr = (1.0 + 5.0_f32.sqrt()) / 2.0;
let line_height = (canvas_pixel_size.0 as f32).sqrt();
let title_font_size = 1.5 * line_height / gr;
debug!("Calculated title font size to be {}", title_font_size);
let axis_font_size = title_font_size / 2.0;
debug!("Calculated x-axis font size to be {}", axis_font_size);
let axis_unit_font_size = axis_font_size * 1.0;
let legend_font_size = axis_font_size;
FontSizes {
title_font_size,
axis_font_size,
axis_unit_font_size,
legend_font_size,
}
}
}
pub fn create_glyphs<'a>(
font_size: f32,
text: &'a str,
font: &'a Font,
) -> Vec<PositionedGlyph<'a>> {
let scale = Scale::uniform(font_size);
let v_metrics = font.v_metrics(scale);
font.layout(text, scale, point(0.0, 0.0 + v_metrics.ascent))
.collect()
}
pub fn draw_glyphs(
canvas: &mut ImageBuffer<Rgba<u8>, Vec<u8>>,
colour: [u8; 4],
glyphs: Vec<PositionedGlyph>,
position: (u32, u32),
) {
for glyph in glyphs {
if let Some(bounding_box) = glyph.pixel_bounding_box() {
glyph.draw(|x, y, v| {
let r = colour[0];
let g = colour[1];
let b = colour[2];
let a = (v * 255.0) as u8;
let px = x + position.0 + bounding_box.min.x as u32;
let py = y + position.1 + bounding_box.min.y as u32;
match canvas.get_pixel_mut_checked(px, py) {
Some(pixel) => *pixel = Rgba([r, g, b, a]),
None => warn!("Cannot draw text outside of canvas at ({}, {}), shorter title/labels required or increase the canvas size", px, py),
}
});
}
}
for pixel in canvas.pixels_mut() {
if pixel.0[3] == 0 {
*pixel = Rgba(WHITE);
}
}
}
pub fn get_maximum_height_of_glyphs(glyphs: &[PositionedGlyph]) -> u32 {
let min_y = glyphs
.first()
.map(|g| g.pixel_bounding_box().unwrap().min.y)
.unwrap();
let max_y = glyphs
.last()
.map(|g| g.pixel_bounding_box().unwrap().max.y)
.unwrap();
(max_y - min_y) as u32
}
pub fn get_width_of_glyphs(glyphs: &[PositionedGlyph]) -> u32 {
let min_x = glyphs
.first()
.map(|g| g.pixel_bounding_box().unwrap().min.x)
.unwrap();
let max_x = glyphs
.last()
.map(|g| g.pixel_bounding_box().unwrap().max.x)
.unwrap();
(max_x - min_x) as u32
}