Developing with Graphics/ja
│
Deutsch (de) │
English (en) │
español (es) │
français (fr) │
italiano (it) │
日本語 (ja) │
한국어 (ko) │
Nederlands (nl) │
português (pt) │
русский (ru) │
slovenčina (sk) │
中文(中国大陆) (zh_CN) │
中文(臺灣) (zh_TW) │
このページは、どのようにビットマップや、その他のグラフィックスを扱うかのチュートリアルの最初のページになるでしょう。 私はグラフィクスに携わっていないので、専門的な経験を披露してくれる皆さんを招待します。 次の項目にリンクやページを追加して、Wikiを製作してください。
このページで、一般的なお知らせをすることがあります。
その他のグラフィックス
- GLScene/ja - OpenGL ライブラリの移植 GLScene
- TAChart/ja - Lazarus用のチャートコンポーネント
- PascalMagick/ja - インターフェース用の簡単なAPI ImageMagick,マルチプラットホームでのビットマップを扱うフリーソフトウエア
- PlotPanel/ja - アニメーショングラフのためのチャートや描画コンポーネント
TBitmapの作業
まず覚えていただきたいことは、Lazarusはプラットホームに対して独立しているということです。 ですから、WindowsAPIの機能を使うメソッドは言うまでもなく、つかわないでください。 たとえば、Scanlineのようなメソッドは、Lazarusではサポートしません。 なぜなら、ScanlineはDevice Independant Bitmap(DIB)を扱い、結局GDI32.dllを使うことになるから(プラットホーム独立ではなくなるから)です。
TBitmapにwidth,heightを特定しないなら、デフォルトはかなり小さいものになっているので、気をつけてください。
フェーディングの例
フェーディングするピクチャを作る場合、Delphiでは、このように書けます。
type
PRGBTripleArray = ^TRGBTripleArray;
TRGBTripleArray = array[0..32767] of TRGBTriple;
procedure TForm1.FadeIn(aBitMap: TBitMap);
var
Bitmap, BaseBitmap: TBitmap;
Row, BaseRow: PRGBTripleArray;
x, y, step: integer;
begin
Bitmap := TBitmap.Create;
try
Bitmap.PixelFormat := pf32bit; // or pf24bit
Bitmap.Assign(aBitMap);
BaseBitmap := TBitmap.Create;
try
BaseBitmap.PixelFormat := pf32bit;
BaseBitmap.Assign(Bitmap);
for step := 0 to 32 do begin
for y := 0 to (Bitmap.Height - 1) do begin
BaseRow := BaseBitmap.Scanline[y];
Row := Bitmap.Scanline[y];
for x := 0 to (Bitmap.Width - 1) do begin
Row[x].rgbtRed := (step * BaseRow[x].rgbtRed) shr 5;
Row[x].rgbtGreen := (step * BaseRow[x].rgbtGreen) shr 5; // Fading
Row[x].rgbtBlue := (step * BaseRow[x].rgbtBlue) shr 5;
end;
end;
Form1.Canvas.Draw(0, 0, Bitmap);
InvalidateRect(Form1.Handle, nil, False);
RedrawWindow(Form1.Handle, nil, 0, RDW_UPDATENOW);
end;
finally
BaseBitmap.Free;
end;
finally
Bitmap.Free;
end;
end;
上の関数は、Lazarusでは、このように実装します:
procedure TForm1.FadeIn(ABitMap: TBitMap);
var
SrcIntfImg, TempIntfImg: TLazIntfImage;
ImgHandle,ImgMaskHandle: HBitmap;
FadeStep: Integer;
px, py: Integer;
CurColor: TFPColor;
TempBitmap: TBitmap;
begin
SrcIntfImg:=TLazIntfImage.Create(0,0);
SrcIntfImg.LoadFromBitmap(ABitmap.Handle,ABitmap.MaskHandle);
TempIntfImg:=TLazIntfImage.Create(0,0);
TempIntfImg.LoadFromBitmap(ABitmap.Handle,ABitmap.MaskHandle);
TempBitmap:=TBitmap.Create;
for FadeStep:=1 to 32 do begin
for py:=0 to SrcIntfImg.Height-1 do begin
for px:=0 to SrcIntfImg.Width-1 do begin
CurColor:=SrcIntfImg.Colors[px,py];
CurColor.Red:=(CurColor.Red*FadeStep) shr 5;
CurColor.Green:=(CurColor.Green*FadeStep) shr 5;
CurColor.Blue:=(CurColor.Blue*FadeStep) shr 5;
TempIntfImg.Colors[px,py]:=CurColor;
end;
end;
TempIntfImg.CreateBitmap(ImgHandle,ImgMaskHandle,false);
TempBitmap.Handle:=ImgHandle;
TempBitmap.MaskHandle:=ImgMaskHandle;
Canvas.Draw(0,0,TempBitmap);
end;
SrcIntfImg.Free;
TempIntfImg.Free;
TempBitmap.Free;
end;
このページのLazarusのコードは、 $LazarusPath/examples/lazintfimage/fadein1.lpi のプロジェクトから取ってきたものです。 もし、あなたが画像処理プログラムで早いスタートをしたいなら、この例を良く読みましょう。
色(が)透明なビットマップを描く
Lazarus 0.9.11で実装された新しい機能で、色透明ビットマップを描画することができます。 ビットマップファイル(*.BMP)は、透明性のどんな情報を持つことができません。しかし、ビットマップ上のある色を透明色と選択すれば、色透明ビットマップにすることができます。これは、Win32アプリケーションでよくつかわれてきたトリックです。
次のサンプルはWindowsのリソースからビットマップをロードし、透明となる色(clFuchsia)を指定し、canvasに描画します。
procedure MyForm.MyButtonOnClick(Sender: TObject); var buffer: THandle; bmp: TBitmap; memstream: TMemoryStream; begin bmp := TBitmap.Create; buffer := Windows.LoadBitmap(hInstance, MAKEINTRESOURCE(ResourceID)); if (buffer = 0) then exit; // Error loading the bitmap bmp.Handle := buffer; memstream := TMemoryStream.create; try bmp.SaveToStream(memstream); memstream.position := 0; bmp.LoadFromStream(memstream); finally memstream.free; end; bmp.Transparent := True; bmp.TransparentColor := clFuchsia; MyCanvas.Draw(0, 0, bmp); bmp.Free; // Release allocated resource end;
TMemoryStreamでメモリ操作を行っていることに注意してください。 それらは、読み込んだイメージを確実に操作するのに必要です。
動きのあるグラフィックス - チラツキを防止する方法
多くのプログラムが、2D画像としてGUIを描画します。 それらの画像は、高速に変更する必要がある場合、すぐ次のような問題に直面します。高速に更新する画像は、しばしばスクリーン上でチラツキをおこします。 時々、全体的なイメージをユーザーが見ている時、ほんの一部分だけ描画される時、発生します。 それは、描画の作業に時間がかかるのでおこります。
しかし、どのようにしたらチラツキを防止し、最善の描画速度を得ることができるのでしょうか。もちろん、OpenGLを使ったハードウエアアクセラレーションを使うこともできます。しかし、この方法は小さなプログラムや古いコンピュータには、大変重いものです。 このチュートリアルでは、TCanvasに描画する方法に焦点をしぼります。 もし、OpenGLの助けが必要であれば、Lazarusについてくるサンプルを見てください。ほかにも、ダブルバッファをサポートしたcanvasや、スプライトコンポーネントのあるA.J.Venterのgamepackを使うこともできます。
それでは、Canvasに描画するオプションを調べてみましょう。
- Draw to a TImage
- Draw on the OnPaint event of the form, a TPaintBox or another control
- Create a custom control which draws itself
- Using A.J. Venter's gamepack
TImageに描画する
TImageに描画するのにOnPaintイベントを使ってはいけません。 TImageはバッファされていますので、あなたが一度描画したり変更しさえすれば、TImageはずっとそのイメージを持続します。 しかし、コンスタントに再描画をおこなえば、チラツキが発生するでしょう。 この場合に、他の方法を試します。 TImageに描画することは、ほかの方法よりも遅いのです。
procedure TForm1.BitBtn1Click(Sender: TObject);
var
x, y: Integer;
begin
// Draws the backgroung
MyImage.Canvas.Pen.Color := clWhite;
MyImage.Canvas.Rectangle(0, 0, Image.Width, Image.Height);
// Draws squares
MyImage.Canvas.Pen.Color := clBlack;
for x := 1 to 8 do
for y := 1 to 8 do
MyImage.Canvas.Rectangle(Round((x - 1) * Image.Width / 8), Round((y - 1) * Image.Height / 8),
Round(x * Image.Width / 8), Round(y * Image.Height / 8));
end;
OnPaintイベントで描画する
この場合、フォームのOnPaintイベントで、すべての描画が終了しなければなりません。この方法ではTImageのように、バッファには残りません。
自分自身を描画するカスタムコントロールを作成する
カスタムコントロールを作成することは、あなたのコードを構造化し、そのコントロールを再利用できる、という利点があります。 この方法はとても高速ですが、まず、TBitmapに描画して、canvasにそれを転送しなければ、チラツキを発生することがあります。この方法では、コントロールのOnPaintイベントを必要としません。
カスタムコントロールの例:
type
TMyDrawingControl = class(TCustomControl)
public
procedure Paint; override;
end;
implementation
procedure TMyDrawingControl.Paint;
var
x, y: Integer;
Bitmap: TBitmap;
begin
Bitmap := TBitmap.Create;
try
// Initializes the Bitmap Size
Bitmap.Height := Height;
Bitmap.Width := Width;
// Draws the background
Bitmap.Canvas.Pen.Color := clWhite;
Bitmap.Canvas.Rectangle(0, 0, Width, Height);
// Draws squares
Bitmap.Canvas.Pen.Color := clBlack;
for x := 1 to 8 do
for y := 1 to 8 do
Bitmap.Canvas.Rectangle(Round((x - 1) * Width / 8), Round((y - 1) * Height / 8),
Round(x * Width / 8), Round(y * Height / 8));
Canvas.Draw(0, 0, Bitmap);
finally
Bitmap.Free;
end;
inherited Paint;
end;
フォーム上で生成する方法は次のとおりです:
procedure TMyForm.FormCreate(Sender: TObject);
begin
MyDrawingControl:= TMyDrawingControl.Create(Self);
MyDrawingControl.Height := 400;
MyDrawingControl.Width := 500;
MyDrawingControl.Top := 0;
MyDrawingControl.Left := 0;
MyDrawingControl.Parent := Self;
MyDrawingControl.DoubleBuffered := True;
end;
destroyを忘れてはいけない。
(訳注: CreateでFormのSelfを指定しているから、いらないのでは?)
just don´t forget to destroy it:
procedure TMyForm.FormDestroy(Sender: TObject);
begin
MyDrawingControl.Free;
end;
TopとLeftは、0が標準の位置なので、かならずしも設定する必要はありません。 しかし、これは、コントロールが置かれる位置を再設定します。
"MyDrawingControl.Parent := Self;"は、とても重要です。これを書かなくては、コントロールが表示されません。
"MyDrawingControl.DoubleBuffered := True;" は、Windows上でチラツキを防止するためのものです。gtk上では何の効果もありません。 (訳注:gtk上では、効果がないのか、そもそも、DoubleBufferdを指定する必要がないのか?どっちだろう。)
A.J.Venterのgamepackを使う
gamepackによる方法は、すべてのものを、1つのダブルバッファされたcanvasに描画してしまおう、というものです。あなたが更新を準備できた時点で、、見えるcanvasの変更をおこなうことができます。多少コードを必要としますが、多くのスプライトをもつ"シーン"を、大幅に高速に描画更新できる、という利点があります。もし、このアプローチを使いたくなったら、Lazarusのゲーム開発コンポーネントセットであるA.J.Venterのgamepackに興味をもったでしょう。gamepackは、スプライト同様にダブルバッファを表示するエリアを提供してくれますし、ひとつひとつが、大変上手く統合されています。
gamepackはsubversionを通して得ることができます。
svn co svn://silentcoder.co.za/lazarus/gamepack