Migaro. 技術Tips

                       

ミガロ. 製品の技術情報
IBMiの活用に役立つ情報を掲載!


【Delphi】画面キャプチャー機能の実装

今回は画面のキャプチャー画像を作成するテクニックをご紹介します。

フォームやコンポーネントはその内容を描画するためのCanvasを持っています。

この内容をそっくりそのままBitmapにする、
いわゆる画面キャプチャー、スクリーンショットを画像として出力する機能が実装できます。

但し、フォームのCanvas等ではキャプション部分を除いたクライアント領域部分しか
Canvas内に存在しませんのでご注意ください。

 

設定方法

以下のロジックは、ButtonのClickイベント等の適当なイベントを作成し、
フォームのクライアント領域のBitmapを
「c:\Temp」フォルダに「Test.bmp」として作成するサンプルです。

procedure TForm1.Button1Click(Sender: TObject);
var
  BMP: TBitmap;
  RCT: TRect;
begin
  //*** TempフォルダにTest.bmpを作成します。 ***
  BMP := TBitmap.Create;
  try
    // Bitmapの色数を指定します。
    BMP.PixelFormat := pf24bit;
    // Bitmapの大きさを指定します。
    BMP.Width  := Form1.ClientWidth;
    BMP.Height := Form1.ClientHeight;
    // コピー範囲の大きさを指定します。
    RCT := Rect(0, 0, BMP.Width, BMP.Height);
    // Bitmapデータを作成します。
    BMP.Canvas.CopyRect(RCT, Form1.Canvas, RCT);
    // Bitmapデータをファイルとして保存します。
    BMP.SaveToFile('C:\Temp\Test.bmp');
  finally
    BMP.Free;
  end;
end;

Bitmapオブジェクトを作成し、そのCanvasにFormのCanvasの内容をコピーするだけです。
ここではFormのクライアント領域と同じ大きさのBitmapを、Tempフォルダに
固定ファイル名で作成しています。

拡大や特定のコンポーネントのみのBitmapを作成することも可能ですので、工夫してご活用ください。


尚、以下にJPEGファイルとして保存する例を記載しておきます。

uses節に「Vcl.Imaging.jpeg」を追加する必要がありますので、ご注意ください。
(※XE以前のバージョンでは「JPEG」を追加)

procedure TForm2.Button2Click(Sender: TObject);
var
  BMP: TBitmap;
  JPG: TJPEGImage;
  RCT: TRect;
begin
  //*** TempフォルダにTest.jpgを作成します。 ***
  BMP := TBitmap.Create;
  try
    // Bitmapの色数を指定します。
    BMP.PixelFormat := pf24bit;
    // Bitmapの大きさを指定します。
    BMP.Width  := Form1.ClientWidth;
    BMP.Height := Form1.ClientHeight;
    // コピー範囲の大きさを指定します。
    RCT := Rect(0, 0, BMP.Width, BMP.Height);
    // Bitmapデータを作成します。
    BMP.Canvas.CopyRect(RCT, Form1.Canvas, RCT);
 
    JPG := TJpegImage.Create;
    try
      // BitmapデータをJPEGデータに変換します。
      JPG.Assign(BMP);
      // JPEGデータをファイルとして保存します。
      JPG.SaveToFile('C:\Temp\Test.jpg');
    finally
      JPG.Free;
    end;
  finally
    BMP.Free;
  end;
end;

 

 
<出力画像イメージ>

 

TForm以外のコンポーネントのキャプチャを取る手順

ここまでForm1を例としてロジックを紹介してきましたが、
TFormのような「Canvas」プロパティを持つコンポーネントでないと
この手順は(そのままでは)使用できません。

例えばTPanelのような、Canvasプロパティを持たないコンポーネントの
範囲のみを指定してキャプチャを取る場合は、以下のように設定します。

TPanelの場合、はるか上位にある「TCustomControl」クラスに存在する
Canvasプロパティを呼び出します。

 

<宣言部ロジック>

typeによる型宣言にて、
TCustomControlを継承したクラスを1つ宣言します。(青字部分)

type
  TCtrlX = class(TCustomControl)  // 名前は何でもよい
    property Canvas;   // ここでCanvasを定義する
  end;
  TForm1 = class(TForm) // ここから従来の型宣言ロジック
    Button1: TButton;
    ・・・

 

<実装部ロジック>

