hediet / vscode-drawio

This unofficial extension integrates Draw.io (also known as diagrams.net) into VS Code.
https://marketplace.visualstudio.com/items?itemName=hediet.vscode-drawio
GNU General Public License v3.0
9.09k stars 413 forks source link

Bundled offline version gets custom fonts wrong in bundled png image format, when rendering the png #263

Open chipbite opened 3 years ago

chipbite commented 3 years ago

Using: Updated extension (1.6.2), vs code, windows 10.

Issue: ("custom") Fonts are not used, and text is rendered incorrectly when saving diagram as bundled file (e g .drawio.png).

Repro:

  1. Create diagram using plugin. Save to device. Add shape (rectangle) with some text.
  2. Set font of shape to use e g "Roboto" (open font by Google, see https://fonts.google.com/specimen/Roboto)
  3. Save diagram.

Expected result:

(a) Roboto is used in shape in editor (after step 2) and (b) rendered png bitmap is created using the Roboto font.

Actual result:

(a) Roboto is indeed correctly used in the editor (after step 2) image

but (b) the png image is not correctly rendered with the font, but instead seems to default to a serif (times new roman...?) font instead: image

Analysis

This works using the online drawio version (v.14.9.9): If I open the test diagram in diagrams.net and save it, I get the expected result (b): The rendered png image is created correctly using the Roboto font.

So, this extension bundles an older drawio version for its offline use. That may explain the issue? drawio-vscode-plug-fontissues2

gabyx commented 2 years ago

The following script

import os
import xml.etree.ElementTree as ET
import re
import requests
import base64

ET.register_namespace('', "http://www.w3.org/2000/svg")
ET.register_namespace('xlink', "http://www.w3.org/1999/xlink")

currentDir = os.path.dirname(__file__)

def get_fonts_css(fontURL, embed=True):

    headers = {
        "User-Agent":
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 " +
        "(KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36"
    }

    r = requests.get(fontURL, headers=headers)
    if r.status_code != 200:
        raise RuntimeError(f"Failed to get fonts css: '{fontURL}', '{r}'")
    if ".woff" not in r.text:
        raise RuntimeError("Failed to get woff fonts.")

    # Embed all fonts
    prefix = "data:font/{0};charset=utf-8;base64,"
    res = r.text

    if embed:

        def repl(match):
            url = match.group(1)
            print(f"Embedding '{url}' ...")
            ext = os.path.splitext(url)[1].strip(".")
            r = requests.get(url, headers=headers)
            if r.status_code != 200:
                raise RuntimeError(f"Failed to get fonts: '{url}', '{r}'")
            return "url({0})".format(
                prefix.format(ext) +
                base64.b64encode(r.content).decode(encoding="utf-8"))

        res, _ = re.subn(r"url\((.*?)\)", repl, res)

    return res

def replace_fonts(f, fontsCSS):
    print(f"Replace fonts in {f}")
    xml = ET.parse(f)
    root = xml.getroot()
    s = root.findall(".//{*}style")

    s[0].text = fontsCSS
    xml.write(f, encoding="utf-8")

fontURL = "https://fonts.googleapis.com/css?family=Fira+Code:i,b,r|Fira+Sans:i,b,r"  # noqa: E501
fontsCSS = get_fonts_css(fontURL)

f = os.path.join(currentDir, "Workflow.svg")
replace_fonts(f, fontsCSS)

Replaces fonts in the svg, for a working workaround.

chipbite commented 2 years ago

Replaces fonts in the svg, for a working workaround.

Thanks! That is interesting and related - but this issue is about png, not svg.

AFAIK drawio cannot successfully bundle fonts in svg, at all. I am pretty sure there is an issue for this in the drawio project here on github.

However, drawio does handle fonts successfully for png, so there is something off about this vs code plugin not getting the same result. Which is what this issue is about. :-)