Delphi Programming / Object Pascal
サイトのトップページへ リンクのページへ ロゴマーク
[掲載 2012年11月23日] [更新 2022年10月29日] GDI+ 関係サンプル
   
GDI+ 関係サンプル 
G030_画像の拡大・縮小時の補間モード
動作確認等 Windows 7 U64(SP1) + Delphi XE(UP1) Pro
一部,Windows 10 ビルド 19043 Pro 64 bit + Delphi XE5(UP2) Pro VCL-32
G030_GDIPlus_Interpolation.zip [2.2 MB] 2022年10月29日版 (EXE 同梱)







01_図形描画と画像の拡大・縮小時における補間モード


図形や画像をリサイズして拡大縮小すると,一般的には描画が劣化します.このため,通常はアンチエイリアスの処理としてピクセル間の補間を行います.GDI+ では画像や図形のリサイズの際にデフォルトのアンチエイリアス処理を行ってくれますが,TGPGraphics では,SetInterpolationMode という関数を使用して,補間のアルゴリズムを指定して補間することができます.そのテストです.
補間のモードは TInterpolationMode 型の列挙型となっています.次の値があります.

ニアレストネイバー法は,単純に元の画像の画素を増したり,間引きする方式です.ジャギー (ギザギサ) が目立ちやすく階調のある画像のリサイズには向いていなと言われています.
バイリニア法,バイキュービック法は周辺の複数の画素を数学的に考慮して処理するので,時間はかかりますが,一般に高品質の結果が得られます.結果の品質は,画像の種類にもよりす.

本サンプルはビットマップ画像でテストしています.直線や曲線等,図形の描画の時のアンチエイリアス効果については各自で確認してくだい.


定数名 機能・補間アルゴリズム
InterpolationModeInvalid 指定は無効
InterpolationModeDefault 既定のモード.InterpolationModeBilinear
InterpolationModeLowQuality 低品質補間
InterpolationModeHighQuality 高品質補間
InterpolationModeBilinear 双一次補間.バイリニア法
50% 以下にする縮小処理には適していない
InterpolationModeBicubic 双三次補間.バイキュービック法
25% 以下にする縮小処理には適していない
InterpolationModeNearestNeighbor 最近傍補間.ニアレストネイバー法
InterpolationModeHighQualityBilinear 高品質双一次補間
InterpolationModeHighQualityBicubic 高品質双三次補間


図1
設計時画面
  • 表示用の TImmage を 2 つ配置
図2
InterpolationModeInvalid
  • 上の画像は,VCL での描画結果
  • 補間モードが無効な場合の結果
  • GDI+ では,直線もそうであるが,ある程度の補間処理をするようだ
図3
InterpolationModeNearestNeighbor
  • VCL での結果に近い
  • VCL ではこのモードで内部処理しているのかも知れない
図4
InterpolationModeHighQualityBicubic
  • 今回のテストで,一番滑らかに感じたモード

リスト1
GDI+ の TGPGraphics の補間モードのテスト
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, GDIPAPI, GDIPOBJ, StdCtrls, ExtCtrls;

type
  TForm1 = class(TForm)
    Image1: TImage;
    Image2: TImage;
    RadioGroup1: TRadioGroup;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure RadioGroup1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//=============================================================================
//  フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  Self.Caption := 'GDI+  画像拡大時の補間モード';

  //TInterpolationModeの値は上から-1, 0, 1, 2, ...となっている
  with RadioGroup1.Items do begin
    Add('InterpolationModeInvalid');
    Add('InterpolationModeDefault');
    Add('InterpolationModeLowQuality');
    Add('InterpolationModeHighQuality');
    Add('InterpolationModeBilinear');
    Add('InterpolationModeBicubic');
    Add('InterpolationModeNearestNeighbor');
    Add('InterpolationModeHighQualityBilinear');
    Add('InterpolationModeHighQualityBicubic');
  end;
  RadioGroup1.ItemIndex := 0;
end;

//=============================================================================
//  RadioGroup1のOnClickイベント
//=============================================================================
procedure TForm1.RadioGroup1Click(Sender: TObject);
begin
  Button1Click(nil);
end;

