如何将getUserMedia获取的图像用于form表单上传及解决后置摄像头调用问题
实现方案指导
方案选型结论
对你提到的三个思路的可行性判断如下:
- 直接给input file赋值:浏览器安全策略禁止JS主动修改文件选择框的内容,该方案完全不可行。
- Base64编码后通过textarea提交:可实现,但存在两个缺陷:Base64编码会让数据体积增加约33%,且后端需要额外处理Base64格式转二进制文件,不推荐。
- 新增上传按钮提交二进制流:最优方案,直接通过FormData提交图片二进制Blob,完全符合你要求的
multipart/form-data格式,后端无需修改原有接收文件的逻辑。
问题1:调用后置摄像头的修正
你原代码中getUserMedia仅指定video: true,没有明确指定摄像头方向,修改请求参数即可优先调用后置摄像头:
// 原代码 // navigator.mediaDevices.getUserMedia({video: true}) // 修改为 navigator.mediaDevices.getUserMedia({ video: { facingMode: { ideal: "environment" // 优先后置摄像头,无后置时自动降级为前置 } } })
问题2:图片提交逻辑实现
核心思路
拍照时保存生成的图片Blob,点击上传按钮时将Blob放入FormData对象,通过AJAX提交即可。
完整修改后代码
<!DOCTYPE html> <html lang="tr"> <head> <meta charset="UTF-8"> <title>Take Photo</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <style> html,body,video {margin:0;padding:0;} .btn-group {position: fixed;top:0;left:0;right:0;height:3em;z-index: 10;} button {height:3em;width:50%;float:left;border: none;color: white;} #takeBtn {background: #2196F3;} #uploadBtn {background: #4CAF50;} video {height:3em;width:10em;right:0;top:0;position:fixed;z-index: 11;} #takePhotoCanvas {width:100vw;height:calc(100vh - 3em);left:0;top:3em;position:fixed;} </style> </head> <body> <div class="btn-group"> <button id="takeBtn">Take Photo</button> <button id="uploadBtn" disabled>Upload Photo</button> </div> <video autoplay=""></video> <canvas id="takePhotoCanvas"></canvas> <script> var imageCapture; // 存储拍照生成的Blob var capturedBlob = null; // 调用后置摄像头 navigator.mediaDevices.getUserMedia({ video: { facingMode: { ideal: "environment" } } }) .then(mediaStream => { document.querySelector('video').srcObject = mediaStream; const track = mediaStream.getVideoTracks()[0]; imageCapture = new ImageCapture(track); }) .catch(error => console.log(error)); // 拍照按钮绑定 document.querySelector('#takeBtn').addEventListener('click', takePhotoButton); // 上传按钮绑定 document.querySelector('#uploadBtn').addEventListener('click', uploadPhoto); function takePhotoButton() { imageCapture.takePhoto() .then(blob => { // 存储Blob capturedBlob = blob; // 启用上传按钮 document.querySelector('#uploadBtn').disabled = false; return createImageBitmap(blob); }) .then(imageBitmap => { const canvas = document.querySelector('#takePhotoCanvas'); drawCanvas(canvas, imageBitmap); }) .catch(error => console.log(error)); }; function uploadPhoto() { if (!capturedBlob) return; // 构建FormData const formData = new FormData(); // 和原来input file的name保持一致,后端无需修改 formData.append('profile_pic', capturedBlob, 'captured_photo.jpg'); // 提交请求 fetch('/upload.asp', { method: 'POST', body: formData }) .then(res => res.text()) .then(result => { alert('上传成功'); // 上传成功后可重置状态 capturedBlob = null; document.querySelector('#uploadBtn').disabled = true; }) .catch(error => { console.log('上传失败', error); alert('上传失败'); }) } /* Utils */ function drawCanvas(canvas, img) { canvas.width = getComputedStyle(canvas).width.split('px')[0]; canvas.height = getComputedStyle(canvas).height.split('px')[0]; let ratio = Math.min(canvas.width / img.width, canvas.height / img.height); let x = (canvas.width - img.width * ratio) / 2; let y = (canvas.height - img.height * ratio) / 2; canvas.getContext('2d').clearRect(0, 0, canvas.width, canvas.height); canvas.getContext('2d').drawImage(img, 0, 0, img.width, img.height, x, y, img.width * ratio, img.height * ratio); }; </script> </body> </html>
适配说明
如果你的WebView环境不支持fetchAPI,可替换为XMLHttpRequest实现提交,逻辑完全一致。
内容的提问来源于stack exchange,提问作者user2046734
相关产品推荐
相关产品推荐

