疑难解决历程之-- 图片压缩上传篇

图片压缩上传


不管是前端还是后端的开发人员,基本上都会使用到过图片上传,为了衡量网络传输性能,我们会对上传的图片进行压缩。

前端进行压缩是为了用户使用体验更优和网络传输压力更小,后端进行压缩是为了图片存储更优。

这里我是用vant.js的uploader组件,进行图片压缩和上传。

先描述一下我的需求: 是表单页面的数据一次提交给后端(包括表单数据和图片数据)

遇到的问题: 点击提交按钮无反应,上传图片的预览显示不出上传图片的缩略图。

解决思路:

(1)首先提交按钮无反应,原因是表单数据和图片数据一次性提供给接口的时候,前后端通信时间长,用户可能没耐心以为未点击成功,出现重复点击情况,调起多起数据访问请求。

(2)上传图片的缩略图不显示问题可能是由于图片未进行压缩,相机拍摄出的照片像素过大,手机网络信号差及内存小等综合性原因。

解决方法:

(1)给提交按钮加一个进度条,方便用户看到进度条提示,不进行重复点击操作,另外给按钮添加限制,一个交互过程未结束的情况下不重复发起交互通信。

// 进度条这里暂用vant.js中的
import Vue from 'vue';
import { Progress } from 'vant';

Vue.use(Progress);
// 可自行设计进度条样式
<van-progress :percentage="50" />

(2)图片过大,前后端传输过程中所需时间长,成本高,效率低,在网速慢的情况下更容易出现问题。所以在前后端通信交互前,前端进行本地压缩。

这里可以使用beforeRead和afterRead函数选择压缩,beforeRead是选择文件是压缩并把文件数据存在页面上,afterRead是选择文件上传在页面后再进行图片压缩。

afterRead方式可能存在图片过大手机端出现缩略图不显示的问题,建议使用beforeRead方式,缩略图显示正常,减少性能损耗。

// 这里限制只上传一张展品,可设置多张,加下multiple,max-count可以设置多
<van-uploader v-model="fileList" :max-count="1" :after-read="afterRead" :before-read="beforeRead" />

import Vue from 'vue';
import { Uploader } from 'vant';

Vue.use(Uploader);

beforeRead(file) { 
	// 上传之前检测图片类似返回true和false会影响到onRead函数
	let _this = this;
	let regex = /(.jpg|.jpeg|.png|.bmp)$/
	if (!regex.test(file.type)) {
		Toast('图片格式不支持上传')
        return false
   	} else {
   		//自己定义的文件大小,超过多少M就开始压缩(现在是1M)
        let maxSize = 1 * 1024 * 1024; 
        let fileObj = file; // 当前的图片
        
        if(file.size > maxSize){
        	//实例化文件读取对象
        	var reader = new FileReader(); 
        	//将文件读取为 DataURL,也就是base64编码
        	reader.readAsDataURL(file); 
        	//文件读取成功完成时触发
        	reader.onload = function(ev) { 
        		//获得文件读取成功后的DataURL,也就是base64编码
           	 	var dataURL = ev.target.result; 
            	var files = {content:dataURL,file:fileObj}
            	_this.imgcompress(fileObj, files);
        	}
        }
    }
},

afterRead(file) {
   	console.log(file)
},

