efharkin Posted November 20, 2022 Share Posted November 20, 2022 (edited) Description of bugs: Text in imported SVG documents is not rendered in the correct size or font family if the font was specified using the shorthand "font" property (eg "font: 10pt 'Arial'"), and font sizes seem to always be interpreted in points even if "px" units are specified. Use case: I like to use Affinity Designer to make manual adjustments to scientific figures generated using the popular Python plotting library Matplotlib and saved as SVGs. It so happens that Matplotlib writes font information using the "font" property rather than "font-size" and "font-family". Affinity Designer is fantastic but has long had issues with rendering text from SVG files created by Matplotlib, so I often end up having to either save the SVG text as paths (making it non-editable) or save my figures as PNGs and use Affinity only for arranging them. I know at least a few people who are currently using Inkscape (which doesn't have this bug) and would consider switching to Affinity if this issue were fixed. To reproduce: Open the minimal SVG file below in Affinity Designer and in a web browser. (See screenshots below; the one with consistent font sizes is from Firefox 106.0.5 and the other is from Affinity.) <?xml version="1.0" encoding="utf-8" standalone="no"?> <!DOCTYPE svg> <svg xmlns:xlink="http://www.w3.org/1999/xlink" width="200pt" height="125pt" viewBox="0 0 200 125" xmlns="http://www.w3.org/2000/svg" version="1.1"> <text x="0" y="15" style="font: 7.5pt 'Arial'">font: 7.5pt 'Arial'</text> <text x="0" y="30" style="font: 10px 'Arial'">font: 10px 'Arial'</text> <text x="0" y="45" style="font: 7.5pt 'Helvetica'">font: 7.5pt 'Helvetica'</text> <text x="0" y="60" style="font: 10px 'Helvetica'">font: 10px 'Helvetica'</text> <text x="0" y="75" style="font-size: 7.5pt; font-family: 'Arial'">font-size: 7.5pt; font-family: 'Arial'</text> <text x="0" y="90" style="font-size: 10px; font-family: 'Arial'">font-size: 10px; font-family: 'Arial'</text> <text x="0" y="105" style="font-size: 7.5pt; font-family: 'Helvetica'">font-size: 7.5pt; font-family: 'Helvetica'</text> <text x="0" y="120" style="font-size: 10px; font-family: 'Helvetica'">font-size: 10px; font-family: 'Helvetica'</text> </svg> To test compatibility with Matplotlib directly, here's a minimal Python script. The screenshots are again from Firefox and Affinity. import matplotlib as mpl import matplotlib.pyplot as plt # Export text as regular text instead of paths or using svgfonts mpl.rcParams['svg.fonttype'] = 'none' # Set font to a widely-available but non-default font to show that Affinity # ignores font-family mpl.rcParams['font.family'] = 'sans-serif' mpl.rcParams['font.sans-serif'] = 'Helvetica' # Make the figure 1in x 0.75in so that incorrect font sizes in Affinity are # very obvious (text will badly overflow). plt.figure(figsize=(1, 0.75)) plt.plot([1, 2, 3], [2, 1, 1], label='My line') plt.ylabel('Y-axis label') plt.xlabel('X-axis label') plt.legend(loc='upper left', bbox_to_anchor=(1, 1)) plt.savefig('matplotlib-demo.svg', bbox_inches='tight') System information: MacOS 10.15.7 on Intel Macbook Pro Affinity Designer 2.0.0 Turning hardware acceleration on and off doesn't affect problem No unusual hardware or software Edited November 20, 2022 by efharkin Add example python script to reproduce Quote Link to comment Share on other sites More sharing options...
efharkin Posted November 20, 2022 Author Share Posted November 20, 2022 In case anyone comes across this issue looking for a temporary fix, running SVGs created by Matplotlib through the script below produces usable results for me: #!python import re def patch_affinity_svg(svg_text): """Patch Matplotlib SVG so that it can be read by Affinity Designer.""" matches = [ x for x in re.finditer('font: ([0-9.]+)px ([^;]+);', svg_text) ] svg_pieces = [svg_text[: matches[0].start()]] for i, match in enumerate(matches): # Change "font" style property to separate "font-size" and # "font-family" properties because Affinity ignores "font". font_size_px, font_family = match.groups() new_font_style = ( f'font-size: {float(font_size_px):.1f}px; ' f'font-family: {font_family};' ) svg_pieces.append(new_font_style) if i < len(matches) - 1: svg_pieces.append(svg_text[match.end() : matches[i + 1].start()]) else: svg_pieces.append(svg_text[match.end() :]) return ''.join(svg_pieces) if __name__ == '__main__': import argparse parser = argparse.ArgumentParser() parser.add_argument('fname', help="Path to Matplotlib SVG file to patch.") parser.add_argument( '-o', '--output', help="Path to output patched file.", required=False ) args = parser.parse_args() with open(args.fname, 'r') as f: svg_text = f.read() patched_svg = patch_affinity_svg(svg_text) if args.output is None: args.output = args.fname with open(args.output, 'w') as f: f.write(patched_svg) Quote Link to comment Share on other sites More sharing options...
Staff NathanC Posted December 2, 2022 Staff Share Posted December 2, 2022 Hi @efharkin, This has been previously logged with the developers, i've included the details of your report for consideration. Quote Link to comment Share on other sites More sharing options...
daxigua Posted December 7, 2022 Share Posted December 7, 2022 (edited) NameError: name 'patch_affinity_svg' is not defined Edited December 7, 2022 by daxigua Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.