# eduwin 画布绘图教程

eduwin 的画布（Canvas）组件提供完整的 2D 绘图能力，基于 GDI+ 实现，支持线、矩形、椭圆、多边形、扇形、贝塞尔曲线、路径、文本、图像等绘制，还内置双缓冲离屏渲染，天然无闪烁。

---

## 1. 创建画布

```c
#include "eduwin.h"

HWND win = create_window(L"画布演示", 640, 480);
HWND canvas = create_canvas(win, 0, 0, 640, 480);
```

`create_canvas` 在窗口中创建一个画布控件，参数依次为父窗口、x、y、宽度、高度。

> **注意：所有绘图操作必须在 `show_window` 之后调用！**
> `show_window` 触发 `WM_SIZE` 消息，画布会重新创建离屏位图，之前绘制的内容会被清空。

---

## 2. 基本绘图流程

```c
show_window(win);

// 1. 清空画布背景
canvas_clear(canvas, 240, 240, 240, 255);  // 灰色不透明背景

// 2. 设置画笔（轮廓）
canvas_set_pen(canvas, 0, 0, 255, 255, 3);  // 蓝色 3px 不透明

// 3. 设置画刷（填充）
canvas_set_brush(canvas, 255, 200, 200, 255); // 粉色不透明

// 4. 绘图
canvas_draw_rect(canvas, 20, 20, 100, 80);    // 矩形边框
canvas_fill_ellipse(canvas, 140, 20, 100, 80); // 填充椭圆
canvas_draw_line(canvas, 20, 120, 300, 120);   // 直线
canvas_draw_text(canvas, L"Hello 画布", 20, 140, 0, 0, 0, 255, 20); // 文字
```

---

## 3. 绘图状态

```c
void canvas_clear(HWND canvas, int r, int g, int b, int a);
void canvas_set_pen(HWND canvas, int r, int g, int b, int a, int width);
void canvas_set_brush(HWND canvas, int r, int g, int b, int a);
void canvas_set_font(HWND canvas, const WCHAR *family, int size);
```

- `canvas_clear` 用指定颜色填充整个画布（清除原有内容），参数为 RGBA，范围 0–255
- `canvas_set_pen` 设置轮廓画笔的颜色、透明度和线宽（默认黑色 1px 不透明）
- `canvas_set_brush` 设置填充画刷的颜色和透明度（默认白色不透明）
- `canvas_set_font` 设置文本字体和字号（默认 Microsoft YaHei 14）

绘图状态是全局的——设置后影响后续所有绘制，直到再次修改。

```c
canvas_set_pen(canvas, 255, 0, 0, 255, 5);   // 红色 5px 画笔
canvas_draw_rect(canvas, 10, 10, 100, 100);  // 红色5px边框

canvas_set_pen(canvas, 0, 128, 0, 200, 1);   // 绿色半透明 1px 画笔
canvas_draw_rect(canvas, 130, 10, 100, 100); // 绿色1px边框
```

---

## 4. 基本几何图形

```c
void canvas_draw_line(HWND canvas, int x1, int y1, int x2, int y2);
void canvas_draw_rect(HWND canvas, int x, int y, int w, int h);
void canvas_fill_rect(HWND canvas, int x, int y, int w, int h);
void canvas_draw_ellipse(HWND canvas, int x, int y, int w, int h);
void canvas_fill_ellipse(HWND canvas, int x, int y, int w, int h);
void canvas_fill_polygon(HWND canvas, const PointF *pts, int count);
void canvas_fill_pie(HWND canvas, int x, int y, int w, int h, float start_angle, float sweep_angle);
```

- `draw_line` / `draw_rect` / `draw_ellipse` 用当前画笔绘制轮廓
- `fill_rect` / `fill_ellipse` / `fill_polygon` / `fill_pie` 用当前画刷填充

填充多边形示例：

```c
/* 绘制一个蓝色三角形 */
PointF pts[3] = {
    {200, 50},  /* 顶点 */
    {150, 150}, /* 左下 */
    {250, 150}  /* 右下 */
};
canvas_set_brush(canvas, 50, 100, 200, 200);  // 半透明蓝色
canvas_fill_polygon(canvas, pts, 3);
```

填充扇形示例：

```c
/* 绘制一个从 0° 到 90° 的扇形 */
canvas_set_brush(canvas, 200, 100, 50, 220);
canvas_fill_pie(canvas, 300, 50, 120, 120, 0, 90);
```

---

## 5. 弧形与贝塞尔曲线

```c
void canvas_draw_arc(HWND canvas, int x, int y, int w, int h, float start_angle, float sweep_angle);
void canvas_draw_bezier(HWND canvas, int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4);
```

- `draw_arc` 绘制椭圆弧线段，`start_angle` 为起始角度（度），`sweep_angle` 为扫过的角度（逆时针为正）
- `draw_bezier` 绘制三次贝塞尔曲线，4 个点依次为起点、控制点 1、控制点 2、终点

```c
/* 弧线：从 0° 到 180° */
canvas_set_pen(canvas, 200, 50, 50, 255, 3);
canvas_draw_arc(canvas, 50, 200, 100, 80, 0, 180);

/* 贝塞尔曲线 */
canvas_draw_bezier(canvas, 200, 200, 250, 100, 350, 300, 400, 200);
```

---

## 6. 路径系统

路径（Path）允许你将多条线段、弧线、椭圆、矩形组合成一个图形，然后统一绘制或填充。