imgcompress(file, files) {
  	const img = document.createElement("img");
  	// 读取文件资源实例
	const reader = new FileReader(); 
	//读取图片资源
    reader.readAsDataURL(file); 
    reader.onload = (e) => {
		//读取成功
        let _this = this;
        img.src = e.target.result;
        img.onload = function () {
        //上传的图片的宽高
	    const { width: originWidth, height: originHeight } = img; 
	    //设置一个canvas 的最大宽高
        const maxWidth = 1024, maxHight = 1024;
        if (originWidth > maxWidth || originHeight > maxHight) {
      		//计算出图片的缩放比例
            if (originWidth > originHeight) {
            	//宽 大于 高
            	const Proportion = Math.ceil(originWidth / maxWidth);
           		//目标的宽度
            	let targetWidht = parseInt(originWidth / Proportion); 
            	//目标的高度
            	let targetHeight = parseInt(originHeight / Proportion); 
				_this.createCanvasCompress(targetWidht, targetHeight, img, files, 1);
      		} else {
      			//高大于宽
       			const Proportion = Math.ceil(originHeight / maxHight); 
       			//目标的宽度
            	let targetWidht = parseInt(originWidth / Proportion); 
            	//目标的高度
            	let targetHeight = parseInt(originHeight / Proportion); 
            	let bold = _this.createCanvasCompress(targetWidht, targetHeight, img, files, 1);
            }
    	} else {
            let quality = 0.8;
            _this.createCanvasCompress(originWidth, originHeight, img, files, quality);
    	}
   	}
	};
},

createCanvasCompress(targetWidth, targetHeight, img, files, quality) {
   	let _this = this;
   	return new Promise((resolve, reject) => {
      	const canvas = document.createElement("canvas");
        const context = canvas.getContext("2d");
        // 设置宽高度为等同于要压缩图片的尺寸
        canvas.width = targetWidth;
        canvas.height = targetHeight;
        context.clearRect(0, 0, targetWidth, targetHeight);
        //将img绘制到画布上
        console.log(targetWidth, targetHeight);
        context.drawImage(img, 0, 0, targetWidth, targetHeight);
        files.content = canvas.toDataURL(files.file.type, quality); // 0.92为默认压缩质量
        const newFile = this.dataURLtoFile(files.content, files.file.name);
        let obj = {content: files.content, file: newFile}
        let commonImg = []
        commonImg.push(obj)
        this.fileList = commonImg;
        return true
      });
    },

(3) 这里有几个图片格式转换的方法如下:

1.文件转化为base64格式

// 文件转化为base64格式
filetoBase(file) {
	//实例化文件读取对象
 	var reader = new FileReader(); 
 	//将文件读取为 DataURL,也就是base64编码
	reader.readAsDataURL(file); 
	//文件读取成功完成时触发
 	reader.onload = function (ev) { 
 		//获得文件读取成功后的DataURL,也就是base64编码
    	var dataURL = ev.target.result;
        console.log(dataURL);
        return dataURL
      }
    },

2.将base64转换为file文件

// 将base64转换为file文件
dataURLtoFile (dataurl, filename) { 
  	let arr = dataurl.split(',')
  	let mime = arr[0].match(/:(.*?);/)[1]
	let bstr = atob(arr[1])
 	let n = bstr.length
	let u8arr = new Uint8Array(n)
	while (n--) {
   		u8arr[n] = bstr.charCodeAt(n)
  	}
  	return new File([u8arr], filename, {type: mime})
},

3.网络链接图片转base64

// 网络链接图片转base64
imgToBase64(url,cb){
 	var canvas = document.createElement('canvas'),
	ctx = canvas.getContext('2d'),
    img = new Image;     
    img.crossOrigin = 'Anonymous';
    img.onload = function () {
      	canvas.height = img.height;
        canvas.width = img.width;
        ctx.drawImage(img, 0, 0);
        var dataURL = canvas.toDataURL('image/png');
        cb && cb(dataURL);
        canvas = null;
  	};
    img.src = url;
},

4.base64转文件格式

// base64转文件格式
base64toFile(base, filename){
	var arr = base.split(',');
  	var mime = arr[0].match(/:(.*?);/)[1];
 	var bstr = atob(arr[1]);
	var n = bstr.length;
  	var u8arr = new Uint8Array(n);
  	while (n--) {
    	u8arr[n] = bstr.charCodeAt(n);
 	}
  	//转换成file对象
   	return new File([u8arr], filename, { type: mime });
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值