Simpler canDecode check

This commit is contained in:
Jake Archibald
2020-08-26 11:41:21 +01:00
parent fd5c557065
commit 6e52ac2a73
5 changed files with 36 additions and 18 deletions

View File

@@ -1,23 +1,16 @@
import { builtinDecode, sniffMimeType, canDecodeImage } from '../lib/util';
import { builtinDecode, sniffMimeType, canDecodeImageType } from '../lib/util';
import Processor from './processor';
import webpDataUrl from 'url-loader!./tiny.webp';
import avifDataUrl from 'url-loader!./tiny.avif';
const webPSupported = canDecodeImage(webpDataUrl);
const avifSupported = canDecodeImage(avifDataUrl);
export async function decodeImage(blob: Blob, processor: Processor): Promise<ImageData> {
const mimeType = await sniffMimeType(blob);
const canDecode = await canDecodeImageType(mimeType);
try {
if (mimeType === 'image/avif' && !(await avifSupported)) {
return await processor.avifDecode(blob);
if (!canDecode) {
if (mimeType === 'image/avif') return await processor.avifDecode(blob);
if (mimeType === 'image/webp') return await processor.webpDecode(blob);
// If it's not one of those types, fall through and try built-in decoding for a laugh.
}
if (mimeType === 'image/webp' && !(await webPSupported)) {
return await processor.webpDecode(blob);
}
// Otherwise, just throw it at the browser's decoder.
return await builtinDecode(blob);
} catch (err) {
throw Error("Couldn't decode image");

View File

@@ -78,11 +78,36 @@ async function decodeImage(url: string): Promise<HTMLImageElement> {
return img;
}
/** Caches results from canDecodeImageType */
const canDecodeCache = new Map<string, Promise<boolean>>();
/**
* Attempts to load the given URL as an image.
* Tests whether the browser supports a particular image mime type.
*
* @param type Mimetype
* @example await canDecodeImageType('image/avif')
*/
export function canDecodeImage(url: string): Promise<boolean> {
return decodeImage(url).then(() => true, () => false);
export function canDecodeImageType(type: string): Promise<boolean> {
if (!canDecodeCache.has(type)) {
const resultPromise = (async () => {
const picture = document.createElement('picture');
const img = document.createElement('img');
const source = document.createElement('source');
source.srcset = 'data:,x';
source.type = type;
picture.append(source, img);
// Wait a single microtick just for the `img.currentSrc` to get populated.
await 0;
// At this point `img.currentSrc` will contain "data:,x" if format is supported and ""
// otherwise.
return !!img.currentSrc;
})();
canDecodeCache.set(type, resultPromise);
}
return canDecodeCache.get(type)!;
}
export function blobToArrayBuffer(blob: Blob): Promise<ArrayBuffer> {

View File

Before

Width:  |  Height:  |  Size: 303 B

After

Width:  |  Height:  |  Size: 303 B

View File

Before

Width:  |  Height:  |  Size: 38 B

After

Width:  |  Height:  |  Size: 38 B

View File

@@ -1,5 +1,5 @@
import webpDataUrl from 'url-loader!../codecs/tiny.webp';
import avifDataUrl from 'url-loader!../codecs/tiny.avif';
import webpDataUrl from 'url-loader!./tiny.webp';
import avifDataUrl from 'url-loader!./tiny.avif';
// Give TypeScript the correct global.
declare var self: ServiceWorkerGlobalScope;