diff --git a/web/src/lib/utils/asset-utils.ts b/web/src/lib/utils/asset-utils.ts index 84e386d620058..9240a2fddde4a 100644 --- a/web/src/lib/utils/asset-utils.ts +++ b/web/src/lib/utils/asset-utils.ts @@ -301,19 +301,54 @@ const supportedImageMimeTypes = new Set([ 'image/webp', ]); -const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); // https://stackoverflow.com/a/23522755 -if (isSafari) { - supportedImageMimeTypes.add('image/heic').add('image/heif'); -} +async function addSupportedMimeTypes(): Promise { + const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); // https://stackoverflow.com/a/23522755 + if (isSafari) { + const match = navigator.userAgent.match(/Version\/(\d+)/); + + if (!match) { + return; + } + + const majorVersion = Number.parseInt(match[1]); + const MIN_REQUIRED_VERSION = 17; + + if (majorVersion >= MIN_REQUIRED_VERSION) { + supportedImageMimeTypes.add('image/jxl').add('image/heic').add('image/heif'); + } + + return; + } -function checkJxlSupport(): void { - const img = new Image(); - img.addEventListener('load', () => { + if (globalThis.isSecureContext && typeof ImageDecoder !== 'undefined') { + const dynamicMimeTypes = [{ type: 'image/jxl' }, { type: 'image/heic', aliases: ['image/heif'] }]; + + for (const mime of dynamicMimeTypes) { + const isMimeTypeSupported = await ImageDecoder.isTypeSupported(mime.type); + if (isMimeTypeSupported) { + for (const mimeType of [mime.type, ...(mime.aliases || [])]) { + supportedImageMimeTypes.add(mimeType); + } + } + } + + return; + } + + const jxlImg = new Image(); + jxlImg.addEventListener('load', () => { supportedImageMimeTypes.add('image/jxl'); }); - img.src = 'data:image/jxl;base64,/woIAAAMABKIAgC4AF3lEgA='; // Small valid JPEG XL image + jxlImg.src = 'data:image/jxl;base64,/woIAAAMABKIAgC4AF3lEgA='; // Small valid JPEG XL image + + const heicImg = new Image(); + heicImg.addEventListener('load', () => { + supportedImageMimeTypes.add('image/heic'); + }); + heicImg.src = + 'data:image/heic;base64,AAAAGGZ0eXBoZWljAAAAAG1pZjFoZWljAAABrW1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAHBpY3QAAAAAAAAAAAAAAAAAAAAADnBpdG0AAAAAAAIAAAAQaWRhdAAAAAAAAQABAAAAOGlsb2MBAAAAREAAAgABAAAAAAAAAc0AAQAAAAAAAAAsAAIAAQAAAAAAAAABAAAAAAAAAAgAAAA4aWluZgAAAAAAAgAAABVpbmZlAgAAAQABAABodmMxAAAAABVpbmZlAgAAAAACAABncmlkAAAAANhpcHJwAAAAtmlwY28AAAB2aHZjQwEDcAAAAAAAAAAAAB7wAPz9+PgAAA8DIAABABhAAQwB//8DcAAAAwCQAAADAAADAB66AkAhAAEAKkIBAQNwAAADAJAAAAMAAAMAHqAggQWW6q6a5uBAQMCAAAADAIAAAAMAhCIAAQAGRAHBc8GJAAAAFGlzcGUAAAAAAAAAAQAAAAEAAAAUaXNwZQAAAAAAAABAAAAAQAAAABBwaXhpAAAAAAMICAgAAAAaaXBtYQAAAAAAAAACAAECgQMAAgIChAAAABppcmVmAAAAAAAAAA5kaW1nAAIAAQABAAAANG1kYXQAAAAoKAGvCchMZYA50NoPIfzz81Qfsm577GJt3lf8kLAr+NbNIoeRR7JeYA=='; // Small valid HEIC/HEIF image } -checkJxlSupport(); +void addSupportedMimeTypes(); /** * Returns true if the asset is an image supported by web browsers, false otherwise