10

さまざまなブラウザーが HTML5 Canvas でフォント サイズをレンダリングする方法に問題があります。特に、フォント サイズが整数でない場合。たとえば、「8.5px Arial」、「2.23em Arial」などです。

canvas.font= FontSize + "px Arial"; の場合 ここで、FontSize は (8.1、8.2、8.3、...) です。線形の結果が期待されますが、これを一貫してアーカイブする唯一のブラウザーは IE です! ( 知っている )。Firefox は 11.2 ピクセル未満で四捨五入しますが、それ以上は線形です。Chrome と Safari は、フォントを整数値にのみスケーリングします。

丸めルールはピクセルに設定されているようで、.5 未満の最も近い整数に丸められます

私のキャンバスアプリは、いくつかのプログラムによるアニメーション化された変換(スケールと変換)を実行しています効率のためにキャンバス変換を回避しようとしていますが、それで問題が解決すると思われますが、CSS3だけでhtmlテキストサイズを設定してこれをテストしていません( Canvas.font は仕様に基づいていると想定されます)

ブラウザーは、pt、px、em、% のフォント サイズ間で少なくとも一貫した動作をします。[編集: Safari が % サイズをレンダリングしないことを除いて]

[余談: すべてのフォントは、少し大きくすると少し太字に見えます。Safari は、17.4px から 17.5px になるとそのケーキを受け取ります.. BAMB!]

以下にいくつかのサンプル画像を添付しましたが、すべてのブラウザーを 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>

ピクセル スケール ピクセルスケール ポイント スケール ポイントスケール em スケール - 1em = 5px Arial emスケール パーセント スケール - 100% = 5px Arial パーセント目盛り

4

1 に答える 1

6

私はあなたが私のために私の仕事をすることになっていると思っていました ;) とにかく、これは私が問題をどのように解決したかです.

要約すると(おそらく質問では明確ではなかったため)、フォントサイズに浮動小数点数を掛けてテキストを拡大および縮小しようとしていました。しかし、ほとんどの場合、フォント サイズが最も近い整数値に丸められるため、不安定な結果になりました。

たとえば。

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

zoom = 1.04 (12.48px) は上記のコードと同じようにレンダリングされますが、zoom =1.06 (12.75px) は 13px に切り上げられます。

これにより、キャンバス上の他のすべての要素が正しくスケーリングされているにもかかわらず、値の間でフォント サイズが非常に望ましくないジャンプをすることになりました。

この問題は、すべてのブラウザーが "EXAMPLE TEXT" のような特定のテキスト文字列をレンダリングし、長さがわずかに異なるという事実によって悪化しました。

ソリューション

初期化中にテキストを標準フォント サイズ (ズーム = 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 は常に 1 に等しくなります。予想される行の長さは、サンプルの行の長さ iniLineLength に、このレンダリング パスのフォント サイズと同じ倍率を掛けたものです。

これには、ブラウザの動作のすべての違いを正規化する効果があるという利点があります...ほぼ。

問題

行の長さが正規化されていても、行内の各文字の正確な位置は同じではありません。下の画像に効果を与えます。

ここに画像の説明を入力

しかし、これはすでに私が持っていたものよりも大幅に改善されています.

さらに、tmpCanvas を mainCanvas にクリップしたい場合があります。そうしないと、1 文字をフルスクリーンにするためだけに、メガピクセルに相当するテキストを作成およびコピーしようとするため、ブラウザが停止します。

それを念頭に置いて、レンダリングするテキストの実際の行に合わせて、必要に応じて tmp キャンバスの幅と高さを設定することもできます。これにより、メモリや時間などを節約できます。

于 2013-03-17T11:09:51.027 に答える