Алгоритм оценки ширины текста на основе содержимого - PullRequest
11 голосов
/ 29 апреля 2009

Это длинный путь, но кто-нибудь знает алгоритм оценки и классификации ширины текста (для шрифта переменной ширины) на основе его содержимого?

Например, я хотел бы знать, что iiiiiiii не такой широкий, как abcdefgh , который, в свою очередь, не такой широкий, как WWWWWWWW , даже хотя все три строки имеют длину восемь символов.

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

Этот вопрос на самом деле не зависит от языка, но если есть алгоритм, я его реализую на Java. Это для веб-приложения. Я знаю, что есть ответы на SO, которые решают эту проблему с помощью JavaScript, чтобы получить ширину содержащего div элемента, но я задавался вопросом, возможно ли решение на стороне сервера.

Ответы [ 8 ]

15 голосов
/ 29 апреля 2009

Большинство каркасов GUI предоставляют некоторый способ для вычисления текстовых метрик для шрифтов на заданных устройствах вывода.

Например, используя java.awt.FontMetrics, я считаю, что вы можете сделать это:

import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics; 

public int measureText(Graphics g, String text) {
   g.setFont(new Font("TimesRoman", Font.PLAIN, 12));
   FontMetrics metrics = g.getFontMetrics();

   return metrics.stringWidth(text);
}

Не проверено, но вы поняли.


В .Net вы можете использовать метод Graphics.MeasureString. В C #:

private void MeasureStringMin(PaintEventArgs e)
{

    // Set up string.
    string measureString = "Measure String";
    Font stringFont = new Font("Arial", 16);

    // Measure string.
    SizeF stringSize = new SizeF();
    stringSize = e.Graphics.MeasureString(measureString, stringFont);

    // Draw rectangle representing size of string.
    e.Graphics.DrawRectangle(new Pen(Color.Red, 1), 0.0F, 0.0F, stringSize.Width, stringSize.Height);

    // Draw string to screen.
    e.Graphics.DrawString(measureString, stringFont, Brushes.Black, new PointF(0, 0));
}
5 голосов
/ 07 июля 2011

Это сработало для меня:

AffineTransform af = new AffineTransform();     
FontRenderContext fr = new FontRenderContext(af,true,true);     
Font f = new Font("Arial", 0, 10); // use exact font
double width= f.getStringBounds("my string", fr).getWidth();      
2 голосов
/ 29 апреля 2009

Вы действительно не можете узнать, какой браузер, настройки шрифта, размер экрана и т. Д. Использует клиент. (Хорошо, иногда заголовки запроса дают указание, но на самом деле ничего непоследовательного или надежного.)

Итак, я бы:

  • отображать образец текста в Internet Explorer с настройками по умолчанию на экране / размер окна 1024x768 (это обычно самый распространенный размер)
  • возьмите среднее число символов / строку с этой конфигурацией и используйте ее для своей оценки.

Обычно я нахожу это "достаточно хорошим", например, для оценки количества строк, которые какой-либо текст займет в браузере, чтобы оценить, сколько объявлений показывать рядом с текстом.

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

2 голосов
/ 29 апреля 2009

Не существует надежного серверного решения для расчета ширины текста. (вне создания изображения текста и, возможно, SVG)

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

Точно не указано, что вы, возможно, захотите обрезать строку (это может быть полезно при нахождении потенциальных решений), но наиболее распространенным является то, что вы хотите отрезать текст в какой-то момент и создать эллипс.

Это можно надежно сделать на многих платформах браузеров с помощью свойства css и NO javascript:

http://www.jide.fr/emulate-text-overflowellipsis-in-firefox-with-css

2 голосов
/ 29 апреля 2009

Для веб-приложения вы не можете (действительно) получить правильную оценку. Разные шрифты имеют разную ширину, поэтому это зависит не только от клиента (браузера) и его настроек масштабирования и DPI, но также от шрифтов, имеющихся на этом компьютере (и в операционной системе), или их замен.

Если вам нужно точное измерение, создайте графическое изображение (растровое изображение, SVG или даже какой-нибудь PDF-файл и т. Д.), Которое будет размещено и отображено на сервере, а не на клиенте.

1 голос
/ 29 апреля 2009

Для хорошего * клиентского решения вы можете попробовать гибридный подход CSS-and-Javascript, предложенный ответом RichieHindle на мой вопрос .

Учитывая, что вы не знаете, каким шрифтом пользователь увидит страницу (они всегда могут переопределить ваш выбор, Ctrl- + страница и т. Д.), «Правильное» место для этого - браузер. Хотя браузеры не делают это легко!

* когда я говорю «приятно», я имею в виду «возможно, хорошо, но я еще не пробовал».

1 голос
/ 29 апреля 2009

На самом деле это попытка встроить некоторые смарты в метод усечения строки [...]

Это действительно стоит усилий? У нас была именно эта проблема. И это было на разных языках. Решением было оставить все как есть. Сложность поддержания этого интеллекта быстро увеличивается (и, вероятно, экспоненциально) с каждым языком, для которого вы добавляете поддержку. Отсюда и наше решение.

[...] алгоритм для оценки и классификации ширины текста (для шрифта переменной ширины) на основе его содержимого?

Большинство библиотек шрифтов предоставят вам эту информацию. Но это довольно низкоуровневые вещи. Основная идея состоит в том, чтобы передать строку и вернуть ширину в точках.

1 голос
/ 29 апреля 2009

Я думаю, вам следует выбрать одно из следующих решений:

  • Точное решение: Суммируйте ширину для каждого символа в строке (большинство API предоставят вам эту информацию)
  • Быстрая оценка: выберите максимальную или минимальную ширину и умножьте ее на количество символов.

Конечно, возможна некоторая смешанная оценка, но я думаю, что это слишком много усилий в неправильном направлении.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...