60 lines
1.7 KiB
TypeScript
60 lines
1.7 KiB
TypeScript
export interface MediaDimensions {
|
|
height: number
|
|
width: number
|
|
}
|
|
|
|
const METADATA_TIMEOUT_MS = 10_000
|
|
|
|
function waitForDimensions(
|
|
file: File,
|
|
element: HTMLImageElement | HTMLVideoElement,
|
|
successEvent: "load" | "loadedmetadata"
|
|
): Promise<MediaDimensions | undefined> {
|
|
return new Promise((resolve) => {
|
|
const objectUrl = URL.createObjectURL(file)
|
|
let settled = false
|
|
const timeout = window.setTimeout(finish, METADATA_TIMEOUT_MS)
|
|
|
|
function finish(dimensions?: MediaDimensions) {
|
|
if (settled) return
|
|
settled = true
|
|
window.clearTimeout(timeout)
|
|
URL.revokeObjectURL(objectUrl)
|
|
resolve(dimensions)
|
|
}
|
|
|
|
element.addEventListener(
|
|
successEvent,
|
|
() => {
|
|
const width =
|
|
element instanceof HTMLVideoElement
|
|
? element.videoWidth
|
|
: element.naturalWidth
|
|
const height =
|
|
element instanceof HTMLVideoElement
|
|
? element.videoHeight
|
|
: element.naturalHeight
|
|
finish(width > 0 && height > 0 ? { height, width } : undefined)
|
|
},
|
|
{ once: true }
|
|
)
|
|
element.addEventListener("error", () => finish(), { once: true })
|
|
element.src = objectUrl
|
|
})
|
|
}
|
|
|
|
/** Reads intrinsic dimensions before an adapter uploads an image or video. */
|
|
export function readMediaDimensions(
|
|
file: File
|
|
): Promise<MediaDimensions | undefined> {
|
|
if (file.type.startsWith("image/")) {
|
|
return waitForDimensions(file, new Image(), "load")
|
|
}
|
|
if (file.type.startsWith("video/")) {
|
|
const video = document.createElement("video")
|
|
video.preload = "metadata"
|
|
return waitForDimensions(file, video, "loadedmetadata")
|
|
}
|
|
return Promise.resolve(undefined)
|
|
}
|