有时候,我们不想通过上传本地图片的方式上传图片,而是通过相机拍照,将这个拍照后的图片直接上传到服务器上,不需要保存到本地。
比如,用video模拟一个摄像头,通过webrtc调用摄像头的方式拍一张照,然后通过canvas通过getContext('2d')获取的绘图对象CanvasRenderingContext2DdrawImage(video, x, y, width, heigth)方法将video图像通过canvas直接画到html页面上,用来呈现拍照后的结果。
通常的做法是用

<input type="file"/>

的方式上传图片的。但这种方式是要求图片具体存在的,本地或者url路径上的。
现在我们来通过canvas的toDataURL或者toBlob方法、File对象、FormData对象来通过ajax上传图片。

<video id="video"></video>
<canvas id="canvas"></canvas>

<script type="text/javascript">
    // 调用摄像头的代码省略...

    let video = document.querySelector('#video')
    let canvas = document.querySelector('#canvas')

    let context = canvas.getContext('2d')
    context.drawImage(video, 0, 0, 300, 150)    // 将video标签的图片画到canvas上

    // 正片开始
    // 通过canvas调用toBlob方法获取blob对象,传入一个回调函数,这个回调函数的参数就是blob对象
    let s = canvas.toBlob(function (blob) {
        /*
         * 注意第一个File的构造方法第一个参数必须要用[]包起来,表明这是一个数组
         * 第二个参数是这个文件名
         * 第三个参数是选项,其中通过type指定这个文件的mime值
         */
        let file2 = new File([blob], 'a.jpg', {type: 'image/jpg'})

        // ajax上传文件不能像上传普通对象那样,得用上FormData
        let formData = new FormData()
        formData.append('file', file2)

        $.ajax({
            url: '/a',    // 后台接口
            type: 'POST',
            processData: false,    // processData和contentType必须指定为false
            contentType: false,
            cache: false,
            data: formData,
            success(res) {
                console.log("上传完成!")
            }
        })
    });
</script>

第二种方式,通过base64转码,这里只看js代码
这是canvas调用toDataURL方法将图片base64编码

let base64 = canvas.toDataURL();    // 同样通过canvas的toDataURL方法将canvas图片Base64编码

let bstr = atob(base64.split(',')[1]);    // atob是将base64编码解码,去掉data:image/png;base64,部分
let n = bstr.length;
let u8arr = new Uint8Array(n);

while (n--) {
    u8arr[n] = bstr.charCodeAt(n);
}

// 写法同上
let file2 = new File([u8arr], 'a.jpg', {type: 'image/jpg'})

let formData = new FormData()
formData.append('file', file2)
console.log(formData)

$.ajax({
    url: '/a',
    type: 'POST',
    processData: false,
    contentType: false,
    cache: false,
    data: formData,
    success(res) {
        console.log("上传完成!")
    }
})

其上两种写法皆可
下面是后台代码,这里用的是java

@Controller
public class IndexCtronller {

    @RequestMapping(value = "/a", method = RequestMethod.POST)
    public ResponseEntity index(MultipartFile file) {    // 通过MultipartFile对象接收文件
        String contextPath = "C:\\Users\\dagger\\Desktop";    // 上传文件路径
        File file1 = new File(contextPath, "a.jpg");
        try {
            file.transferTo(file1);    // 将文件保存到服务器桌面
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}
02-10 12:28