flood fill coloring on android - android

i just try to use FloodFill class and i found strange problem with coloring.
Lets start with code:
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);
}
}
}
And method where i use FloodFill:
public void colorize()
{
bmp = ((BitmapDrawable)view.getDrawable()).getBitmap();
view.setOnTouchListener(new ImageView.OnTouchListener()
{
#Override
public boolean onTouch(View v, MotionEvent event)
{
int x = (int)event.getX();
int y = (int)event.getY();
...
flood.floodFill(bmp, new Point(x, y), bmp.getPixel(x, y), color);
view.setImageBitmap(bmp);
...
}
});
}
If i try to use standard android color f.g: Color.RED and Color.GREEN, everything works fine. I can replace f.g red with green its works, but if i try to use custom color like this: f.g. Color.rgb(34, 198, 67) i get single point colored instead of filled shape.
Can You help me to find a solution for this problem?
Edit1:
I spoted something interesting. Custom colors seems to be different values on some pixels but i dont know why if i using flood-fill.

Problem solved. Bitmap where i used floodfill was RGB_565. I just convert it to ARGB_8888 and everything work fine.

Related

Flood fill explanation

Im working with my project with paiting/coloring features.Can anyone explain this flood fill algorithm and how this works? Is this flood fill queue? and what does queue mean(in this algorithm)?
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);
}
}
}
There is not a specific name for this algorithm, BUT when filling large areas, I would recommend QueueLinear Flood Fill Algorith which is way faster than the above.
Here is a link to implementation:
http://www.codeproject.com/Articles/16405/Queue-Linear-Flood-Fill-A-Fast-Flood-Fill-Algorith

Custom shaped buttons in Android - Am I doing it right?

I'm trying to implement four custom shaped buttons like you can see in the following picture:
What I did so far: I took 4 different pictures - each with only one color visible (see above). The other part of the image is transparent. This has the result, that I have four pictures with the same size.
Now I used a relative-layout where all my 4 pictures are added into imageviews on the same position. Because of the transparency, I can see the desired picture.
For my ImageViews I've implemented onTouchListener with the following content:
private class ImageOnTouchListener implements View.OnTouchListener {
private int categoryId;
public ImageOnTouchListener(int categoryId) {
this.categoryId = categoryId;
}
#Override
public boolean onTouch(View v, MotionEvent event) {
Bitmap bmp = Bitmap.createBitmap(v.getDrawingCache());
int x = (int) event.getX();
int y = (int) event.getY();
boolean isInsideBitmap = x < bmp.getWidth() && y < bmp.getHeight() && x >= 0 && y >= 0;
boolean isActionUp = event.getAction() == MotionEvent.ACTION_UP;
if (isInsideBitmap) {
int color = bmp.getPixel(x, y);
bmp.recycle();
if (color == Color.TRANSPARENT){
return false;
}
else {
if (isActionUp) {
buttonClick();
}
}
}else{
bmp.recycle();
}
return true;
}
}
This approach works but it consumes a lot of memory as I'm always creating a bitmap when I move my finger. I'm not quite sure if this is the best way to implement this. Is there anything I can do different which might result in a more efficient way?
Using the fact that you can tell whether or not coordinates belong in a circle with the equation x² + y² <= radius² when the circle's center is (0, 0), I think the following should work.
public class ImageOnTouchListener implements View.OnTouchListener {
// TODO Adjust this value
private static int QUADRANT_RADIUS = 100; // in pixels
// TODO Adjust this value
private static int SPACE_BETWEEN_QUADRANTS = 5; // in pixels
#Override
public boolean onTouch(View v, MotionEvent event) {
int relativeX = (int) (event.getX() - v.getX());
int relativeY = (int) (event.getY() - v.getY());
int center = QUADRANT_RADIUS + (SPACE_BETWEEN_QUADRANTS / 2);
boolean isInsideCircle = Math.pow(relativeX - center, 2) + Math.pow(relativeY - center, 2) <= Math.pow(center, 2);
boolean isInsideBottomLeftQuadrant = isInsideCircle &&
relativeX <= QUADRANT_RADIUS &&
relativeY >= QUADRANT_RADIUS + SPACE_BETWEEN_QUADRANTS;
boolean isInsideBottomRightQuadrant = isInsideCircle &&
relativeX >= QUADRANT_RADIUS + SPACE_BETWEEN_QUADRANTS &&
relativeY >= QUADRANT_RADIUS + SPACE_BETWEEN_QUADRANTS;
boolean isInsideTopLeftQuadrant = isInsideCircle &&
relativeX <= QUADRANT_RADIUS &&
relativeY <= QUADRANT_RADIUS;
boolean isInsideTopRightQuadrant = isInsideCircle &&
relativeX >= QUADRANT_RADIUS + SPACE_BETWEEN_QUADRANTS &&
relativeY <= QUADRANT_RADIUS;
boolean isActionUp = event.getAction() == MotionEvent.ACTION_UP;
if (isActionUp) {
if (isInsideBottomLeftQuadrant) {
// Handle bottom left quadrant click
buttonClick();
return true;
} else if (isInsideBottomRightQuadrant) {
// Handle bottom right quadrant click
} // etc.
}
return false;
}
}
You'll need to adjust the QUADRANT_RADIUS and SPACE_BETWEEN_QUADRANTS values, and then either handle all touch events from a single view (like my snippet does) or have a slightly different touch listener per image.

