HTML5 Canvas元素在iOS Chrome/Safari浏览器下无法渲染问题求助
问题根因
你遇到的是iOS WebKit内核专属的兼容问题,所有iOS端第三方浏览器(包括Chrome)都共用系统WebKit内核,所以会和Safari出现相同的异常,具体有4个核心问题:
- Canvas属性语法错误
你给canvas标签的宽高属性加了px后缀,这不符合HTML规范:canvas的width/height属性是无单位的像素值,加px会导致WebKit内核解析为无效值,画布实际尺寸和预期不符,渲染的内容超出可视范围表现为纯白。 - Mat类型和颜色空间不匹配
你定义dst的类型为单通道的cv.CV_8UC1,但cv.COLOR_RGBA2RGB输出的是三通道RGB数据,类型不匹配会导致内存数据异常。桌面/安卓端Web内核有容错机制能兼容错误格式,但iOS WebKit对Canvas渲染的格式校验极严格,直接拒绝渲染格式异常的像素数据。 - processVideo调用时序错误
你写的setTimeout(processVideo(), 0)是立即执行processVideo函数,而非把函数作为引用延时触发,此时如果video的元数据还未加载完成、video.videoHeight/video.videoWidth还是0,创建的Mat尺寸是无效的,iOS下不会自动适配后续的有效帧尺寸。 - video元素配置缺失
iOS下要正常从video元素捕获摄像头帧,必须给video标签添加playsinline属性,禁止iOS默认的视频全屏播放逻辑,否则即使video能正常显示画面,捕获的帧数据也是无效的。
修复方案
1. 修改HTML代码
移除canvas宽高的px后缀,给video添加playsinline属性:
<div id="localVideo"> <video id="video" playsinline></video> <canvas id="canvas" height="480" width="640"></canvas> <canvas id="hiddenCanvas" height="480" width="640"></canvas> </div>
如果需要隐藏video元素不要用display: none,改成如下样式避免iOS停止帧捕获:
#video { position: absolute; left: -9999px; opacity: 0; pointer-events: none; }
2. 修正JS逻辑
let video = document.getElementById('video'); // 等video元数据加载完成再初始化opencv相关实例 video.onloadedmetadata = () => { let cap = new cv.VideoCapture(video); let src = new cv.Mat(video.videoHeight, video.videoWidth, cv.CV_8UC4); // 把dst类型改成3通道匹配COLOR_RGBA2RGB的输出 let dst = new cv.Mat(video.videoHeight, video.videoWidth, cv.CV_8UC3); const FPS = 15; function processVideo() { try { if (!streaming) { // 清理资源退出 delete cap; src.delete(); dst.delete(); return; } cap.read(src); cv.cvtColor(src, dst, cv.COLOR_RGBA2RGB); // 可选:如果渲染还是异常,把dst转成RGBA格式再调用imshow,适配iOS的ImageData格式要求 // let showMat = new cv.Mat(); // cv.cvtColor(dst, showMat, cv.COLOR_RGB2RGBA); // cv.imshow('canvas', showMat); // showMat.delete(); cv.imshow('canvas', dst); cv.imshow('hiddenCanvas', src); let delay = 1000 / FPS; setTimeout(processVideo, delay); } catch (err) { console.log(err); } } // 修正setTimeout传参,只传函数引用不要加括号执行 setTimeout(processVideo, 0); }
如果修改后三通道的dst还是无法渲染,直接去掉转RGB的逻辑用四通道的src渲染即可,opencv.js的imshow对四通道RGBA格式的兼容性最好。
官方示例可正常运行的原因
官方示例没有上述错误:canvas宽高没有加px后缀、Mat类型和转换目标匹配、函数触发时机在video元数据加载完成后、video添加了playsinline属性,所以iOS下可以正常渲染。
内容的提问来源于stack exchange,提问作者Ollie Graham
相关产品推荐
相关产品推荐

