package asd.asd.asd; import android.app.Activity; import android.content.Context; import android.graphics.*; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; public class FingerPaint extends GraphicsActivity implements ColorPickerDialog.OnColorChangedListener { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new MyView(this)); mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setDither(true); mPaint.setColor(0xFFFF0000); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeJoin(Paint.Join.ROUND); mPaint.setStrokeCap(Paint.Cap.ROUND); mPaint.setStrokeWidth(12); mEmboss = new EmbossMaskFilter(new float[] { 1, 1, 1 }, 0.4f, 6, 3.5f); mBlur = new BlurMaskFilter(8, BlurMaskFilter.Blur.NORMAL); } private Paint mPaint; private MaskFilter mEmboss; private MaskFilter mBlur; public void colorChanged(int color) { mPaint.setColor(color); } public class MyView extends View { private static final float MINP = 0.25f; private static final float MAXP = 0.75f; private Bitmap mBitmap; private Canvas mCanvas; private Path mPath; private Paint mBitmapPaint; public MyView(Context c) { super(c); mBitmap = Bitmap.createBitmap(320, 480, Bitmap.Config.ARGB_8888); mCanvas = new Canvas(mBitmap); mPath = new Path(); mBitmapPaint = new Paint(Paint.DITHER_FLAG); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); } @Override protected void onDraw(Canvas canvas) { // canvas.drawColor(0xFFAAAAAA); canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint); canvas.drawPath(mPath, mPaint); } private float mX, mY; private static final float TOUCH_TOLERANCE = 1; private void touch_start(float x, float y) { mPath.reset(); mPath.moveTo(x, y); mX = x; mY = y; } private void touch_move(float x, float y) { float dx = Math.abs(x - mX); float dy = Math.abs(y - mY); if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) { mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2); mX = x; mY = y; } } private void touch_up() { mPath.lineTo(mX, mY); // commit the path to our offscreen mCanvas.drawPath(mPath, mPaint); // kill this so we don't double draw mPath.reset(); } @Override public boolean onTouchEvent(MotionEvent event) { float x = event.getX(); float y = event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: touch_start(x, y); invalidate(); break; case MotionEvent.ACTION_MOVE: touch_move(x, y); invalidate(); break; case MotionEvent.ACTION_UP: touch_up(); invalidate(); break; } return true; } } private static final int COLOR_MENU_ID = Menu.FIRST; private static final int EMBOSS_MENU_ID = Menu.FIRST + 1; private static final int BLUR_MENU_ID = Menu.FIRST + 2; private static final int ERASE_MENU_ID = Menu.FIRST + 3; private static final int SRCATOP_MENU_ID = Menu.FIRST + 4; @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); menu.add(0, COLOR_MENU_ID, 0, "Color").setShortcut('3', 'c'); menu.add(0, EMBOSS_MENU_ID, 0, "Emboss").setShortcut('4', 's'); menu.add(0, BLUR_MENU_ID, 0, "Blur").setShortcut('5', 'z'); menu.add(0, ERASE_MENU_ID, 0, "Erase").setShortcut('5', 'z'); menu.add(0, SRCATOP_MENU_ID, 0, "SrcATop").setShortcut('5', 'z'); /**** Is this the mechanism to extend with filter effects? Intent intent = new Intent(null, getIntent().getData()); intent.addCategory(Intent.CATEGORY_ALTERNATIVE); menu.addIntentOptions( Menu.ALTERNATIVE, 0, new ComponentName(this, NotesList.class), null, intent, 0, null); *****/ return true; } @Override public boolean onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { mPaint.setXfermode(null); mPaint.setAlpha(0xFF); switch (item.getItemId()) { case COLOR_MENU_ID: new ColorPickerDialog(this, this, mPaint.getColor()).show(); return true; case EMBOSS_MENU_ID: if (mPaint.getMaskFilter() != mEmboss) { mPaint.setMaskFilter(mEmboss); } else { mPaint.setMaskFilter(null); } return true; case BLUR_MENU_ID: if (mPaint.getMaskFilter() != mBlur) { mPaint.setMaskFilter(mBlur); } else { mPaint.setMaskFilter(null); } return true; case ERASE_MENU_ID: mPaint.setXfermode(new PorterDuffXfermode( PorterDuff.Mode.CLEAR)); return true; case SRCATOP_MENU_ID: mPaint.setXfermode(new PorterDuffXfermode( PorterDuff.Mode.SRC_ATOP)); mPaint.setAlpha(0x80); return true; } return super.onOptionsItemSelected(item); } }
위 소스는 ApiDemos 폴더에 있는 FingerPaint 인데요
이걸 에뮬레이터에서 실행하면 칠해지는게 좀 느리더군요;;
onDraw에서 칠한 부분을 다시 보여주기 위해서
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
이부분을 마우스로 그리는 동안에도 계속 실행하면서
느려지는것 같은데요.
그래서 이부분하고 mPath.reset(); 부분을 지웠더니
상당히 빨라지더군요!
근데 문제는 이렇게하면 mPath가 리셋이 되지 않아서그런지
많이 칠할수록 칠하는 속도가 느려지더라구요;;
제가 드리고 싶은 질문은
1. FingerPaint를 단말기에서 실행하면 빠르게 동작하는지
2. 단말기에서도 똑같은 속도라면 혹시 빠르게 반응하게 하는 방법은 없는가
하는것 입니다.
ApiDemos 에서 FingerPaint만 추려낸 프로젝트 파일을 같이 첨부할게요!
속도가 느린 이유는 mPath 내부에 많은 path 가 쌓이기 때문입니다.
canvas.drawPath(mPath, mPaint) 부분에서 쌓인 path 들을 그리게 되는데 reset 이 없다면 path 가 계속 쌓이기만 해서 속도가 느려지게 됩니다.
속도를 올리기 위해선 path 를 쓰지 말고 Canvas.drawLine() 함수를 이용하여 bitmap 에 바로 이미지를 그리게 하고 onDraw 함수에서 bitmap 만 뿌리면 속도가 굉장히 빨라질 것입니다.
문제는 이렇게 할 경우 path 를 썼을 때 얻을 수 있는 잇점이 사라지게 되는데요.
mPath.quadTo(mX, mY, (x + mX)/2
, (y + mY)/
2
);
이 부분은 곡선이 부드럽게 이어지도록 해주는 부분인데 lineTo 를 쓰면 부드러운 감이 없어지게 됩니다.