js前端js压缩图片代码实战jquery+canvas压缩图片
效果还是很让人满意,因为不仅仅是压缩那么简单,考虑到现在大多数手机随便拍张照片都有可能5-15M的,用户上传有的时候可不管你大小和服务器传输性能、存储性能,所以很难保障上传过程不出现什么问题,那么这个代码极大程度考虑兼容性,实测10M图片随便上传,尽可能保障分辨率的同时按照阶梯层度保障画质(500k-2M时画质优先,其它的太大了就画质一般,但好歹能随便上传且大小较低!)
结合参考资料,我加入了根据文件大小分配不同的压缩率,而不是写死每张图片压缩至10%
参考资料转载原文:
在IOS中,canvas绘制图片是有两个限制的:
首先是图片的大小,如果图片的大小超过两百万像素,图片也是无法绘制到canvas上的,调用drawImage的时候不会报错,但是你用toDataURL获取图片数据的时候获取到的是空的图片数据。
再者就是canvas的大小有限制,如果canvas的大小大于大概五百万像素(即宽高乘积)的时候,不仅图片画不出来,其他什么东西也都是画不出来的。
应对第一种限制,处理办法就是瓦片绘制了。瓦片绘制,也就是将图片分割成多块绘制到canvas上,我代码里的做法是把图片分割成100万像素一块的大小,再绘制到canvas上。
而应对第二种限制,我的处理办法是对图片的宽高进行适当压缩,我代码里为了保险起见,设的上限是四百万像素,如果图片大于四百万像素就压缩到小于四百万像素。四百万像素的图片应该够了,算起来宽高都有2000X2000了。
如此一来就解决了IOS上的两种限制了。
除了上面所述的限制,还有两个坑,一个就是canvas的toDataURL是只能压缩jpg的,当用户上传的图片是png的话,就需要转成jpg,也就是统一用canvas.toDataURL('image/jpeg', 0.1) , 类型统一设成jpeg,而压缩比就自己控制了。
另一个就是如果是png转jpg,绘制到canvas上的时候,canvas存在透明区域的话,当转成jpg的时候透明区域会变成黑色,因为canvas的透明像素默认为rgba(0,0,0,0),所以转成jpg就变成rgba(0,0,0,1)了,也就是透明背景会变成了黑色。解决办法就是绘制之前在canvas上铺一层白色的底色。
javascript1
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<!--新增库-->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<!--新增库-->
<title>图片上传</title>
<script language="JavaScript">
<!--
$(document).ready(function(){
$(":file").change(function(){
if (CheckInputFile(this)) {
$("#form1").hide();
//$("#form1").submit();
compressAndUploadImage('imgfile');
}
});
});
function CheckInputFile(file) {
var ExtIn = ["jpg", "gif", "bmp", "png"]; //允许后缀名
var ExtOut = []; //禁止后缀名
//检测变量
var bCheck = true;
//空值、文件数限制、后缀名
if (!$(file).val()) {
bCheck = false; alert("请选择一个文件");
} else if (!!ExtIn.length && !RegExp("\.(" + ExtIn.join("|") + ")$", "i").test($(file).val())) {
//检测是否允许后缀名
bCheck = false; alert("只允许上传" + ExtIn.join(",") + "文件");
} else if (!!ExtOut.length && RegExp("\.(" + ExtOut.join("|") + ")$", "i").test($(file).val())) {
//检测是否禁止后缀名
bCheck = false; alert("只允许上传" + ExtIn.join(",") + "文件");
}
return bCheck;
}
//-->
</script>
</head>
<body>
<form id="form1" name="form1" method="post" action="upfile.asp" enctype="multipart/form-data" >
<input type="hidden" name="uptype" value="<%=uptype%>" />
<a class="files" href="javascript:void(0);"><input type="file" id="imgfile" name="file1" class="upimginput" value="" /></a>
</form>
<div id="upLoading">文件上传中...</div>
<script>
function compressAndUploadImage(fileInputId) {
var fileInput = document.getElementById(fileInputId);
var file = fileInput.files[0];
if (!file.type.match(/image.*/)) {
alert('请选择一个图片文件!');
return;
}
var reader = new FileReader();
reader.onload = function (readerEvent) {
var image = new Image();
image.onload = function (imageEvent) {
if (image.width <= 1000 && image.height <= 1000 && file.size <= 500 * 1024) {
uploadFile(file); // 直接上传原文件
} else {
//关键压缩代码开始
var initSize = image.src.length;
var width = image.width;
var height = image.height;
// 如果图片大于四百万像素,计算压缩比并将大小压至400万以下
var ratio;
if ((ratio = width * height / 4000000) > 1) {
ratio = Math.sqrt(ratio);
width /= ratio;
height /= ratio;
} else {
ratio = 1;
}
// 如果宽度或高度大于800px,等比缩放到800以下
//可选,这样确保图片尺寸不会特别大,因为网页上用不着特别大
/*
if (width > 800 || height > 800) {
var maxDim = Math.max(width, height);
var scale = 800 / maxDim;
width *= scale;
height *= scale;
}
*/
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
canvas.width = width;
canvas.height = height;
// 铺底色
ctx.fillStyle = "#fff";
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 如果图片像素大于100万则使用瓦片绘制
var count;
if ((count = width * height / 1000000) > 1) {
count = ~~(Math.sqrt(count) + 1); // 计算要分成多少块瓦片
// 计算每块瓦片的宽和高
var nw = ~~(width / count);
var nh = ~~(height / count);
var tCanvas = document.createElement('canvas');
var tctx = tCanvas.getContext('2d');
tCanvas.width = nw;
tCanvas.height = nh;
for (var i = 0; i < count; i++) {
for (var j = 0; j < count; j++) {
tctx.clearRect(0, 0, tCanvas.width, tCanvas.height); // 清空临时画布
tctx.drawImage(image, i * nw * ratio, j * nh * ratio, nw * ratio, nh * ratio, 0, 0, nw, nh);
ctx.drawImage(tCanvas, i * nw, j * nh, nw, nh); // 将瓦片绘制到主画布
}
}
} else {
ctx.drawImage(image, 0, 0, width, height); // 直接绘制小图
}
//根据文件大小计算压缩质量,单位K
var quality;
var fileSizeInK = file.size / 1024;
if (fileSizeInK <= 500) {
quality = 0.9;//压缩后是原本质量的90%
} else if (fileSizeInK > 500 && fileSizeInK <= 1000) {
quality = 0.8;
} else if (fileSizeInK > 1000 && fileSizeInK <= 1500) {
quality = 0.7;
} else if (fileSizeInK > 1500 && fileSizeInK <= 2000) {
quality = 0.6;
} else if (fileSizeInK > 2000 && fileSizeInK <= 2500) {
quality = 0.5;
} else if (fileSizeInK > 2500 && fileSizeInK <= 3000) {
quality = 0.4;
} else if (fileSizeInK > 3000 && fileSizeInK <= 3500) {
quality = 0.3;
} else if (fileSizeInK > 3500 && fileSizeInK <= 4000) {
quality = 0.2;
} else {
quality = 0.1;//压缩后是原本质量的10%
}
// 进行最小压缩
new Promise(function(resolve, reject) {
canvas.toBlob(function(blob) {
if (blob) {
resolve(blob);
} else {
reject(new Error("Canvas toBlob failed"));
}
}, 'image/jpeg', quality); // 设置为 jpeg 格式,质量 定义变量quality,单位0.1-1.0
})
.then(function(blob) {
if (blob.size <= 500 * 1024) { // 判断文件大小是否小于等于 500KB
uploadFile(blob); // 上传压缩文件
console.log('压缩前:' + initSize);
console.log('压缩后:' + blob.size);
console.log('压缩率:' + ~~(100 * (initSize - blob.size) / initSize) + "%");
} else {
alert('无法将图片压缩到小于500KB。');
}
})
.catch(function(error) {
console.error('压缩过程中出现错误:', error);
alert('图片压缩失败,请稍后重试。');
});
//关键压缩代码结束
}
};
image.src = readerEvent.target.result;
};
reader.readAsDataURL(file);
}
function uploadFile(blobOrFile) {
var formData = new FormData();
formData.append('file1', blobOrFile, 'image.jpg'); // 第三个参数是文件名
formData.append('uptype', document.querySelector('input[name="uptype"]').value);
$.ajax({
url: 'upfile.asp', // 上传脚本地址
type: 'POST',
data: formData,
processData: false, // 告诉jQuery不要处理发送的数据
contentType: false, // 告诉jQuery不要设置内容类型
success: function (response) {
console.log('文件上传成功');
// 创建一个DOM解析器
var parser = new DOMParser();
// 将返回的HTML字符串解析成一个文档对象
var doc = parser.parseFromString(response, 'text/html');
// 获取所有的script标签
var scripts = doc.querySelectorAll('script[type="text/javascript"]');
// 逐个执行script标签中的代码
scripts.forEach(function(script) {
eval(script.textContent);
});
},
error: function (jqXHR, textStatus, errorThrown) {
console.error('文件上传失败', textStatus, errorThrown);
}
});
}
</script>
</body>
</html>
- 1、压缩起到关键作用的是//关键压缩代码开始...//关键压缩代码结束
- 2、具体根据项目实际进行修改,表单、字段、输入框名称
参考资料:
https://www.cnblogs.com/moqiutao/p/6279905.html
https://blog.51cto.com/u_12205/6830173