Математическая логика для изменения размера шрифта - PullRequest
1 голос
/ 27 июня 2010

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

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

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

какую формулу я должен использовать, чтобы размер шрифта заполнял синий контейнер?

здесьмои цифры:

Content height:  342.46
Content/Container Width:  400
Font Size:  11
Line Height:  11 * 1.2 //120% of the font size gives the line height
Number of Lines:  24
Number of Words:  2055

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

альтернативный текст http://www.freeimagehosting.net/uploads/c1a4f77c5f.jpg

Ответы [ 4 ]

1 голос
/ 27 июня 2010

В системе набора текста TeX эта проблема обычно решается с помощью простого алгоритма деления пополам (представленного, например, Кнутом в TeXbook), здесь, в псевдопифоне:

def findsize:
    maxsize=100pt
    minsize=8pt
    epsilon=0.5pt
    while (maxsize-minsize>epsilon):
        triedsize=(maxsize+minsize)/2
        setfontsize(triedsize)
        if boxisoverfull():
            maxsize=triedsize
        else:
            minsize=triedsize
    return minsize

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

Проблема в том, что веб-браузер, вероятно, будет перерисовывать каждую попытку, поэтому это может быть медленным. Вы можете преодолеть это, сделав окно исчезнет (например, дисплей: нет) на время вычислений. Я помню, я делал это один раз, и это работало даже в IE6.

1 голос
/ 27 июня 2010

Я не думаю, что есть идеальное решение этой проблемы.

По сути, количество «потерянного» пространства в конце каждой строки и абзаца очень сильно зависит от рассматриваемого текста. Ширина символов и кернинг вызывают незначительные различия в среднем (но основные различия в худшем случае).

Итак, вы должны пойти по некоторой эвристике. Если возможно, попросите ли вы программное обеспечение «угадать» размер шрифта, проверьте, подходит ли текст или нет (как это делается, зависит от того, какой язык / API вы используете), и, если нет, немного увеличьте или уменьшите.

Вот возможная эвристика:

#numBreaks is the number of line breaks in the text
#numChars is the number of chars (excluding breaks) in the text
#avgCharWidth and lineHeight (pixels) are derived from font size

#avgWrapWidth is the width of the container minus a bit to
#account for the wasted space on the right. I would suggest:
#avgWrapWidth = realWidth - avgCharWidth * 6

totalLength = numChars * avgCharWidth
numLines = totalLength / avgWrapWidth + numBreaks
textHeight = numLines * lineHeight

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

1 голос
/ 27 июня 2010

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

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

Однако давайтеотложите в сторону точность и вместо этого рассмотрите упрощенную модель, которая может помочь вам в правильном подходе.

Доступная область width * height.Для данного фрагмента текста данного length мы хотим определить подходящий fontsize такой, чтобы обернутая высота текста была близка к height.

В настоящее время давайте просто приглушимпо всем деталям единиц и капризов текстового содержимого и представьте, что мы можем вычислить общий размер текста из length и fontsize:

textWidth = A * fontsize * length
lineHeight = B * fontsize

, где A и B некоторые константы масштабирования.(B должно быть легко рассчитать, и на самом деле его значение равно 1,2. A немного сложнее и зависит от того, как вы выберете для измерения length, например, как количество символов, или число, или слова. Однако вы делаетеэто, A может быть только приблизительным, но если вы имеете дело с разумным количеством текста с хорошим поведением, аппроксимация может быть довольно хорошей.)

Тогда область, занимаемая текстом:

textArea = A * fontsize * length * B * fontsize
    = A * B * length * fontsize ^ 2

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

fontsize <= sqrt(width * height/(A * B * length))

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

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

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

1 голос
/ 27 июня 2010

Все становится намного проще, если вы можете использовать шрифт фиксированной ширины. Тогда такие факторы, как: кернинг, разная ширина символов и т. Д., Исчезают.

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

Быстрая и грязная схема, которая должна быть достаточно хорошей, может быть:

  1. Добавить <span id="CanYouSeeMe">.</span> в конец текста.

  2. Измерение смещения пролета (SpanOffset) относительно высоты контейнера (ContainerHeight).

  3. Установите размер шрифта (FS) на: FS *= ContainerHeight / SpanOffset;

  4. Измерьте новое SpanOffset.

  5. Если SpanOffset все еще меньше, чем ContainerHeight, увеличьте FS небольшим шагом в цикле, пока SpanOffset просто не покинет контейнер, а затем сделайте резервную копию с шагом 1.

  6. Аналогично, если SpanOffset был за пределами ContainerHeight, уменьшите FS с небольшим шагом в цикле, пока SpanOffset просто не войдет в контейнер.

...