HTML5唤起摄像头拍摄、裁剪并上传

页面唤起相机拍摄、保存、修改尺寸以及上传

近期有个需求,需要在微信中打开移动端页面,让用户在页面中唤起相机进行人脸拍摄,用于身份认证或满足其他业务上的需要。同时要保证上传图像不能过大,需要对图片进行裁剪再上传

过程

  1. 利用input的acceptcapture这两个属性来限定接收类型和相机方向(前后摄像)
  2. 拍摄获取的图片和普通文件上传一样利用FileReader进行读取处理
  3. 设置到图片目标大小,再用canvas.drawImage读取图片,最后利用canvas.toDataURL转化为base64

input唤起相机

  • accept限定上传文件必须是照片类型image/*
  • capture设置为user,指定优先使用前置摄像头(安卓部分低版本不会生效,默认打开后置摄像头)

利用FileReader进行读取处理

            function handleTakePhoto(e) {
                // 读取照片
                if (this.files && this.files[0]) {
                    const fileData = this.files[0],
                        fileReader = new FileReader();
                    // 转化为base64
                    fileReader.readAsDataURL(fileData);
                    fileReader.onload = (e) => {
                       // fileReader.result可以获取到base64图片链接
                    };
                }
            }

利用canvas修改图片尺寸

  1. new一个Image实例并加载图片,再设置图片宽高
  2. 设置canvas大小与目标尺寸一致,利用drawImage绘制图片,最后利用toDataURL来转化回base64
  • 注:此处需等待图片加载完成才能绘制到canvas上,因此需要用promise来做异步处理
            function changePhotoSize(imgData) {
                const $canvas = document.querySelector(".used-for-changing-photo-size"),
                    context = $canvas.getContext("2d"),
                    image = new Image(),
                    // 设置目标宽度(高度随原比例变化)
                    targetWidth = 480;
                let aspectRatio = 1;
                image.src = imgData;
                return new Promise((resolve, reject) => {
                    image.onload = function () {
                        aspectRatio = (this.height / this.width).toFixed(3);
                        this.height = aspectRatio * targetWidth;
                        this.width = targetWidth;
                        $canvas.setAttribute("width", this.width + "px");
                        $canvas.setAttribute("height", this.height + "px");
                        context.drawImage(this, 0, 0, this.width, this.height);
                        resolve($canvas.toDataURL());
                    };
                    image.onerror = (e) => {
                        reject(e);
                    };
                });
            }

完整代码

<!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>h5摄像Demo</title>
    <style>
        .img-container {
            display: flex;
            justify-content: center;
            align-items: center;
            overflow: hidden;
        }

        .img-container img {
            max-width: 100vw;
            margin-bottom: 20px;
            height: auto;
        }

        .call-camera-container {
            position: relative;
            width: 50px;
            margin: 0 auto;
            text-align: center;
            overflow: hidden;
        }

        .call-camera-container button {
            width: 100%;
            height: 100%;
            line-height: 30px;
        }

        .call-camera-container input {
            position: absolute;
            left: 0;
            top: 0;
            right: 0;
            bottom: 0;
            opacity: 0;
        }

        canvas.used-for-changing-photo-size {
            visibility: hidden;
        }
    </style>
</head>

<body>
    <!-- 拍摄相片 -->
    <div class="img-container">
        <img src="http://iph.href.lu/375x375" alt="占位" />
    </div>
    <!-- 唤起按钮 -->
    <div class="call-camera-container">
        <button>📷</button>
        <input type="file" accept="image/*" capture="user" />
    </div>
    <!-- 用于处理图像大小 -->
    <canvas class="used-for-changing-photo-size"></canvas>
    <script>
        window.addEventListener("load", () => {
            const $camera = document.querySelector("input");
            // 部分机型默认设置会不生效,需要手动再赋值
            $camera.setAttribute("capture", "user");
            $camera.onchange = handleTakePhoto;
            /**
             * 处理照片数据
             */
            function handleTakePhoto(e) {
                // 读取照片
                if (this.files && this.files[0]) {
                    const fileData = this.files[0],
                        fileReader = new FileReader();
                    // 转化为base64
                    fileReader.readAsDataURL(fileData);
                    fileReader.onload = (e) => {
                        changePhotoSize(fileReader.result).then(res => {
                            const $img = document.querySelector(".img-container img");
                            $img !== null && ($img.src = res);
                        }).catch(e => { })
                    };
                }
            }

            /**
             * 调整照片大小
             * @param {string} imgData
             */
            function changePhotoSize(imgData) {
                const $canvas = document.querySelector(".used-for-changing-photo-size"),
                    context = $canvas.getContext("2d"),
                    image = new Image(),
                    // 设置目标宽度(高度随原比例变化)
                    targetWidth = 480;
                let aspectRatio = 1;
                image.src = imgData;
                return new Promise((resolve, reject) => {
                    image.onload = function () {
                        aspectRatio = (this.height / this.width).toFixed(3);
                        this.height = aspectRatio * targetWidth;
                        this.width = targetWidth;
                        $canvas.setAttribute("width", this.width + "px");
                        $canvas.setAttribute("height", this.height + "px");
                        context.drawImage(this, 0, 0, this.width, this.height);
                        resolve($canvas.toDataURL());
                    };
                    image.onerror = (e) => {
                        reject(e);
                    };
                });
            }
        });
    </script>
</body>

</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值