diff --git a/src/mscanvas.rs b/src/mscanvas.rs index aa6a77a..f6121c9 100644 --- a/src/mscanvas.rs +++ b/src/mscanvas.rs @@ -293,24 +293,48 @@ impl MSCanvas { let width = canvas.width.min(self.width) as usize; let height = canvas.height.min(self.height) as usize; - // 预计算步长,避免重复计算 let src_stride = self.width as usize * 4; - let dst_stride = width * 4; + let dst_stride = canvas.width as usize * 4; // ⚠️ Bug fix: use canvas.width, not `width` for y in 0..height { - let src_base = y * src_stride; - let dst_base = y * dst_stride; + let src_row = &self.pixels[y * src_stride..y * src_stride + width * 4]; + let dst_row = &mut pixels[y * dst_stride..y * dst_stride + width * 4]; - // 使用显式循环,可能被编译器自动向量化 - for x in 0..width { - let src_idx = src_base + x * 4; - let dst_idx = dst_base + x * 4; + // Process 4 pixels at a time (16 bytes) for better auto-vectorization + let chunks = width / 4; + let remainder = width % 4; - // 只在非透明时复制 - if self.pixels[src_idx + 3] != 0 { - // 一次复制4个字节(可能被优化为单个u32操作) - pixels[dst_idx..dst_idx + 4] - .copy_from_slice(&self.pixels[src_idx..src_idx + 4]); + for chunk in 0..chunks { + let base = chunk * 16; + // Check alpha bytes for 4 pixels at once + let a0 = src_row[base + 3]; + let a1 = src_row[base + 7]; + let a2 = src_row[base + 11]; + let a3 = src_row[base + 15]; + + if a0 | a1 | a2 | a3 != 0 { + // At least one pixel is non-transparent + if a0 != 0 && a1 != 0 && a2 != 0 && a3 != 0 { + // All 4 pixels are non-transparent — bulk copy 16 bytes + dst_row[base..base + 16].copy_from_slice(&src_row[base..base + 16]); + } else { + // Mixed — copy individually + for i in 0..4 { + let off = base + i * 4; + if src_row[off + 3] != 0 { + dst_row[off..off + 4].copy_from_slice(&src_row[off..off + 4]); + } + } + } + } + // else: all 4 transparent — skip entirely + } + + // Handle remaining pixels + for x in (chunks * 4)..width { + let off = x * 4; + if src_row[off + 3] != 0 { + dst_row[off..off + 4].copy_from_slice(&src_row[off..off + 4]); } } } diff --git a/src/paint.rs b/src/paint.rs index b984566..b1619bf 100644 --- a/src/paint.rs +++ b/src/paint.rs @@ -1,5 +1,3 @@ -use std::thread; - use ::image::{ImageBuffer, ImageError, Rgba}; use iced::Theme; use iced::padding; @@ -9,6 +7,8 @@ use iced::widget::container; use iced::widget::{Column, button, column, image, pick_list, row, text}; use iced::{Border, Element, Length, Point, Renderer, Subscription, Task}; use iced::{color, event, mouse}; +use std::thread; +// use std::time::Duration; use crate::color_box::{ColorSelectionBox, CurrentColorBox}; use crate::image_button::image_button; @@ -596,6 +596,8 @@ impl PaintApp { } pub fn update(&mut self, message: Message) -> Task { + // let now = Instant::now(); + match self.tool_selected { Tool::Select => { self.update_with_select(message); @@ -718,6 +720,11 @@ impl PaintApp { return Task::perform(async { Message::RefreshImage }, |msg| msg); } + // let elapsed = now.elapsed(); + // if elapsed.gt(&Duration::from_millis(10)) { + // println!("update used: {:?}", elapsed); + // } + Task::none() } @@ -1393,13 +1400,17 @@ impl PaintApp { /// 将原始字节转换为 Iced 的图像句柄 fn update_image_handle(&mut self) { + // let now = Instant::now(); // 克隆数据以避免所有权问题,或者使用 Arc 如果数据量大 // 这里为了简单直接 clone,对于 800x600 (约 2MB) 来说很快 // let data = self.canvas.get_pixels(); let data = self.view_canvas.overlay_pixels(&self.canvas); + // println!("overlay_pixels used: {:?}", now.elapsed()); let (width, height) = self.canvas.size(); self.image_handle = image::Handle::from_rgba(width as u32, height as u32, data); + + // println!("update_image_handle used: {:?}", now.elapsed()); } }