Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.2k views
in Technique[技术] by (71.8m points)

android using flood fill algorithm getting out of memory exception

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

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...