代码截图一键出 PNG 实测:3 种窗口风格,长行超 95 字符会被裁

1 阅读8分钟

粘贴一段代码,点一下导出,就得到一张带窗口边框、圆角和渐变背景的 PNG。

默认 15 像素字号下,导出的图固定 3000 像素宽,19 行代码跑出来是 3000 × 2154。

它有两个硬边界:一行超过 95 个半角字符会被窗口右边裁掉,代码超过 830 行只剩一句「导出失败,请重试」。

图 1:默认配置的首屏,左侧粘贴代码,右侧实时渲染出 macOS 圆点窗口、海洋渐变底和 One Dark 配色,底部标着「预览 976 × 675 | 导出 3000 × 2154 px」

在线案例与源码:atomgit.com/deli007/dem… 成品是一个 43731 字符、1168 行的单文件 index.html,双击就能打开,加载过程零外部请求。

一、为什么值得自己做一个:代码不出本机

在线的代码截图工具很好用,代价是代码要贴到别人的服务器上。

内网仓库地址、没发布的接口路径、写死的测试账号,都不适合往外传。

本地单文件没有这个问题。双击打开,代码只在自己浏览器里转,拔了网线也能用。

另一个原因是重复劳动。

每次写文章、发群、做 PPT,都得重新调一遍字体、背景和边距,调完下次又忘了。

我想要的其实就是一个能记住配置、点一下就出图的页面,顺手还能把每次的参数存下来。

二、准备环境:进入码道 Web,把需求写成 9 条约束

浏览器打开码道 Web 版:devcloud.cn-north-4.huaweicloud.com/chat/home,登…

码道有三种使用方式:WebUI(浏览器对话)、TUI(终端命令行)和桌面 IDE(IDE 插件)。本文用 WebUI 版演示。

需求我列了 9 条,写得很死:

  • 左边粘贴代码,右边实时预览,改一个字预览跟着变
  • 3 种窗口风格:macOS 圆点、Windows 方块、无边框
  • 渐变背景至少 10 套,代码配色至少 4 套,两两自由组合
  • 行号开关、字号 12 到 24 像素、内边距 16 到 96 像素
  • 语言标签跟着文件名走,切语言时自动换默认文件名
  • 一键导出 PNG
  • 单文件 index.html,不许引 CDN、外链字体和外部图片

最后一条是底线。只要挂了一个外链,「断网也能用」就是空话。

生成过程中它反问了我 3 个决定:预览和导出的渲染方案选 Canvas 手绘还是 DOM 加 SVG、要不要内置轻量语法高亮、代码区配色给几套。

这几个问题问得都在点上,我按推荐项答了 Canvas 手绘、内置高亮、深浅多主题。

三、成品长什么样:3 种窗口、10 套渐变、4 套配色

页面顶部是导出按钮,左边一列控制面板,右边一块画布。

窗口风格换的是标题栏:macOS 是左边三颗彩色圆点,Windows 是右边三个方块按钮,关闭键红底白叉。

无边框模式去掉标题栏,改成顶部居中一颗胶囊标签,顺手多留 40 像素上边距。

图 2:Windows 方块风格配亮白配色和霞光渐变,标题栏右侧三个窗口按钮,关闭键红底白叉

渐变背景 10 套,从海洋、紫罗兰到落日、石墨,都是两三个色标拉出来的线性渐变。

代码配色 4 套。One Dark 和午夜黑是深色,亮白和纸白是浅色,浅色主题下代码区、行号栏、分隔线会一起换。

图 2 就是浅色配深渐变的反差组合,截图发出去比纯深色更跳。

图 3:无边框模式,语言标签变成顶部居中的胶囊,Python 代码的关键字、字符串、数字各有颜色

语言支持 14 种:JavaScript、TypeScript、Python、Java、C、C++、Go、Rust、HTML、CSS、JSON、SQL、Shell 和纯文本。

高亮是一套轻量 tokenizer。它按语言逐个扫注释、字符串、数字、关键字和函数名,遇到没闭合的引号或块注释会记住状态,跨行接着算。

细节三个滑杆里,我平时用得最多的是内边距。

内边距调到 72 像素、字号 20 像素、关掉行号,就是下面这张的效果,适合截一段短代码当配图。

图 4:纸白配色配石墨渐变,字号 20 像素、内边距 72 像素、行号关闭,同一段 SQL 看起来更宽松

四、验证与踩坑:四个边界都是一条条量出来的

先说最坑的一个。

第一版生成完,它自己跑了一轮 Playwright 像素采样,报告写得挺漂亮:三色圆点、渐变起止点、标题栏和行号栏的颜色全部与主题定义值吻合。

我把页面打开一看,窗口是画出来了,代码一个字都没有。

后来我在页面上套了一层代理,把 canvas 2D 上下文的每次调用打出来,问题立刻现形:所有填充文字调用的 y 坐标都是 NaN。

根因在布局函数。它算好了代码区的起始高度 codeTop,却没把这个字段放进返回值。

调用方拿到的 L.codeTop 是 undefined,加出来就是 NaN,整段文字全画到画布外面了。

补上这一个字段,代码、行号、注释立刻都出来,我数了代码区的前景色像素是 349 个。

这件事的教训是:颜色对不代表画对了。像素采样能证明颜色值正确,证明不了有东西被画出来。

第二个边界是行宽。

15 像素字号下一个半角字符宽 8.247 像素,窗口宽度上限 904 像素,减去两侧各 40 像素内边距和 39 像素行号栏,能放代码的宽度是 785 像素。

折算下来一行最多约 95 个半角字符,多出来的部分被窗口圆角的裁切区直接切掉,既不换行也不横向滚动。

我拿一行 479 字符的压缩配置试了一次,后半截整段消失,左侧文本框里还能横向拖到全文,右侧预览已经没有了。

图 5:一行 479 字符的压缩配置,窗口右边把代码尾部整段裁掉,下面标注的导出宽度仍然是 3000 像素

第三个边界是导出的尺寸上限。

导出走的是 3 倍分辨率离屏重绘,宽度固定 3000 像素,高度跟着行数走。

我在同一份代码上试了 13 组行数,7 组成功,6 组直接弹「导出失败,请重试」。

代码行数导出尺寸结果
19 行3000 × 2154成功,PNG 3.0 MB
200 行3000 × 16272成功
450 行3000 × 35772成功
600 行3000 × 47472成功
830 行3000 × 65412成功
840 行3000 × 66192导出失败,请重试
1100 行3000 × 86472导出失败,请重试

分界线卡在 65535 像素。830 行的导出高度 65412 还在线内,840 行的 66192 就超了,画布建不出来,只能走「导出失败,请重试」这条回退分支。

所以这个工具适合截函数、类、配置片段,不适合整文件截图。

第四个边界是空输入和耗时。

清空文本框不会白屏,画布缩成一条 750 像素高的空白条,参数面板照样能点。

制表符会被当成 4 个空格展开,缩进代码在预览里不会跟左侧文本框错位。

连续重绘我量了四档,每档三次取中位数:20 行 1.4 毫秒,100 行 4.9 毫秒,300 行 13.4 毫秒,500 行 26.5 毫秒。

行数翻五倍,耗时大致也翻五倍,说明开销是线性的,瓶颈在逐 token 的填充文字,不在计算。

导出的文件我也拆开对过。19 行那张是 3000 × 2154,文件 3122448 字节,开头是 PNG 的固定魔数 89504e47。

五、本地复现:一条命令

单文件直接双击能开,想走本地服务就一行:

python -m http.server 8000
# 浏览器打开 http://127.0.0.1:8000/index.html

想复现第三个边界,把文本框换成 840 行任意代码,点导出,看到那句「导出失败,请重试」就对了。

六、用码道的体会:它能做完,最后一眼得自己看

这一轮从提需求到交付,任务耗时 23 分 22 秒,产出 42.7 KB 的单文件。

它主动问了 3 个实现决定,自己写了验证脚本,还把 3 张运行截图存进了工程目录。

它没做到的是最后一眼。像素采样的结论是颜色都对,可代码根本没画出来,这个错误它自己的脚本没覆盖到。

我的做法改成:生成完先自己打开、自己粘贴、自己点一遍导出,再拿去写文章。

七、小结与下一步

记住两个数字就够了:一行 95 个半角字符,导出 830 行封顶。

其余的配置随便调,窗口风格、渐变、配色、字号、内边距都是即时生效,预览什么样导出就是什么样。

下一步我想加的是长行自动换行开关,以及导出尺寸可选 1 倍或 2 倍,把 830 行这个上限抬高。

码道 Web 版入口:devcloud.cn-north-4.huaweicloud.com/chat/home

案例与源码:atomgit.com/deli007/dem…