Angular中Canvas加载图片实现类视频流效果
Angular 移动端Canvas类视频流实现(Socket接收帧数据)
实现目标:通过Socket从后端接收图像帧数据,创建Blob URL并在移动端Canvas上渲染,达到类视频流的视觉体验。
核心实现代码
// 订阅Socket图像消息 this.sessionSocket.SocketMessagesImage.subscribe((message) => { // 过滤无效帧,且在不显示断言图片时处理 if (message.size > 4 && !this.showAssertionImage) { this.ngZone.run(() => { // 用requestAnimationFrame保证渲染与浏览器刷新同步 this.animationFrameId = requestAnimationFrame(() => this.frameEmitted(message) ); }); } }); // 处理单帧数据并渲染到Canvas frameEmitted(frameData: Blob) { this.lastFrame = frameData; // 用URL.createObjectURL生成Blob URL,性能优于FileReader const url = URL.createObjectURL( new Blob([frameData], { type: "image/jpeg" }) ); this.imageToDraw.src = url; // 释放上一个Blob URL,避免内存泄漏 if (this.previousUrl) { URL.revokeObjectURL(this.previousUrl); } this.previousUrl = url; // 图片加载完成后执行Canvas绘制逻辑 this.imageToDraw.onload = (_event) => { const context = this.mobileCanvas.nativeElement.getContext("2d"); // 判断图像分辨率是否变化 const resChanged = this.mobileCanvas.nativeElement.height !== this.imageToDraw.height; // 同步Canvas尺寸与图像尺寸 this.mobileCanvas.nativeElement.height = this.imageToDraw.height; this.mobileCanvas.nativeElement.width = this.imageToDraw.width; // 分辨率变化时切换容器横竖屏样式 if (resChanged) { const container = document.getElementById("canv-container"); if (this.imageToDraw.height < this.imageToDraw.width) { container.classList.remove("device-portrait"); container.classList.add("device-landscape"); } else { container.classList.add("device-portrait"); container.classList.remove("device-landscape"); } this.WindowResized = true; } // 将图像绘制到Canvas context.drawImage(this.imageToDraw, 0, 0); // 尺寸变化后执行屏幕缩放适配 if (this.WindowResized) { this.scaleScreen(); } }; }
关键优化与细节说明
- 性能优化:使用
URL.createObjectURL直接将二进制数据转为可访问的URL,比FileReader.readAsDataURL更高效,适合高频帧渲染场景 - 内存管理:每次生成新Blob URL后,及时释放旧URL,避免浏览器内存占用过高
- 流畅度保障:通过
requestAnimationFrame调度渲染逻辑,让Canvas绘制时机与浏览器刷新周期同步,减少画面卡顿 - 适配处理:根据图像宽高比自动切换容器的横竖屏样式,保证移动端显示效果
- Angular上下文兼容:用
ngZone.run包裹渲染逻辑,确保变化能触发Angular的变更检测
内容的提问来源于stack exchange,提问作者Mirza Rizwan
相关产品推荐
相关产品推荐

