前言
在开发中经常有调用摄像头拍照上传的需求。移动端一般通过input组件调用移动端设备进行拍照,或者是调用第三方平台提供的jssdk进行拍照。input组件在PC端环境中只有选择附件的功能,无法直接调起摄像头进行拍照。PC端环境拍照一般是通过video组件获取到视频流,截取当前视频的画面实现拍照的效果。
移动端拍照
使用input组件进行拍照,设置input的type为file,接收的文件类型为图片。
<input onchange="fileChange(this)" type="file" accept="image/*" />
<script>
function fileChange(el) {
let file = el.files
}
</script>
accept规定可通过文件上传控件提交的文件类型
capture表示的是系统所捕获的默认设备,加上capture="camera"之后不会调用图库,而是直接打开摄像头拍照。
<input onchange="fileChange(this)" type="file" accept="image/*" capture="camera"/>
<script>
function fileChange(el) {
let file = el.files
}
</script>
桌面端拍照
使用video组件获取视频流,通过点击“拍照”按钮截取当前视频的画面,以此来模拟拍照的效果。
示例代码如下:
<html lang="en">
<head>
<meta charset="UTF-8">
<title>拍照</title>
<style type="text/css">
div {
margin-bottom: 10px;
}
</style>
</head>
<body>
<div>
<button id="switchCamera">打开/切换摄像头</button>
<button id="closeCamera">关闭摄像头</button>
<button id="takePicture">拍照</button>
</div>
<video id="video" width="240" height="160" autoplay></video>
<canvas id="canvas" width="240" height="160"></canvas>
<script>
const WIDTH = 240
const HEIGHT = 160
function getUserMedia(constraints, success, error) {
if (navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices.getUserMedia(constraints).then(success).catch(error);
} else if (navigator.webkitGetUserMedia) {
navigator.webkitGetUserMedia(constraints, success, error)
} else if (navigator.mozGetUserMedia) {
navigator.mozGetUserMedia(constraints, success, error);
} else if (navigator.getUserMedia) {
navigator.getUserMedia(constraints, success, error);
}
}
function openCameraFn() {
if (navigator.mediaDevices.getUserMedia ||
navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia) {
getUserMedia({
audio: false,
video: {
width: WIDTH,
height: HEIGHT,
deviceId: videoDevices[videoDeviceIndex]
}
}, (stream)=>{
video.srcObject = stream;
video.play();
}, (err)=>{
console.log('开启摄像头失败:' + err)
})
}
}
function closeCameraFn() {
if (video.srcObject) {
try {
let tracks = video.srcObject.getTracks();
for (let track of tracks) {
track.stop();
}
} catch(err) {
console.log(err)
}
}
}
function dataURLtoFile(dataUrl, fileName) {
if (!fileName) {
return null;
}
const arr = dataUrl.split(',');
const mime = arr[0].match(/:(.*?);/)[1];
const bytes = window.atob(arr[1])
// 处理异常,将ascii码小于0的转换为大于0
const ab = new ArrayBuffer(bytes.length);
const ia = new Uint8Array(ab);
for (let i = 0; i < bytes.length; i++) {
ia[i] = bytes.charCodeAt(i);
}
if (fileName.indexOf(".") < 0) {
fileName += `.${mime.replace("image/", "")}`
}
return new File([ab], fileName, { type: mime });
}
let videoDevices = []
let videoDeviceIndex = 0
let video = document.getElementById("video")
let canvas = document.getElementById("canvas")
let context2d = canvas.getContext("2d")
// 获取摄像头设备信息
try {
navigator.mediaDevices.enumerateDevices().then(function(devices){
videoDevices = []
devices.forEach(function(device) {
let deviceKind = device.kind
if (deviceKind.match(/^video.*/)) {
videoDevices.push(device.deviceId)
}
})
})
} catch (err) {
console.log('获取设备失败:' + JSON.stringify(err))
}
document.getElementById("switchCamera").addEventListener('click', function (ev) {
closeCameraFn()
openCameraFn()
videoDeviceIndex = (videoDeviceIndex++) % videoDevices.length
})
document.getElementById("closeCamera").addEventListener('click', function (ev) {
closeCameraFn()
})
document.getElementById("takePicture").addEventListener('click', function (ev) {
context2d.drawImage(video, 0, 0, WIDTH, HEIGHT)
let picture = canvas.toDataURL("image/png")
let pictureFile = dataURLtoFile(picture, Date.now()+'.png')
})
</script>
</body>
</html>
对上述示例代码的说明:
- canvas.getContext(contextID):返回一个表示用来绘制的环境类型的环境。其本意是要为不同的绘制类型(2 维、3 维)提供不同的环境。当前,唯一支持的是 "2d",它返回一个CanvasRenderingContext2D 对象,该对象实现了一个画布所使用的大多数方法。 (参见:www.w3school.com.cn/jsref/met_c…
- context2d.drawImage: drawImage() 方法在画布上绘制图像、画布或视频。(参见:www.w3school.com.cn/tags/canvas…
- canvas.toDataURL:把画布上的绘制内容以一个data URI的格式返回。(参见:www.w3cschool.cn/microgame/m…
- MediaDevices.enumerateDevices():请求一个可用的媒体输入和输出设备的列表,例如麦克风,摄像机,耳机设备等。返回的Promise完成时,会带有一个描述设备的MediaDeviceInfo的数组。 (参见:developer.mozilla.org/zh-CN/docs/…
实现的效果为:
左边为video实时显示的视频画面,右边为点击拍照按钮以后截取到的视频当前画面。
chrome浏览器默认只支持https,localhost,127.0.0.1这三种地址获取摄像头,如果不具备https的环境,则需要手动设置chrome浏览器访问的地址允许使用摄像头,否则摄像头不可用,具体操作步骤如下:
(1)在chrome浏览器输入:chrome://flags/#unsafely-treat-insecure-origin-as-secure
(2)找到“Insecure origins treated as secure”这一项,在输入框中输入允许调用摄像头的http地址,示例:http://119.75.217.109:8080
(3)修改“Disabled”为“Enabled”
(4)点击“Relaunch”按钮重启浏览器即可
总结
使用H5进行拍照,如果input能直接调起摄像头拍照的话,还是更推荐使用input组件直接进行拍照,相对来说更方便,需要写的代码量也更少,能更专注于业务的开发。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!