Skip to main content

text2img/
lib.rs

1#![deny(missing_docs)]
2//! Creates a png image from text.
3//! Useful to protect sensitive information from bots and scrapers,
4//! such as email addresses and telephone numbers in web pages,
5//! and even passwords sent via email
6//!
7//! - [x] Png Support 8 bit rgba
8//! - [x] Font Weight implemented as Random pixels
9//! - [ ] Png Support 1 bit monochrome -  to reduce image size
10//! - [ ] Poisson Disk rendering
11
12use fontdue::layout::{CoordinateSystem, Layout, TextStyle};
13use raqote::DrawTarget;
14
15const FONT_DATA: &[u8]= include_bytes!("../assets/Roboto-Regular.ttf") as &[u8];
16
17/// Converts a text string into an image
18///
19/// # Arguments
20/// * `text` - a non empty string to render
21/// * `weight` - a percentage of pixels to be painted
22/// * `font_size` - the size of the font. Note this is not the same as the height of the image
23/// # Return
24/// the result. DrawTarget on success, an error message on failure
25///
26/// # Deprecated
27/// This should not leak the implementation of DrawTarget from the raqote crate,
28/// and will be removed in a future release.
29#[must_use]
30#[deprecated]
31pub fn text2img_internal(text:String, weight:u8, font_size:u8) -> Result<DrawTarget,String> {
32
33    if text.is_empty() {
34        return Err("Content can not be empty".to_owned());
35    }
36
37    if weight==0 {
38        return Err("Weight can not be zero".to_owned());
39    }
40
41    let settings = fontdue::FontSettings::default();
42
43    let font=fontdue::Font::from_bytes(FONT_DATA, settings).unwrap();
44
45    let mut layout = Layout::new(CoordinateSystem::PositiveYDown);
46
47    //TODO_maybe this is for centering text in larger image
48    // let x=0;
49    // let y=0;
50    // let width=500;
51    // let height=70;
52    // layout.reset(&LayoutSettings {
53    // 	x: x as f32,
54    // 	y: y as f32,
55    // 	max_width: Option::Some(width as f32),
56    // 	max_height: Option::Some(height as f32),
57    // 	horizontal_align: fontdue::layout::HorizontalAlign::Center,
58    // 	..LayoutSettings::default()
59    // });
60
61    let fonts = &[font.clone()];
62    layout.append(fonts, &TextStyle::new(&text, font_size as f32, 0));
63    let height=layout.height() as i32;
64    let first=layout.glyphs().first().unwrap();
65    let last=layout.glyphs().last().unwrap();
66
67    //This calculates the x of the last pixel and adds a margin equivalent to the first glyphs pixel
68    let width=(last.x as usize + last.width + first.x as usize) as i32;
69
70    let mut dt = DrawTarget::new(width, height);
71
72    for glyph in layout.glyphs() {
73        let glyph=glyph.to_owned();
74        let index=glyph.key.glyph_index;
75        let px=glyph.key.px;
76        let (metrics, coverage) = font.rasterize_indexed(index, px);
77
78        let mut image_data = Vec::with_capacity(coverage.len());
79
80        //TODO split this off into a trait
81        for cov in coverage.iter() {
82            let pixel = if weight==100 || fastrand::u8(0..=100)<=weight {
83                rgb_to_u32(0, 0, 0, *cov)
84            } else { 0};
85            image_data.push(pixel);
86        }
87        dt.draw_image_at(
88            glyph.x,
89            glyph.y,
90            &raqote::Image {
91                width: metrics.width as i32,
92                height: metrics.height as i32,
93                data: &image_data,
94            },
95            &raqote::DrawOptions {
96                blend_mode: raqote::BlendMode::Darken,
97                alpha: 1.0,
98                antialias: raqote::AntialiasMode::Gray,
99            },
100        );
101    }
102
103    Ok(dt)
104}
105
106/// Converts a rgba u8 to a u32
107/// # Arguments
108/// * `red` - red component byte
109/// * `green` - green component byte
110/// * `blue` - blue component byte
111/// * `alpha` - aƱpha component byte, 255 is opaque, 0 is transparent
112///
113/// # Return
114/// argb as a u32
115pub fn rgb_to_u32(red: u8, green: u8, blue: u8, alpha: u8) -> u32 {
116    (((alpha as u32) << 24) | ((red as u32) << 16) | ((green as u32) << 8) | (blue as u32)) as u32
117}