上記のロジック内でCopyRect(Bitmapデータの作成)を行っている箇所で、
Form1.Canvasの代わりに、
先ほど宣言したクラスでキャストしたコンポーネントのCanvasを指定します。

    // Bitmapデータを作成します。(変更前)
    BMP.Canvas.CopyRect(RCT, Form1.Canvas, RCT);

    // Bitmapデータを作成します。(変更後)
    // ※RCTのWidthやHeightもPanel1の大きさにあわせて設定する
    BMP.Canvas.CopyRect(RCT, TCtrlX(Panel1).Canvas, RCT);

 

TScrollBoxの中身全体のキャプチャを取る手順

ここまでご紹介した各ロジックでは、
画面内に見えている範囲のCanvasをもとにBitmapにキャプチャしています。
そのため、TScrollBoxでは画面内に見えている範囲しかキャプチャできません。

しかし逆に言えば、画面に見えていればキャプチャ可能なため、
TScrollBoxのスクロール位置を少しずつずらしながら内部で合成していき、
最終的に大きな画像として出力することは可能です。

ここまでの手順を応用して、画面に表示しきれないほど
縦横に大きなサイズを持つTScrollBoxの中身をキャプチャする手順を紹介します。

 

<画面設計>

まず、対象のTScrollBoxの内部全体にTPanelを配置します。
このTPanelは縦横のプロパティを
「Top=0」「Left=0」「Height=任意の高さ」「Width=任意の幅」
に設定しておきます。
(※このTPanelに対してキャプチャを行うため、Panelの外側にコンポーネントを配置してもキャプチャされません。)

縦横を設定したTPanelの上に、LabelやImage等の各コンポーネントを配置していきます。

 

<実装部ロジック>

前項「TForm以外のコンポーネントのキャプチャを取る手順」のロジックを応用し、
TCustomControlを継承したクラス(本記事では「TCtrlX」)を使って
縦横を設定したTPanelのキャプチャを少しずつ取っていきます。

以下の例では
「① スクロールを移動して、キャプチャしたい部分を表示させる」
「② その部分が描画されるのを待つ」
「③ 200×200ピクセルずつキャプチャする」
の手順を左上から右下までひたすら繰り返しています。

出力結果の画像が一部分の繰り返しになってしまう等、
うまくいかない場合は赤字部分の値を微調整してください。

procedure TForm1.Button3Click(Sender: TObject);
var
  ix, iy: Integer;
  BMP: TBitmap;
  JPG: TJPEGImage;
  RCT: TRect;
begin
  //*** TempフォルダにTest.jpgを作成します。 ***
  BMP := TBitmap.Create;
  try
    // Bitmapの色数を指定します。
    BMP.PixelFormat := pf24bit;
    // Bitmapの大きさを指定します。
    BMP.Width  := Panel1.ClientWidth;
    BMP.Height := Panel1.ClientHeight;

    for ix := 1 to ((BMP.Width + 199) div 200) do
    begin
      for iy := 1 to ((BMP.Height + 199) div 200) do
      begin
        // 200x200ずつ描画させるため、ScrollBox側を移動させて画面描画させる
        ScrollBox1.HorzScrollBar.Position := (ix-1) * 200;
        ScrollBox1.VertScrollBar.Position := (iy-1) * 200;
        Panel1.Repaint; // スクロール移動後、パネルの再描画が必須
        Sleep(10);      // 再描画待機(うまく描画されない場合は延ばしてみる)

        // コピー範囲の大きさを指定します。
        RCT := Rect((ix-1) * 200, (iy-1) * 200, ix * 200, iy * 200);
        // Bitmapデータを作成します。(変更後)
        // ※RCTのWidthやHeightもPanel1の大きさにあわせて設定する
        BMP.Canvas.CopyRect(RCT, TCtrlX(Panel1).Canvas, RCT);
      end;
    end;

    JPG := TJpegImage.Create;
    try
      // BitmapデータをJPEGデータに変換します。
      JPG.Assign(BMP);
      // JPEGデータをファイルとして保存します。
      JPG.SaveToFile('出力先JPEGのパス.jpg');
    finally
      JPG.Free;
    end;
  finally
    BMP.Free;
  end;
end;

 


 

<関連記事>
【Delphi】画面印刷の方法 | Migaro. Tips

 

(ミガロ.情報マガジン「MIGARO News!!」Vol.207 2018年2月号より)
(「TForm以外の~」の節は2022年11月に新規追記)
(「TScrollBoxの~」の節は2023年7月に新規追記)