From 7891fce774bf02cc738453ffad59db3c8846b95d Mon Sep 17 00:00:00 2001 From: Mari Date: Sat, 4 May 2024 01:28:05 -0700 Subject: [PATCH] add font support --- .gitignore | 5 +++-- Dockerfile | 2 +- src/commands/base.ts | 3 ++- src/commands/party.ts | 4 ++-- src/index.ts | 5 ++++- src/renderStatus.ts | 9 +++++++-- 6 files changed, 19 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 219f608..a7bd793 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ logs/ !.vscode/extensions.json .env dist/ -data/characters -data/images +data/characters/ +data/images/ data/party.yaml +data/fonts/ diff --git a/Dockerfile b/Dockerfile index ff46bad..e80f8cb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ FROM node:latest AS build -RUN apt-get update && apt-get install -y --no-install-recommends dumb-init +RUN apt-get update && apt-get install -y --no-install-recommends dumb-init fira- WORKDIR /usr/src/app COPY package*.json .prettierrc .eslintrc.cjs tsconfig.json /usr/src/app/ COPY src /usr/src/app/src/ diff --git a/src/commands/base.ts b/src/commands/base.ts index ee4c86f..07b96b7 100644 --- a/src/commands/base.ts +++ b/src/commands/base.ts @@ -267,7 +267,8 @@ export abstract class AbstractCharacterStatusCommand extends SlashCommand { .slice(0, 10) .map((s) => characterDataDelta(s, this.dataDir)) ); - const images = await Promise.all(deltas.map(async (s) => renderStatus(await svg, s))); + const fontDir = join(this.dataDir, 'fonts') + const images = await Promise.all(deltas.map(async (s) => renderStatus(await svg, s, fontDir))); const sharps = images.map((b) => Sharp(b)); const metadatas = await Promise.all(sharps.map((s) => s.metadata())); let resultImage: Buffer | null; diff --git a/src/commands/party.ts b/src/commands/party.ts index 42a00db..81310a9 100644 --- a/src/commands/party.ts +++ b/src/commands/party.ts @@ -46,7 +46,7 @@ export class PartyCommand extends AbstractCharacterStatusCommand { > { const replace: boolean | undefined = ctx.options.replace; const oldPartyMemberNames = party.activeParty; - const newPartyMemberData = characters.get('party'); + const newPartyMemberData = characters.get('characters'); if (!newPartyMemberData || newPartyMemberData.length === 0) { return [ `The current active party is:\n **${oldPartyMemberNames.join('**\n **')}**`, @@ -78,7 +78,7 @@ export class PartyCommand extends AbstractCharacterStatusCommand { ]; if (replace || deltas.length === 0 || (replace === false && deltas.length > newPartyMemberNames.length)) { return [ - `The current active party is:\n **${newPartyMemberData.map((c) => c.name).join('**\n **')}**`, + `The active party is now:\n **${newPartyMemberData.map((c) => c.name).join('**\n **')}**`, newPartyMemberData.flatMap((c) => (c.success ? [c] : [])) ]; } else { diff --git a/src/index.ts b/src/index.ts index ba93d06..ca43127 100644 --- a/src/index.ts +++ b/src/index.ts @@ -37,7 +37,10 @@ const server = fastify({ logger: true }); -const options = { dataDir: process.env.DATA_DIR ?? '../data' }; +const options = { + dataDir: process.env.DATA_DIR ?? '../data', + fontDir: process.env.FONT_DIR ?? '../fonts' +}; creator .withServer(new FastifyServer(server)) diff --git a/src/renderStatus.ts b/src/renderStatus.ts index 1aa03f8..b8243b7 100644 --- a/src/renderStatus.ts +++ b/src/renderStatus.ts @@ -169,7 +169,7 @@ const mappings: [filter: (status: GameStatus) => boolean, selector: string, hit: [dead(), '#characterFaceImage', removeElement] ]; -export async function renderStatus(svgTemplate: string, status: GameStatusWithPortrait): Promise { +export async function renderStatus(svgTemplate: string, status: GameStatusWithPortrait, fontDir: string): Promise { const dom = new JSDOM(svgTemplate, { contentType: 'image/svg+xml', pretendToBeVisual: false, @@ -183,7 +183,12 @@ export async function renderStatus(svgTemplate: string, status: GameStatusWithPo } } } - const resvg = new Resvg(dom.window.document.documentElement.outerHTML, {}); + const resvg = new Resvg(dom.window.document.documentElement.outerHTML, { + font: { + fontDirs: [fontDir], + loadSystemFonts: false, + } + }); resvg.resolveImage('https://invalid.invalid/face.png', status.portrait); return resvg.render().asPng(); }