From 40c89b11c4d2198cfc14163d4bf3ccff2dedf212 Mon Sep 17 00:00:00 2001 From: "Gustavo \"Guz\" L. de Mello" Date: Tue, 16 Jan 2024 18:55:41 -0300 Subject: [PATCH] =?UTF-8?q?refactor(text-rendering):=20=E2=99=BB=EF=B8=8F?= =?UTF-8?q?=20use=20embeded=20fonts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removed the text to path conversion, it was too complicated to align the generated paths with the dynamic layouts' texts. So embeded font files using data URIs is being used, this is experimental and a "quick-fix", because data URIs could be not compatible and/or work in some environments and browsers. A comment and/or issue with more details about this will be created. --- index.html | 1 - package.json | 1 + packages/banners/package.json | 3 --- packages/banners/src/index.js | 35 ++++++++++++++++++++++++-------- packages/banners/src/text-svg.js | 14 ------------- pnpm-lock.yaml | 15 +++++++------- 6 files changed, 35 insertions(+), 34 deletions(-) delete mode 100644 packages/banners/src/text-svg.js diff --git a/index.html b/index.html index 549341c..6655b80 100644 --- a/index.html +++ b/index.html @@ -5,7 +5,6 @@ - diff --git a/package.json b/package.json index cefbd9f..f008565 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "@commitlint/config-conventional": "^18.4.3", "@commitlint/types": "^18.4.3", "@vercel/node": "^3.0.11", + "cal-sans": "^1.0.1", "eslint": "^8.54.0", "husky": "^8.0.0", "turbo": "^1.10.16", diff --git a/packages/banners/package.json b/packages/banners/package.json index 1938f4d..b9ed74a 100644 --- a/packages/banners/package.json +++ b/packages/banners/package.json @@ -16,8 +16,5 @@ "@types/node": "^20.10.0", "eslint": "^8.54.0", "linkedom": "^0.16.4" - }, - "dependencies": { - "@fredli74/typr": "^0.3.8" } } diff --git a/packages/banners/src/index.js b/packages/banners/src/index.js index 85263c7..6a8a3a7 100644 --- a/packages/banners/src/index.js +++ b/packages/banners/src/index.js @@ -3,7 +3,6 @@ */ import getLocalLayout from './layouts.js'; import { isValidIcon } from './utils.js'; -import fontSvg from './text-svg.js'; /** * @param {Readonly} string - The string to be converted. @@ -106,7 +105,7 @@ function regexHelper(string) { * @returns {[number, number]} */ getTranslate() { - if (!string.includes('translate')) return [ 0, 0 ]; + if (!string.includes('translate')) return [0, 0]; const translateRegex = /translate\((?:[^,]+),(?:[^)]+)\)/gu; @@ -122,6 +121,25 @@ function regexHelper(string) { /* eslint-enable */ } +/** + * @returns {Promise} + */ +async function getSvgCSS() { + const buffer = await fetch( + import.meta.resolve('/packages/banners/static/CalSans-SemiBold.ttf'), + ); + // eslint-disable-next-line unicorn/prefer-code-point, max-len + const base64 = btoa(String.fromCharCode(...new Uint8Array(await buffer.arrayBuffer()))); + + const css = ` + @font-face { + font-family: 'Cal Sans'; + src: url('data:application/x-font-ttf;base64,${base64}') format('truetype'); + } + `; + return css; +} + /** * @param {BannerObject} object - The Banner Object to be generated from. * @returns {Promise} - The SVG of the banner. @@ -134,15 +152,19 @@ async function banner(object) { // @ts-expect-error because fetch is Readonly in Banner object; const lFetch = object.lib?.fetch ?? globalThis.fetch; /** @type {Readonly} */ - const svg = await getLocalLayout('horizontal'); + const layoutSvg = await getLocalLayout('horizontal'); - const dom = stringToHtml(svg, doc); + const dom = stringToHtml(layoutSvg, doc); const helper = domHelper(dom); + await helper.asyncModify('svg > defs', async el => + el?.appendChild(stringToHtml(``, doc)), + ); + await helper.asyncModify('[data-banner-class="icon"]', async (el) => { if (!el || !object.icon || !isValidIcon(object.icon)) return; - const [ iconSet, iconName ] = object.icon.split(':'); + const [iconSet, iconName] = object.icon.split(':'); const res = await lFetch(`https://api.iconify.design/${iconSet}/${iconName}.svg`); @@ -171,7 +193,6 @@ async function banner(object) { el.parentElement?.setAttribute('transform', `${transform ?? ''} translate(${coords.join(',')})`); - const styles = el.getAttribute('style'); const size = regexHelper(styles ?? '').getFontSize(); @@ -199,8 +220,6 @@ async function banner(object) { }, ); - dom.appendChild(stringToHtml(``, doc)); - return htmlToString(dom, doc); } diff --git a/packages/banners/src/text-svg.js b/packages/banners/src/text-svg.js deleted file mode 100644 index 12529e2..0000000 --- a/packages/banners/src/text-svg.js +++ /dev/null @@ -1,14 +0,0 @@ -import * as typr from '@fredli74/typr'; - -const buffer = await fetch( - import.meta.resolve('/packages/banners/static/CalSans-SemiBold.ttf'), -); -const font = new typr.Font(await buffer.arrayBuffer()); -const glyhps = font.stringToGlyphs('Hello world'); - -const path = font.glyphsToPath(glyhps); -const svg = font.pathToSVG(path); - -export default svg; - - diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 54b16e8..5230bf4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -24,6 +24,9 @@ importers: '@vercel/node': specifier: ^3.0.11 version: 3.0.11 + cal-sans: + specifier: ^1.0.1 + version: 1.0.1 eslint: specifier: ^8.54.0 version: 8.54.0 @@ -41,10 +44,6 @@ importers: version: 0.34.6 packages/banners: - dependencies: - '@fredli74/typr': - specifier: ^0.3.8 - version: 0.3.8 devDependencies: '@types/node': specifier: ^20.10.0 @@ -601,10 +600,6 @@ packages: engines: {node: '>=14'} dev: true - /@fredli74/typr@0.3.8: - resolution: {integrity: sha512-0Wr3arrJUOoF5HyE8/nusPsdOQaUEd9t0dq8GTHBgSakuh543VqQklIpuRWF/nEnoxkIJzHpCYYesWTyEqgrFg==} - dev: false - /@humanwhocodes/config-array@0.11.13: resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==} engines: {node: '>=10.10.0'} @@ -1615,6 +1610,10 @@ packages: engines: {node: '>=8'} dev: true + /cal-sans@1.0.1: + resolution: {integrity: sha512-XwN3/7jez8WmFVcNnNqO2K9lh133KiIcURCyGFnSM+ZmNZ8zIcOTNfr3SpenLAkRceYsq+fQNX/PL4C1rIkEPQ==} + dev: true + /call-bind@1.0.5: resolution: {integrity: sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==} dependencies: