当使用洪水填充算法填充颜色后绘制线条时,填充颜色消失

Posted

技术标签:

【中文标题】当使用洪水填充算法填充颜色后绘制线条时,填充颜色消失【英文标题】:When line is draw after filling color using flood fill algorithm then filling color is gone 【发布时间】:2015-06-30 05:04:00 【问题描述】:

我有画布绘图应用程序。我成功地完成了集成填充算法,通过手指绘制形状为手指绘制圆形和矩形区域填充颜色。我的问题是用手指为创建的形状填充颜色后,在画布上绘制线条时填充的颜色消失了。

public class DrawingView extends View 
    private final Paint mDefaultPaint;
    private final Paint mFloodPaint = new Paint();
    Bitmap mBitmap;
    float x, y;
    ProgressDialog pd;
    LinearLayout drawing_layout;
    private Canvas mLayerCanvas = new Canvas();
    private Bitmap mLayerBitmap;
    final Point p1 = new Point();
    private Stack<DrawOp> mDrawOps = new Stack<>();
    private Stack<DrawOp> mUndoOps = new Stack<>();

    boolean isFill;/* = false;*/
    private SparseArray<DrawOp> mCurrentOps = new SparseArray<>(0);

    public DrawingView(Context context) 
        this(context, null, 0);

    

    public DrawingView(Context context, AttributeSet attrs) 
        this(context, attrs, 0);
    

    public DrawingView(Context context, AttributeSet attrs, int defStyle) 
        super(context, attrs, defStyle);

        mDefaultPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mDefaultPaint.setStyle(Paint.Style.STROKE);
        mDefaultPaint.setStrokeJoin(Paint.Join.ROUND);
        mDefaultPaint.setStrokeCap(Paint.Cap.ROUND);
        mDefaultPaint.setStrokeWidth(40);
        mDefaultPaint.setColor(Color.GREEN);

        /*mFloodPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mFloodPaint.setStyle(Paint.Style.STROKE);
        mFloodPaint.setStrokeJoin(Paint.Join.ROUND);
        mFloodPaint.setStrokeCap(Paint.Cap.ROUND);
        mFloodPaint.setStrokeWidth(40);
        mFloodPaint.setColor(Color.GREEN);*/

        setFocusable(true);
        setFocusableInTouchMode(true);
        setBackgroundColor(Color.WHITE);

        setLayerType(LAYER_TYPE_SOFTWARE, null);
        setSaveEnabled(true);
    

    @Override
    public boolean onTouchEvent(@NonNull MotionEvent event) 
        final int pointerCount = MotionEventCompat.getPointerCount(event);

        switch (MotionEventCompat.getActionMasked(event)) 
        case MotionEvent.ACTION_DOWN: 
            if (isFill == true) 

                int xx = (int) event.getX();
                int yy = (int) event.getY();
                Point pp = new Point(xx, yy);

                /*Point pp = new Point();
                pp.x = (int) event.getX();
                pp.y = (int) event.getY();*/

                final int sourceColor = mLayerBitmap.getPixel(xx, yy);
                final int targetColor = mDefaultPaint.getColor();
//              final int targetColor = mFloodPaint.getColor();

                new TheTask(mLayerBitmap, pp, sourceColor, targetColor)
                        .execute();

//              JniBitmap.floodFill(mLayerBitmap, xx, yy, sourceColor,targetColor);

/*              FloodFill f = new FloodFill();
                f.floodFill(mLayerBitmap, pp, sourceColor, targetColor);*/

            
            else if(isFill == false)
                for (int p = 0; p < pointerCount; p++) 
                    final int id = MotionEventCompat.getPointerId(event, p);
                    DrawOp current = new DrawOp(mDefaultPaint);
                    current.getPath().moveTo(event.getX(), event.getY());
                    mCurrentOps.put(id, current);
                           
            
        
            break;

        case MotionEvent.ACTION_MOVE: 

                if (isFill == false) 

                final int id = MotionEventCompat.getPointerId(event, 0);
                DrawOp current = mCurrentOps.get(id);
                final int historySize = event.getHistorySize();
                for (int h = 0; h < historySize; h++) 
                    x = event.getHistoricalX(h);
                    y = event.getHistoricalY(h);
                    current.getPath().lineTo(x, y);
                
                x = MotionEventCompat.getX(event, 0);
                y = MotionEventCompat.getY(event, 0);
                current.getPath().lineTo(x, y);
            
        
            break;

        case MotionEvent.ACTION_UP: 
            if(isFill == false)
