Automattic / Automattic/node-canvas

Fonts not working

Open
#2,391 1 comment 0 reactions 0 assignees View on GitHub
Text & Fonts
Dominant language
JavaScript
Stars
10.7k
Forks
1.2k
Avg merge
4d 8h
Merged PRs (30d)
1

Description

Hello there,

I've been trying to make custom fonts work in a lambda/.docker container for a week now but there seem to be no way to make it happen.

Here is my javascript code:

`
import { createCanvas, loadImage, registerFont } from 'canvas';
import createDOMPurify from 'dompurify';
import { JSDOM } from 'jsdom';

async function generateCanvasImage(params) {

const config = params.templateName === 'book1' ? book1Config : book2Config;
const imagesConfig = await fetchTemplate(
`https://xxxx.s3.eu-west-1.amazonaws.com/${params.templateName}.json`
);

**registerFont('assets/fonts/bronic.ttf', { family: 'Bronic', weight: 'normal', style: 'regular' });
registerFont('assets/fonts/Neo-Regular.ttf', {family: 'Neo', weight: 'normal', style: 'regular'});**

const scale = 3; // Increase for higher DPI; typical high-DPI screens use a scale of 2 or 3
const canvas = createCanvas(
config.pageSize.width * scale,
config.pageSize.height * scale
);
const ctx = canvas.getContext('2d');
ctx.scale(scale, scale);

const pageIndex = params.pageIndex;
const page = config.pages[pageIndex];

const pageCharacters = imagesConfig[pageIndex].characters;

//Draw background
const bg = await loadImage(page.background);
ctx.drawImage(bg, 0, 0, config.pageSize.width, config.pageSize.height);

// Draw characters
for (let i = 0; i < page.characters.length; i++) {
const character = page.characters[i];
const { size, position } = getCharacterSizeAndPosition(character, params);
const id = slugify(
character.id === 'pet'
? `page-${pageIndex}-${params.petBreed}-${params.petColor}`
: `page-${pageIndex}-${params.companionAge}-${params.companionGender}-${params.companionSkin}-${params.companionHair}`
);
logger.info(id, i);

if (
typeof pageCharacters.filter((c) => c.id === character.id)[0] !==
'undefined'
) {
const characterImageObj = pageCharacters
.filter((c) => c.id === character.id)[0]
.prompts.filter((p) => p.id.toLowerCase() === id.toLowerCase())[0];
if (
typeof characterImageObj !== 'undefined' &&
typeof characterImageObj.imgLocS3 !== 'undefined'
) {
const characterImage = await fetchImage(
characterImageObj.imgLocS3 + '?t=' + new Date().valueOf()
);
const img = await loadImage(
`data:image/jpeg;base64,${Buffer.from(characterImage).toString(
'base64'
)}`
);
ctx.drawImage(img, position.x, position.y, size, size);
// doc.image(Buffer.from(characterImage), position.x, position.y, { fit: [size, size], align: 'center', valign: 'center' });
} else {
logger.error(`Found undefined for ${id}`);
}
} else {
logger.error(`Found undefined character for ${id}`);
}
}

for (let o = 0; o < page.overlays.length; o++) {
let overlay = page.overlays[o];
console.log(overlay);
const img = await loadImage(overlay.url);
ctx.drawImage(
img,
overlay.position.x,
overlay.position.y,
config.pageSize.width,
config.pageSize.height
);
}

for (let t = 0; t < page.text_contents.length; t++) {
let text_content = page.text_contents[t];

ctx.fillStyle = '#D9FFF2';
console.log(`'${text_content.fontSize}px "${text_content.font}"'`);
ctx.font = `${text_content.fontSize}px "${text_content.font}"`;
ctx.textAlign = text_content.align;

ctx.fillText(
replacePlaceholders(text_content.text, params),
text_content.position.x,
text_content.position.y
);
}

return canvas.toBuffer();
}`

These are my system details

"node version" 20
"node-canvas":"2.11.2",
"cairoVersion":"1.17.6",
"jpegVersion":"6b",
"gifVersion":"5.2.1",
"freetypeVersion":"2.13.0",
"pangoVersion":"1.48.10"

The whole application runs inside a lambda / docker container, this is the dockerfile

`FROM public.ecr.aws/lambda/nodejs:20

RUN dnf install -y gcc-c++ \
cairo \
cairo-devel \
pango \
pango-devel \
libjpeg \
libjpeg-devel \
giflib \
giflib-devel \
libpng \
libpng-devel \
pixman \
pixman-devel \
python3 \
make

ENV PKG_CONFIG_PATH=/usr/lib64/pkgconfig:/usr/lib/pkgconfig:/usr/share/pkgconfig

RUN rm -rf /usr/share/fonts/*
RUN rm -rf /usr/local/share/fonts/*
RUN rm -rf ${HOME}/.local/share/fonts/*
RUN mkdir -p /usr/local/share/fonts/bronic
COPY assets/fonts/bronic.ttf /usr/local/share/fonts/bronic
RUN chmod 644 /usr/local/share/fonts/bronic/*
RUN mkdir -p /usr/local/share/fonts/allianz-neo
COPY assets/fonts/Neo-Regular.ttf /usr/local/share/fonts/neo
RUN chmod 644 /usr/local/share/fonts/allianz-neo/*

ENV FONTCONFIG_PATH /usr/local/share/fonts/
RUN fc-cache --really-force --verbose
COPY assets ${LAMBDA_TASK_ROOT}/assets
COPY templates ${LAMBDA_TASK_ROOT}/templates
RUN ls -la ${LAMBDA_TASK_ROOT}/*
COPY package*.json handler.js pageGenerator.js sizingLogic.js ${LAMBDA_TASK_ROOT}

WORKDIR ${LAMBDA_TASK_ROOT}

RUN chmod 777 ${LAMBDA_TASK_ROOT}/assets/fonts

RUN npm i node-gyp -g

RUN npm install

CMD ["handler.generatePages"]`

I've tried both the approaches installing the font directly onto docker and then just referencing it into my code, or using registerFont in the code and pointing to the correct ttf file.

Nothing seems to be working and there seems to be no utility to debug this, to verify if the fonts have been loaded correctly.

I can definitely see that the font file is found but then it just doesn't render.

Does anybody have any idea of how to solve this issue?

Thanks,
Salvo

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.