IOS 和Android H5 打开摄像头拍照 使用navigator.MediaDevices.getUserMedia() 拍照

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.7.10/dist/vue.js"></script>
    <style>
        *{
            margin:0;padding: 0;
        }
        .video-wrap {
            overflow: hidden;
            width: 30vw;
            height: 45vw;
            border-radius: 100%;
            display: flex;
            justify-content: center;
            align-items: center;
            position: relative;
            z-index: 3;
            background-color: #ccc;
        }

        .pic_video {
            width: 60vw;
            height: 60vw;
            transform: rotateY(180deg);
            z-index: 6;
            position: relative;
        }

        .buddon {
            display: flex;

        }

        .warm_title2 {
            background-color: rgb(150, 150, 231);
            color: #fff;
            width: 100px;
            height: 40px;
            line-height: 40px;
            text-align: center;
            margin-right: 10px;
        }

        #canvas {
            height: 40vw;
            transform: rotateY(180deg);
            display: none;
        }

        img {
            transform: rotateY(180deg);
        }
        .flex{
            display: flex;
            justify-content: center;
            margin-top:20px

        }
        .center{
            margin:0 auto;
        }
        #video{
            mix-blend-mode: normal;
            outline: -webkit-focus-ring-color auto 0px;
        }
    </style>
</head>

<body>
    <div id="app">
        <div class="buddon flex" v-if="imginfo ==''">
            <div class="warm_title2" @click='moveToCameraAVG()'>打开摄像头</div>
            <div @click='captureAvg' class="warm_title2">拍照</div>
        </div>
        <div class="buddon flex" v-else>
            <div @click='reloadPage' class="warm_title2">重新拍照</div>
        </div>
       
        <div v-if="imginfo!==''"  class="flex">
            <img :src="imginfo" />
        </div>
        <div class="flex" v-else>
            <div class="video-wrap" >
                <video id="video" class="pic_video" playsinline autoplay x5-video-player-type="h5"></video>
            </div>
        </div>
        <canvas id="canvas" class="canvas_pic" style='margin: 0;padding: 0;'></canvas>
        <!-- <div>
            img绘制: <img v-if="imginfo!==''" :src="imginfo" />
        </div>
        <div>
            canvas绘制 : <canvas id="canvas" class="canvas_pic" style='margin: 0;padding: 0;'></canvas>
        </div> -->



    </div>
