Delphi Programming / Object Pascal
[掲載 2019年08月31日] [更新 2019年09月02日] Delphi サンプルプログラム集 |
091_アイコン画像をビットマップ画像に変換 |
動作確認等 |
Windows 7 U64(SP1) + Delphi XE5(UP2) Pro VCL-32 |
|
091_TIcon_ToBitmap.zip [6,627 KB] 2019年09月02日版 (EXE 同梱) |
拡張子が .ico のアイコン画像ファイルを,TIcon オブジェクト,あるいは TWICImage オブジェクトに読み込んでビットマップ画像に変換するサンプルです.
TBitmap.Canvas に TIcon のオブジェクトを描画すればビットマップが取得できますが,32 ビットのアイコン画像の透明ピクセルは処理しません.Delphi 2010 以降では Icon.AssignTo メソッドで,アイコンオブジェクトをピッマップのオブジェクトに変換できますが,24 ビット以下のアイコン画像は正常に変換できません.
同じく
Delphi 2010 で実装された TWICIMage
を使用すると,32 ビットのアイコン画像も 24 ビット以下のアイコン画像も正常にビットマップ画像に変換できます.TWICImage を使用すると,アイコンのオブジェクトを TImage に正しく表示てきます.
本ページのサンプルは,これらのことを確認するためのサンプルと言えます.
|
添付のプロジェクトのフォームは下図のようになっています.
読み込むアイコン画像ファイルを選択するために TOpenPictureDialog を配置しています.
左側の TImage には,作成したビットを TImage.Picture.Assign
で描画します.右側の TImage には作成したビットマップとを Tmage.Canvas.Draw
メソッドで描画するようにしています.
|
|
図1せ
設計時の画面
- TImage を 2 つ配置
- TOpenPictureDialog ょ 1 つ配置
|
TIcon では PNG 形式のアイコン画像は読み込めません.読み込もうとすると,下図のように「システムリソース不足です」のエラーが発生して読み込めません.
TIcon は,アイコン画像を読み込む時にビットマップの TBitmapInfoHeader 構造体を読みにいきます.ところが PNG 形式のアイコン画像にはこの情報がありません.TIcon はその構造体のデータがあるべき位置の値を取得してメモリを確保しようとします.この値は,一般的に,プロセスで使用可能なメモリの上限を超えた非常に大きな値となります.例えば Exa Byte (EB - エクサ - TB の 10 の 6 乗倍) オーダの値になります.そのためこのエラーが発生します.
TWICImage であれば PNG 形式のアイコン画像を読み込むことができます.
|
|
図2
PNG 形式のアイコン画像の場合
- メモリの確保に失敗してシステムリソース不足のエラーとなる
|
[備考 1]
Ticon, TWICImage はマルチアイコンを操作できません.TIcon は,マルチアイコンのファイルの場合,32 x 32 のサイズのアイコンがある場合は 32 x 32 のアイコンを取得します.そのサイズがない場合は 32 x 32 に近いサイズのアイコンを 32 x 32 にリサイズして取得します. |
[備考 2]
Windows では,256 x 256 サイズのアイコンは,PNG 形式の画像として格納するようになっています.それ以外のサイズはマスク画像とビットマップ画像を格納したビットマップ形式の画像です.
PNG 画像と 32 ビットのビットマップ画像はアルファチャンネル付きの画像です.アルファチャンネルには透明ピクセルとしての情報があります.PNG 形式のアイコン画像と 32 ビットのアイコン画像には,透過ピクセルと透過しないピクセルを識別するためのマスク画像がありません. |
01_TBitmap.Canvas にアイコン画像を描画する方法 |
TBitmap の Canvas にアイコンオブジェクトを描画する方法の確認テストです.
この方法は 32 ビットの透明ピクセルの処理は行われません.透明ピクセルの部分は TBitmap デフォルトの背景色である「白」になります.
|
|
図3
TBitmap.Canvas にアイコン画像を描画
- 24 ビットの色数のアイコン画像の場合
- 元のアイコン画像と同じ 24 ビットのビットマップ画像となる
|
|
図4
TBitmap.Canvas にアイコン画像を描画
- 32 ビットの色数のアイコン画像の場合
- 画像の背景部分が透過していないので「白」になっている
- 画像以外の部分は透過して背景の市松模様が見えている
|
左側の TImage の Transparent
の値を True にすると下図のようになります.
|
|
図5
左側の TImage の Transparent の値を True にする
|
リスト1
TBitmap.Canvas にアイコン画像を描画する方法 |
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;
type
TForm1 = class(TForm)
Button1: TButton;
Image1: TImage;
OpenPictureDialog1: TOpenPictureDialog;
Image2: TImage;
CheckBox1: TCheckBox;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
FInitDir : string;
FImgFilePath : string;
FBackImgPath : string;
public
{ Public 宣言 }
procedure DrawBackGroundImage(ACanvas: TCanvas; AFilePath: string);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
//=============================================================================
// フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
Self.Color := $00B3FFB3;
FInitDir := ExpandFileName('..\Images\');
FBackImgPath := ExpandFileName('..\BackTexture_01.bmp');
CheckBox1.Checked := True;
end;
//=============================================================================
// アイコン画像をビットマップ画像に変換
// TBitmap.Canvas.Draw メソッドを使用する方法
// アイコンをTBitmap.Canvasに描画すればTBitmapとして取得できる
//
// 透明部分はは正常に変換できない
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LBitmap : TBitmap;
LIcon : TIcon;
begin
OpenPictureDialog1.Filter := 'アイコンファイル|*.ico';
OpenPictureDialog1.InitialDir := FInitDir;
if not OpenPictureDialog1.Execute then exit;
FInitDir := ExtractFileDir(OpenPictureDialog1.FileName);
FImgFilePath := OpenPictureDialog1.FileName;
Image1.Picture.Assign(nil);
Image2.Picture.Assign(nil);
//透過状態が分かるように背景に市松模様のビットマップ画像を描画
DrawBackGroundImage(Image1.Canvas, FBackImgPath);
DrawBackGroundImage(Image2.Canvas, FBackImgPath);
LBitmap := TBitmap.Create;
LIcon := TIcon.Create;
try
//アイコン画像を読み込む
LIcon.LoadFromFile(FImgFilePath);
LBitmap.Transparent := CheckBox1.Checked;
//アイコン画像からビットマップ画像を作成
LBitmap.SetSize(LIcon.Width, LIcon.Height);
LBitmap.Canvas.Draw(0, 0, LIcon);
//作成した画像を TIMage に描画
Image1.Picture.Assign(LBitmap);
Image2.Canvas.Draw(0, 0, LBitmap);
finally
FreeAndNil(LBitmap);
FreeAndNil(LIcon);
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.
02_TIcon.AssignTo を使用したビットマップ画像への変換 |
TIcon.AssignTo メソッドを使用してビットマップ画像に変換する方法の確認テストです.
TIcon.AssignTo メソッドで変換した画像は 32 ビットのアルファチャンネル付きのビットマップ画像となります.TBitmap.Assign(TIcon) でも同じ結果になります.
|
|
図6
TIcon.AssignTo メソッドで TBitmap にアイコン画像を描画
|
|
図7
図5 TIcon.AssignTo メソッドで TBitmap にアイコン画像を描画
- 32 ビットのアイコン画像の場合は正常にビットマップに変換できる
|
リスト2
TIcon.AssignTo (TButmap) を使用してビットマップに変換 |
//=============================================================================
// アイコン画像をビットマップ画像に変換
// TIcon.AssignTo メソッドを使用して変換
// Delphi 2010 以降用
//
// 32 ビット未満の画像は正常に変換できない
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LBitmap : TBitmap;
LIcon : TIcon;
begin
OpenPictureDialog1.Filter := 'アイコンファイル|*.ico';
OpenPictureDialog1.InitialDir := FInitDir;
if not OpenPictureDialog1.Execute then exit;
FInitDir := ExtractFileDir(OpenPictureDialog1.FileName);
FImgFilePath := OpenPictureDialog1.FileName;
Image1.Picture.Assign(nil);
Image2.Picture.Assign(nil);
//透過状態が分かるように背景に市松模様のビットマップ画像を描画
DrawBackGroundImage(Image1.Canvas, FBackImgPath);
DrawBackGroundImage(Image2.Canvas, FBackImgPath);
LBitmap := TBitmap.Create;
LIcon := TIcon.Create;
try
//アイコン画像を読み込む
LIcon.LoadFromFile(FImgFilePath);
LBitmap.Transparent := CheckBox1.Checked;
//アイコン画像からビットマップ画像を作成
LIcon.AssignTo(LBitmap);
//作成した画像を TImage に描画
Image1.Picture.Assign(LBitmap);
Image2.Canvas.Draw(0, 0, LBitmap);
finally
FreeAndNil(LBitmap);
FreeAndNil(LIcon);
end;
end;
03_アイコン画像の色数でビットマップ画像への変換処理を変更 |
変換元のアイコン画像が 32 ビットだった場合は
TIcon.AssignTo を使用し,24 ビット以下だった場合には TBitmap.Canvas にアイコン画像を描画する例です.
アイコン画像のビット数の判定に,以下のサンプルで使用している拙作のユニット内の関数を使用しています.
|
|
図8
アイコン画像のビット数 (色数) を判定して処理を分岐
- 32 ビットの色数のアイコン画像の場合
- 24 ビット以下のアイコン画像も正常にピッマップ画像に変換できる
|
リスト3
アイコン画像の色数でビットマップ画像への変換処理を変更 |
//=============================================================================
// アイコン画像をビットマップ画像に変換
// アイコン画像の色数を判定して処理を分ける方法
//
// 拙作のユニット plExtractMultiIcon を使用
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LBitmap : TBitmap;
LIcon : TIcon;
begin
OpenPictureDialog1.Filter := 'アイコンファイル|*.ico';
OpenPictureDialog1.InitialDir := FInitDir;
if not OpenPictureDialog1.Execute then exit;
FInitDir := ExtractFileDir(OpenPictureDialog1.FileName);
FImgFilePath := OpenPictureDialog1.FileName;
Image1.Picture.Assign(nil);
Image2.Picture.Assign(nil);
//透過状態が分かるように背景に市松模様のビットマップ画像を描画
DrawBackGroundImage(Image1.Canvas, FBackImgPath);
DrawBackGroundImage(Image2.Canvas, FBackImgPath);
LBitmap := TBitmap.Create;
LIcon := TIcon.Create;
try
//アイコン画像を読み込む
LIcon.LoadFromFile(FImgFilePath);
//アイコン画像からビットマップ画像を作成
if GetIconBitCount(LIcon) >= 32 then begin
LIcon.AssignTo(LBitmap);
end else begin
LBitmap.Transparent := CheckBox1.Checked;
LBitmap.SetSize(LIcon.Width, LIcon.Height);
LBitmap.Canvas.Draw(0, 0, LIcon);
end;
//作成した画像を TImage に描画
Image1.Picture.Assign(LBitmap);
Image2.Canvas.Draw(0, 0, LBitmap);
finally
FreeAndNil(LBitmap);
FreeAndNil(LIcon);
end;
end;
04_透過色の値でビットマップ画像への変換処理を変更 |
32 ビットのビットマップの TransparentColor の値が $02000000 になることを利用する方法です.
まず TIcon.AssignTo
でビットマップに変換します.変換後のヒットマップの
TransparentColor の値が $02000000 でない場合は TBitmap.Canvas にアイコン画像を描画して再作成します.
|
|
図9
透過色の値でビットマップ画像への変換処理を変更
- 32 ビットの色数のアイコン画像の場合
- 24 ビット以下のアイコン画像も正常にピッマップ画像に変換できる
|
リスト4
透過色の値でビットマップ画像への変換処理を変更 |
//=============================================================================
// アイコン画像をビットマップ画像に変換
// TIcon.AssignToメソッドで変換する
// 変換後のビットマップが 32 ビットでないビットマップだった場合は
// TCanvas.Draw で変換し直す
//
// 32 ビットのビットマップの TransparentColor の値が $02000000 になることを利用
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LBitmap : TBitmap;
LIcon : TIcon;
LLL : TColor;
begin
OpenPictureDialog1.Filter := 'アイコンファイル|*.ico';
OpenPictureDialog1.InitialDir := FInitDir;
if not OpenPictureDialog1.Execute then exit;
FInitDir := ExtractFileDir(OpenPictureDialog1.FileName);
FImgFilePath := OpenPictureDialog1.FileName;
Image1.Picture.Assign(nil);
Image2.Picture.Assign(nil);
//透過状態が分かるように背景に市松模様のビットマップ画像を描画
DrawBackGroundImage(Image1.Canvas, FBackImgPath);
DrawBackGroundImage(Image2.Canvas, FBackImgPath);
LBitmap := TBitmap.Create;
LIcon := TIcon.Create;
try
//アイコン画像を読み込む
LIcon.LoadFromFile(FImgFilePath);
// ビットマップ画像に変換
LIcon.AssignTo(LBitmap);
// 32 bit のビットマップでない場合は TCanvas.Draw で変換し直す
if LBitmap.TransparentColor <> $02000000 then begin
FreeAndNil(LBitmap);
LBitmap := TBitmap.Create;
LBitmap.Transparent := CheckBox1.Checked;
LBitmap.SetSize(LIcon.Width, LIcon.Height);
LBitmap.Canvas.Draw(0, 0, LIcon);
end;
// 作成した画像を TImage に描画
Image1.Picture.Assign(LBitmap);
Image2.Canvas.Draw(0, 0, LBitmap);
finally
FreeAndNil(LBitmap);
FreeAndNil(LIcon);
end;
end;
24 ビット以下のアイコン画像は全て 24 ビットのビットマップ画像にしてもいいのであれば,以下のように 24 ビットに固定する処理でも十分かも知れません.
|
// ビットマップ画像に変換
LIcon.AssignTo(LBitmap);
// 32 bit のビットマップでない場合は 24 ビットに固定する
if LBitmap.TransparentColor <> $02000000 then begin
LBitmap.PixelFormat := pf24bit;
LBitmap.Transparent := CheckBox1.Checked;
end;
05_TWICImage を使用してイコン画像をビットマップ画像に変換 |
TWICImage を使用してビットマップ画像に変換する方法です.
TIWCImage を使用すると,32 ビットのアイコン画像も 24 ビット未満のアイコン画像もビットマップ画像に変換できます.PNG 形式のアイコン画像もビットマップ画像に変換できます.
マルチアイコンの場合,TWICImagae は,32 x 32 サイズのアイコンがある時はそれを取得します.そのサイズのアイコンがない場合は,32 x 32 に一番近いサイズのアイコンを取得します.
|
|
図10
TWICImage を使用してアイコン画像をビットマップ画像へ変換
- 24 ビットのアイコン画像の場合
- 32 ビットのアルファチャンネル付きのビットマップ画像になる
|
|
図11
図10 TWICImage を使用してアイコン画像をビットマップ画像へ変換
|
リスト6
TWICImage を使用してイコン画像をビットマップ画像に変換 |
//=============================================================================
// アイコン画像をビットマップ画像に変換
// TWICImage を使用して変換する方法
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LWICImage : TWICImage;
LBitmap : TBitmap;
begin
OpenPictureDialog1.Filter := 'アイコンファイル|*.ico';
OpenPictureDialog1.InitialDir := FInitDir;
if not OpenPictureDialog1.Execute then exit;
FInitDir := ExtractFileDir(OpenPictureDialog1.FileName);
FImgFilePath := OpenPictureDialog1.FileName;
Image1.Picture.Assign(nil);
Image2.Picture.Assign(nil);
//透過状態が分かるように背景に市松模様のビットマップ画像を描画
DrawBackGroundImage(Image1.Canvas, FBackImgPath);
DrawBackGroundImage(Image2.Canvas, FBackImgPath);
LWICImage := TWICImage.Create;
LBitmap := TBitmap.Create;
try
//アイコン画像を読み込む
LWICImage.LoadFromFile(FImgFilePath);
// TWICImage を保存するとビットマップ画像ファイルになる
LWICImage.ImageFormat := wifBmp;
// TBitmap に代入
LBitmap.Assign(LWICImage);
// 作成した画像を TImage に描画
Image1.Picture.Assign(LBitmap);
Image2.Canvas.Draw(0, 0, LBitmap);
finally
FreeAndNil(LBitmap);
FreeAndNil(LWICImage)
end;
end;
06_TWICImage を使用しアてイコン画像を TImage に描画 |
TWICImage にアイコン画像を読み込んで TImage に描画すると,32 ビットのアイコン画像も 24 ビット未満のアイコン画像も正常に描画できます.PNG 形式のアイコン画像も描画できます. |
|
図12
アイコン画像を TImage に描画
- 8 ビットのアイコン画像の場合
- 32 ビットのアイコン画像も正常に描画できる
- PNG 形式のアイコン画像も描画できる
|
リスト7
TWICImage を使用しアてイコン画像を TImage に描画 |
//=============================================================================
// TWICImage を使用してイコン画像を TImage に描画
// PNG 形式のアイコン画像も描画可能
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LWICImage : TWICImage;
begin
OpenPictureDialog1.Filter := 'アイコンファイル|*.ico';
OpenPictureDialog1.InitialDir := FInitDir;
if not OpenPictureDialog1.Execute then exit;
FInitDir := ExtractFileDir(OpenPictureDialog1.FileName);
FImgFilePath := OpenPictureDialog1.FileName;
Image1.Picture.Assign(nil);
Image2.Picture.Assign(nil);
//透過状態が分かるように背景に市松模様のビットマップ画像を描画
DrawBackGroundImage(Image1.Canvas, FBackImgPath);
DrawBackGroundImage(Image2.Canvas, FBackImgPath);
LWICImage := TWICImage.Create;
try
//アイコン画像を読み込む
LWICImage.LoadFromFile(FImgFilePath);
//画像を TImage に描画
Image1.Picture.Assign(LWICImage);
Image2.Canvas.Draw(0, 0, LWICImage);
finally
FreeAndNil(LWICImage)
end;
end;
上のコードで TWICImage の代わりに TIcon を使用して,Icon にアイコン画像を読み込んで TImage に描画すると下図のようになります.この状態は,透過ピクセル,あるいは透明ピクセルの処理が正しく処理されていない結果です.
|
[備考]
TImage に アイコン画像のオブジェクト,または メタファイル画像のオブジェクトを描画している状態の時に TImage.Picture.Bitmap を参照すると,それらのオブジェクトは破棄されます.代わりに空のビットマップが生成されます.
TImage.Picture.Bitmap のプロパティを操作しても,表示中の画像は変化しません.
|
|
図13
TIcon にアイコン画像を読み込んで TImage に描画した結果 |
07_TKIcon を使用してイコン画像をビットマップ画像に変換 |
マルチアイコン操作用の TKIcon クラスを使用する例です.
32 ビットのアイコン画像からは 32 ビットのビットマップ画像を取得します.24 ビット以下のアイコン画像からは 24 ビットのビットマップ画像を作成するようにしています.
TKIcon はアイコン画像を PNG 画像として取得する関数があります.それを利用して PNG 形式のアイコン画像の時は PNG 画像として取得するようにしています.
|
リスト8
TKIcon を使用してイコン画像をビットマップ画像または PNG 画像に変換 |
//=============================================================================
// アイコン画像をビットマップ画像または PNG 画像に変換
// TKIcon を使用する方法
// PNG 形式のアイコンは TPngImage の画像にする
//
// TKIcon はマルチアイコン操作用なので,アイコン画像のインデックスを指定する
// シングルアイコンの場合は,このインデックスは 0 にする
//
// uses に pngimage, KIcon が必要
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LBitmap : TBitmap;
LPngImage : TPngImage;
LIconNo : Integer;
LKicon : TKIcon;
LIconData : TKIconData;
begin
OpenPictureDialog1.Filter := 'アイコンファイル|*.ico';
OpenPictureDialog1.InitialDir := FInitDir;
if not OpenPictureDialog1.Execute then exit;
FInitDir := ExtractFileDir(OpenPictureDialog1.FileName);
FImgFilePath := OpenPictureDialog1.FileName;
Image1.Picture.Assign(nil);
Image2.Picture.Assign(nil);
// 透過状態が分かるように背景に市松模様のビットマップ画像を描画
DrawBackGroundImage(Image1.Canvas, FBackImgPath);
DrawBackGroundImage(Image2.Canvas, FBackImgPath);
LKicon := TKIcon.Create;
LBitmap := TBitmap.Create;
LPngImage := TPngImage.Create;
try
// アイコン画像を読み込む
LKicon.LoadFromFile(FImgFilePath);
LIconNo := 0;
LIconData := LKicon.IconData[LIconNo];
// PNG 形式のアイコンの場合は TPngImage オブジェクトにする
if LIconData.IsPNG then begin
// アイコン画像を TPngImage の画像にする
LKicon.CopyToPng(LIconNo, LPngImage);
// PNG 画像を描画
Image1.Picture.Assign(LPngImage );
Image2.Canvas.Draw(0, 0, LPngImage);
end else begin
// アイコン画像を TBitmap の画像にする
LKicon.CopyToBitmap(LIconNo, LBitmap);
// 32 ビットのアイコンの時はアルファチャンネルが有効な TBitmap にする
if LIconData.Bpp = 32 then begin
LBitmap.AlphaFormat := afDefined;
end else begin
LBitmap.PixelFormat := pf24bit;
LBitmap.Transparent := CheckBox1.Checked;
end;
// ビットマップ画像を描画
Image1.Picture.Assign(LBitmap);
Image2.Canvas.Draw(0, 0, LBitmap);
end;
finally
FreeAndNil(LBitmap);
FreeAndNil(LPngImage);
FreeAndNil(LKicon);
end;
end;
TKIcon にアイコン画像を読み込んで TImage に描画すると,32 ビットのアイコン画像も 24 ビット未満のアイコン画像も正常に描画できます.PNG 形式のアイコン画像も描画できます.
|
|
図14
TKIcon に読み込んだアイコン画像を TImage に描画
- 8 ビットのアイコン画像の場合
- 32 ビットのアイコン画像も正常に描画できる
- PNG 形式のアイコン画像も描画できる
|
LKicon := TKIcon.Create;
try
// アイコン画像を読み込む
LKicon.LoadFromFile(FImgFilePath);
Image1.Picture.Assign(LKicon);
Image2.Canvas.Draw(0, 0, LKicon);
finally
FreeAndNil(LKicon);
end;
|