ビットマップを高速処理ビットマップを高速処理VB6がリリースされた後、VBステップアップ講座の第2段を思い立ったのが3年前の98年、月日が経つのは早いものです。その間、更新しなければ...と思いながらも色んな事情が重なって続きを書くことができませんでした。2001年も残すところ僅かとなった今日この頃、VBのバージョン7とも言えるVB.NETがリリースされ、VB6もやがてはすてれていくのかなぁなどと感慨に耽る間もなく、日々職業プログラマとしてVBプログラミングに勤しんでいます。VB6はリリース当時の私の心配とは裏腹に、まさに大ヒットしたツールだと思います。ビジネスプログラミングの業界ではVBはデファクトスタンダードと言っても過言ではないでしょう。Basicという取っ付きやすい言語で敷居も広く、インターネット上での情報も豊富でVB人口はVB6の発売以来爆発的に増えたようです。裾野は広がったものの、業界ではVBのプログラマはいまだに人手不足状態です。VB.NETでは言語仕様がかなり変更されたようですが、機会があれば取り上げてみたいと思っています。昔からBasicといえば「遅い」というのが常識でした。Windows以前のN88-Basic時代から、「Basicといえば入門用にはいいんだけど、実行速度が遅いから実用には向かないね」というのあ通説で、スピードを稼ぐためにアセンブラやC言語に走ったものです。Basicも「入門言語」の域を脱し、ビジネスはじめあらゆるアプリケーションの開発に標準で使われれつつあります。一般的なアプリケーションならBasicの最大の欠点である「遅さ」はそれほど目立たなくなてtきました。グラフィックの処理ではやっぱりBasicの「遅さ」が足かせになってしまいます。ビットマップ画像のピクセルを処理するには、VBの標準ではPointやPsetメソッドを使用することになっていますが、これらを使って画像全体にエフェクトをかけるような処理をするとうんざりするほど時間がかかってしまいます。前置きが長くなりましたが、今回はVBで少しでも高速にビットマップを扱えるようAPIを使った例を紹介します。(今回のサンプルプロジェクトはここを押すとダウンロードできます)サンプルではファイルサイズを小さくするため、画像を張りつけてない状態で保存しています。最初にプロジェクトファイルを開き、Form1を表示してください。空のピクチャーボックスがあるので、プロパティのPictureで適当な画像ファイルを指定してピクチャーボックス上に何か画像を表示してください。選択した画像がピクチャーボックス上に表示されます。プログラムを実行してCommand1ボタンを押すと、画像の色が反転します。プログラムの内容はいたって簡単なものです。Sub今回使用するAPI関数は、GetObject、GetBitmapBits、SetBitmapBitsの3つです。関数の内容は順を追って説明します。ビットマップ情報を入れるためにBITMAP構造体を使用します。これらはVB6に付属のAPIビューアからコピー&ペーストすることができます。Command1_Click()の中を見てみましょう。bmpGeObjectは、オブジェクトに関する情報を取り出す関数です。ペン、DIB(デバイス独立ビットマップ)で、オブジェクトのハンドルを第1引数に渡すことでそれに見合った情報を返してくれます。ビットマップのハンドルであるPicture1.Picture.Handleを渡すと、ビットマップに関する情報が返ってくるのでBITMAP構造体型のあるbmpという変数も渡してやります。2番目のLen(bmp)は、関数に受け取る領域の大きさを知らせることで不正なメモリエラーを防ぐためです。1)ここでは、画像に必要なバイト配列を再定義しています。実はビットマップの1ライン分の幅=1ライン分のデータ量とはなりません。画像がモノクロなら1ピクセルは2ビットで表せますし、24ビットカラーなら1ピクセルを表現するのに3バイト(24ビット)必要になります。ビットマップの色数はbmBitsPixelに入ります。bmBitsPixelが8であれば画像は8ビットカラーつまり256色ということです。bmWidthBytesには1ラインに必要なバイト数が入ります。この数字は2の倍数になります。0)GetBitmapBitsはビットマップのピクセル値をバッファにコピーする関数です。ヘルプではGetBitmapBitsは16ビットバージョンのWindows(3.x以前)との互換用に残されたもので、Windows95以降ではGetDIBits関数を使うことを奨励されていますが、GetDIBitsは扱いが少し面倒になります。Windows2000でもGetBitmapBitsの動作は確認できましたので、ここではより簡単なGetBitmapBitsを使用しています。0)としているのは、Img配列の(0,0)番目の要素、つまり配列の先頭を渡しています。ここは実際にはAPI呼び出し時にはImg配列の先頭のアドレスが渡されます。For文の中では、ビットマップ中のピクセルに対して縦・横順に色を反転しています。y)は、Img(x,y)=255-Img(x,y)と書いても構いませんが、ここでNotを使っているのは主に高速化のためです。この程度のプログラムなら高速化といっても目に見えるほどの効果は上がりませんが、ただでさえ遅いVBを少しでも速くするためのテクニックとでも理解してください。0)Img配列内で操作したデータをビットマップに返してやります。Picture1.Refresh)最後にピクチャーボックスの変更を反映させます。いかがでしょうか?もし余裕があればこれと同じ処理をするプログラムをPoint、Pset関数を使って書いて比較してみてください。Delphiのページで書いたようにメモリ内のビットマップを直接操作することはできませんが、かなり高速な処理ができるようになったと思います。上記の例のように簡単な処理なら良いのですが、画像にフィルターをかけるような(つまりループ回数が何倍にもなる)処理では、まだまだVBの遅さは実用に耐えられないですが、工夫次第では十分使える用途があると思います。