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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use image::{DynamicImage, RgbaImage};
use crate::{format, Color, Point, Rect, Size};
#[derive(Debug)]
pub struct Packer {
image: RgbaImage,
bins: Bin,
}
#[derive(Debug)]
struct Bin {
occupied: Option<Size>,
area: Rect,
children: Option<Box<(Bin, Bin)>>,
}
impl Packer {
pub fn new(size: Size) -> Self {
let mut image = RgbaImage::new(size.width, size.height);
image
.pixels_mut()
.for_each(|v| *v = Color::from([255, 0, 255, 0]));
Self {
image,
bins: Bin {
occupied: None,
children: None,
area: Rect::new(Point::new(0, 0), size),
},
}
}
pub fn pack(&mut self, image: &DynamicImage, gap: u32) -> Option<Rect> {
let size = Size::new(image.width(), image.height());
let gapped_size = Size::new(image.width() + gap * 2, image.height() + gap * 2);
match self.bins.insert(gapped_size) {
Some(rect) => {
let rect = Rect::new(Point::new(rect.min_x() + gap, rect.min_y() + gap), size);
let image = image.to_rgba8();
image.enumerate_pixels().for_each(|(x, y, p)| {
self.image.put_pixel(x + rect.min_x(), y + rect.min_y(), *p)
});
Some(rect)
}
None => None,
}
}
pub fn save(&self, name: &str, img: format::ImageFormat) -> anyhow::Result<()> {
self.image
.save_with_format(format!("{}.{}", name, img.ext()), img.as_image_format())?;
Ok(())
}
}
impl Bin {
pub fn fits(&self, size: Size) -> bool {
if self.area.width() < size.width || self.area.height() < size.height {
return false;
}
if let Some(children) = self.children.as_ref() {
return children.0.fits(size) || children.1.fits(size);
}
true
}
pub fn insert(&mut self, size: Size) -> Option<Rect> {
if !self.fits(size) {
return None;
}
if let Some(ref mut children) = self.children {
if let Some(rect) = children.0.insert(size) {
return Some(rect);
}
if let Some(rect) = children.1.insert(size) {
return Some(rect);
}
return None;
}
self.occupied = Some(size);
self.children = Some(Box::new((
Bin {
occupied: None,
area: Rect::new(
Point::new(self.area.min_x() + size.width, self.area.min_y()),
Size::new(self.area.width() - size.width, size.height),
),
children: None,
},
Bin {
occupied: None,
area: Rect::new(
Point::new(self.area.min_x(), self.area.min_y() + size.height),
Size::new(self.area.width(), self.area.height() - size.height),
),
children: None,
},
)));
Some(Rect::new(self.area.origin, size))
}
}