diff options
Diffstat (limited to 'import/fallback_generator/src/lib.rs')
-rw-r--r-- | import/fallback_generator/src/lib.rs | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/import/fallback_generator/src/lib.rs b/import/fallback_generator/src/lib.rs new file mode 100644 index 0000000..efb6579 --- /dev/null +++ b/import/fallback_generator/src/lib.rs @@ -0,0 +1,103 @@ +#![feature(random, string_remove_matches)] +use ab_glyph::{FontRef, PxScale}; +use anyhow::Result; +use image::{DynamicImage, ImageBuffer, ImageEncoder, Rgba, codecs::qoi::QoiEncoder}; +use imageproc::drawing::{draw_text_mut, text_size}; +use std::{ + hash::{Hash, Hasher}, + io::Write, +}; + +pub fn generate_fallback(name: &str, output: &mut dyn Write) -> Result<()> { + let width = 1024; + let height = (width * 1000) / 707; + + let mut image = ImageBuffer::<Rgba<f32>, Vec<f32>>::new(width, height); + + let text = name; + let bg = random_accent(text, 0.4); + image.pixels_mut().for_each(|p| *p = bg); + + let font = FontRef::try_from_slice(include_bytes!( + "/usr/share/fonts/cantarell/Cantarell-VF.otf" + )) + .unwrap(); + let font_bold = FontRef::try_from_slice(include_bytes!( + "/usr/share/fonts/TTF/OpenSans-CondensedExtraBold.ttf" + )) + .unwrap(); + + let mut bgtext = text.to_string(); + bgtext.remove_matches(&[',', ' ']); + let bgtext = bgtext.repeat(3); + let scale = PxScale { x: 1000., y: 1000. }; + let (w, h) = text_size(scale, &font, &bgtext); + for i in -1..4 { + draw_text_mut( + &mut image, + random_accent(&text, 0.6), + width as i32 / 2 - w as i32 / 2 + i * h as i32, + i * h as i32 * 2 / 3, + scale, + &font_bold, + &bgtext, + ); + } + + image.enumerate_pixels_mut().for_each(|(_x, y, p)| { + let f = 1. - (y as f32 / height as f32) * 0.5; + p.0[0] *= f; + p.0[1] *= f; + p.0[2] *= f; + }); + + let scale = PxScale { x: 200., y: 200. }; + let (w, _h) = text_size(scale, &font, text); + draw_text_mut( + &mut image, + Rgba([1., 1., 1., 1.]), + width as i32 / 2 - w as i32 / 2, + height as i32 * 3 / 4, + scale, + &font, + text, + ); + + let image = DynamicImage::from(image).to_rgb8(); + + QoiEncoder::new(output).write_image( + image.as_raw(), + image.width(), + image.height(), + image::ExtendedColorType::Rgb8, + )?; + Ok(()) +} + +struct XorshiftHasher(u64); +impl Hasher for XorshiftHasher { + fn finish(&self) -> u64 { + self.0 + } + fn write(&mut self, bytes: &[u8]) { + for b in bytes { + self.0 = self + .0 + .wrapping_add((*b as u64).wrapping_shl(24) + (*b as u64).wrapping_shl(56)); + self.0 ^= self.0.wrapping_shl(13); + self.0 ^= self.0.wrapping_shr(7); + self.0 ^= self.0.wrapping_shl(17); + } + } +} + +fn random_accent(text: &str, y: f32) -> Rgba<f32> { + let mut hasher = XorshiftHasher(0); + text.hash(&mut hasher); + let h = hasher.finish(); + let mut u = (h >> 32) as u32 as f32 / u32::MAX as f32; + let mut v = (h) as u32 as f32 / u32::MAX as f32; + u *= 0.2; + v *= 0.2; + Rgba([y - u * 0.5 - v * 0.5, y + v, y + u, 1.]) +} |