2011年04月09日

メイリオの描画位置がずれる問題の解決方法(クリッピング)(C#)

前回『メイリオの描画位置がずれる問題(C#)』の解決方法です。これはクリッピングによる解決方法です。別の解決方法も→『メイリオの描画位置がずれる問題の解決方法(Transform)(C#)

GraphicsPathにAddStringするときに、あらかじめ座標をずらしておけば良いのですが、Pathの位置を知ることができるのはAddStringした後です。
また、DrawPathでは座標をずらすことはできません。

そこで、一時的に別のImageを作成しておき、そこにテキストを描画しておいてから、テキストの範囲のみをクリッピングして、描画したいImageにコピーする、というやり方をします。
クリッピングのやり方は、以前の記事『画像(イメージ)のトリミング(C#)』と同じです。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // PictureBoxを生成しFormに追加
            PictureBox picture = new PictureBox();
            picture.Width = this.Width;
            picture.Height = this.Height;
            this.Controls.Add(picture);

            // Imageを生成してPictureBoxに割当
            Bitmap image = new Bitmap(this.Width, this.Height);
            picture.Image = image;

            // Imageに描画
            Graphics g = Graphics.FromImage(image);
            g.Clear(Color.Black);

            // アンチエリアス
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;

            // レンダリング品質
            g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;

            // 描画する文字
            string text = "Aaあぁアァ亜宇";

            // メイリオでの描画
            {
                Font font = new Font("メイリオ", 24, FontStyle.Bold);
                Point pos = new Point(20, 20);

                // GraphicsPathの生成
                System.Drawing.Drawing2D.GraphicsPath gp = new System.Drawing.Drawing2D.GraphicsPath();

                // テキストをPathに変換
                gp.AddString(text, font.FontFamily, (int)font.Style, font.SizeInPoints,
                    pos, StringFormat.GenericDefault);

                // ☆別のImageに描画したあと、Imageをトリミングして、対象のImageに描画する
                {
                    // 一時編集用のImageを作成する(文字の縁の分、少し大きめにする)
                    Bitmap tempImage = new Bitmap(
                        (int)(gp.GetBounds().X + gp.GetBounds().Width + 10),
                        (int)(gp.GetBounds().Y + gp.GetBounds().Height + 10));

                    // イメージからGraphicsを取得
                    Graphics tempGraphics = Graphics.FromImage(tempImage);

                    // アンチエリアス
                    tempGraphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;

                    // レンダリング品質
                    tempGraphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;

                    // 文字の縁を描画
                    tempGraphics.DrawPath(new Pen(Brushes.Blue, 3.0f), gp);

                    // 文字を塗る
                    tempGraphics.FillPath(Brushes.White, gp);

                    // Pathに内接する四角形を描画
                    RectangleF rect = gp.GetBounds();
                    tempGraphics.DrawRectangle(Pens.Red, rect.X, rect.Y, rect.Width, rect.Height);

                    // Imageをクリッピングする
                    RectangleF clipRect = new RectangleF(
                        gp.GetBounds().X,
                        gp.GetBounds().Y,
                        gp.GetBounds().Width + 1.0f,
                        gp.GetBounds().Height + 1.0f);
                    tempImage = tempImage.Clone(clipRect, tempImage.PixelFormat);

                    // クリッピングしたImageを描画
                    g.DrawImage(tempImage, pos);

                    // 終了
                    tempImage.Dispose();
                    tempGraphics.Dispose();
                }

                // 描画位置にマーキング
                g.DrawLine(Pens.Pink, pos.X - 20, pos.Y, pos.X + 20, pos.Y);
                g.DrawLine(Pens.Pink, pos.X, pos.Y - 20, pos.X, pos.Y + 20);

                // 終了
                gp.Dispose();
            }

            // MSゴシックでの描画
            {
                Font font = new Font("MS Pゴシック", 24, FontStyle.Bold);
                Point pos = new Point(20, 120);

                // GraphicsPathの生成
                System.Drawing.Drawing2D.GraphicsPath gp = new System.Drawing.Drawing2D.GraphicsPath();

                // テキストをPathに変換
                gp.AddString(text, font.FontFamily, (int)font.Style, font.SizeInPoints,
                    pos, StringFormat.GenericDefault);

                // ☆別のImageに描画したあと、Imageをトリミングして、対象のImageに描画する
                {
                    // 一時編集用のImageを作成する(文字の縁の分、少し大きめにする)
                    Bitmap tempImage = new Bitmap(
                        (int)(gp.GetBounds().X + gp.GetBounds().Width + 10),
                        (int)(gp.GetBounds().Y + gp.GetBounds().Height + 10));

                    // イメージからGraphicsを取得
                    Graphics tempGraphics = Graphics.FromImage(tempImage);

                    // アンチエリアス
                    tempGraphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;

                    // レンダリング品質
                    tempGraphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;

                    // 文字の縁を描画
                    tempGraphics.DrawPath(new Pen(Brushes.Blue, 3.0f), gp);

                    // 文字を塗る
                    tempGraphics.FillPath(Brushes.White, gp);

                    // Pathに内接する四角形を描画
                    RectangleF rect = gp.GetBounds();
                    tempGraphics.DrawRectangle(Pens.Red, rect.X, rect.Y, rect.Width, rect.Height);

                    // Imageをクリッピングする
                    RectangleF clipRect = new RectangleF(
                        gp.GetBounds().X,
                        gp.GetBounds().Y,
                        gp.GetBounds().Width + 1.0f,
                        gp.GetBounds().Height + 1.0f);
                    tempImage = tempImage.Clone(clipRect, tempImage.PixelFormat);

                    // クリッピングしたImageを描画
                    g.DrawImage(tempImage, pos);

                    // 終了
                    tempImage.Dispose();
                    tempGraphics.Dispose();
                }

                // 描画位置にマーキング
                g.DrawLine(Pens.Pink, pos.X - 20, pos.Y, pos.X + 20, pos.Y);
                g.DrawLine(Pens.Pink, pos.X, pos.Y - 20, pos.X, pos.Y + 20);

                // 終了
                gp.Dispose();
            }
        }
    }
}

実行するとこのようになります。
meyrio-2.png
白っぽい十字の線が本来描画させたい位置です。実際に描画されたのが赤い四角形の位置です。
今回は、ずれがなく表示できています。

良かったらクリックしてください
にほんブログ村 IT技術ブログ プログラム・プログラマーへ  人気ブログランキングへ

posted by among at 09:25 | Comment(0) | TrackBack(0) | C#
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

この記事へのトラックバックURL
http://blog.sakura.ne.jp/tb/44114435

この記事へのトラックバック