Shopify / react-native-skia

High-performance React Native Graphics using Skia
https://shopify.github.io/react-native-skia
MIT License
6.7k stars 423 forks source link

Usage of custom font-family in ImageSVG #1894

Closed wcandillon closed 9 months ago

wcandillon commented 9 months ago

Discussed in https://github.com/Shopify/react-native-skia/discussions/1876

Originally posted by **Jakub-Plan-d-k** September 26, 2023 Hello, I am facing a problem following the documentation on fonts, which can be found [here](https://shopify.github.io/react-native-skia/docs/images-svg) The root of the problem is a bit deeper - I am trying to implement my icon set font for Apache eCharts, where Skia is the rendering engine of choice. As of now I have tracked the issue to the following problem: when I try to use custom font-family within ImageSVG (where the svg contains ``) refuses to work for me, no matter what. Documentation says everything available in the app should be available there. The icon set works perfectly everywhere else, the font is linked via react-native-asset. The project is pure react native, no expo. I have tried a few versions of your library, including the 0.1.210, built today. I have tried and played with the following: - system font-family within ImageSVG `` element - works perfectly ✅ - `` element where custom font is passed as a prop thorugh the fontMgr, like [here](https://shopify.github.io/react-native-skia/docs/text/fonts/#custom-fonts) - works perfectly ✅ - tested 3 different custom font families (one of them being the icon set), I even moved all the glyphs to the very beginning of the icon font file, just in case - does not work at all❌ - custom font added after setting up the useFont/useFonts hooks - does not help in any way❌ - changed the name of the font file so it contains the "-" in the middle, then relinked and rebuild everything - does not help in any way❌ I am a bit lost. Is there a way to pass the font prop to ImageSVG? Or am I missing something? Regards, Jakub
wcandillon commented 9 months ago

@Jakub-Plan-d-k after investigation, it doesn't seem to be something trivial to add so we cannot promise a timeframe on when this will be implemented. In the meantime, here are some workarounds:

Jakub-Plan-d-k commented 9 months ago

@wcandillon thank you for the answer and for very satisfying communication! It is not urgent from my side so I am totally alright to wait.

wcandillon commented 9 months ago

I am closing this for now as it doesn't seem to be something we will add to our roadmap but please let's keep the discussion on this. It's interesting.

Looking at your use case you will have a much better chance to override the renderer to integrate deeply with RN Skia instead of passing an SVG string as a result. This will likely lead to much better results overall.

Jakub-Plan-d-k commented 9 months ago

@wcandillon I have absolutely 0 control of the Skia renderer in Apache eCharts. I guess my solution will be to try with react-native-svg.

RustyTheBoyRobot commented 7 months ago

@wcandillon - you mentioned that one option was to "add the necessary fonts as part of the native project so that they appear as system fonts on both iOS and Android." Can you elaborate a bit more?

I added some custom fonts to my RN project (for the Android flavor, the fonts went into android/app/src/main/assets/fonts) and now I can style RN Text elements with those fonts:

import { Text } from 'react-native';
// ...
<Text style={{ fontFamily: "OpenSans-Regular" }} >I am OpenSans</Text>

However, if I try to use this same font name in a <text> element in ImageSVG, the text is still using the default font:

const fontUsageSvg = Skia.SVG.MakeFromString(`
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000">
    <text y="50" font-size="50px" font-family="OpenSans-Regular">Am I OpenSans?</text>
  </svg>
`);
// ...
<Canvas ref={ref}>
  <ImageSVG
    svg={fontUsageSvg}
    x={0}
    y={0}
    width={w}
    height={h}
  />
</Canvas>

I assumed that if the RN Text element could use the font, it would mean that ImageSVG would be able to as well. Is that what you meant by "appearing as system fonts?"

RustyTheBoyRobot commented 7 months ago

Your third option was to contribute a PR, with guidance by you @wcandillon. I'd like to explore this, since our code has a performance bottleneck around rendering our text out to paths. I've got quite a bit of experience with OpenTypeJS, if that helps.

wcandillon commented 7 months ago

Hello Brad,

I investigated this a bit but it looks like in its current form this skia module makes it hard for us to achieve it. These would be the APIs we need to make available on : https://github.com/google/skia/blob/main/modules/svg/src/SkSVGDOM.cpp#L393 May I ask about your use case? To see if there is another way to achieve the desired result.

What about having the "custom fonts" loaded in the app, so they are "system fonts"?

RustyTheBoyRobot commented 6 months ago

May I ask about your use case?

We have software that takes dynamic data and generates a PNG to be printed as a label. Some of that data is text, some are graphics (SVGs). We lay all of that content out in an SVG, then rasterize it. All of our text uses the OpenSans font. We're looking to migrate to using RN Skia to rasterize for performance reasons.

What about having the "custom fonts" loaded in the app, so they are "system fonts"?

I might be misunderstanding, but I tried this with a React Native font loading mechanism. I have OpenSans loading in my app such that I can style other RN components with that font. Is that what you mean by a "system font?" Or do you mean some Skia-system font, loaded via a Skia mechanism (i.e., ResourceProvider)?

wcandillon commented 6 months ago

@RustyTheBoyRobot I must warn you that currently SVGs that have a text tag will crash with the latest version of RN Skia (see #2097). Any fonts can be loaded and used for rendering without the SVG module, for instance we provide a paragraph API: https://shopify.github.io/react-native-skia/docs/text/paragraph/ For instance in the first example we use custom font (Roboto for instance) and then the appropriate emoji font for the system (iOS/Android)