今回は画面のキャプチャー画像を作成するテクニックをご紹介します。
フォームやコンポーネントはその内容を描画するための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月に新規追記)