Рассчитать точный размер глифа шрифта

Мне нужен способ найти точный размер и положение глифа относительно его ограничивающей рамки.

Мы используем D3.js для создания SVG с заголовком, меньшей подписью и коротким основным текстом. Примерно так:

Лорем ипсум

Lorem ipsum dolor

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

Как и в этом примере, мне нужно, чтобы текст был выровнен по левому краю независимо от размера шрифта.

Проблема в том, что выравнивается ограничивающая рамка каждой строки, а не глифы. Из-за чего заголовки выглядят с отступом. Как рассчитать расстояние между ограничительной рамкой и глифом, чтобы правильно выровнять текст?

Коллега сел и вручную измерил это для английского шрифта, который работает очень хорошо. Вероятно, мы могли бы сделать это в Adobe Illustrator, но нам нужна информация для английского, китайского и арабского шрифтов. Сделать это вручную более или менее невозможно.

Единственное решение, которое я могу придумать, — это ввести каждый символ в элемент холста и сопоставить каждый пиксель, чтобы увидеть, где начинается и заканчивается глиф.

То, что я думаю, было бы идеальным, так это способ использовать информацию о пути шрифта SVG для поиска крайностей, таким образом, мы получили бы точные числа вместо оценок. Наши оценки имеют большую погрешность. Есть ли способ сделать это с помощью node.js?

Пример того, как выглядит 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>

Нам нужно вычислить значения x и y для элементов text и tspan, в частности отрицательные значения x. Примечание: на самом деле мы не используем семейства шрифтов serif или sans-serif, мы используем собственный шрифт. Я не думаю, что английский шрифт создан для использования в Интернете. Мы использовали fontsquirrel.com для создания файла шрифта SVG.

Обновлять

Шрифты SVG казались наиболее логичным вариантом, поскольку вся информация о пути в файле доступна для чтения в node. Вам просто нужно интерпретировать это. Но мы нашли и решили использовать opentype.js, который работает со шрифтами otf и ttf. .

Я все еще хотел бы знать, возможно ли это вообще сделать со шрифтами SVG.


person pstenstrm    schedule 20.06.2014    source источник
comment
В настоящее время нет способа получить метрики глифов в SVG. Возможно, вам стоит просто использовать шрифт без засечек.   -  person Robert Longson    schedule 20.06.2014
comment
Я обновил свой вопрос. На самом деле мы не используем эти шрифты, мы используем пользовательские шрифты, которые невозможно заменить.   -  person pstenstrm    schedule 20.06.2014
comment
Джейсон Дэвид некоторое время назад написал код для плагина d3-cloud для обнаружения столкновений между символами, который работал путем рендеринга символов и выполнения рекурсивных вычислений с ограниченным прямоугольником. В конце концов, он не использовал его, но, возможно, вы можете использовать его повторно: jasondavies.com /wordcloud/о   -  person musically_ut    schedule 20.06.2014
comment
@musical_ut Это выглядит интересно, и я могу что-то использовать. На самом деле не имеет значения, если это неэффективно   -  person pstenstrm    schedule 21.06.2014


Ответы (2)


Я думаю, что это может сделать то, что вы хотите. Обратите внимание, что он требует jQuery и немного хакерский. Вы можете установить высоту строки в объекте css.

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
} */

редактировать: краткая демонстрация здесь

person kyledavide    schedule 30.06.2014
comment
Это дало бы только ширину и высоту ограничивающей рамки, а не глифа. - person pstenstrm; 30.06.2014

Увидел ваш вопрос и сам столкнулся с проблемой. Я решил это очень просто, на мой взгляд. Я только что создал новый текстовый элемент с непрозрачностью 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;
}
person Arnoud Wolfard    schedule 23.12.2014