前端项目上传图片,压缩,拍照图片旋转解决方案
发布于: 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;};
// 转换成Bufferconst 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-usinfunction 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 加入
还未添加个人简介











评论