diegomura / react-pdf

📄 Create PDF files using React
https://react-pdf.org
MIT License
14.83k stars 1.18k forks source link

Loading and registering fonts is broken #680

Closed simondobson closed 3 years ago

simondobson commented 5 years ago

Describe the bug When attempting to load the source of a font, locally or from an external URL, an error comes back as Error: Unknown font format like in your example here

https://react-pdf.org/repl?example=font-register

To Reproduce Steps to reproduce the behavior including code snippet (if applies):

  1. Register a font
  2. See console errors & failure to load the doc

Expected behavior Fonts are loaded successfully and applied to the document.

Screenshots

Screenshot 2019-08-05 at 15 37 23
carpben commented 5 years ago

I opened a similar issue. Now I see this was created earlier, so I'll copy everything to here.

Describe the bug A clear and concise description of what the bug is. Can't register fonts

To Reproduce Steps to reproduce the behavior including code snippet (if applies):

  1. Create a simple PDF Viewer with just text
import { Document, Font, Image, Page, PDFViewer , StyleSheet, Text, View } from "@react-pdf/renderer"

class BensPlayGround extends Component {
    public render() {
        return (
            <Box
                stl={css`
                    iframe {
                        width: ${width}px;
                        height: ${width * 1.5}px;
                    }
                `}
            >
                < PDFViewer >
                    <MyDocument />
                </PDFViewer >

            </Box>
        )
    }
}

const styles={...}

const MyDocument = () => (
    <Document>
      <Page size="A4" style={styles.page}>
          <View style={styles.pageW}>
                    <Text
                        style={styles.title}
                    >
                        Certificate of Appreciation
                    </Text>
        </View>
      </Page>
    </Document>
 )

Everything works well.

  1. Try to change the font to "monteserrat 700 or Roboto 700" by either using a url, or using a ttf file in the same directory
    
    Font.register({ family: "Roboto", fonts: [
    { src: "/roboto.bold.ttf", fontWeight: 700 },
    ]})

const styles = StyleSheet.create({ title: { ...... fontWeight: 700, fontFamily: "Roboto", } })

const MyDocument = () => (

Certificate of Appreciation

)