//=============================================================================
//  画像を拡大・縮小する時の補間アルゴリズムの比較テスト
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LFilePath   : string;
  LBitmap     : TBitmap;
  LSrcRect    : TRect;
  LGDIGraphic : TGPGraphics;
  LGDIBitmap  : TGPBitmap;
  LPolaMode   : TInterpolationMode;
begin
  //表示する画像のファイル名
  LFilePath := '501.bmp';

  //まずVCLのTCanvasのCopyRectによる描画の場合
  LBitmap := TBitmap.Create;
  try
    LBitmap.LoadFromFile(LFilePath);
    //元の画像のこの部分を拡大表示する
    LSrcRect := Rect(20, 30, 20 + 35, 30 + 30);

    //画像の一部をImage1に描画
    Image1.Canvas.CopyRect(Rect(0, 0, Image1.Width, Image1.Height),
                           LBitmap.Canvas,
                           LSrcRect);
  finally
    FreeAndNil(LBitmap);
  end;


  //以下GDI+ の補間モードを指定しての描画
  //RadioGruupのItemに応じて補間モードを選択
  LPolaMode := -1;
  case RadioGroup1.ItemIndex of
    0: LPolaMode := InterpolationModeInvalid;
    1: LPolaMode := InterpolationModeDefault;
    2: LPolaMode := InterpolationModeLowQuality;
    3: LPolaMode := InterpolationModeHighQuality;
    4: LPolaMode := InterpolationModeBilinear;
    5: LPolaMode := InterpolationModeBicubic;
    6: LPolaMode := InterpolationModeNearestNeighbor;
    7: LPolaMode := InterpolationModeHighQualityBilinear;
    8: LPolaMode := InterpolationModeHighQualityBicubic;
   end;

  //Image2の画像を消去
  Image2.Picture.Assign(nil);
  LGDIGraphic := TGPGraphics.Create(Image2.Canvas.Handle);

  LGDIBitmap := TGPBitmap.Create(LFilePath);

  //補間モード設定
  LGDIGraphic.SetInterpolationMode(LPolaMode);
  //GDIBitmapをImage2に描画
  //TCanvasのStretchDrawまたはCopyRectに相当する
  LGDIGraphic.DrawImage(
                LGDIBitmap,
                MakeRect(0, 0, Image2.Width, Image2.Height),
                LSrcRect.Left,
                LSrcRect.Top,
                LSrcRect.Right  - LSrcRect.Left,
                LSrcRect.Bottom - LSrcRect.Top,
                UnitPixel);

  LGDIBitmap.Free;
  LGDIGraphic.Free;
end;

end.




02_画像の拡大・縮小・部分拡大等の方法


上のサンプルで使用している画像は,下図のビットマップ画像です.この画像の一部分を拡大表示しています.

図5
テストに使用したビットマップ画像
GDI+ の DrawImage には,多くのオーバーロード関数があります.
表示元の画像の領域を指定し,出力先の描画領域も指定可能な関数もあります.これを使用すると,元の画像をリサイズして拡大・縮小表示したりできます.また,元の画像の一部分だけをリサイズして拡大・縮小表示することもできます.
詳しくは,下記の参考リンクや,GDI+ のソースコードで確認してください.





03_画像拡大時における終端ピクセル処理とピクセルオフセットの設定


TGPGraphics の SetInterpolationMode 関数を使用したアンチエイリアス処理は,直線や曲線の描画に対しても有効です.画像の拡大表示の場合,補間処理として別の要素があります.

画像の拡大では,周辺のピクセルの情報から新しいピクセルを追加作成します.この時,画像の上端と下端あるいは左端と右端のピクセルは,その下または右には参照すべきピクセルがありません.それをどう扱うかを TGPImageAttributes.SetWrapMode で指定することができます.また,ピクセルのどの領域までを参照するかを TGPGraphics.SetPixelOffsetMode で指定できます.

本サンプルは,[画像の表示と表示サイズでの画像保存] の TImage への画像表示のサンプルプログラムにチェックボックスを追加し,現象と関数の効果を確認しやすいように,背景にテクスチャ画像を描画しています.
テストに使用した画像はビットマップ画像です.これらの処理がないと,終端のピクセルに,元の画像にな存在しない色のピクセルが追加されたり,均等に拡大されないことがあります.

