-
為什么要實(shí)現(xiàn)圖片壓縮拜马?
在當(dāng)前各大手機(jī)廠商比賽攝像頭大戰(zhàn)的時(shí)候,帶來(lái)的就是一張隨隨便便的照片就能達(dá)到10M-100M不等,那么就帶了上傳圖片等待時(shí)間長(zhǎng)扮超,加載時(shí)間長(zhǎng)蹋肮,造成不必要的浪費(fèi),為了解決這問(wèn)題就必須對(duì)圖片進(jìn)行壓縮后再進(jìn)行上傳坯辩。
-
如何實(shí)現(xiàn)圖片壓縮漆魔?
1 用到的相關(guān)API
- canvas 對(duì)圖片進(jìn)行重繪
canvas 是為了客戶(hù)端矢量圖形而設(shè)計(jì)的却音。它自己沒(méi)有行為矢炼,但卻把一個(gè)繪圖 API 展現(xiàn)給客戶(hù)端 JavaScript 以使腳本能夠把想繪制的東西都繪制到一塊畫(huà)布上。
- FileReader 相關(guān)閱讀
對(duì)象允許Web應(yīng)用程序異步讀取存儲(chǔ)在用戶(hù)計(jì)算機(jī)上的文件(或原始數(shù)據(jù)緩沖區(qū))的內(nèi)容夷陋,使用
File
或Blob
對(duì)象指定要讀取的文件或數(shù)據(jù)
2 思路分析
將文件類(lèi)型的(file)圖片轉(zhuǎn)成base64的編碼方式
創(chuàng)建Image去接受圖片文件的信息
創(chuàng)建等比例大小的canvas
將圖片繪制到canvas
對(duì)canvas進(jìn)行壓縮胰锌,獲取新的信息
將新的信息轉(zhuǎn)換為圖片文件
-
逐步實(shí)現(xiàn)
既然有了思路,那么開(kāi)始實(shí)踐吧酬土!
- 先寫(xiě)一個(gè)選擇圖片的標(biāo)簽和方法
HTML
<input type="file" name="" id="filedemo">
JS
let filetab = document.getElementById('filedemo')
filetab.onchange = function (e) {
let file = e.target.files[0] // 獲取到的圖片信息
let file_type = file.type // 圖片的類(lèi)型
let file_name = file.name // 圖片的名字
let file_size = file.size // 圖片的大小
}
獲取到的信息包含大小榛搔,類(lèi)型....
文件的size是按照字節(jié)践惑,1字節(jié)就是1byte就是1B,1KB = 1024B尔觉,1MB = 1024 * 1024B
- 將獲取的圖片轉(zhuǎn)為base64,返回一個(gè)空或者轉(zhuǎn)換后的Base64
/**
* > 小恐龍
* @param {file} 需要壓縮的圖片文件
* @return 圖片的Base64
*/
function ImageToBase64(file) {
return new Promise(resolve => {
if (!file) resolve(null) // 沒(méi)有文件時(shí)直接返回
let fileReader = new FileReader()
fileReader.readAsDataURL(file)
fileReader.onload = function (e) {
// e 是 onLoad之后返回的參數(shù)信息专甩,其中就有我們需要的Base64的信息
let imgBase64Info = e.target.result
resolve(imgBase64Info) // 返回獲取到的Base64信息
}
})
}
- 通過(guò)拿到的Base64的信息涤躲,我們通過(guò)創(chuàng)建canvas畫(huà)布贡未,進(jìn)行畫(huà)圖,設(shè)置壓縮級(jí)別后轉(zhuǎn)出為Base64俊卤,之后返回新的Base64信息
/**
* > 小恐龍
* @param {base64} 獲取BASE64的返回值
* @return 新的Base64
*/
function comperImage(base64, filetype, quality) {
return new Promise(resolve => {
if (!base64) resolve() // 沒(méi)有給信息直接返回
let image = new Image()
image.src = base64
image.onload = function (e) {
let info = e.path[0]
let sacle = info.width / info.height // 獲取寬高比例
let canvas = document.createElement('canvas') // 創(chuàng)建畫(huà)布
let ctx = canvas.getContext('2d')
canvas.width = info.width // 設(shè)置畫(huà)布寬高
canvas.height = info.height
ctx.drawImage(image, 0, 0, canvas.width, canvas.height) // 將圖片繪制在畫(huà)板上
let newBase64 = canvas.toDataURL(filetype, quality) // 將畫(huà)板內(nèi)容轉(zhuǎn)為圖片并設(shè)置壓縮比例
resolve(newBase64)
}
})
}
- 將新的Base64轉(zhuǎn)為新的文件并且返回
/*/**
* Base64轉(zhuǎn)換為File
* > 小恐龍
* @param { string } 文件的url消恍,此處為生成的新的Base64
* @param { string } 要生成的文件名字
* @return File
*/
function dataURLtoFile(dataurl, filename) {
return new Promise(resolve => {
var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
resolve(new File([u8arr], filename, { type: mime }))
})
}
- 當(dāng)做完以上步驟之后狠怨,我們就可以拿到新的文件進(jìn)行后續(xù)的操作邑遏。
放個(gè)案例
/**
* 壓縮圖片
* > 小恐龍
* @param { file } 需要壓縮的文件
* @return
*/
async function comImg(file, quality, filename = `new_${file.name}`) {
// 將png格式文件轉(zhuǎn)為JPEG輸出棍苹,因?yàn)镻ng圖片不能用這種方式進(jìn)行壓縮
let filetype = file.type === 'image/png' ? 'image/jpeg' : file.type
let base64 = await ImageToBase64(file) // 獲取需要壓縮圖片的base64
let newBase64 = await comperImage(base64, filetype, quality) // 獲取壓縮后的base64
let newFile = await dataURLtoFile(newBase64, filename) // 生成新文件
console.log(`壓縮后文件大小${newFile.size}`)
let resultImg = new Image() // 創(chuàng)建Image標(biāo)簽
resultImg.src = URL.createObjectURL(newFile) // 創(chuàng)建img的src
document.body.appendChild(resultImg) //添加至頁(yè)面
}
看下效果
可以看到枢里,壓縮的效果還是非常明顯的,至此栏豺,一個(gè)圖片的壓縮就完成了。
感覺(jué)還不錯(cuò)的觀眾姥爺別忘記巷疼,點(diǎn)贊收藏 灵奖。