Graphics.TransformのMatrixの中身を覗いてみる

C# コンピュータ
C#

画像を拡大縮小する方法でワールド変換行列を使う方法があります。
仕組み自体は難しくてよく理解できていないのですが、Grapics.TransformプロパティにセットされているSystem.Drawing.Drawing2D.Matrixオブジェクトのプロパティに値をセットして画像をGraphics.DrawImage()することで拡大縮小することが出来るようです。

今回は、拡大処理と移動処理をすることでMatrixオブジェクトが同変化しているか確認してみたいと思います。

ソース

//
// Graphics.TransformのMatrixの中身を覗いてみる
//
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Text.RegularExpressions;

// コンパイル
// csc /t:xe Matrix.cs

class Form1 : Form {

    Bitmap bmp;

    PictureBox picbox = new PictureBox {
        Dock = DockStyle.Fill,
    };

    // Matrixのプロパティを出力
    static void OutputMatrix(System.Drawing.Drawing2D.Matrix mat) {
        Console.WriteLine("{0}", mat);
        Console.Write("Elements:[");
        foreach(var v in mat.Elements) {
            Console.Write("{0:0.0},", v);
        }
        Console.WriteLine("]");
        Console.WriteLine("IsIdentity:{0}",mat.IsIdentity);
        Console.WriteLine("IsInvertible:{0}",mat.IsInvertible);
        Console.WriteLine("OffsetX:{0}",mat.OffsetX);
        Console.WriteLine("OffsetY:{0}",mat.OffsetY);
        Console.WriteLine("");
    }

    // コンストラクタ
    Form1(){

        bmp = new Bitmap(@"H:\Pictures\202010021053.png");

        picbox.Image = new Bitmap(bmp.Width, bmp.Height);

        // イベント関連
        picbox.MouseDown += (sender, e) => {
            using (var g = Graphics.FromImage(picbox.Image)) {
                var mat = g.Transform;
                
                Console.WriteLine("変換前");
                OutputMatrix(mat);

                Console.WriteLine("拡大");
                mat.Scale(1.0f, 2.0f,   
                        System.Drawing.Drawing2D.MatrixOrder.Append);
                g.Transform = mat;

                // ピクチャボックスのクリア  
                g.Clear(picbox.BackColor);
                // 描画
                g.DrawImage(bmp, 0, 0);
                // 再描画  
                picbox.Refresh();

                OutputMatrix(mat);

                Console.WriteLine("移動");
                mat.Translate(100, 100,   
                        System.Drawing.Drawing2D.MatrixOrder.Append);
                g.Transform = mat;

                // ピクチャボックスのクリア  
                g.Clear(picbox.BackColor);
                // 描画
                g.DrawImage(bmp, 0, 0);
                // 再描画  
                picbox.Refresh();

                OutputMatrix(mat);

                Console.WriteLine("初期値");
                mat = new System.Drawing.Drawing2D.Matrix();
                OutputMatrix(mat);
            }
        };  
        // コントロールの登録
        Controls.Add(picbox);


    }

    // エントリーポイント
    [STAThread]
    static void Main() {
        Application.Run(new Form1());
    }
}

結果

マウスをクリックすると画像が描画されます。

変換前
System.Drawing.Drawing2D.Matrix
Elements:[1.0,0.0,0.0,1.0,0.0,0.0,]
IsIdentity:True
IsInvertible:True
OffsetX:0
OffsetY:0

拡大
System.Drawing.Drawing2D.Matrix
Elements:[1.0,0.0,0.0,2.0,0.0,0.0,]
IsIdentity:False
IsInvertible:True
OffsetX:0
OffsetY:0

移動
System.Drawing.Drawing2D.Matrix
Elements:[1.0,0.0,0.0,2.0,100.0,100.0,]
IsIdentity:False
IsInvertible:True
OffsetX:100
OffsetY:100

初期値
System.Drawing.Drawing2D.Matrix
Elements:[1.0,0.0,0.0,1.0,0.0,0.0,]
IsIdentity:True
IsInvertible:True
OffsetX:0
OffsetY:0

ピクチャーボックスの画像は縦長に引き延ばされ右下に移動して描画されていました。

拡大すると、Elementsの0番目に水平方向の倍率、3番目に垂直方向の倍率がセットされていました。
移動すると、Elementsの4番目と5番目の要素が変化していて、同じ値がOffsetX、OffsetYにセットされていました。
また、System.Drawing.Drawing2D.Matrixをnewで生成した値が、返還前の値と同じでした。

試してみましたがワールド変換行列を使った処理自体は理解できたとはいいがたいのですが、入り口と出口を抑えられたと思います。

コメント