N2-Works
WEB企画・制作/システム開発 大阪拠点

AndroidのBitmap画像プログラミング(4) 線の描画

AndroidのBitmap画像プログラミングの第四回は線の描画方法を紹介します。

線の描画と言っても、CanvasクラスのdrawLineとかではなく、画像バッファのカラー情報を操作する方法を取ります。

線の描画

今回は横方向に引く関数と、2つの座標を用意して線を引く関数を用意しました。

後者の関数だけで線は引けるのですが、横方向のみの場合はArrays.fillを使用して高速に処理をしています。

これは画像バッファのindexが連続しているからできるのであって、後者ではその判定を行うのが面倒になるからです。

その関数ではブレゼンハムアルゴリズムで、描画すべき画像バッファ位置を割り出しています。

加算・減算だけで画像バッファ位置を割り出せ、乗算・割算を使用しないため処理が高速になります。

/**
 * 横線描画処理
 *
 * @param   : int :  sx    :  始点x
 * @param   : int :  dx    :  終点x
 * @param   : int :  y     :  y座標
 * @param   : int :  color :  ARGB
 * @return  : boolean
 * @author  : N.Nishimura
 * @version : 1.0
 * @since  : 2011/02/22 1.0
 */
public boolean LineToX(int sx, int dx, int y, int color)
{
  // 描く必要なし
  if (y  < 0) {
    return false;
  }
  if (y >= mHeight) {
    return false;
  }
    // swap
  if (sx > dx) {
    int t = 0;
    t = sx;
    dx = sx;
    sx = t;
  }
    // 描く必要なし
  if (dx < 0) {
    return false;
  }
  if (sx >= mWidth) {
    return false;
  }
    // クリッピング
  if (sx < 0) {
    sx = 0;
  }
  if (dx >= mWidth) {
    dx = mWidth - 1;
  }
    // 始点アドレスを取得
  int s = GetPixelAddress(sx, y);
  Arrays.fill(mBuffer, s, s + dx - sx, color);

  return true;
}

/**
 * 線描画処理
 * ブレゼンハムアルゴリズム
 *
 * @param  : int  :  sx    :  始点x
 * @param  : int  :  dx    :  終点x
 * @param  : int  :  sy    :  始点y
 * @param  : int  :  dy    :  終点y
 * @param  : int  :  color  :  ARGB
 * @return  : boolean
 * @author  : N.Nishimura
 * @version  : 1.0
 * @since  : 2011/02/22 1.0
 */
public boolean LineTo(int sx, int dx, int sy, int dy, int color)
{
  // クリッピング
  if (sx < 0) {
    sx = 0;
  }
  if (sy < 0) {
    sy = 0;
  }
  if (dx < 0) {
    dx = 0;
  }
  if (dy < 0) {
    dy = 0;
  }
  if (sx >= mWidth) {
    sx = mWidth - 1;
  }
  if (dx >= mWidth) {
    dx = mWidth - 1;
  }
  if (sy >= mHeight) {
    sy = mHeight -1;
  }
  if (dy >= mHeight) {
    dy = mHeight - 1;
  }
    // 始点から終点の距離を求める
  int distance_x = dx - sx;
  int add_x = 1;
  if (distance_x < 0) {
    distance_x = -distance_x;
    add_x = -add_x;
  }
  int distance_y = dy - sy;
  int add_y = 1;
  if (distance_y < 0) {
    distance_y = -distance_y;
    add_y = -add_y;
  }
    // 現在の座標
  int cur_x = sx;
  int cur_y = sy;
    // 距離が長い方を軸とする
  int counter = 0;
  if (distance_x > distance_y) {
    for (int i = 0; i < distance_x; i++) {
      mBuffer[cur_x + mWidth * cur_y] = color;
      counter += distance_y;
      if (counter > distance_x) {
        counter -= distance_x;
        cur_y += add_y;
      }
      cur_x += add_x;
    }
  }
  else {
    for (int i = 0; i < distance_x; i++) {
      mBuffer[cur_x + mWidth * cur_y] = color;
      counter += distance_x;
      if (counter > distance_y) {
        counter -= distance_y;
        cur_x += add_x;
      }
      cur_y += add_y;
    }
  }
  return true;
}

Activity

package net.n2works.BitmapTest;

// SYSTEM PACKAGE
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.PorterDuff.Mode;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class BitmapTest extends Activity
{
  // Bitmap
  private Bitmap mBitmap;

  /**
   * Component
   */
  // SurfaceView
  private SurfaceView mView;
  // ExecutorService
  private ScheduledExecutorService executor;

  /**
   * クラス定数
   */
  private final int BG_COLOR = 0xff000000;
  private final int BITMAP_W = 300;
  private final int BITMAP_H = 300;

    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        // 下地の作成
        ImageBuffer buf = new ImageBuffer(BITMAP_W, BITMAP_H);

        // 横線を描画
        buf.LineToX(0, BITMAP_W, BITMAP_H / 2, 0xffff0000);

        // 線の描画
        buf.LineTo(0, BITMAP_W, 0, BITMAP_H, 0xff0000ff);
        buf.LineTo(BITMAP_W, 0, 0, BITMAP_H, 0xffffff00);

        mBitmap = Bitmap.createBitmap(BITMAP_W, BITMAP_H, Bitmap.Config.ARGB_8888);
        mBitmap.setPixels(buf.GetBuffer(), 0, BITMAP_W, 0, 0, BITMAP_W, BITMAP_H);

        // Viewの設定
        mView = new SurfaceViewEx(this);
        setContentView(mView);
    }

    protected void onDestroy()
    {
    mBitmap.recycle();
    executor.shutdown();
    super.onDestroy();
  }

    private class SurfaceViewEx extends SurfaceView
    implements SurfaceHolder.Callback
    {
      boolean is_run;

      /**
       * クラス定数
       */
      private static final int FPS = 60;

    public SurfaceViewEx(Context context)
    {
      super(context);

      getHolder().addCallback(this);
      getHolder().setType(SurfaceHolder.SURFACE_TYPE_GPU);
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
    {
    }

    public void surfaceCreated(SurfaceHolder holder)
    {
      executor = Executors.newSingleThreadScheduledExecutor();
      is_run = true;
      executor.scheduleAtFixedRate(
        new Runnable()
        {
          public void run()
          {
            if (is_run) {
              Canvas c = getHolder().lockCanvas();
              Draw(c);
              getHolder().unlockCanvasAndPost(c);
            }
          }
        },
        1000 / FPS, 1000 / FPS,
        TimeUnit.MILLISECONDS
      );
    }

    public void surfaceDestroyed(SurfaceHolder holder)
    {
      is_run = false;
    }

    protected void Draw(Canvas c)
    {
      // 背景色クリア
      c.drawColor(BG_COLOR, Mode.SCREEN);

      // Bitmap描画
      c.drawBitmap(mBitmap, 0, 0, null);
    }
  }
}

 

[Android]2011年02月25日 18時43分47秒

※1000文字以内で入力してください

captcha
TOP