最近在整理一个内部工具集时,遇到了一个有点烦的需求:需要频繁把设计稿从 WebP 转成 PNG 给后端用,或者把截图从 PNG 转成 JPG 发到群里。每次都要打开某个在线转换网站,上传、等待、下载,有时候还得忍受广告和上传速度的折磨。
作为一个"能用代码解决就不想手动操作"的人,我决定自己写一个图片格式转换工具。而且我有个硬性要求:绝对不上传图片。毕竟有些截图涉及内部系统信息,传给别人服务器总觉得不太踏实。
为什么不用现成的转换库?
市面上的在线转换工具不少,但普遍有几个痛点:
- 必须上传:图片传到别人服务器,隐私没保障
- 有文件大小限制:很多网站限制 10MB 以内
- 广告太多:用起来心烦
- 格式支持不全:有的只支持转 JPG,不支持 WebP
我需要的方案是:纯本地处理、支持三种主流格式互转、还能控制输出质量和尺寸。正好 Canvas API 就能搞定这些,完全不依赖后端。
技术方案:Canvas + toBlob
核心思路其实很简单:把图片绘制到 Canvas 上,然后用 canvas.toBlob() 导出目标格式。
javascript
ctx.drawImage(img, 0, 0, w, h);
canvas.toBlob(callback, 'image/webp', 0.9);
就这么几行代码,就完成了格式转换的核心逻辑。但实际开发中还是踩了不少坑,下面一个个说。
踩坑记录
1. 透明背景转 JPEG 会变成黑色
这是最容易踩的坑。PNG 和 WebP 都支持透明通道,但 JPEG 不支持。直接转换的话,透明区域会变成黑色,非常难看。
解决方案是在绘制前先填充白色背景:
javascript
if (fmt === 'image/jpeg') {
ctx.fillStyle = '#ffffff';
ctx.fillRect(0, 0, w, h);
}
2. 质量参数对 PNG 无效
toBlob() 的第三个参数质量只对有损格式(JPEG、WebP)生效,PNG 是无损格式,传了也白传。
javascript
var q = parseFloat($quality.value);
if (fmt === 'image/png') q = undefined;
3. 大图片处理容易崩溃
如果用户上传了一张 5000x5000 的图,直接绘制到 Canvas 可能直接爆内存。所以我加了一个"最大边长"选项,等比缩放后再处理:
javascript
if (maxDim > 0 && Math.max(w, h) > maxDim) {
var s = maxDim / Math.max(w, h);
w = Math.round(w * s);
h = Math.round(h * s);
}
AI 辅助开发过程
这个工具我用 AI 辅助写了大半。说实话,让 AI 写代码这事,体验有点像和一个"很聪明但偶尔会犯傻"的同事协作。
第一次给 AI 的 prompt 大概是这样的:
帮我写一个纯前端的图片格式转换工具,支持 PNG/JPG/WebP 互转,要有质量控制和尺寸缩放功能,界面要简洁,支持拖拽上传。
AI 第一次生成的代码其实已经能跑了,但有几个问题:
- 没有处理 JPEG 透明背景问题 ------ 这是我后来自己发现的坑,AI 一开始没考虑到
- 界面太丑 ------ AI 生成的样式比较粗糙,我后来自己调了 CSS
- 没有 i18n 支持 ------ 我需要在中文和英文环境都能用
来回调优的过程:
我告诉 AI "转 JPEG 时透明区域会变黑,需要填充白色背景",它马上给出了解决方案。我又说 "加个质量滑块和尺寸限制",它也能很快实现。
最有意思的是,AI 一开始把 toBlob 的质量参数写死了 0.9,我让它改成可配置的,它连 UI 控件都帮我一起生成了。
我的感受是: AI 写代码适合从零开始搭框架、写常规逻辑,但业务上的坑(比如 JPEG 透明背景)还是得自己踩过才知道怎么改。不过 AI 的学习能力确实强,你告诉它一次坑在哪,它就不会再犯。
最终实现的效果
工具做出来以后,用起来是这样的流程:
- 点击或拖拽图片到页面
- 选择目标格式(JPEG/PNG/WebP)
- 调整质量(仅对有损格式生效)和最大边长(可选)
- 预览转换前后对比,确认后下载
整个过程完全在浏览器本地完成,没有任何上传操作。我特意在页面上标注了"无需上传,保护隐私",毕竟这才是这个工具的核心价值。
技术细节
文件读取
用 FileReader 读取图片,转成 Image 对象:
javascript
var reader = new FileReader();
reader.onload = function(e) {
var img = new Image();
img.onload = function() {
// 图片加载完成,开始处理
};
img.src = e.target.result;
};
reader.readAsDataURL(file);
格式转换
核心就一个 toBlob 调用,但要注意质量参数的处理:
javascript
canvas.toBlob(function(blob) {
// blob 就是转换后的文件
// 创建下载链接或预览
}, fmt, q);
下载
用 URL.createObjectURL 生成临时链接,配合 <a> 标签的 download 属性触发下载:
javascript
var a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = baseName + '.' + ext;
a.click();
性能优化
- 内存管理 :转换完成后及时
revokeObjectURL,避免内存泄漏 - 按需处理:只有用户点击转换时才执行 Canvas 操作,不做预加载
- 尺寸限制:默认不限制尺寸,但用户可选最大边长来防止大图卡死
适用场景
这个工具比较适合以下场景:
- 设计师:把 WebP 设计稿转成 PNG 给前端
- 后端开发:把 PNG 截图转成 JPG 减小体积
- 普通用户:发图片前转成合适格式,避免平台限制
- 注重隐私的人:不想把图片传到第三方服务器
一些心得
开发这个工具的过程中,最深的感受是:很多看似简单的需求,实际做起来总有几个隐藏的坑。比如 JPEG 透明背景变黑这个事,不做一遍真的想不到。
另外,AI 辅助开发确实能省很多时间,但关键的业务逻辑和边界情况,还是得靠经验来补齐。AI 是个好帮手,但别指望它一次就能写出完美的代码。
如果你也有类似需求------比如经常需要转图片格式,又不想把图片传到别人服务器上------可以直接在线体验这个工具:
代码逻辑不复杂,核心就几十行,但确实解决了我的日常痛点。至少现在转图片格式,我再也不用打开那些充满广告的在线转换网站了。