【问题标题】:reproduce Bounding Box of text in Browsers在浏览器中重现文本边界框
【发布时间】:2017-08-25 16:34:57
【问题描述】:

在浏览器中使用 SVG 时,浏览器有一个 getBBox 函数,可以为您提供各种元素的边界框。但是当涉及到文本元素时,我真的很困惑这个边界框是如何计算的。 我知道字体大小基于字体文件中指定的 em-Box。 但是我的测试表明,这些都不会产生与 FF 或 Chrome 相同的结果(在 fontsize 1000 上仅相差几个 px):

fontSize != bbox-height
(ascender-descender)/unitsPerEm * fontSize != bbox-height
(unitsPerEm-descender)/unitsPerEm * fontSize != bbox-height
...maybe adding a fixed amount to ascender for accents? Like Ć

那么浏览器中文本的bbox高度背后的秘密是什么?

我什至尝试查看 FF 和 Chrome 的源代码,但找到计算所基于的正确位置本身就是一个挑战

// 编辑:回应评论: 我想像在浏览器中那样计算 svg 文本的 bbox(复制行为)。我需要知道正确计算bbox所需的字体指标和用于计算(宽度和高度足够)的公式

【问题讨论】:

  • 您真正想知道什么?因为您加粗的文本无论如何都不是一个真正的问题。浏览器是复杂的应用程序,它们明智地使用第三方库进行文本解析等操作,使用 harfbuzz 或 freetype 等整形器,它们提取绑定到特定字体的字符串并返回轮廓数据和排版指标。
  • 那么问题是:使用了哪些指标以及如何获取它们?
  • 酷:你能更新你的帖子明确是那个问题吗?以及准确解释您需要哪些指标用于什么目的,这样我们就不会得到XY problem
  • 如果你只是编辑问题而不是添加单词“编辑”会好得多。人们会找到您的问题并期望看到他们需要看到的内容。不再适用的文本不需要留在问题中(实际上只是让事情变得不太清楚)。那么你可以重写一个完整的问题吗?这也是关于浏览器在将<text> 元素渲染为<svg> 块的一部分时所做的事情吗? (如果是这样,明确说明也是一个好主意)

标签: javascript svg fonts bounding-box


【解决方案1】:

经过大量的研究和反复试验,我找到了一个可能的解决方案,至少可以解释文本 bbox 尺寸的 chrome 行为。

BBox 高度

首先我使用了 npm 包fontkit 来加载和解析字体文件。 fontkit 为您提供整体字体的几个指标,其中包括:

  • font.ascent
  • font.descent
  • font.lineGap
  • font.unitsPerEm

所以为了计算 bbox 的高度,我想到了以下几点:

bboxHeight = (font.ascent - font.descent + font.lineGap) / unitsPerEm * fontSize

但是,当字体大于 em 框 (font.ascent - font.descent > unitsPerEm) 时会导致错误。在这种特殊情况下,bboxHeightfont.ascent - font.descent

这导致以下高度代码:

var fontHeight = font.ascent - font.descent
var lineHeight = fontHeight > font.unitsPerEm ? fontHeight : fontHeight + font.lineGap
var height = lineHeight/font.unitsPerEm * fontSize

BBox 宽度

为了计算文本的宽度,我使用了fontkitlayout 功能。 layout 使您可以访问从中提取文本的字形,还可以访问字形的度量。我们需要的度量是advanceWidth,它包括当前glpyh旁边其他字形的边距。通过总结所有advanceWidths 并相应地缩放它们,我最终得到了bboxWidth

var width = font.layout(text).glyphs.reduce((last, curr) => last + curr.advanceWidth, 0)
width = width / font.unitsPerEm * fontSize

BBox y 位置

麻烦不止于此,我们还要计算bbox的y位置。这是一个相当简单的公式:

var bboxY = y-font.ascent/font.unitsPerEm * fontSize

y 是从 dom 中提取的理论位置(ydy 属性)


BBox x 位置

这只是你从 dom 中提取的数字(xdx


整箱:

var box = {
    x:x,
    y: y-font.ascent/font.unitsPerEm * fontSize,
    width: width
    height: height
}

希望对其他人有所帮助!

【讨论】:

  • 非常有帮助。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-26
  • 2011-10-15
  • 2011-04-21
  • 2012-09-03
  • 1970-01-01
  • 2014-04-27
相关资源
最近更新 更多