Flood fill in Android application

I am creating an drawing application using canvas. I am using below code to flood fill but on low or medium dpi devices, some portion of image remains unfilled i.e. at edges of an non-uniform shape. Some dots remains unfilled at non uniform edges.
public class FloodFill extends AsyncTask<Void, Void, Void>
{
private int width;
private int height;
private int target;
private int replacement;
private Point node;
private ProgressDialog progress;
public FloodFill(Bitmap image, Point node2, int targetColor, int replacementColor)
{
flood = Bitmap.createBitmap(image);
image.recycle();
this.width = flood.getWidth();
this.height = flood.getHeight();
this.target = targetColor;
this.replacement = replacementColor;
this.node = node2;
}
#Override
protected void onPreExecute()
{
super.onPreExecute();
progress = new ProgressDialog(MainActivity.this);
progress.setMessage("Filling");
progress.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progress.setIndeterminate(true);
progress.setCancelable(false);
progress.show();
}
#Override
protected Void doInBackground(Void... params) {
if (target != replacement)
{
Queue<Point> queue = new LinkedList<Point>();
do
{
int x = node.x;
int y = node.y;
while (x > 0 && flood.getPixel(x - 1, y) == target)
{
x--;
}
boolean spanUp = false;
boolean spanDown = false;
while (x < width && flood.getPixel(x, y) == target)
{
flood.setPixel(x, y, replacement);
if (!spanUp && y > 0 && flood.getPixel(x, y - 1) == target)
{
queue.add(new Point(x, y - 1));
spanUp = true;
}
else if (spanUp && y > 0 && flood.getPixel(x, y - 1) != target)
{
spanUp = false;
}
if (!spanDown && y < height - 1 && flood.getPixel(x, y + 1) == target)
{
queue.add(new Point(x, y + 1));
spanDown = true;
}
else if (spanDown && y < height - 1 && flood.getPixel(x, y + 1) != target)
{
spanDown = false;
}
x++;
}
} while ((node = queue.poll()) != null);
}
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
progress.dismiss();
invalidate();
}
}
I need help regarding this, whether I should try to implement another algorithm, if yes, then which one or I should try to implement anti-aliasing on image after flood fill.
Thanks in advance.

floodfill android not working when the bitmap is fit to screen with create scaled bitmap

In my app i used flood fill for filling the part of the bitmap with color. Everything worked fine, but I create the bitmap with createscaledbitmap , it does not work. Please suggest me.
my code is as follows.
I had floodfill run in asynch task.
#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 = resultBmp.getPixel((int) x, (int) y);
final int targetColor = paint.getColor();
new TheTask(resultBmp, 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();
}
}
}
my floodfill class
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);
}
}
}
my ondraw method is
#Override
protected void onDraw(Canvas canvas) {
this.canvas = canvas;
int w = mBitmap.getWidth();
int h = mBitmap.getHeight();
resultBmp = null;
int widthofBitMap = screenWidth;
int heightofBitMap = widthofBitMap * h / w;
resultBmp = Bitmap.createScaledBitmap(mBitmap, widthofBitMap, heightofBitMap, true);
canvas.drawBitmap(resultBmp, 0, 0, paint);
//if i create only bitmap without scaling it works fine.
// for ex
//canvas.drawBitmap(mBitmap,0,0,paint); works fine.
}
please suggest me
The flood fill method is taking every pixel and changing its color in thread, So instead of increasing the size using create scaled bitmap, I am using separate bitmaps for different screen sizes. Its a cumbersome process but there is no other way according to my research.

How to implement the flood-fill algorithm in android?

How to implement the Flood-fill algorithm in android.But the code was written in c language.could we implement the algorithm in android.is there any open source code available or any website tutorial link
Algorithm for flood fill is a very simple recursive one.
//Initialize i and j to the place to start
floodFill(int arr[][], target_color, replace_color)
{
if(arr[i][j] == replace_color)
return;
replace(target_color, replace_color);
floodFill(int[i+1][j], target_color, replace_color);
floodFill(int[i][j+1], target_color, replace_color);
floodFill(int[i-1][j], target_color, replace_color);
floodFill(int[i][j-1], target_color, replace_color);
}
Flood Fill using queue. Use a asynctask to flood fill.
Parameters
bitamp to be filled
point where the user touches (x,y cordinates)
Color of pixel where use touches
Color to be replaced.
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);
}
}
}

Categories

Resources