使用rust绘制头像

前言

一直想搞个好看的头像,但是鉴于之前和其他人的头像撞了好几次,决定自己画一个。摸索了一段时间krita,发现还是略显麻烦,于是暂且搁置。

最近突发奇想,不如用rust计算机绘画,搞一个分形头像。不过试了几个不忍直视,决定还是按更贴近个人审美的方向搞个能看的。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
use image::{ImageBuffer, Rgb};
use std::f64::consts::{E, PI};

fn hsv_to_rgb(h: f64, s: f64, v: f64) -> Rgb<u8> {
let c = v * s;
let x = c * (1.0 - ((h / 60.0) % 2.0 - 1.0)).abs();
let m = v - c;

let (r, g, b) = match h {
h if h < 60.0 => (c, x, 0.0),
h if h < 120.0 => (x, c, 0.0),
h if h < 180.0 => (0.0, c, x),
h if h < 240.0 => (0.0, x, c),
h if h < 300.0 => (x, 0.0, c),
_ => (c, 0.0, x),
};

Rgb([
((r + m) * 255.0).clamp(0.0, 255.0) as u8,
((g + m) * 255.0).clamp(0.0, 255.0) as u8,
((b + m) * 255.0).clamp(0.0, 255.0) as u8,
])
}

fn generate_line_avatar(size: u32) -> ImageBuffer<Rgb<u8>, Vec<u8>> {
let mut img = ImageBuffer::new(size, size);
let center = (size as f64 / 2.0, size as f64 / 2.0);
let max_radius = center.0 * 0.9;

for (x, y, pixel) in img.enumerate_pixels_mut() {
let dx = x as f64 - center.0;
let dy = y as f64 - center.1;
let distance = (dx * dx + dy * dy).sqrt();
let angle = dy.atan2(dx) + PI;

// 线条密度函数
let line_density = 2.0; // 控制线条数量
let mut wave = (angle * line_density + distance * 0.1).sin();

// 添加干扰波纹
wave += 0.6 * (angle * 15.0 + distance * 0.05).cos();

// 创建动态线条阈值
let threshold = 0.8 * (1.0 - distance / max_radius).powf(2.0);
let is_line = wave.abs() > threshold;

// 颜色生成
let hue = (distance * 0.5 + angle * 180.0 / PI) % 360.0;
let saturation = 0.8 - distance / max_radius * 0.3;
let value = if is_line { 0.9 } else { 0.2 };

*pixel = hsv_to_rgb(hue, saturation, value);
}

// 添加中心光晕
for x in 0..size {
for y in 0..size {
let dx = x as f64 - center.0;
let dy = y as f64 - center.1;
let distance = (dx * dx + dy * dy).sqrt();

if distance < 15.0 {
let alpha = (1.0 - distance / 15.0).powf(2.0);
let p = img.get_pixel_mut(x, y);
p.0 =
p.0.map(|c| (c as f64 * (1.0 - alpha) + 255.0 * alpha) as u8);
}
}
}

img
}

fn main() {
let img = generate_line_avatar(1024);
img.save("line_avatar.png").unwrap();
println!("线条头像已生成:line_avatar.png");
}

结果展示

line avatar