如何为Angular自定义相机的video元素设置竖屏全高模式
Angular自定义相机竖屏拍摄落地方案
问题核心原因
仅通过CSS旋转video元素属于视觉层面的调整,摄像头输出的原始媒体流方向没有改变,调用drawImage取帧生成图片时,读取的是原始流的横屏画面,自然输出横屏结果。
移动端后置摄像头传感器本身多为横向安装,部分机型即使指定了摄像头参数,依然会默认输出横屏流,需要从流配置、帧校正两个层面处理。
分步实现
1. 初始化摄像头时强制指定竖屏流约束
调用getUserMedia时不要只传facingMode: 'environment',要明确添加竖屏比例、尺寸约束,尽可能让摄像头直接输出竖屏流:
async initCustomCamera() { const cameraConstraints = { video: { facingMode: { ideal: 'environment' }, // 优先调用后置摄像头 aspectRatio: { ideal: 9 / 16 }, // 强制要求9:16竖屏比例 width: { ideal: 1080 }, // 竖屏短边理想宽度 height: { ideal: 1920 }, // 竖屏长边理想高度 }, audio: false }; // 绑定流到video元素 this.mediaStream = await navigator.mediaDevices.getUserMedia(cameraConstraints); const videoEl: HTMLVideoElement = this.videoRef.nativeElement; videoEl.srcObject = this.mediaStream; await videoEl.play(); }
2. 元数据加载时判断是否需要旋转校正
监听video的loadedmetadata事件,读取流的实际宽高,判断是否为横屏输出的流:
// 绑定到video的loadedmetadata事件 onVideoLoaded() { const videoEl: HTMLVideoElement = this.videoRef.nativeElement; const streamWidth = videoEl.videoWidth; const streamHeight = videoEl.videoHeight; // 流宽度大于高度说明是横屏输出,拍摄时需要旋转校正 this.needRotateFrame = streamWidth > streamHeight; this.streamWidth = streamWidth; this.streamHeight = streamHeight; }
3. 拍摄时通过Canvas校正方向输出竖屏图片
不要直接截取video画面,通过Canvas做帧绘制,需要旋转时做坐标变换,保证输出的是完整竖屏画面:
async captureIdCardPhoto() { const videoEl: HTMLVideoElement = this.videoRef.nativeElement; const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); if (this.needRotateFrame) { // 横屏流转竖屏:canvas宽高对调 canvas.width = this.streamHeight; canvas.height = this.streamWidth; // 坐标变换:原点移到画布中心,旋转90度后绘制画面 ctx.translate(canvas.width / 2, canvas.height / 2); ctx.rotate(Math.PI / 2); ctx.drawImage( videoEl, -this.streamWidth / 2, -this.streamHeight / 2, this.streamWidth, this.streamHeight ); } else { // 原生竖屏流直接绘制 canvas.width = this.streamWidth; canvas.height = this.streamHeight; ctx.drawImage(videoEl, 0, 0, canvas.width, canvas.height); } // 导出最终竖屏图片,可直接用于上传、识别 return new Promise<Blob>((resolve) => { canvas.toBlob((blob) => { resolve(blob); }, 'image/jpeg', 0.92); }); }
4. 预览层CSS适配
给video元素加适配样式,保证预览画面和最终输出画面比例一致,叠加身份证参考线时不会出现错位:
.camera-preview { width: 100%; height: 100vh; object-fit: cover; /* 画面铺满容器不拉伸 */ } /* 身份证参考线直接用绝对定位叠加在video上层即可 */ .id-card-guide { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 80vw; aspect-ratio: 85.6 / 54; /* 标准身份证长宽比 */ border: 2px dashed #fff; border-radius: 8px; }
避坑提示
- 不要仅靠
transform: rotate(90deg)旋转video元素做预览,这个操作不会改变原始媒体流方向,拍摄时依然会得到横屏图片 - 部分安卓机型需要在HTTPS环境下才能正常调用后置摄像头,本地调试可以用localhost
- 拍摄完成后如果需要在页面展示结果,给img标签加
image-orientation: from-image样式,避免部分浏览器自动旋转图片导致方向错误
内容的提问来源于stack exchange,提问作者Titus Sutio Fanpula
相关产品推荐
相关产品推荐

