1use image::{Rgba, RgbaImage};
2
3#[derive(Clone, Copy, Debug)]
4pub struct BlitRect {
5 pub x: u32,
6 pub y: u32,
7 pub w: u32,
8 pub h: u32,
9}
10
11impl BlitRect {
12 pub fn new(x: u32, y: u32, w: u32, h: u32) -> Self {
13 Self { x, y, w, h }
14 }
15}
16
17#[derive(Clone, Copy, Debug)]
18pub struct BlitOptions {
19 pub rotated: bool,
20 pub extrude: u32,
21 pub outlines: bool,
22}
23
24pub fn blit_rgba(
34 src: &RgbaImage,
35 canvas: &mut RgbaImage,
36 dst: BlitRect,
37 src_rect: BlitRect,
38 options: BlitOptions,
39) {
40 let (cw, ch) = canvas.dimensions();
41 let BlitRect {
42 x: dx,
43 y: dy,
44 w: _,
45 h: _,
46 } = dst;
47 let BlitRect {
48 x: sx,
49 y: sy,
50 w: sw,
51 h: sh,
52 } = src_rect;
53 let BlitOptions {
54 rotated,
55 extrude,
56 outlines,
57 } = options;
58
59 let (rw, rh) = if rotated { (sh, sw) } else { (sw, sh) };
61
62 for yy in 0..rh {
64 for xx in 0..rw {
65 let (ix, iy) = if rotated {
66 (sx + yy, sy + (sh - 1 - xx))
67 } else {
68 (sx + xx, sy + yy)
69 };
70 if dx + xx < cw && dy + yy < ch {
71 let px = *src.get_pixel(ix, iy);
72 canvas.put_pixel(dx + xx, dy + yy, px);
73 }
74 }
75 }
76
77 if outlines {
78 let red = Rgba([255, 0, 0, 255]);
80 for xx in 0..rw {
81 if dx + xx < cw && dy < ch {
82 canvas.put_pixel(dx + xx, dy, red);
83 }
84 let by = dy + rh.saturating_sub(1);
85 if dx + xx < cw && by < ch {
86 canvas.put_pixel(dx + xx, by, red);
87 }
88 }
89 for yy in 0..rh {
90 if dx < cw && dy + yy < ch {
91 canvas.put_pixel(dx, dy + yy, red);
92 }
93 let rx = dx + rw.saturating_sub(1);
94 if rx < cw && dy + yy < ch {
95 canvas.put_pixel(rx, dy + yy, red);
96 }
97 }
98 }
99
100 if extrude > 0 {
101 for e in 1..=extrude {
103 if dy >= e && dy < ch {
105 for xx in 0..rw {
106 if dx + xx < cw {
107 let p = *canvas.get_pixel(dx + xx, dy);
108 if dy >= e {
109 canvas.put_pixel(dx + xx, dy - e, p);
110 }
111 }
112 }
113 }
114 if dy + rh - 1 < ch && dy + rh - 1 + e < ch {
116 for xx in 0..rw {
117 if dx + xx < cw {
118 let p = *canvas.get_pixel(dx + xx, dy + rh - 1);
119 canvas.put_pixel(dx + xx, dy + rh - 1 + e, p);
120 }
121 }
122 }
123 if dx >= e && dx < cw {
125 for yy in 0..rh {
126 if dy + yy < ch {
127 let p = *canvas.get_pixel(dx, dy + yy);
128 canvas.put_pixel(dx - e, dy + yy, p);
129 }
130 }
131 }
132 if dx + rw - 1 < cw && dx + rw - 1 + e < cw {
134 for yy in 0..rh {
135 if dy + yy < ch {
136 let p = *canvas.get_pixel(dx + rw - 1, dy + yy);
137 canvas.put_pixel(dx + rw - 1 + e, dy + yy, p);
138 }
139 }
140 }
141 }
142 let c00 = if dx < cw && dy < ch {
144 *canvas.get_pixel(dx, dy)
145 } else {
146 Rgba([0, 0, 0, 0])
147 };
148 let c10 = if dx + rw > 0 && dx + rw - 1 < cw && dy < ch {
149 *canvas.get_pixel(dx + rw - 1, dy)
150 } else {
151 Rgba([0, 0, 0, 0])
152 };
153 let c01 = if dx < cw && dy + rh > 0 && dy + rh - 1 < ch {
154 *canvas.get_pixel(dx, dy + rh - 1)
155 } else {
156 Rgba([0, 0, 0, 0])
157 };
158 let c11 = if dx + rw > 0 && dx + rw - 1 < cw && dy + rh > 0 && dy + rh - 1 < ch {
159 *canvas.get_pixel(dx + rw - 1, dy + rh - 1)
160 } else {
161 Rgba([0, 0, 0, 0])
162 };
163 if dx >= 1 && dy >= 1 {
164 for ex in 1..=extrude {
165 for ey in 1..=extrude {
166 if dx >= ex && dy >= ey {
167 canvas.put_pixel(dx - ex, dy - ey, c00);
168 }
169 }
170 }
171 }
172 if dy >= 1 && dx + rw - 1 < cw {
173 for ex in 1..=extrude {
174 for ey in 1..=extrude {
175 if dy >= ey && dx + rw - 1 + ex < cw {
176 canvas.put_pixel(dx + rw - 1 + ex, dy - ey, c10);
177 }
178 }
179 }
180 }
181 if dx >= 1 && dy + rh - 1 < ch {
182 for ex in 1..=extrude {
183 for ey in 1..=extrude {
184 if dx >= ex && dy + rh - 1 + ey < ch {
185 canvas.put_pixel(dx - ex, dy + rh - 1 + ey, c01);
186 }
187 }
188 }
189 }
190 if dx + rw - 1 < cw && dy + rh - 1 < ch {
191 for ex in 1..=extrude {
192 for ey in 1..=extrude {
193 if dx + rw - 1 + ex < cw && dy + rh - 1 + ey < ch {
194 canvas.put_pixel(dx + rw - 1 + ex, dy + rh - 1 + ey, c11);
195 }
196 }
197 }
198 }
199 }
200}