```c
void *canvas_create_path(void);
void canvas_add_path_line(void *path, float x1, float y1, float x2, float y2);
void canvas_add_path_arc(void *path, float x, float y, float w, float h, float start_angle, float sweep_angle);
void canvas_add_path_ellipse(void *path, float x, float y, float w, float h);
void canvas_add_path_rect(void *path, float x, float y, float w, float h);
void canvas_close_path(void *path);
void canvas_draw_path(HWND canvas, void *path);
void canvas_fill_path(HWND canvas, void *path);
void canvas_delete_path(void *path);
```

使用模式：创建路径 → 添加图形 → 绘制/填充 → 销毁路径。

```c
/* 创建一个心形路径 */
void *path = canvas_create_path();
canvas_add_path_ellipse(path, 0, 0, 80, 80);    // 左圆
canvas_add_path_ellipse(path, 60, 0, 80, 80);   // 右圆
canvas_add_path_line(path, 0, 50, 70, 140);      // 左侧边
canvas_add_path_line(path, 70, 140, 140, 50);     // 右侧边
canvas_close_path(path);

canvas_set_brush(canvas, 220, 60, 80, 255);
canvas_fill_path(canvas, path);

canvas_set_pen(canvas, 180, 30, 50, 255, 2);
canvas_draw_path(canvas, path);

canvas_delete_path(path);
```

---

## 7. 绘制文本

```c
void canvas_set_font(HWND canvas, const WCHAR *family, int size);
void canvas_draw_text(HWND canvas, const WCHAR *text, int x, int y, int r, int g, int b, int a, int size);
```

- `canvas_set_font` 设置全局字体和字号（`size` 为 0 时不影响后续单次绘制）
- `canvas_draw_text` 的 `r g b a` 为文字颜色和透明度，`size` 传 0 使用 `canvas_set_font` 设定的字号

```c
/* 设置全局字体 */
canvas_set_font(canvas, L"SimSun", 24);     // 宋体 24 号
canvas_draw_text(canvas, L"你好，eduwin", 50, 300, 50, 50, 50, 255, 0);  // 用全局设置

/* 单次绘制指定字号 */
canvas_draw_text(canvas, L"大标题", 50, 340, 200, 50, 50, 255, 36);
canvas_draw_text(canvas, L"小标注", 50, 390, 128, 128, 128, 255, 12);
```

---

## 8. 绘制图像

```c
void *load_image_from_file(const WCHAR *filepath, UINT *width, UINT *height);
void canvas_draw_image(HWND canvas, void *image, int x, int y, int w, int h);
```

```c
UINT iw, ih;
void *img = load_image_from_file(L"photo.png", &iw, &ih);
if (img)
{
    canvas_draw_image(canvas, img, 10, 10, (int)iw, (int)ih);
}
```

---

## 9. 局部清除与文件输出

```c
void canvas_clear_rect(HWND canvas, int x, int y, int w, int h, int r, int g, int b, int a);
void canvas_save_image(HWND canvas, const WCHAR *filepath);
```

`canvas_clear_rect` 用颜色填充指定矩形区域（局部清除），`a` 为透明度。`canvas_save_image` 将画布当前内容保存为图像文件（根据扩展名自动选择编码器，支持 png/jpg/bmp）。

```c
/* 在灰色区域中挖一个矩形 */
canvas_set_brush(canvas, 180, 180, 180, 255);
canvas_fill_rect(canvas, 10, 10, 200, 100);

/* 局部清除并填充绿色 */
canvas_clear_rect(canvas, 50, 30, 100, 40, 100, 200, 50, 255);

/* 保存为文件 */
canvas_save_image(canvas, L"output.png");
```

---

## 10. 画布尺寸

```c
int canvas_get_width(HWND canvas);
int canvas_get_height(HWND canvas);
```

获取画布的实际像素尺寸，通常配合 `show_window` 之后使用：

```c
int cw = canvas_get_width(canvas);
int ch = canvas_get_height(canvas);
canvas_draw_text(canvas, L"居中文字", cw / 2 - 60, ch / 2, 0, 0, 0, 255, 20);
```

---

## 完整示例

```c
#include "eduwin.h"

int main(void)
{
    init_app();

    HWND win = create_window(L"画布绘图教程", 400, 400);
    HWND canvas = create_canvas(win, 0, 0, 400, 400);

    show_window(win);

    /* 白色背景 */
    canvas_clear(canvas, 255, 255, 255, 255);

    /* 红色矩形边框 */
    canvas_set_pen(canvas, 220, 50, 50, 255, 3);
    canvas_draw_rect(canvas, 20, 20, 160, 100);

    /* 蓝色填充椭圆 */
    canvas_set_brush(canvas, 60, 120, 200, 200);
    canvas_fill_ellipse(canvas, 220, 20, 160, 100);

    /* 绿色直线 */
    canvas_set_pen(canvas, 60, 160, 60, 255, 2);
    canvas_draw_line(canvas, 20, 180, 380, 180);

    /* 半透明填充三角形 */
    canvas_set_brush(canvas, 200, 160, 60, 180);
    PointF pts[3] = {{200, 220}, {100, 350}, {300, 350}};
    canvas_fill_polygon(canvas, pts, 3);

    /* 灰色文字 */
    canvas_draw_text(canvas, L"eduwin 画布", 140, 370, 80, 80, 80, 255, 16);

    run_app();
    return 0;
}
```

编译命令：

```bat
cl canvas_demo.c /Feoutput.exe /I include /link eduwin.lib lib\*.lib
```
