多模态Agent上传图片:前端压缩格式与预览实战

接了个图片问答的需求:用户传张图,AI 看图回答。听着就是个 <input type=file>,真做下去才知道前端要替用户兜多少事------几十兆的原图直接传,请求超时;HEIC 格式后端不认;预览图把内存吃爆。一篇实战,把上传这条链路的脏活拆开讲。

先压,别让用户传原图

现在手机随手一拍就是十几兆,原图传上去既慢又烧带宽,多模态模型其实也不需要那么高分辨率。前端用 canvas 等比缩到长边 1568px 左右(多数视觉模型的友好尺寸)再传,体积能砍九成:

ini 复制代码
async function compress(file: File, maxEdge = 1568, quality = 0.82): Promise<Blob> {
  const bitmap = await createImageBitmap(file);
  const scale = Math.min(1, maxEdge / Math.max(bitmap.width, bitmap.height));
  const w = Math.round(bitmap.width * scale);
  const h = Math.round(bitmap.height * scale);
  const canvas = new OffscreenCanvas(w, h);
  const ctx = canvas.getContext('2d')!;
  ctx.drawImage(bitmap, 0, 0, w, h);
  bitmap.close(); // 重要,及时释放,否则内存涨得吓人
  return canvas.convertToBlob({ type: 'image/jpeg', quality });
}

bitmap.close() 那行别漏。我做批量上传时没释放,连传十几张内存直接飙到几百兆,移动端 webview 当场崩。OffscreenCanvas 还能放进 Web Worker 压,不卡主线程,长列表上传体验好很多。

HEIC 是个大坑

iPhone 默认存 HEIC,浏览器 <img> 和 canvas 大多不认,createImageBitmap 直接抛错。我一开始没考虑,苹果用户上传全军覆没,测试机是安卓还没测出来,上线才暴雷。

处理方式:检测到 HEIC 先用 heic2any 之类转成 jpeg 再走压缩。代价是这个库 gzip 后小两百 KB,我做了动态 import,只有真遇到 HEIC 才加载,别让所有用户为少数格式买单:

javascript 复制代码
async function normalize(file: File): Promise<File> {
  if (/heic|heif/i.test(file.type) || /.heic$/i.test(file.name)) {
    const { default: heic2any } = await import('heic2any'); // 按需加载
    const blob = await heic2any({ blob: file, toType: 'image/jpeg' });
    return new File([blob as Blob], file.name.replace(/.heic$/i, '.jpg'), { type: 'image/jpeg' });
  }
  return file;
}

预览图用 objectURL,记得 revoke

预览别用 FileReader 读 base64------大图转 base64 又慢又占内存,还会把 DOM 撑大。用 URL.createObjectURL 几乎零成本,但必须配对 revoke,否则这块内存到页面关都不释放:

ini 复制代码
const url = URL.createObjectURL(file);
previewEl.src = url;
previewEl.onload = () => URL.revokeObjectURL(url); // 加载完立刻回收

删除某张待传图片时也要 revoke 对应的 url。我有个版本忘了在删除分支里回收,用户反复添加删除几十次后,内存只涨不跌,典型的泄漏。

上传前的体面校验

别等传到后端才报「格式不支持」。前端先把住门------类型白名单、单张大小上限、张数上限,错误就地提示,省一次往返也省用户的脾气:

kotlin 复制代码
function validate(file: File) {
  const ok = ['image/jpeg', 'image/png', 'image/webp', 'image/heic'];
  if (!ok.includes(file.type)) return '只支持 JPG/PNG/WebP/HEIC';
  if (file.size > 20 * 1024 * 1024) return '单张不能超过 20MB';
  return null;
}

一个没做完美的

压缩质量我固定在 0.82,对照片够用,但用户传的若是带细密文字的截图,压完字会糊,影响模型识别。理想做法是按内容自适应质量,我评估了下投入产出比,暂时没做,先在文案里提示「文字截图建议原图」绕过去。算个偷懒,但当下够用。

多模态那头的模型能力我直接接讯飞 这类 MaaS 的现成 API,不操心算力和模型怎么部署,前端只把图片处理这条链路打磨干净。

你们上传链路还有啥隐形坑?HEIC 之外我估计还有冷门格式,评论区补补刀。

相关推荐
姗姗来迟了1 小时前
Vue3封装可复用AI对话组件:一次抽象复盘
人工智能
怕浪猫2 小时前
哪些软件对 Chrome DevTools Protocol 频繁使用
人工智能·架构·前端框架
leo在掘金3 小时前
从DeepSeek 510亿融资到GitHub 33K Star开源项目:这周的技术生态发生了什么?
人工智能
小姜前线技术4 小时前
AI流式渲染打字机效果抖动?节流方案踩坑实录
人工智能
用户018349301694 小时前
AI对话状态管理:useReducer还是XState
人工智能
先锋部队4 小时前
给AI对话加「停止生成」按钮:abort SSE实战
人工智能
新新技术迷4 小时前
移动端H5接AI对话的坑:键盘顶起与滚动到底
人工智能