none
Graphicsで文字列を回転して表示させるには? RRS feed

  • 質問

  • Visual Studio 2017 .Net 4.7.2 Windows 10

    上記の環境にて、Graphicsに文字列を縦書きしたいと考えています。

    インターネットで調べた結果、以下の関数を使用すると回転して書くことができるところまではわかりましたが、

    90度で描画したときと270度で描画した場合で、文字の太さが違うように見えます。

    文字の太さなどはすべて統一されて回転して描画するにはどうしたらよいでしょうか?

    できればば背景には別のイメージが描画しているため、背景と同じビットマップ(Image)で描画したいと考えています。

    よろしくお願いします。

    以下、確認したサンプル

    float x = 100; float y = 100;

    // g = graphics

    g.TranslateTransform(x , y); g.RotateTransform(90); g.DrawString("ああああ", new Font("MS ゴシック", 11), new SolidBrush(Color.Red), 0, 0); g.ResetTransform();


    2019年6月5日 7:51

回答

  • TextRenderingHint プロパティの値を、AntiAlias 等に変更してみてください。

    既定値は SystemDefault ですが、この場合、既定では ClearTypeGridFit 相当でレンダリングされます。
    (OS 側で ClearType を無効にしていた場合は、元のコードのままでも大丈夫かも)

    ClearType

    それと、new Font や new SolidBrush も Dispose 対象ですね。

    g.DrawString("ああああ", new Font("MS ゴシック", 11), new SolidBrush(Color.Red), 0, 0);

    • 回答としてマーク mogja 2019年6月6日 6:02
    2019年6月6日 4:37

