vercel / satori

Enlightened library to convert HTML and CSS to SVG
https://og-playground.vercel.app
Mozilla Public License 2.0
10.46k stars 228 forks source link

Requiring a variable font causes a type error #162

Open alii opened 1 year ago

alii commented 1 year ago

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

karelnagel commented 1 year ago

Having the same issue, has anyone found a fix?

arimendelow commented 1 year ago

Same issue here, still no fix?

levz0r commented 1 year ago

Same issue, Next.js v13.0.3.

mcnaveen commented 1 year ago

Any update on this? Facing a similar issue.

mxswat commented 1 year ago

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

mrmianbao commented 10 months ago

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

mixeden commented 9 months ago

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

heychazza commented 9 months ago

+1 hitting this with the same font

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

patrick91 commented 8 months ago

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) :)

jahirfiquitiva commented 6 months ago

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

fromaline commented 5 months ago

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

tifandotme commented 3 months ago

Any update?

AlbertMarashi commented 3 months ago

+1 would like support for variable fonts

imsanchez commented 2 months ago

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/next@14.2.1_@babel+core@7.24.0_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/pipe-readable.js:126:15)
    at async DevServer.runEdgeFunction (/Users/isaiah/Desktop/CodeTrackr/codetrackr/node_modules/.pnpm/next@14.2.1_@babel+core@7.24.0_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/next-server.js:1248:13)
    at async NextNodeServer.handleCatchallRenderRequest (/Users/isaiah/Desktop/CodeTrackr/codetrackr/node_modules/.pnpm/next@14.2.1_@babel+core@7.24.0_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/next-server.js:248:37)
    at async DevServer.handleRequestImpl (/Users/isaiah/Desktop/CodeTrackr/codetrackr/node_modules/.pnpm/next@14.2.1_@babel+core@7.24.0_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/base-server.js:811:17)
    at async /Users/isaiah/Desktop/CodeTrackr/codetrackr/node_modules/.pnpm/next@14.2.1_@babel+core@7.24.0_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/dev/next-dev-server.js:339:20
    at async Span.traceAsyncFn (/Users/isaiah/Desktop/CodeTrackr/codetrackr/node_modules/.pnpm/next@14.2.1_@babel+core@7.24.0_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/trace/trace.js:154:20)
    at async DevServer.handleRequest (/Users/isaiah/Desktop/CodeTrackr/codetrackr/node_modules/.pnpm/next@14.2.1_@babel+core@7.24.0_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/dev/next-dev-server.js:336:24)
    at async invokeRender (/Users/isaiah/Desktop/CodeTrackr/codetrackr/node_modules/.pnpm/next@14.2.1_@babel+core@7.24.0_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/lib/router-server.js:174:21)
    at async handleRequest (/Users/isaiah/Desktop/CodeTrackr/codetrackr/node_modules/.pnpm/next@14.2.1_@babel+core@7.24.0_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/lib/router-server.js:353:24)
    at async requestHandlerImpl (/Users/isaiah/Desktop/CodeTrackr/codetrackr/node_modules/.pnpm/next@14.2.1_@babel+core@7.24.0_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/lib/router-server.js:377:13)
    at async Server.requestListener (/Users/isaiah/Desktop/CodeTrackr/codetrackr/node_modules/.pnpm/next@14.2.1_@babel+core@7.24.0_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/server/lib/start-server.js:141:13) 

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

Kas-tle commented 2 months ago

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());
}