下図の結果で示すような現象は画像の場合です.図形を描画するコードを Paint メソッド内等で実行する場合は発生しません.また,写真等の画像ではこの現象が発生してもあまり目立ちません.



図6
テストに使用したビットマップ画像
  • 元のサイズで表示
図7
処理をしないで拡大リサイズした結果
  • SetWrapMode と SetPixelOffsetMode による処理をしない場合
  • 画像の下端と右端に,元の画像にはない描画が行われている

図8
SetPixelOffsetMode だけの処理をした場合
図9
SetWrapMode と SetPixelOffsetMode による処理をした場合

下図は別のビットマップ画像での結果です.このビットマップ画像は,1 ドットの黒い線で矩形を描画して作成したものです.
上で述べた処理を実行すると,線の太さが均等に拡大されていることが確認できます.ただし,線の部分のピクセルの色が全て元の「黒」ではなく,中間色で補間されていいます.つまりぼやけた感じの描画となります.


図10
テストに使用した別のビットマップ画像
  • 元のサイズで表示
図11
処理をしないで拡大表示した結果
  • SetWrapMode と SetPixelOffsetMode による処理をしない場合
  • 線の太さが均等に拡大されていない
  • 下端と右端の描画は半透明
図12
処理をして拡大表示した結果
  • SetWrapMode と SetPixelOffsetMode による処理をした場合
  • 線の太さが均等に拡大されている
  • ただし,線の部分の全てが元の「黒」ではない

リスト2
画像拡大時における終端のピクセル処理とピクセルオフセットの設定
//=============================================================================
//  TCheckBoxのOnClickイベント処理
//  画像描画時の終端ピクセルの描画モードとピクセルのオフセットモードを設定
//=============================================================================
procedure TForm1.CheckBox1Click(Sender: TObject);
begin
  if not Assigned(FGPBitmap) then exit;
  if FGPBitmap.GetWidth <= 0 then exit;

  Image1.Picture.Assign(nil);
  GDIDrawImageToTImage;
end;

//-----------------------------------------------------------------------------
//  実際の描画コード
//-----------------------------------------------------------------------------
procedure TForm1.GDIDrawImageToTImage;
var
  LGPGraphic : TGPGraphics;
  LBackImage : string;
  LGPImage   : TGPImage;
  LGPTBrush  : TGPTextureBrush;
begin
  if not Assigned(FGPBitmap) then exit;

  //TGPGraphicsのオブジェクトを生成
  //描画先はこのTImageのCanvas
  LGPGraphic := TGPGraphics.Create(Image1.Canvas.Handle);

  //背景のテクスチャを作成して描画
  LBackImage := ExpandFileName('backTexture.gif');
  if FileExists(LBackImage) then begin
    LGPImage  := TGPImage.Create(LBackImage);
    LGPTBrush := TGPTextureBrush.Create(LGPImage);
    try
      LGPGraphic.FillRectangle(LGPTBrush,
                               MakeRect(0, 0, Image1.Width,Image1.Height));
    finally
      FreeAndNil(LGPImage);
      FreeAndNil(LGPTBrush);
    end;
  end;

  //終端ピクセルの描画モードとピクセルのオフセットモードを設定
  if CheckBox1.Checked then begin
    //TGPImageAttributesによる設定が他にもあるかも知れない
    //それらを有効するには生成していない場合に限って生成する方が良い
    if not Assigned(FGPImageAttr) then begin
      FGPImageAttr := TGPImageAttributes.Create;
    end;
    FGPImageAttr.SetWrapMode(WrapModeTileFlipXY);
  end else begin
    if Assigned(FGPImageAttr) then FreeAndNil(FGPImageAttr);
  end;

  if CheckBox2.Checked then begin
    LGPGraphic.SetPixelOffsetMode(PixelOffsetModeHalf);
  end;

  //TGPBitmapをこのTImageのCanvasに描画
  LGPGraphic.DrawImage(
              FGPBitmap,
              MakeRect(0, 0, Image1.Width, Image1.Height),
              0,
              0,
              FGPBitmap.GetWidth,
              FGPBitmap.GetHeight,
              UnitPixel,
              fGPImageAttr);

  //Createしたオブジェクトは解放処理する
  if Assigned(LGPGraphic) then FreeAndNil(LGPGraphic);
