前端项目上传图片,压缩,拍照图片旋转解决方案
发布于: 2021 年 05 月 10 日
1.使用 input 标签上传
capture = 'user' 调用前置摄像头, 'environment' 调用后置摄像头
<input type="file" multiple id="imgFile" accept="image/*" capture=""/>
复制代码
2.获取上传的数据
$refs!: {
imgFile: any;
};
const file = e.target.files[0];
const rFilter = /\.(png|jpg|gif|jpeg|webp)$/; // 检查图片格式
if (!rFilter.test(file.type)) {
alert('请上传图片');
this.$refs.imgFile.value = '';
return false
}
复制代码
3.使用 FileReader 对象读取文件类型
/**
* 获取文件数据
*/
enum Type {
readAsArrayBuffer = 'readAsArrayBuffer',
readAsDataURL = 'readAsDataURL',
}
const getFileData = (file: Blob | object, type?: string): Promise<string | Blob> => {
return new Promise((resolve, reject) => {
const fileReader: any = new FileReader();
switch (type) {
case Type.readAsArrayBuffer:
fileReader.readAsArrayBuffer(file);
break;
case Type.readAsDataURL:
fileReader.readAsDataURL(file);
break;
default:
fileReader.readAsArrayBuffer(file);
break;
}
return fileReader.addEventListener('load', () => {
return resolve(fileReader.result);
});
});
};
复制代码
4.使用 FormData 对象上传文件
const formDate = new FormData()
formDate.append(name, value, filename)
复制代码
5.上传文件
// 设置上传内容格式
headers: {
'Content-Type': 'multipart/form-data'
}
// axios 使用onUploadProgress监听上传进度
复制代码
6.移动端拍照旋转的问题(几年没更新,用苹果 7 测试没发现任何问题,返回 6 图片显示也是正常的,上传到服务器也是正常的,本地 node 测试)
下载 npm i exif-js -S
// 返回方向
EXIF.getData(file, function() {
EXIF.getAllTags(this)
return EXIF.getTag(this, 'Orientation')
})
复制代码
2.使用本地代码解决
const getOrientation = (buffer) => {
const view = new DataView(buffer);
if (view.getUint16(0, false) !== 0xFFD8) { return -2; }
const length = view.byteLength;
let offset = 2;
while (offset < length) {
const marker = view.getUint16(offset, false);
offset += 2;
if (marker === 0xFFE1) {
if (view.getUint32(offset += 2, false) !== 0x45786966) { return -1; }
const little = view.getUint16(offset += 6, false) === 0x4949;
offset += view.getUint32(offset + 4, little);
const tags = view.getUint16(offset, little);
offset += 2;
for (let i = 0; i < tags; i++) {
if (view.getUint16(offset + i * 12, little) === 0x0112) {
return view.getUint16(offset + i * 12 + 8, little);
}
}
// tslint:disable-next-line: no-bitwise
} else if ((marker & 0xFF00) !== 0xFF00) { break; } else { offset += view.getUint16(offset, false); }
}
return -1;
};
// 转换成Buffer
const dataURItoBuffer = (dataURI) => {
const byteString = atob(dataURI.split(',')[1]);
const buffer = new ArrayBuffer(byteString.length);
const view = new Uint8Array(buffer);
for (let i = 0; i < byteString.length; i++) {
view[i] = byteString.charCodeAt(i);
}
return buffer;
};
复制代码
7.初始化画布大小
initCanvas(Mw: number, Mh: number, img: any) {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
document.body.append(canvas);
// 配置画布最大大小
const maxW: number = Mw;
const maxH: number = Mh;
let w: number = img.width;
let h: number = img.height;
if (w < h && h > maxH) {
w = parseInt((maxH * img.width) / img.height);
h = maxH;
} else if (w >= h && w > maxW) {
h = parseInt((maxW * img.height) / img.width);
w = maxW;
}
canvas.width = w;
canvas.height = h;
console.log(canvas, w, h, img.width, img.height);
}
复制代码
8.使用 canvas 处理方向
// http://stackoverflow.com/questions/19463126/how-to-draw-photo-with-correct-orientation-in-canvas-after-capture-photo-by-usin
function orientationHelper(canvas, ctx, orientation) {
const w = canvas.width,
h = canvas.height;
if (orientation > 4) {
canvas.width = h;
canvas.height = w;
}
switch (orientation) {
case 3:
ctx.translate(w, h);
ctx.rotate(Math.PI);
break;
case 6:
ctx.rotate(0.5 * Math.PI);
ctx.translate(0, -h);
break;
case 8:
ctx.rotate(-0.5 * Math.PI);
ctx.translate(-w, 0);
break;
}
}
复制代码
9.导出画布
// canvas的toDataURL是只能压缩jpg,png图片的透明性质在canvas中是无效的,(win10有透明元素,苹果7,默认就没有)
ctx.drawImage(img, 0, 0, w, h);
const dataURL = canvas.toDataURL('image/jpeg', quality);
复制代码
10.图片压缩处理完成后转为 blob 格式
const convertBase64UrlToBlob = (a) => {
const arr = a.split(',');
const mime = arr[0].match(/:(.*?);/)[1];
const bstr = atob(arr[1]);
let n = bstr.length;
const u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], { type: mime });
};
复制代码
11.配置 axios,上传文件防止序列化
transformRequest: [function (data, headers) {
if (headers['Content-Type'] === 'multipart/form-data;charset=UTF-8') {
return data;
}
// 对 data 进行任意转换处理
return Qs.stringify(data);
}],
复制代码
12.触发事件
async changeFile(e: any) {
const file = e.target.files[0];
const rFilter = /(png|jpg|gif|jpeg|webp)$/; // 检查图片格式
if (!rFilter.test(file.type)) {
alert('请上传图片');
this.$refs.imgFile.value = '';
} else {
const url = await getFileData(file);
this.imgSrc = url;
const Orientation = getOrientation(dataURItoBuffer(url));
console.log(Orientation, '方向00');
const img = new Image();
img.src = url;
img.onload = () => {
this.initCanvas(1000, 1000, img, Orientation);
};
}
}
复制代码
划线
评论
复制
发布于: 2021 年 05 月 10 日阅读数: 20
版权声明: 本文为 InfoQ 作者【★】的原创文章。
原文链接:【http://xie.infoq.cn/article/9ae39a9ae9b7f8ce20a5624d9】。文章转载请联系作者。
★
关注
还未添加个人签名 2020.08.05 加入
还未添加个人简介
评论