前端壓縮:
基本上前端進(jìn)行圖片壓縮都是基于canvas進(jìn)行壓縮充包,可以按照自定義尺寸縮小副签,達(dá)到壓縮體積的效果。
操作流程:前端拿到選中圖片數(shù)據(jù),利用canvas繪制進(jìn)行自定義壓縮淆储,將壓縮后的圖片數(shù)據(jù)作為上傳數(shù)據(jù)冠场。
優(yōu)點(diǎn):不改變圖片尺寸情況下,壓縮出來(lái)的圖片體積減小本砰,清晰度肉眼看不出變化慈鸠。
缺點(diǎn):自定義圖片尺寸情況下,壓縮出來(lái)的圖片體積減小灌具,但是清晰度明顯變差青团。
示例插件: compressorjs
npm i compressor -S
示例代碼:
new Compressor(file, options)
// options 部分屬性介紹
{
quality: 0.6, // 取值范圍0~1,推薦0.6~0.8咖楣,數(shù)值與圖片體積壓縮效果成反比
min-width: 200, // 大于0督笆,輸出圖片最小寬度
min-height: 200, // 大于0,輸出圖片最小高度
max-width: 200, // 大于0诱贿,輸出圖片最大寬度
max-height: 200, // 大于0娃肿,輸出圖片最大高度
width: 980, // 只設(shè)置width時(shí)會(huì)保留原有比例
height: 988, // 設(shè)置壓縮后的圖片高度
resize: 'contain', // 'none' || 'contain' || 'cover',
success: (result) => {}, // 成功回調(diào),result為壓縮后文件對(duì)象珠十,可進(jìn)行自定義上傳
// 圖片繪制到canvas壓縮前執(zhí)行的鉤子函數(shù)料扰,如為圖片增加濾鏡
beforeDraw(context, canvas) {
context.filter = 'grayscale(100%)';
},
// 圖片繪制到canvas壓縮后執(zhí)行的鉤子函數(shù),如為圖片增加水印效果
drew(context, canvas) {
context.fillStyle = '#fff';
context.font = '2rem serif';
// 如:在圖片左下角增加自定義文本
context.fillText('watermark', 20, canvas.height - 20);
},
}
//示例效果:將選中圖片按照原比例焙蹭,寬度設(shè)置為980px進(jìn)行壓縮晒杈,增加灰色濾鏡、以及文字水印
const file; // 選中圖片數(shù)據(jù)
if (file) {
new Compressor(file, {
quality: 0.6,
width: 980
resize: 'contain',
success(result) {
// result: 文件對(duì)象孔厉,自定義上傳處理
},
// 為圖片增加濾鏡
beforeDraw(context, canvas) {
context.filter = 'grayscale(100%)';
},
// 為圖片增加水印效果
drew(context, canvas) {
context.fillStyle = '#fff';
context.font = '2rem serif';
// 如:在圖片左下角增加自定義文本
context.fillText('watermark', 20, canvas.height - 20);
},
error(err) {
console.log(err.message);
},
});
}
[示例原圖](# 圖片一) 執(zhí)行了beforeDrew鉤子圖片 執(zhí)行了drew鉤子圖片
node端壓縮:
處理類型:
1拯钻、對(duì)現(xiàn)有圖片進(jìn)行壓縮上傳替換
2、對(duì)前端上傳的圖片進(jìn)行壓縮再進(jìn)行上傳
示例插件:tinify
優(yōu)點(diǎn):壓縮出來(lái)的圖片體積減小撰豺,不改變尺寸情況下無(wú)損壓縮粪般。
缺點(diǎn):每月免費(fèi)額度為500次,且resize等操作會(huì)累計(jì)次數(shù)污桦,超過的次數(shù)需要付費(fèi)亩歹。
npm i tinify -S
示例代碼
const tinify = require('tinify')
tinify.key = 'APIKey'
//1、使用 tinify.fromUrl 對(duì)在線圖片進(jìn)行壓縮
// 拿到壓縮后的圖片對(duì)象
const result = await tinify.fromUrl(url)
// 處理圖片名稱后做自定義上傳處理凡橱、拿到返回地址做數(shù)據(jù)替換即可
let arr = url.split('.')
let imgType = arr[arr.length - 1]
const FormData = require('form-data')
const formData = new FormData()
formData.append('is_watermark', false)
formData.append('file', result)
formData.append('submit_user', '林福才-子丘')
let filename = `${moment().unix()}.${imgType}`
// 自定義處理上傳小作、替換...
//2、對(duì)前端傳遞過來(lái)的圖片文件進(jìn)行壓縮
var from = new formidable.IncomingForm();
// 設(shè)置編輯
form.encoding = 'utf-8';
// 設(shè)置文件存儲(chǔ)路徑
form.uploadDir = path.join(__dirname, '../upload/')
// 保留后綴
form.keepExtensions = true
// 設(shè)置單文件大小限制
form.maxFieldsSize = 10 * 1024 * 1024;
// 解析請(qǐng)求數(shù)據(jù) files為文件數(shù)據(jù)梭纹,fileds為其他字段數(shù)據(jù)躲惰,自定義返回?cái)?shù)據(jù)結(jié)構(gòu)
let fileRes = await new Promise(async (resolve, reject) => {
form.parse(req, (err, fields, files) => {
resolve({fileBuffer:files, ...fields})
})
})
// 拿到解析到的文件數(shù)據(jù),使用tinify.fromBuffer進(jìn)行壓縮轉(zhuǎn)換
const newFile = await tinify.fromBuffer(fileRes.fileBuffer)
// 需要自定義大小变抽,可通過resize進(jìn)行調(diào)整
const resizeFile = newFile.resize({
method: 'fit', // 'scale' || 'fit' || 'cover' || 'thumb'
width: 200,
hieght: 100
})
// 自定義處理文件上傳础拨,將地址返回給前端即可
前端multipart上傳時(shí)氮块,可通過form.onPart單獨(dú)處理接收的文件數(shù)據(jù),進(jìn)行數(shù)據(jù)拼接
// 手動(dòng)拼接數(shù)據(jù)诡宗,在form.parse的回調(diào)resolve({fileBuffer, ...fileds})
let fileArr = []
let fileLength = []
let fileBuffer;
let fileName = ''
form.onPart = (part) => {
// 讓formidable處理非文件數(shù)據(jù)
if(!part.filename) {
form.handlePart(part);
}
part.addListener('data', (d) => {
if(part.name !== file || d.length == 0) return
fileArr.push(d)
fileLength += d.length
})
part.addListener('end', () => {
if(part.name == 'file') {
fileName = part.filename
fileBuffer = Buffer.concat(fileArr, fileLength)
}
})
}
圖片效果
圖片一
https://i.niupic.com/images/2022/03/16/9WAE.png
圖片二
https://i.niupic.com/images/2022/03/16/9WAF.png