feat: Implement eraser

This commit is contained in:
2026-02-27 22:29:17 +08:00
parent da99cfc765
commit 1f8a2859f9
2 changed files with 263 additions and 59 deletions

View File

@@ -40,16 +40,15 @@ pub struct MSCanvas {
width: i32,
height: i32,
// 原始像素数据RGBA 格式
// 长度 = width * height * 4
/// 原始像素数据RGBA 格式
/// 长度 = width * height * 4
pixels: Vec<u8>,
pixels_bak: Vec<u8>,
// 当前笔画颜色
/// 当前笔画颜色
color: MSColor,
// brush 大小
brush_radius: f32,
line_width: i32,
}
#[allow(unused)]
@@ -61,7 +60,7 @@ impl MSCanvas {
pixels: vec![255; (width * height * 4) as usize],
pixels_bak: Vec::new(),
color: MSColor::BLACK,
brush_radius: 0.5,
line_width: 1,
}
}
@@ -69,13 +68,17 @@ impl MSCanvas {
self.color = color;
}
pub fn set_brush_radius(&mut self, brush_radius: f32) {
self.brush_radius = brush_radius;
pub fn set_line_width(&mut self, line_width: i32) {
self.line_width = line_width;
}
}
#[allow(unused)]
impl MSCanvas {
pub fn size(&self) -> (i32, i32) {
(self.width, self.height)
}
pub fn get_pixels(&self) -> Vec<u8> {
self.pixels.clone()
}
@@ -157,15 +160,16 @@ impl MSCanvas {
}
}
pub fn draw_brush_at(&mut self, center: Point) {
if self.brush_radius < 1.0 {
pub fn brush_circle(&mut self, center: Point) {
if self.line_width <= 1 {
self.draw_pixel_at(center);
return;
}
let square = self.brush_radius * self.brush_radius;
let r = self.brush_radius.floor() as i32;
for dy in -r..=r {
for dx in -r..=r {
let square = (self.line_width as f32) * (self.line_width as f32) / 4.0;
let l = self.line_width / 2;
let r = self.line_width - l;
for dy in -l..r {
for dx in -l..r {
if (dx * dx + dy * dy) as f32 <= square {
self.draw_pixel_at(Point::new(center.x + dx as f32, center.y + dy as f32));
}
@@ -173,6 +177,20 @@ impl MSCanvas {
}
}
pub fn brush_square(&mut self, center: Point) {
if self.line_width <= 1 {
self.draw_pixel_at(center);
return;
}
let l = self.line_width / 2;
let r = self.line_width - l;
for dy in -l..r {
for dx in -l..r {
self.draw_pixel_at(Point::new(center.x + dx as f32, center.y + dy as f32));
}
}
}
fn bresenham_line(&mut self, begin: Point, end: Point) -> Vec<Point> {
let x1 = begin.x;
let y1 = begin.y;
@@ -259,10 +277,25 @@ impl MSCanvas {
}
}
pub fn draw_line_thick(&mut self, begin: Point, end: Point) {
pub fn draw_line_with_circle_brush(&mut self, begin: Point, end: Point) {
// let points = self.bresenham_line(begin, end);
// for point in points {
// self.draw_brush_at(point);
// }
self.draw_line_with(begin, end, MSCanvas::brush_circle);
}
pub fn draw_line_with_square_brush(&mut self, begin: Point, end: Point) {
self.draw_line_with(begin, end, MSCanvas::brush_square);
}
pub fn draw_line_with<F>(&mut self, begin: Point, end: Point, brush_fn: F)
where
F: Fn(&mut MSCanvas, Point) -> (),
{
let points = self.bresenham_line(begin, end);
for point in points {
self.draw_brush_at(point);
brush_fn(self, point);
}
}
@@ -387,22 +420,65 @@ impl MSCanvas {
(iter_count, fill_count)
}
pub fn stroke_rect(&mut self, x: f32, y: f32, width: f32, height: f32) {
self.draw_line_thick(Point::new(x, y), Point::new(x, y + height));
self.draw_line_thick(Point::new(x, y + height), Point::new(x + width, y + height));
self.draw_line_thick(Point::new(x + width, y + height), Point::new(x + width, y));
self.draw_line_thick(Point::new(x, y), Point::new(x + width, y));
pub fn clear_rect(&mut self, x: i32, y: i32, width: i32, height: i32) {
for yi in y..(y + height) {
self.clear_row(x, x + width, yi);
}
}
pub fn stroke_rect1(&mut self, left_top: Point, right_bottom: Point) {
let x = left_top.x;
let y = left_top.y;
let width = (right_bottom.x - left_top.x);
let height = (right_bottom.y - left_top.y);
self.stroke_rect(x, y, width, height);
pub fn fill_rect(&mut self, x: i32, y: i32, width: i32, height: i32) {
for yi in y..(y + height) {
self.draw_pixel_row(x, x + width, yi);
}
}
pub fn stroke_rect(&mut self, x: i32, y: i32, width: i32, height: i32) {
self.fill_rect(x, y, width, self.line_width);
self.fill_rect(x, y + height - self.line_width, width, self.line_width);
self.fill_rect(x, y, self.line_width, height);
self.fill_rect(x + width - self.line_width, y, self.line_width, height);
}
pub fn stroke_rect1(&mut self, p1: Point, p2: Point) {
let mut x = p1.x;
let mut y = p1.y;
let mut width = (p2.x - p1.x);
let mut height = (p2.y - p1.y);
if width < 0.0 && height < 0.0 {
x = p2.x;
y = p2.y;
width = (p1.x - p2.x);
height = (p1.y - p2.y);
} else if width < 0.0 {
x += width;
width = -width;
} else if height < 0.0 {
y += height;
height = -height;
}
self.stroke_rect(x as i32, y as i32, width as i32, height as i32);
}
pub fn clear(&mut self) {
self.pixels.fill(255);
}
pub fn clear_row(&mut self, xs: i32, xe: i32, y: i32) {
if y < 0 || y >= self.height {
return;
}
let xs = xs.clamp(0, self.width - 1);
let xe = xe.clamp(0, self.width as i32);
for x in xs..xe {
let index = ((y * self.width + x) * 4) as usize;
// 写入 RGBA 数据
// 注意Color 的 r, g, b, a 是 0.0 - 1.0,需要转为 0 - 255
self.pixels[index] = 255; // R
self.pixels[index + 1] = 255; // G
self.pixels[index + 2] = 255; // B
self.pixels[index + 3] = 255; // A
}
}
}