首页 前端知识 浏览器调用摄像头

浏览器调用摄像头

2024-02-25 11:02:09 前端知识 前端哥 624 785 我要收藏

背景
来了来了,用户奇怪的需求又来了,是这样的,原生的文件上传,在移动设备上是可以调用摄像头现拍然后直接上传的,而web端则是弹出选择图片的窗口,而用户用的那个平板,却是后者,他想直接拍直接上传,然后我就想,把设备的照相机功能放在任务栏不就行了吗,结果他们说,操作的工人都是年龄比较大的老工人了,那么繁琐的操作他们整不明白…然后我就只能,封装个组件…

ps:需要注意的是,浏览器只支持 https,localhost和127.0.0.1调用摄像头,而http是不支持的,但是只有http怎么办呢,也是有方法可以配置的:
在浏览器地址栏中输入“chrome://flags/#unsafely-treat-insecure-origin-as-secure”,回车,如下图,将该选项置为Enabled,在输入框中输入需要访问的地址,多个地址使用“,”隔开,然后点击右下角弹出的Relaunch按钮,自动重启浏览器之后就可以在添加的http地址下调用摄像头和麦克风了。
在这里插入图片描述
话不多说,上代码:
HTML

<div class="cameraBox"></div>

JS( 这个项目用的jquey,很久没写了,写的不好,大佬勿喷)

var canvas 
var video 
var videoWidth
var videoHeight
var cameraIsOpen = false // 摄像头是否开启 默认为否
$(()=>{
	//这里就是一个按钮一个弹框,可以自由发挥
    let cameraBoxCode = `<button type="button" class="btn btn-default" title="开启摄像头" οnclick="cameraOpen()" >
                            <i class="fa fa-camera"></i>
                        </button>
                        <span id="photoName"></span>
                        <div id='cameraModal' class="modal fade" role="dialog" tabindex="1" aria-hidden="true">
                            <div class="modal-dialog">
                                <div class="modal-content">
                                    <div class="modal-header myDataTableModalHead" style="height: 3em;vertical-align: middle;padding: 5px 16px;">
                                        <button type="button" class="close" οnclick="modalClose()" aria-label="Close">
                                            <span aria-hidden="true">
                                                ×
                                            </span>
                                        </button>
                                        <span class="cardIcon"></span><h4 class="modal-title">拍照</h4>
                                    </div>
                                    <div class="modal-body" style="max-height:80vh;overflow:overlay">
                                        <video id="video" width="100%" autoplay="autoplay"></video>
                                        <canvas id="canvas" width="100%"></canvas>
                                    </div>
                                    <div class="modal-footer">
                                        <button type="button" class="btn btn-default" οnclick="modalClose()">
                                            <label data-locale="i18n_cancel"></label>
                                        </button>
                                        <button type="button" class="btn btn-primary" οnclick="takePhoto()">
                                            <label>拍照</label>
                                        </button>
                                    </div>
                                </div>
                            </div>
                        </div>`
    $('.cameraBox').append(cameraBoxCode)
})

//打开摄像头弹框
function cameraOpen(){
    canvas = document.getElementById('canvas')
    video = document.getElementById('video')
    $('#cameraModal').modal('show')
    setTimeout(()=>{
        getMedia()
    },1000)
}

//调取摄像头
function getMedia(){
    $('#canvas').hide()
    $('#video').show()
    videoWidth = '500'
    videoHeight = '500' // 摄像头宽高
    navigator.getMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMeddia || navigator.msGetUserMedia || navigator.mediaDevices.getUserMedia
    if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
		navigator.mediaDevices.getUserMedia({
			video: {width:videoWidth,height:videoHeight},
			audio: false
		}).then((stream) => {
			mediaStreamTrack = typeof stream.stop === 'function' ? stream : stream.getTracks()[0]
			video.srcObject =stream
			video.play()
			cameraIsOpen = true
		}).catch((err) => {
			$.modal.error('调用摄像头失败,请检查设备是否连接!')
		})
	} else if (navigator.getMedia) {// 使用旧方法打开摄像头
		navigator.getMedia({
            video: {width:videoWidth,height:videoHeight},
		}, (stream) => {
			mediaStreamTrack = stream.getTracks()[0]
			video.srcObject =stream
			video.play()
			cameraIsOpen = true
		}, (err) => {
			$.modal.error('调用摄像头失败,请检查设备是否连接!')
		})
	}
}

//拍照
function takePhoto(){
    $('#canvas').attr('width',videoWidth)
    $('#canvas').attr('height',videoHeight)
    $('#video').hide()
    $('#canvas').show()
    let ctx = canvas.getContext('2d')
    ctx.drawImage(video,0,0,videoWidth,videoHeight)
    let pic = canvas.toDataURL('image/png')
    pic = pic.replace(/^data:image\/(png|jpg);base64,/,"")
    let photo = dataURLtoFile(pic,createPic()) //转文件流
    $('#photoName').text(photo.name)
    modalClose()
    console.log(photo)
}

//产生随机图片名称
function createPic(){
    var now = new Date() 
    var year = now.getFullYear() //得到年份
    var month = now.getMonth()//得到月份
    var date = now.getDate()//得到日期
    var hour = now.getHours()//得到小时
    var minu = now.getMinutes()//得到分钟
    month = month + 1
    if (month < 10) month = '0' + month
    if (date < 10) date = '0' + date
    var number = now.getSeconds()%43 //这将产生一个基于目前时间的0到42的整数。
    var time = year + month + date + hour + minu
    var enNum = []
    for(var i=0;i<4;i++){
      var ranNum = Math.ceil(Math.random() * 25) //生成一个0到25的数字
       //大写字母'A'的ASCII是65,A~Z的ASCII码就是65 + 0~25然后调用String.fromCharCode()传入ASCII值返回相应的字符并push进数组里
       enNum.push(String.fromCharCode(65 + ranNum))
    }
    return time+'_'+number+enNum.join('')+'.png'
}

//base64转文件流
function dataURLtoFile(dataurl, filename) {
    // 将base64编码转为字符串
    const bstr = window.atob(dataurl)
    let n = bstr.length
    const u8arr = new Uint8Array(n) // 创建初始化为0的,包含length个元素的无符号整型数组
    while (n--) {
      u8arr[n] = bstr.charCodeAt(n)
    }
    return new File([u8arr], filename, {
      type: 'image/png'
    })
}

//关闭弹框
function modalClose(){
    $('#cameraModal').modal('hide')
    if(cameraIsOpen){
        mediaStreamTrack.stop() // 关闭摄像头
    }
}

转载请注明出处或者链接地址:https://www.qianduange.cn//article/2696.html
标签
bootstrap
评论
会员中心 联系我 留言建议 回顶部
复制成功!