Safari 15.2 Canvas 和 .otf 字体

Safari 15.2 Canvas and .otf Fonts

我在最新的 Safari 15.2 中加载 .otf 字体时遇到问题。同样的代码过去在同一浏览器的以前版本中工作得很好,在其他浏览器中仍然工作得很好。

我遇到的问题字体之一是 Adobe Gilbert

我试过以两种不同的方式加载字体文件:

@font-face {
  font-family: gcb;
  src: url(/assets/fonts/Gilbert-Color-Bold-Preview5.otf);
}

var selectedFont = new FontFace('gcb', 'url(/assets/fonts/Gilbert-Color-Bold-Preview5.otf)');
selectedFont.load().then(function(font) {
  document.fonts.add(font);
});

(async () => {
  const fontURL = "https://cdn.jsdelivr.net/gh/Fontself/TypeWithPride@master/fonts/Gilbert-Color%20Bold%20Preview_1005.otf";
  const selectedFont = new FontFace('gcb', 'url(' + fontURL + ')');
  await selectedFont.load();
  document.fonts.add(selectedFont);
  const canvas = document.querySelector("canvas");
  ctx = canvas.getContext("2d", { alpha: false });
  ctx.fillStyle = '#fff';
  ctx.fillRect(0, 0, 300, 30);
  ctx.font = "15pt gcb";
  ctx.fillStyle = '#000';
  ctx.fillText("I'm a canvas", 0, 20);
  ctx.font = "15pt sans-serif";
  ctx.fillText(", right?", 105, 20);
})().catch(console.error)
span, text {
  font: 15pt gcb;
}
<canvas height=30></canvas><br>
<span>I'm a span</span><br>
<svg height=30><text y="15">I'm an SVG</text></svg>

在 Safari 中,我没有在 canvas:

中绘制任何内容

在 Chrome 上,我得到的文本呈现为黑色,而在 Firefox 中,文本呈现为彩色 as expected

我怎样才能让 Safari 至少呈现像 Chrome 这样的文本?

所以首先,这似乎只影响彩色字体,我能够在 Safari 中绘制相同字体的非彩色版本(也在 .otf 中)很好。

那么,这是一个错误,请随时让 Safari 用户在他们的 issue tracker.

上知道它

遗憾的是,您无能为力。
想到的唯一 hack 是在 canvas 上绘制文本的地方渲染 SVG 图像。
为此,您必须首先获取字体并生成它的数据 URL 版本,以便它可以嵌入到一个独立的 SVG 文档中,您将在 HTMLImageElement 中加载该文档以在 canvas.

真的,这是一个黑客,但由于他们仍然能够通过他们的 SVG 渲染器渲染该字体,所以可行:

(async () => {
  const fontURL = "https://cdn.jsdelivr.net/gh/Fontself/TypeWithPride@master/fonts/Gilbert-Color%20Bold%20Preview_1005.otf";
  const fontRes = await fetch(fontURL);
  if (!fontRes.ok) {
    throw new Error("failed to load");  
  }
  const fontBlob = await fontRes.blob();
  const dataURL = await new Promise((res) => {
    const reader = new FileReader();
    reader.onload = () => res(reader.result);
    reader.readAsDataURL(fontBlob);
  });
  const svgNode = document.querySelector("svg").cloneNode(true);
  const style = document.createElementNS("http://www.w3.org/2000/svg", "style");
  style.textContent = `
    @font-face {
        font-family: gcb;
      src: url("${ dataURL }") format("opentype");
    }
    text {
        font: 15pt gcb;
    }
  `;
  svgNode.prepend(style);
  svgNode.querySelector("text").textContent = "I'm a svg drawn in a canvas";
  const markup = new XMLSerializer().serializeToString(svgNode);
  const svgBlob = new Blob([markup], { type: "image/svg+xml" });
  const img = new Image;
  await new Promise((res, rej) => {
    img.onload = e => setTimeout(res, 100); // webkit fires load before inner fonts are loaded...
    img.onerror = rej;
      img.src = URL.createObjectURL(svgBlob);
  });
  const canvas = document.querySelector("canvas");
  const ctx = canvas.getContext("2d", { alpha: false });
  ctx.fillStyle = '#fff';
  ctx.fillRect(0, 0, 300, 30);
  ctx.font = "15pt gcb";
  ctx.drawImage(img, 0, 0);
})().catch(console.error)
span, text {
  font: 15pt gcb;
}
@font-face {
  font-family: gcb;
  src: url(https://cdn.jsdelivr.net/gh/Fontself/TypeWithPride@master/fonts/Gilbert-Color%20Bold%20Preview_1005.otf) format("opentype");
}
<canvas height=30></canvas><br>
<span>I'm a span</span><br>
<svg height=30 width="300"><text y="15">I'm an SVG</text></svg>