</body>
<script src="./jquery.js"></script>
<script>
    new Vue({
        el: '#app',
        data() {
            return {
                imginfo: ''
            }
        },
        methods: {

            // 头像相机

            moveToCameraAVG() {

                var self = this;

                if (navigator.mediaDevices === undefined) {

                    navigator.mediaDevices = {};

                }

                if (navigator.mediaDevices.getUserMedia === undefined) {

                    navigator.mediaDevices.getUserMedia = function (constraints) {

                        var getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia || navigator.oGetUserMedia;

                        if (!getUserMedia) {

                            return Promise.reject(new Error('getUserMedia is not implemented in this browser'));

                        }

                        return new Promise(function (resolve, reject) {

                            getUserMedia.call(navigator, constraints, resolve, reject);

                        });

                    }

                }

                if (window.stream) {

                    window.stream.getTracks().forEach(track => {

                        track.stop();

                    });

                }

                var constraints = window.constraints = {

                    audio: false,

                    video: {

                        sourceId: 'default',

                        facingMode: { exact: "user" }

                    }

                };

                navigator.mediaDevices.getUserMedia(constraints)

                    .then(function (stream) {

                        var video = document.getElementById('video');

                        try {

                            window.stream = stream;

                            video.srcObject = stream;

                        } catch (error) {

                            video.src = window.URL.createObjectURL(stream);

                        }

                        self.localMediaStream = stream;

                        video.play();

                    })

                    .catch(function (err) {

                        alert(err.name + ": " + err.message);

                    });

            },
            imageToCircle(picUrl) {
                let radius, diameter, canvas, ctx;
                let img = new Image()
                img.setAttribute('crossOrigin', 'anonymous'); // 解决图片跨域访问失败
                img.src = picUrl
                var video = document.getElementById('video');
                return new Promise((reslove) => {
                    img.addEventListener("load", () => {
                        let height = $('.video-wrap').height()
                        let width = $('.video-wrap').width()
                        radius = width / 2;
                        let canvas = document.createElement('canvas');
                        if (!canvas.getContext) { // 判断浏览器是否支持canvas,如果不支持在此处做相应的提示
                            console.log('您的浏览器版本过低,暂不支持。');
                            return false;
                        }
                        canvas.width = width;
                        canvas.height = height;

                        ctx = canvas.getContext("2d");
                        ctx.clearRect(0, 0, width, height);

                        // 描边
                        ctx.save();         //save和restore可以保证样式属性只运用于该段canvas元素
                        ctx.strokeStyle = '#ffffff';       //设置边线的颜色
                        ctx.lineWidth = 0;
                        ctx.beginPath();    //开始路径
                        //ctx.ellipse(radius, radius, radius - 5, 0, Math.PI * 2);      //画一个整圆.
                        const radiusX = width / 2
                        const radiusY = height / 2
                        ctx.ellipse(radiusX, radiusY, radiusX, radiusY, 0, 0, Math.PI * 2, true)

                        // 参数(从左到右):
                        // (起点x,起点y,半径x,半径y,旋转的角度,起始角,结果角,顺时针还是逆时针)
                        ctx.stroke();
                        //绘制边线

                        // 截圆形图
                        ctx.save();
                        ctx.beginPath();
                        ctx.ellipse(radiusX, radiusY, radiusX, radiusY, 0, 0, Math.PI * 2, true)
                        ctx.clip();

                        const videoRatio = video.videoHeight / video.videoWidth // 原视频比例
                        const domHeight = video.offsetHeight // 元素宽高
                        const domWidth = video.offsetWidth
                        let realW = 0, realH = 0;
                        if (domHeight / domWidth >= videoRatio) { // 宽度占满,计算高度
                            realW = domWidth
                            realH = domWidth * videoRatio
                        } else { // 高度占满,计算宽度
                            realH = domHeight
                            realW = domHeight / videoRatio
                        }

                        let x = realW - width, y = realH - height, swidth = width, sheight = height

                        ctx.drawImage(img, x / 2, y / 2, swidth, sheight, 0, 0, swidth, height);
                        ctx.restore();
                        // toDataURL()是canvas对象的一种方法,用于将canvas对象转换为base64位编码
                        let dataURL = canvas.toDataURL('image/png');
                        reslove(dataURL)

                    }, false)

                })
            },

            //停止摄像机

            stopCapture: function () {

                var video = document.getElementById('video');

                if (!video.srcObject) return

                let stream = video.srcObject

                let tracks = stream.getTracks();

                tracks.forEach(track => {

                    track.stop()

                })

            },

            // 头像照片

            async captureAvg() {

                var vm = this;

                var video = document.getElementById('video');

                var canvas = document.getElementById('canvas'), ctx = canvas.getContext('2d')
                const videoRatio = video.videoHeight / video.videoWidth // 原视频比例
                const domHeight = video.offsetHeight // 元素宽高
                const domWidth = video.offsetWidth
                let realW = 0, realH = 0;
                if (domHeight / domWidth >= videoRatio) { // 宽度占满,计算高度
                    realW = domWidth
                    realH = domWidth * videoRatio
                } else { // 高度占满,计算宽度
                    realH = domHeight
                    realW = domHeight / videoRatio
                }

                CWidth = realW,
                    CHeight = realH;//获取屏幕大小让canvas自适应
                canvas.width = CWidth;
                canvas.height = realH;

                if (vm.localMediaStream) {

                    ctx.drawImage(video, 0, 0, CWidth, CHeight);

                    var dataURL = canvas.toDataURL('image/jpeg'); //dataURL = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA'
                    const roundUrl = await this.imageToCircle(canvas.toDataURL('image/png'));
                    vm.imginfo = roundUrl;

                    // 停止摄像机

                    video.pause();

                    this.stopCapture();

                }

            },
            reloadPage(){
                location.reload()
            }
        }
    })
</script>

</html>

posted on 2022-08-29 15:54  myYouth  阅读(3111)  评论(0编辑  收藏  举报

导航