//              mLayerCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
            for (int p = 0; p < pointerCount; p++) 
                final int id = MotionEventCompat.getPointerId(event, p);
                mDrawOps.push(mCurrentOps.get(id));
                mCurrentOps.remove(id);
            
            updateLayer();
            
        
        /*  else
                for (int p = 0; p < pointerCount; p++) 
                    final int id = MotionEventCompat.getPointerId(event, p);
                    mDrawOps.push(mCurrentOps.get(id));
                    mCurrentOps.remove(id);
                
            */
//      
            break;

        case MotionEvent.ACTION_CANCEL: 
            if(isFill == false)
            for (int p = 0; p < pointerCount; p++) 
                mCurrentOps.remove(MotionEventCompat.getPointerId(event, p));
            
            updateLayer();
        
        
            break;

        default:
            return false;
        

        invalidate();
        return true;
    

    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;
            mLayerBitmap = bm;
            pd = new ProgressDialog(getContext());
            this.pt = p;
            this.replacementColor = tc;
            this.targetColor = sc;
            pd.setMessage("Filling....");
            pd.show();
        

        @Override
        protected void onPreExecute() 
        

        @Override
        protected void onProgressUpdate(Integer... values) 
        

        @Override
        protected Void doInBackground(Void... params) 
            FloodFill f = new FloodFill();
//           mLayerBitmap = f.floodFill(bmp, pt, targetColor, replacementColor);
            f.floodFill(mLayerBitmap, pt, targetColor, replacementColor);

//          New Commented Algorithm
//          f.FloodFill(mLayerBitmap, pt, targetColor, replacementColor);
            return null;
        

        @Override
        protected void onPostExecute(Void result) 
            pd.dismiss();
            invalidate();
            isFill = false;
        
    

    public void fillShapeColor(Bitmap mBitmap2) 
        isFill = true;
    

    /*public void fillShapeColor() 
        isFill = true;
    */

    public void setDrawing() 
        isFill = false;
    

    @Override
    protected void onSizeChanged(int w, int h, int oldW, int oldH) 
        super.onSizeChanged(w, h, oldW, oldH);
        mLayerBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        mLayerCanvas.setBitmap(mLayerBitmap);
        updateLayer();
    

/*  private void updateDLayer()
        mLayerCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
        for (DrawOp drawOp : mDrawOps) 
            if (drawOp != null) 
//              drawOp.draw(new Canvas(mLayerBitmap));
                drawOp.draw(mLayerCanvas);
            
        
        invalidate();
    */

    private void updateLayer() 
/*      isFill=false;
        if(isFill==false)
            mLayerCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
        
        else
            System.out.println("Not using mLayerCanvas.drawColor()");
        */
//      mLayerCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
//      this.getPaintStrokeWidth();
//      this.getPaintMaskFilter();

/*      if(isFill == false)
//      this.getPaintOpacity();
            mLayerCanvas.save();
//          mLayerCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
            mLayerCanvas.restore();
        */


        /*mDefaultPaint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
        mLayerCanvas.drawPaint(mDefaultPaint);
        mDefaultPaint.setXfermode(new PorterDuffXfermode(Mode.SRC));
        mLayerCanvas.drawPaint(mDefaultPaint);*/

/*      if(isFill==false)
            mLayerCanvas.save();
            mLayerCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
            mLayerCanvas.restore();
            invalidate();   
        
        else
            mLayerCanvas.save();
            for (DrawOp drawOp : mDrawOps) 
                if (drawOp != null) 
//                  drawOp.draw(new Canvas(mLayerBitmap));
                    drawOp.draw(mLayerCanvas);
                
            
            mLayerCanvas.restore();
        */

        /*DrawOp dr = new DrawOp(mDefaultPaint);
        if(dr.getPath().isEmpty())
//          isFill = true;
            isFill = false;

        
        else
            isFill=true;
            mLayerCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
        */

        if(isFill == false)
            mLayerCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
        

        for (DrawOp drawOp : mDrawOps) 
            if (drawOp != null) 
