This is how I got custom font files on AWS s3 to be loaded (but for this example I am using a local file system) - note that they are all woffs.
If all of your fonts can be loaded by the TTFont
class from fontTools, you can do something like this - it is possible to convert the different fonts into other fonts with this library as well:
from fontTools.ttLib import TTFont
from pathlib import Path
import xml.etree.ElementTree as ET
from io import BytesIO
from reportlab.graphics import renderPM
import svglib.fonts
from svglib.svglib import svg2rlg
def to_pdf_buffer(d, *args, **kwargs):
buffer = BytesIO()
renderPDF.drawToFile(d, buffer, *args, **kwargs)
return buffer
def to_pil(d, *args, **kwargs):
pil = renderPM.drawToPIL(d, *args, **kwargs)
return pil
ET.register_namespace('', "http://www.w3.org/2000/svg")
file_path = Path("my_svg.svg")
root = ET.parse(str(file_path)).getroot()
font_map = svglib.fonts.get_global_font_map()
fonts = []
unloaded_fonts = []
Folder = "./" # folder to where your fonts are
for e in self.root.findall(".//{http://www.w3.org/2000/svg}text"):
font_family_name = e.get('font-family')
if font_family_name is not None and font_family_name not in fonts:
fonts.append(font_family_name)
path = Path(Folder)
if path.exists() and path.is_dir():
file = path.joinpath(Path(f"./{font_family_name}.woff"))
data = file.read_bytes()
try:
TTFont(data)
except:
unloaded_fonts.append(font_family_name)
continue
else:
try:
font = BytesIO(file.read_bytes())
font_map.register_font(font_family_name, font_path=font)
except:
unloaded_fonts.append(font_family_name)
if len(unloaded_fonts) > 0:
print(f"Could not load fonts: {', '.join(unloaded_fonts)}")
drawing = svg2rlg(BytesIO(ET.tostring(root)), font_map=font_map)
pil = to_pil(drawing, dpi=1200)
pil.save(str(file_path.with_suffix(".png")))
svglib
has a font map that is available by calling the svglib.get_global_font_map()
function. You can load fonts into by using the font map's method register_fonts
which takes a font name and either a path or data (its somewhere in their docs - you can't supply both or something like that).
This uses the ElementTree library to parse for text element font-family tags. It gets their name and finds a font file with the that font family name and loads it, which works for my application, but won't work for others, because typically you load the fonts using css @font-face. In order for the @font-face option to work, you'd have to parse it and get it's data and register those fonts into the font map. It's not terribly difficult, but I am definitely both too lazy and having my attention redirected to a different problem at this time, so I don't have the will power to do it, but this is enough information for a foundation for another builder to come and build upon it.
Just want to clarify once more: to make this work, your text has to have a font-family and your font files must be names of those font-families; also mine were all woffs, so you may have to replace the file extension.
EDIT:
A major draw back (IMO) is that svglib does not support SVG 2, which is part of the reason why I ultimately abandoned this solution. I am still working on something for SVG 2.