From 95f77351644980159feeed829c11ccc2ce00882f Mon Sep 17 00:00:00 2001 From: Manav Rathi Date: Thu, 3 Apr 2025 15:28:53 +0530 Subject: [PATCH] Add test --- web/packages/gallery/utils/convert.ts | 35 ++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/web/packages/gallery/utils/convert.ts b/web/packages/gallery/utils/convert.ts index 3cb3dbc757..4157916a9c 100644 --- a/web/packages/gallery/utils/convert.ts +++ b/web/packages/gallery/utils/convert.ts @@ -69,7 +69,7 @@ export const renderableImageBlob = async ( // render HEICs, e.g. Safari 18+. In such cases not only is the // Wasm conversion unnecessary, the native hardware accelerated // support will also be _much_ faster. - if (mimeType == "image/heic" && /*TODO*/ false) { + if (mimeType == "image/heic" && (await isHEICSupported())) { log.debug( () => `Using native HEIC support for ${fileName}`, ); @@ -123,6 +123,39 @@ const nativeConvertToJPEG = async (imageBlob: Blob) => { return new Blob([jpegData], { type: "image/jpeg" }); }; +let _isHEICSupported: Promise | undefined; + +/** + * Return true if the browser can natively render HEIC files. + * + * For performance, the result of the check is cached. There shouldn't be a + * reason for this cache to need be invalidated, the browser should drop its + * HEIC support in the middle of it running (but I'm sure posterity will prove + * this assumption wrong in a way I can't yet anticipate). + * + * Some more details: + * + * - The check works by trying to load a small HEIC file. + * + * - Currently (Spring 2025), the only browser with support for HEIC is Safari. + */ +const isHEICSupported = () => + (_isHEICSupported ??= new Promise((resolve) => { + const image = new Image(); + image.onload = () => resolve(true); + image.onerror = () => resolve(false); + image.src = testHEICDataURL; + })); + +/** + * A data URL encoding the smallest HEIC image (439 bytes). + * + * Source: + * https://github.com/vvideo/detect-audio-video/blob/main/src/image/smallest/index.ts + */ +const testHEICDataURL = + "data:image/heic;base64,AAAAGGZ0eXBoZWljAAAAAG1pZjFoZWljAAABaW1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAHBpY3QAAAAAAAAAAAAAAAAAAAAADnBpdG0AAAAAAAEAAAAiaWxvYwAAAABEQAABAAEAAAAAAYkAAQAAAAAAAAAuAAAAI2lpbmYAAAAAAAEAAAAVaW5mZQIAAAAAAQAAaHZjMQAAAADpaXBycAAAAMppcGNvAAAAdmh2Y0MBA3AAAAAAAAAAAAAe8AD8/fj4AAAPAyAAAQAYQAEMAf//A3AAAAMAkAAAAwAAAwAeugJAIQABACpCAQEDcAAAAwCQAAADAAADAB6gIIEFluqumubgIaDAgAAAAwCAAAADAIQiAAEABkQBwXPBiQAAABRpc3BlAAAAAAAAAEAAAABAAAAAKGNsYXAAAAABAAAAAQAAAAEAAAAB////wQAAAAL////BAAAAAgAAABBwaXhpAAAAAAMICAgAAAAXaXBtYQAAAAAAAAABAAEEgQKDBAAAADZtZGF0AAAAKigBrwayEx2gkim3i/2Rd0CR/V6h6GbEyV3dheegYfLV9ZwraCH8nff+7w=="; + /** * Return a new {@link Blob} containing a video's data in a format that the * browser (likely) knows how to play back (using an video tag).