end;




04_画像のリサイズによる拡大と拡大表示


本ページに限らず,GDI+ 関係のサンプルで「拡大」という用語を使用しています.これは実際にはリサイズの結果としての「拡大」を意味しています.
下図は 32 x 32 のサイズのアイコン画像を拡大表示した状態です.このような拡大表示は画像の画素,ピクセルの様子を見る時にも使われることがあります.Windows に付属の拡大鏡も画像を拡大表示するものです.

GDI+ では,画像のサイズよりも大きい Canvas に描画すると,下の一番最後の結果のように,アンチエイリアスの処理が行われます.
VCL の TCanvas.StretchDraw メソッドで画像を描画する時はアンチエイリアス処理は行われません,下の最初とその次のような結果となります.これは最近傍補間 (ニアレストネイバー法) による描画となります.GDI+ でもこの補間による描画はできますが,完全にアンチエイリアスなしの描画は行われないようです.



図13
画像の拡大表示の例
  • アイコン画像の編集等の場合に使われる
図14
Windows 7 に付属の拡大鏡による画像の拡大表示
  • ディスクに保存してある画は,Windows フォトビューアで拡大表示すれば確認できる
図15
画像のリサイズによる拡大の例
  • アンチエイリアスの処理が行われる




05_GDI+ を使用しない画像の拡大 / 縮小時の補間 - Graphics32


VCL の TBitmap は,拡大または縮小の時に補間モードを指定できまん.
以下の GitHub のページからダウンロードしたユニットを使用すると,補間モードを指定して TBitmap 画像を拡大または縮小することができます.



[備考 1]
2022年10月28日現在,上のリンクからダウンロードした ZIP 書庫内のユニットresizeimageunit.pas の uses 部にある optimizedscanlineunit.pas, misc_functions.pas が ZIP 書庫に含まれていません.これらのユニットファイルの入手方法については不明です.


上のリンクからダウンロードした ZIP 書庫は,ファイルが不足していて利用できません.そこで,Graphics32 を使用したサンプルを作成してみました.
Graphics32 の TBitmap32 クラスは,GDI+ と違い,TBitmap のアルファチャンネルも自動で処理してくれます.本サンプルでは,アルファチャンネル付きのビットマップ画像を使用しています.TBitmap32 を使用する部分は,独立したメソッドとして実装しました.補間モードは,バイリニアニ固定しています.



図16
添付の画像を拡大表示
  • 左が元の画像
  • 背景の市松模様の画像は,
    透過状態の確認用

リスト3
Graphics32 を使用して TBitmap 画像をリサイズ
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Image1: TImage;
    Image2: TImage;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
    procedure ResizeBmpByGR32(SrcBmp: TBitmap; DstBmp: TBitmap;
      DstWidht, DstHeight: Integer; ResizeFlag: Boolean = True); overload;
    procedure ResizeBmpByGR32(SrcBmp: TBitmap; DstBmp: TBitmap; SrcX, SrcY, SrcCX,
      SrcCY: Integer; DstCX, DstCY: Integer; ResizeFlag: Boolean = True); overload;
    procedure DrawBackGroundImage(ACanvas: TCanvas; AFilePath: string);
  end;

var
  Form1: TForm1;

implementation

uses
  GR32,
  GR32_Resamplers;

{$R *.dfm}

//=============================================================================
//  TBitmap の画像をリサイズ
//  TBitmap 以外の画像も TBitmap に変換すれば同様ににリサイズ可能
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LSrcBmp : TBitmap;
  LDstBmp : TBitmap;
begin
  LSrcBmp := TBitmap.Create;
  LDstBmp := TBitmap.Create;
  try
    LSrcBmp.AlphaFormat := afDefined;
    LSrcBmp.LoadFromFile('virus detected.bmp');

    // リサイズ前の TBitmap を TImage に描画
    DrawBackGroundImage(Image1.Canvas, 'backTexture_02.bmp');
    Image1.Canvas.Draw(0, 0, LSrcBmp);

    // 256 x 256 にリサイズ
    ResizeBmpByGR32(LSrcBmp, LDstBmp,256, 256);

    // リサイズ後の TBitmap を TImage に描画
    DrawBackGroundImage(Image2.Canvas, 'backTexture_02.bmp');
    Image2.Canvas.Draw(0, 0, LDstBmp);
  finally
    FreeAndNil(LSrcBmp);
    FreeAndNil(LDstBmp);
  end;
