🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

像素比对 dingchenhui0618-arch/dsh-vision-diff

DeepSeek Harness
dingchenhui0618-arch24 天前有提交已提供中文文档扫描:含敏感能力

比对两张截图,输出差异结论与对照页

29.5/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/15 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add dingchenhui0618-arch/dsh-vision-diff
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:待复验
是什么
dsh 原生插件 · vision
装得上吗
曾在 dsh 0.2.0-rc.2 下真实安装成功,但当前 dsh 已更新至 0.2.1-rc.5,本站尚未在新版下复验
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 24 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

读写/删除本地文件发起外部网络请求
查看扫描证据(共 17 处,展示前 14 条)
  • 读取本地文件
    lib/index.js:111
    const parsed = JSON.parse(readFileSync(statePath, 'utf8') || '{}')
  • 读取本地文件
    lib/index.js:132
    if (!existsSync(dataDir)) mkdirSync(dataDir, { recursive: true })
  • 写入本地文件
    lib/index.js:132
    if (!existsSync(dataDir)) mkdirSync(dataDir, { recursive: true })
  • 写入本地文件
    lib/index.js:133
    writeFileSync(statePath, JSON.stringify({ history: history, latest: latest }, null, 2))
  • 读取本地文件
    lib/index.js:146
    } while (existsSync(join(runsDir, id)))
  • 读取本地文件
    lib/index.js:173
    info = statSync(path)
  • 读取本地文件
    lib/index.js:180
    return new Uint8Array(readFileSync(path))
  • 写入本地文件
    lib/index.js:210
    mkdirSync(dir, { recursive: true })
  • 写入本地文件
    lib/index.js:212
    if (item.bytes !== undefined) writeFileSync(join(dir, item.name), Buffer.from(item.bytes))
  • 写入本地文件
    lib/index.js:213
    else writeFileSync(join(dir, item.name), item.text, 'utf8')
  • 删除本地文件递归
    lib/index.js:316
    rmSync(dropped.dir, { recursive: true, force: true })
  • 读取本地文件
    lib/index.js:464
    if (file === undefined || !existsSync(file)) {
  • 发起网络请求
    lib/client.js:40
    fetch(API, { headers: { accept: 'application/json' } })
  • 发起网络请求
    lib/client.js:149
    fetch(API + '/clear', { method: 'POST', headers: { 'content-type': 'application/json' }, body: '{}' })
扫描于 2026/11/4(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

DeepSeek Harness 的像素级截图比对:输入两张本地 PNG,输出 PIXEL_CHANGED 判定、差异区域和一份自包含的 HTML 对比页。零依赖,全本地。

README

由 DeepSeek 最新模型翻译生成
dsh-vision-diff 两张截图进去,出来一句机器可读的结论和一张能给人看的对照页:同一屏两次渲染到底变没变、变在哪。 Pixel-level screenshot diff for DeepSeek Harness。输入两张本地 PNG;输出 PIXEL_CHANGED=true|false 结论、差异区域,以及一份自包含的 HTML 对照页。全部在本地跑——不调模型、不联网、不上传。 它解决什么 截图类插件已经会「看懂内容」:识图、OCR、元素定位、多模态问答。但视觉回归最刚需的那一步没人做——回答「这两张图一样吗」,而且要能用脚本判断,不是让人再看一眼。 所以这个插件的输出以一行字符串开头: PIXEL_CHANGED=false 一致就是 false,不一致就是 true。grep 一下就能当断言用,后面才是差异比例、差异区域、证据数字和对照页。 它不做内容识别。 它不做「这个按钮是什么」这种判断。它只回答变化,因为那一步可以做成确定性的,而「看懂」那一步不行。
展开完整文档(README 剩余 1 节)
dsh-vision-diff

两张截图进去,出来一句机器可读的结论和一张能给人看的对照页:同一屏两次渲染到底变没变、变在哪。

Pixel-level screenshot diff for DeepSeek Harness。输入两张本地 PNG;输出 PIXEL_CHANGED=true|false 结论、差异区域,以及一份自包含的 HTML 对照页。全部在本地跑——不调模型、不联网、不上传。

它解决什么

截图类插件已经会「看懂内容」:识图、OCR、元素定位、多模态问答。但视觉回归最刚需的那一步没人做——回答「这两张图一样吗」,而且要能用脚本判断,不是让人再看一眼。

所以这个插件的输出以一行字符串开头:

PIXEL_CHANGED=false

一致就是 false,不一致就是 true。grep 一下就能当断言用,后面才是差异比例、差异区域、证据数字和对照页。

它不做内容识别。 它不做「这个按钮是什么」这种判断。它只回答变化,因为那一步可以做成确定性的,而「看懂」那一步不行。

装

npm 版 CLI 管理的 profile
dsh plugin --profile <name> add <插件目录>

桌面版:desktop profile 由 Electron app 独占,npm 版 CLI 会被拒绝—— error: profile "desktop" is managed exclusively by the Electron application 用它自带的那个 CLI 才行(在 app 的 resources/runtime/cli/bin/dsh 下): "<app>/resources/runtime/cli/bin/dsh" plugin --profile desktop add <插件目录>

装完重启一次 app(host 半区的改动必须重启进程才会加载;Node 按 URL 缓存 ES 模块,关开插件换不掉已经加载的代码)。重启后对话视图里会出现「视觉差异」Tab,agent 也多了一个 vision_diff 工具。

用

让 agent 调

vision_diff(before: "shots/home-dark.png", after: "shots/home-light.png")

命令行直接看产物

每次比对会在 $DSH_HOME/vision-diff/runs/<id>/ 留一份完整证据,双击 index.html 就能看,不需要服务器。

参数

| 参数 | 必填 | 说明 |
| before | ✅ | 第一张 PNG 的路径(绝对路径,或相对 cwd) |
| after | ✅ | 第二张 PNG 的路径 |
| ignore | | 忽略区,见下 |
| threshold | | 通道差必须大于它才算变化。默认 0。截图有压缩噪声时用 2~8 |
| blockSize | | 判断两个差异像素是否相连的粒度,默认 16。只影响区域如何分块,不影响区域边界 |
| regionLimit | | 最多返回几个差异区域,默认 20,按差异像素数从大到小取 |
| cwd | | 解析相对路径用的目录。不填则用插件配置的工作目录 |
| label | | 这次比对的说明,会写进报告和对照页 |

忽略区

每次都会变的部分——时钟、光标、随机广告、动画帧——用忽略区排除掉,否则日报式的比对会天天报「有变化」。

以下写法都接受:

{ "x": 0, "y": 0, "w": 100, "h": 40 }
{ "x1": 0, "y1": 0, "x2": 100, "y2": 40 }
{ "left": 0, "top": 0, "right": 100, "bottom": 40 }
[0, 0, 100, 40]
{ "regions": [ { "x": 0, "y": 0, "w": 100, "h": 40 } ] }
{ "x": 0, "y": 0, "w": 0.1, "h": 0.05, "unit": "fraction" }

unit: "fraction" 时按图片宽高的比例解释,所以同一份配置能跨分辨率复用。

宽度或高度取负值表示反方向(人拖框拖反了就是这么写的)。超出图像的部分会被裁剪而不是报错。

解析不了的忽略区不会被静默忽略——它进 ignoreRejected,并在结论、对照页和 Tab 上都标出来,因为一个失效的忽略区会让差异数字虚高,看起来像被测页面出了问题。

输出

{
"pixelChanged": true,
"verdict": "PIXEL_CHANGED=true",
"width": 1920, "height": 1080,
"afterWidth": 1920, "afterHeight": 1080,
"dimensionChanged": false,
"totalPixels": 2073600,
"comparedPixels": 2073600,
"ignoredPixels": 0,
"diffPixels": 1483,
"diffPercent": 0.071527,
"maxChannelDelta": 255,
"meanAbsError": 0.4123,
"boundingBox": { "x": 240, "y": 96, "w": 120, "h": 18 },
"regions": [ { "x": 240, "y": 96, "w": 120, "h": 18, "pixels": 1483, "blocks": 9 } ],
"regionsTruncated": false,
"threshold": 0,
"blockSize": 16,
"ignore": [],
"ignoreRejected": []
}

几个刻意的取舍:

- diffPercent 保留 6 位小数。 1920×1080 里一个像素是 0.0000482%,四舍五入到两位就成了 0.00,紧挨着 diffPixels: 1 读起来像「没变化」。
- 比对范围是 before 的完整面积。 尺寸不一样时,没有对应像素的部分计为已变化,同时 dimensionChanged 置真。反过来——只比重叠区——会让「侧边栏没了」这种渲染事故报出 PIXEL_CHANGED=false。
- regions 的边界是精确像素包围盒。 网格只用来判断连通性(一个视觉变化算一个区域),不用来决定矩形——否则一个像素的变化会被描述成 16×16 的「区域」。
- meanAbsError 是每通道平均绝对误差。 四个通道都计入。用「每像素最大通道差」去平均会让单通道的变化显得大四倍。

支持的图片

刻意划定的范围,而不是碰巧能跑:非交错的 PNG,颜色类型 0/2/3/4/6(灰度、RGB、调色板、灰度+alpha、RGBA),位深 8 或 16(16 位取高字节)。

不支持的会明确报出来,不会近似解码:

- Adam7 交错 → 报错并提示另存为非交错
- 位深 1/2/4(每字节多像素)→ 报错并提示另存为 8 位
- 非 PNG 文件 → 报错说明文件头不匹配
- CRC 校验失败 → 报错说明文件已损坏

这一条比看上去重要:这个插件的全部价值就是它的数字可信,所以一个把不支持的布局猜着解出来、给出一个看似合理但错误的像素数的解码器,比一个直接拒绝的解码器糟得多。

隐私与成本

全部本地。 不调用模型、不联网、不上传图片。截图里可能是别人的私有页面、客户后台、未发布的产品——这也是它做成插件而不是服务的理由。

零依赖。 host 半区只 import node: 内置模块和同目录兄弟模块。PNG 编解码是自己写的(src/png.js),因为它必须存在,而引一个解码器库就破坏了这条铁律。

数据落在哪

| 路径 | 内容 |
| $DSH_HOME/vision-diff/runs/<id>/index.html | 自包含对照页,可归档、可转发 |
| $DSH_HOME/vision-diff/runs/<id>/report.json | 原始结论 |
| $DSH_HOME/vision-diff/runs/<id>/diff.png | 差异图:红色=变化,蓝色=已忽略 |
| $DSH_HOME/vision-diff/runs/<id>/before.png、after.png | 输入副本(keepInputs: false 可不留) |
| $DSH_HOME/vision-diff/state.json | 历史索引与最近一次结论 |

HTTP 面(挂在 webServer 的 /dsh-vision-diff 前缀下):

GET /dsh-vision-diff 统计、最近一次、历史、配置 GET /dsh-vision-diff/view/<id> 自包含对照页 GET /dsh-vision-diff/asset/<id>/<file> 原始 PNG POST /dsh-vision-diff/clear 清空历史索引

容错姿态

这个插件任何一处坏掉都不该拖垮 harness,所以:

- 读文件优先走 ctx.fs,让读取经过 harness 自己的文件系统抽象、遵守它的策略。只有宿主根本没有 fs 服务时才退回 node:fs——出错不会静默退回,因为那等于绕过一个安全边界。
- 像素上限取 ctx.attachments.imageLimits.maxImagePixels(宿主给的话)与配置的较小值。超限的图在解码前就被拒绝,不是解完再发现占了 4GB。
- webServer.register 失败只是没有对照页和 Tab,vision_diff 工具照常工作——一个变了形状的 web 契约不该让用户连比对都做不了。
- 落盘是尽力而为:state.json 写不进去不影响这次比对的结果。
- 历史滚动:超出 historyKeep(默认 30)的旧记录,连同它的产物目录一起清掉,不会无声堆积。
- 每次注册都可撤销(ctx.effect),因为 dsh 能在运行期卸载插件。

配置

apply(ctx, config) 的 config 全部可覆盖:

| key | 默认 | 说明 |
| dataDir | $DSH_HOME/vision-diff | 产物与索引落在哪 |
| baseDir | process.cwd() | 解析相对路径的基准目录 |
| maxBytes | 64 MB | 单个输入文件上限 |
| maxPixels | 4000 万(取与宿主图像策略的较小值) | 单张图上限 |
| threshold / blockSize / regionLimit | 0 / 16 / 20 | 这三个的默认值,可被单次调用覆盖 |
| historyKeep | 30 | 保留多少次记录 |
| keepInputs | true | 是否在产物目录里留下输入副本(对照页永远内含两边,不受此项影响) |

开发

node --test # 60 个测试
node scripts/build.mjs

测试用的 PNG 是手工构造的,不是编码器自己产出的。 encodePng 只写 filter 0,所以「编码再解码」这种往返测试永远测不到 filter 1–4。测试里有一份独立的 PNG 构造器(自己的分块、自己的 CRC32、自己的正向 filter),解码器的所有滤镜都是对着这份独立实现验证的。

test/host.test.mjs 用桩 Context 驱动真实的 apply():真的把文件写进临时目录、真的走工具执行路径、真的调 HTTP handler,不是这些逻辑的复刻。

和现有实现的关系

没有参考任何现有实现的代码。 这条设想的证据来源是 ankye/dsh-client-vision——它做的是内容识别(识图、多模态问答),回答的是「这屏是什么」;本插件回答的是「这两屏一样吗」。两者不重叠,我也没有去看它的实现。

- PNG 编解码是按 PNG 规范手写的(node:zlib 提供 DEFLATE,其余是分块解析、五种行过滤器、CRC32)。
- 差异算法是自己写的逐像素比较 + 连通块聚类,没有用 pixelmatch 之类的库——引依赖会破坏零依赖构建。
- 工程骨架(零依赖构建、host/client 双半区、cordis.patch.yml、README、测试)沿用 dsh-warden 的既有结构,那是同一个作者自己的脚手架。

本插件是独立仓库,不是任何仓库的 fork。

License

MIT
预览分享卡片长什么样 ↓dingchenhui0618-arch/dsh-vision-diff
分享 · DeepSeek Harness Hub
dingchenhui0618-arch/dsh-vision-diff

比对两张截图,输出差异结论与对照页

这是你的仓库?认领条目

回到顶部