image_renderer/
canvas.rs

1//! Canvas 绘制上下文
2//!
3//! 提供类似 skia-safe 风格的绘制 API
4
5use crate::color::Color;
6use crate::error::{DrawError, Result};
7use crate::font::TextStyle;
8use crate::paint::{Paint, PaintStyle};
9use crate::point::Point;
10use crate::rect::Rect;
11use crate::surface::Surface;
12use image::Rgba;
13use imageproc::drawing::{
14    draw_filled_rect_mut, draw_hollow_rect_mut, draw_line_segment_mut, draw_text_mut,
15};
16use imageproc::rect::Rect as ImageprocRect;
17
18/// Canvas 绘制上下文
19///
20/// 提供在图片表面上进行各种绘制操作的能力
21pub struct Canvas {
22    /// 底层图片表面
23    surface: Surface,
24}
25
26impl Canvas {
27    /// 创建新的 Canvas
28    pub fn new(width: u32, height: u32) -> Result<Self> {
29        let surface = Surface::new(width, height)?;
30        Ok(Self { surface })
31    }
32
33    /// 创建指定背景色的 Canvas
34    pub fn new_with_color(width: u32, height: u32, color: Color) -> Result<Self> {
35        let surface = Surface::new_with_color(width, height, color.to_rgba())?;
36        Ok(Self { surface })
37    }
38
39    /// 从已有的 Surface 创建 Canvas
40    pub fn from_surface(surface: Surface) -> Self {
41        Self { surface }
42    }
43
44    /// 从文件加载图片并创建 Canvas
45    pub fn from_file<P: AsRef<std::path::Path>>(path: P) -> Result<Self> {
46        let surface = Surface::from_file(path)?;
47        Ok(Self { surface })
48    }
49
50    /// 获取 Canvas 宽度
51    pub fn width(&self) -> u32 {
52        self.surface.width()
53    }
54
55    /// 获取 Canvas 高度
56    pub fn height(&self) -> u32 {
57        self.surface.height()
58    }
59
60    /// 获取 Canvas 尺寸
61    pub fn dimensions(&self) -> (u32, u32) {
62        self.surface.dimensions()
63    }
64
65    /// 清空 Canvas 为指定颜色
66    pub fn clear(&mut self, color: Color) {
67        self.surface.clear(color.to_rgba());
68    }
69
70    /// 保存到文件
71    pub fn save<P: AsRef<std::path::Path>>(&self, path: P) -> Result<()> {
72        self.surface.save(path)?;
73        Ok(())
74    }
75
76    /// 导出为 PNG 字节数据
77    pub fn to_png_bytes(&self) -> Result<Vec<u8>> {
78        Ok(self.surface.to_png_bytes()?)
79    }
80
81    /// 导出为 JPEG 字节数据
82    pub fn to_jpeg_bytes(&self, quality: u8) -> Result<Vec<u8>> {
83        Ok(self.surface.to_jpeg_bytes(quality)?)
84    }
85
86    /// 获取底层 Surface
87    pub fn surface(&self) -> &Surface {
88        &self.surface
89    }
90
91    /// 获取可变的底层 Surface
92    pub fn surface_mut(&mut self) -> &mut Surface {
93        &mut self.surface
94    }
95
96    /// 绘制点
97    pub fn draw_point(&mut self, point: Point, paint: &Paint) {
98        let x = point.x;
99        let y = point.y;
100
101        if x >= 0 && y >= 0 {
102            let x = x as u32;
103            let y = y as u32;
104            if x < self.width() && y < self.height() {
105                self.surface.put_pixel(x, y, paint.color().to_rgba());
106            }
107        }
108    }
109
110    /// 绘制线段
111    pub fn draw_line(&mut self, start: Point, end: Point, paint: &Paint) {
112        let start_f = (start.x as f32, start.y as f32);
113        let end_f = (end.x as f32, end.y as f32);
114
115        draw_line_segment_mut(
116            self.surface.image_mut(),
117            start_f,
118            end_f,
119            paint.color().to_rgba(),
120        );
121    }
122
123    /// 绘制矩形
124    pub fn draw_rect(&mut self, rect: Rect, paint: &Paint) {
125        let imageproc_rect = ImageprocRect::at(rect.x, rect.y).of_size(rect.width, rect.height);
126
127        match paint.style() {
128            PaintStyle::Fill => {
129                draw_filled_rect_mut(
130                    self.surface.image_mut(),
131                    imageproc_rect,
132                    paint.color().to_rgba(),
133                );
134            }
135            PaintStyle::Stroke => {
136                // 绘制空心矩形
137                draw_hollow_rect_mut(
138                    self.surface.image_mut(),
139                    imageproc_rect,
140                    paint.color().to_rgba(),
141                );
142
143                // 如果线宽大于1,需要绘制多层
144                let stroke_width = paint.stroke_width() as i32;
145                for i in 1..stroke_width {
146                    let inner_rect = ImageprocRect::at(rect.x + i, rect.y + i).of_size(
147                        rect.width.saturating_sub((i * 2) as u32),
148                        rect.height.saturating_sub((i * 2) as u32),
149                    );
150                    if inner_rect.width() > 0 && inner_rect.height() > 0 {
151                        draw_hollow_rect_mut(
152                            self.surface.image_mut(),
153                            inner_rect,
154                            paint.color().to_rgba(),
155                        );
156                    }
157                }
158            }
159            PaintStyle::FillAndStroke => {
160                // 先填充
161                draw_filled_rect_mut(
162                    self.surface.image_mut(),
163                    imageproc_rect,
164                    paint.color().to_rgba(),
165                );
166                // 再描边
167                draw_hollow_rect_mut(
168                    self.surface.image_mut(),
169                    imageproc_rect,
170                    paint.color().to_rgba(),
171                );
172            }
173        }
174    }
175
176    /// 绘制圆角矩形
177    pub fn draw_rounded_rect(&mut self, rect: Rect, radius: f32, paint: &Paint) {
178        // 使用四个圆弧和四条直线来绘制圆角矩形
179        let r = radius.min((rect.width as f32 / 2.0).min(rect.height as f32 / 2.0));
180
181        if r <= 0.0 {
182            self.draw_rect(rect, paint);
183            return;
184        }
185
186        let color = paint.color().to_rgba();
187
188        // 简化实现:绘制矩形主体和四个角
189        match paint.style() {
190            PaintStyle::Fill | PaintStyle::FillAndStroke => {
191                // 填充中心矩形
192                let center_rect = ImageprocRect::at(rect.x, rect.y + r as i32)
193                    .of_size(rect.width, rect.height - (r * 2.0) as u32);
194                draw_filled_rect_mut(self.surface.image_mut(), center_rect, color);
195
196                // 填充上下矩形
197                let top_rect = ImageprocRect::at(rect.x + r as i32, rect.y)
198                    .of_size(rect.width - (r * 2.0) as u32, r as u32);
199                draw_filled_rect_mut(self.surface.image_mut(), top_rect, color);
200
201                let bottom_rect =
202                    ImageprocRect::at(rect.x + r as i32, rect.y + rect.height as i32 - r as i32)
203                        .of_size(rect.width - (r * 2.0) as u32, r as u32);
204                draw_filled_rect_mut(self.surface.image_mut(), bottom_rect, color);
205
206                // 绘制四个圆角
207                self.draw_circle_corner(rect.x + r as i32, rect.y + r as i32, r, color, true);
208                self.draw_circle_corner(
209                    rect.x + rect.width as i32 - r as i32,
210                    rect.y + r as i32,
211                    r,
212                    color,
213                    true,
214                );
215                self.draw_circle_corner(
216                    rect.x + r as i32,
217                    rect.y + rect.height as i32 - r as i32,
218                    r,
219                    color,
220                    true,
221                );
222                self.draw_circle_corner(
223                    rect.x + rect.width as i32 - r as i32,
224                    rect.y + rect.height as i32 - r as i32,
225                    r,
226                    color,
227                    true,
228                );
229            }
230            PaintStyle::Stroke => {
231                // 描边实现
232                self.draw_rect(rect, paint);
233            }
234        }
235    }
236
237    /// 辅助方法:绘制圆形区域
238    fn draw_circle_corner(&mut self, cx: i32, cy: i32, radius: f32, color: Rgba<u8>, fill: bool) {
239        let r = radius as i32;
240        for dy in -r..=r {
241            for dx in -r..=r {
242                let dist_sq = dx * dx + dy * dy;
243                let r_sq = (radius * radius) as i32;
244
245                if fill && dist_sq <= r_sq {
246                    let x = cx + dx;
247                    let y = cy + dy;
248                    if x >= 0 && y >= 0 {
249                        self.surface.put_pixel(x as u32, y as u32, color);
250                    }
251                }
252            }
253        }
254    }
255
256    /// 绘制圆形
257    pub fn draw_circle(&mut self, center: Point, radius: f32, paint: &Paint) {
258        let color = paint.color().to_rgba();
259        let r = radius as i32;
260
261        match paint.style() {
262            PaintStyle::Fill | PaintStyle::FillAndStroke => {
263                // 填充圆形
264                for dy in -r..=r {
265                    for dx in -r..=r {
266                        let dist_sq = dx * dx + dy * dy;
267                        let r_sq = (radius * radius) as i32;
268
269                        if dist_sq <= r_sq {
270                            let x = center.x + dx;
271                            let y = center.y + dy;
272                            if x >= 0 && y >= 0 {
273                                self.surface.put_pixel(x as u32, y as u32, color);
274                            }
275                        }
276                    }
277                }
278            }
279            PaintStyle::Stroke => {
280                // 描边圆形
281                let stroke_width = paint.stroke_width();
282                let inner_r = (radius - stroke_width).max(0.0);
283                let inner_r_sq = (inner_r * inner_r) as i32;
284                let outer_r_sq = (radius * radius) as i32;
285
286                for dy in -r..=r {
287                    for dx in -r..=r {
288                        let dist_sq = dx * dx + dy * dy;
289
290                        if dist_sq <= outer_r_sq && dist_sq >= inner_r_sq {
291                            let x = center.x + dx;
292                            let y = center.y + dy;
293                            if x >= 0 && y >= 0 {
294                                self.surface.put_pixel(x as u32, y as u32, color);
295                            }
296                        }
297                    }
298                }
299            }
300        }
301    }
302
303    /// 绘制椭圆
304    pub fn draw_oval(&mut self, rect: Rect, paint: &Paint) {
305        let cx = rect.x + rect.width as i32 / 2;
306        let cy = rect.y + rect.height as i32 / 2;
307        let rx = rect.width as f32 / 2.0;
308        let ry = rect.height as f32 / 2.0;
309
310        let color = paint.color().to_rgba();
311
312        match paint.style() {
313            PaintStyle::Fill | PaintStyle::FillAndStroke => {
314                // 填充椭圆
315                for y in rect.y..(rect.y + rect.height as i32) {
316                    for x in rect.x..(rect.x + rect.width as i32) {
317                        let dx = (x - cx) as f32;
318                        let dy = (y - cy) as f32;
319
320                        if (dx * dx) / (rx * rx) + (dy * dy) / (ry * ry) <= 1.0 {
321                            if x >= 0 && y >= 0 {
322                                self.surface.put_pixel(x as u32, y as u32, color);
323                            }
324                        }
325                    }
326                }
327            }
328            PaintStyle::Stroke => {
329                // 描边椭圆
330                let stroke_width = paint.stroke_width();
331                let inner_rx = (rx - stroke_width).max(0.0);
332                let inner_ry = (ry - stroke_width).max(0.0);
333
334                for y in rect.y..(rect.y + rect.height as i32) {
335                    for x in rect.x..(rect.x + rect.width as i32) {
336                        let dx = (x - cx) as f32;
337                        let dy = (y - cy) as f32;
338
339                        let outer = (dx * dx) / (rx * rx) + (dy * dy) / (ry * ry);
340                        let inner =
341                            (dx * dx) / (inner_rx * inner_rx) + (dy * dy) / (inner_ry * inner_ry);
342
343                        if outer <= 1.0 && inner >= 1.0 {
344                            if x >= 0 && y >= 0 {
345                                self.surface.put_pixel(x as u32, y as u32, color);
346                            }
347                        }
348                    }
349                }
350            }
351        }
352    }
353
354    /// 绘制文本
355    pub fn draw_text(
356        &mut self,
357        text: &str,
358        position: Point,
359        text_style: &TextStyle,
360        paint: &Paint,
361    ) {
362        let scale = text_style.scale();
363        let font = text_style.font.inner();
364        let color = paint.color().to_rgba();
365
366        draw_text_mut(
367            self.surface.image_mut(),
368            color,
369            position.x,
370            position.y,
371            scale,
372            font,
373            text,
374        );
375    }
376
377    /// 绘制图片
378    pub fn draw_image(&mut self, image: &Surface, position: Point) -> Result<()> {
379        self.draw_image_rect(
380            image,
381            None,
382            Rect::new(position.x, position.y, image.width(), image.height()),
383        )
384    }
385
386    /// 绘制图片的指定区域到指定位置
387    pub fn draw_image_rect(
388        &mut self,
389        image: &Surface,
390        src_rect: Option<Rect>,
391        dst_rect: Rect,
392    ) -> Result<()> {
393        // 获取源矩形
394        let src = src_rect.unwrap_or_else(|| Rect::new(0, 0, image.width(), image.height()));
395
396        // 验证源矩形
397        if src.x < 0
398            || src.y < 0
399            || src.x as u32 + src.width > image.width()
400            || src.y as u32 + src.height > image.height()
401        {
402            return Err(DrawError::InvalidCoordinates { x: src.x, y: src.y });
403        }
404
405        // 如果需要缩放
406        let src_image = if src.width != dst_rect.width || src.height != dst_rect.height {
407            // 先裁剪
408            let cropped = image.crop(src.x as u32, src.y as u32, src.width, src.height)?;
409            // 再缩放
410            cropped.resize(dst_rect.width, dst_rect.height)?
411        } else {
412            // 只裁剪
413            image.crop(src.x as u32, src.y as u32, src.width, src.height)?
414        };
415
416        // 复制像素
417        for y in 0..dst_rect.height {
418            for x in 0..dst_rect.width {
419                let src_pixel = src_image.get_pixel(x, y).unwrap();
420                let dst_x = dst_rect.x + x as i32;
421                let dst_y = dst_rect.y + y as i32;
422
423                if dst_x >= 0
424                    && dst_y >= 0
425                    && (dst_x as u32) < self.width()
426                    && (dst_y as u32) < self.height()
427                {
428                    // Alpha 混合
429                    self.blend_pixel(dst_x as u32, dst_y as u32, src_pixel);
430                }
431            }
432        }
433
434        Ok(())
435    }
436
437    /// Alpha 混合像素
438    fn blend_pixel(&mut self, x: u32, y: u32, src: Rgba<u8>) {
439        if let Some(dst) = self.surface.get_pixel(x, y) {
440            let src_alpha = src[3] as f32 / 255.0;
441            let dst_alpha = dst[3] as f32 / 255.0;
442
443            if src_alpha == 0.0 {
444                return;
445            }
446
447            if src_alpha == 1.0 {
448                self.surface.put_pixel(x, y, src);
449                return;
450            }
451
452            // Alpha 混合
453            let out_alpha = src_alpha + dst_alpha * (1.0 - src_alpha);
454
455            if out_alpha == 0.0 {
456                return;
457            }
458
459            let r = ((src[0] as f32 * src_alpha + dst[0] as f32 * dst_alpha * (1.0 - src_alpha))
460                / out_alpha) as u8;
461            let g = ((src[1] as f32 * src_alpha + dst[1] as f32 * dst_alpha * (1.0 - src_alpha))
462                / out_alpha) as u8;
463            let b = ((src[2] as f32 * src_alpha + dst[2] as f32 * dst_alpha * (1.0 - src_alpha))
464                / out_alpha) as u8;
465            let a = (out_alpha * 255.0) as u8;
466
467            self.surface.put_pixel(x, y, Rgba([r, g, b, a]));
468        }
469    }
470
471    /// 九宫格绘制图片(类似 skia-safe 的 draw_image_nine)
472    ///
473    /// 将图片分割成 3x3 的九宫格,智能拉伸以适应目标区域。
474    /// 四个角落保持不变,边缘单向拉伸,中心区域双向拉伸。
475    ///
476    /// # 参数
477    ///
478    /// * `image` - 要绘制的图片
479    /// * `center` - 中心矩形区域,定义九宫格的分割方式
480    /// * `dst` - 目标绘制区域
481    ///
482    /// # 九宫格分割示例
483    ///
484    /// ```text
485    /// ┌─────────┬──────────┬─────────┐
486    /// │  角落1  │  上边缘  │  角落2  │
487    /// │ (固定)  │ (水平拉) │ (固定)  │
488    /// ├─────────┼──────────┼─────────┤
489    /// │ 左边缘  │  中心    │ 右边缘  │
490    /// │ (垂直拉)│ (双向拉) │ (垂直拉)│
491    /// ├─────────┼──────────┼─────────┤
492    /// │  角落3  │  下边缘  │  角落4  │
493    /// │ (固定)  │ (水平拉) │ (固定)  │
494    /// └─────────┴──────────┴─────────┘
495    /// ```
496    pub fn draw_image_nine(&mut self, image: &Surface, center: Rect, dst: Rect) -> Result<()> {
497        // 验证 center 矩形的有效性
498        if center.x < 0
499            || center.y < 0
500            || center.x as u32 >= image.width()
501            || center.y as u32 >= image.height()
502            || center.x as u32 + center.width > image.width()
503            || center.y as u32 + center.height > image.height()
504        {
505            return Err(DrawError::InvalidCoordinates {
506                x: center.x,
507                y: center.y,
508            });
509        }
510
511        // 计算源图片的九个区域
512        let src_left = center.x as u32;
513        let src_top = center.y as u32;
514        let src_right = image.width() - (center.x as u32 + center.width);
515        let src_bottom = image.height() - (center.y as u32 + center.height);
516        let src_center_width = center.width;
517        let src_center_height = center.height;
518
519        // 计算目标区域的九个区域
520        // 如果目标区域太小,角落区域可能需要缩小
521        let dst_left = src_left.min(dst.width / 3);
522        let dst_top = src_top.min(dst.height / 3);
523        let dst_right = src_right.min(dst.width / 3);
524        let dst_bottom = src_bottom.min(dst.height / 3);
525
526        let dst_center_width = dst.width.saturating_sub(dst_left + dst_right);
527        let dst_center_height = dst.height.saturating_sub(dst_top + dst_bottom);
528
529        // 绘制九个区域
530
531        // 1. 左上角(固定大小)
532        if dst_left > 0 && dst_top > 0 {
533            let src_rect = Rect::new(0, 0, src_left, src_top);
534            let dst_rect = Rect::new(dst.x, dst.y, dst_left, dst_top);
535            self.draw_image_rect(image, Some(src_rect), dst_rect)?;
536        }
537
538        // 2. 上边缘(水平拉伸)
539        if dst_center_width > 0 && dst_top > 0 {
540            let src_rect = Rect::new(src_left as i32, 0, src_center_width, src_top);
541            let dst_rect = Rect::new(dst.x + dst_left as i32, dst.y, dst_center_width, dst_top);
542            self.draw_image_rect(image, Some(src_rect), dst_rect)?;
543        }
544
545        // 3. 右上角(固定大小)
546        if dst_right > 0 && dst_top > 0 {
547            let src_rect = Rect::new((image.width() - src_right) as i32, 0, src_right, src_top);
548            let dst_rect = Rect::new(
549                dst.x + (dst.width - dst_right) as i32,
550                dst.y,
551                dst_right,
552                dst_top,
553            );
554            self.draw_image_rect(image, Some(src_rect), dst_rect)?;
555        }
556
557        // 4. 左边缘(垂直拉伸)
558        if dst_left > 0 && dst_center_height > 0 {
559            let src_rect = Rect::new(0, src_top as i32, src_left, src_center_height);
560            let dst_rect = Rect::new(dst.x, dst.y + dst_top as i32, dst_left, dst_center_height);
561            self.draw_image_rect(image, Some(src_rect), dst_rect)?;
562        }
563
564        // 5. 中心区域(双向拉伸)
565        if dst_center_width > 0 && dst_center_height > 0 {
566            let src_rect = Rect::new(
567                src_left as i32,
568                src_top as i32,
569                src_center_width,
570                src_center_height,
571            );
572            let dst_rect = Rect::new(
573                dst.x + dst_left as i32,
574                dst.y + dst_top as i32,
575                dst_center_width,
576                dst_center_height,
577            );
578            self.draw_image_rect(image, Some(src_rect), dst_rect)?;
579        }
580
581        // 6. 右边缘(垂直拉伸)
582        if dst_right > 0 && dst_center_height > 0 {
583            let src_rect = Rect::new(
584                (image.width() - src_right) as i32,
585                src_top as i32,
586                src_right,
587                src_center_height,
588            );
589            let dst_rect = Rect::new(
590                dst.x + (dst.width - dst_right) as i32,
591                dst.y + dst_top as i32,
592                dst_right,
593                dst_center_height,
594            );
595            self.draw_image_rect(image, Some(src_rect), dst_rect)?;
596        }
597
598        // 7. 左下角(固定大小)
599        if dst_left > 0 && dst_bottom > 0 {
600            let src_rect = Rect::new(
601                0,
602                (image.height() - src_bottom) as i32,
603                src_left,
604                src_bottom,
605            );
606            let dst_rect = Rect::new(
607                dst.x,
608                dst.y + (dst.height - dst_bottom) as i32,
609                dst_left,
610                dst_bottom,
611            );
612            self.draw_image_rect(image, Some(src_rect), dst_rect)?;
613        }
614
615        // 8. 下边缘(水平拉伸)
616        if dst_center_width > 0 && dst_bottom > 0 {
617            let src_rect = Rect::new(
618                src_left as i32,
619                (image.height() - src_bottom) as i32,
620                src_center_width,
621                src_bottom,
622            );
623            let dst_rect = Rect::new(
624                dst.x + dst_left as i32,
625                dst.y + (dst.height - dst_bottom) as i32,
626                dst_center_width,
627                dst_bottom,
628            );
629            self.draw_image_rect(image, Some(src_rect), dst_rect)?;
630        }
631
632        // 9. 右下角(固定大小)
633        if dst_right > 0 && dst_bottom > 0 {
634            let src_rect = Rect::new(
635                (image.width() - src_right) as i32,
636                (image.height() - src_bottom) as i32,
637                src_right,
638                src_bottom,
639            );
640            let dst_rect = Rect::new(
641                dst.x + (dst.width - dst_right) as i32,
642                dst.y + (dst.height - dst_bottom) as i32,
643                dst_right,
644                dst_bottom,
645            );
646            self.draw_image_rect(image, Some(src_rect), dst_rect)?;
647        }
648
649        Ok(())
650    }
651
652    /// 测量文本尺寸
653    pub fn measure_text(&self, text: &str, text_style: &TextStyle) -> (u32, u32) {
654        let scale = text_style.scale();
655        let font = text_style.font.inner();
656
657        let v_metrics = font.v_metrics(scale);
658        let height = (v_metrics.ascent - v_metrics.descent).ceil() as u32;
659
660        let width = font
661            .layout(text, scale, rusttype::point(0.0, 0.0))
662            .map(|g| g.position().x + g.unpositioned().h_metrics().advance_width)
663            .last()
664            .unwrap_or(0.0)
665            .ceil() as u32;
666
667        (width, height)
668    }
669
670    /// 绘制虚线
671    ///
672    /// 根据 Paint 中的虚线样式绘制虚线。如果虚线样式为 Solid,则绘制实线。
673    ///
674    /// # 参数
675    ///
676    /// * `start` - 起点
677    /// * `end` - 终点
678    /// * `paint` - 绘制样式(包含虚线模式)
679    ///
680    /// # 示例
681    ///
682    /// ```no_run
683    /// use image_renderer::{Canvas, Color, Paint, Point, paint::DashStyle};
684    ///
685    /// let mut canvas = Canvas::new(400, 300).unwrap();
686    /// let mut paint = Paint::stroke(Color::BLUE, 2.0);
687    /// paint.set_dash_style(DashStyle::ShortDash);
688    ///
689    /// canvas.draw_dashed_line(
690    ///     Point::new(50, 100),
691    ///     Point::new(350, 100),
692    ///     &paint
693    /// );
694    /// ```
695    pub fn draw_dashed_line(&mut self, start: Point, end: Point, paint: &Paint) {
696        // 如果是实线,直接使用普通绘制
697        if paint.dash_style().is_solid() {
698            self.draw_line(start, end, paint);
699            return;
700        }
701
702        // 获取虚线模式
703        let pattern = match paint.dash_pattern() {
704            Some(p) => p,
705            None => {
706                self.draw_line(start, end, paint);
707                return;
708            }
709        };
710
711        if pattern.is_empty() {
712            self.draw_line(start, end, paint);
713            return;
714        }
715
716        // 计算线段长度和方向
717        let dx = end.x - start.x;
718        let dy = end.y - start.y;
719        let length = ((dx * dx + dy * dy) as f32).sqrt();
720
721        if length == 0.0 {
722            return;
723        }
724
725        // 计算单位方向向量
726        let unit_dx = dx as f32 / length;
727        let unit_dy = dy as f32 / length;
728
729        // 遍历虚线模式绘制
730        let mut current_pos = 0.0;
731        let mut pattern_index = 0;
732        let mut is_dash = true; // 开始是实线段
733
734        while current_pos < length {
735            let segment_length = pattern[pattern_index % pattern.len()];
736            let next_pos = (current_pos + segment_length).min(length);
737
738            if is_dash {
739                // 绘制实线段
740                let seg_start = Point::new(
741                    start.x + (unit_dx * current_pos) as i32,
742                    start.y + (unit_dy * current_pos) as i32,
743                );
744                let seg_end = Point::new(
745                    start.x + (unit_dx * next_pos) as i32,
746                    start.y + (unit_dy * next_pos) as i32,
747                );
748                self.draw_line(seg_start, seg_end, paint);
749            }
750
751            current_pos = next_pos;
752            pattern_index += 1;
753            is_dash = !is_dash; // 交替实线和间隙
754        }
755    }
756
757    /// 绘制虚线矩形
758    ///
759    /// 根据 Paint 中的虚线样式绘制矩形边框。如果虚线样式为 Solid,则绘制实线矩形。
760    ///
761    /// # 参数
762    ///
763    /// * `rect` - 矩形区域
764    /// * `paint` - 绘制样式(包含虚线模式)
765    ///
766    /// # 示例
767    ///
768    /// ```no_run
769    /// use image_renderer::{Canvas, Color, Paint, Rect, paint::DashStyle};
770    ///
771    /// let mut canvas = Canvas::new(400, 300).unwrap();
772    /// let mut paint = Paint::stroke(Color::RED, 2.0);
773    /// paint.set_dash_style(DashStyle::DashDot);
774    ///
775    /// canvas.draw_dashed_rect(
776    ///     Rect::new(50, 50, 300, 200),
777    ///     &paint
778    /// );
779    /// ```
780    pub fn draw_dashed_rect(&mut self, rect: Rect, paint: &Paint) {
781        // 如果是实线,直接使用普通绘制
782        if paint.dash_style().is_solid() {
783            self.draw_rect(rect, paint);
784            return;
785        }
786
787        // 绘制四条边
788        // 上边
789        self.draw_dashed_line(
790            Point::new(rect.x, rect.y),
791            Point::new(rect.x + rect.width as i32, rect.y),
792            paint,
793        );
794
795        // 右边
796        self.draw_dashed_line(
797            Point::new(rect.x + rect.width as i32, rect.y),
798            Point::new(rect.x + rect.width as i32, rect.y + rect.height as i32),
799            paint,
800        );
801
802        // 下边
803        self.draw_dashed_line(
804            Point::new(rect.x + rect.width as i32, rect.y + rect.height as i32),
805            Point::new(rect.x, rect.y + rect.height as i32),
806            paint,
807        );
808
809        // 左边
810        self.draw_dashed_line(
811            Point::new(rect.x, rect.y + rect.height as i32),
812            Point::new(rect.x, rect.y),
813            paint,
814        );
815    }
816
817    /// 绘制虚线圆角矩形
818    ///
819    /// 根据 Paint 中的虚线样式绘制圆角矩形边框。如果虚线样式为 Solid,则绘制实线圆角矩形。
820    ///
821    /// # 参数
822    ///
823    /// * `rect` - 矩形区域
824    /// * `radius` - 圆角半径
825    /// * `paint` - 绘制样式(包含虚线模式)
826    ///
827    /// # 示例
828    ///
829    /// ```no_run
830    /// use image_renderer::{Canvas, Color, Paint, Rect, paint::DashStyle};
831    ///
832    /// let mut canvas = Canvas::new(400, 300).unwrap();
833    /// let mut paint = Paint::stroke(Color::BLUE, 2.0);
834    /// paint.set_dash_style(DashStyle::ShortDash);
835    ///
836    /// canvas.draw_dashed_rounded_rect(
837    ///     Rect::new(50, 50, 300, 200),
838    ///     20.0,
839    ///     &paint
840    /// );
841    /// ```
842    pub fn draw_dashed_rounded_rect(&mut self, rect: Rect, radius: f32, paint: &Paint) {
843        // 限制圆角半径
844        let r = radius.min((rect.width as f32 / 2.0).min(rect.height as f32 / 2.0));
845
846        if r <= 0.0 {
847            self.draw_dashed_rect(rect, paint);
848            return;
849        }
850
851        // 如果是实线,使用普通圆角矩形绘制
852        if paint.dash_style().is_solid() {
853            self.draw_rounded_rect(rect, r, paint);
854            return;
855        }
856
857        // 绘制四条直边(虚线)
858        // 上边
859        self.draw_dashed_line(
860            Point::new(rect.x + r as i32, rect.y),
861            Point::new(rect.x + rect.width as i32 - r as i32, rect.y),
862            paint,
863        );
864
865        // 右边
866        self.draw_dashed_line(
867            Point::new(rect.x + rect.width as i32, rect.y + r as i32),
868            Point::new(
869                rect.x + rect.width as i32,
870                rect.y + rect.height as i32 - r as i32,
871            ),
872            paint,
873        );
874
875        // 下边
876        self.draw_dashed_line(
877            Point::new(
878                rect.x + rect.width as i32 - r as i32,
879                rect.y + rect.height as i32,
880            ),
881            Point::new(rect.x + r as i32, rect.y + rect.height as i32),
882            paint,
883        );
884
885        // 左边
886        self.draw_dashed_line(
887            Point::new(rect.x, rect.y + rect.height as i32 - r as i32),
888            Point::new(rect.x, rect.y + r as i32),
889            paint,
890        );
891
892        // 绘制四个圆角(虚线弧)
893        // 左上角
894        self.draw_dashed_arc(
895            Point::new(rect.x + r as i32, rect.y + r as i32),
896            r,
897            180.0,
898            270.0,
899            paint,
900        );
901
902        // 右上角
903        self.draw_dashed_arc(
904            Point::new(rect.x + rect.width as i32 - r as i32, rect.y + r as i32),
905            r,
906            270.0,
907            360.0,
908            paint,
909        );
910
911        // 右下角
912        self.draw_dashed_arc(
913            Point::new(
914                rect.x + rect.width as i32 - r as i32,
915                rect.y + rect.height as i32 - r as i32,
916            ),
917            r,
918            0.0,
919            90.0,
920            paint,
921        );
922
923        // 左下角
924        self.draw_dashed_arc(
925            Point::new(rect.x + r as i32, rect.y + rect.height as i32 - r as i32),
926            r,
927            90.0,
928            180.0,
929            paint,
930        );
931    }
932
933    /// 绘制虚线圆弧
934    ///
935    /// 根据 Paint 中的虚线样式绘制圆弧。
936    ///
937    /// # 参数
938    ///
939    /// * `center` - 圆心
940    /// * `radius` - 半径
941    /// * `start_angle` - 起始角度(度数,0度为3点钟方向)
942    /// * `end_angle` - 结束角度(度数)
943    /// * `paint` - 绘制样式(包含虚线模式)
944    fn draw_dashed_arc(
945        &mut self,
946        center: Point,
947        radius: f32,
948        start_angle: f32,
949        end_angle: f32,
950        paint: &Paint,
951    ) {
952        // 获取虚线模式
953        let pattern = match paint.dash_pattern() {
954            Some(p) if !p.is_empty() => p,
955            _ => {
956                // 如果没有虚线模式,绘制实线弧
957                self.draw_arc_solid(center, radius, start_angle, end_angle, paint);
958                return;
959            }
960        };
961
962        // 计算弧长
963        let angle_range = (end_angle - start_angle).abs();
964        let arc_length = (angle_range.to_radians() * radius) as f32;
965
966        if arc_length <= 0.0 {
967            return;
968        }
969
970        // 沿着弧线绘制虚线
971        let mut current_length = 0.0;
972        let mut pattern_index = 0;
973        let mut is_dash = true;
974
975        while current_length < arc_length {
976            let segment_length = pattern[pattern_index % pattern.len()];
977            let next_length = (current_length + segment_length).min(arc_length);
978
979            if is_dash {
980                // 计算起始和结束角度
981                let seg_start_angle = start_angle + (current_length / arc_length) * angle_range;
982                let seg_end_angle = start_angle + (next_length / arc_length) * angle_range;
983
984                // 绘制弧段
985                self.draw_arc_segment(center, radius, seg_start_angle, seg_end_angle, paint);
986            }
987
988            current_length = next_length;
989            pattern_index += 1;
990            is_dash = !is_dash;
991        }
992    }
993
994    /// 绘制实线圆弧段
995    fn draw_arc_solid(
996        &mut self,
997        center: Point,
998        radius: f32,
999        start_angle: f32,
1000        end_angle: f32,
1001        paint: &Paint,
1002    ) {
1003        self.draw_arc_segment(center, radius, start_angle, end_angle, paint);
1004    }
1005
1006    /// 绘制圆弧段(使用点连线)
1007    fn draw_arc_segment(
1008        &mut self,
1009        center: Point,
1010        radius: f32,
1011        start_angle: f32,
1012        end_angle: f32,
1013        paint: &Paint,
1014    ) {
1015        // 计算需要的点数(极高密度以获得抗锯齿效果)
1016        // 使用超精细计算:通过极高的点密度模拟抗锯齿
1017        let angle_range = (end_angle - start_angle).abs();
1018        let arc_length = angle_range.to_radians() * radius;
1019
1020        // 使用极高的点密度来模拟抗锯齿效果
1021        // 每0.25像素一个点,确保圆弧足够平滑
1022        let points_per_pixel = 4.0; // 每像素4个点
1023        let num_points = (arc_length * points_per_pixel)
1024            .ceil()
1025            .max(angle_range * 2.0)
1026            .max(10.0) as i32;
1027
1028        // 生成弧线上的点
1029        let mut points = Vec::new();
1030        for i in 0..=num_points {
1031            let t = i as f32 / num_points as f32;
1032            let angle = start_angle + t * (end_angle - start_angle);
1033            let rad = angle.to_radians();
1034
1035            let x = center.x + (radius * rad.cos()) as i32;
1036            let y = center.y + (radius * rad.sin()) as i32;
1037            points.push(Point::new(x, y));
1038        }
1039
1040        // 使用线段连接点,保持线宽一致
1041        for i in 0..points.len() - 1 {
1042            self.draw_line(points[i], points[i + 1], paint);
1043        }
1044    }
1045
1046    /// 绘制自定义边框的矩形(支持每条边独立配置,每个角独立圆角)
1047    ///
1048    /// # 参数
1049    ///
1050    /// * `rect` - 矩形区域
1051    /// * `border` - 边框配置(每条边可独立设置颜色、线宽、虚线样式)
1052    /// * `radius` - 圆角配置(每个角可独立设置圆角半径)
1053    ///
1054    /// # 示例
1055    ///
1056    /// ```no_run
1057    /// use image_renderer::{Canvas, Color, Border, BorderSide, BorderRadius, DashStyle, Rect};
1058    ///
1059    /// let mut canvas = Canvas::new(400, 300).unwrap();
1060    ///
1061    /// // 创建不同样式的边框
1062    /// let border = Border::new(
1063    ///     BorderSide::solid(Color::RED, 2.0),           // 上边:红色实线
1064    ///     BorderSide::dashed(Color::BLUE, 3.0, DashStyle::ShortDash), // 右边:蓝色虚线
1065    ///     BorderSide::solid(Color::GREEN, 2.0),         // 下边:绿色实线
1066    ///     BorderSide::dashed(Color::YELLOW, 3.0, DashStyle::Dot),     // 左边:黄色点线
1067    /// );
1068    ///
1069    /// // 创建不同的圆角
1070    /// let radius = BorderRadius::new(20.0, 10.0, 5.0, 15.0);
1071    ///
1072    /// let rect = Rect::new(50, 50, 300, 200);
1073    /// canvas.draw_custom_border_rect(rect, &border, &radius);
1074    /// ```
1075    pub fn draw_custom_border_rect(
1076        &mut self,
1077        rect: Rect,
1078        border: &crate::border::Border,
1079        radius: &crate::border::BorderRadius,
1080    ) {
1081        // 限制圆角半径在合理范围内
1082        let radius = radius.clamp(rect.width as f32, rect.height as f32);
1083
1084        // 如果所有圆角都是0,使用简化的直角矩形绘制
1085        if radius.is_zero() {
1086            self.draw_custom_border_rect_no_radius(rect, border);
1087            return;
1088        }
1089
1090        // 绘制四条边(考虑圆角)
1091        // 上边:从左上圆角结束到右上圆角开始
1092        if border.top.width > 0.0 {
1093            let mut paint = crate::Paint::stroke(border.top.color, border.top.width);
1094            paint.set_dash_style(border.top.dash_style.clone());
1095
1096            let start = Point::new(rect.x + radius.top_left as i32, rect.y);
1097            let end = Point::new(rect.x + rect.width as i32 - radius.top_right as i32, rect.y);
1098            self.draw_dashed_line(start, end, &paint);
1099        }
1100
1101        // 右边:从右上圆角结束到右下圆角开始
1102        if border.right.width > 0.0 {
1103            let mut paint = crate::Paint::stroke(border.right.color, border.right.width);
1104            paint.set_dash_style(border.right.dash_style.clone());
1105
1106            let start = Point::new(rect.x + rect.width as i32, rect.y + radius.top_right as i32);
1107            let end = Point::new(
1108                rect.x + rect.width as i32,
1109                rect.y + rect.height as i32 - radius.bottom_right as i32,
1110            );
1111            self.draw_dashed_line(start, end, &paint);
1112        }
1113
1114        // 下边:从右下圆角结束到左下圆角开始
1115        if border.bottom.width > 0.0 {
1116            let mut paint = crate::Paint::stroke(border.bottom.color, border.bottom.width);
1117            paint.set_dash_style(border.bottom.dash_style.clone());
1118
1119            let start = Point::new(
1120                rect.x + rect.width as i32 - radius.bottom_right as i32,
1121                rect.y + rect.height as i32,
1122            );
1123            let end = Point::new(
1124                rect.x + radius.bottom_left as i32,
1125                rect.y + rect.height as i32,
1126            );
1127            self.draw_dashed_line(start, end, &paint);
1128        }
1129
1130        // 左边:从左下圆角结束到左上圆角开始
1131        if border.left.width > 0.0 {
1132            let mut paint = crate::Paint::stroke(border.left.color, border.left.width);
1133            paint.set_dash_style(border.left.dash_style.clone());
1134
1135            let start = Point::new(
1136                rect.x,
1137                rect.y + rect.height as i32 - radius.bottom_left as i32,
1138            );
1139            let end = Point::new(rect.x, rect.y + radius.top_left as i32);
1140            self.draw_dashed_line(start, end, &paint);
1141        }
1142
1143        // 绘制四个圆角
1144        // 左上角 (180° 到 270°)
1145        if radius.top_left > 0.0 {
1146            // 使用上边和左边的平均样式绘制圆角
1147            let corner_border = self.blend_corner_style(&border.top, &border.left);
1148            let mut paint = crate::Paint::stroke(corner_border.color, corner_border.width);
1149            paint.set_dash_style(corner_border.dash_style);
1150
1151            self.draw_dashed_arc(
1152                Point::new(
1153                    rect.x + radius.top_left as i32,
1154                    rect.y + radius.top_left as i32,
1155                ),
1156                radius.top_left,
1157                180.0,
1158                270.0,
1159                &paint,
1160            );
1161        }
1162
1163        // 右上角 (270° 到 360°)
1164        if radius.top_right > 0.0 {
1165            let corner_border = self.blend_corner_style(&border.top, &border.right);
1166            let mut paint = crate::Paint::stroke(corner_border.color, corner_border.width);
1167            paint.set_dash_style(corner_border.dash_style);
1168
1169            self.draw_dashed_arc(
1170                Point::new(
1171                    rect.x + rect.width as i32 - radius.top_right as i32,
1172                    rect.y + radius.top_right as i32,
1173                ),
1174                radius.top_right,
1175                270.0,
1176                360.0,
1177                &paint,
1178            );
1179        }
1180
1181        // 右下角 (0° 到 90°)
1182        if radius.bottom_right > 0.0 {
1183            let corner_border = self.blend_corner_style(&border.right, &border.bottom);
1184            let mut paint = crate::Paint::stroke(corner_border.color, corner_border.width);
1185            paint.set_dash_style(corner_border.dash_style);
1186
1187            self.draw_dashed_arc(
1188                Point::new(
1189                    rect.x + rect.width as i32 - radius.bottom_right as i32,
1190                    rect.y + rect.height as i32 - radius.bottom_right as i32,
1191                ),
1192                radius.bottom_right,
1193                0.0,
1194                90.0,
1195                &paint,
1196            );
1197        }
1198
1199        // 左下角 (90° 到 180°)
1200        if radius.bottom_left > 0.0 {
1201            let corner_border = self.blend_corner_style(&border.bottom, &border.left);
1202            let mut paint = crate::Paint::stroke(corner_border.color, corner_border.width);
1203            paint.set_dash_style(corner_border.dash_style);
1204
1205            self.draw_dashed_arc(
1206                Point::new(
1207                    rect.x + radius.bottom_left as i32,
1208                    rect.y + rect.height as i32 - radius.bottom_left as i32,
1209                ),
1210                radius.bottom_left,
1211                90.0,
1212                180.0,
1213                &paint,
1214            );
1215        }
1216    }
1217
1218    /// 绘制无圆角的自定义边框矩形
1219    fn draw_custom_border_rect_no_radius(&mut self, rect: Rect, border: &crate::border::Border) {
1220        // 上边
1221        if border.top.width > 0.0 {
1222            let mut paint = crate::Paint::stroke(border.top.color, border.top.width);
1223            paint.set_dash_style(border.top.dash_style.clone());
1224            self.draw_dashed_line(
1225                Point::new(rect.x, rect.y),
1226                Point::new(rect.x + rect.width as i32, rect.y),
1227                &paint,
1228            );
1229        }
1230
1231        // 右边
1232        if border.right.width > 0.0 {
1233            let mut paint = crate::Paint::stroke(border.right.color, border.right.width);
1234            paint.set_dash_style(border.right.dash_style.clone());
1235            self.draw_dashed_line(
1236                Point::new(rect.x + rect.width as i32, rect.y),
1237                Point::new(rect.x + rect.width as i32, rect.y + rect.height as i32),
1238                &paint,
1239            );
1240        }
1241
1242        // 下边
1243        if border.bottom.width > 0.0 {
1244            let mut paint = crate::Paint::stroke(border.bottom.color, border.bottom.width);
1245            paint.set_dash_style(border.bottom.dash_style.clone());
1246            self.draw_dashed_line(
1247                Point::new(rect.x + rect.width as i32, rect.y + rect.height as i32),
1248                Point::new(rect.x, rect.y + rect.height as i32),
1249                &paint,
1250            );
1251        }
1252
1253        // 左边
1254        if border.left.width > 0.0 {
1255            let mut paint = crate::Paint::stroke(border.left.color, border.left.width);
1256            paint.set_dash_style(border.left.dash_style.clone());
1257            self.draw_dashed_line(
1258                Point::new(rect.x, rect.y + rect.height as i32),
1259                Point::new(rect.x, rect.y),
1260                &paint,
1261            );
1262        }
1263    }
1264
1265    /// 混合两条边的样式用于圆角(取平均值)
1266    fn blend_corner_style(
1267        &self,
1268        side1: &crate::border::BorderSide,
1269        side2: &crate::border::BorderSide,
1270    ) -> crate::border::BorderSide {
1271        // 如果其中一条边宽度为0,使用另一条
1272        if side1.width == 0.0 {
1273            return side2.clone();
1274        }
1275        if side2.width == 0.0 {
1276            return side1.clone();
1277        }
1278
1279        // 混合颜色(简单平均)
1280        let color = crate::Color::rgba(
1281            ((side1.color.r as u16 + side2.color.r as u16) / 2) as u8,
1282            ((side1.color.g as u16 + side2.color.g as u16) / 2) as u8,
1283            ((side1.color.b as u16 + side2.color.b as u16) / 2) as u8,
1284            ((side1.color.a as u16 + side2.color.a as u16) / 2) as u8,
1285        );
1286
1287        // 混合线宽(取平均)
1288        let width = (side1.width + side2.width) / 2.0;
1289
1290        // 虚线样式:优先使用第一条边的样式
1291        let dash_style = side1.dash_style.clone();
1292
1293        crate::border::BorderSide::new(color, width, dash_style)
1294    }
1295}