end;

//-----------------------------------------------------------------------------
//  Graphics32 を使用した TBitmap 画像のリサイズ
//-----------------------------------------------------------------------------
procedure TForm1.ResizeBmpByGR32(SrcBmp, DstBmp: TBitmap; DstWidht,
  DstHeight: Integer; ResizeFlag: Boolean);
begin
  ResizeBmpByGR32(SrcBmp, DstBmp, 0, 0,
                  SrcBmp.Width, SrcBmp.Height, DstWidht, DstHeight, ResizeFlag);
end;

//-----------------------------------------------------------------------------
//  Graphics32 を使用した TBitmap 画像のリサイズ
//  元の TBitmap の部分的な矩形領域の拡大 / 縮小も可能
//  補間モードは TLinearResampler ( 多分,双一次補間 - バイリニア補間 ) に固定
//
//  uses に GR32, GR32_Resamplers が必要
//-----------------------------------------------------------------------------
procedure TForm1.ResizeBmpByGR32(SrcBmp, DstBmp: TBitmap; SrcX, SrcY, SrcCX,
  SrcCY, DstCX, DstCY: Integer; ResizeFlag: Boolean);
var
  LPixelFmt : TPixelFormat;
  LAlphaFmt : TAlphaFormat;
  LSrcBmp32 : TBitmap32;
  LDstBmp32 : TBitmap32;
  LSrcRect  : TRect;
  LDstRect  : TRect;
begin
  LPixelFmt := SrcBmp.PixelFormat;
  LAlphaFmt := SrcBmp.AlphaFormat;

  // 操作対象の画像の矩形領域
  LSrcRect := Rect(SrcX, SrcY, SrcCX, SrcCY);
  LDstRect := Rect(0,0, DstCX, DstCY);

  LSrcBmp32 := TBitmap32.Create;
  LDstBmp32 := TBitmap32.Create;
  try
    if ResizeFlag then begin
      LSrcBmp32.Resampler := TLinearResampler.Create;
    end;
    // 元の TBitmap を TBitmap32 に変換
    SrcBmp.AlphaFormat := LAlphaFmt;
    LSrcBmp32.Assign(SrcBmp);

    // TBitmap32 を変換後のサイズにして,その Canvas に元のビットマップを描画     L
    LDstBmp32.SetSize(LDstRect.Width, LDstRect.Height);
    LDstBmp32.Draw(LDstRect, LSrcRect, LSrcBmp32);

    // リサイズ後に画像を描画した TBitmap32 を TBitmap に変換
    DstBmp.Assign(LDstBmp32);
    DstBmp.AlphaFormat := LAlphaFmt;

    // ビット深さを元に戻す
    DstBmp.PixelFormat := LPixelFmt;
  finally
    FreeAndNil(LSrcBmp32);
    FreeAndNil(LDstBmp32);
  end;
end;
//----------------------------------------------------------------------------
//  TImage の背景として市松模様のブラシを描画
//  TBitmap の透過状態の確認用
//  この模様が見える部分は透明または半透明の部分ということになる
//----------------------------------------------------------------------------
procedure TForm1.DrawBackGroundImage(ACanvas: TCanvas; AFilePath: string);
var
  LBmpBack : TBitmap;
begin
  LBmpBack := TBitmap.Create;
  try
    LBmpBack.LoadFromFile(AFilePath);
    ACanvas.Brush.Style  := bsSolid;
    ACanvas.Brush.Bitmap := LBmpBack;
    ACanvas.FillRect(ACanvas.ClipRect);
  finally
    FreeAndNil(LBmpBack);
  end;
end;


end.


補間モードの設定コードを次のようにすれば,任意の補間モードにできます.


    // 別の補間モードにするには TLanczosKernel の部分を変更する
    // LResamplerType : TKernelResampler;

    if ResizeFlag then begin
      LResamplerType        := TKernelResampler.Create(LSrcBmp32);
      LResamplerType.Kernel := TLanczosKernel.Create;
      LResamplerType.Changed;
      LSrcBmp32.Resampler := LResamplerType;
    end;


