文章目錄
- 0,前言
- 1,將圖片的url網絡鏈接(http://) 轉為base64格式
- 2,將base64的圖片數據轉換為file文件
- 3,將以base64的圖片數據轉換為Blob
- 4,將file文件轉化為base64
- 5,將file文件轉換為Blob
- 6,獲取文件(圖片視頻等)的本地內存地址 可以直接訪問
- 7,視頻截幀(截取視頻的第一幀)
- 8,總結
本篇文章側重點是對圖片文件的處理,比如url轉file、轉base64;file轉blob類型等。
注意
:不要把視頻文件轉成base64,因為base64格式本質是一串很長的字符串,如果在手機端上傳大一點的視頻文件并有轉bsee64的操作
,那么就會導致頁面自動刷新、程序崩潰、甚至瀏覽器直接被系統殺掉,因為視頻的base64字符串太大會撐報內存的。
如果上傳視頻文件后,想要對視頻的回顯可以使用createObjectUrl()
方法來生成臨時的內存地址來訪問。
0,前言
JavaScript 提供了一些 API 來處理文件或原始文件數據,例如:File、Blob、FileReader、ArrayBuffer、base64 等; 了解它們會對下面的一些方法更容易理解;
推薦閱讀以下博客
(知乎):1,https://zhuanlan.zhihu.com/p/568915443
(csdn):2,https://blog.csdn.net/mrlaochen/article/details/120209650
1,將圖片的url網絡鏈接(http://) 轉為base64格式
/*** 將圖片的url網絡鏈接(http://) 轉為base64格式* @param {string}*/export function imgUrlToBase64(imgUrl) {return new Promise((resolve) => {var img = new Image();img.src = imgUrl;// 設置圖片跨域屬性img.setAttribute("crossOrigin", "anonymous");// 注意 onload是異步的行為img.onload = () => {var canvas = document.createElement("canvas");canvas.width = img.width;canvas.height = img.height;var ctx = canvas.getContext("2d");ctx.drawImage(img, 0, 0);var dataURL = canvas.toDataURL("image/png");resolve(dataURL);};});
}
使用如下:
// 網絡圖片鏈接let finalImg = "https://img0.baidu.com/it/u=3021883569,1259262591&fm=253&fmt=auto&app=120&f=JPEG?w=1140&h=641";// 開始使用imgUrlToBase64(finalImg).then((res) => {console.log("res:", res);});
2,將base64的圖片數據轉換為file文件
/*** 將以base64的圖片數據轉換為File文件* @param {string}*/
export function base64ToFile(dataUrl, fileName = "myFile") {let arr = dataUrl.split(",");let mime = arr[0].match(/:(.*?);/)[1];let suffix = mime.split("/")[1];let bstr = atob(arr[1]);let n = bstr.length;let u8arr = new Uint8Array(n);while (n--) {u8arr[n] = bstr.charCodeAt(n);}return new File([u8arr], `${fileName}.${suffix}`, {type: mime});
}
使用案例:
<input type="file" />// 原生添加點擊事件document.getElementsByTagName("input")[0].onchange = async function (e) {// 拿到的文件類型let file = e.target.files[0];console.log("file:",file);// 先轉為base64let base64 = await fileTransferBase64(file);// 將以base64的圖片url數據轉換為File文件let file2 = base64ToFile(base64) ================注意看這行===================console.log("file2:", file2);};
3,將以base64的圖片數據轉換為Blob
/*** 將以base64的圖片數據轉換為Blob * @param urlData 用url方式表示的base64圖片數據*/function base64UrlToBlob(urlData, filename) {try {if (urlData == "" || !urlData) {return console.warn("urlData不存在");}if (!filename) {filename = "myfile";}// 以base64的圖片url數據轉換為Blobvar arr = urlData.split(","),mime = arr[0].match(/:(.*?);/)[1],bstr = atob(arr[1]),n = bstr.length,u8arr = new Uint8Array(n);while (n--) {u8arr[n] = bstr.charCodeAt(n);}let bold = new Blob([u8arr], { type: mime });return { bold, filename };} catch (error) {console.warn("base64轉換為Blob出問題了:", error);}}
使用案例:
<input type="file" />// 原生添加點擊事件document.getElementsByTagName("input")[0].onchange = async function (e) {// 拿到的文件類型let file = e.target.files[0];console.log("file:", file);let base64 = await fileTransferBase64(file);// 將以base64的圖片url數據轉換為File文件let blob = base64UrlToBlob(base64); =======注意這行=========console.log("blob:", blob);};
4,將file文件轉化為base64
/*** 將file文件轉化為base64 使用promise* @param file 該文件的file類型*/export function fileTransferBase64(file) {try {return new Promise((resolve, reject) => {const reader = new FileReader(); //異步讀取reader.readAsDataURL(file);// 成功和失敗返回對應的信息,reader.result一個base64,可以直接使用reader.onload = (e) => {resolve(e.target.result);};// 失敗返回失敗的信息reader.onerror = (error) => {console.warn('file文件轉化為base64s失敗:', error);reject(error);};});} catch (error) {console.warn('捕獲fileTransferBase64方法的錯誤:', error);}}
使用案例:
轉file類型 涉及到異步 所以要用 promise
來封裝一下;
<input type="file" />// 原生添加點擊事件document.getElementsByTagName("input")[0].onchange = async function (e) {// 拿到的文件類型let file = e.target.files[0];// 轉file類型 涉及到異步 所以要用 promiselet base64 = await fileTransferBase64(file)console.log("base64:",base64);};
5,將file文件轉換為Blob
/*** 直接將file數據轉換為Blob * @param file格式*/export function fileToBlob(file) {return new Promise((resolve, reject) => {// FileReader 異步讀取文件const reader = new FileReader();// readAsDataURL: dataurl它的本質就是圖片的二進制數據, 進行base64加密后形成的一個字符串,reader.readAsDataURL(file);// 成功和失敗返回對應的信息,reader.result一個base64,可以直接使用reader.onload = (e) => {let arr = e.target.result.split(',');let mime = arr[0].match(/:(.*?);/)[1];console.log(mime);const blob = new Blob([e.target.result], { type: mime });resolve(blob);};// 失敗返回失敗的信息reader.onerror = (error) => {console.warn('file數據轉換為Blob失敗:', error);reject(error);};});}
使用案例:
轉blob類型也涉及到異步 所以要用 promise
來封裝一下;
<input type="file" />// 原生添加點擊事件document.getElementsByTagName("input")[0].onchange = async function (e) {// 拿到的文件類型let file = e.target.files[0];// 轉file類型 涉及到異步 所以要用 promiselet blob = await fileToBlob(file);console.log("blob:", blob);};
6,獲取文件(圖片視頻等)的本地內存地址 可以直接訪問
此方法可以用來上傳文件之后的回顯。
/*** 獲取文件(圖片視頻等)的本地內存地址 可以直接訪問* @param file 該文件的文件流*/export function createObjectURLFun(file) {let url = '';if (window.createObjectURL != undefined) {// basicurl = window.createObjectURL(file);} else if (window.URL != undefined) {// mozilla(firefox)url = window.URL.createObjectURL(file);} else if (window.webkitURL != undefined) {// webkit or chromeurl = window.webkitURL.createObjectURL(file);}return url;}
使用案例:
// 原生添加點擊事件document.getElementsByTagName("input")[0].onchange = async function (e) {// 拿到的文件類型let file = e.target.files[0];let objectURL = createObjectURLFun(file)console.log("objectURL:", objectURL); //打印結果: objectURL: blob:null/31fff142-4b83-4749-b71d-a9a4f6c16a43};
7,視頻截幀(截取視頻的第一幀)
常用上傳視頻文件后截取視頻文件的第一幀當做封面使用;
第一種:
/*** 獲取視頻的第一幀 來當做封面 * @param url 視頻的url 可以是一個由window.URL.createObjectURL返回的視頻內存臨時地址(推薦使用)*/
export function getFirstImg(url) {return new Promise(function (resolve, reject) {try {let dataURL = '';let width = '90'; // 單位是px 可以隨意更改let height = '90';let listen = 'canplay';//需要監聽的事件let video = document.createElement('video');let canvas = document.createElement('canvas');//使用嚴格模式('use strict');video.setAttribute('crossOrigin', 'anonymous'); //處理跨域video.setAttribute('src', url);video.setAttribute('width', width);video.setAttribute('height', height);video.currentTime = 1; // 第一幀video.preload = 'auto'; //metadata:抓取原數據//判斷IOS 監聽 durationchange或progress 但是在ios會出現黑屏if (/iPad|iPhone|iPod/.test(navigator.userAgent)) {video.load();video.autoplay = true;video.muted = true; //靜音listen = 'loadeddata';}// 第二版 dataLoadvideo.addEventListener(listen, () => {console.log("我走了");canvas.width = width;canvas.height = height;canvas.getContext('2d').drawImage(video, 0, 0, width, height); //繪制canvasdataURL = canvas.toDataURL('image/jpeg'); //轉換為base64resolve(dataURL);});} catch (error) {console.log('視頻截幀的失敗報錯:', error);}});
}
第二種:
export function getFirstImg2(url) {const video = document.createElement("video");video.crossOrigin = "anonymous"; // 允許url跨域video.autoplay = true; // 自動播放video.muted = true; // 靜音video.src = url;return new Promise((resolve, reject) => {try {video.addEventListener("loadedmetadata",() => {console.log("loadedmetadata");video.currentTime = 2;const canvas = document.createElement("canvas");video.addEventListener("canplaythrough", () => {console.log("canplaythrough");canvas.width = video.videoWidth;canvas.height = video.videoHeight;canvas.getContext("2d").drawImage(video, 0, 0, canvas.width, canvas.height);const firstFrame = canvas.toDataURL();// console.log(firstFrame); // 輸出第一幀畫面的Base64編碼字符串resolve(firstFrame);});},{ once: true });} catch (err) {console.error(err);reject("");}});
}
8,總結
以上的幾個方法如果使用了new Promise
說明里面存在異步操作,那么在調用的時候要使用 .then
來獲取轉換后的文件。或直接使用 async await
語法進行接收resolve ()
方法返回的文件;
保證代碼能夠同步運行,避免預料之外的問題;