html5中调用摄像头拍照并上传(附绕过https的想法)

6,923 阅读2分钟

html5调用摄像头

html5调用摄像头的api是window.navigator.mediaDevices.getUserMedia({/*config*/});,这个api可以同时调用相机和麦克风,并且可以设置相机的码率和分辨率。

使用video标签,将相机的画面实时展示在页面中。

拍照功能用canvas实现,先获取context画笔,调用drawImage方法,将video标签中的画面置入canvas

使用formData上传,使用canvas.toBlob,将图像转为blob上传服务器

代码如下:

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
    />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
  </head>
  <body>
    <p id="message"></p>
    <p id="error"></p>
    <video style="width: 320px;height: 180px;"></video>
    <canvas width="320" height="180 "></canvas>
    <button id="take">take</button>
    <button id="upload">upload</button>
    <input style="display: none;" type="file" accept="image/*" />
  <script src="./index.js"></script>
  </body>
</html>

index.js

document.querySelector("#message").innerHTML =
    "getUserMedia" in navigator.mediaDevices
        ? "api is exist"
        : "api is not exist";

const constraints = {
    audio: false,
    video: {
        width: 180,
        height: 320,
        facingMode: { exact: "environment" }
    }
};
window.navigator.mediaDevices
      .getUserMedia(constraints)
      .then(mediaStream => {
          const video = document.querySelector("video");
          video.srcObject = mediaStream;
          video.onloadedmetadata = e => {
              video.play();
          };
      })
      .catch(err => {
          document.querySelector("#error").innerHTML = err.name + ": " + err.message;
      });
const video = document.querySelector("video");
const canvas = document.querySelector("canvas");
const take = document.querySelector("#take");
const upload = document.querySelector("#upload");

const drawImage = () => {
    canvas.getContext("2d").drawImage(video, 0, 0, canvas.width, canvas.height);
};
const uploadImg = () => {
    canvas.toBlob(blob => {
        const formData = new FormData();
        formData.append("img", blob);
        formData.append("123", "123");
        fetch("/api/upload", {
            method: "POST",
            body: formData
        })
            .then(response => response.json())
            .catch(error => console.error("Error:", error))
            .then(response => console.log("Success:", response));
    });
};
take.addEventListener("click", drawImage);
upload.addEventListener("click", uploadImg);

需要注意的是调用相机需要https 我写的demo,配置了后台上传和https github

绕过https使用摄像头的想法

因为业务需要使用摄像头拍账单,但是公司的后台管理系统做不了https,所以研究后萌生了使用谷歌浏览器的扩展插件实现绕过https的功能,现在已经在业务中使用了

Chrome插件(扩展)开发全攻略

谷歌扩展分了background.js和content.js background顾名思义,就是在浏览器后台运行的,域名也是以chrome-extension开头的,不能操作当前页面dom,能使用chrome的api

chrome-extension://xxxx/background.html 在这个页面,调用摄像头是没有任何安全限制的

content就是在当前访问页面中执行的js,是可以操作dom的,但是只能使用chrome部分的api

思路就是,在content.js里通过chrome的api将消息传递给background.js,background.js中进行摄像头的调用,但是好像chrome的消息传递是不能带对象的,所以我在backgournd.js中将图片base64的字符串传给了content.js,再将图片放在页面的img标签里