目录
[与传统 Image 对象对比](#与传统 Image 对象对比)
[WebGL 纹理上传](#WebGL 纹理上传)
[在 Web Worker 中预处理图像](#在 Web Worker 中预处理图像)
[高效绘制到 Canvas 2D](#高效绘制到 Canvas 2D)
[绘制COCO RLE 掩码处理后的ImageData](#绘制COCO RLE 掩码处理后的ImageData)

前言
ImageBitmap 是一种可以直接绘制到 Canvas(2D 或 WebGL)上的位图图像 ,可以高性能、低延迟的图像解码与渲染 。简单来说,从数据源到屏幕的流程是:Blob/File/ArrayBuffer → ImageBitmap → WebGL Texture
它在主线程外异步解码图片(JPEG, PNG等),并创建一个预优化的、可直接上传给GPU的位图对象,避免解码阻塞UI。
ImageBitmap能把处理的数据,高效上传到GPU显存中,成为Texture(纹理)。
与传统 Image 对象对比
解码不卡顿,上传极快
Image 的解码会阻塞主线程,导致页面滚动、动画卡顿。而 ImageBitmap 的解码在后台进行。
javascript
// 使用 Image - 解码在主线程
const img = new Image();
img.onload = () => { /* 此时解码已完成并可能已阻塞UI */ };
img.src = 'large.jpg';
// 使用 ImageBitmap - 解码在后台
const response = await fetch('large.jpg');
const blob = await response.blob();
const bitmap = await createImageBitmap(blob); // ⬅️ 此处解码不阻塞UI
// 可以安全地更新加载进度条,UI依然流畅
图示

使用方式
ImageBitmap 通过全局的 createImageBitmap() 工厂函数创建,它接受多种图像源并返回一个 Promise。
javascript
// 从多种源创建 ImageBitmap
async function createBitmapFromVariousSources(source) {
let imageBitmap;
// 1. 从 Blob/File(最常见)
if (source instanceof Blob) {
imageBitmap = await createImageBitmap(source);
}
// 2. 从 ImageData(例如处理过的Canvas数据)
if (source instanceof ImageData) {
imageBitmap = await createImageBitmap(source);
}
// 3. 从另一个 ImageBitmap(可进行二次处理)
if (source instanceof ImageBitmap) {
imageBitmap = await createImageBitmap(source);
}
// 4. 从 <img>, <svg>, <video> 等元素
// const imgElement = document.getElementById('my-img');
// imageBitmap = await createImageBitmap(imgElement);
// 5. 带选项的创建:只解码一部分,或调整大小
const options = {
imageOrientation: 'flipY', // 纠正方向
premultiplyAlpha: 'premultiply',
colorSpaceConversion: 'none',
resizeWidth: 100, // 缩放到指定宽度
resizeHeight: 100,
resizeQuality: 'high'
};
// 只解码源图像的 (x:10, y:10, 宽:100, 高:100) 区域
imageBitmap = await createImageBitmap(source, 10, 10, 100, 100, options);
return imageBitmap;
}
应用场景
WebGL 纹理上传
javascript
async function loadTextureForWebGL(gl, url) {
const response = await fetch(url);
const blob = await response.blob();
// 关键步骤:在可能阻塞的解码完成后再返回主线程
const imageBitmap = await createImageBitmap(blob);
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
// 高效上传!这是性能提升的关键调用
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imageBitmap);
// 用完记得关闭,释放内存
imageBitmap.close();
return texture;
}
在 Web Worker 中预处理图像
将耗时的图像处理(如滤镜、裁剪)完全移出主线程。
javascript
// main.js 主线程
const worker = new Worker('image-processor.js');
const fileInput = document.querySelector('input[type="file"]');
fileInput.addEventListener('change', (e) => {
const file = e.target.files[0];
worker.postMessage({ image: file }, [file]); // 转移所有权,零拷贝
});
// image-processor.js Worker线程
self.onmessage = async (e) => {
const blob = e.data.image;
// Worker中也可以使用 createImageBitmap!
const bitmap = await createImageBitmap(blob);
// ... 在Worker中对bitmap进行各种处理 ...
const processedBitmap = doSomeHeavyProcessing(bitmap);
// 将处理结果传回主线程
self.postMessage({ bitmap: processedBitmap }, [processedBitmap]);
};
高效绘制到 Canvas 2D
javascript
const canvas = document.getElementById('my-canvas');
const ctx = canvas.getContext('2d');
async function drawImageFast(blob) {
const imageBitmap = await createImageBitmap(blob);
// 绘制性能优于 ctx.drawImage(imgElement, ...)
ctx.drawImage(imageBitmap, 0, 0);
imageBitmap.close();
}
绘制COCO RLE 掩码处理后的ImageData
javascript
async function maskArrayToImageBitmap(maskArray, width, height) {
// 1. 将掩码数组 (0/255) 转换为 RGBA ImageData
const canvas = new OffscreenCanvas(width, height);
const ctx = canvas.getContext('2d');
const imageData = ctx.createImageData(width, height);
for (let i = 0; i < maskArray.length; i++) {
const value = maskArray[i]; // 0 or 255
const idx = i * 4;
imageData.data[idx] = value; // R
imageData.data[idx + 1] = value; // G
imageData.data[idx + 2] = value; // B
imageData.data[idx + 3] = 255; // A
}
ctx.putImageData(imageData, 0, 0);
// 2. 从 Canvas 或 ImageData 创建 ImageBitmap
// 方法A: 从OffscreenCanvas直接创建
const bitmapFromCanvas = await createImageBitmap(canvas);
// 方法B: 从ImageData创建(更直接)
const bitmapFromImageData = await createImageBitmap(imageData);
return bitmapFromCanvas; // 或 bitmapFromImageData
}
// 使用:将你解码的mask转换为ImageBitmap
// const { mask, width, height } = decodeCocoRle(cocoRle);
// const maskBitmap = await maskArrayToImageBitmap(mask, width, height);
// 然后可以用于WebGL或快速绘制
注意事项
-
手动内存管理 :
ImageBitmap持有图像数据,使用后必须调用.close()方法释放内存,否则会导致内存泄漏。 -
浏览器兼容性 :现代浏览器支持良好,但对于非常古老的浏览器(如IE)和某些深度裁剪、调整大小等高级选项,支持度可能不一。核心的
createImageBitmap(blob)在主流浏览器中均已支持。 -
源限制 :与
img元素类似,受同源策略/CORS限制。但处理本地Blob(如File)或已正确设置CORS的响应则没有问题。
总结
ImageBitmap 是 为性能而生的底层图形原语,当你需要高性能解码、渲染控制,或与 Canvas/WebGL/Worker 交互时,ImageBitmap 是不二之选