@tldraw/utils
Version:
tldraw infinite canvas SDK (private utilities).
189 lines (182 loc) • 6.62 kB
text/typescript
import { fetch } from './network'
/**
* Utility class providing helper methods for file and blob operations.
*
* FileHelpers contains static methods for common file operations including
* URL fetching, format conversion, and MIME type manipulation. All methods work with
* web APIs like fetch, FileReader, and Blob/File objects.
*
* @example
* ```ts
* // Fetch and convert a remote image to data URL
* const dataUrl = await FileHelpers.urlToDataUrl('https://example.com/image.png')
*
* // Convert user-selected file to text
* const text = await FileHelpers.blobToText(userFile)
*
* // Change file MIME type
* const newFile = FileHelpers.rewriteMimeType(originalFile, 'application/json')
* ```
*
* @public
*/
export class FileHelpers {
/**
* Converts a URL to an ArrayBuffer by fetching the resource.
*
* Fetches the resource at the given URL and returns its content as an ArrayBuffer.
* This is useful for loading binary data like images, videos, or other file types.
*
* @param url - The URL of the file to fetch
* @returns Promise that resolves to the file content as an ArrayBuffer
* @example
* ```ts
* const buffer = await FileHelpers.urlToArrayBuffer('https://example.com/image.png')
* console.log(buffer.byteLength) // Size of the file in bytes
* ```
* @public
*/
static async urlToArrayBuffer(url: string) {
const response = await fetch(url)
return await response.arrayBuffer()
}
/**
* Converts a URL to a Blob by fetching the resource.
*
* Fetches the resource at the given URL and returns its content as a Blob object.
* Blobs are useful for handling file data in web applications.
*
* @param url - The URL of the file to fetch
* @returns Promise that resolves to the file content as a Blob
* @example
* ```ts
* const blob = await FileHelpers.urlToBlob('https://example.com/document.pdf')
* console.log(blob.type) // 'application/pdf'
* console.log(blob.size) // Size in bytes
* ```
* @public
*/
static async urlToBlob(url: string) {
const response = await fetch(url)
return await response.blob()
}
/**
* Converts a URL to a data URL by fetching the resource.
*
* Fetches the resource at the given URL and converts it to a base64-encoded data URL.
* If the URL is already a data URL, it returns the URL unchanged. This is useful for embedding
* resources directly in HTML or CSS.
*
* @param url - The URL of the file to convert, or an existing data URL
* @returns Promise that resolves to a data URL string
* @example
* ```ts
* const dataUrl = await FileHelpers.urlToDataUrl('https://example.com/image.jpg')
* // Returns: 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEA...'
*
* const existing = await FileHelpers.urlToDataUrl('data:text/plain;base64,SGVsbG8=')
* // Returns the same data URL unchanged
* ```
* @public
*/
static async urlToDataUrl(url: string) {
if (url.startsWith('data:')) return url
const blob = await FileHelpers.urlToBlob(url)
return await FileHelpers.blobToDataUrl(blob)
}
/**
* Convert a Blob to a base64 encoded data URL.
*
* Converts a Blob object to a base64-encoded data URL using the FileReader API.
* This is useful for displaying images or embedding file content directly in HTML.
*
* @param file - The Blob object to convert
* @returns Promise that resolves to a base64-encoded data URL string
* @example
* ```ts
* const blob = new Blob(['Hello World'], { type: 'text/plain' })
* const dataUrl = await FileHelpers.blobToDataUrl(blob)
* // Returns: 'data:text/plain;base64,SGVsbG8gV29ybGQ='
*
* // With an image file
* const imageDataUrl = await FileHelpers.blobToDataUrl(myImageFile)
* // Can be used directly in img src attribute
* ```
* @public
*/
static async blobToDataUrl(file: Blob): Promise<string> {
return await new Promise((resolve, reject) => {
if (file) {
const reader = new FileReader()
reader.onload = () => resolve(reader.result as string)
reader.onerror = (error) => reject(error)
reader.onabort = (error) => reject(error)
reader.readAsDataURL(file)
}
})
}
/**
* Convert a Blob to a unicode text string.
*
* Reads the content of a Blob object as a UTF-8 text string using the FileReader API.
* This is useful for reading text files or extracting text content from blobs.
*
* @param file - The Blob object to convert to text
* @returns Promise that resolves to the text content as a string
* @example
* ```ts
* const textBlob = new Blob(['Hello World'], { type: 'text/plain' })
* const text = await FileHelpers.blobToText(textBlob)
* console.log(text) // 'Hello World'
*
* // With a text file from user input
* const content = await FileHelpers.blobToText(myTextFile)
* console.log(content) // File content as string
* ```
* @public
*/
static async blobToText(file: Blob): Promise<string> {
return await new Promise((resolve, reject) => {
if (file) {
const reader = new FileReader()
reader.onload = () => resolve(reader.result as string)
reader.onerror = (error) => reject(error)
reader.onabort = (error) => reject(error)
reader.readAsText(file)
}
})
}
/**
* Creates a new Blob or File with a different MIME type.
*
* Creates a copy of the given Blob or File with a new MIME type while preserving
* all other properties. If the current MIME type already matches the new one, returns the
* original object unchanged. For File objects, preserves the filename.
*
* @param blob - The Blob or File object to modify
* @param newMimeType - The new MIME type to assign
* @returns A new Blob or File with the updated MIME type
* @example
* ```ts
* // Change a generic blob to a specific image type
* const blob = new Blob([imageData])
* const imageBlob = FileHelpers.rewriteMimeType(blob, 'image/png')
*
* // Change a file's MIME type while preserving filename
* const file = new File([data], 'document.txt', { type: 'text/plain' })
* const jsonFile = FileHelpers.rewriteMimeType(file, 'application/json')
* console.log(jsonFile.name) // 'document.txt' (preserved)
* console.log(jsonFile.type) // 'application/json' (updated)
* ```
* @public
*/
static rewriteMimeType(blob: Blob, newMimeType: string): Blob
static rewriteMimeType(blob: File, newMimeType: string): File
static rewriteMimeType(blob: Blob | File, newMimeType: string): Blob | File {
if (blob.type === newMimeType) return blob
if (blob instanceof File) {
return new File([blob], blob.name, { type: newMimeType })
}
return new Blob([blob], { type: newMimeType })
}
}