@loaders.gl/images
Version:
Framework-independent loaders and writers for images (PNG, JPG, ...)
107 lines • 4.24 kB
JavaScript
// loaders.gl
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors
import { isBrowser } from '@loaders.gl/loader-utils';
const MIME_TYPES = [
'image/png',
'image/jpeg',
'image/gif',
'image/webp',
'image/avif',
'image/tiff',
// TODO - what is the correct type for SVG
'image/svg',
'image/svg+xml',
'image/bmp',
'image/vnd.microsoft.icon'
];
/** Only one round of tests is performed */
const mimeTypeSupportedPromise = null;
/** Run-time browser detection of file formats requires async tests for most precise results */
export async function getSupportedImageFormats() {
if (mimeTypeSupportedPromise) {
return await mimeTypeSupportedPromise;
}
const supportedMimeTypes = new Set();
for (const mimeType of MIME_TYPES) {
const supported = isBrowser
? await checkBrowserImageFormatSupportAsync(mimeType)
: checkNodeImageFormatSupport(mimeType);
if (supported) {
supportedMimeTypes.add(mimeType);
}
}
return supportedMimeTypes;
}
/** Cache sync values for speed */
const mimeTypeSupportedSync = {};
/**
* Check if image MIME type is supported. Result is cached to avoid repeated tests.
*/
export function isImageFormatSupported(mimeType) {
if (mimeTypeSupportedSync[mimeType] === undefined) {
const supported = isBrowser
? checkBrowserImageFormatSupport(mimeType)
: checkNodeImageFormatSupport(mimeType);
mimeTypeSupportedSync[mimeType] = supported;
}
return mimeTypeSupportedSync[mimeType];
}
/**
* Checks that polyfills are installed and that mimeType is supported by polyfills
* @todo Ideally polyfills should declare what formats they support, instead of storing that data here.
*/
function checkNodeImageFormatSupport(mimeType) {
const NODE_FORMAT_SUPPORT = ['image/png', 'image/jpeg', 'image/gif'];
const imageFormatsNode = globalThis.loaders?.imageFormatsNode || NODE_FORMAT_SUPPORT;
const parseImageNode = globalThis.loaders?.parseImageNode;
return Boolean(parseImageNode) && imageFormatsNode.includes(mimeType);
}
/** Checks image format support synchronously.
* @note Unreliable, fails on AVIF
*/
function checkBrowserImageFormatSupport(mimeType) {
switch (mimeType) {
case 'image/avif': // Will fail
case 'image/webp':
return testBrowserImageFormatSupport(mimeType);
default:
return true;
}
}
const TEST_IMAGE = {
'image/avif': 'data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAAB0AAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAIAAAACAAAAEHBpeGkAAAAAAwgICAAAAAxhdjFDgQ0MAAAAABNjb2xybmNseAACAAIAAYAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAACVtZGF0EgAKCBgANogQEAwgMg8f8D///8WfhwB8+ErK42A=',
// Lossy test image. Support for lossy images doesn't guarantee support for all WebP images.
'image/webp': 'data:image/webp;base64,UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA'
};
/** Checks WebP and AVIF support asynchronously */
async function checkBrowserImageFormatSupportAsync(mimeType) {
const dataURL = TEST_IMAGE[mimeType];
return dataURL ? await testBrowserImageFormatSupportAsync(dataURL) : true;
}
/**
* Checks browser synchronously
* Checks if toDataURL supports the mimeType.
* @note Imperfect testOn Chrome this is true for WebP but not for AVIF
*/
function testBrowserImageFormatSupport(mimeType) {
try {
const element = document.createElement('canvas');
const dataURL = element.toDataURL(mimeType);
return dataURL.indexOf(`data:${mimeType}`) === 0;
}
catch {
// Probably Safari...
return false;
}
}
// Check WebPSupport asynchronously
async function testBrowserImageFormatSupportAsync(testImageDataURL) {
return new Promise((resolve) => {
const image = new Image();
image.src = testImageDataURL;
image.onload = () => resolve(image.height > 0);
image.onerror = () => resolve(false);
});
}
//# sourceMappingURL=image-format.js.map