import { md5 } from "../../crypto/funcs/md5" import { sha256 } from "../../crypto/funcs/sha256" import { setUnEnumerable } from "../../objects" import { jsonParse } from "../../objects/funcs/jsonParse" import { blobReadText } from "./blobReadText" /** 从 Blob 中读取数据,会缓存结果到 Blob 对象上,以减少多次调用的开销 * * 对 blob._u8a 支持,即如果 blob 对象上有一个自定义属性 _u8a,且它是一个 Uint8Array,则表示这个 Blob 的数据内容, * 这是 Safari 下 Figma 插件无法读取 Blob 的 ArrayBuffer 时的一个变通方案 * */ export class BlobReader { static async getText(blob: Blob) { return getCahce(blob, "text", async () => { // 如果 blob 有 _u8a 属性,直接使用它 if ((blob as any)._u8a) { const decoder = new TextDecoder() return decoder.decode((blob as any)._u8a) } return blobReadText(blob) }) } static async getJSON(blob: Blob) { return getCahce(blob, "json", async () => { // 如果 blob 有 _u8a 属性,直接使用它 let text: string if ((blob as any)._u8a) { const decoder = new TextDecoder() text = decoder.decode((blob as any)._u8a) } else { text = await blobReadText(blob) } return jsonParse(text) }) } static async getMD5(blob: Blob) { return getCahce(blob, "md5", async () => { // 如果 blob 有 _u8a 属性,直接使用它 if ((blob as any)._u8a) { return await md5((blob as any)._u8a, { outMore: true }) } return await md5(blob, { outMore: true }) }) } static async getSHA256(blob: Blob) { return getCahce(blob, "sha256", async () => { // 如果 blob 有 _u8a 属性,直接使用它 if ((blob as any)._u8a) { return await sha256((blob as any)._u8a, { outMore: true }) } return await sha256(blob, { outMore: true }) }) } static async getArrayBuffer(blob: Blob) { return getCahce(blob, "arrayBuffer", async () => { // 如果 blob 有 _u8a 属性,直接使用它 if ((blob as any)._u8a) { return (blob as any)._u8a.buffer } return await blob.arrayBuffer() }) } /** * 获取自定义数据 * 对一个 blob 使用自定义数据处理函数得到一个数据,这个数据会被缓存到 blob 对象上 * 例如,可以使用这个函数来获取图片的 ImageData 对象 * @example * let imageData = await BlobReader.getCustomData(blob, "imageData", async (blob) => blobToImageData(blob)) * * @param blob * @param key * @param dataHandler * @returns */ static async getCustomData(blob: Blob, key: string, dataHandler: (blob: Blob) => Promise) { return getCahce(blob, `custom_${key}`, async () => { return await dataHandler(blob) }) } static async clearBlobCache(blob: Blob) { for (let key in blob) { if (key.startsWith("__cache_")) { delete (blob)[key] } } } } async function getCahce(blob: Blob, cacheKey: string, getter: () => Promise): Promise { let finKey = `__cache_${cacheKey}` let cache = (blob)[finKey] if (cache) { return cache } else { let value = await getter() setUnEnumerable(blob, finKey, value) return value } }