计算字体字形的确切大小

时间:2020-11-28 20:30:36

I need a way to find the exact size and position of a glyph relative to its bounding box.

我需要一种方法来找到字形相对于其边界框的确切大小和位置。

We're using D3.js to create an SVG with a heading, a smaller byline and a short body text. Pretty much this:

我们正在使用D3.js创建一个带有标题,较小的署名和短正文的SVG。差不多这个:

Lorem ipsum

Lorem ipsum dolor

Lorem ipsum dolor sit amet,
consectetur adipisicing elit,
sed do eiusmod tempor
incididunt ut labore et dolore
magna aliqua

Lorem ipsum dolor sit amet,consectetur adipisicing elit,sed do eiusmod tempor incididunt ut labore et dolore magna aliqua

As in this example, I need the text to be left-aligned regardless of font-size.

在这个例子中,无论font-size如何,我都需要左对齐文本。

The problem is that it is each lines bounding box that's aligned and not the glyphs. Which makes the headings look indented. How can I calculate that space between the bounding box and the glyph so I can correctly align the text?

问题是每个线条边界框都是对齐的而不是字形。这使标题看起来缩进。如何计算边界框和字形之间的空间,以便我可以正确对齐文本?

A colleague sat down and manually measured this for the English font, which works pretty well. We could probably do this in Adobe Illustrator, but we need the information for English, Chinese and Arabic fonts. To do this by hand is more or less impossible.

一位同事坐下来手动测量了这个英文字体,效果非常好。我们可以在Adobe Illustrator中执行此操作,但我们需要英文,中文和阿拉伯字体的信息。用手做这个或多或少是不可能的。

The only solution I can come up with is to type each character in a canvas element and map each pixel to see where the glyph starts and ends.

我能想出的唯一解决方案是在canvas元素中键入每个字符并映射每个像素以查看字形的开始和结束位置。

What I think would be ideal is a way to use the SVG font path information to find the extremes, that way we would get the exact numbers instead of estimates. Our estimates have a big margin of error. Is there a way to do that with node.js?

我认为理想的是一种使用SVG字体路径信息来查找极值的方法,这样我们就可以得到确切的数字而不是估计值。我们的估计有很大的误差。有没有办法用node.js做到这一点?

An example of what the SVG looks like:

SVG的示例:

<svg viewBox="0,0,1008,1424" height="1052px" width="744px" version="1.1" 
    xmlns:xlink="http://www.w3.org/1999/xlink" 
    xmlns="http://www.w3.org/2000/svg">
    <g transform="translate(50,150)" class="container">
        <g transform="translate(0,205)" class="textContainer">
            <g fill="white" font-family="serif" font-size="" class="header">
                <text>
                    <tspan y="147.7104222717285" style="" font-size="208" 
                        x="-21.8359375">Lorem ipsum</tspan>
                </text>
                <text>
                    <tspan y="201.46275431823733" style="" font-size="45" 
                        x="-4.72412109375">Lorem ipsum dolor</tspan>
                </text>
            </g>
            <g lengthAdjust="spacingAndGlyphs" textLength="297" fill="white" 
                transform="translate(0,214)" font-family="sans-serif" 
                class="paragraph" font-size="14">
                <text y="16.8" x="0">Lorem ipsum dolor sit amet,</text>
                <text y="33.6" x="0">consectetur adipisicing elit,</text>
                <text y="50.4" x="0">sed do eiusmod tempor</text>
                <text y="67.2" x="0">incididunt ut labore et dolore</text>
                <text y="84" x="0">magna aliqua</text>
            </g>
        </g>
    </g>
</svg>

It is the x and y values on the text and tspan elements we need to calculate, the negative x values in particular. Note: we don't actually use the serif or sans-serif font families, we use a custom font. I don't think the English font is created with web use in mind. We used fontsquirrel.com to create the SVG font file.

它是我们需要计算的文本和tspan元素的x和y值,特别是负x值。注意:我们实际上并没有使用serif或sans-serif字体系列,我们使用自定义字体。我不认为英文字体是在创建Web时使用的。我们使用fontsquirrel.com来创建SVG字体文件。