すべての返信

  • 錯覚だったりしませんか?

    座標指定がビットマップのピクセルに対して整数ではなかったり、GraphicsのCompositingMode,CompositingQuality,InterpolationMode,PixelOffsetMode,SmoothingModeプロパティなどの影響でアンチエイリアスが効いていて太さが違って見えることは有り得そうですが。

    namespace WindowsFormsApp1
    {
        using System;
        using System.Collections.Generic;
        using System.Drawing;
        using System.Windows.Forms;
    
        public partial class Form1 : Form
        {
            public Form1()
            {
                this.Width = 800;
                this.Height = 300;
    
                TableLayoutPanel table = new TableLayoutPanel();
                table.ColumnCount = 3;
                table.ColumnStyles.Add(new ColumnStyle(SizeType.Percent) { Width = 33.3f });
                table.ColumnStyles.Add(new ColumnStyle(SizeType.Percent) { Width = 33.3f });
                table.ColumnStyles.Add(new ColumnStyle(SizeType.Percent) { Width = 33.3f });
                table.Dock = DockStyle.Fill;
                List<PictureBox> pictreBoxies = new List<PictureBox>();
    
                this.Controls.Add(table);
                for (int i = 0; i < 3; i++)
                {
                    PictureBox pb = new PictureBox();
    
                    pb.BackColor = Color.White;
                    pb.BorderStyle = BorderStyle.FixedSingle;
                    pb.SizeMode = PictureBoxSizeMode.AutoSize;
                    table.SetColumn(pb, i);
                    table.Controls.Add(pb);
                    pictreBoxies.Add(pb);
                }
    
                //ビットマップを3枚用意
                List<Bitmap> bitmaps = new List<Bitmap>();
                for (int i = 0; i <= 2; i++)
                {
                    bitmaps.Add(new Bitmap(200, 200));
                }
    
                //90度と270度で描く
                for (int i = 1, r = 90; i <= 2; i++, r += 180)
                {
                    using (Graphics g = Graphics.FromImage(bitmaps[i]))
                    {
                        float x = 100f;
                        float y = 100f;
    
                        g.TranslateTransform(x, y);
                        g.RotateTransform(r);
                        g.DrawString("ああああ", new Font("MS ゴシック", 11), new SolidBrush(Color.Red), 0, 0);
                        g.ResetTransform();
                    }
    
                    pictreBoxies[i].Image = bitmaps[i];
                }
    
                //1ピクセルずつ比較して違いがあるピクセルを探す
                bool found = false;
                for (int x = 0; x < 200; x++)
                {
                    for (int y = 0; y < 200; y++)
                    {
                        Color c1 = bitmaps[1].GetPixel(x, y);
                        Color c2 = bitmaps[2].GetPixel(199 - x, 199 - y);
                        if (c1 != c2)
                        {
                            //違いあり
                            bitmaps[0].SetPixel(x, y, Color.Red);
                            System.Diagnostics.Debug.WriteLine("{0},{1}", x, y);
                            found = true;
                        }
                        else
                        {
                            //違いなし
                            bitmaps[0].SetPixel(x, y, Color.Green);
                        }
                    }
                }
                pictreBoxies[0].Image = bitmaps[0];
    
                this.Text = found ? "違いがありました" : "違いが見つかりませんでした";
            }
        }
    }

    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    2019年6月5日 9:47
  • gekka様ありがとうございます。

    錯覚ではないと思います。サンプルコードありがとうございます。

    描画した際の画像を添付します。

    >>CompositingMode,CompositingQuality,InterpolationMode,PixelOffsetMode,SmoothingModeプロパティ

    この辺の兼ね合いがあるのかもしれません。

    90度(左側)で描画すると太くなる次第です。

                Bitmap bitmap90 = new Bitmap(pictureBox1.Width, pictureBox1.Height);
                Bitmap bitmap270 = new Bitmap(pictureBox2.Width, pictureBox2.Height);
    
                float x = 100.0f;
                float y = 100.0f;
    
                using (Graphics g = Graphics.FromImage(bitmap90))
                {
                    g.TranslateTransform(x, y);
                    g.RotateTransform(90);
                    g.DrawString("ああああ", new Font("MS ゴシック", 11), new SolidBrush(Color.Red), 0, 0);
                    g.ResetTransform();
                }
                pictureBox1.Image = bitmap90;
    
    
                using (Graphics g = Graphics.FromImage(bitmap270))
                {
                    g.TranslateTransform(x, y);
                    g.RotateTransform(270);
                    g.DrawString("ああああ", new Font("MS ゴシック", 11), new SolidBrush(Color.Red), 0, 0);
                    g.ResetTransform();
                }
                pictureBox2.Image = bitmap270;
    プロパティ系は特に指定はしていません。

    以上、よろしくお願いします。

    2019年6月6日 1:06
  • TextRenderingHint プロパティの値を、AntiAlias 等に変更してみてください。

    既定値は SystemDefault ですが、この場合、既定では ClearTypeGridFit 相当でレンダリングされます。
    (OS 側で ClearType を無効にしていた場合は、元のコードのままでも大丈夫かも)

    ClearType

    それと、new Font や new SolidBrush も Dispose 対象ですね。

    g.DrawString("ああああ", new Font("MS ゴシック", 11), new SolidBrush(Color.Red), 0, 0);

    • 回答としてマーク mogja 2019年6月6日 6:02
    2019年6月6日 4:37
  • 魔界の仮面弁士

    サンプルありがとうございます。

    SingleBitPerPixelGridFitを指定することにより、270度と同じ見た目で描画することができました。

    ありがとうございました。

    2019年6月6日 6:02
  • 魔界の仮面弁士

    サンプルありがとうございます。

    いえ、サンプルは掲載していませんでしたが…折角書いてあったので投稿しておきますね。

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
    
            comboBox1.DropDownStyle = ComboBoxStyle.DropDownList;
            comboBox1.DataSource = Enum.GetValues(typeof(TextRenderingHint));
            comboBox1.SelectedIndex = -1;
            comboBox1.SelectedIndexChanged += delegate
            {
                if (comboBox1.SelectedIndex < 0) { return; }
                TextRenderingHint trh = (TextRenderingHint)comboBox1.SelectedItem;
    
                Bitmap bitmap90 = new Bitmap(pictureBox1.Width, pictureBox1.Height);
                Bitmap bitmap270 = new Bitmap(pictureBox2.Width, pictureBox2.Height);
    
                float x = 100.0f;
                float y = 100.0f;
    
                using (var f = new Font("MS ゴシック", 11F))  // ☆
                using (var b = new SolidBrush(Color.Red))  // ☆
                using (Graphics g1 = Graphics.FromImage(bitmap90))
                using (Graphics g2 = Graphics.FromImage(bitmap270))
                {
                    g1.TextRenderingHint = trh;  // ★
                    g1.TranslateTransform(x, y);
                    g1.RotateTransform(90);
                    g1.DrawString("ああああ", f, b, 0, 0);
                    g1.ResetTransform();
    
                    g2.TextRenderingHint = trh;  // ★
                    g2.TranslateTransform(x, y);
                    g2.RotateTransform(270);
                    g2.DrawString("ああああ", f, b, 0, 0);
                    g2.ResetTransform();
                }
                var oldImg1 = pictureBox1.Image;
                var oldImg2 = pictureBox2.Image;
                pictureBox1.Image = bitmap90;
                pictureBox2.Image = bitmap270;
                if (oldImg1 != null) { oldImg1.Dispose(); }
                if (oldImg2 != null) { oldImg2.Dispose(); }
            };
            comboBox1.SelectedItem = TextRenderingHint.SystemDefault;
        }
    }

    2019年6月6日 6:39