#![cfg(feature = "ogp_images")] use crate::contrast::generate_color_pair_rgba; use image::{DynamicImage, ImageBuffer, Pixel, Rgb, Rgba}; use lazy_static::lazy_static; use pronouns_today::{Pronoun, util::{self, pcg64_seed, seed_with_today}}; use rusttype::{Font, Scale, point}; const SCALE: u32 = 400; const FONT_SCALE: f32 = 250.0; const FONT_DATA: &[u8] = include_bytes!("../assets/LeagueGothic.otf"); lazy_static! { static ref FONT: Font<'static> = Font::try_from_bytes(FONT_DATA) .expect("Invalid font data in build. This build and binary is invalid, and cannot be used."); } pub fn render_today(pronouns: &Pronoun, name: &str) -> ImageBuffer, Vec> { let mut state = util::INITIAL_STATE; seed_with_today(&mut state); pcg64_seed(&mut state, name.as_bytes()); render(pronouns, &mut state) } pub fn render(pronouns: &Pronoun, pcg64: &mut u128) -> ImageBuffer, Vec> { let (color1, color2) = generate_color_pair_rgba(pcg64); render_with_colors(pronouns, color1, color2) } pub fn render_with_colors(pronouns: &Pronoun, color1: Rgba, color2: Rgba) -> ImageBuffer, Vec> { let scale = Scale::uniform(FONT_SCALE); let mut output_image = ImageBuffer::from_fn(SCALE * 2, SCALE, |x, _| { if x < SCALE { color1 } else { color2 } }); for (color, text, offset) in [(color2, &pronouns.subject_pronoun, 0), (color1, &pronouns.object_pronoun, 400)] { let v_metrics = FONT.v_metrics(scale); let glyphs: Vec<_> = FONT .layout(&text.to_uppercase(), scale, point(0.0, v_metrics.ascent)) .collect(); let min_x = glyphs .first() .map(|g| g.pixel_bounding_box().unwrap().min.x) .unwrap_or(0); let max_x = glyphs .last() .map(|g| g.pixel_bounding_box().unwrap().max.x) .unwrap_or(0); let width = max_x - min_x; let height = v_metrics.ascent - v_metrics.descent; // Recompute offset to center text on page let x_offset = (SCALE as u32 - width as u32) / 2 + offset; let y_offset = ((SCALE as f32 - height) / 2.0) as u32; // Draw glyphs onto the buffer for glyph in glyphs { if let Some(bounding_box) = glyph.pixel_bounding_box() { glyph.draw(|x, y, v| { if v > 0.0 { let mut overlay_color = color; let alpha = &mut overlay_color.channels_mut()[3]; *alpha = (*alpha as f32 * v) as u8; output_image.get_pixel_mut( x + x_offset + bounding_box.min.x as u32, y + y_offset + bounding_box.min.y as u32 ).blend(&overlay_color); } }); } } } DynamicImage::ImageRgba8(output_image).into_rgb8() }