Android: How to fill color to the specific part of the Image only?
Solution 1
This is the complete code of filling color into image below :
Image for filling: http://i.stack.imgur.com/7rita.jpg
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_horizontal"
android:orientation="vertical" >
<RelativeLayout
android:id="@+id/relative_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:layout_weight="1" >
<ImageView
android:id="@+id/coringImage"
android:layout_width="300dp"
android:layout_height="300dp" />
</RelativeLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<Button
android:id="@+id/btn_red"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="red" />
<Button
android:id="@+id/btn_yellow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="yellow" />
<Button
android:id="@+id/btn_blue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="blue" />
</LinearLayout>
</LinearLayout>
Activity Class
public class FillColorActivity extends Activity implements OnTouchListener {
private RelativeLayout drawingLayout;
private MyView myView;
Button red, blue, yellow;
Paint paint;
/** Called when the activity is first created. */
/*
*
* private ImageView imageView; private Canvas cv; private Bitmap mask,
* original, colored; private int r,g,b; private int sG, sR, sB;
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
myView = new MyView(this);
drawingLayout = (RelativeLayout) findViewById(R.id.relative_layout);
drawingLayout.addView(myView);
red = (Button) findViewById(R.id.btn_red);
blue = (Button) findViewById(R.id.btn_blue);
yellow = (Button) findViewById(R.id.btn_yellow);
red.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
paint.setColor(Color.RED);
}
});
yellow.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
paint.setColor(Color.YELLOW);
}
});
blue.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
paint.setColor(Color.BLUE);
}
});
}
public class MyView extends View {
private Path path;
Bitmap mBitmap;
ProgressDialog pd;
final Point p1 = new Point();
Canvas canvas;
// Bitmap mutableBitmap ;
public MyView(Context context) {
super(context);
paint = new Paint();
paint.setAntiAlias(true);
pd = new ProgressDialog(context);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeWidth(5f);
mBitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.cartoon).copy(Bitmap.Config.ARGB_8888, true);
this.path = new Path();
}
@Override
protected void onDraw(Canvas canvas) {
this.canvas = canvas;
paint.setColor(Color.GREEN);
canvas.drawBitmap(mBitmap, 0, 0, paint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
p1.x = (int) x;
p1.y = (int) y;
final int sourceColor = mBitmap.getPixel((int) x, (int) y);
final int targetColor = paint.getColor();
new TheTask(mBitmap, p1, sourceColor, targetColor).execute();
invalidate();
}
return true;
}
public void clear() {
path.reset();
invalidate();
}
public int getCurrentPaintColor() {
return paint.getColor();
}
class TheTask extends AsyncTask<Void, Integer, Void> {
Bitmap bmp;
Point pt;
int replacementColor, targetColor;
public TheTask(Bitmap bm, Point p, int sc, int tc) {
this.bmp = bm;
this.pt = p;
this.replacementColor = tc;
this.targetColor = sc;
pd.setMessage("Filling....");
pd.show();
}
@Override
protected void onPreExecute() {
pd.show();
}
@Override
protected void onProgressUpdate(Integer... values) {
}
@Override
protected Void doInBackground(Void... params) {
FloodFill f = new FloodFill();
f.floodFill(bmp, pt, targetColor, replacementColor);
return null;
}
@Override
protected void onPostExecute(Void result) {
pd.dismiss();
invalidate();
}
}
}
// flood fill
public class FloodFill {
public void floodFill(Bitmap image, Point node, int targetColor,
int replacementColor) {
int width = image.getWidth();
int height = image.getHeight();
int target = targetColor;
int replacement = replacementColor;
if (target != replacement) {
Queue<Point> queue = new LinkedList<Point>();
do {
int x = node.x;
int y = node.y;
while (x > 0 && image.getPixel(x - 1, y) == target) {
x--;
}
boolean spanUp = false;
boolean spanDown = false;
while (x < width && image.getPixel(x, y) == target) {
image.setPixel(x, y, replacement);
if (!spanUp && y > 0
&& image.getPixel(x, y - 1) == target) {
queue.add(new Point(x, y - 1));
spanUp = true;
} else if (spanUp && y > 0
&& image.getPixel(x, y - 1) != target) {
spanUp = false;
}
if (!spanDown && y < height - 1
&& image.getPixel(x, y + 1) == target) {
queue.add(new Point(x, y + 1));
spanDown = true;
} else if (spanDown && y < height - 1
&& image.getPixel(x, y + 1) != target) {
spanDown = false;
}
x++;
}
} while ((node = queue.poll()) != null);
}
}
}
@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
return false;
}
}
Solution 2
Use FloodFill.
FloodFill f= new FloodFill();
f.floodFill(bmp,pt,targetColor,replacementColor);
public class FloodFill {
public void floodFill(Bitmap image, Point node, int targetColor,
int replacementColor) {
int width = image.getWidth();
int height = image.getHeight();
int target = targetColor;
int replacement = replacementColor;
if (target != replacement) {
Queue<Point> queue = new LinkedList<Point>();
do {
int x = node.x;
int y = node.y;
while (x > 0 && image.getPixel(x - 1, y) == target) {
x--;
}
boolean spanUp = false;
boolean spanDown = false;
while (x < width && image.getPixel(x, y) == target) {
image.setPixel(x, y, replacement);
if (!spanUp && y > 0 && image.getPixel(x, y - 1) == target) {
queue.add(new Point(x, y - 1));
spanUp = true;
} else if (spanUp && y > 0
&& image.getPixel(x, y - 1) != target) {
spanUp = false;
}
if (!spanDown && y < height - 1
&& image.getPixel(x, y + 1) == target) {
queue.add(new Point(x, y + 1));
spanDown = true;
} else if (spanDown && y < height - 1
&& image.getPixel(x, y + 1) != target) {
spanDown = false;
}
x++;
}
} while ((node = queue.poll()) != null);
}
}
}
Solution 3
I would suspect the initial bitmap was created in read-only mode. That is probably what cause the exception on setPixel(). You can change that via BitmapFactory options:
opt = new BitmapFactory.Options();
// force RGBA pixel format even for 8-bit grey scale image files.
opt.inPreferredConfig = Bitmap.Config.ARGB_8888;
// want to modify the bitmap content.
opt.inMutable = true;
Bitmap bitmap=BitmapFactory.decodeFile("clown.png", opt);
Shreyash Mahajan
About Me https://about.me/sbm_mahajan Email [email protected] [email protected] Mobile +919825056129 Skype sbm_mahajan
Updated on July 28, 2022Comments
-
Shreyash Mahajan over 1 year
I have Image Like this:
Now, i want to fill the color to the Specific part of that image. as like If i select color blue and if i touch on Cap then the cap should be fill with the color Blue. Same thing should be also happen with the other part like nose, Mouth, Eyes etc
So, How it is possible using android ?
Can any budy help me please.
Updated
I have try with the implementation of the FloodFill algorithm in my app. See Here
But after doing that i got exception like:
03-09 17:45:16.260: ERROR/AndroidRuntime(2558): java.lang.IllegalStateException 03-09 17:45:16.260: ERROR/AndroidRuntime(2558): at android.graphics.Bitmap.setPixel(Bitmap.java:847) 03-09 17:45:16.260: ERROR/AndroidRuntime(2558): at com.project.fingerpaint.FinderPaintDemo.FloodFill(FinderPaintDemo.java:284) 03-09 17:45:16.260: ERROR/AndroidRuntime(2558): at com.project.fingerpaint.FinderPaintDemo.access$3(FinderPaintDemo.java:272) 03-09 17:45:16.260: ERROR/AndroidRuntime(2558): at com.project.fingerpaint.FinderPaintDemo$MyView.onTouchEvent(FinderPaintDemo.java:187) 03-09 17:45:16.260: ERROR/AndroidRuntime(2558): at android.view.View.dispatchTouchEvent(View.java:3766) 03-09 17:45:16.260: ERROR/AndroidRuntime(2558): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:863) 03-09 17:45:16.260: ERROR/AndroidRuntime(2558): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:863) 03-09 17:45:16.260: ERROR/AndroidRuntime(2558): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:863) 03-09 17:45:16.260: ERROR/AndroidRuntime(2558): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:863) 03-09 17:45:16.260: ERROR/AndroidRuntime(2558): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:863) 03-09 17:45:16.260: ERROR/AndroidRuntime(2558): at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1671) 03-09 17:45:16.260: ERROR/AndroidRuntime(2558): at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1107) 03-09 17:45:16.260: ERROR/AndroidRuntime(2558): at android.app.Activity.dispatchTouchEvent(Activity.java:2086) 03-09 17:45:16.260: ERROR/AndroidRuntime(2558): at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1655) 03-09 17:45:16.260: ERROR/AndroidRuntime(2558): at android.view.ViewRoot.handleMessage(ViewRoot.java:1785) 03-09 17:45:16.260: ERROR/AndroidRuntime(2558): at android.os.Handler.dispatchMessage(Handler.java:99) 03-09 17:45:16.260: ERROR/AndroidRuntime(2558): at android.os.Looper.loop(Looper.java:123) 03-09 17:45:16.260: ERROR/AndroidRuntime(2558): at android.app.ActivityThread.main(ActivityThread.java:4627) 03-09 17:45:16.260: ERROR/AndroidRuntime(2558): at java.lang.reflect.Method.invokeNative(Native Method) 03-09 17:45:16.260: ERROR/AndroidRuntime(2558): at java.lang.reflect.Method.invoke(Method.java:521) 03-09 17:45:16.260: ERROR/AndroidRuntime(2558): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868) 03-09 17:45:16.260: ERROR/AndroidRuntime(2558): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626) 03-09 17:45:16.260: ERROR/AndroidRuntime(2558): at dalvik.system.NativeStart.main(Native Method)
Now, What wrong in my code ??
Please help me in that condition.
Thanks.
-
Ramakrishna over 11 years@Raghuandan K how we can get the particular bitmap and point from selected area. Can you explain it.
-
Raghunandan over 11 yearsfinal Point p1 = new Point(); p1.x=(int) x; p1.y=(int) y; final int sourceColor= mDrawingManager.mDrawingUtilities.mBitmap.getPixel((int)x,(int) y); final int targetColor = mDrawingManager.mDrawingUtilities.mPaint.getColor(); new TheTask(mDrawingManager.mDrawingUtilities.mBitmap, p1, sourceColor, targetColor).execute();
-
Ramakrishna over 11 yearsOkay, thanks let me try and get back to you.
-
Raghunandan over 11 yearsHere x and y are co-ordinates where user touches on the screen.
-
Raghunandan over 11 yearsmDrawingUtilities.mCanvas = new Canvas(mDrawingUtilities.mBitmap);
-
Raghunandan over 11 years@Ramakrishna did it solve your problem.
-
Ramakrishna over 11 yearsNo getting out of memory exception. Why?
-
Raghunandan over 11 years
-
Pankaj Lilan over 7 years@Raghunandan I am getting IllegalStateException in Flood Fill image.setPixel(x, y, replacement); as I am trying to add bitmap from sdcard. So what would be the possible solution for this?
-
isuru about 7 yearsIf I use SVG instead of normal image, what will be the approach?
-
Raghunandan about 7 years@isuru not sure as i have not done this. But can you convert vectordrawable to Bitmap and then apply floodfill stackoverflow.com/questions/33696488/…. Check if it works
-
Zia Ur Rahman about 6 yearsDoes not fill the area when I tap on Image. code is below. can you please implement it in MainActivity on Touch event to get any color and fill the area. please
-
Zia Ur Rahman about 6 yearsBrilliant! Great work. Thanks, but How can we make this filling Fast. How to add code to make it fast filling? And it leaves white spaces/dots on corners, how to fill/cover it fully. please
-
Sheetal Shinde about 2 years@Tim Thanks!!! But there are some spaces at corner which ain't get filled..How to make it smooth to occupy full portion with color.