其实就是利用canvas的 toDataURL,图片压缩不支持png会越压越大
图片压缩支持image/jpeg, Chrome支持image/webp
压缩前后端都能实现,这里说一下前端压缩
toDataURL语法
canvas.toDataURL(type, encoderOptions);
// type 可选,图片格式,默认是 image/png,
// encoderOptions 可选,图片质量 0 - 1,如果超出取值范围默认值0.92
toDataURL 用法例子
var base64 = canvasEl.toDataURL('image/jpeg', .5);
console.log(base64);
前端代码, 二进制上传,非base64
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>文件上传</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="//cdn.bootcss.com/axios/0.16.2/axios.min.js"></script>
</head>
<body>
<div id="app">
<input type="file" id="file">
</div>
<script>
// base64 转换blob对象用于上传
function dataURItoBlob(dataurl) {
var arr = dataurl.split(',');
var mime = arr[0].match(/:(.*?);/)[1];
var bstr = window.atob(arr[1]);
var n = bstr.length;
var u8arr = new Uint8Array(n);
while(n--) u8arr[n] = bstr.charCodeAt(n);
return new Blob([u8arr], {type: mime});
}
document.getElementById('file').onchange = function () {
var file = this.files;
if( file.length == 0 ) return;
var fileReader = new FileReader();
console.log(`压缩前字节大小:${file[0].size}`);
fileReader.readAsDataURL(file[0]);
fileReader.onload = function () {
var img = new Image();
img.src = this.result;
img.onload = function () {
// 创建canvas 实现压缩
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
ctx.drawImage(img, 0, 0);
// 压缩类型, 压缩比例 0 - 1, 实测20MB压缩到 7MB多, 生成base64
var url = canvas.toDataURL(file[0].type, .5);
// base64 转换blob对象
var blob = dataURItoBlob(url);
console.log(`压缩后字节大小:${blob.size}`);
// 创建 FormData 用于ajax上传
var formData = new FormData();
formData.append('file', blob);
// Ajax发送给后端
axios({
method: 'POST',
url: '/upload',
data: formData,
})
.then(res => {
console.log(res)
})
.catch(e => {
console.log(e)
})
}
}
}
</script>
</body>
</html>
Node.js接收
其实跟普通form表单接收是一样的
var express = require('express')
var app = express();
var formidable = require('formidable');
var fs = require('fs')
var path = require('path')
var crypto = require('crypto')
var md5 = str => {
return crypto.createHash('md5').update(str.toString()).digest('hex')
}
app.use((req, res, next) => {
// 不同源,设置跨域头
res.set({
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST,GET',
'Access-Control-Allow-Credentials': true
})
next();
})
app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'ejs')
app.get('/', (req, res) => {
res.render('index')
})
// 这个才是主要的
app.post('/upload', (req, res) => {
var form = new formidable.IncomingForm();
form.uploadDir = './upload';
form.parse(req, function (err, fields, files) {
var suffix = {
'image/jpeg': '.jpg',
'image/png': '.png',
}
fs.renameSync(files.file.path, `./upload/${md5(Date.now())}${suffix[files.file.type]}`)
res.json({
files
})
});
})
app.listen(3000)