上傳圖片,圖片太大,如何在前端實現圖片壓縮後上傳
上傳圖片是我們在前端開發中最常見不過的日常需求,當然了,為了提升使用者體驗,以及減少伺服器訪問圖片的壓力,一般情況在不影響圖片檢視的情況下,我們會對圖片進行適當的壓縮處理,處理後上傳,使用者的上傳操作的響應時間會大大減小,且在伺服器拿取圖片時,時間也會縮短。針對前端的壓縮最佳化,我下面寫了個簡版的壓縮處理。
function
compressPic
(
file
,
quality
)
{
let
reads
=
new
FileReader
();
reads
。
readAsDataURL
(
file
)
reads
。
onload
=
({
target
:
{
result
:
src
}})
{
// 這裡quality的範圍是(0-1)
var
canvas
=
document
。
createElement
(
“canvas”
);
var
ctx
=
canvas
。
getContext
(
“2d”
);
var
img
=
new
Image
();
img
。
src
=
src
;
img
。
onload
=
function
()
{
let
width
=
img
。
width
;
canvas
。
width
=
width
;
canvas
。
height
=
width
*
(
img
。
height
/
img
。
width
);
ctx
。
drawImage
(
img
,
0
,
0
,
canvas
。
width
,
canvas
。
height
);
// 轉換成base64格式 quality為圖片壓縮質量 0-1之間 值越小壓縮的越大 圖片質量越差
let
data
=
canvas
。
toDataURL
(
file
。
type
,
quality
);
return
data
}
};
},
透過上面這段程式碼即可實現圖片的壓縮處理,完成的實現思路就是:
input 讀取到 image/file 建立一個FileReader 使用 FileReader 將其轉換為 base64 編碼
new Image 建立img元素 使img的src指向FileReader轉換的base64
document。createElement(“canvas”) 建立canvas
ctx。drawImage(img,0,0, canvas。width, canvas。height) 將img畫到canvas上
canvas。toDataURL(file。type, quality) 將canvas轉換為圖片base64格式
透過上面的問題確實是能解決壓縮的問題 但是某些情況下 可能存在一些問題 quality的值存在0-1區間時 可能在測試0。1 至 0。99時 出現quality到0。8時或0。9時 壓縮後圖片記憶體卻佔的比之前更大了 在0。01 - 0。99這個區間內雖然是可以實現壓縮 但是壓縮的比例是不確定性的 所以我們在你實現壓縮為一定比例時 我們可以用另外一種發放去實現。
二分法實現:
具體的實現思路就是 就是我們先取quality為0。5 進行壓縮 壓縮後判斷圖片大小體積和指定體積比較 當壓縮後體積過小時 然後再二分取0。 5 - 1的一半 0。75 然後再去處理 體積大了 向下二分 體積小了 向上二分 ,但是要注意的一半取個3-4次二分即可 二分多次後會增長這個壓縮時間 影響使用者體驗, 具體的程式碼,如下:
function
compressPic
(
file
,
size
,
device
)
{
const
reader
=
new
FileReader
()
// 建立 FileReader
reader
。
readAsDataURL
(
file
)
reader
。
onload
=
({
target
:
{
result
:
src
}
})
=>
{
const
image
=
new
Image
()
// 建立 img 元素
image
。
src
=
src
const
canvas
=
document
。
createElement
(
‘canvas’
)
// 建立 canvas 元素
image
。
onload
=
()
=>
{
canvas
。
width
=
image
。
width
canvas
。
height
=
image
。
height
canvas
。
getContext
(
‘2d’
)。
drawImage
(
image
,
0
,
0
,
image
。
width
,
image
。
height
)
// 繪製 圖片到canvas上
let
canvasURL
,
nearFile
// 建立變數 圖片的file 最接近目標大小的file
let
pointDirection
=
true
// 設定預設的二分方向 true為加二分值 false為減二分值
let
quality
=
0
for
(
let
i
=
1
;
i
<=
device
;
i
++
)
{
canvasURL
=
canvas
。
toDataURL
(
file
。
type
,
pointDirection
?
(
quality
+=
1
/
(
2
**
i
))
:
(
quality
-=
1
/
(
2
**
i
)))
let
blob
=
dataURLtoBlob
(
canvasURL
)
// 此方法為base64轉化為blod方法 見上方
miniFile
=
blobToFile
(
blob
,
‘new’
+
file
。
name
,
file
。
type
)
// 此方法為blod轉file方法
// 上方呼叫的兩個方法 dataURLtoBlod和blobToFile已經更新到下方文章中 可拿來直接使用
}
return
miniFile
}
}
}
透過上面這段程式碼可以實現接近指定體積的壓縮,完整的實現思路就是:
input 讀取到 image/file 建立一個FileReader 使用 FileReader 將其轉換為 base64 編碼
new Image 建立img元素 使img的src指向FileReader轉換的base64
document。createElement(“canvas”) 建立canvas
ctx。drawImage(img,0,0, canvas。width, canvas。height) 將img畫到canvas上
建立幾個變數 canvasURL:canvas轉圖片的file;nearFile:二分後的file檔案
透過for迴圈 根據二分的次數 取到最接近的指定體積的quality的值
當然了 再很多情況中我們可能不一定給後端提供的是base64格式的圖片 我們上傳過去一般是file格式 在這我提供一個將base64轉為file格式的js方法
我們的實現思路就是 將base64轉化為blod格式 然後將其轉化為file格式
// base64轉換為blod
function
dataURLtoBlob
(
dataurl
)
{
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
);
}
return
new
Blob
([
u8arr
],
{
type
:
mime
});
},
// blod轉化為file theBlod: blod格式檔案 fileName: 檔名稱 fileType:檔案型別
function
blobToFile
(
theBlob
,
fileName
,
fileType
)
{
let
file
=
new
window
。
File
([
theBlob
],
fileName
,
{
type
:
fileType
})
return
file
;
}
這裡我提供了一個demo可以供體驗者體驗下壓縮的功能
圖片壓縮demo
上一篇:H264基本原理
下一篇:關於GOP和幀率、位元速率的關係