Bitmapでピクセルに対して操作しようとしたら。。。
FireMonkeyのTBitmapクラスには、VCLで存在していたScanlineがない。
これだと1ピクセルずつ描画していくような処理をする場合に結構困る。
で、どうするかというと
TBitmapDataレコードを使う
こちらの記事で紹介されているTBitmapDataレコードを使う方法でいけることはわかった。
TBitmapData.DataフィールドにはBitmapのピクセルデータ配列のポインタが格納されている。
これをTAlphaColorArrayとして考え、各ピクセルに対して色情報を与える。
というもの。
TBitmapDataにはScanlineメソッドなども用意されているが、直接アドレス指定した方が処理は早いようだ。
問題点
上記記事のソースでは
YAddr := Y * Bmp.Height;
としているが、実際には
YAddr := Y * Bmp.Width;
が正しいと思われる。
TAlphaColorArrayにはビットマップの左上から1行ずつ並べたデータが配置されている。
つまり2行目の一番左のピクセルのインデックスは、1行分のピクセルということになる。
ダウンロードしたテストソースをいじって確認したけど、やはりWidthで間違いないと思う。
そして更に問題。
ダウンロードしたソースではWidthであっていたのだが、自作クラスの中にこれを組み込もうとしたときに、イメージと実際の描画がずれていた。
原因を探ってみると、どうやらTBitmapDataレコードのPitchフィールドに代入されている値が違うことがわかった。
TBitmapDataレコードの詳細な解説があまり見つからなかったが、これはどうやら1行あたりのバイト数を表しているようだ。
更に、BytesPerPixelプロパティを参照すれば1ピクセルあたりのバイト数がわかる。
つまり、Pitch = Width ✕ BytesPerPixelとなる。。。
と思っていた。でも違った。。。
ダウンロードしたプロジェクトではそうなっていたのだが、自分ので実行してみるとPitchが想定より十数Byteほど多くなっていた。
これのせいでズレが生じていたわけだが、なぜそうなるのかがさっぱりわからない。
ひとまず上記のソースは
YAddr := Y * (BmpData.Pitch div BmpData.BytesPerPixel);
としておくほうが良さそう。
この修正を入れることでイメージ通りの描画はしてくれるようになった。
それにしてもなぜズレるのか。。。時間がないので深入りして調べることはできなかったので、いずれちゃんと調べたいとは思う。
ディスカッション
コメント一覧
まだ、コメントがありません