Update

SVG fonts seemed like the most logical option, since you have all the path information in the file readable in node. You'd just have to interpret it. But we found, and decided to go with, opentype.js which works with otf and ttf fonts.

SVG字体似乎是最合理的选项,因为您可以在节点中读取文件中的所有路径信息。你只需要解释它。但我们发现,并决定使用与otf和ttf字体一起使用的opentype.js。

I'd still like to know if this is at all possible to do with SVG fonts.

我还是想知道这是否与SVG字体完全相同。

2 个解决方案

#1


1  

I think this may do what you want. Note that it requires jQuery and is a bit hacky. You may want to set line-height in the css object.

我想这可能会做你想要的。请注意,它需要jQuery并且有点hacky。您可能希望在css对象中设置line-height。

function glyphSize(glyph,css){
  var span = $('<div>');
  span.text(glyph);
  span.css({
    display:'inline-block',
    position:'fixed',
    top:'100%'
  }).css(css);

  $('body').append(span);
  var out = {
    width:span.width(),
    height:span.height()
  } 
  span.remove();
  return out;
}

var size = glyphSize('a',{
  'font-family':'fantasy, sans-serif' // css to apply to the test element
});

/* size = {
 width:7,
 height:20
} */

edit: quick demo here

编辑:快速演示在这里

#2


0  

Saw your question and had the problem myself. I solved it very simple in my opinion. I just created a new text element with opacity 0.0. I add it to the svg, get the bbox and remove it. The bbox contains the width and height:

看到你的问题并自己解决了问题。在我看来,我解决了这个问题。我刚刚创建了一个不透明度为0.0的新文本元素。我将它添加到svg,获取bbox并将其删除。 bbox包含宽度和高度:

getBBox : function(svgId, text, styleClass) {
    // Add tmp text element to the SVG
    var tempSvgTextElement = d3.select("#" + svgId)
    .append("text")
    .style("opacity", 0.0)
    .attr("class", styleClass);

    var tSpanTextNode = document.createTextNode(text);
    var svgTSpan = tempSvgTextElement.append("tspan").attr("class", styleClass).node();
    svgTSpan.appendChild(tSpanTextNode);
    var bbox = tempSvgTextElement.node().getBBox();
    tempSvgTextElement.remove();
    return bbox;
}

#1


1  

I think this may do what you want. Note that it requires jQuery and is a bit hacky. You may want to set line-height in the css object.

我想这可能会做你想要的。请注意,它需要jQuery并且有点hacky。您可能希望在css对象中设置line-height。

function glyphSize(glyph,css){
  var span = $('<div>');
  span.text(glyph);
  span.css({
    display:'inline-block',
    position:'fixed',
    top:'100%'
  }).css(css);

  $('body').append(span);
  var out = {
    width:span.width(),
    height:span.height()
  } 
  span.remove();
  return out;
}

var size = glyphSize('a',{
  'font-family':'fantasy, sans-serif' // css to apply to the test element
});

/* size = {
 width:7,
 height:20
} */

edit: quick demo here

编辑:快速演示在这里

#2


0  

Saw your question and had the problem myself. I solved it very simple in my opinion. I just created a new text element with opacity 0.0. I add it to the svg, get the bbox and remove it. The bbox contains the width and height:

看到你的问题并自己解决了问题。在我看来,我解决了这个问题。我刚刚创建了一个不透明度为0.0的新文本元素。我将它添加到svg,获取bbox并将其删除。 bbox包含宽度和高度:

getBBox : function(svgId, text, styleClass) {
    // Add tmp text element to the SVG
    var tempSvgTextElement = d3.select("#" + svgId)
    .append("text")
    .style("opacity", 0.0)
    .attr("class", styleClass);

    var tSpanTextNode = document.createTextNode(text);
    var svgTSpan = tempSvgTextElement.append("tspan").attr("class", styleClass).node();
    svgTSpan.appendChild(tSpanTextNode);
    var bbox = tempSvgTextElement.node().getBBox();
    tempSvgTextElement.remove();
    return bbox;
}