獲取剪下板的圖片 -> File -> Base64 -> Blob -> url -> Image,以及它們之間的各種相互轉換

林恒發表於2024-12-03

🧑‍💻 寫在開頭

點贊 + 收藏 === 學會🤣🤣🤣

一、獲取剪下板的圖片(拿到 File 物件)

js貼上事件paste簡單解析及遇到的坑 - 雲+社群 - 騰訊雲 (tencent.com)

document.addEventListener('paste', function(event) {
    let items = event.clipboardData && event.clipboardData.items;
    let file: any = null;
    if (items && items.length) {
        // 檢索剪下板items
        for (var i = 0; i < items.length; i++) {
            if (items[i].type.indexOf('image') !== -1) {
                file = items[i].getAsFile();
                break;
            }
        }
    }
    fileByBase64(file, (base64) => {
        shotCallback(base64);
    });
    console.log('file', file);
    // 此時file就是剪下板中的圖片檔案
});

本來想直接獲取這個物件的,然鵝這個 clipboardData 物件只存在於 ClipboardEvent 事件中,只能在事件(這裡是 parse 事件)觸發的時候才能拿到。

ClipboardEvent.clipboardData - Web API 介面參考 | MDN (mozilla.org)

題外話:可以直接用 navigator.clipboard 獲取到剪下板內容(拿到 Blob 物件)

Navigator.clipboard - Web API 介面參考 | MDN (mozilla.org)

剪貼簿操作 Clipboard API 教程 - 阮一峰的網路日誌 (ruanyifeng.com)

const getClipboard = async () => {
    const clipboardItems = await navigator.clipboard.read();
    for (const clipboardItem of clipboardItems) {
        for (const type of clipboardItem.types) {
            const blob = await clipboardItem.getType(type);
            console.log(URL.createObjectURL(blob));
        }
    }
};

二、File 物件轉 Base64(利用 FileReader)

const fileByBase64 = (file, callback) => {
    const reader = new FileReader();
    // 傳入一個引數物件即可得到基於該引數物件的文字內容
    reader.readAsDataURL(file);
    reader.onload = function(e: any) {
        // target.result 該屬性表示目標物件的 DataURL
        console.log(e.target.result);
        callback(e.target.result);
    };
};

題外話 canvas -> dataUrl(Base64)

才發現 Base64 是 DataUrl 的編碼,可以理解為一種東西吧。

canvas 物件可以直接轉變成 base64,有一個很常用的 api:

const dataURL = canvas.toDataURL();

三、Base64 轉 Blob

const base64ByBlob = (base64, callback) => {
    let arr = base64.split(','),
        mime = arr[0].match(/:(.*?);/)[1],
        bstr = atob(arr[1]),
        n = bstr.length,
        u8arr = new Uint8Array(n);
    while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
    }
    console.log(new Blob([u8arr], { type: mime }));
    callback(new Blob([u8arr], { type: mime }));
};

題外話:Blob -> Base64(利用 FileReader)

由於 File 是特殊型別的 Blob,所以跟 File -> Base64 是一樣的。

function blobToDataURI(blob, callback) {
    var reader = new FileReader();
    reader.onload = function (e) {
        callback(e.target?.result);
    };
    reader.readAsDataURL(blob);
}

題外話:File <--> Blob

它倆可以用建構函式直接相互轉換,沒有中間商 Base64。不過 file -> blob 會丟失 filename。

const blob = new Blob([file], {
	type: file.type
}
const file = new File([blob], filename, {
	type: blob.type
});

四、blob 轉 url、file 轉 url

const url1 = window.URL.createObjectURL(blob);
const url2 = window.URL.createObjectURL(file);

這裡的 file 會被當做 blob 物件來使用,畢竟 file 是特殊的 blob,所以輸出結果都是:

blob:http://localhost:3000/1df14e9d-b9d3-43d5-87ff-2f7c0ae44a9d

這種由 blob:http:// 開頭的路徑。

題外話:url -> blob

const urlToBlob = () => {
	fetch(url)
		.then((res) => res.blob())
		.then((blob) => console.log(blob));
};

五、url 變 Image

const img = new Image();
img.src = url;

綜合應用:獲取剪下板圖片並轉成 Base64,然後 Base64 轉成 Blob,然後 Blob 轉成 url,然後轉成圖片 append 到 body 上

document.addEventListener('paste', function(event) {
    let items = event.clipboardData && event.clipboardData.items;
    console.log('items', items);
    let file: any = null;
    if (items && items.length) {
        // 檢索剪下板 items
        for (var i = 0; i < items.length; i++) {
            if (items[i].type.indexOf('image') !== -1) {
                // 此時file就是剪下板中的圖片檔案
                file = items[i].getAsFile();
                break;
            }
        }
    }
    fileByBase64(file, base64 => {
        base64ByBlob(base64, (blob) => {
            const url = window.URL.createObjectURL(blob);
            console.log('url', url);
            const img = new Image();
            img.src = url;
            img.onload = () => {
                document.body.appendChild(img);
            };
        });
    });
});

如果不需要額外使用 Base64 的話,直接用 file 物件替代 blob 也是可以的,因為 file 只是特殊的 blob,大家都是二進位制檔案:

document.addEventListener('paste', function(event) {
    let items = event.clipboardData && event.clipboardData.items;
    console.log('items', items);
    let file: any = null;
    if (items && items.length) {
        // 檢索剪下板 items
        for (var i = 0; i < items.length; i++) {
            if (items[i].type.indexOf('image') !== -1) {
                // 此時file就是剪下板中的圖片檔案
                file = items[i].getAsFile();
                break;
            }
        }
    }
    const url = window.URL.createObjectURL(file);
    console.log('url', url);
    const img = new Image();
    img.src = url;
    img.onload = () => {
        document.body.appendChild(img);
    };
});

如果對您有所幫助,歡迎您點個關注,我會定時更新技術文件,大家一起討論學習,一起進步。

獲取剪下板的圖片 -> File -> Base64 -> Blob -> url -> Image,以及它們之間的各種相互轉換

相關文章