Quantcast
Channel: C#タグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 8895

C# - フォントメトリクスを調査してみたらカオスだった件 - 未解決

$
0
0

混乱した結果、記事も空中分解気味になってしまったが、とりあえず投稿してみる。

経緯

下記みたいな感じでStringFormatでセンタリング指定してDrawStringしても縦位置がずれるので、調べてみた。

var sf = new StringFormat();
sf.Alignment = StringAlignment.Center; // 横中央
sf.LineAlignment = StringAlignment.Center; // 縦中央 ・・・ にならない(?)

g.DrawString(text, font, Brushes.Black, new Point(Width/2,Height/2), sf);

gとかqとかの下にはみ出る文字の影響と推測。
参考サイト フォント メトリックを取得する - Microsoft Docs から抜粋:

image.png

Descentの分だけ上に寄っているとすれば、Descentの半分だけY座標を足して描画すれば大体中央に来そう。

謎#1

上記の参考サイトはSizeを使っているが、Heightを使わないと何故か位置が合わない。(?)

descentPixel = font.Size * descent / fontFamily.GetEmHeight(FontStyle.Regular);

いろんなフォントを描画してみる

AscentとHeightの位置に横線を描画してみる。
コード抜粋

    FontFamily ff = font.FontFamily;
    int ascent = ff.GetCellAscent(font.Style);
    int emHeight = ff.GetEmHeight(font.Style);

    // 下記の各Y座標(pixel単位)で横線を引いてみた
    float fontHeight = font.GetHeight(g); // g: 描画に使用するGraphicsクラス
    float ascentHeight  = fontHeight * ascent  / emHeight;

システムのデフォルトフォント

それっぽい(※ドキュメントがよく分からないため根拠がない)

image.png

ビルマ文字(なぜか、はみ出る)

Font.GetHeightがやたら大きい値になったので、縦長の文字を探して色々やってたらビルマ文字1にたどり着いた。なぜかはみ出る。

image.png

ソースコード

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Windows.Forms;

class FontMetricsTest : Form
{
    TrackBar   trackbar;
    PictureBox pct;
    ComboBox   cmbFonts;
    TextBox    txtContent;

    FontMetricsTest()
    {
        Text = "Font metrics test";
        ClientSize = new Size(600, 400);

        cmbFonts = new ComboBox();
        foreach (FontFamily ff in FontFamily.Families) {
            cmbFonts.Items.Add(ff.Name);
        }
        cmbFonts.Text = SystemFonts.DefaultFont.Name;
        cmbFonts.Location = new Point(0,0);
        cmbFonts.Width = 300;
        cmbFonts.DropDownHeight = 500;
        cmbFonts.DropDownStyle = ComboBoxStyle.DropDownList;
        cmbFonts.SelectedIndexChanged += (sender,e)=>{MyRedraw();};
        Controls.Add(cmbFonts);

        trackbar = new TrackBar();
        trackbar.Location = new Point(300,0);
        trackbar.Maximum = 100;
        trackbar.Value   = 50;
        trackbar.Minimum = 1;
        trackbar.TickFrequency = 33;
        trackbar.ValueChanged += (sender,e)=>{MyRedraw();};
        Controls.Add(trackbar);

        txtContent = new TextBox();
        txtContent.Location = new Point(0, 50);
        txtContent.Width = 300;
        txtContent.Text = "g あいう Qiita";
        txtContent.TextChanged += (sender,e)=>{MyRedraw();};
        Controls.Add(txtContent);

        pct = new PictureBox();
        pct.Location = new Point(0, 80);
        pct.Size = new Size(600, 300);
        pct.Image = new Bitmap(600,300);
        Controls.Add(pct);

        MyRedraw();
    }

    void MyRedraw()
    {
        int w = pct.Image.Width;
        int h = pct.Image.Height;

        string fontName = cmbFonts.Text;
        Font font = new Font(fontName, (float)trackbar.Value);

        string text = txtContent.Text;
        if (font.Name != fontName) {
            text = "Font unmatch: \"" + font.Name + "\" is loaded.";
        }

        using ( Graphics g = Graphics.FromImage(pct.Image) ) {
            g.Clear(Color.Black);

            FontFamily ff = font.FontFamily;

            int ascent = ff.GetCellAscent(font.Style);
            int descent = ff.GetCellDescent(font.Style);
            int emHeight = ff.GetEmHeight(font.Style);

            float fontHeight = font.GetHeight(g);
            float ascentHeight  = fontHeight * ascent  / emHeight;
//          float ascentSize    = font.Size  * ascent  / emHeight;

            Console.Write("==== "); Console.Write(font.Name); Console.WriteLine(" ====");
            Console.Write("font.Size: ");  Console.WriteLine(font.Size);
            Console.Write("fontHeight: "); Console.WriteLine(fontHeight);
            Console.Write("ascent: ");     Console.WriteLine(ascent);
            Console.Write("descent: ");    Console.WriteLine(descent);
            Console.Write("sum: ");        Console.WriteLine(ascent+descent);
            Console.Write("emHeight: ");   Console.WriteLine(emHeight);

            Pen pen = new Pen(Color.LightGray, 1.0f);
//          Pen penDash = new Pen(Color.LightGray, 1.0f);
//          penDash.DashStyle = DashStyle.Dash;
            g.DrawLine(pen,     0, fontHeight, w, fontHeight);
            g.DrawLine(pen,     0, ascentHeight, w, ascentHeight);
//          g.DrawLine(penDash, 0, font.Size, w, font.Size);
//          g.DrawLine(penDash, 0, ascentSize, w, ascentSize);

            g.DrawString(text, font, Brushes.White, new PointF(0,0));
        }

        pct.Refresh();
    }

    static void DumpSystemFontNames()
    {
        var dict = new Dictionary<string,Font>() {
            {"CaptionFont      " , SystemFonts.CaptionFont     },
            {"DefaultFont      " , SystemFonts.DefaultFont     },
            {"DialogFont       " , SystemFonts.DialogFont      },
            {"IconTitleFont    " , SystemFonts.IconTitleFont   },
            {"MenuFont         " , SystemFonts.MenuFont        },
            {"MessageBoxFont   " , SystemFonts.MessageBoxFont  },
            {"SmallCaptionFont " , SystemFonts.SmallCaptionFont},
            {"StatusFont       " , SystemFonts.StatusFont      }
        };

        foreach (var pair in dict) {
            Console.Write(pair.Key);
            Console.Write(",");
            Console.Write(pair.Value.Size);
            Console.Write(",");
            Console.WriteLine(pair.Value.Name);
        }
    }

    [STAThread]
    static void Main(string[] args)
    {
        // DumpSystemFontNames();
        Application.Run(new FontMetricsTest());
    }
}

結論

色々やってみたが、結局わからん・・・
実験してみるとFont.Size≠描画の高さだし、
Font.Height=行間、とドキュメントからは読み取ったけど、はみ出るケースもあるし、、

特定の文字列を中央表示したいなら、Graphics.MeasureStringとかを使って、描画する文字列に応じて調整するほうがよいかもしれない。

参考サイト

そのた

調べてる最中にSystem.Windows.MediaのほうのFontFamilyに迷い込んだりしたが別モノと思われる。


  1. 文字はwikipediaからのコピペ。 


Viewing all articles
Browse latest Browse all 8895

Trending Articles