Delphi 2009におけるグラフィック機能の強化点
この記事は以前EDNサイトに作成されていた記事を転載したものです。 ヘルプ・ドキュメントの箇所を除き、当時の内容のまま掲載しています。
目次
概要
Delphi 2009で強化されたグラフィック機能について解説します。
Delphi 2009ではTBitmapの32ビット形式サポート、PNGサポート、TCanvas.Drawメソッドの拡張、TImageListの拡張など、グラフィック機能の強化も行われています。今回は新しいグラフィック機能についてできるだけ網羅的に解説を行います。
TBitmap
32ビット形式のサポート
Delphi 2009ではTBitmapが32ビット形式をサポートしました。32ビット形式のビットマップは1ピクセルあたりに4バイトのデータを割り当てており、RGB各色が1バイトずつ使用し、更にアルファチャンネル用に1バイトを使用します。32ビット形式ではアルファチャンネルの情報を設定することで半透明なビットマップを作ることが可能です。
なお、アルファチャンネルの値が取り得る値は0~255で、0だと完全に透明、255だと完全に不透明になります。
- 32ビット形式のビットマップを表示する
- まず最も簡単な例として、既存の32ビット形式のビットマップファイルを読み込んで、TImageに表示するプログラムを作成してみます。なお、読み込む画像は幅・高さ共に100ピクセルで、TImageの幅・高さも100に設定しておきます。
- 読み込む画像(幅100ピクセル、高さ100ピクセル)
- 画像に設定されたアルファ値(黒いほど透明、白いほど不透明)
- Code#001:TImageへの読み込み
//Code#001:TImageへの読み込み begin //Draw Image Image1.Picture := nil; Image1.Picture.LoadFromFile('32bitbitmap.bmp'); Image1.Picture.Bitmap.AlphaFormat := afDefined;//重要! end;
- コード自体はとても簡単です。ビットマップファイルをLoadFromFileで読み込めば良いだけです。ただし、読み込んだ後にTImage.Picture.BitmapのAlphaFormatプロパティをafDefinedに設定しなければなりません。設定を忘れてしまうと画像のアルファチャンネルの値が無視されて表示されてしまいます。その他の注意点は特にありません。実行結果は以下のようになります。
- 実行結果
Canvas.Drawで描画する場合
先ほどの例ではTImageを使いましたが、実用的なグラフィックプログラムであればTPaintBoxなどに描画するのが一般的です。今度はTPaintBoxのCanvasに描画を行ってみます。なお、用いる画像は先ほどの例と全く同じものです。
- Code#002:Canvas.Drawによる描画
var BMP: TBitmap; begin //Draw at Canvas BMP := TBitmap.Create; try BMP.LoadFromFile('32bitbitmap.bmp'); BMP.AlphaFormat := afDefined; PaintBox1.Canvas.Draw(0,0,BMP); finally BMP.Free; end; end;
- こちらも簡単なコードです。TBitmapのインスタンスを生成し、LoadFromFileを使ってファイルを読み込みます。やはりここでもAlphaFormatプロパティの設定が重要になっています。Canvas.Drawを実行する前にAlphaFormatプロパティをafDefinedに設定する必要があります。これを怠ると、やはりアルファチャンネルの値が無視されて描画されてしまいます。このコードの実行結果は以下の通りです。
- 実行結果
- ※Point
- 表示・描画の際には、AlphaFormatプロパティをafDefinedに設定することを忘れないようにしましょう。
アルファチャンネルの生成
今度は、既存の24ビット形式のビットマップ画像に対してアルファチャンネルを生成してみます。使用する画像は先ほどと同じ物(但しアルファチャンネルは未設定)です。また、描画はPaintBoxのCanvasに対して行います。
- Code#003:アルファチャンネルの生成
//Code#003:アルファチャンネルの生成 type TRGBQArray = array [0..High(Integer) div 4 - 1] of RGBQUAD; PRGBQArray = ^TRGBQArray; var BMP: TBitmap; PQ: PRGBQArray; i: Integer; ii: Integer; begin //Create Alpha BMP := TBitmap.Create; try BMP.LoadFromFile('24bitbitmap.bmp'); BMP.PixelFormat := pf32bit; {1ピクセルずつアルファチャンネルの値を設定} for i := 0 to BMP.Height - 1 do begin PQ := BMP.ScanLine[i];//RGBQuadの配列へのポインタを代入する for ii := 0 to BMP.Height - 1 do begin TRGBQuad(PQ[ii]).rgbReserved := 64;//アルファチャンネルの値を64に設定 end; end; BMP.AlphaFormat := afDefined; PaintBox1.Canvas.Draw(0,0,BMP); finally BMP.Free; end; end;
- まず、TBitmapのインスタンスを生成し、画像を読み込みます。次に、PixelFormatプロパティをpf32bitに設定し、アルファチャンネルを設定できるようにします。その後は、ScanLineプロパティを使って1ピクセルずつアルファチャンネルの値を設定していきます。描画時の注意点は先ほどのCanvas.Drawの時と同じです。
- 実行結果は以下の通りになります。
- 画像全体に同じアルファチャンネルの値を設定したため、画像全体がちゃんと半透明で表示されていますね。
PNGのサポート
新たに追加されたTPNGImage
Delphi 2009からはついにPNGが標準でサポートされました。これでようやくビットマップ、JPEG、GIF、PNGの標準的なライブラリが全て揃ったことになります。
PNGを扱うクラスはTPNGImageです。使用するにはまずuses節にPNGImageを追加します
- JPEG、PNG、GIFのユニット名
- 困ったことに、JPEG、GIF、PNGのユニット名は命名規則が統一されていません。
- JPEG:JPEG.pas(Delphi 3から)
- GIF:GIFImg.pas(Delphi 2007から)
- PNG:PNGImage.pas(Delphi 2009から)
- これは、元々GIFがAnders Melander氏制作のライブラリ、PNGがGustavo Huffenbacher Daud氏制作のライブラリであるからです。
- ドキュメント
PNGの作成・読み込み・保存
TPNGImageの使い方は非常に簡単で、TJPEGImageのようなグラフィッククラスを使ったことがあればすぐに使いこなせるように出来ています。 ここではまず、ビットマップをPNGに変換してファイルに保存する例を見てみます。
- Code#004:BitmapからPNGへの変換
//Code#004:BitmapからPNGへの変換 uses ・・・・, PNGImage; {略} var BMP: TBitmap; PNG: TPNGImage; begin BMP := TBitmap.Create; PNG := TPNGImage.Create; try BMP.LoadFromFile('hogehoge.bmp');//24bit Bitmap PNG.Assign(BMP); PNG.CompressionLevel := 5; PNG.Filters := [pfNone,pfSub,pfUp,pfAverage,pfPaeth]; PNG.SaveToFile('HogeHoge.png'); finally BMP.Free; PNG.Free end; end;
- ビットマップを変換してPNGを生成するのもJPEGと同じ要領で、極めて簡単です。AssignするだけでOKです。ただし、Assignの引数に指定するビットマップが32ビット形式の場合はエラーを起こしてしまいます。32ビット形式から変換をする際には別の変換方法を採用しなければなりません。
- PNGの圧縮レベルはCompressionLevelプロパティで指定します。JPEGの際は1~100の整数値を指定し、数値が大きいほど高品質(=ファイルサイズは大きい)でした。PNGの場合は、0~9の整数値を指定し、数値が小さいほど速度重視(=ファイルサイズは大きい)、数値が大きいほど圧縮率重視(=ファイルサイズは小さい)になります。
- PNGのフィルターはFiltersプロパティで指定します。Filtersプロパティには複数のフィルターを指定することが可能です。フィルターはpfNone、pfSub、pfUp、pfAverage、pfPaethの5種類を指定できます。特段の理由がなければ上記コードのように全てのフィルターを指定することが推奨されています。
- ファイルの読み込みについてはLoadFromFile、ファイルへの保存についてはSaveToFileメソッドが使えます。つまり、TBitmapやTJPEGImageと全く同じ要領でPNGファイルの読み書きが可能です。
アルファチャンネル
TPNGImageはアルファチャネルもサポートしています。ここでは、既存の24ビットPNG画像に対して新たにアルファチャンネルを設定する例を紹介します。アルファチャネルを設定するには、AlphaScanlineを使うと便利です。
- Code#005:アルファチャンネルの作成
//Code#005:アルファチャンネルの作成 var i,ii: Integer; PNG: TPNGImage; begin PNG := TPngImage.Create; try PNG.LoadFromFile('alpha.png');//24bit PNG(No Alpha) PNG.CreateAlpha;//アルファチャンネルの生成 {1ピクセルずつアルファチャンネルの値を設定} for i := 0 to PNG.Height - 1 do begin for ii := 0 to PNG.Width - 1 do begin PNG.AlphaScanline[i]^[ii] := 128; end; end; PNG.SaveToFile('alpha.png'); finally PNG.Free; end; end;
- まずTPNGImageのインスタンスを生成し、ファイルを読み込みます。次にCreateAlphaメソッドを実行します。32ビット形式でないPNG画像の場合はCreateAlphaメソッドを実行してからではないとアルファチャンネルの設定が出来ません。CreateAlphaメソッドを実行したら、1ピクセルずつAlphaScanlineを使ってアルファチャンネルの値を設定していきます。
- 実行結果は以下の通りです。
- 画像全体が半透明で表示されています。TBitmapと違い、表示前にAlphaFormatプロパティを設定するといったような作業は不要です。
32ビット形式のビットマップからの変換
PixelFormat = pf32bitのTBitmapから直にAssignするとエラーになるので、若干面倒なコードを書かなければなりません。
- Code#006:32ビット形式のビットマップからの変換
//Code#006:32ビット形式のビットマップからの変換 type TRGBQArray = array [0..High(Integer) div 4 - 1] of RGBQUAD; PRGBQArray = ^TRGBQArray; TRGBTArray = array [0..High(Integer) div 3 - 1] of RGBTRIPLE; PRGBTArray = ^TRGBTArray; var PNG: TPngImage; i,ii: Integer; BPQ: PRGBQArray; CQ: RGBQUAD; PPT: PRGBTArray; CT: RGBTRIPLE; BMP: TBitmap; begin BMP := TBitmap.Create; PNG := TPngImage.CreateBlank(COLOR_RGBALPHA,8,100,100); try BMP.LoadFromFile('original.bmp'); for i := 0 to BMP.Height - 1 do begin BPQ := BMP.ScanLine[i]; PPT := PNG.ScanLine[i]; for ii := 0 to BMP.Width - 1 do begin CQ := BPQ[ii]; CT.rgbtBlue := CQ.rgbBlue; CT.rgbtGreen := CQ.rgbGreen; CT.rgbtRed := CQ.rgbRed; PPT[ii] := CT; PNG.AlphaScanline[i]^[ii] := CQ.rgbReserved; end; end; PNG.SaveToFile('result.png'); finally BMP.Free; PNG.Free; end; end;
- まず、TPNGImageのインスタンスをCreateメソッドではなくCreateBlankメソッドで作成します。なぜなら、TPNGImageのWidthとHeightはReadOnlyなので、新しい値を代入できません。今回のコードでは空のPNGにビットマップの情報を1ピクセルずつ移植するという処理なので、WidthとHeightを設定しないままTPNGImageのインスタンスを生成するCreateは役に立ちません。
- CreateBlankメソッドの第1引数にはCOLOR_RGBALPHAを指定します。これで32ビット形式のPNGとなるので、別途CreateAlphaメソッドを実行する必要がなくなります。第2引数は8をセットしておけば1ピクセルあたりの情報量はRGBAの4バイトになります。第3,4引数には新しいイメージの幅と高さ(今回の例では両方ともビットマップ画像の幅と高さである100)をセットします。
- 変換はビットマップの各ピクセルの情報のうち、RGBをRGBTripleの変数を経由してScanlineで、Alpha値をAlphaScanlineで渡しています。
TCanvas
半透明描画が可能なDrawメソッド
TCanvas.Drawメソッドに新しくオーバーロードが追加されました。従来は引数が3つでしたが、新たなオーバーロードは4つめの引数にOpacityというバイト型をとる物が追加されています。これは描画時にOpacityに値を指定することによって、Graphicで指定した画像を半透明で描画することが出来るという機能です。
- Code#007:TCanvas.Drawのオーバーロード
//Code#007:TCanvas.Drawのオーバーロード var BMP: TBitmap; begin BMP := TBitmap.Create; try BMP.LoadFromFile('original.bmp'); PaintBox1.Canvas.Draw(0,0,BMP); PaintBox2.Canvas.Draw(0,0,BMP,64); finally BMP.Free; end; end;
TImageList
PNGおよび32ビット形式ビットマップのサポート
PNGのサポートと32ビット形式のサポートに伴い、TImageListもこれらの形式に対応しました。PNGの表示はもちろん、アルファチャンネルにも対応しているため、半透明な画像を表示することも可能です。
今回はDelphi 2009に付属しているグラフィック素材集であるGlyFXに収録されている32x32のPNGイメージ(アルファチャンネル設定済み)をTImageListに読み込んで、それらをTListViewに表示してみます。
- Step1:Width、Height、ColorDepthの設定
- まず、画像を追加する前にTImageListのWidthとHeightをそれぞれ画像の幅と高さに合わせます。今回は両方とも32に設定しておきます。それから、非常に重要なことですが、32ビット形式のビットマップまたはPNGを追加する際には、画像を追加する前にColorDepthプロパティをcd32bitに設定する必要があります。画像の追加後にColorDepthプロパティの設定を変更すると、TImageListに追加されていた画像が全て消えてしまいます。
- Step2:画像の追加