React圖片壓縮上傳統(tǒng)一處理方式
React圖片壓縮上傳統(tǒng)一處理
最近項目需要對上傳的圖片文件進行壓縮后才上傳到服務(wù)器中,于是研究了一番,下面給出詳細的壓縮方法,筆者使用的是React Ant Design前端框架的Upload組件上傳圖片:
通過查看Ant Design官網(wǎng)文檔,在上傳文件前可以修改文件:
| transformFile | 在上傳之前轉(zhuǎn)換文件。支持返回一個 Promise 對象 | Function(file): string | Blob | File | Promise<string | Blob | File> | 無 |
壓縮相關(guān)代碼
圖片壓縮的原理:實際上根據(jù)圖片大小有沒有超過預(yù)定的最大最小時,如果超過指定的高度/寬度,在不怎么失真的前提下裁剪圖片,然后使用canvas畫布的drawImage()方法繪制圖片。
下面是關(guān)鍵的代碼:
//在上傳之前轉(zhuǎn)換文件
transformFile = (file) => {
/**
* 針對圖片進行壓縮,如果圖片大小超過壓縮閾值,則執(zhí)行壓縮,否則不壓縮
*/
//判斷是否是圖片類型
if (this.checkIsImage(file.name)) {
const {compressThreshold = 5, isPictureCompress = false, pictureQuality = 0.92} = this.props;
let fileSize = file.size / 1024 / 1024;
// console.log('before compress, the file size is : ', fileSize + "M");
//當(dāng)開啟圖片壓縮且圖片大小大于等于壓縮閾值,進行壓縮
if ((fileSize >= compressThreshold) && isPictureCompress) {
//判斷瀏覽器內(nèi)核是否支持base64圖片壓縮
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('2d');
//原始圖片寬度、高度
let originImageWidth = img.width, originImageHeight = img.height;
//默認最大尺度的尺寸限制在(1920 * 1080)
let maxWidth = 1920, maxHeight = 1080, ratio = maxWidth / maxHeight;
//目標(biāo)尺寸
let targetWidth = originImageWidth, targetHeight = originImageHeight;
//當(dāng)圖片的寬度或者高度大于指定的最大寬度或者最大高度時,進行縮放圖片
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, 0, targetWidth, targetHeight);
// 繪制圖片
ctx.drawImage(img, 0, 0, targetWidth, targetHeight);
// quality值越小,圖像越模糊,默認圖片質(zhì)量為0.92
const imageDataURL = canvas.toDataURL(file.type || 'image/jpeg', pictureQuality);
// 去掉URL的頭,并轉(zhuǎn)換為byte
const imageBytes = window.atob(imageDataURL.split(',')[1]);
// 處理異常,將ascii碼小于0的轉(zhuǎn)換為大于0
const arrayBuffer = new ArrayBuffer(imageBytes.length);
const uint8Array = new Uint8Array(arrayBuffer);
for (let i = 0; i < imageBytes.length; i++) {
uint8Array[i] = imageBytes.charCodeAt(i);
}
let mimeType = imageDataURL.split(',')[0].match(/:(.*?);/)[1];
let newFile = new File([uint8Array], file.name, {type: mimeType || 'image/jpeg'});
// console.log('after compress, the file size is : ', (newFile.size / 1024 / 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;
}
};
相關(guān)屬性說明:
compressThreshold: 5, //壓縮的閾值,圖片大小超過5M,則需要進行壓縮isPictureCompress: false, //是否開啟圖片壓縮pictureQuality: 0.92, //指定壓縮的圖片質(zhì)量,取值范圍為0~1,quality值越小,圖像越模糊,默認圖片質(zhì)量為0.92
使用方法
<NHUpload
uploadType={'file'}
multiple={true}
fileCountLimit={fjsl}
maxFileSize={20}
fileTypeLimit={fileTypeList}
onChange={this.fjOnChange}
isPictureCompress={true} //是否開啟圖片壓縮
pictureQuality={0.5} //圖片質(zhì)量
compressThreshold={1} //壓縮閾值
/>在使用時,我們可以根據(jù)業(yè)務(wù)需求動態(tài)設(shè)置需要壓縮的閾值,圖片質(zhì)量等等,對圖片壓縮可以大大節(jié)省服務(wù)器的資源,現(xiàn)在手機隨便拍一張照片就是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;
// 修改目標(biāo)圖片名字
// aLink.download = 'a.png';
aLink.download =document.getElementById('file').value.substring(document.getElementById('file').value.lastIndexOf('\\') + 1);
aLink.click();
}
dataURLtoBlob(dataurl) {
var arr = dataurl.split(',');
//注意base64的最后面中括號和引號是不轉(zhuǎn)譯的
var _arr = arr[1].substring(0,arr[1].length-2);
var mime = arr[0].match(/:(.*?);/)[1],
bstr =atob(_arr),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], {
type: mime
});
}
handleUpload(e) {
// console.log('啊哈!', e.target.files[0]);
var myFile = this.A(e.target.files[0]);
// console.log('---------myFile----------', myFile);
const reader = new FileReader();
reader.readAsDataURL(e.target.files[0]);
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', 0.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: '675px' }} /></div>
<div><img src={laterPic} alt="" style={{ width: '675px' }} /></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 圖片壓縮比 0-1,數(shù)字越小,圖片壓縮越小
* @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 || 0.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)
}
})
})
}
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
React-Hooks之useImperativeHandler使用介紹
這篇文章主要為大家介紹了React-Hooks之useImperativeHandler使用介紹,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-07-07
React?中如何將CSS?visibility?屬性設(shè)置為?hidden
這篇文章主要介紹了React中如何將CSS?visibility屬性設(shè)置為?hidden,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-05-05
JS中使用react-tooltip插件實現(xiàn)鼠標(biāo)懸浮顯示框
前段時間遇到的一個需求,要求鼠標(biāo)懸停顯示使用描述, 用到了react-tooltip插件,今天寫一個總結(jié),感興趣的朋友跟隨小編一起看看吧2019-05-05
react-json-editor-ajrm解析錯誤與解決方案
由于歷史原因,項目中 JSON 編輯器使用的是 react-json-editor-ajrm,近期遇到一個嚴(yán)重的展示錯誤,傳入編輯器的數(shù)據(jù)與展示的不一致,這是產(chǎn)品和用戶不可接受的,本文給大家介紹了react-json-editor-ajrm解析錯誤與解決方案,需要的朋友可以參考下2024-06-06
react中關(guān)于Context/Provider/Consumer傳參的使用
這篇文章主要介紹了react中關(guān)于Context/Provider/Consumer傳參的使用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-09-09
React找不到模塊“./index.module.scss”或其相應(yīng)的類型聲明及解決方法
這篇文章主要介紹了React找不到模塊“./index.module.scss”或其相應(yīng)的類型聲明及解決方法,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-09-09
react-native?父函數(shù)組件調(diào)用類子組件的方法(實例詳解)
這篇文章主要介紹了react-native?父函數(shù)組件調(diào)用類子組件的方法,通過詳細步驟介紹了React 函數(shù)式組件之父組件調(diào)用子組件的方法,代碼簡單易懂,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-09-09

