0%

图片上传与压缩


整理一下图片上传和图片压缩,以及canvas的一些小BUG

图片上传应该是老生常谈的问题了,今天记录一下,方便以后造轮子

上传图片一般分为两种,一种是文件流,一种是base64的数据

文件流

先是html的代码,样式就不写了,点击添加之后可以多图上传

1
2
3
4
5
6
7
8
9
10
11
12
13
<form method="post" enctype="multipart/form-data">
<div class="chooseImg">
<img src="../assets/1.png" alt="" />
<input type="file" name="photo" accept="image/*" />
</div>

<!--处理添加空白-->
<div id="upload">
<!--<input type="button" value="添加" />-->
<input type="button" value="添加" @click="addimg" />
<input type="submit" value="上传" />
</div>
</form>

接下来是逻辑部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
init() {
// 监听提交
$('form').submit(function(event) {
event.preventDefault();
var data = new FormData(this);
$.post({
url: 'http://127.0.0.1:3000/singlePic',
data: data,
//false:是告诉jquery不使用默认的数据类型
contentType: false,
processData: false,
success: function(resData) {
if(resData.code == 'success') {
console.log(resData);
}
},
error:function(resData){
console.log(resData);
}
})
})
},
// 点击添加后出现添加图片
addimg(){
// 获取最外层大框的div
var chooseImgDiv = document.querySelector('.chooseImg');
// 创建img标签元素
var img = document.createElement('img');
// src赋值图片
img.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAWYAAAFpCAYAAACvcILDAAAG2ElEQVR4nO3dsU5cBxiE0SxKBaVb137/5+EdKE0JsYlugbW2CIHZGe05zUqJrrRC6M+nFTs5Pf/wFwA1bi79BgB4zWEGKOMwA5RxmAHKOMwAZRxmgDJ/n/uH9/f3f3zoy5cvr14PDw8Pr1495znPec5zr93e3r68fv369ey//0kxA5Q5nfuCyVHM3759i78hgGunmAHKnP2M+dfPTADIUcwAZc5+xgzA5zj+WuNPn0woZoAyDjNA0M9i/t3fOB8cZoAyZw/zWy46AJ9DMQOUUcwAZRQzQJmz3/wD4HO85ZvVihmgjGIGCFLMAIOsywGUUcwAZazLAQRZlwMY5DADBFmXAxhkKwOgjGIGKKOYAcooZoAytjIAgmxlAAxSzABBihlgkHU5gDKKGaCMdTmAIOtyAIMcZoAg63IAg2xlAJRRzABlFDNAGcUMUMZWBkCQrQyAQYoZIEgxAwyyLgdQRjEDlLEuBxBkXQ5gkMMMEGRdDmCQrQyAMooZoIxiBiijmAHK2MoACLKVATBIMQMEKWaAQdblAMooZoAy1uUAgqzLAQxymAGCrMsBDLKVAVBGMQOUUcwAZRQzQBlbGQBBtjIABilmgCDFDDDIuhxAGcUMUMa6HECQdTmAQQ4zQJB1OYBBtjIAyihmgDKKGaCMYgYoYysDIMhWBsAgxQwQpJgBBlmXAyijmAHKWJcDCLIuBzDIYQYIsi4HMMhWBkAZxQxQRjEDlFHMAGVsZQAE2coAGKSYmXN8WfW9X1o9nU6vXiFJMQMMsi7HnMfHx5fXp6endz1/c/Nvj9zd3X3Ye4KPpJgByihmgCDrcgCDHGaAIOtyAINsZQCUUcwAZRQzQBnFDFDGVgZAkK0MgEGKGSBIMQMMspUBUEYxA5RRzABB1uUABjnMAEHW5QAG2coAKKOYAcooZoAyihmgjK0MgCBbGQCDFDNAkGIGGGQrA6CMYgYoo5gBgqzLAQxymAGCrMsBDLKVAVBGMQOUUcwAZRQzQBlbGQBBtjIABilmgCDFDDDIVgZAGcUMUEYxAwRZlwMY5DADBFmXAxhkKwOgjGIGKKOYAcooZoAytjIAgmxlAAxSzABBihlgkK0MgDKKGaCMYgYIsi4HMMhhBgiyLgcw6OxnzG/5DITLeX5+fnl9fHy88Du5jKenpw95/vv37x/xdubc3t6+vJ5Opwu/E35HMQOUUcyDjmL+v+V47a7153f8/ijmXooZoIytDIAgWxkAgxQzQJBiBhhkKwOgjGIGKKOYAYKsywEMcpgBgqzLAQw6e5jfctEB+ByKGaCMdblBxyrYzc11/nf1o1bhrvXnZ1Wu33X+ZgIUs5Ux6Cieu7u7C7+Tyzj+zyPvLeejlK/158dl2coAGKSYAYIUM8AgWxkAZRQzQBnFDBBkXQ5gkMMMEGRdDmCQdTmAMooZoIxiBiijmAHK2MoACLKVATBIMQMEKWaAQbYyAMooZoAyihkgyLocwCCHGSDIuhzAIFsZAGUUM0AZxQxQRjEDlLGVARBkKwNgkGIGCFLMAINsZQCUUcwAZRQzQJB1OYBBDjNAkHU5gEG2MgDKKGaAMooZoIxiBihjKwMgyFYGwCDFDBCkmAEG2coAKKOYAcooZoAg63IAgxxmgCDrcgCDbGUAlFHMAGUUM0AZxQxQxlYGQJCtDIBBihkgSDEDDLKVAVBGMQOUOT3/cOk3Af/F8Sv73l/d0+n06hWSrMsBDPJXGcxRvCxTzACDbGUAlFHMAGUUM0AZxQxQxl9lAATZygAYpJgBghQzwCDrcgBlFDNAGetyAEG2MgAGOcwAQW/5ZrXDDFDGVgZAGcUMUEYxA5RRzABlbGUABNnKABikmAGCFDPAIOtyAGUUM0AZ63IAQdblAAY5zABB1uUABtnKACijmAHKKGaAMooZoIytDIAgWxkAgxQzQJBiBhhkXQ6gjGIGKGNdDiDIuhzAIIcZIMi6HMAgWxkAZRQzQBnFDFBGMQOUsZUBEGQrA2CQYgYIUswAg6zLAZRRzABlrMsBBFmXAxjkMAMEWZcDGGQrA6CMYgYoo5gByihmgDK2MgCCbGUADFLMAEGKGWCQdTmAMooZoIx1OYAg63IAgxxmgCDrcgCDbGUAlFHMAGUUM0AZxQxQxlYGQJCtDIBBihkgSDEDDLIuB1BGMQOUsS4HEGRdDmCQwwwQZF0OYJCtDIAyihmgjGIGKKOYAcrYygAIspUBMEgxAwQpZoBB1uUAyihmgDLW5QCCrMsBDPrjX2Ucl/133wI8Lv6vl99znvOc5zz3tufOUcwAZXzGDFBGMQOUcZgByjjMAGUcZoAyDjNAGYcZoIzDDFDmHz0CkE/nMDSkAAAAAElFTkSuQmCC';
// 添加子元素
chooseImgDiv.appendChild(img);
// 创建input
var input = document.createElement('input');
// 赋值input为file类型,name为photo
input.type = 'file';
input.name = 'photo';
//获取任意类型的图片
input.accept = 'image/*';
//输入的字段是否实现自动完成功能
input.autocomplete = 'off';
//添加到父级节点中
chooseImgDiv.appendChild(input);
chooseImgDiv.appendChild(document.createTextNode(' '));

this.addEvent();
this.addImgInput();


},
// 给图片添加点击事件
addEvent() {
//遍历找到img兄弟节点--> file
var imgs = document.getElementsByTagName('img');
// 点击图片后,将事件传递给下一个兄弟节点,也就是input
for(var i = 0; i < imgs.length; i++) {
imgs[i].onclick = function() {
this.nextElementSibling.click();
}
}
},
// 判断上传文件的类型
addImgInput(){
// 获取所有的类型为file的input
var inputs = document.querySelectorAll('.chooseImg input[type=file]');
// 添加所有input的监听状态onchange
for(var i = 0; i < inputs.length; i++) {
// 当input发生改变时,也就是上传图片了
inputs[i].onchange = function() {
console.log(this.files);
// 获取图文件
var file = this.files[0];
//判断文件是否是image类型
if(file.type.startsWith('image')) {
// 将img的src赋值为这张图片
this.previousElementSibling.src = URL.createObjectURL(file);
}
}
}
}

