android - 如何使用 Canvas 设置仅绘制图像形状

标签 android image canvas bitmap imageview

我正在用安卓做一个绘画应用。我能够在 Canvas 上展示图片并能够绘画。我只需要在图像中绘画,就像市场上的 colorfy,Coloring Bunny,Happy Zoo 之类的应用程序。我不确定如何完成这项任务。需要您的建议。

这是我的代码。

activity_main.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"
android:background="#FFF">

<ImageView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:src="@drawable/bug"/>

<code.android.com.kidscolorbook.DrawingPad
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/drawingPad"
    android:textColor="#FFFFFF"
    android:cursorVisible="true"
    />
<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/btnClear"
    android:layout_gravity="bottom|center"
    android:text="Clear Canvas"/>

主 Activity .java

public class MainActivity extends AppCompatActivity {

DrawingPad drawingPad;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Settings.System.putInt(getBaseContext().getContentResolver(),
            "show_touches", 1);
    drawingPad = (DrawingPad) findViewById(R.id.drawingPad);
   // drawingPad.setBackgroundResource(R.drawable.bug);
    Button btnClear = (Button) findViewById(R.id.btnClear);
    btnClear.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            drawingPad.clearCanvas();
        }
    });
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        return true;
    }

    return super.onOptionsItemSelected(item);
}

@Override
protected void onPause() {
    super.onPause();
    Settings.System.putInt(getBaseContext().getContentResolver(),
            "show_touches", 0);

}}

绘图板.java

public class DrawingPad extends View {

private Context mContext;
private Path mPath;
private Paint mPaint;

private Bitmap mBitmap;
private Canvas mCanvas;

private float mX,mY;
private static final float TOLERANCE = 5;

public DrawingPad(Context context, AttributeSet attrs) {
    super(context, attrs);

    this.mContext = context;
    mPath = new Path();
    mPaint = new Paint();

    mPaint.setAntiAlias(true);
    mPaint.setColor(Color.RED);
    mPaint.setStyle(Paint.Style.STROKE);
    mPaint.setStrokeJoin(Paint.Join.ROUND);
    mPaint.setStrokeWidth(50f);


}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    Resources resources = getResources();
    mBitmap = BitmapFactory.decodeResource(resources, R.drawable.circle);
    mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
    mCanvas = new Canvas(mBitmap);

}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.drawPath(mPath, mPaint);

}


@Override
public boolean onTouchEvent(MotionEvent event) {

    float x = event.getX();
    float y = event.getY();


    switch (event.getAction()){
        case MotionEvent.ACTION_DOWN :
            startTouch(x, y);
            invalidate();
            break;
        case MotionEvent.ACTION_MOVE:
            moveTouch(x, y);
            invalidate();
            break;
        case MotionEvent.ACTION_UP:
            upTouch(mX,mY);
            invalidate();
            break;

    }

    return true;
}

private void startTouch(float x,float y){
    mPath.moveTo(x,y);
    mX = x;
    mY = y;
}

private void moveTouch(float x,float y)
{
    float dx = Math.abs(x - mX);
    float dy = Math.abs(y - mY);
    System.out.print("******"+x+y);
    if(dx >= TOLERANCE || dy>= TOLERANCE){
        mPath.quadTo(mX,mY,(x+mX)/2,(y+mY)/2);

        mX = x;
        mY = y;
    }
}

private void upTouch(float x, float y)
{
    mPath.lineTo(x,y);
}

public void clearCanvas()
{
    mPath.reset();
    invalidate();
}}

我的输出:

enter image description here

我只需要在图像中和特定形状上进行绘画,而不需要散布颜色。(我知道我们可以减少笔触宽度)但是如果你可以看看上面提到的应用程序,你可能会完全理解问题。

需要您的建议,比如我们如何才能实现这种功能。

提前致谢。

最佳答案

我有同样的问题,经过长时间的研究,我找到了部分解决方案 FloodFill 模式?这是什么意思:这意味着当你在图像上的任何点单击具有相同的颜色(targetColor)--> 在我们的例子中是白色,它转换为(replacementColor)--> 无论你的绘画颜色在你的例子中 mPaint 有红色,这是您可能需要进行一些更改的代码

@Override
public boolean onTouchEvent(MotionEvent event) {

    float x = event.getX();
    float y = event.getY();


    switch (event.getAction()){
        case MotionEvent.ACTION_DOWN :
            startTouch(x, y);
            int sourceColor = bgImg.getPixel((int) x, (int) y);
            int desColor = paint.getColor();
            // pass the bitmap you want paint
            FloodFill(  mBitmap , new Point((int) x, (int) y) , sourceColor , desColor  );
            invalidate();
            break;
        case MotionEvent.ACTION_MOVE:
            moveTouch(x, y);
            invalidate();
            break;
        case MotionEvent.ACTION_UP:
            upTouch(mX,mY);
            invalidate();
            break;

    }

    return true;
}



private void FloodFill(Bitmap bmp, Point pt, int targetColor, int replacementColor) {
        Queue<Point> q = new LinkedList<Point>();
        q.add(pt);
        while (q.size() > 0) {
            Point n = q.poll();
            if (bmp.getPixel(n.x, n.y) != targetColor)
                continue;

            Point w = n, e = new Point(n.x + 1, n.y);
            while ((w.x > 0) && (bmp.getPixel(w.x, w.y) == targetColor)) {
                bmp.setPixel(w.x, w.y, replacementColor);
                if ((w.y > 0) && (bmp.getPixel(w.x, w.y - 1) == targetColor))
                    q.add(new Point(w.x, w.y - 1));
                if ((w.y < bmp.getHeight() - 1)
                        && (bmp.getPixel(w.x, w.y + 1) == targetColor))
                    q.add(new Point(w.x, w.y + 1));
                w.x--;
            }
            while ((e.x < bmp.getWidth() - 1)
                    && (bmp.getPixel(e.x, e.y) == targetColor)) {
                bmp.setPixel(e.x, e.y, replacementColor);

                if ((e.y > 0) && (bmp.getPixel(e.x, e.y - 1) == targetColor))
                    q.add(new Point(e.x, e.y - 1));
                if ((e.y < bmp.getHeight() - 1)
                        && (bmp.getPixel(e.x, e.y + 1) == targetColor))
                    q.add(new Point(e.x, e.y + 1));
                e.x++;
            }
        }
    }

关于android - 如何使用 Canvas 设置仅绘制图像形状,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32899587/

相关文章:

android - Cordova s​​tartsWith 方法不适用于旧手机

html - 如何使用 CSS 对图像进行去饱和和饱和处理?

javascript - 带有大图像的 Canvas drawImage

html - 用于渲染视频的 2d 上下文与 WebGL

android - 从另一个类调用 Activity 类中的公共(public)方法?

android - 共享首选项无法正确评估?

javascript - 如何使用 JS 渲染预加载的图像

c# - Windows Phone 8.1 的绘图控件(通用应用程序)

android - OutOfMemoryError 尽管 vm 有足够的空闲内存

javascript - 是否可以在 slimbox 中显示的图像中添加链接?