procedure TForm1.CopyAsBmpBtnClick(Sender: TObject);
begin
Clipboard.Assign( Image1.Picture.Bitmap );
end;
と書くだけだ.
写真やペイント系のソフトで描いた絵ならこの方法で問題ないが, GDIやCanvasのメソッドを使って描いたグラフや図形の場合は, ビットマップではなくベクトルフォーマットでコピーしたいものである. ベクトルフォーマットでコピーした画像は,コピー先で拡大/縮小しても劣化が少ない.
ベクトルフォーマットでコピーするのはビットマップでコピーするほど簡単ではないが,
TMetafileのSaveToClipboardFormatメソッドを使えば,拡張メタファイル形式(EMF形式)で
クリップボードにコピーするために必要なデータが得られる.
このメソッドのプロトタイプは,
procedure SaveToClipboardFormat( var AFormat: Word; var AData: THandle; var APalette: HPALETTE );
例えば以下のように使う.
procedure TForm1.CopyAsEMFBtnClick(Sender: TObject);
var
Metafile: TMetafile;
MetafileCanvas: TMetafileCanvas;
DispW, DispH, MMPerPixelW, MMPerPixelH: Integer;
Format: Word;
Data: THandle;
Palette: HPALETTE;
begin
DispW := GetDeviceCaps( Canvas.Handle, HORZSIZE );
DispH := GetDeviceCaps( Canvas.Handle, VERTSIZE );
MMPerPixelW := Round( DispW * 100 / Screen.Width );
MMPerPixelH := Round( DispH * 100 / Screen.Height );
Metafile := TMetafile.Create;
try
with Metafile do
begin
Enhanced := True;
MMWidth := Image1.Width * MMPerPixelW;
MMHeight := Image1.Height * MMPerPixelH;
Width := Image1.Width;
Height := Image1.Height;
end;
MetafileCanvas := TMetafileCanvas.Create( Metafile, Canvas.Handle );
DrawPicture( MetafileCanvas, Metafile.Width, Metafile.Height );
MetafileCanvas.Free;
Metafile.SaveToClipboardFormat( Format, Data, Palette );
Clipboard.SetAsHandle( Format, Data );
finally
Metafile.Free;
end;
end;
DrawPicture手続きでMetafileCanvasに適当な絵を描画した後, MetafileCanvasを解放してMetafileに画像を転送する. その後,SaveToClipboardFormatでコピーに必要なデータを取得し, SetAsHandleに渡す.
VCLのソースを見てみると,SaveToClipboardFormatはFormatにCF_ENHMETAFILEを設定し, DataにはCopyEnhMetafile APIで作成したメモリメタファイルのハンドルを設定している. また,Paletteには常に0が返ってくる.
SetAsHandleはSetClipboardData APIにDataパラメータで渡された メタファイルのハンドルを渡す. 一旦,ハンドルをクリップボードに渡すと,ハンドルの所有権がOS側に移るので, コピーが終了した後アプリケーション側でメタファイルのハンドルを解放することはない.
以上で問題なく画像をEMF形式でコピーできるのだが,ここではちょっと回りくどいことをしてみよう.
SetClipboardDataのプロトタイプは
function SetClipboardData( uFormat: UINT; hMem: THandle ): THandle; stdcall;
手順としては,
1. メタファイルのデータを格納するのに必要なメモリサイズを取得
2. 1で取得したサイズの領域をグローバルヒープ上に確保
3. データを2で確保した領域にコピー
4. コピーしたデータからメモリメタファイルのハンドルを生成
5. クリップボードにコピー
という具合になる.
メタファイルデータのサイズ取得およびコピーはGetEnhMetaFileBits APIを用いる.
このAPIのプロトタイプは
function GetEnhMetaFileBits( p1: HENHMETAFILE; p2: UINT; p3: PByte ): UINT; stdcall;
function GlobalAlloc( uFlags: UINT; dwBytes: DWORD ): HGLOBAL; stdcall;
また,コピーしたメタファイルのデータからメモリメタファイルのハンドルを生成するには
SetEnhMetafileBits APIを用いる.
プロトタイプは
function SetEnhMetaFileBits( p1: UINT; p2: PChar ): HENHMETAFILE; stdcall;
具体的なコードは以下のようになる.
procedure SaveToClipAsEMF( Metafile: TMetafile );
var
hMetafilePict: HGLOBAL;
h: HENHMETAFILE;
Size: Integer;
Buffer: Pointer;
begin
Size := GetEnhMetaFileBits( Metafile.Handle, 0, nil );
hMetafilePict := GlobalAlloc( GMEM_MOVEABLE or GMEM_DDESHARE, Size );
try
Buffer := GlobalLock( hMetafilePict );
GetEnhMetaFileBits( Metafile.Handle, Size, Buffer );
h := SetEnhMetafileBits( Size, Buffer );
GlobalUnlock( hMetafilePict );
Clipboard.SetAsHandle( CF_ENHMETAFILE, h );
except
GlobalFree( hMetafilePict );
end;
end;
SEO | [PR] 爆速!無料ブログ 無料ホームページ開設 無料ライブ放送 | ||