Дробные размеры шрифта html5 canvas?

У меня проблема с тем, как разные браузеры отображают размеры шрифтов на холсте HTML5. Разработан, где размер шрифта не являются целыми числами. Например "8.5 px Arial", "2.23 em Arial" и так далее.

для холста.font= FontSize + "px Arial"; где FontSize (8.1, 8.2, 8.3,...) Я ожидал бы линейного результата, однако единственный браузер, который последовательно архивирует это IE ! ( Я знаю ). В Firefox туров ниже 11.2 px а линейная дальше. Только Chrome и Safari масштабируйте шрифты до целочисленных значений.

правило округления, похоже, установлено в пиксели и округляется до ближайшего целого числа ниже .5

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

браузеры, по крайней мере, согласованы в поведении между размерами шрифтов pt, px, em и%. [edit: кроме Safari не отображает размеры%]

[ в сторону: все шрифты выглядят немного полужирными, когда они немного увеличены. Safari берет этот торт, когда мы идем от 17.4 px до 17.5 px .. БЭМБ!]

Я приложил несколько примеров изображений ниже, но мне бы очень хотелось, чтобы некоторые идеи о том, как сделать все браузеры более похожими на IE (снова никогда не думал, что скажу это) - это ошибка или стандартных шрифтов?

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

<!DOCTYPE html><html><head><script>
function display() {
    var canvas = document.getElementById('test');
    // For EM and % cases....
    //canvas.style.font="5px Arial";
    canvas.height = 1000;
    var context = canvas.getContext('2d');
    var minSize = 10;
    var lineHeight = 100;
    for(var a=minSize; a< 20; a+=0.1)
    {
        var font_size =  Math.round(a*10000)/10000;
        context.font = a + "px Arial";
        context.fillText("A: EXAMPLE TEXT > " +  font_size, 20, (font_size-minSize)*lineHeight);
    }
}
</script></head><body onload="display()"><canvas id="test"></canvas></body></html>

шкала пиксель pixel scale Точечная шкала point scale шкала em-1em = 5px Arial em scale процентная шкала-100% = 5px Arial percent scale

1 ответов


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

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

Так для пример.

var zoom = 1.02;
var font_size = 12;
context.font = (font_size * zoom) + "px Arial"; // 12.24px

zoom = 1.04 (12.48 px) будет отображаться так же, как и приведенный выше код, а zoom =1.06 (12.75 px) будет округлен до 13px.

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

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

в решение

во время инициализации визуализируйте текст со стандартным размером шрифта (zoom=1) и измерьте длину строки, пусть это значение будет называться iniLineLength

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

tmpContext.font = (font_size * zoom) + "px Arial";
tmpContext.fillText(MyLineOfText,0, 0); 
var s = (iniLineLength * zoom) / tmpContext.measureText(MyLineOfText) ;
mainContext.drawImage(tmpCanvas,x, y, pw * s, ph);

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

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

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

вопросы

даже при нормализованной длине линии точное положение каждого символа в строке не совпадает. Давая эффект на изображении ниже.

enter image description here

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

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

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