Closed grahampcharles closed 5 months ago
Loading the font over https fixed for me. See here. The REPL is a little buggy lately though. Does this fix your issue?
This is the way we are currently dealing with a locally hosted font:
import BoldArial from "../../assets/fonts/ArialBold.ttf";
import Arial from "../../assets/fonts/Arial.ttf";
Font.register({
family: "Arial",
fontStyle: "normal",
fontWeight: "normal",
fonts: [
{
src: Arial,
},
{
src: BoldArial,
fontWeight: "bold",
},
],
});
Then to use it:
const styles = StyleSheet.create({
normalText: {
fontFamily: "Arial",
},
boldExample: {
fontWeight: "bold",
fontFamily: "Arial",
},
});
I'm also having serious troubles over what seems to be a tiny tasking of locating and loading font files. I'm on Next, and among Next, React, Webpack 4 and react-pdf, I've given up and finally moved the fonts to the back end. Now, I'm battling weird CORS issues in Chrome, but at least that's a more well-known problem. 😅 Not saying it's the library author's fault . . . it's just that the number of tools and possible configurations has grown so much that we are always stuck in this hole or another.
I keep getting Unknown font format error if I try to load Roboto from google fonts or any other page, either from local or the url.
import RobotoRegular from "../../../../../static/frontend/fonts/Roboto-Regular.ttf";
Font.register({
family: "Roboto",
// src: "https://fonts.googleapis.com/css2?family=Roboto&display=swap",
src: RobotoRegular,
});
export const styles = StyleSheet.create({
page: {
fontFamily: "Roboto",
},
});
I am also still having an issue trying to register a font.
Currently my code looks like this
Font.register({
family: 'Mosaic',
src: require("../../fonts/PaletteMosaic-Regular.ttf"),
})
I am getting "Unhandled Rejection (TypeError): dataUrl.split is not a function" in font.js whenever I try to view the document in the PDFViewer. I tested in both Edge and Chrome.
I feel like I am missing something but all of the examples look similar to what I have above. Has anyone found other solutions that have worked for them?
Are you running react-pdf in the browser or node? To what resolves require("../../fonts/PaletteMosaic-Regular.ttf")
in your project?
I am running it in the browser. That path resolves to /src/fonts in my React app
As a url? It seems that the resolve is not returning either a url of the font, or base64 encoded data or buffer. Try console logging the require and check that
This is what I get in the Edge console when I log require("../../fonts/PaletteMosaic-Regular.ttf")
:
Module {default: "/static/media/PaletteMosaic-Regular.d47d626b.ttf", __esModule: true, Symbol(Symbol.toStringTag): "Module"}
default: "/static/media/PaletteMosaic-Regular.d47d626b.ttf"
Symbol(Symbol.toStringTag): "Module"
__esModule: true
[[Prototype]]: Object
@ghood97 With this error it looks like the url
property expects a string, but you're passing an object with the string under the default attribute (the font is exported as an ES Module). Therefore you get the dataUrl.split
error where the plugin treats the object as a string, which of course doesn't work. I would expect the following to work:
const font = require("../../fonts/PaletteMosaic-Regular.ttf")
Font.register({
family: 'Mosaic',
src: font.default,
})
That's exactly right @tobua , thanks! The snippet above should work, but only if the font is being served as an asset on the web server you're using. Don't forget you're in a web environment so you cannot load things from your file system with just their path
@tobua @diegomura Thanks for pointing that out to me, that was a good teaching moment!
That worked to clear up the "dataUrl.split is not a function" error. Now I am getting TypeError: Cannot read property 'hasGlyphForCodePoint' of null. I saw this was mentioned in a couple of other issues as well.
Well, now it's less simple. The error basically means that the font it's trying to render hasn't been registered or the registration failed. A few tips:
fontFamily
in the stylesheet matches the registered font Mosaic
Here is some more info after testing:
fontFamily
matches the registered fontTypeError: Cannot read property 'hasGlyphForCodePoint' of null
)At least I can see the the font is being loaded and displayed even if it is just briefly. What else could cause this error?
What react-pdf version are you using? It's hard to tell without a way to replicate it or more context. Font.register
can and should be outside any component
I just updated to @react-pdf/renderer v2.0.18. I was a couple of minor versions behind. I am no longer getting errors and the document loads, but now the font is not being applied to the text.
Just to be clear this is the code I am currently using:
const font = require("../../fonts/OpenSans-Regular.ttf").default
Font.register({
family: 'OpenSans',
src: font,
})
const titleStyles = StyleSheet.create({
title: {
textAlign: 'center',
fontSize: '32',
fontFamily: 'OpenSans'
}
})
return (
<Text style={titleStyles.title}>{props.title}</Text>
)
I also tried to change the font src in the REPL with "https://fonts.gstatic.com/s/stixtwotext/v1/YA9Gr02F12Xkf5whdwKf11l0jbKkeidMTtZ5Yihg2ROfURA.woff2" and that didn't work either.
Is there anything else I should try?
UPDATE: The font is applied to the PDF when I download it and open it., but it does not show in the PDFViewer.
Had no luck with woff2 either, I don't think it's supported. Since you mentioned the REPL the following did work well there:
Font.register({
family: 'CyrBit',
src: 'https://fonts.cdnfonts.com/s/7818/CyrBit.woff',
})
const Quixote = () => (
<Document>
<Page>
<Text style={{fontFamily: 'CyrBit'}}>hello</Text>
</Page>
</Document>
);
ReactPDF.render(<Quixote />);
Since in your case downloading works while the PDFViewer fails I assume you're rendering before registering the font. Downloading works, as this only renders once the user downloads.
The PDFViewer will render as soon as displayed on the page, therefore you basically need to ensure to register before even rendering any React with react-dom.render
.
Without a reproducible example all this is just a guess.
That makes sense. I will play around with it a little more. Thanks for your help on this.
The last thing I will add about this is that when the PDFViewer JSX is before the PDFDownloadLink, the font is applied in the viewer. But when the PDFViewer JSX is after the PDFDownloadLink, it does not apply the font in the viewer.
Example: This does NOT apply the font
<PDFDownloadLink document={doc} fileName={filename} style={{ display: 'block' }}>
{({ loading }) => (loading ? loadingJsx : downloadReadyJsx)}
</PDFDownloadLink>
<Container fluid>
<PDFViewer style={{ display: 'block', width: '100%', height: '100vh' }}>
{doc}
</PDFViewer>
</Container>
This DOES apply the font
<Container fluid>
<PDFViewer style={{ display: 'block', width: '100%', height: '100vh' }}>
{doc}
</PDFViewer>
</Container>
<PDFDownloadLink document={doc} fileName={filename} style={{ display: 'block' }}>
{({ loading }) => (loading ? loadingJsx : downloadReadyJsx)}
</PDFDownloadLink>
So I know that the font is registering before the render, but I have no idea why the above example would make a difference. It is consistent every time
Good point, glad it's now working. Just updated my example and the viewer fails completely if the download link is rendered before. I even left a note there before to only render either one, as at first they couldn't be rendered together.
Might very well be an issue with the plugin, but in my opinion not directly related to the fonts. Since all browser viewers already have download options it's probably not a priority.
@diegomura to close this.
@ghood97 I debugged the font loading today, and I at least found a workaround for the ordering problem. See https://github.com/diegomura/react-pdf/issues/1494#issuecomment-918359220
This is the way we are currently dealing with a locally hosted font:
import BoldArial from "../../assets/fonts/ArialBold.ttf"; import Arial from "../../assets/fonts/Arial.ttf"; Font.register({ family: "Arial", fontStyle: "normal", fontWeight: "normal", fonts: [ { src: Arial, }, { src: BoldArial, fontWeight: "bold", }, ], });
Then to use it:
const styles = StyleSheet.create({ normalText: { fontFamily: "Arial", }, boldExample: { fontWeight: "bold", fontFamily: "Arial", }, });
Thanks!! It really works!
It does work this way in the browser in development for me as well.
But sometimes the font is not loaded when the PDF is rendered for the first time after refreshing, which is why I have to resort to the await
trick I described in https://github.com/diegomura/react-pdf/issues/1494#issuecomment-918359220.
And when bundling for production (using vite in my case), I always get the Unknown font format
error. Will have to debug that one soon.
The reason for my problem on production was that vite refused to bundle the font files in a production build. When react-pdf fetched the fonts, the server would then fall back to serving the index.html of my vite app. This file of course is not a font file, and so react-pdf / fontkit rightfully reported Unknown font format
.
The reason for my problem on production was that vite refused to bundle the font files in a production build. When react-pdf fetched the fonts, the server would then fall back to serving the index.html of my vite app. This file of course is not a font file, and so react-pdf / fontkit rightfully reported
Unknown font format
.
same problem :(
@zavbala I doubt you have the exact same problem as me, since I am using a rather nonstandard setup of running a Vue.js app using Vite, which only uses react for PDF rendering, nothing else. The problem in my case was not with react-pdf itself, but rather with Vite. React-pdf / fontkit could have provided a more helpful error message, but that's about it.
In case you do have a very similar setup (especially if you use Vite), I solved the problem by forcing Vite to include the font files in the production bundle, see here. This line in my case MUST be in a Vue.js file, it won't work if it's in a .jsx file or if it's only imported by a .jsx file.
But I suspect you probably experience the other problem that is detailed in this issue, for which a workaround already exists: You can await
a Font.load({ fontFamily: 'MyCustomFont' })
call before rendering the PDF, and then it works.
Anyone still experiencing this issue should check my solution for Next.JS, but it works with React too. The solution for local font is to make sure the font is publicly available from your app URL.
https://github.com/diegomura/react-pdf/issues/1954#issuecomment-1891009006
Will close this as it derail a lot from original post and several fixes were proposed. Thanks so much all for replying!
Does anyone have working code that changes the font? Ideally, from fonts.gstatic.com or hosted locally? I'm spending hours on what should be really trivial; specifically:
Tearing my hair out over this. Does react-pdf just not do fonts?