エンタープライズ:特集 2003/07/04 17:20:00 更新
C Magazine

C MAGAZINE 2002年8月号より転載
プログラムのレシピ――プログラミングの考え方・作り方 (10/13)

グラフィックエディタの製作(6)
基本機能の作成−再描画の高速化

再描画の高速化

 List 10の最後のList 10-(6)では、ブラシで描画した部分を画面に反映させるために、RepaintBitmapという自作のメソッドを呼び出します。RepaintBitmapはList 11のようなプログラムです。

 List 11ではTCanvasクラスのCopyRectメソッドを使って、ブラシで描画した部分だけを画面にコピーします。ブラシで描画した部分(矩形の領域)は、List 10- (6)のようにビットマップ上の座標がわかっています。これに対応する画面上の領域はList 11- (1)のように計算できるので、この部分だけを再描画します。

List 11 必要な部分だけ再描画する処理(UGEditorForm.cpp)
void TGEditorForm::RepaintBitmap(int x, int y, int w, int h) {
    TCanvas *c=PaintBox-> Canvas;
    c-> CopyRect(
        //===================================================== (1)
        // コピー先となる画面上の矩形
        TRect(x*ZoomRate,y*ZoomRate,
            (x+w)*ZoomRate,(y+h)*ZoomRate),
        // コピー元のビットマップ
        Bitmap-> Canvas,
        // コピー元のビットマップ上の矩形
        TRect(x,y,x+w,y+h)
    );
}

 もしList 10- (6)でRepaintBitmapのようなメソッドを呼び出さず、代わりに、

Repaint();

としても、画面の更新はできます。しかし試してみれば一目瞭然ですが、再描画が遅いわ、画面はちらつくわで、使い物になりません。ただし、プログラムの開発中にとりあえずRepaintメソッドを使っておくのはかまいません。

 なおWin32 APIの場合には、CopyRectメソッドの代わりにBitBlt関数やStretchBlt関数(あるいはStretchDIBits関数)を使います。これらの関数はビットマップの転送元と転送先の範囲をそれぞれ矩形で指定できるので、必要な部分だけを画面上にコピーすればよいのです。

クローンブラシによる描画

 クローンブラシは本格的なペイントツールでは一般的な機能です。半透明ブラシでは描画色が単色でしたが、クローンブラシでは描画色を画像から拾ってきます。クローンブラシはテクスチャを作ったり、写真をレタッチしたりと、いろいろな使い方ができる機能です。

Fig12

Fig. 12 クローンブラシ


 文章では説明しにくいのですが、Fig. 12でおわかりいただけるでしょうか。画面左上の「×」印が描画色を拾うポイントです。画像の一部がコピーされていますね。ただのコピーではなく、ブラシの形状や濃淡を反映したコピーになります。

 作成したグラフィックエディタでは、[Ctrl]+[Shift]+右クリックで描画色を拾うポイントを設定します。クローンブラシを使った描画は、[Ctrl]+[Shift]+左クリック(またはドラッグ)です。

 クローンブラシは、Fig. 11で説明した半透明ブラシとほぼ同じ仕組みで実現できます。Fig. 11- (B)のように単色で塗る代わりに、画像上の指定したポイント(クローン元)からピクセルごとに色を拾ってくるわけです。

プログラム例

 クローンブラシのプログラムはList 12です。半透明ブラシのプログラム(List 10)とほとんど同じなのですが、List 12- (1)と(2)が少しだけ違います。List 12- (1)のCloneSourceXとCloneSourceYはクローン元の座標で、この座標をブラシの中心座標に合わせます。List 12- (2)は描画色をクローン元から拾う処理です。

List 12 クローンブラシ(UGEditorForm.cpp)
// クローンブラシで描画
void TGEditorForm::DrawWithCloneBrush(int x, int y) {
    // ブラシのビットマップ
    Graphics::TBitmap *brushBmp=BrushForm-> GetBrush();
    // ブラシと画像を操作するTCanvasオブジェクト
    TCanvas *brush=brushBmp-> Canvas;
    TCanvas *bmp=Bitmap-> Canvas;
    // ブラシの座標と大きさ
    int brushX, brushY;
    int brushW=brushBmp-> Width, brushH=brushBmp-> Height;
    // 画像上の座標
    int bmpLeft=x-brushW/2, bmpTop=y-brushH/2;
    int bmpX, bmpY;
    //========================================================= (1)
    // クローン元の座標
    int cloneX, cloneY;
    int cloneLeft=CloneSourceX-brushW/2,
        cloneTop=CloneSourceY-brushH/2;
    // 画像の色、ブラシの濃淡、クローン元の色
    TColor bmpCol, brushCol, cloneCol;
    // アルファ値(透明度)
    int alphaR, alphaG, alphaB;
    // ブラシの左上から右下に向かって
    // 1ピクセルずつ処理する
    for (
        brushY=0, bmpY=bmpTop, cloneY=cloneTop;
        brushY< brushH; 
        brushY++, bmpY++, cloneY++
    ) {
        for (
            brushX=0, bmpX=bmpLeft, cloneX=cloneLeft; 
            brushX< brushW; 
            brushX++, bmpX++, cloneX++
        ) {
            // ブラシの濃度を取得
            brushCol=brush-> Pixels[brushX][brushY]&0xffffff;
            // ブラシが透明ならば次のピクセルへ
            if (brushCol==0xffffff) {
                continue;
            }
            //================================================= (2)
            // クローン元の色を拾って、描画色にする
            cloneCol=bmp-> Pixels[cloneX][cloneY];
            // ブラシが完全に不透明ならば、
            // 描画色をベタ塗りする
            if (brushCol==0) {
                bmp-> Pixels[bmpX][bmpY]=cloneCol;
                continue;
            } else
            // ブラシが半透明ならば、描画色と背景とを合成する
            {
                bmpCol=bmp-> Pixels[bmpX][bmpY];
                alphaR=RGB_R(brushCol); 
                alphaG=RGB_G(brushCol); 
                alphaB=RGB_B(brushCol);
                bmp-> Pixels[bmpX][bmpY]=RGBToColor(
                    (RGB_R(bmpCol)*alphaR + 
                        RGB_R(cloneCol)*(255-alphaR))/255 ,
                    (RGB_G(bmpCol)*alphaG + 
                        RGB_G(cloneCol)*(255-alphaG))/255 ,
                    (RGB_B(bmpCol)*alphaB + 
                        RGB_B(cloneCol)*(255-alphaB))/255
                );
            }
        }
    }
    // 再描画処理
    RepaintBitmap(bmpLeft, bmpTop, brushW, brushH);
}

前のページ | 1 2 3 4 5 6 7 8 9 10 11 12 13 | 次のページ

[松浦健一郎(ひぐぺん工房),C MAGAZINE]

Copyright © ITmedia, Inc. All Rights Reserved.