在线图片工具的便利不应以把原图上传到陌生服务器为代价。LemonArt 的设计原则是:用户选择文件后,数据只在当前设备的浏览器内存中流转;网页只负责提供界面、算法和下载结果,不建立图片上传接口。
一、浏览器本地处理的完整生命周期
用户选择 File 后,页面通过 URL.createObjectURL 创建本地预览地址。这个地址不等于公开 URL,它指向当前页面进程可访问的临时资源。图片加载到 Image 或 Canvas 后,页面在移除文件和组件销毁时调用 URL.revokeObjectURL,避免大量批量任务积累资源。
转换后的 Blob 同样只保存在浏览器内存中,用户点击下载时由浏览器发起本地下载。因为没有上传请求,服务器日志、CDN 缓存和第三方图片存储都不会接触到原始图像。
生命周期管理在代码里的体现是“成对出现”:createObjectURL 与 revokeObjectURL 必须一一对应。删除单个文件、清空整个列表和组件卸载三条路径都要释放;编辑器的原图与导出结果各持有独立 URL,分别管理。漏掉任何一条路径,长会话下内存都会缓慢增长。
- 不发送 File、Blob 或 Base64 到业务 API。
- 预览地址只在当前页面生命周期内有效。
- 删除文件、清空列表和页面离开时释放临时资源。
- 错误提示只展示必要的格式或能力信息,不输出图片内容。
function removeFile(item: ImageFile) {
URL.revokeObjectURL(item.url) // 原图预览
if (item.resultUrl) URL.revokeObjectURL(item.resultUrl) // 转换结果
files = files.filter((entry) => entry.id !== item.id)
}
function clearFiles() {
files.forEach((item) => {
URL.revokeObjectURL(item.url)
if (item.resultUrl) URL.revokeObjectURL(item.resultUrl)
})
files = []
}ts二、本地不等于没有边界
本地处理不能绕过浏览器和设备限制。大型 PSD、RAW 或超高分辨率图片可能无法被当前浏览器解码;浏览器标签页也可能因内存不足被系统回收。好的隐私产品不应承诺“任何格式、任何尺寸都能处理”,而应明确支持范围、单文件大小上限和失败原因。
三、权限最小化与第三方依赖
LemonArt 不需要登录、云盘权限或长期文件访问权限。用户主动选择的文件只交给当前页面使用,页面不保存处理历史。字体等视觉资源可以通过静态依赖加载,但图像处理链路不依赖远程图片 API,OpenCV.js 也在站点自己的静态资源路径下提供。
四、SEO 与隐私可以同时成立
“本地处理”不是无法被搜索引擎理解的卖点。页面可以通过清晰的标题、描述、FAQ、结构化数据和技术博客解释处理方式,而不需要收集用户图片来做内容。LemonArt 的博客正是用可抓取的技术内容建立搜索入口,工具本身仍保持无上传设计。
五、如何验证“本地处理”承诺
隐私承诺应该可验证,而不是只写进宣传文案。最直接的验证方式是打开开发者工具,观察 Network 面板:正常使用时除了静态资源(HTML、CSS、JS、WASM、字体),不应出现任何携带图片数据的请求;把网络断掉,工具应当依然能完成上传、转换和下载,因为数据链路根本不经过网络。
更严格的审计还可以检查三点:项目源码中是否存在任何 upload 接口或第三方图片 API;处理结果是否只在内存中由 Blob 承载;页面是否引入了不必要的分析或统计脚本。这三项与实现一一对应,任何人都能复核,也让“本地处理”成为可被信任的事实而非口号。
- Network 面板在正常操作中不应出现图片上传请求。
- 断网状态下转换与下载应仍可工作,这是本地处理的决定性证据。
- 源码审计:无上传接口、无远程图片 API、无第三方分析依赖。
- 把“可验证”写进产品说明,比空洞的安全承诺更有说服力。
要点总结
- 本地图片工具的关键是没有上传链路,而不只是文案写“安全”。
- Object URL、Blob 和 Canvas 都要有明确的生命周期管理。
- 隐私承诺要能被 DevTools、断网测试和源码审计独立验证。
- 诚实说明浏览器限制,能同时提升隐私可信度和产品体验。