satori icon indicating copy to clipboard operation
satori copied to clipboard

Requiring a variable font causes a type error

Open alii opened this issue 2 years ago • 16 comments

Bug report

When satori's .addFonts method is called, it calls opentype which (in a Next.js app) throws the following error

error - TypeError: Cannot read properties of undefined (reading '259')
    at parseFvarAxis (webpack-internal:///(middleware)/./node_modules/@shuding/opentype.js/dist/opentype.module.js:10290:22)
    at Object.parseFvarTable [as parse] (webpack-internal:///(middleware)/./node_modules/@shuding/opentype.js/dist/opentype.module.js:10326:13)
    at Object.parseBuffer [as parse] (webpack-internal:///(middleware)/./node_modules/@shuding/opentype.js/dist/opentype.module.js:11618:33)
    at vt.addFonts (webpack-internal:///(middleware)/./node_modules/satori/dist/esm/index.wasm.js:18:20138)
    at new vt (webpack-internal:///(middleware)/./node_modules/satori/dist/esm/index.wasm.js:18:19783)
    at mu (webpack-internal:///(middleware)/./node_modules/satori/dist/esm/index.wasm.js:18:49554)
    at Object.start (webpack-internal:///(middleware)/./node_modules/@vercel/og/dist/index.js:10:2973)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

Description / Observed Behavior

Could not load a variable font

Expected Behavior

The font loads

Reproduction

const font = fetch(
	new URL(
		'path/to/GeneralSans-Variable.ttf',
		import.meta.url,
	),
).then(async res => res.arrayBuffer());

// Then load with:
const options = {
	fonts: [
		{
			name: "General Sans",
			data: await font,
			style: "normal",
		},
	],
};

https://www.fontshare.com/fonts/general-sans

Additional Context

ali in ~/code/website on master λ yarn why satori
└─ @vercel/og@npm:0.0.15
   └─ satori@npm:0.0.38 (via npm:0.0.38)

Originally was going to report this issue in shuding/opentype.js, but the repo has issues disabled, so was not sure if it was more appropriate to go in https://github.com/opentypejs/opentype.js or here

alii avatar Oct 11 '22 01:10 alii

Having the same issue, has anyone found a fix?

karelnagel avatar Nov 12 '22 09:11 karelnagel

Same issue here, still no fix?

arimendelow avatar Jan 10 '23 08:01 arimendelow

Same issue, Next.js v13.0.3.

levz0r avatar Mar 08 '23 11:03 levz0r

Any update on this? Facing a similar issue.

mcnaveen avatar May 05 '23 14:05 mcnaveen

Same issue here using Montserrat-VariableFont_wght.ttf from https://fonts.google.com/specimen/Montserrat

mxswat avatar May 16 '23 14:05 mxswat

did you try removing style? I'm using variable fonts in the latest version without issue, but just { name, data }.

mrmianbao avatar Sep 10 '23 08:09 mrmianbao

Btw if you use variable .woff, the message disappears, but the font is not getting applied

mixeden avatar Sep 25 '23 19:09 mixeden

+1 hitting this with the same font

Same issue here using Montserrat-VariableFont_wght.ttf from https://fonts.google.com/specimen/Montserrat

heychazza avatar Oct 07 '23 14:10 heychazza

The workaround is to use a non variable version of the same font, which was fine for my use case (I only needed one weight) :)

patrick91 avatar Oct 22 '23 21:10 patrick91

I'm facing this issue when using a .woff2 font 😬

jahirfiquitiva avatar Dec 15 '23 23:12 jahirfiquitiva

I'm facing the same issue, any updates on this?

fromaline avatar Jan 25 '24 10:01 fromaline

Any update?

tifandotme avatar Apr 07 '24 18:04 tifandotme

+1 would like support for variable fonts

AlbertMarashi avatar Apr 08 '24 07:04 AlbertMarashi

I lost so much time trying to debug this.

The error via ImageResponse from next/og (@vercel/og):

⨯ Error: failed to pipe response
    at pipeToNodeResponse (/Users/isaiah/Desktop/CodeTrackr/codetrackr/node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected]/node_modules/next/dist/server/pipe-readable.js:126:15)
    at async DevServer.runEdgeFunction (/Users/isaiah/Desktop/CodeTrackr/codetrackr/node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected]/node_modules/next/dist/server/next-server.js:1248:13)
    at async NextNodeServer.handleCatchallRenderRequest (/Users/isaiah/Desktop/CodeTrackr/codetrackr/node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected]/node_modules/next/dist/server/next-server.js:248:37)
    at async DevServer.handleRequestImpl (/Users/isaiah/Desktop/CodeTrackr/codetrackr/node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected]/node_modules/next/dist/server/base-server.js:811:17)
    at async /Users/isaiah/Desktop/CodeTrackr/codetrackr/node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected]/node_modules/next/dist/server/dev/next-dev-server.js:339:20
    at async Span.traceAsyncFn (/Users/isaiah/Desktop/CodeTrackr/codetrackr/node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected]/node_modules/next/dist/trace/trace.js:154:20)
    at async DevServer.handleRequest (/Users/isaiah/Desktop/CodeTrackr/codetrackr/node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected]/node_modules/next/dist/server/dev/next-dev-server.js:336:24)
    at async invokeRender (/Users/isaiah/Desktop/CodeTrackr/codetrackr/node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected]/node_modules/next/dist/server/lib/router-server.js:174:21)
    at async handleRequest (/Users/isaiah/Desktop/CodeTrackr/codetrackr/node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected]/node_modules/next/dist/server/lib/router-server.js:353:24)
    at async requestHandlerImpl (/Users/isaiah/Desktop/CodeTrackr/codetrackr/node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected]/node_modules/next/dist/server/lib/router-server.js:377:13)
    at async Server.requestListener (/Users/isaiah/Desktop/CodeTrackr/codetrackr/node_modules/.pnpm/[email protected]_@[email protected][email protected][email protected]/node_modules/next/dist/server/lib/start-server.js:141:13) 

Switching to a non-variable font works, thank you.

imsanchez avatar Apr 16 '24 02:04 imsanchez

If working with google fonts to get non-variable weight ones I found that you have to spoof the user agent to something old get it to return non-variable weight ttf files:

async function getTtfFont(family: string, axes: string[], value: number[]): Promise<ArrayBuffer> {
    const familyParam = axes.join(',') + '@' + value.join(',');

    // Get css style sheet with user agent Mozilla/5.0 Firefox/1.0 to ensure non-variable TTF is returned
    const cssCall = await fetch(`https://fonts.googleapis.com/css2?family=${family}:${familyParam}&display=swap`, {
        headers: {
            'User-Agent': 'Mozilla/5.0 Firefox/1.0',
        },
    });

    const css = await cssCall.text();
    const ttfUrl = css.match(/url\(([^)]+)\)/)?.[1];

    return await fetch(ttfUrl).then(res => res.arrayBuffer());
}

Kas-tle avatar Apr 16 '24 03:04 Kas-tle