图片压缩上传

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
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

/**
* @Date: 2016/11/17 0017
* @Time: 10:14
* @Author: lxbin
*
* Created with JetBrains WebStorm.
*/

/**
* https://leonshi.com/2015/10/31/html5-canvas-image-compress-crop/
* https://jafeney.com/2016/08/11/20160811-image-upload/
* https://ilovetile.com/3506
*/

/**
* 读取文件
* @param file 文件对象
* @return {Promise}
*/
function readFileAsync(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onload = e => resolve(readFile.target.result)
reader.onerror = e => reject(new Error('Could not read file'))
reader.readAsDataURL(file)
})
}

/**
* 加载图片
* @param url 图片地址
* @return {Promise}
*/
function loadImageAsync(url) {
return new Promise((resolve, reject) => {
const image = new Image()
image.onload = () => resolve(image)
image.onerror = () => reject(new Error('Could not load image at ' + url))
image.src = url
})
}

/**
* base64的图片dataUri转Blob
* @param dataURI
* @return {*}
*/
function dataURItoBlob(dataURI) {
// convert base64 to raw binary data held in a string
// doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this
const byteString = atob(dataURI.split(',')[1]);

// separate out the mime component
const mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]

// write the bytes of the string to an ArrayBuffer
const ab = new ArrayBuffer(byteString.length);
const ia = new Uint8Array(ab);
for (let i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}

// write the ArrayBuffer to a blob, and you're done
return new Blob([ab], {type: mimeString});

// Old code
// const bb = new BlobBuilder();
// bb.append(ab);
// return bb.getBlob(mimeString);
}

/**
* 图片转Blob
* @param image 图片对象
* @param quality 图片质量(0到1之间)
* @param scale 缩放比例(0到1之间)
* @return {Promise}
*/
function imageToBlob(image, quality, scale) {
return new Promise((resolve, reject) => {
try {
let canvas = document.createElement('canvas')
canvas.width = image.naturalWidth * scale
canvas.height = image.naturalHeight * scale
while (canvas.width >= 3264 || canvas.height >= 2448) {//超过这个值base64无法生成,在IOS上
canvas.width = canvas.naturalWidth * scale
canvas.height = canvas.naturalHeight * scale
}

let ctx = canvas.getContext('2d').drawImage(image, 0, 0, canvas.width, canvas.height)

//方式一:低版本兼容性差些
//canvas.toBlob(function (blob) {
// console.group('[Leo]file compress to blob')
// console.log('文件类型 => ' + image.type)
// console.log('文件大小 => ' + (image.size / 1024 / 1024).toFixed(2) + 'M')
// console.log('blob质量 => ' + quality)
// console.log('blob大小 => ' + (blob.size / 1024 / 1024).toFixed(2) + 'M')
// console.groupEnd()
// resolve(blob)
//}, 'image/jpeg', quality)

//方式二:
const base64 = canvas.toDataURL('image/jpeg', quality);
const blob = dataURItoBlob(base64);
blob.name = blob.filename = image.name
console.group('[Leo]image compress to blob')
console.log('文件类型 => ' + image.type)
console.log('文件大小 => ' + (image.size / 1024 / 1024).toFixed(2) + 'M')
console.log('blob质量 => ' + quality)
console.log('blob大小 => ' + (blob.size / 1024 / 1024).toFixed(2) + 'M')
console.groupEnd()
resolve(blob);
} catch (e) {
reject(new Error("Image could not convert to blob :" + e))
}
})
}

/**
* Ajax上传
* @param uri 上传的Action地址
* @param file 文件对象
* @return {Promise}
*/
function uploadFile(uri, file) {
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest()
if (xhr.upload) {
xhr.upload.addEventListener("progress", (e) => {// 处理上传进度
if (e.lengthComputable) {
let percent = (e.loaded / e.total * 100).toFixed(2) + '%'
console.log("上传中(" + percent + ")");
//TODO:反馈到DOM里显示
} else {
console.log('unable to compute');
}
}, false)
}
xhr.onreadystatechange = (e) => {// 文件上传成功或是失败
if (xhr.readyState === 4) {
if (xhr.status === 200) {
resolve(xhr.responseText)// 上传成功
} else {
reject(xhr.responseText)// 上传出错处理
}
}
}
xhr.open("POST", uri, true)// 开始上传
let form = new FormData()
form.append("filedata", file, file.name)
xhr.send(form)
})
}

/**
* 上传文件
* @param file 文件对象
* @param quality 图片质量(0到1之间)
* @param scale 缩放比例(0到1之间)
*/
export default async function fileUpload(file, quality, scale) {
try {
let fileUrl = await readFileAsync(file)
let image = await loadImageAsync(fileUrl)
image.name = file.name
let blob = await imageToBlob(image, quality, scale)
let upload = await uploadFile(blob)
return upload
} catch (e) {
console.log('file upload failed')
}
}

参考:
https://leonshi.com/2015/10/31/html5-canvas-image-compress-crop/
https://jafeney.com/2016/08/11/20160811-image-upload/
https://ilovetile.com/3506

坚持原创技术分享,您的支持将鼓励我继续创作!
  • 本文作者: Leo
  • 本文链接: https://xuebin.me/posts/c1474639.html
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!