VUE写的话就在初始化一下

1
2
3
4
5
mounted() {
this.init();
this.addEvent();
this.addImgInput()
},

数据流

同样是监听一下input改变

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
init() {
// 获取所有的类型为file的input
var inputs = document.querySelectorAll('input[type=file]');
// 添加所有input的监听状态onchange
for(var i = 0; i < inputs.length; i++) {
// 当input发生改变时,也就是上传图片了
inputs[i].onchange = function() {
var file = document.querySelector('input').files[0];
var reader = new FileReader();
// 文件读取成功完成时触发
reader.onload = function(e){
// onload事件的回调函数接受一个事件对象,该对象的target.result就是文件的内容
console.log(e.target.result)
// 这里的e.target.result就已经是base64数据流了
document.querySelector('img').src = e.target.result;
};
reader.readAsDataURL(file);
}
}
}

图片压缩

图片压缩也是我们经常需要用到的,每行代码都有注释,直接上代码,不多说

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
compress(res, index) {
var preview = document.getElementById("imgPreview");
// new Image()是可以用来做预加载的
var img = new Image();
//用来设置压缩比例,越低,越失真
var maxHeight = 300;
//要先确保图片完整获取到,这是个异步事件
img.onload = ()=> {
// 创建canvas标签
var canvas = document.createElement('canvas');
// 创建 context对象,getContext("2d")对象是内建的 HTML5 对象,拥有多种绘制路径、矩形、圆形、字符以及添加图像的方法。
var ctx = canvas.getContext('2d');
// 判断是否需要压缩
if(img.height > maxHeight) {
img.width *= maxHeight / img.height;
img.height = maxHeight;
}
// 重新赋值
canvas.height = img.height;
canvas.width = img.width;
// clearRect() 方法清空给定矩形内的指定像素。要清除的矩形左上角的 x 坐标,要清除的矩形左上角的 y 坐标,要清除的矩形的宽度,以像素计,要清除的矩形的高度,以像素计
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 在canvas绘制前填充白色背景,否则jpeg图片的透明背景会变成黑色,在clearRect()方法之后,否则会被清空
ctx.fillStyle = "#fff";
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 在画布上定位图像,并规定图像的宽度和高度:context.drawImage(img,x,y,width,height);
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
//转换图片为dataURL(图片格式,图片质量)
// 这是一个功能函数,FileReader对象也有类似的方法,比如.readAsDataURL(),canvas正巧拥有.toDataURL()方法。
// canvas.toDataURL([type, encoderOptions]);参数type指定图片类型,如果指定的类型不被支持则以默认值image/png替代,encoderOptions可以为image/jpeg 或 image/webp类型的图片设置图片质量
var dataUrl = canvas.toDataURL('image/jpeg', 1);
// 创建标签
var div = document.createElement('div');
var img1 = document.createElement('img');
//把得到的base64赋值到img标签显示
img1.src = dataUrl;
div.appendChild(img1);
preview.appendChild(div);
this.urlArr.push(dataUrl);
}

// 在img对象中添加src,否则图片不显示
img.src = res;
}