補間によるアンチエイリアスの効果を,直線を描画しただけのビットマップ画像で確認した結果です.



図17
アンチエイリアスなし
  • TCanvas.StretchDraw による描画
図18
アンチエイリアスの効果
  • Graphics32 を使用して拡大 した結果

テスト用の,直線だけのビットマップ画像は,以下のコードで作成しました.このビットマップを保存して拡大表示しました.拡大表示した画像をピクセル単位で拡大したのが上の画像です.


procedure TForm1.Button1Click(Sender: TObject);
const
  FBackColor : TColor = clWhite;
var
  LBitmap : TBitmap;
  LCanvas : TCanvas;
begin
  LBitmap := TBitmap.Create;
  try
    LBitmap.SetSize(32, 32);
    LBitmap.PixelFormat := pf24bit;

    LCanvas := LBitmap.Canvas;

    LCanvas.Brush.Color := FBackColor;
    LCanvas.FillRect(LCanvas.ClipRect);

    LCanvas.Pen.Width := 5;
    LCanvas.Pen.Color := clBlack;

    LCanvas.MoveTo(0, 0);
    LCanvas.LineTo(LBitmap.Width, LBitmap.Height);
    LBitmap.SaveToFile('line.bmp');
  finally
    FreeAndNil(LBitmap);
  end;
end;


[備考 2]
今回作成したサンプルは,Graphics32 の [Source] フォルダにライブラリパスを通すだけでコンパイルして実行できます.
Graphics32 には,TPaintBox32, TImage32, TBitmap32List などのコンポーネントも含まれています.それらを利用するには,[Source] 内の GR32_Reg.pas をインストールします.参考リンクの Graphics32 のリンクからダウンロードしたファイルにはパッケージファイルはありません.適当なパッケージに登録します.


図19
Graphics32 関係コンポーネント

Delphi XE5 で,Graphics32 を使用するプロジェクトをビルド (再構築) すると,「Windows.dcu が見つかりません」などのエラーが発生します.その場合は,以下のように,ユニットスコープ名 WinApi を追加すればエラーは発生しなくなります.
こエラーの発生は,数十ヵ所あります.


Windows, Messages  ---> Winapi.Windows, Winapi.Messages
Windows.TPoint     ---> Winapi.Windows.TPoint;

   


Graphics32 の TImage32 に,TBitmap32 のビットマップ画像を描画する例です.



図20
実行結果

リスト4
Graphics32 の TImage32 に,TBitmap32 のビットマップ画像を描画
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtDlgs, Vcl.StdCtrls,
  Vcl.ExtCtrls, GR32, GR32_Image, GR32_Backends;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Image321: TImage32;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//=============================================================================
//  Graphics32 の TImage32 に TBitmap32 を描画する例
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LBitmap32 : TBitmap32;
  LBitmap : TBitmap;
begin
  LBitmap32 := TBitmap32.Create;
  try
    // TImage32.Bitmmap ( TImage の内部ピッマップ相当) のサイズを設定
    Image321.Bitmap.SetSize(Image321.Width, Image321.Height);
    // 背景を指定色で塗り潰す
    // Ex. 緑は clGreen32
    Image321.Bitmap.Clear($FFFFFFFF);


    // TImage32 の背景を市松模様のタイルにする
    LBitmap := TBitmap.Create;
    try
      LBitmap.LoadFromFile('backTexture_02.bmp');

      Image321.Bitmap.Canvas.Brush.Style  := bsSolid;
      Image321.Bitmap.Canvas.Brush.Bitmap := LBitmap;
      Image321.Bitmap.Canvas.FillRect(Image321.Bitmap.Canvas.ClipRect);
    finally
      FreeAndNil(LBitmap);
    end;


    // ビットマップ画像を読み込んで TImage32 ( の TBitmap ) に描画
    LBitmap32.LoadFromFile('virus detected.bmp');

    // dmTransparent にすると半透明は無効 ( RGB 値だけで描画される )
    LBitmap32.DrawMode := dmBlend;
    LBitmap32.DrawTo(Image321.Bitmap);
  finally
    FreeAndNil(LBitmap32);
  end;
end;

end.