feat: 实现矩形选择功能
This commit is contained in:
102
src/mscanvas.rs
102
src/mscanvas.rs
@@ -113,6 +113,40 @@ impl Path2D {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RectSelection {
|
||||
/// 左上角坐标
|
||||
x: i32,
|
||||
y: i32,
|
||||
w: i32,
|
||||
h: i32,
|
||||
pixels: Vec<u8>,
|
||||
}
|
||||
|
||||
impl RectSelection {
|
||||
pub fn new(x: i32, y: i32, w: i32, h: i32, pixels: Vec<u8>) -> RectSelection {
|
||||
Self { x, y, w, h, pixels }
|
||||
}
|
||||
|
||||
pub fn contains(&self, p: Point) -> bool {
|
||||
let x = p.x as i32;
|
||||
let y = p.y as i32;
|
||||
!(x < self.x || y < self.y || x >= self.x + self.w || y >= self.y + self.h)
|
||||
}
|
||||
|
||||
pub fn move_offset(&mut self, offset_x: i32, offset_y: i32) {
|
||||
self.x += offset_x;
|
||||
self.y += offset_y;
|
||||
}
|
||||
|
||||
pub fn size(&self) -> (i32, i32) {
|
||||
(self.w, self.h)
|
||||
}
|
||||
|
||||
pub fn position(&self) -> (i32, i32) {
|
||||
(self.x, self.y)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MSCanvas {
|
||||
width: i32,
|
||||
height: i32,
|
||||
@@ -209,20 +243,45 @@ impl MSCanvas {
|
||||
dst
|
||||
}
|
||||
|
||||
pub fn pixel_at(&self, x: i32, y: i32) -> MSColor {
|
||||
pub fn pixel_at(&self, x: i32, y: i32) -> Option<MSColor> {
|
||||
// 边界检查
|
||||
if x < 0 || x >= self.width || y < 0 || y >= self.height {
|
||||
return MSColor::ZERO;
|
||||
return None;
|
||||
}
|
||||
|
||||
let index = ((y * self.width + x) * 4) as usize;
|
||||
|
||||
MSColor::new(
|
||||
Some(MSColor::new(
|
||||
self.pixels[index],
|
||||
self.pixels[index + 1],
|
||||
self.pixels[index + 2],
|
||||
self.pixels[index + 3],
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
pub fn pixel_is(&self, x: i32, y: i32, color: MSColor) -> bool {
|
||||
match self.pixel_at(x, y) {
|
||||
Some(c) => c == color,
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn select_rect(&self, x: i32, y: i32, w: i32, h: i32) -> RectSelection {
|
||||
let mut result = vec![255; (w * h * 4) as usize];
|
||||
|
||||
let mut index = 0;
|
||||
for yi in y..(y + h) {
|
||||
for xi in x..(x + w) {
|
||||
let color = self.pixel_at(xi, yi).unwrap_or(MSColor::WHITE);
|
||||
result[index] = color.r;
|
||||
result[index + 1] = color.g;
|
||||
result[index + 2] = color.b;
|
||||
result[index + 3] = color.a;
|
||||
index += 4;
|
||||
}
|
||||
}
|
||||
|
||||
RectSelection::new(x, y, w, h, result)
|
||||
}
|
||||
|
||||
pub fn overlay_pixels(&mut self, canvas: &MSCanvas) -> Vec<u8> {
|
||||
@@ -540,7 +599,7 @@ impl MSCanvas {
|
||||
pub fn fill_slow(&mut self, begin: Point) {
|
||||
let start_x = begin.x as i32;
|
||||
let start_y = begin.y as i32;
|
||||
let target_color = self.pixel_at(start_x, start_y);
|
||||
let target_color = self.pixel_at(start_x, start_y).unwrap_or(MSColor::ZERO);
|
||||
if target_color == self.fill_color {
|
||||
return;
|
||||
}
|
||||
@@ -552,7 +611,7 @@ impl MSCanvas {
|
||||
if x < 0 || x >= self.width || y < 0 || y >= self.height {
|
||||
continue;
|
||||
}
|
||||
if self.pixel_at(x, y) == target_color {
|
||||
if self.pixel_is(x, y, target_color) {
|
||||
self.fill_pixel_at1(x, y);
|
||||
|
||||
let p1 = (x - 1, y);
|
||||
@@ -578,7 +637,7 @@ impl MSCanvas {
|
||||
return;
|
||||
}
|
||||
|
||||
let target_color = self.pixel_at(start_x, start_y);
|
||||
let target_color = self.pixel_at(start_x, start_y).unwrap_or(MSColor::ZERO);
|
||||
if target_color == self.fill_color {
|
||||
return;
|
||||
}
|
||||
@@ -588,11 +647,11 @@ impl MSCanvas {
|
||||
|
||||
while let Some((y, mut lx, mut rx)) = stack.pop() {
|
||||
// 向左扩展 lx
|
||||
while lx - 1 >= 0 && self.pixel_at(lx - 1, y) == target_color {
|
||||
while lx - 1 >= 0 && self.pixel_is(lx - 1, y, target_color) {
|
||||
lx -= 1;
|
||||
}
|
||||
// 向右扩展 rx
|
||||
while rx + 1 < width && self.pixel_at(rx + 1, y) == target_color {
|
||||
while rx + 1 < width && self.pixel_is(rx + 1, y, target_color) {
|
||||
rx += 1;
|
||||
}
|
||||
|
||||
@@ -605,10 +664,10 @@ impl MSCanvas {
|
||||
if y - 1 >= 0 {
|
||||
let mut x = lx;
|
||||
while x <= rx {
|
||||
if self.pixel_at(x, y - 1) == target_color {
|
||||
if self.pixel_is(x, y - 1, target_color) {
|
||||
let span_start = x;
|
||||
// 跳过连续的目标色块
|
||||
while x <= rx && self.pixel_at(x, y - 1) == target_color {
|
||||
while x <= rx && self.pixel_is(x, y - 1, target_color) {
|
||||
x += 1;
|
||||
}
|
||||
// 将这个 span 入栈(用于后续处理上一行的上一行)
|
||||
@@ -623,9 +682,9 @@ impl MSCanvas {
|
||||
if y + 1 < height {
|
||||
let mut x = lx;
|
||||
while x <= rx {
|
||||
if self.pixel_at(x, y + 1) == target_color {
|
||||
if self.pixel_is(x, y + 1, target_color) {
|
||||
let span_start = x;
|
||||
while x <= rx && self.pixel_at(x, y + 1) == target_color {
|
||||
while x <= rx && self.pixel_is(x, y + 1, target_color) {
|
||||
x += 1;
|
||||
}
|
||||
stack.push((y + 1, span_start, x - 1));
|
||||
@@ -1314,6 +1373,23 @@ impl MSCanvas {
|
||||
let points = self.path2d.points.clone();
|
||||
self.fill_polygon(&points[..]);
|
||||
}
|
||||
|
||||
pub fn draw_rect_selection(&mut self, x: i32, y: i32, rect: &RectSelection) {
|
||||
let w = rect.w.min(self.width - x);
|
||||
let h = rect.h.min(self.height - y);
|
||||
|
||||
for dy in 0..h {
|
||||
for dx in 0..w {
|
||||
let src_idx = ((dy * rect.w + dx) * 4) as usize;
|
||||
let dst_idx = (((y + dy) * self.width + x + dx) * 4) as usize;
|
||||
|
||||
self.pixels[dst_idx] = rect.pixels[src_idx];
|
||||
self.pixels[dst_idx + 1] = rect.pixels[src_idx + 1];
|
||||
self.pixels[dst_idx + 2] = rect.pixels[src_idx + 2];
|
||||
self.pixels[dst_idx + 3] = rect.pixels[src_idx + 3];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn point_muln(point: Point, t: f32) -> Point {
|
||||
|
||||
Reference in New Issue
Block a user