Skip to content

AtomCode 图片附件与剪贴板系统分析

持续深度分析 — 图片附件协议、剪贴板集成、Markdown 渲染 2026-06-23


1. 图片附件系统

1.1 ImageInput 结构体

rust
struct ImageInput {  // 2 个字段
    media_type: String,  // 媒体类型 (如 "image/png", "image/jpeg")
    data: String,        // Base64 编码图片数据
}

1.2 图片附件协议

用户操作:
  ┌───────────────────────────────────┐
  │ Ctrl+V (粘贴剪贴板图片)            │
  │ /paste (粘贴文本 + 图片)           │
  │ 拖拽图片到 TUI 窗口 (Windows)      │
  │ 附件菜单 → 上传图片               │
  └───────────────┬───────────────────┘


  剪贴板读取 → 图片数据 (Base64)


  ImageInput {
      media_type: "image/png",
      data: "iVBORw0KGgo..."  (Base64)
  }


  POST /chat 或 POST /live/message
  {
      message: "...",
      images: [{ media_type, data }]
  }

1.3 ChatRequest 中的图片字段

rust
struct ChatRequest {  // 5 个字段
    session_id: String,
    message: String,
    images: Option<Vec<ImageInput>>,  // 可选图片
    provider: Option<String>,
    model: Option<String>,
}

1.4 LiveMessageReq 中的图片字段

rust
struct LiveMessageReq {  // 4 个字段
    session_id: String,
    message: String,
    images: Option<Vec<ImageInput>>,  // 可选图片
    provider: Option<String>,
    model: Option<String>,
}

2. 剪贴板系统

2.1 跨平台剪贴板

Linux/macOS: CLIPBOARD, PRIMARY, SECONDARY 选择区
  - 使用 X11 选择区协议
  - CLIPBOARD: 标准 Ctrl+C/Ctrl+V
  - PRIMARY: 鼠标选中自动复制
  
Windows: Ctrl+V 回退方案
  - "Attach an image from the clipboard (Windows fallback for Ctrl+V)"

2.2 支持的 MIME 类型

text/plain;charset=utf-8    — 纯文本
text/plain;charset=UTF-8    — UTF-8 文本
STRING                      — 兼容字符串
UTF8_STRING                 — UTF-8 字符串
image/png                   — PNG 图片
image/jpeg                  — JPEG 图片
text/html                   — HTML 格式文本

2.3 剪贴板安全检测

x-kde-passwordManagerHint    — KDE 密码管理器禁止读取剪贴板
incorrect type received from clipboard  — 类型不匹配

3. WebUI 中的附件菜单

从嵌入式 JS 提取的附件菜单字符串:

javascript
"attach.menu":         "Add",
"attach.image":        "Upload image",
"attach.file":         "Upload file",
"attach.skill":        "Choose skill",
"attach.imageSoon":    "Coming soon",
"attach.removeImage":  "Remove image",
"attach.tooLarge":     "Images must be under {mb}M; oversized images were skipped.",
"attach.dismissError": "Dismiss",
"attach.skillsEmpty":  "No skills yet. Add one at .atomcode/skills/<name>/SKILL.md...",
"attach.skillsLoading":"Loading"

3.1 附件限制

限制
最大图片大小{mb}M(可配置,默认约 5-10MB)
超限行为自动跳过超大图片,显示提示
支持格式PNG, JPEG

3.2 WebUI 附件组件

javascript
// 附件插入组件
Zr = {
    onInsert: tt,       // 文本插入回调
    onPickFile: () => D(!0),  // 文件选择
    onAddImages: rt,    // 图片添加
}

4. 图片大小限制与处理

上传统计:
  1. 用户粘贴/拖拽图片
  2. 检测图片大小 > 阈值 → 跳过
  3. 编码为 Base64
  4. 构造 ImageInput { media_type, data }
  5. 发送到 daemon

服务端:
  1. 接收 Base64 + media_type
  2. 转发给 LLM provider (OpenAI/Anthropic 原生支持图片)
  3. 流式返回文本响应

5. 剪贴板事件(TUI)

crossterm 事件:
  EnableBracketedPaste    — 启用括号粘贴模式
  DisableBracketedPaste   — 禁用括号粘贴模式
  EnableFocusChange       — 启用焦点事件
  DisableFocusChange      — 禁用焦点事件
  PopKeyboardEnhancementFlags  — 键盘增强标记弹出
  PushKeyboardEnhancementFlags — 键盘增强标记推入

6. WebUI 粘贴流程

从嵌入式 JS 提取的粘贴处理:

javascript
// textarea 上的 onPaste 处理
<textarea
    class="message-input"
    rows={2}
    placeholder={s("chat.inputPlaceholder")}
    value={u}
    onInput={Qe}
    onKeyDown={He}
    onPaste={at}          // 粘贴事件处理
/>

onPaste 处理器 (at) 负责:

  1. 读取剪贴板文本
  2. 读取剪贴板图片(如存在)
  3. 将文本插入 textarea
  4. 将图片添加到待发送队列
  5. 调用 onAddImages 显示预览

7. 附件大小限制配置

rust
// 超限错误消息
"Images must be under {mb}M; oversized images were skipped."

8. 新覆盖的盲区

#之前未覆盖的领域状态发现
1ImageInput 结构体2 字段:media_type + base64 data
2剪贴板系统X11 CLIPBOARD/PRIMARY + Windows 回退
3附件菜单 UI上传/图片/Skill 三个入口
4图片大小限制可配置 MB 阈值 + 超限跳过
5TUI 粘贴事件crossterm bracketed paste 事件
6MIME 类型支持文本/图片/HTML 剪贴板格式

逆向命令索引

bash
# 提取图片相关结构体
strings atomcode.bin.bak | grep -E "struct ImagePart|struct ImageInput|ContentBlock::Image" | sort -u
# 输出: struct ImagePart with 2 elements struct ImageInput with 2 elements struct variant ContentBlock::Image with 2 elements

# 提取支持的图片 MIME 类型
strings atomcode.bin.bak | grep -E "image/png|image/jpeg|image/webp|image/gif" | sort -u | head -5

# 提取剪贴板相关
strings atomcode.bin.bak | grep -iE "clipboard|CLIPBOARD|PRIMARY" | sort -u | head -5

本报告由持续分析循环生成

基于 VitePress 构建 · AtomCode v4.25.3 逆向工程分析文档