DOBON.NET プログラミング道: .NET Framework, VB.NET, C#, Visual Basic, Visual Studio, インストーラ, ...

フォームやコントロールの外観をキャプチャする

ここでは、コントロール(フォームを含む)の外観を画像(Imageオブジェクト)としてキャプチャする方法を紹介します。なお、画面全体をキャプチャする方法は、「画面をキャプチャする」で紹介しています。

.NET Framework 2.0以降で、Control.DrawToBitmapメソッドを使用する方法

.NET Framework 2.0からは、ControlクラスにDrawToBitmapメソッドが追加され、これを使ってコントロールをキャプチャすることができます。

この方法では、キャプチャするコントロールの上に別の(子コントロールでない)コントロールがかぶさっていたり、フォームが別のフォームの下にあったりしても、問題なくキャプチャされます。Visibleがfalseであるコントロールでも、キャプチャできます(ただし、TextBoxはだめ)。

このメソッドでは、RichTextBoxでは正常にキャプチャできません(RichTextBoxが配置されているフォームをキャプチャしても、RichTextBoxは正常に描画されません)。WebBrowserクラスなどでも正常にキャプチャできないようです。また、大きなサイズの画像としてはキャプチャできません。その他の制限については、ヘルプの「Control.DrawToBitmap メソッド」をご覧ください。

下の例では、コードの書かれたフォームの外観をキャプチャして、ファイルに保存しています。

VB.NET
コードを隠すコードを選択
'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()
C#
コードを隠すコードを選択
//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を使用した方法

次にWin32 APIを使用した方法を紹介します。以下に示すCaptureControlメソッドは、指定されたコントロールのクライアント領域をキャプチャして、Bitmapオブジェクトとして返します。

この方法では、前述したControl.DrawToBitmapメソッドによる方法と違い、キャプチャするフォームやコントロールが別のフォームなどで隠れていると、正常にキャプチャされません(画面で見たままの状態でキャプチャされます)。

VB.NET
コードを隠すコードを選択
'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
C#
コードを隠すコードを選択
//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();
}

PrintWindow関数

Windows XP以上であれば、PrintWindow関数を使ってキャプチャすることもできます。この場合は、キャプチャするフォームやコントロールが別のフォームなどの隠れていても、きちんとキャプチャできます。

VB.NET
コードを隠すコードを選択
<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
C#
コードを隠すコードを選択
[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のあるフォームクラスに書かれているものとします。

VB.NET
コードを隠すコードを選択
'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()
C#
コードを隠すコードを選択
//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の時は失敗します。

Print Screenキーでキャプチャする方法

フォームをキャプチャする方法として、フォームをアクティブにしてから、Alt+PrintScreenキーストロークを送信する方法も考えられます。これについては、「画面をキャプチャする」をご覧ください。

  • 履歴:
  • 2007/11/13 タイトルを変更。Control.DrawToBitmapメソッドを使用する方法、Win32 APIを使用した方法、Print Screenキーでキャプチャする方法を追加。

注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。

  • このサイトで紹介されているコードの多くは、例外処理が省略されています。例外処理については、こちらをご覧ください。
  • イベントハンドラの意味が分からない、C#のコードをそのまま書いても動かないという方は、こちらをご覧ください。
  • コードの先頭に記述されている「Imports ??? がソースファイルの一番上に書かれているものとする」(C#では、「using ???; がソースファイルの一番上に書かれているものとする」)の意味が分からないという方は、こちらをご覧ください。
  • Windows Vista以降でUACが有効になっていると、ファイルへの書き込みに失敗する可能性があります。詳しくは、こちらをご覧ください。
  • .NET Tipsをご利用いただく際は、注意事項をお守りください。