0

after your suggestions i got working code:

public class FingerPaint extends Activity {

private RelativeLayout drawingLayout;
private MyView myView;
@Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    myView = new MyView(this);
    setContentView(myView);
    drawingLayout.addView(myView);
}

public class MyView extends View {

    private Paint paint;
    private Path path;
    Bitmap mBitmap;
    ProgressDialog pd;
    final Point p1 = new Point();
    Canvas canvas;
    //Bitmap mutableBitmap ;
    public MyView(Context context) {
        super(context);

        this.paint = new Paint();
        this.paint.setAntiAlias(true);
        pd = new ProgressDialog(context);
        this.paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeJoin(Paint.Join.ROUND);
        paint.setStrokeWidth(5f);
        mBitmap = BitmapFactory.decodeResource(getResources(),
                R.drawable.paint).copy(Bitmap.Config.ARGB_8888, true);


        this.path = new Path();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        this.canvas = canvas;
        this.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);
        }
    }
}
}

Now it is working fine.ThanQ

G_S
  • 7,068
  • 2
  • 21
  • 51
  • this link is so fast : http://stackoverflow.com/questions/8070401/android-flood-fill-algorithm – Arash Jan 26 '14 at 16:36

3 Answers3

4

Use Async Task. Running every operation on Main Ui thread may cause's out of memory exception. My suggestion , use threads. Do Floodfill in background. Check this link. May help You. Fill the complete canvas but keep the bound fill area as it is like circle, rectangle

    private Paint paint;
private Path path;
Bitmap mBitmap;
ProgressDialog pd;
 final Point p1 = new Point();
Canvas canvas;
private static final float TOUCH_TOLERANCE = 4;
float mX,mY;

public DrawingView(Context context ) {
    super(context);

    this.paint = new Paint();
    this.paint.setAntiAlias(true);
    pd= new ProgressDialog(context);
    this.paint.setStyle(Paint.Style.STROKE);
    paint.setStrokeJoin(Paint.Join.ROUND);
    paint.setStrokeWidth(5f);
    mBitmap= BitmapFactory.decodeResource(getResources(), R.drawable.rose_sketch);
    this.path = new Path();
}

@Override
protected void onDraw(Canvas canvas) {
    this.canvas=canvas;
    this.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:
    //final Point p1 = new Point();
    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();
    }
}
}

USE FLOODFILL NOW.

 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);
    }
}
}

Edit:

One of the users commented that the solution @ Android flood-fill algorithm works faster than the solution posted here. So take look at the solution in the link although i haven't tested it myself.

Community
  • 1
  • 1
Raghunandan
  • 132,755
  • 26
  • 225
  • 256
  • i checked the link and used few lines that i felt necessary. Once check the edited question – G_S Oct 11 '12 at 08:44
  • FloodFill works fine. Couple of questions. Do you do freehand drawing on screen or do you draw a bitmap and color the same using floodfill. – Raghunandan Oct 11 '12 at 11:10
  • i have that image(capture 1) in drawable folder and am displaying it using Bitmapfactory.decodeResource(); to this image i want to add color in specific region using flood fill – G_S Oct 12 '12 at 03:09
  • just comment all other functions. Try filling the image with floodfill. The above code works fine. Have a look and revert back. – Raghunandan Oct 12 '12 at 04:06
  • http://tinypic.com/view.php?pic=35lrakm&s=6. See the link. First time click. http://tinypic.com/view.php?pic=2jc7sqo&s=6. Second time click. – Raghunandan Oct 12 '12 at 04:09
  • i refer the link what you suggested and i edited my code.but its not working i get exception.i posted my edited code and logcat result above – G_S Oct 12 '12 at 06:40
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/17915/discussion-between-raghunandan-and-sharath) – Raghunandan Oct 12 '12 at 07:51
  • @Arash its the same floodfill algorithm if you take a look closer – Raghunandan Jan 26 '14 at 16:34
  • yes but i tested both on my Galaxy S4 and the link i put works great – Arash Jan 26 '14 at 16:36
  • @Arash its the same algorithm so the peformance should be the same it can't change coz its the same algorithm and both uses queue in fact i picked it from a link on SO don't remember long time back – Raghunandan Jan 26 '14 at 16:37
  • i know what you say,i test your answer it works well but some time this problem happens : http://stackoverflow.com/questions/21364736/cannot-generate-texture-from-bitmap so i found the other and its faster and it does not have that problem – Arash Jan 26 '14 at 16:42
  • i edited the link please change in your answer : http://stackoverflow.com/a/17426163/401403 – Arash Jan 26 '14 at 17:36
0

I have seen this problem with my code whenver there is some really complex computations going on in the UI thread. If you have implemented flood fill in the UI thread, the computations are causing 99% CPU usage due to which other applications and services are not getting thier share of the CPU. As a result, android will try to kill your app inorder to restore the integrity of the System. As a simple solution, try to offload your computations to a AsyncTask or a thread.

Royston Pinto
  • 6,681
  • 2
  • 28
  • 46
  • i tried this but am getting same problem can u suggest me somemore please – G_S Oct 01 '12 at 09:02
  • final Runnable r = new Runnable() { public void run() { drawingLayout.removeView(myView); drawingLayout.addView(myView); handler.postDelayed(this, 1000); } }; – G_S Oct 01 '12 at 09:02
  • Handler will also run on the UI thread, so it may not be a good idea. Isn't AsyncTask working for you? I usually offload all my intensive computations there. – Royston Pinto Oct 01 '12 at 09:20
  • no,its also nit working.can u provide me with complete code please – G_S Oct 01 '12 at 09:37
  • U will find code on AsyncTask on StackOverflow, try to add mEmboss = new EmbossMaskFilter(new float[] { 1, 1, 1 }, 0.4f, 6, 3.5f); mBlur = new BlurMaskFilter(8, BlurMaskFilter.Blur.NORMAL); into AsyncTask as these look very intensive to me, else you maight even have to optmize your algorithm.! – Royston Pinto Oct 01 '12 at 09:53
  • i already have this lines in my code.but not working.selected region is not filling yet.. – G_S Oct 06 '12 at 03:30
-1

I think you have to swich off the multitoutch of your screen because of that it went to out of memory....

vimal v
  • 1
  • 1