//              drawOp.draw(new Canvas(mLayerBitmap));
                drawOp.draw(mLayerCanvas);
            
        
        invalidate();
    

    @Override
    protected void onDraw(Canvas canvas) 
        super.onDraw(canvas);

        if (isInEditMode()) 
            return;
        

      /*int w = canvas.getWidth();
        int h = canvas.getHeight();
        canvas.drawRect(0,0,w,h, mDefaultPaint);*/
        canvas.drawBitmap(mLayerBitmap, 0, 0, null);

        for (int i = 0; i < mCurrentOps.size(); i++) 
            DrawOp current = mCurrentOps.valueAt(i);
            if (current != null) 
                current.draw(canvas);
            
        
    

    public void operationClear() 
        mDrawOps.clear();
        mUndoOps.clear();
        mCurrentOps.clear();
        // To Clear Whole Canvas
        mLayerCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
        updateLayer();
    

    public void operationUndo() 
        if (mDrawOps.size() > 0) 
            mUndoOps.push(mDrawOps.pop());
            updateLayer();
        
    

    public void operationRedo() 
        if (mUndoOps.size() > 0) 
            mDrawOps.push(mUndoOps.pop());
            updateLayer();
        
    

    public void setPaintStrokeWidth(float widthPx) 
        mDefaultPaint.setStrokeWidth(widthPx);
//      mFloodPaint.setStrokeWidth(widthPx);
    

    /*public float getPaintStrokeWidth()
        return mDefaultPaint.getStrokeWidth();

    */

    public void setPaintOpacity(int percent) 
        int alphaValue = (int) Math.round(percent * (255.0 / 100.0));
        mDefaultPaint.setColor(combineAlpha(mDefaultPaint.getColor(),
                alphaValue));

//      mFloodPaint.setColor(combineAlpha(mFloodPaint.getColor(),
//              alphaValue));
    

    /*public int getPaintOpacity()
        this.setPaintOpacity(50);
        return mDefaultPaint.getColor();
    */

    public void setPaintColor(String color) 
        mDefaultPaint.setXfermode(null);
        mDefaultPaint.setColor(combineAlpha(Color.parseColor(color),
                mDefaultPaint.getAlpha()));
//      mDefaultPaint.setColor(mDefaultPaint.getAlpha());

        mFloodPaint.setXfermode(null);
        mFloodPaint.setColor(combineAlpha(Color.parseColor(color),
                mFloodPaint.getAlpha()));
    

    public void setPaintColor(int color) 
        mDefaultPaint.setXfermode(null);
        mDefaultPaint.setColor(combineAlpha(color, mDefaultPaint.getAlpha()));

        mFloodPaint.setXfermode(null);
        mFloodPaint.setColor(combineAlpha(color, mFloodPaint.getAlpha()));
    

//  New Created
    public void setEraser(int color)
//      mDefaultPaint.setAlpha(0xFF);
        mDefaultPaint.setColor(color);
        mDefaultPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
    

    public void setPaintMaskFilter(MaskFilter filter) 
        mDefaultPaint.setMaskFilter(filter);

//      mFloodPaint.setMaskFilter(filter);
    

    /*public MaskFilter getPaintMaskFilter()
        return mDefaultPaint.getMaskFilter();

    */

    public void setPaintShader(BitmapShader shader) 
        mDefaultPaint.setShader(shader);

//      mFloodPaint.setShader(shader);
    

    public void setPaintColorFilter(ColorFilter colorFilter) 
        mDefaultPaint.setColorFilter(colorFilter);

//      mFloodPaint.setColorFilter(colorFilter);
    

    private static int combineAlpha(int color, int alpha) 
        return (color & 0x00FFFFFF) | ((alpha & 0xFF) << 24);
    

    private static class DrawOp 
        private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        private final Path mPath = new Path();

        public DrawOp(Paint paint) 
            reset(paint);
        

        void reset(Paint paint) 
            mPath.reset();
            update(paint);
        

        void update(Paint paint) 
            mPaint.set(paint);
        

        void draw(Canvas canvas) 
            canvas.drawPath(mPath, mPaint);
        

        public Path getPath() 
            return mPath;
        
    

      public void setFillColor(boolean flag)
            this.isFill = flag;
        

【问题讨论】:

【参考方案1】:

更新您的 updateLayer() 方法,如下所示:

private void updateLayer() 
        /*if(isFill == false)
            mCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
        */

        for (DrawOp drawOp : mDrawOps) 
            if (drawOp != null) 
                drawOp.draw(mCanvas);
            
        
        invalidate();
    

【讨论】:

以上是关于当使用洪水填充算法填充颜色后绘制线条时,填充颜色消失的主要内容,如果未能解决你的问题,请参考以下文章

洪水覆盖算法(Flood Fill):颜色填充

R语言使用ggplot2包使用geom_density()函数绘制密度图(自定义颜色填充线条色彩分组均值线)实战(density plot)

Java GUI 填充错误

用一种颜色作为描边绘制一个多边形,用另一种颜色作为填充?

达到边界颜色时,填充无法填充整个形状?

图像处理------泛洪填充算法(Flood Fill Algorithm) 油漆桶功能