调用也很简单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
init() {
var _this = this;
// 获取所有的类型为file的input
var inputs = document.querySelectorAll('input[type=file]');
// 添加所有input的监听状态onchange
for(var i = 0; i < inputs.length; i++) {
// 当input发生改变时,也就是上传图片了
inputs[i].onchange = function() {
var file = document.querySelector('input').files[0];
var reader = new FileReader();
// 文件读取成功完成时触发
reader.onload = function(e) {
// onload事件的回调函数接受一个事件对象,该对象的target.result就是文件的内容
var temp = i;
// 这里是调用压缩
_this.compress(e.target.result, temp);
};
reader.readAsDataURL(file);
}
}

},

基本上图片上传的文件流,数据流,压缩就是这样的了,以后遇到具体问题再具体分析吧

服务端的代码

服务端接受文件流和数据流的方法是不同的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
// 这些就不介绍了,可以看我专门介绍node的博客
var express = require('express');
var bodyParser = require('body-parser');
var fs = require('fs');
var multer = require('multer');
var form = multer();
var app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
// 跨域设置
app.all('*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
res.header("X-Powered-By",' 3.2.1')
res.header("Content-Type", "application/json;charset=utf-8");
next();
});

app.use(express.static('wwwroot'));

//创建一个存储对象
var storage = multer.diskStorage({
// 目录路径,存储位置
destination:'./uploadIMG',
// 设置文件的名称
filename:function(req,file,cb){
// cb(null,Date.now()+'.jpg');
console.log(file.originalname);
cb(null,file.originalname);
}
})

//让存储对象来接收数据
//storage这个对象来接受数据
var upload = multer({storage:storage})

app.post('/singlePic',upload.array('photo'),function(req,res){
upload.array('photo')
console.log(upload.array('photo'))

res.send({
code:'success',
message:'成功'
})
})

// 接受数据流
app.post('/base64Img',function(req,res){
console.log(req.body)
//接收前端POST过来的base64
var imgData = req.body.imgMsg;
//过滤data:URL
var base64Data = imgData.replace(/^data:image\/\w+;base64,/, "");
var dataBuffer = new Buffer(base64Data, 'base64');
fs.writeFile("uploadIMG/image.jpeg", dataBuffer, function(err) {
if(err) {
res.send(err)
}else {
res.send({
code:'success',
message:'成功'
})
}
});
})


app.post('/hello',function(req,res){
console.log(req.body)
res.send({
code:'success',
message:'你好陈先生'
})
})

app.listen(3000,function(){
console.log('服务启动成功,端口号3000')
})

以上就是我对上传图片的一些理解,如果文章由于我学识浅薄,导致您发现有严重谬误的地方,请一定在评论中指出,我会在第一时间修正我的博文,以避免误人子弟。

-------------本文结束感谢您的阅读-------------
没办法,总要恰饭的嘛~~