美文网首页
JS调用摄像头拍照,ajax将图片以base64上传,Java解

JS调用摄像头拍照,ajax将图片以base64上传,Java解

作者: 天降小纸箱 | 来源:发表于2021-07-14 17:08 被阅读0次

    本文首先实现js调用摄像头,将视频画面显示在界面上,同时拍照功能(本质为截取当前视频画面),然后将截图通过ajax以base64字符串的形式上传,并在后台将base64转换成图片。

    本文主要内容:
    一. JS调用摄像头实现拍照并上传springboot后台
    二:springboot后台将base64数据转为图片格式并保存,记录常见的错误

    一. JS调用摄像头实现拍照并上传springboot后台

    1. 在HTML 页面中添加3个按钮,一个video播放器,一个显示拍照截图的canvas,代码如下:
    <button type="button" class="btn btn-primary" onclick="openCamera()">打开摄像头</button>
    
    <button type="button" class="btn btn-success" onclick="snap()">开始&nbsp;拍照</button>
    
    <button type="button" class="btn btn-info" onclick="closeCamera()">关闭摄像头</button>
    
    
    <video id="video" width="400px" height="400px" autoplay="autoplay"></video>
    
    <canvas id="canvas" width="300px" height="300px"></canvas>
    
    1. 在js中实现三个按钮的点击函数:
    // 视频控件
    let video = document.getElementById("video");
    let buffer; // 视频流缓冲
    /**
     * 开启摄像头,在 视频中
     * @returns {number}
     */
    function openCamera() {
        console.log("开启摄像头");
        // 兼容性处理
        navigator.getUserMedia = navigator.getUserMedia ||
            navigator.webkitGetUserMedia ||
            navigator.mozGetUserMedia;
        if (navigator.getUserMedia) {
            navigator.getUserMedia({
                    audio: true, video: {width: 256, height: 256}
                }, function (stream) {
                    console.log("getUserMedia:", stream)
                    buffer = stream;
                    //var src = window.URL && window.URL.createObjectURL(buffer) || stream;
                    video.muted = true; // 设置视频静音
                    video.srcObject = buffer;
                    video.onloadedmetadata = function (e) {
                        video.play();
                    };
                },
                function (err) {
                    alert('哦哦……哪里错了呢?是不是没有摄像头啊?');
                    console.log(`哦哦,发生了错误:${err.name}`);
                }
            );
        } else {
            console.log('getUserMedia not supported');
            alert('嗯哼,浏览器不支持 getUserMedia 呢,换最新版火狐浏览器试试!');
        }
        return 0
    }
    
    /**
     * 关闭摄像头
     */
    function closeCamera() {
        console.log("关闭摄像头");
        buffer && buffer.getVideoTracks()[0].stop(); // 暂停当前播放的音视频
        buffer = null;
    }
    
    /**
     * 视频流截图,并传输数据
     */
    function snap() {
        console.log('开始拍照');
        if (!buffer) {
            alert('请打开摄像头!');
            console.log('没有视频流');
            return
        }
        let canvas = document.getElementById("canvas");
        let ctx = canvas.getContext('2d');
        ctx.drawImage(video, 0, 0, 256, 256);
        // 将图片数据转换为 base64
        let scan_data = canvas.toDataURL();
    
        $.ajax({
            type: 'post',
            data: scan_data,
            url: "/snap_data",
            contentType: false,
            processData:false,
            success: function (data) {
                console.log(data.toString())
            },
            error: function (xmlhttprequest) {
                console.log(xmlhttprequest);
            }
        })
    }
    
    1. 如上 function snap() 函数中,实现拍照功能的同时,通过
    // 将图片数据转换为 base64
        let scan_data = canvas.toDataURL();
    

    语句可将图片转为base64,再通过ajax传输到后台。
    在此处中,我将传输路径定义为 "/snap_data",在后台接收数据格式应为 String

    1. 可手动验证base64数据格式是否正确,通过
      console.log(scan_data);
      打印base64值,再通过在线网站解析base64可看见正确解析为图片

    二:springboot后台将base64数据转为图片格式并保存,记录常见的错误

    1.新建Controller类,定义路径为 "/snap_data"

    1. base64的数据格式为
    data:image/png;base64,iVBORw0KGgoAAAANSUhXXXX...
    

    其中,data:image/png;base64 为头部信息,我们使用Java转码时需要去掉此部分信息,否则会导致图片生成之后无法查看
    故,先将base64字符串拆分成头部和内容两部分,其中去掉内容中一些没必要的空格,否则有可能导致图片无法查看

    String[] strings = base64string.split(","); // 将base64 头部信息摘出来
    System.out.println(strings.length + "\ttype: " + strings[0]);
    String imgStr = strings[1].replaceAll(" ",""); // 去掉多余的空格
    
    1. 获取文件类型函数:
    /**
        *
        * @param type
        * @return
        */
       public static String GetBaseImgType(String type) {
           String imgType = BaseImgTypeERR;
           switch (type) {
               case "data:image/jpg;base64":
                   imgType = BaseImgTypeJpg;
                   break;
               case "data:image/jpeg;base64":
                   imgType = BaseImgTypeJpeg;
                   break;
               case "data:image/png;base64":
                   imgType = BaseImgTypePng;
                   break;
               default:break;
           }
           return imgType;
       }
    
    1. 获取项目绝对路径,并在项目下新建文件夹保存图片
    /**
         * 保存图片文件的绝对路径
         *
         * @param fileName
         * @return
         * @throws IOException
         */
        public static File GetLocalIMGPath(String fileName) throws IOException {
            if (null == fileName || fileName.isEmpty()) {
                System.out.println("file name is empty!");
                return null;
            }
    
            File directory = new File(""); // 定义当前路径
            String path = directory.getCanonicalPath();  // 获取当前路径
    
            File file_dir = new File(path, "images"); // 文件存放路径
            if (!file_dir.exists()) {
                file_dir.mkdirs();
            }
    
    //        File imageFile = new File(file_dir, fileName).getAbsoluteFile();
    //        File local_path = imageFile.getAbsoluteFile();
    //        System.out.println(imageFile);
    
            return new File(file_dir, fileName).getAbsoluteFile();
        }
    
    1. base64字符串转图片并保存
    /**
         * 将 base64 字符串转换成图片
         *
         * @param base64string
         * @param imgPath
         * @return
         * @throws IOException
         */
        public static boolean Base64ToImg(String base64string, File imgPath) throws IOException {
    //        图像不为空
            if (null == base64string || base64string.isEmpty())
                return false;
            BASE64Decoder decoder = new BASE64Decoder();
            OutputStream outputStream = null;
            try {
                // 解码
                byte[] bytes = decoder.decodeBuffer(base64string);
                for (int i = 0; i < bytes.length; i++) {
                    if (bytes[i] < 0) { // 调整异常数据
                        bytes[i] += 256;
                    }
                }
                outputStream = new FileOutputStream(imgPath);
                outputStream.write(bytes);
                outputStream.flush();
                outputStream.close();
                System.out.println(imgPath);
                return true;
            } catch (IOException e) {
                e.printStackTrace();
                return false;
            }
        }
    
    1. Controller中完整调用:
    @Controller
    public class FileController {
    
        @RequestMapping("/snap_data")
        @ResponseBody
        public String getSnapData(@RequestBody String base64string) throws IOException {
            String[] strings = base64string.split(","); // 将base64 头部信息摘出来
            System.out.println(strings.length + "\ttype: " + strings[0]);
            String imgStr = strings[1].replaceAll(" ",""); // 去掉多余的空格
            // 文件命名: img_snap_时间戳.xxx
            String imgName = Base64Utils.BaseImgName + System.currentTimeMillis() +
                    Base64Utils.GetBaseImgType(strings[0]);
            if (imgName.endsWith(".err")){
                System.out.println("图片类型格式错误");
                return "false";
            }
            File imgPath = Base64Utils.GetLocalIMGPath(imgName);
            boolean img = Base64Utils.Base64ToImg(imgStr, imgPath);
    //        boolean img = Base64Utils.ConvertBase64ToImg(base64string, imgPath);
            System.out.println(img);
            return "success";
        }
    }
    
    常见导致图片写入无法查看的错误:
    1. base64数据没有拆分头部
    2. base64主体部分没有去掉空格

    相关文章

      网友评论

          本文标题:JS调用摄像头拍照,ajax将图片以base64上传,Java解

          本文链接:https://www.haomeiwen.com/subject/ugpypltx.html