# Image Editor **English**: Annotate and crop images in place. Right-click any image in your vault to open the built-in editor — draw, add text or mosaic, crop — then save to replace the original instantly. ## Features (English) - Right-click any embedded image (reading mode / live preview) to open the built-in editor - Annotation tools: pen, line, arrow, rectangle, ellipse, text, mosaic — with undo / redo and keyboard shortcuts - Crop with rule-of-thirds guides; apply or cancel at any time - Save to replace the original image, or export as a new PNG file - Non-PNG images (JPG / WebP / BMP / GIF) are auto-converted to PNG and all vault links are updated automatically 在 Obsidian 文档里**右键图片 → 编辑图片**,直接打开内置图片编辑器做标注和裁剪,点「完成」后原图被替换、文档里的图片立即刷新。 ## 功能 | 能力 | 说明 | | --- | --- | | 右键唤起 | 在阅读模式 / 实时预览里右键任意内嵌图片,菜单出现「编辑图片」 | | 多开 | 每张图一个独立标签页,可同时开多个编辑器;同一张图重复右键会聚焦已开的那一个 | | 标注 | 画笔、直线、箭头、矩形、椭圆、文本、马赛克(矩形 / 椭圆支持半透明填充) | | 裁剪 | 拖出选区,8 个手柄微调,支持三分参考线,可撤销 | | 视图 | 滚轮缩放(以光标为中心)、空格或抓手拖拽平移、适应窗口 / 1:1 | | 历史 | 撤销 / 重做,最多 40 步;裁剪也进历史栈 | | 保存 | 覆盖原图,或另存为新 PNG 不动原图 | ## 安装 把这三个文件放进 `<你的库>/.obsidian/plugins/image-editor-xhz/`: ``` main.js manifest.json styles.css ``` 然后在 Obsidian「设置 → 第三方插件」里刷新并启用 **Image Editor (标注 / 裁剪)**。 也可以直接: ```bash npm install npm run build # 类型检查 + 压缩打包,产出 main.js ``` 开发时用 `npm run dev` 进入 esbuild 监听模式。 ## 使用 ### 打开编辑器 1. 在文档中的图片上右键 → **编辑图片** 2. 命令面板:`编辑光标处的图片`(光标放在那一行即可) 3. 命令面板:`打开图片进行编辑…`(模糊搜索全库图片) 4. 文件管理器里右键图片文件 → **编辑图片** ### 快捷键 | 按键 | 作用 | | --- | --- | | `P` `L` `A` `R` `O` `T` `M` `C` `H` | 画笔 / 直线 / 箭头 / 矩形 / 椭圆 / 文本 / 马赛克 / 裁剪 / 抓手 | | `Ctrl/⌘ + Z` | 撤销 | | `Ctrl/⌘ + Shift + Z`、`Ctrl/⌘ + Y` | 重做 | | `Ctrl/⌘ + S` | 保存并替换原图 | | `Enter` | 裁剪模式下应用裁剪 | | `Esc` | 取消文本输入 / 退出裁剪 | | 滚轮 | 以光标为中心缩放 | | `Shift + 滚轮` | 水平平移 | | 空格 + 拖拽、中键拖拽 | 平移视图 | 文本工具:点一下图片,出现输入框,`Ctrl + Enter` 确认,`Esc` 取消。 ### 保存行为 - **原图是 PNG**:直接覆盖原文件,文档里的图片会立刻刷新。 - **原图是 JPG / WebP / BMP**:PNG 是有损格式之外的新格式,插件会另存为同名 `.png`, 并**自动把全库 md 里指向原图的链接改到新文件**(wikilink 和 `![]()` 都支持, 含 `|300`、`#center` 参数以及带空格路径)。是否删除原图可在设置里选,默认不动。 - **另存为**:生成 `原名-edited.png`,原图保持不变。 - 关闭标签页时如果有未保存的修改,会弹出提醒(标题栏也会带 `*` 标记)。 ### 设置 设置 → 第三方插件 → Image Editor: - 默认工具 / 颜色 / 线宽 / 文本字号 - 保存后自动关闭编辑器 - 转换格式后是否把原图移入回收站 - 阅读模式右键菜单兜底(阅读模式下 Obsidian 不一定广播右键事件,开启后会往弹出的菜单里补一个「编辑图片」) ## 实现要点 - **分层绘制**:`base`(底图)+ `composite`(底图叠所有形状)+ 屏幕 canvas。 所有形状存的是**原始图像像素坐标**,缩放、裁剪、导出都不失真。 马赛克需要读取已合成像素,所以必须在 composite 层做。 - **多开**:单个 view type + `workspace.getLeaf('tab')`,每个 leaf 一个 `ItemView` 实例, 内部按 `state.file` 区分图片;同一路径会被重定向到已开的标签页。 - **图片定位**:DOM 路径(阅读模式 `.internal-embed`、实时预览 `` 的 `app://` src) 加上源码路径(`editor.posAtMouse` + 行内 embed 正则)双保险。 - **即时刷新**:用 `vault.modifyBinary` 写入,Obsidian 会重新生成带 mtime 的图片地址, 文档里的渲染随之更新,不需要重启或手动刷新。 ## 项目结构 ``` src/ main.ts 插件入口:右键菜单、命令、设置 editor-view.ts 编辑器视图:工具栏、保存、链接迁移 canvas-engine.ts 绘制引擎:形状、裁剪、历史、导出 image-resolver.ts 从右键位置 / 光标解析出图片文件 image-loader.ts 二进制 → icons.ts 内联 SVG 图标(不依赖 lucide 版本) utils.ts / types.ts test/ 冒烟测试 + 逻辑测试(npm test) ``` `npm test` 会用 stub 顶替 obsidian,在 Node 里跑 29 项用例,覆盖链接替换正则、 路径清洗、几何计算以及引擎的绘制 / 撤销 / 裁剪 / 导出流程。