ここでは、コントロール(フォームを含む)の外観を画像(Imageオブジェクト)としてキャプチャする方法を紹介します。なお、画面全体をキャプチャする方法は、「画面をキャプチャする」で紹介しています。
.NET Framework 2.0からは、ControlクラスにDrawToBitmapメソッドが追加され、これを使ってコントロールをキャプチャすることができます。
この方法では、キャプチャするコントロールの上に別の(子コントロールでない)コントロールがかぶさっていたり、フォームが別のフォームの下にあったりしても、問題なくキャプチャされます。Visibleがfalseであるコントロールでも、キャプチャできます(ただし、TextBoxはだめ)。
このメソッドでは、RichTextBoxでは正常にキャプチャできません(RichTextBoxが配置されているフォームをキャプチャしても、RichTextBoxは正常に描画されません)。WebBrowserクラスなどでも正常にキャプチャできないようです。また、大きなサイズの画像としてはキャプチャできません。その他の制限については、ヘルプの「Control.DrawToBitmap メソッド」をご覧ください。
下の例では、コードの書かれたフォームの外観をキャプチャして、ファイルに保存しています。
'Imports System.Drawing 'コントロールの外観を描画するBitmapの作成 Dim bmp As New Bitmap(Me.Width, Me.Height) 'キャプチャする Me.DrawToBitmap(bmp, New Rectangle(0, 0, Me.Width, Me.Height)) 'ファイルに保存する bmp.Save("C:\test\1.png") '後始末 bmp.Dispose()
//using System.Drawing; //コントロールの外観を描画するBitmapの作成 Bitmap bmp = new Bitmap(this.Width, this.Height); //キャプチャする this.DrawToBitmap(bmp, new Rectangle(0, 0, this.Width, this.Height)); //ファイルに保存する bmp.Save("C:\\test\\1.png"); //後始末 bmp.Dispose();
次にWin32 APIを使用した方法を紹介します。以下に示すCaptureControlメソッドは、指定されたコントロールのクライアント領域をキャプチャして、Bitmapオブジェクトとして返します。
この方法では、前述したControl.DrawToBitmapメソッドによる方法と違い、キャプチャするフォームやコントロールが別のフォームなどで隠れていると、正常にキャプチャされません(画面で見たままの状態でキャプチャされます)。
'Imports System.Drawing <System.Runtime.InteropServices.DllImport("gdi32.dll")> _ Private Shared Function BitBlt(ByVal hdcDest As IntPtr, _ ByVal nXDest As Integer, ByVal nYDest As Integer, _ ByVal nWidth As Integer, ByVal nHeight As Integer, _ ByVal hdcSrc As IntPtr, _ ByVal nXSrc As Integer, ByVal nYSrc As Integer, _ ByVal dwRop As Integer) As Boolean End Function Private Const SRCCOPY As Integer = &HCC0020 'フォームのイメージを取得する Public Function CaptureControl(ByVal ctrl As Control) As Bitmap Dim g As Graphics = ctrl.CreateGraphics() Dim img As New Bitmap(ctrl.ClientRectangle.Width, _ ctrl.ClientRectangle.Height, g) Dim memg As Graphics = Graphics.FromImage(img) Dim dc1 As IntPtr = g.GetHdc() Dim dc2 As IntPtr = memg.GetHdc() BitBlt(dc2, 0, 0, img.Width, img.Height, dc1, 0, 0, SRCCOPY) g.ReleaseHdc(dc1) memg.ReleaseHdc(dc2) memg.Dispose() g.Dispose() Return img End Function Private Sub Button1_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles Button1.Click 'コントロールの外観を描画するBitmapの作成 Dim bmp As Bitmap = CaptureControl(Me) 'キャプチャする bmp.Save("C:\test\1.png") '後始末 bmp.Dispose() End Sub
//using System.Drawing; [System.Runtime.InteropServices.DllImport("gdi32.dll")] private static extern bool BitBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, int dwRop); private const int SRCCOPY = 0xCC0020; /// <summary> /// コントロールのイメージを取得する /// </summary> /// <param name="ctrl">キャプチャするコントロール</param> /// <returns>取得できたイメージ</returns> public Bitmap CaptureControl(Control ctrl) { Graphics g = ctrl.CreateGraphics(); Bitmap img = new Bitmap(ctrl.ClientRectangle.Width, ctrl.ClientRectangle.Height, g); Graphics memg = Graphics.FromImage(img); IntPtr dc1 = g.GetHdc(); IntPtr dc2 = memg.GetHdc(); BitBlt(dc2, 0, 0, img.Width, img.Height, dc1, 0, 0, SRCCOPY); g.ReleaseHdc(dc1); memg.ReleaseHdc(dc2); memg.Dispose(); g.Dispose(); return img; } //Button1のClickイベントハンドラ private void Button1_Click(object sender, EventArgs e) { //コントロールの外観を描画するBitmapの作成 Bitmap bmp = CaptureControl(this); //キャプチャする bmp.Save("C:\\test\\1.png"); //後始末 bmp.Dispose(); }
Windows XP以上であれば、PrintWindow関数を使ってキャプチャすることもできます。この場合は、キャプチャするフォームやコントロールが別のフォームなどの隠れていても、きちんとキャプチャできます。
<System.Runtime.InteropServices.DllImport("User32.dll")> _ Private Shared Function PrintWindow(ByVal hwnd As IntPtr, _ ByVal hDC As IntPtr, ByVal nFlags As Integer) As Boolean End Function ''' <summary> ''' コントロールのイメージを取得する ''' </summary> ''' <param name="ctrl">キャプチャするコントロール</param> ''' <returns>取得できたイメージ</returns> Public Function CaptureControl(ByVal ctrl As Control) As Bitmap Dim img As New Bitmap(ctrl.Width, ctrl.Height) Dim memg As Graphics = Graphics.FromImage(img) Dim dc As IntPtr = memg.GetHdc() PrintWindow(ctrl.Handle, dc, 0) memg.ReleaseHdc(dc) memg.Dispose() Return img End Function
[System.Runtime.InteropServices.DllImport("User32.dll")] private extern static bool PrintWindow(IntPtr hwnd, IntPtr hDC, uint nFlags); /// <summary> /// コントロールのイメージを取得する /// </summary> /// <param name="ctrl">キャプチャするコントロール</param> /// <returns>取得できたイメージ</returns> public Bitmap CaptureControl(Control ctrl) { Bitmap img = new Bitmap(ctrl.Width, ctrl.Height); Graphics memg = Graphics.FromImage(img); IntPtr dc = memg.GetHdc(); PrintWindow(ctrl.Handle, dc, 0); memg.ReleaseHdc(dc); memg.Dispose(); return img; }
InvokePaintメソッド、及びInvokePaintBackgroundメソッドを使ってPictureBoxに表示されている画像を取得する方法を紹介します。この方法で取得できる画像は、PictureBoxのPaintイベント、及びPaintBackgroundイベントでPaintEventArgs.Graphicsに描画された画像だけです。具体的には、PictureBoxのImageプロパティ、BackGroundImageプロパティ、BackColorプロパティで指定された画像や、PaintイベントハンドラでPaintEventArgs.Graphicsを使って描画された画像などに限られます。
以下に、この方法によりPictureBox(PictureBox1)に表示されている画像を画像ファイルに保存する方法を示します。このコードは、PictureBox1のあるフォームクラスに書かれているものとします。
'Imports System.Drawing 'PictureBox1の大きさを取得 Dim rect As Rectangle = PictureBox1.ClientRectangle 'PictureBox1に表示されている画像を取得するためのBitmap Dim bmp As New Bitmap(rect.Width, rect.Height) 'bmpに画像を入れるための準備 Dim g As Graphics = Graphics.FromImage(bmp) Dim pea As New PaintEventArgs(g, rect) 'PaintBackgroundイベントを発生 Me.InvokePaintBackground(PictureBox1, pea) 'Paintイベントを発生 Me.InvokePaint(PictureBox1, pea) '画像を保存する bmp.Save("C:\test.png") '後始末 g.Dispose() bmp.Dispose()
//using System.Drawing; //PictureBox1の大きさを取得 Rectangle rect = PictureBox1.ClientRectangle; //PictureBox1に表示されている画像を取得するためのBitmap Bitmap bmp = new Bitmap(rect.Width, rect.Height); //bmpに画像を入れるための準備 Graphics g = Graphics.FromImage(bmp); PaintEventArgs pea = new PaintEventArgs(g, rect); //PaintBackgroundイベントを発生 this.InvokePaintBackground(PictureBox1, pea); //Paintイベントを発生 this.InvokePaint(PictureBox1, pea); //画像を保存する bmp.Save(@"C:\test.png"); //後始末 g.Dispose(); bmp.Dispose();
この方法により外見を画像として取得できるコントロールは、あまりありません。PictureBox以外に、Label、Button、DataGridコントロール等でうまく行くようですが、FlatStyleプロパティがSystemの時は失敗します。
フォームをキャプチャする方法として、フォームをアクティブにしてから、Alt+PrintScreenキーストロークを送信する方法も考えられます。これについては、「画面をキャプチャする」をご覧ください。
(この記事は、「.NETプログラミング研究 第46号」で紹介したものを基にしています。)
注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。