Delphi Programming / Object Pascal
[掲載 2013年01月10日] [更新 2013年01月10日] GDI+ 関係サンプル |
GDI+ 関係サンプル
G180_画像のリージョン |
動作確認等 |
Windows 7 U64(SP1) + Delphi XE(UP1) Pro |
|
G180_GDIPlus_ImageToRegion.zip [585 KB] 2013年01月10日版 (EXE 同梱) |
次の画像の,座標 [0, 0] と同じ色以外の部分をリージョンにするサンプルです.
まず,リージョン (TGPRegion) のインスタンスを生成し空にします.画像のピクセルを全て走査して,該当の色でない場合はリージョンに追加していく.という手順で作成しています.
サンプルでは,作成したリージョンを塗りつぶしています.塗り潰す必然性はありませんが,元の画像は,背景色を透過して描画すれば,リージョンを適用した時と同じになってしまいます.
このコードでは,対象の画像のビット深さが 24 ビット以上でないとリージョンは作成できません.
|
|
図1
設計時画面 |
|
図2
実行結果
|
リスト1
画像の指定色以外の部分をリージョンにする |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, ComCtrls, StdCtrls, GDIPOBJ, GDIPAPI;
type
TMyPanel = class(TCustomPanel)
protected
procedure Paint; override;
function GetRegion(GDPBitmap: TGPBitmap; TransColor: TGPColor;
GDPRegion: TGPRegion): Boolean;
end;
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private 宣言 }
MyPanel : TMyPanel;
protected
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
//=============================================================================
// フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
Self.Caption := 'GDI+ 画像のリージョン';
//TMyPanelを生成して配置
MyPanel := TMyPanel.Create(Self);
with MyPanel do begin
Parent := Self;
Left := 5;
Top := 5;
Width := Self.ClientWidth - 10;
Height := Self.ClientHeight - Top - 5;
Anchors := [akLeft, akTop, akRight, akBottom];
Color := clWhite;
BevelOuter := bvNone;
ParentBackground := False;
DoubleBuffered := True;
end;
end;
{ TMyPanel }
//-----------------------------------------------------------------------------
// 画像のリージョンを生成する関数
// 引数で指定した色以外の部分を利へジョンにする
//
// GDPBitmap : リージョンの作成元画像.この内容は変更しない
// TransColor : この色以外の部分をリージョンにする
// GDPRegion : 呼び出し側で生成したリージョンのインスタンス
// この関数実行後,この変数にリージョンのデータが格納される
//-----------------------------------------------------------------------------
function TMyPanel.GetRegion(GDPBitmap: TGPBitmap; TransColor: TGPColor;
GDPRegion: TGPRegion): Boolean;
var
LWidth : Integer;
LHeight : Integer;
LBmpData : TBitmapData;
LScanLine : PByte;
LpQuad : PRGBQuad;
LDataStride : Integer;
LTransR : Byte;
LTransG : Byte;
LTransB : Byte;
LXPos : integer;
LYPos : Integer;
LRValue : Byte;
LGValue : Byte;
LBValue : Byte;
LColorFlag : Boolean;
LRgnRect : TGPRect;
LInImage : Boolean;
begin
//とりあえず戻り値はFalseにして,リージョンを空にする
Result := False;
GDPRegion.MakeEmpty;
LWidth := GDPBitmap.GetWidth;
LHeight := GDPBitmap.GetHeight;
//リージョン作成の際,除外する色
//アルファ値を対象外とするためR,LGValue,Bに分解する
LTransR := GDIPAPI.GetRed (TransColor);
LTransG := GDIPAPI.GetGreen (TransColor);
LTransB := GDIPAPI.GetBlue (TransColor);
//ビットマップとしてのデータを取得
LRgnRect := MakeRect(0, 0, 0, 0);
if GDPBitmap.LockBits(MakeRect(0, 0, LWidth, LHeight),
ImageLockModeWrite,
PixelFormat32bppARGB, LBmpData) <> Ok then begin
exit;
end;
//スキャンラインの先頭ポインタを取得
//Strideは1ラインスキャン当たりのドット(ピクセルではない)
//画像のピクセルx色成分数
LScanLine := LBmpData.Scan0;
LDataStride := LBmpData.Stride;
LInImage := False;
//リージョンの領域矩形(ピクセル数9の初期値は0
//全ピクセルの色を調査して,指定色以外の時は,そのピクセルを追加して
//リージョンにUnionする
LRgnRect := MakeRect(0, 0, 0, 0);
for LYPos := 0 to LHeight - 1 do begin
LpQuad := PRGBQuad(LScanLine);
for LXPos := 0 to LWidth - 1 do begin
LRValue := LpQuad^.rgbRed;
LGValue := LpQuad^.rgbGreen;
LBValue := LpQuad^.rgbBlue;
LColorFlag :=(LRValue = LTransR) and (LGValue = LTransG) and (LBValue = LTransB);
if not LInImage then begin
if not LColorFlag then begin
LInImage := True;
LRgnRect.X := LXPos;
LRgnRect.Y := LYPos;
LRgnRect.Height := 1;
end;
end else begin
if LColorFlag then begin
LInImage := False;
LRgnRect.Width := LXPos - LRgnRect.X;
GDPRegion.Union(LRgnRect);
end;
end;
Inc(LpQuad);
end;
if LInImage then begin
LInImage := False;
LRgnRect.Width := LWidth - LRgnRect.X;
GDPRegion.Union(LRgnRect);
end;
Inc(LScanLine, LDataStride);
end;
Result := True;
GDPBitmap.UnlockBits(LBmpData);
end;
//-----------------------------------------------------------------------------
// TMyPanelクラスのPaintメソッド
// 実際の描画コード
//-----------------------------------------------------------------------------
procedure TMyPanel.Paint;
var
LXLocation : Single;
LYLocation : Single;
LGPBitmap : TGPBitmap;
LGPGraphic : TGPGraphics;
LTargetColor : TGPColor;
LGPImageRgn : TGPRegion;
LGPBrush : TGPBrush;
begin
inherited;
if not Assigned(Parent) then exit;
//描画先のCanvasを設定
LGPGraphic := TGPGraphics.Create(Canvas.Handle);
//背景用の画像からTGPBitmapを生成してTMyPanelのCanvasに描画
LGPBitmap := TGPBitmap.Create('051946.jpg');
LGPGraphic.DrawImage(LGPBitmap, 0, 0, Width, Height);
LGPBitmap.Free;
//画像ファイルからTGPBitmapのインスタンスを生成
LGPBitmap := TGPBitmap.Create('503.bmp');
//画像の表示位置座標を計算
LXLocation := (Width * 1.0 - LGPBitmap.GetWidth) / 2.0;
LYLocation := (Height * 1.0 - LGPBitmap.GetHeight) / 2.0;
//画像の座標(0, 0)の色を除いた部分をリージョンとする
LGPBitmap.GetPixel(0, 0, LTargetColor);
LGPImageRgn := TGPRegion.Create;
GetRegion(LGPBitmap, LTargetColor, LGPImageRgn);
//表示位置を中央にする
LGPImageRgn.Translate(LXLocation, LYLocation);
//リージョン内部をブラシで塗りつぶす
LGPBrush := TGPSolidBrush.Create(aclGreen);
LGPGraphic.FillRegion(LGPBrush, LGPImageRgn);
LGPBitmap.Free;
LGPGraphic.Free;
LGPImageRgn.Free;
LGPBrush.Free;
end;
end.
|