canvas.toDataURL返回 Base64 编码黑色图片的检测方法
canvas.toDataURL()
用于将 Canvas
画布内容转换为 Base64
编码的图片数据 URL。
如果 canvas
绘制工作比较复杂,执行 toDataURL()
可能会失败,返回黑色图片Base64
编码数据。
这里根据转换结果检测是否为黑图,参考:
/**
* 根据 Base64 编码的图片数据判断是否为黑色图片
* @param {string} base64Data - `canvas.toDataURL()` 返回的 Base64 字符串
* @param {Object} [options] - 配置选项
* @param {number} [options.threshold=0.95] - 黑色像素占比阈值(默认 95%)
* @param {number} [options.maxColorValue=10] - RGB 通道最大值(小于此值视为黑色)
* @param {number} [options.sampleStep=1] - 抽样步长(1=全检测,2=隔1像素检测,以此类推)
* @returns {Promise<boolean>} - Promise 返回检测结果(true 表示是黑色图片)
*/
function isBase64ImageBlack(base64Data, options = {}) {
const {
threshold = 0.95,
maxColorValue = 10,
sampleStep = 1
} = options;
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => {
try {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
let blackPixelCount = 0;
const step = sampleStep <= 0 ? 1 : sampleStep;
// 按步长抽样检测
for (let y = 0; y < canvas.height; y += step) {
for (let x = 0; x < canvas.width; x += step) {
const i = (y * canvas.width + x) * 4;
const r = data[i];
const g = data[i + 1];
const b = data[i + 2];
if (r <= maxColorValue && g <= maxColorValue && b <= maxColorValue) {
blackPixelCount++;
}
}
}
// 计算抽样后的有效像素总数
const sampledWidth = Math.ceil(canvas.width / step);
const sampledHeight = Math.ceil(canvas.height / step);
const totalSampledPixels = sampledWidth * sampledHeight;
const blackRatio = blackPixelCount / totalSampledPixels;
resolve(blackRatio >= threshold);
} catch (error) {
reject(error);
}
};
img.onerror = (err) => reject(new Error('图片加载失败: ' + err.message));
img.src = base64Data;
});
}
关于返回黑图的原因非常多,比如浏览器兼容性、canvas
上下文复杂度等,而且还有些概率性。遇到这种情况,没必要重试 toDataURL()
,结果一般还是不对,而是要重新绘制 canvas
。
介绍一种必现的方法:当执行canvas.toDataURL()时,把当前浏览器页签切至后台 。
主要因浏览器对后台标签页的资源限制:后台页面的渲染管线会被暂停或降级,导致 Canvas 内容未更新;同时,浏览器可能主动释放 GPU 资源或清除帧缓冲区,且出于安全隐私考虑,会强制返回黑色图片以避免后台窃取敏感内容。
参考该方法,以便测试和定位实际业务问题。