iPad端Chrome与Safari中canvas.toDataURL导出WebP失效问题求解
问题描述
使用canvas.toDataURL('image/webp', 0.8)处理图片时,安卓及Windows设备可正常生成WebP格式的DataURL,但在iPad(Safari 16.6、Chrome 130.0)上会默认返回PNG格式,canvas.toBlob()调用同样存在该问题。需求是实现所有设备(含苹果设备)将Canvas处理后的图片以WebP格式放入<img>标签中。
相关测试代码如下:
JavaScript
function doConvert() { const fileInput = document.querySelector("input[type='file']"); const img = document.querySelector("img"); const canvas = document.querySelector("canvas"); const p = document.querySelector("p"); const ctx = canvas.getContext("2d"); const file = fileInput.files[0]; if (file) { const reader = new FileReader(); reader.onload = function (e) { const imgElement = new Image(); imgElement.src = e.target.result; imgElement.onload = function() { // Set up the canvas size const width = imgElement.width; const height = imgElement.height; const dpr = window.devicePixelRatio || 1; canvas.width = width * dpr; canvas.height = height * dpr; // Apply scaling and draw image onto canvas ctx.scale(dpr, dpr); ctx.drawImage(imgElement, 0, 0, width, height); // Convert to WebP and display in the img element let dataUrl = canvas.toDataURL("image/webp", 0.8); img.src = dataUrl; p.innerHTML = navigator.userAgent+'<HR>'+dataUrl.substring(0,30)+'...'; // Logging the base64 string for reference }; }; reader.readAsDataURL(file); } }
CSS
img, canvas { width:auto; height:50vh; vertical-align:top; } canvas { border:solid 1px orange; } img { border:solid 1px red; } div { margin:10px; }
HTML
<input type="file" onChange="doConvert()" /> <div>canvas:<canvas></canvas> img:<img /></div> <div> <p></p> </div>
可行解决方案
1. 先检测浏览器的WebP导出支持
iOS 16.4+和macOS 13.3+的Safari理论上支持Canvas导出WebP,但部分场景存在兼容性bug。先通过代码检测当前环境是否支持原生WebP导出:
function supportsCanvasWebPExport() { const testCanvas = document.createElement('canvas'); testCanvas.width = 1; testCanvas.height = 1; return testCanvas.toDataURL('image/webp').startsWith('data:image/webp'); }
2. 原生API结合Fallback方案
优先使用canvas.toBlob()(比toDataURL更高效),若原生导出失败,使用第三方库作为兜底:
function doConvert() { const fileInput = document.querySelector("input[type='file']"); const img = document.querySelector("img"); const canvas = document.querySelector("canvas"); const p = document.querySelector("p"); const ctx = canvas.getContext("2d"); const file = fileInput.files[0]; if (file) { const reader = new FileReader(); reader.onload = function (e) { const imgElement = new Image(); imgElement.src = e.target.result; imgElement.onload = function() { const width = imgElement.width; const height = imgElement.height; const dpr = window.devicePixelRatio || 1; canvas.width = width * dpr; canvas.height = height * dpr; ctx.scale(dpr, dpr); ctx.drawImage(imgElement, 0, 0, width, height); // 尝试原生WebP导出 canvas.toBlob(function(blob) { if (blob && blob.type === 'image/webp') { img.src = URL.createObjectURL(blob); p.innerHTML = `${navigator.userAgent}<HR>data:image/webp;base64,...`; } else { // 原生导出失败,使用libwebp转换 convertCanvasToWebP(canvas, function(webpBlob) { img.src = URL.createObjectURL(webpBlob); p.innerHTML = `${navigator.userAgent}<HR>data:image/webp;base64,...`; }); } }, 'image/webp', 0.8); }; }; reader.readAsDataURL(file); } }
3. 使用libwebp.js作为兜底转换
libwebp是Google官方的WebP编码库,可以将Canvas的像素数据编码为WebP格式,解决原生API不支持的场景:
- 下载libwebp的编译版本并引入到项目中
- 实现转换函数:
function convertCanvasToWebP(canvas, callback) { const ctx = canvas.getContext('2d'); const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); const { width, height, data } = imageData; // 使用libwebp的encodeAPI(具体参数可根据需求调整) WebP.encode(data, width, height, 0.8, function(encodedData) { const webpBlob = new Blob([encodedData], { type: 'image/webp' }); callback(webpBlob); }); }
补充说明
- iOS上的Chrome等第三方浏览器基于WebKit内核,因此兼容性和Safari一致
- 使用
URL.createObjectURL()生成的Blob URL,在页面卸载或不再使用时建议调用URL.revokeObjectURL()释放资源
内容的提问来源于stack exchange,提问作者abe1432181
相关产品推荐
相关产品推荐

