Reputation: 525
I am doing a painting app in android. I am able to show a picture on canvas and able to paint. I need to paint only with in the image like the apps in market colorfy, Coloring Bunny, Happy Zoo like that. I am not sure exactly how to acheive this task. Need your suggestions.
Here is my code.
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"/>
MainActivity.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);
}}
Drawingpad.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();
}}
My output :
I need to paint only with in the image and at specific shapes without spreading color.(i am aware that we can reduce stroke width) But if you can look at the above mentioned apps you may understand issue exactly.
Need your suggestions like how can we achieve that kind of feature.
Thanks in advance.
Upvotes: 1
Views: 872
Reputation: 21452
I have the same issue , after long research I figure part of solution FloodFill
Pattern ? what that mean : this mean when you click at any point at image have the same color(targetColor) --> in our case white color , it convert to (replacementColor) --> whatever your paint color in your case mPaint
has red color , here is the code you will may be need to make some changes
@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++;
}
}
}
Upvotes: 1