From b3f9c170a4a6c7e3aa0923585f0eadb54192fe5e Mon Sep 17 00:00:00 2001 From: SuperSodaSea Date: Sun, 27 Nov 2022 02:48:02 +0800 Subject: [PATCH 1/2] Support loading font assets in data URLs --- .../assets/src/loader/parsers/loadWebFont.ts | 18 +++++++++----- .../loader/parsers/textures/loadTextures.ts | 24 ++++++++----------- .../loader/parsers/textures/utils/index.ts | 1 - packages/assets/src/utils/checkDataUrl.ts | 14 +++++++++++ .../textures => }/utils/checkExtension.ts | 0 packages/assets/src/utils/index.ts | 2 ++ 6 files changed, 38 insertions(+), 21 deletions(-) create mode 100644 packages/assets/src/utils/checkDataUrl.ts rename packages/assets/src/{loader/parsers/textures => }/utils/checkExtension.ts (100%) diff --git a/packages/assets/src/loader/parsers/loadWebFont.ts b/packages/assets/src/loader/parsers/loadWebFont.ts index fada6bddb3..2d4bb8fbef 100644 --- a/packages/assets/src/loader/parsers/loadWebFont.ts +++ b/packages/assets/src/loader/parsers/loadWebFont.ts @@ -1,13 +1,22 @@ import { extensions, ExtensionType, settings, utils } from '@pixi/core'; +import { checkDataUrl } from '../../utils/checkDataUrl'; +import { checkExtension } from '../../utils/checkExtension'; import { LoaderParserPriority } from './LoaderParser'; import type { LoadAsset } from '../types'; import type { LoaderParser } from './LoaderParser'; -const validWeights = ['normal', 'bold', +const validWeights = [ + 'normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900', ]; -const validFonts = ['woff', 'woff2', 'ttf', 'otf']; +const validFontExtensions = ['.ttf', '.otf', '.woff', '.woff2']; +const validFontMIMEs = [ + 'font/ttf', + 'font/otf', + 'font/woff', + 'font/woff2', +]; export type LoadFontData = { family: string; @@ -51,10 +60,7 @@ export const loadWebFont = { test(url: string): boolean { - const tempURL = url.split('?')[0]; - const extension = tempURL.split('.').pop(); - - return validFonts.includes(extension); + return checkDataUrl(url, validFontMIMEs) || checkExtension(url, validFontExtensions); }, async load(url: string, options?: LoadAsset): Promise diff --git a/packages/assets/src/loader/parsers/textures/loadTextures.ts b/packages/assets/src/loader/parsers/textures/loadTextures.ts index 72fd780521..4ba9a30999 100644 --- a/packages/assets/src/loader/parsers/textures/loadTextures.ts +++ b/packages/assets/src/loader/parsers/textures/loadTextures.ts @@ -1,7 +1,8 @@ import { BaseTexture, extensions, ExtensionType, settings, utils } from '@pixi/core'; +import { checkDataUrl } from '../../../utils/checkDataUrl'; +import { checkExtension } from '../../../utils/checkExtension'; import { LoaderParserPriority } from '../LoaderParser'; import { WorkerManager } from '../WorkerManager'; -import { checkExtension } from './utils/checkExtension'; import { createTexture } from './utils/createTexture'; import type { IBaseTextureOptions, Texture } from '@pixi/core'; @@ -9,7 +10,13 @@ import type { Loader } from '../../Loader'; import type { LoadAsset } from '../../types'; import type { LoaderParser } from '../LoaderParser'; -const validImages = ['.jpg', '.png', '.jpeg', '.avif', '.webp']; +const validImageExtensions = ['.jpeg', '.jpg', '.png', '.webp', '.avif']; +const validImageMIMEs = [ + 'image/jpeg', + 'image/png', + 'image/webp', + 'image/avif', +]; /** * Returns a promise that resolves an ImageBitmaps. @@ -51,18 +58,7 @@ export const loadTextures = { test(url: string): boolean { - let isValidBase64Suffix = false; - - for (let i = 0; i < validImages.length; i++) - { - if (url.startsWith(`data:image/${validImages[i].slice(1)}`)) - { - isValidBase64Suffix = true; - break; - } - } - - return isValidBase64Suffix || checkExtension(url, validImages); + return checkDataUrl(url, validImageMIMEs) || checkExtension(url, validImageExtensions); }, async load(url: string, asset: LoadAsset, loader: Loader): Promise diff --git a/packages/assets/src/loader/parsers/textures/utils/index.ts b/packages/assets/src/loader/parsers/textures/utils/index.ts index 330853232e..3240e67946 100644 --- a/packages/assets/src/loader/parsers/textures/utils/index.ts +++ b/packages/assets/src/loader/parsers/textures/utils/index.ts @@ -1,2 +1 @@ -export * from './checkExtension'; export * from './createTexture'; diff --git a/packages/assets/src/utils/checkDataUrl.ts b/packages/assets/src/utils/checkDataUrl.ts new file mode 100644 index 0000000000..392b496cbe --- /dev/null +++ b/packages/assets/src/utils/checkDataUrl.ts @@ -0,0 +1,14 @@ +export function checkDataUrl(url: string, mimes: string | string[]): boolean +{ + if (Array.isArray(mimes)) + { + for (const mime of mimes) + { + if (url.startsWith(`data:${mime}`)) return true; + } + + return false; + } + + return url.startsWith(`data:${mimes}`); +} diff --git a/packages/assets/src/loader/parsers/textures/utils/checkExtension.ts b/packages/assets/src/utils/checkExtension.ts similarity index 100% rename from packages/assets/src/loader/parsers/textures/utils/checkExtension.ts rename to packages/assets/src/utils/checkExtension.ts diff --git a/packages/assets/src/utils/index.ts b/packages/assets/src/utils/index.ts index e6ab887292..8d2cc28980 100644 --- a/packages/assets/src/utils/index.ts +++ b/packages/assets/src/utils/index.ts @@ -1,3 +1,5 @@ +export * from './checkDataUrl'; +export * from './checkExtension'; export * from './convertToList'; export * from './createStringVariations'; export * from './isSingleItem'; From fb1e57f6c4362d002adf1846d8c0cebdbd7a7b51 Mon Sep 17 00:00:00 2001 From: SuperSodaSea Date: Mon, 28 Nov 2022 03:49:02 +0800 Subject: [PATCH 2/2] Add test for font data URL --- packages/assets/test/assets.tests.ts | 71 ++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 20 deletions(-) diff --git a/packages/assets/test/assets.tests.ts b/packages/assets/test/assets.tests.ts index e19b623cdc..df1743d645 100644 --- a/packages/assets/test/assets.tests.ts +++ b/packages/assets/test/assets.tests.ts @@ -333,31 +333,62 @@ describe('Assets', () => expect(assets.bunny.baseTexture).toBe(null); }); - it('should load PNG base64 assets', async () => + it('should load PNG assets from data URL', async () => { - // Other formats (JPG, JPEG, WEBP, AVIF) can be added similarly. - let bunnyBase64 = ` - data:image/png;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAkGBggGBQkIBwgKCQkKDRYODQwMDRoTFBAWHxwhIB8c - Hh4jJzIqIyUvJR4eKzssLzM1ODg4ISo9QTw2QTI3ODX/2wBDAQkKCg0LDRkODhk1JB4kNTU1NTU1NTU1NTU1NTU1NTU1NTU1NT - U1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTX/wgARCAAlABoDAREAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAABgUHBP/E - ABkBAAMBAQEAAAAAAAAAAAAAAAIDBAUBBv/aAAwDAQACEAMQAAAAfoMjG9G5byxWYwUHfPaNTTmebMAqZ1zJphvFntQwkNP49f - dWrUdeIEs1xcBAWmGH/8QANRAAAQMCBAQDAg8AAAAAAAAAAgEDBAURAAYSEwcUIWEQFSIxUjI0NkJFVFVicXWBoqTCw//aAAgB - AQABPwDiRsHGobM3rBfqoBKb+abaNOlYk/Eb4qz8Cmee0mhjsQpnJIwywC7J6XV5nsl27It/h4y6xSIHEFlnLjLLEN+mPG8DCa - BMxcZ037oh+Gd810nMgQIlIkrKciTleds0aBoRp0LoappLqSexcMsTtp0xjPSmWiu6+KtiLaGSoKKikirbsmMpVFqhV2NLqLjp - gEN5g3WoxuKpkTCp6ARVS+2eEz7lv7bgB9x19AMeyivVFxxGyrScswoE6jxliPvz9o7PHo0K06VkBV0j1HFAybCqFGalSTdU3e - vpW1sUygRJ+fjo07dditRX3LA8bSqYG0KLcFRfYZYHIGWg+g4B93GdZfqS9Vxxk+T9J/M/8H8QuKjNBY5BX4jmz7xpcMZCqPm3 - EMZmtHN+myTund1jw4zhbIwzvqEsH9Hv3Qm/74oFO8oy5TqfubvKRWmNdratIoN7YyRTdji/mj1/E9f8lxHv228P/8QAHxEAAg - IDAAMBAQAAAAAAAAAAAQIAAwQREgUQIRRR/9oACAECAQE/AL2CoWJi5VfJJaY1osJ0dzqZ1qikgwVJYpcHWp426sM4Hydj+zMr - U0kzGwBbV0TPHY6qz7nCzL+0tqUfqRNBfk8cGBfv1YNrqARF0xPr/8QAHhEAAgICAwEBAAAAAAAAAAAAAQIAAxESBBAhMTL/2g - AIAQMBAT8AQEnAgqckSxWA9646HfML6kLOUjEAzQyh23xLeQVbAl9hKjE3Mp/Yli1M32cnGAB0h9hhPnX/2Q== + // Other formats (JPEG, WEBP, AVIF) can be added similarly. + let bunnyDataURL = ` + data:image/png;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAkGBggGBQkIBwgKCQkKDRYODQwMDRoTFBAWHxwhIB8cHh + 4jJzIqIyUvJR4eKzssLzM1ODg4ISo9QTw2QTI3ODX/2wBDAQkKCg0LDRkODhk1JB4kNTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NT + U1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTX/wgARCAAlABoDAREAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAABgUHBP/EABkBAA + MBAQEAAAAAAAAAAAAAAAIDBAUBBv/aAAwDAQACEAMQAAAAfoMjG9G5byxWYwUHfPaNTTmebMAqZ1zJphvFntQwkNP49fdWrUdeIE + s1xcBAWmGH/8QANRAAAQMCBAQDAg8AAAAAAAAAAgEDBAURAAYSEwcUIWEQFSIxUjI0NkJFVFVicXWBoqTCw//aAAgBAQABPwDiRs + HGobM3rBfqoBKb+abaNOlYk/Eb4qz8Cmee0mhjsQpnJIwywC7J6XV5nsl27It/h4y6xSIHEFlnLjLLEN+mPG8DCaBMxcZ037oh+G + d810nMgQIlIkrKciTleds0aBoRp0LoappLqSexcMsTtp0xjPSmWiu6+KtiLaGSoKKikirbsmMpVFqhV2NLqLjpgEN5g3WoxuKpkT + Cp6ARVS+2eEz7lv7bgB9x19AMeyivVFxxGyrScswoE6jxliPvz9o7PHo0K06VkBV0j1HFAybCqFGalSTdU3evpW1sUygRJ+fjo07 + dditRX3LA8bSqYG0KLcFRfYZYHIGWg+g4B93GdZfqS9Vxxk+T9J/M/8H8QuKjNBY5BX4jmz7xpcMZCqPm3EMZmtHN+myTund1jw4 + zhbIwzvqEsH9Hv3Qm/74oFO8oy5TqfubvKRWmNdratIoN7YyRTdji/mj1/E9f8lxHv228P/8QAHxEAAgIDAAMBAQAAAAAAAAAAAQ + IAAwQREgUQIRRR/9oACAECAQE/AL2CoWJi5VfJJaY1osJ0dzqZ1qikgwVJYpcHWp426sM4Hydj+zMrU0kzGwBbV0TPHY6qz7nCzL + +0tqUfqRNBfk8cGBfv1YNrqARF0xPr/8QAHhEAAgICAwEBAAAAAAAAAAAAAQIAAxESBBAhMTL/2gAIAQMBAT8AQEnAgqckSxWA96 + 46HfML6kLOUjEAzQyh23xLeQVbAl9hKjE3Mp/Yli1M32cnGAB0h9hhPnX/2Q== `; - // to prevent eslint max-len warning - bunnyBase64 = bunnyBase64.replace(/\s/g, ''); + // Prevent eslint max-len warning + bunnyDataURL = bunnyDataURL.replace(/\s/g, ''); - Assets.add('bunny', bunnyBase64); - const bunny = await Assets.load('bunny'); + const bunny = await Assets.load(bunnyDataURL); expect(bunny).toBeInstanceOf(Texture); }); + + it('should load TTF assets from data URL', async () => + { + // Smile icon from IcoMoon (https://icomoon.io/#icons-icomoon), CC BY 4.0 + let fontDataURL = ` + data:font/ttf;base64,AAEAAAALAIAAAwAwT1MvMg8SDCkAAAC8AAAAYGNtYXAARu8mAAABHAAAAJhnYXNwAAAAEAAAAbQAAAA + IZ2x5ZoDPYX8AAAG8AAABaGhlYWQib6aFAAADJAAAADZoaGVhB8IDxgAAA1wAAAAkaG10eAoAAAAAAAOAAAAAFGxvY2EAKADIAAA + DlAAAAAxtYXhwAAsAaAAAA6AAAAAgbmFtZZlKCfsAAAPAAAABhnBvc3QAAwAAAAAFSAAAACAAAwMAAZAABQAAApkCzAAAAI8CmQL + MAAAB6wAzAQkAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAABAAAD//wPA/8AAQAPAAEAAAAABAAAAAAAAAAAAAAAgAAA + AAAAGAAAAAwAAADQAAAAEAAAAZAABAAMAAAA0AAEABAAAAGQAAwABAAAANAADAAoAAABkAAQAMAAAAAgACAACAAAAAQAg//3//wA + AAAAAIP/9//8AAf/jAAMAAQAAAAAAAAAAAAwAAAAAADQAAAAAAAAAAwAAAAAAAAABAAAAAQAAACAAAAAgAAAAAwAB9kIAAfZCAAA + ABAABAAH//wAPAAEAAAAAAAAAAAACAAA3OQEAAAAAAQAAAAAAAAAAAAIAADc5AQAAAAABAAAAAAAAAAAAAgAANzkBAAAAAAUAAP/ + ABAADwAAbADcAQwBPAGUAAAUyNz4BNzY1NCcuAScmIyIHDgEHBhUUFx4BFxYTMhceARcWFRQHDgEHBiMiJy4BJyY1NDc+ATc2BzQ + 2MzIWFRQGIyImJTQ2MzIWFRQGIyImExcGBw4BBwYjIicuAScmJzceATMyNgIAal1eiygoKCiLXl1qal1eiygoKCiLXl1qVkxMcSA + hISBxTExWVkxMcSAhISBxTEyqJRsbJSUbGyUBgCUbGyUlGxslQFIVHR1GKSgsLCgpRh0dFVIdZj09ZkAoKIteXWpqXV6LKCgoKIt + eXWpqXV6LKCgDoCEgcUxMVlZMTHEgISEgcUxMVlZMTHEgIeAbJSUbGyUlGxslJRsbJSX+6DIjHB0pCwsLCykdHCMyMTw8AAEAAAA + BAACCgfDXXw889QALBAAAAAAA36gxBAAAAADfqDEEAAD/wAQAA8AAAAAIAAIAAAAAAAAAAQAAA8D/wAAABAAAAAAABAAAAQAAAAA + AAAAAAAAAAAAAAAUEAAAAAAAAAAAAAAACAAAABAAAAAAAAAAACgAUAB4AtAABAAAABQBmAAUAAAAAAAIAAAAAAAAAAAAAAAAAAAA + AAAAADgCuAAEAAAAAAAEABwAAAAEAAAAAAAIABwBgAAEAAAAAAAMABwA2AAEAAAAAAAQABwB1AAEAAAAAAAUACwAVAAEAAAAAAAY + ABwBLAAEAAAAAAAoAGgCKAAMAAQQJAAEADgAHAAMAAQQJAAIADgBnAAMAAQQJAAMADgA9AAMAAQQJAAQADgB8AAMAAQQJAAUAFgA + gAAMAAQQJAAYADgBSAAMAAQQJAAoANACkaWNvbW9vbgBpAGMAbwBtAG8AbwBuVmVyc2lvbiAxLjAAVgBlAHIAcwBpAG8AbgAgADE + ALgAwaWNvbW9vbgBpAGMAbwBtAG8AbwBuaWNvbW9vbgBpAGMAbwBtAG8AbwBuUmVndWxhcgBSAGUAZwB1AGwAYQByaWNvbW9vbgB + pAGMAbwBtAG8AbwBuRm9udCBnZW5lcmF0ZWQgYnkgSWNvTW9vbi4ARgBvAG4AdAAgAGcAZQBuAGUAcgBhAHQAZQBkACAAYgB5ACA + ASQBjAG8ATQBvAG8AbgAuAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + `; + + fontDataURL = fontDataURL.replace(/\s/g, ''); + + const font = await Assets.load(fontDataURL); + + expect(font).toBeInstanceOf(FontFace); + }); });