This is how it shows up in the browser. 
![image](https://user-images.githubusercontent.com/13496178/62834338-435d3480-bc53-11e9-86b3-e26e69e796d6.png)

**Desktop (please complete the following information):**
 - OS: [e.g. MacOS, Windows] Windows
 - Browser [e.g. chrome, safari] Chrome
 - React-pdf version [e.g. v1.1.0]  1.6+
akenzua commented 5 years ago

having the same issue

igolden commented 5 years ago

I had this issue as well. I was able to resolve it by importing the font file as a variable then using that as the src value.

import font from "./font.ttf"

Font.register({
  family: "FamilyName",
  format: "truetype",
  src: font 
});
danalexilewis commented 5 years ago

I am having the same issues with trying to bring Lato into a project. Have tried @igolden solution to no avail (though thanks for posting it!)

mdodge-ecgrow commented 4 years ago

I had this issue as well. I was able to resolve it by importing the font file as a variable then using that as the src value.

import font from "./font.ttf"

Font.register({
  family: "FamilyName",
  format: "truetype",
  src: font 
});

Thank you!!! Why isn't this in the docs?

diegomura commented 4 years ago

I'll add it! Thanks

Tuomask commented 4 years ago

Im having the same problem when registering fonts. Tried to import them but I'll get this error: image

Tried with ttf fonts in the same directory with no luck. image

Even when the font is there. What am I doing wrong?

Tuomask commented 4 years ago

Figured it out with a huge help from my colleague. With typescript you need declarations.d.ts file in your src folder.

declare module "*.ttf" {
    const content: any;
    export default content;
}

declare module "*.otf" {
    const content: any;
    export default content;
}
tomgallagher commented 4 years ago

Can anyone tell me which font formats are acceptable? I know TrueType, any others?

ahlag commented 4 years ago

Has anyone fixed this? We have tried doing it with codes below. Still getting the same error.

import headingfont from "./BalooSemiBold.ttf";

Font.register({
  family: "Baloo",
  format: "truetype",
  src: headingfont,
});

<View style={(styles.section, { fontFamily: 'Baloo' })}>
simple-asset-manager commented 4 years ago

I also have not been able to register fonts trying any of these methods - I've been trying it a lot of different ways, but always get that the font is null, or in an unknown format.

As an aside, are there any fonts that are included that I could use since this issue doesn't seem to be going away?

` Method 1 import roboto from '../static/fonts/Roboto/Roboto-Regular.ttf'; Font.register({ family: "Roboto", fonts: [ { src: roboto }, ]})

Method 2 Font.register({ family: 'Roboto', src: 'https://github.com/google/fonts/raw/master/apache/roboto/static/Roboto-Regular.ttf' });

Method 3 Font.register({ family: 'Roboto', fonts: [ {src: '../static/fonts/Roboto/Roboto-Regular.ttf''}] }); `

heyalexchoi commented 4 years ago

I am also unable to register fonts. code:

Font.register({ family: 'SourceSansPro', fonts: [
 { src: 'https://fonts.gstatic.com/s/sourcesanspro/v14/6xK3dSBYKcSV-LCoeQqfX1RYOo3qNa7lujVj9_mf.woff2' }, // font-style: normal, font-weight: normal
 { src: 'https://fonts.gstatic.com/s/sourcesanspro/v14/6xKydSBYKcSV-LCoeQqfX1RYOo3i54rwmhdu3cOWxy40.woff2', fontWeight: 600 },
]});

code, variation 2:

Font.register({ family: 'SourceSansPro', fonts: [
 { src: 'https://fonts.googleapis.com/css2?family=Source+Sans+Pro&display=swap' }, // font-style: normal, font-weight: normal
 { src: 'https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@600&display=swap', fontWeight: 600 },
]});

console:

Error: Unknown font format
    at Object../node_modules/@react-pdf/fontkit/dist/fontkit.browser.es.js.fontkit$1.create (fontkit.browser.es.js:68)
    at FontSource._callee2$ (react-pdf.browser.es.js:2892)
    at tryCatch (runtime.js:63)
    at Generator.invoke [as _invoke] (runtime.js:293)
    at Generator.next (runtime.js:118)
    at asyncGeneratorStep (asyncToGenerator.js:3)
    at _next (asyncToGenerator.js:25)

UPDATE: I was able to get fonts to work using a .ttf url. If you're using a google font you can do this by curling the google font url

➜  resume-builder-site git:(master) ✗ curl https://fonts.googleapis.com/css2\?family\=Source+Sans+Pro:wght@600\&display\=swap
@font-face {
  font-family: 'Source Sans Pro';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: local('Source Sans Pro SemiBold'), local('SourceSansPro-SemiBold'), url(https://fonts.gstatic.com/s/sourcesanspro/v14/6xKydSBYKcSV-LCoeQqfX1RYOo3i54rAkA.ttf) format('truetype');
}

Taking the .ttf url that comes back, and put that into the src

Font.register({ family: 'SourceSansPro', fonts: [
 { src: 'https://fonts.gstatic.com/s/sourcesanspro/v14/6xK3dSBYKcSV-LCoeQqfX1RYOo3aPw.ttf' }, // font-style: normal, font-weight: normal
 { src: 'https://fonts.gstatic.com/s/sourcesanspro/v14/6xKydSBYKcSV-LCoeQqfX1RYOo3i54rAkA.ttf', fontWeight: 600 },
]});
igorvc30 commented 4 years ago

I had this problem using NextJS. I solved this problem using require and installing next-fonts. So a downloaded the .tff and put it at the same folder. This was a really tricky problem, I tried using static folder and url. It was working at dev mode and local builds, but once I sent to production using AWS Amplify, my PDF Viewer was broken.

const font = require('./mplus.ttf')
Font.register({
  family: 'mplus-1',
  src: font
})
iakashpatel commented 4 years ago

I am not able to load font in playground too as well as in app. any idea why it is not loading fonts Arimo ??

here is my code snippet:

const Quixote = () => (
  <Document>
    <Page style={styles.body}>
      <Text style={styles.title} fixed>
        Created with react-pdf
      </Text>
    </Page>
  </Document>
);

Font.register({
  family: 'Arimo',
   format: 'truetype',
  src: 'https://github.com/iakashpatel/fonts/raw/master/Arimo/Arimo-Regular.ttf'
});

const styles = StyleSheet.create({
  body: {
    paddingTop: 35,
    paddingBottom: 65,
    paddingHorizontal: 35,
  },
  title: {
    fontSize: 24,
    textAlign: 'center',
    fontFamily: 'Arimo',
    fontStyle: "normal",
    fontWeight: 400
  }
});

ReactPDF.render(<Quixote />);
michaelahercogova commented 3 years ago

Has anyone got lucky with registering multiple custom fonts?

I have been trying something like this...

import Font1 from './font1.ttf';
import Font1Bold from './font1bold.ttf';
import Font2 from './font2.ttf';
import Font2Bold from './font2bold.ttf';

Font.register({
  family: 'Font1',
  fonts: [
    {
      src: Font1,
    },
    {
      src: Font1Bold,
      fontWeight: 800,
    },
  ],
});

Font.register({
  family: 'Font2',
  fonts: [
    {
      src: Font2,
    },
    {
      src: Font2Bold,
      fontWeight: 800,
    },
  ],
});

It's always the font that is first being used in the document that is loaded correctly and the other one turns out muggled up. I don't think it's the font issue as I tried swapping them around in the document and the result is the same. See the images attached...

Screenshot 2021-01-20 at 09 15 24 Screenshot 2021-01-20 at 09 15 43
michaelahercogova commented 3 years ago

In case anyone encounters similar issue or any issue with font loading in fact, this may be helpful. It turned out the fonts I was trying to register had wrong metadata and pdf-react couldn't recognise them as two different fonts. I have tried converting them from woff to ttf and back as some people were suggesting which didn't help. At the end I ended up getting http://birdfont.org/ and editing the metadata and exporting the fonts in ttf format. Once I have done that registering of different weights and different fonts couldn't be smoother.

kybishop commented 3 years ago

My PDF is rendering fine but for the life of me I can't figure out how to get the fonts to work. Despite registering my fonts with no errors, my PDF renders every time with sans-serif (instead of Roboto).

import Roboto400Font from 'assets/fonts/Roboto/KFOmCnqEu92Fr1Mu4mxP.ttf';
import Roboto500Font from 'assets/fonts/Roboto/KFOlCnqEu92Fr1MmEU9fBBc9.ttf';

export default class SomePage extends React.Component {
  componentDidMount() {
    Font.register({
      family: 'Roboto', fonts: [
        {
          fontWeight: 400,
          src: Roboto400Font,
        },
        {
          fontWeight: 500,
          src: Roboto500Font
        }
      ]
    });

    this.renderHandout();
  }

  renderHandout(canvasUrl) {
    ReactDOM.render(
      <ThePdf />,
      document.getElementById('pdf-goes-here')
    );
  }

  render() {
    return <div id='pdf-goes-here' />;
  }
}

function ThePdf() {
  return <PDFViewer style={{ height: '100vh', width: '100vw' }}>
    <Document>
      <Page size="A4">
        <Text style={{ fontFamily: 'Roboto', fontWeight: 400 }}>
          I should be Roboto, but for some reason I'm sans-serif
        </Text>
      </Page>
    </Document>
  </PDFViewer>
}

I have tried:

Fonts should work front-end side, right? Just want to make sure I didn't miss anything specifying that it's a node-env only feature or something.

wenscl commented 3 years ago

I tried all these solutions to load Roboto but it didn't work. I keep getting the "Unknown font format" error.

import RobotoRegular from "./Roboto-Regular.ttf";

Font.register({
  family: "Roboto",
  src: RobotoRegular,
  // src: "https://fonts.googleapis.com/css2?family=Roboto&display=swap",
});

export const styles = StyleSheet.create({
  h2: {
    fontFamily: "Roboto",
    fontSize: 22,
  },
})
jeno5980515 commented 3 years ago

In case anyone encounters similar issue or any issue with font loading in fact, this may be helpful. It turned out the fonts I was trying to register had wrong metadata and pdf-react couldn't recognise them as two different fonts. I have tried converting them from woff to ttf and back as some people were suggesting which didn't help. At the end I ended up getting http://birdfont.org/ and editing the metadata and exporting the fonts in ttf format. Once I have done that registering of different weights and different fonts couldn't be smoother.

It works!

wenscl commented 3 years ago

How do I know what metadata is wrong? I tried deleting everything that is not required but it didn't work. The font was downloaded from google fonts so it should be fine.

rpilev commented 3 years ago

I am having the same problem. I cannot get fonts to register with any of these methods and end up getting: × Unhandled Rejection (Error): Unknown font format

import RobotoBold from "./fonts/Roboto-Bold.ttf"
import RobotoRegular from "./fonts/Roboto-Regular.ttf"

Font.register({
  family: "Roboto-Regular",
  src: RobotoRegular,
})
Font.register({
  family: "Roboto-Bold",
  src: RobotoBold,
})`

The fonts are from here: https://fonts.google.com/specimen/Roboto?preview.text_type=custom

shin0602 commented 3 years ago

I had the same problem. But I solved it by converting ttf to woff.

// import font from '/font/mplus-2m-regular.ttf' (Error): Unknown font format
import font from '/font/mplus-2m-regular.woff'
Font.register({
  family: 'Mplus',
  src: font,
})

I did the conversion on this site. https://convertio.co/

diegomura commented 3 years ago

I feel this issue has now already covered many different things, most of them are fixed already. Sorry if I missed something. Please create a separate issue if I did. I'm closing it right now

JoshBowdenConcepts commented 3 years ago

I have converted from .tff to .woff and I am getting an Unknown font format error. Font.register({ family: 'Lato', src: '/lato-v14-latin-ext-regular.woff' });

DewangS commented 3 years ago

it may sound a bit irrelevant but while the above solution works i.e. import font and use register, please be extra careful when you build your project. I added homepage: '.' in my package.json before the build and it broke this font registration in prod. I had to remove the homepaage: '.' from my package.json and rebuild the project.

tomherbin commented 2 years ago

@DewangS Thanks same trouble here !

fxbayuanggara commented 2 years ago

I had this issue as well. I was able to resolve it by importing the font file as a variable then using that as the src value.

import font from "./font.ttf"

Font.register({
  family: "FamilyName",
  format: "truetype",
  src: font 
});

You saved my night bro!

seleckis commented 2 years ago

If anyone still has an issue with font loading in Next.js, here is my workaround:

  1. Download ttf font and place somewhere in src folder (e.g. theme/fonts/pt-sans-regular.tff).
  2. If you use typescript add file fonts.d.ts in your typings folder with this content:
    declare module "*.ttf";
  3. Modify next.config.js like this:
    module.exports = {
    // ...
    webpack: (config) => {
    config.module.rules.push({
      test: /\.ttf$/i,
      type: "asset/resource",
    });
    return config;
    },
    // ...
    };
  4. Register font like this:
    
    import PTSansRegular from "theme/fonts/pt-sans-regular.ttf"; // use path according to file location and your project configuration.

Font.register({ family: "PT Sans", fontStyle: "normal", fontWeight: "normal", fonts: [ { src: PTSansRegular, }, ], });


Works fine for me with `PDFDownloadLink`, but not working properly with `PDFViewer`. With `PDFViewer` works only after navigating to a page where the viewer is placed, but after refresh font is not applied.
HoHoangThai1807 commented 2 years ago

I am also unable to register fonts. code:

Font.register({ family: 'SourceSansPro', fonts: [
 { src: 'https://fonts.gstatic.com/s/sourcesanspro/v14/6xK3dSBYKcSV-LCoeQqfX1RYOo3qNa7lujVj9_mf.woff2' }, // font-style: normal, font-weight: normal
 { src: 'https://fonts.gstatic.com/s/sourcesanspro/v14/6xKydSBYKcSV-LCoeQqfX1RYOo3i54rwmhdu3cOWxy40.woff2', fontWeight: 600 },
]});

code, variation 2:

Font.register({ family: 'SourceSansPro', fonts: [
 { src: 'https://fonts.googleapis.com/css2?family=Source+Sans+Pro&display=swap' }, // font-style: normal, font-weight: normal
 { src: 'https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@600&display=swap', fontWeight: 600 },
]});

console:

Error: Unknown font format
    at Object../node_modules/@react-pdf/fontkit/dist/fontkit.browser.es.js.fontkit$1.create (fontkit.browser.es.js:68)
    at FontSource._callee2$ (react-pdf.browser.es.js:2892)
    at tryCatch (runtime.js:63)
    at Generator.invoke [as _invoke] (runtime.js:293)
    at Generator.next (runtime.js:118)
    at asyncGeneratorStep (asyncToGenerator.js:3)
    at _next (asyncToGenerator.js:25)

UPDATE: I was able to get fonts to work using a .ttf url. If you're using a google font you can do this by curling the google font url

➜  resume-builder-site git:(master) ✗ curl https://fonts.googleapis.com/css2\?family\=Source+Sans+Pro:wght@600\&display\=swap
@font-face {
  font-family: 'Source Sans Pro';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: local('Source Sans Pro SemiBold'), local('SourceSansPro-SemiBold'), url(https://fonts.gstatic.com/s/sourcesanspro/v14/6xKydSBYKcSV-LCoeQqfX1RYOo3i54rAkA.ttf) format('truetype');
}

Taking the .ttf url that comes back, and put that into the src

Font.register({ family: 'SourceSansPro', fonts: [
 { src: 'https://fonts.gstatic.com/s/sourcesanspro/v14/6xK3dSBYKcSV-LCoeQqfX1RYOo3aPw.ttf' }, // font-style: normal, font-weight: normal
 { src: 'https://fonts.gstatic.com/s/sourcesanspro/v14/6xKydSBYKcSV-LCoeQqfX1RYOo3i54rAkA.ttf', fontWeight: 600 },
]});

Work fine for me!! Tysm 😄

matiasfacio commented 2 years ago

If anyone still has an issue with font loading in Next.js, here is my workaround:

@seleckis solution worked for me perfectly fine!

yessssssss Thank you!

dlgoodchild commented 1 year ago

This appears to be a create-react-app (CRA) issue. I have the same project created with CRA and with Vite. The Vite works without issue, without any additional configuration and without needing to import the font first as demonstrated above. However. it appears the CRA version seems to require quite a bit of tricky configuration to get it to work. You need to add type definitions for *.ttf, import the font, and then reference that import. I guess something with CRA must have changed, as the demo "REPL" page on react-pdf also fails with the same error (see: https://react-pdf.org/repl?example=font-register)

amesq01 commented 1 year ago

Deu certo fazendo dessa forma:

const Arial = require('../../fonts/Arial/arial.ttf'); const ArialBold = require('../../fonts/Arial/arial_bold.ttf'); const ArialBlack = require('../../fonts/Arial/arial_black.ttf');

Font.register({ family: 'arial', fonts: [ { src: Arial, fontWeight: 'normal' }, { src: ArialBold, fontWeight: 'bold' }, { src: ArialBlack, fontWeight: 'ultrabold' } ] })

cyrus01337 commented 1 year ago

I had to get Libre Franklin (LibreFranklin? libre-franklin? Don't know the right way to say it) and ensure the fonts were self-hosted, so I downloaded them, laid them out in a folder (./src/server/fonts), and resolve a relative filepath to get the absolute filepath, which src needs when registering a new font. If that didn't make sense to you, here's the code that worked for registering the font:

Note: At the time of writing this, variable fonts were not supported.

Font.register({
    family: "libre-franklin",
    fonts: [
        {
            src: path.resolve("./src/server/fonts/LibreFranklin-Regular.ttf"),
            fontWeight: "normal",
        },
        {
            src: path.resolve("./src/server/fonts/LibreFranklin-Bold.ttf"),
            fontWeight: "bold",
        },
        {
            src: path.resolve("./src/server/fonts/LibreFranklin-Light.ttf"),
            fontWeight: "light",
        },
    ],
});
dscampero commented 1 year ago

Currently I solved the problem by creating an "assets" folder inside the "public" folder. Inside assets I placed my fonts and my images and it is working.

Font.register({family:"Montserrat", src: "/assets/Montserrat.ttf"})

This video was very useful! The solution is in min 7

Video

riadkhan60 commented 7 months ago

I used same src of fonts in 3 different projects, I don't know why only one project works

from-nobody commented 6 months ago

If anyone still has an issue with font loading in Next.js, here is my workaround:

  1. Download ttf font and place somewhere in src folder (e.g. theme/fonts/pt-sans-regular.tff).
  2. If you use typescript add file fonts.d.ts in your typings folder with this content:
declare module "*.ttf";
  1. Modify next.config.js like this:
module.exports = {
  // ...
  webpack: (config) => {
    config.module.rules.push({
      test: /\.ttf$/i,
      type: "asset/resource",
    });
    return config;
  },
  // ...
};
  1. Register font like this:
import PTSansRegular from "theme/fonts/pt-sans-regular.ttf"; // use path according to file location and your project configuration.

Font.register({
  family: "PT Sans",
  fontStyle: "normal",
  fontWeight: "normal",
  fonts: [
    {
      src: PTSansRegular,
    },
  ],
});

Works fine for me with PDFDownloadLink, but not working properly with PDFViewer. With PDFViewer works only after navigating to a page where the viewer is placed, but after refresh font is not applied.

A big thanks to you sir!!! I am now using Next.js 14 and it's a little bit different but it works.