目录
- React图片压缩上传统一处理
- 压缩相关代码
- 使用方法
- React图片压缩工具(可下载)
- 示例
- 核心工具
React图片压缩上传统一处理
最近项目需要对上传的图片文件进行压缩后才上传到服务器中,于是研究了一番,下面给出详细的压缩方法。
图片压缩的原理:实际上根据图片大小有没有超过预定的最大最小时,如果超过指定的高度/宽度,在不怎么失真的前提下裁剪图片,然后使用canvas画布的drawImage()方法绘制图片。
下面是关键的代码:
//在上传之前转换文件
transformFile = (file) => {
/**
* 针对图片进行压缩,如果图片大小超过压缩阈值,则执行压缩,否则不压缩
*/
//判断是否是图片类型
if (this.checkIsImage(file.name)) {
const {compressThreshold =, isPictureCompress = false, pictureQuality = 0.92} = this.props;
let fileSize = file.size / / 1024;
// console.log('before compress, the file size is : ', fileSize + "M");
//当开启图片压缩且图片大小大于等于压缩阈值,进行压缩
if ((fileSize >= compressThreshold) && isPictureCompress) {
//判断浏览器内核是否支持base图片压缩
if (typeof (FileReader) === 'undefined') {
return file;
} else {
try {
this.setState({
spinLoading: true
});
return new Promise(resolve => {
//声明FileReader文件读取对象
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
// 生成canvas画布
const canvas = document.createElement('canvas');
// 生成img
const img = document.createElement('img');
img.src = reader.result;
img.onload = () => {
const ctx = canvas.getContext('d');
//原始图片宽度、高度
let originImageWidth = img.width, originImageHeight = img.height;
//默认最大尺度的尺寸限制在( * 1080)
let maxWidth =, maxHeight = 1080, ratio = maxWidth / maxHeight;
//目标尺寸
let targetWidth = originImageWidth, targetHeight = originImageHeight;
//当图片的宽度或者高度大于指定的最大宽度或者最大高度时,进行缩放图片
if (originImageWidth > maxWidth || originImageHeight > maxHeight) {
//超过最大宽高比例
if ((originImageWidth / originImageHeight) > ratio) {
//宽度取最大宽度值maxWidth,缩放高度
targetWidth = maxWidth;
targetHeight = Math.round(maxWidth * (originImageHeight / originImageWidth));
} else {
//高度取最大高度值maxHeight,缩放宽度
targetHeight = maxHeight;
targetWidth = Math.round(maxHeight * (originImageWidth / originImageHeight));
}
}
// canvas对图片进行缩放
canvas.width = targetWidth;
canvas.height = targetHeight;
// 清除画布
ctx.clearRect(, 0, targetWidth, targetHeight);
// 绘制图片
ctx.drawImage(img,, 0, targetWidth, targetHeight);
// quality值越小,图像越模糊,默认图片质量为.92
const imageDataURL = canvas.toDataURL(file.type || 'image/jpeg', pictureQuality);
// 去掉URL的头,并转换为byte
const imageBytes = window.atob(imageDataURL.split(',')[]);
// 处理异常,将ascii码小于的转换为大于0
const arrayBuffer = new ArrayBuffer(imageBytes.length);
const uintArray = new Uint8Array(arrayBuffer);
for (let i =; i < imageBytes.length; i++) {
uintArray[i] = imageBytes.charCodeAt(i);
}
let mimeType = imageDataURL.split(',')[].match(/:(.*?);/)[1];
let newFile = new File([uintArray], file.name, {type: mimeType || 'image/jpeg'});
// console.log('after compress, the file size is : ', (newFile.size / / 1024) + "M");
resolve(newFile);
};
};
reader.onerror = () => {
this.setState({
spinLoading: false
});
return file;
}
}).then(res => {
this.setState({
spinLoading: false
});
return res;
}).catch(() => {
this.setState({
spinLoading: false
});
return file;
});
} catch (e) {
this.setState({
spinLoading: false
});
//压缩出错,直接返回原file对象
return file;
}
}
} else {
//不需要压缩,直接返回原file对象
return file;
}
} else {
//非图片文件,不进行压缩,直接返回原file对象
return file;
}
};
相关属性说明:
- compressThreshold: 5, //压缩的阈值,图片大小超过5M,则需要进行压缩
- isPictureCompress: false, //是否开启图片压缩
- pictureQuality: 0.92, //指定压缩的图片质量,取值范围为0~1,quality值越小,图像越模糊,默认图片质量为0.92
使用方法
<NHUpload
uploadType={'file'}
multiple={true}
fileCountLimit={fjsl}
maxFileSize={}
fileTypeLimit={fileTypeList}
onChange={this.fjOnChange}
isPictureCompress={true} //是否开启图片压缩
pictureQuality={.5} //图片质量
compressThreshold={} //压缩阈值
/>
在使用时,我们可以根据业务需求动态设置需要压缩的阈值,图片质量等等,对图片压缩可以大大节省服务器的资源,现在手机随便拍一张照片就是10几兆。
React图片压缩工具(可下载)
用到的插件:compressorjs
示例
ExampleCanvas.js
import React from 'react';
import { compressorImage } from './Compressor'
export default class UploadPic extends React.Component {
constructor(props) {
super(props);
this.state = {
previewPic: '',
laterPic: ''
};
this.handleUpload = this.handleUpload.bind(this);
this.downloadImg = this.downloadImg.bind(this);
}
downloadImg(){
// console.log('download',this.state.laterPic);
var blob=this.dataURLtoBlob(this.state.laterPic)
const aLink = document.createElement('a');
document.body.appendChild(aLink);
aLink.style.display='none';
const objectUrl = window.URL.createObjectURL(blob);
aLink.href = objectUrl;
// 修改目标图片名字
// aLink.download = 'a.png';
aLink.download =document.getElementById('file').value.substring(document.getElementById('file').value.lastIndexOf('\\') +);
aLink.click();
}
dataURLtoBlob(dataurl) {
var arr = dataurl.split(',');
//注意base的最后面中括号和引号是不转译的
var _arr = arr[].substring(0,arr[1].length-2);
var mime = arr[].match(/:(.*?);/)[1],
bstr =atob(_arr),
n = bstr.length,
uarr = new Uint8Array(n);
while (n--) {
uarr[n] = bstr.charCodeAt(n);
}
return new Blob([uarr], {
type: mime
});
}
handleUpload(e) {
// console.log('啊哈!', e.target.files[]);
var myFile = this.A(e.target.files[]);
// console.log('---------myFile----------', myFile);
const reader = new FileReader();
reader.readAsDataURL(e.target.files[]);
reader.onload = function (e) {
// console.log(e.target.result); // 上传的图片的编码
this.setState({
previewPic:e.target.result
});
}.bind(this);
}
A = async (file) => {
var myfile = await compressorImage(file, 'file',.6)
// console.log('----myfie-----',myfile);
const reader = new FileReader();
reader.readAsDataURL(myfile);
reader.onload = function (e) {
// console.log(e.target.result); // 上传的图片的编码
this.setState({
previewPic:this.state.previewPic,
laterPic: e.target.result
});
}.bind(this);
return myfile
}
render() {
const { previewPic, laterPic } = this.state;
return (
<div id="upload-pic">
<input type="file" id='file' className="file" onChange={this.handleUpload} />
<div><img src={previewPic} alt="" style={{ width: 'px' }} /></div>
<div><img src={laterPic} alt="" style={{ width: 'px' }} /></div>
<button onClick={this.downloadImg} >download</button>
</div>
)
}
}
核心工具
Compressor.js
import React from 'react'
import Compressor from 'compressorjs';
/**
* @param image 图片
* @param backType 需要返回的类型blob,file
* @param quality 图片压缩比-1,数字越小,图片压缩越小
* @returns
*/
export const compressorImage = (image, backType, quality) => {
// console.log('image, backType, quality',image, backType, quality);
return new Promise((resolve, reject) => {
new Compressor(image, {
quality: quality ||.8,
mimeType :'image/jpeg',
success(result) {
// console.log('result', result)
let file = new File([result], image.name, { type: image.type })
if (!backType || backType == 'blob') {
resolve(result)
} else if (backType == 'file') {
resolve(file)
} else {
resolve(file)
}
console.log('图片压缩成功---->>>>>')
},
error(err) {
console.log('图片压缩失败---->>>>>', err)
reject(err)
}
})
})
}