Android change canvas background color without losing any drawings from it

后端 未结 3 1747
暗喜
暗喜 2021-02-09 02:22

I\'m trying to find a way to set background of canvas with a color picked up from custom color picker without removing any drawings on it. I\'m trying to create an application w

3条回答
  •  一生所求
    2021-02-09 02:29

    The answers already given to your question are all pointing in the right direction: you do need to separate your background color block and your foreground drawing in separate layers, then merge them before saving the whole of it in a .png file. This is how Adobe Photoshop workflow is designed as well... It does make sense, if we think about it: take for example a software like MsPaint: because it doesn't use layers, it has to rely on stuff like floodfill algorithms to accomplish (albeit in an incomplete way) something remotely similar to a background change...

    One way to implement such a thing would be to instantiate 2 Canvas objects backed by 2 different bitmaps. The first Canvas-Bitmap pair would be used for your drawing at the foreground, and the second Canvas-Bitmap pair would be used for your merged-layers drawing (i.e. foreground drawing + background color block). Then the 2nd Bitmap is what will be saved to a .png file when you need it to be saved. This way, our first Canvas-Bitmap pair stores your foreground info, which is not destroyed if a background color change needs to be made. Everytime an operation is made, the layers can be merged into the 2nd Canvas-Bitmap pair so that there is always a Bitmap with the correct content that is ready to be saved at your whim.

    Here is a custom View I made so as to clear this methodology up. It implements a simple view used to paint a blue line on the touch-screen using a finger, with a background color changing depending on the X-Y position of said finger so as to demonstrate a background color change without unnecessary code complexity inherent of a complete implementation with a color wheel/menus/inter alia:

    package com.epichorns.basicpaint;
    
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.graphics.Point;
    import android.graphics.Paint.Style;
    import android.view.View;
    
    public class PaintView extends View{
    
        Bitmap mMergedLayersBitmap=null; //Note: this bitmap here contains the whole of the drawing (background+foreground) to be saved.
        Canvas mMergedLayersCanvas=null;
    
        Bitmap mBitmap = null; //bitmap onto which we draw our stuff
        Canvas mCanvas = null; //Main canvas. Will be linked to a .bmp file
        int mBackgroundColor = 0xFF000000; //default background color
        Paint mDefaultPaint = new Paint();
    
        Paint mDrawPaint = new Paint(); //used for painting example foreground stuff... We draw line segments.
        Point mDrawCoor = new Point(); //used to store last location on our PaintView that was finger-touched
    
        //Constructor: we instantiate 2 Canvas-Bitmap pairs
        public PaintView(Context context, int width, int height) {
            super(context);
            mMergedLayersBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 
            mMergedLayersCanvas = new Canvas(mMergedLayersBitmap);
    
            mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            mCanvas = new Canvas(mBitmap);
        }
    
        //Change background color
        public void changeColor(int newColor){
            mBackgroundColor = newColor;
            invalidate(); //refresh view: this will indirectly invoke onDraw soon afterwards
        }
    
        //Called by user of PaintView in order to start a painting "stroke" (finger touching touch-screen): stores the 
        //location of the finger when it first touched the screen
        public void startDraw(int x, int y, int radius, int color){
            mDrawPaint.setColor(color);
            mDrawPaint.setStyle(Style.STROKE);
            mDrawPaint.setStrokeWidth(radius);
            mDrawCoor.x = x;
            mDrawCoor.y = y;        
        }
    
        //Called by user of PaintView when finger touching touch-screen is moving (must be called after a startDraw, 
        //as the latter initializes a couple of necessary things)
        public void continueDraw(int x, int y){
            mCanvas.drawLine(mDrawCoor.x, mDrawCoor.y, x, y, mDrawPaint);
            mDrawCoor.x = x;
            mDrawCoor.y = y;
            invalidate(); //refresh view: this will indirectly invoke onDraw soon afterwards
        }
    
        //Merge the foreground Canvas-Bitmap with a solid background color, then stores this in the 2nd Canvas-Bitmap pair.
        private void mergeLayers(){
            mMergedLayersCanvas.drawColor(mBackgroundColor);
            mMergedLayersCanvas.drawBitmap(mBitmap, 0, 0, mDefaultPaint);
        }
    
        @Override
        public void onDraw(Canvas canvas){
            mergeLayers();
            canvas.drawBitmap(mMergedLayersBitmap, 0, 0, mDefaultPaint);
        }
    
    }
    

    In order to test this view, here is a test Activity that uses the PaintView class. Both of those files are self-sufficient in an Android project, so that you can test it on your real device without hassle:

    package com.epichorns.basicpaint;
    
    import android.app.Activity;
    import android.graphics.Color;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.Display;
    import android.view.MotionEvent;
    import android.view.View;
    import android.widget.LinearLayout;
    
    
    import com.epichorns.basicpaint.PaintView;
    public class BasicPaintActivity extends Activity {
        PaintView mPaintView=null;
        LinearLayout mL = null;
        boolean mIsDrawing=false;
        int mBackgroundColor = 0xFF000000;
    
        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            Display display = getWindowManager().getDefaultDisplay();       
            final float dispWidth = (float)display.getWidth();
            final float dispHeight = (float)display.getHeight();
    
            mPaintView = new PaintView(this, display.getWidth(), display.getHeight());    
            mPaintView.changeColor(mBackgroundColor);
            mPaintView.setOnTouchListener(new View.OnTouchListener(){
    
                public boolean onTouch(View v, MotionEvent event) {
    
                if(event.getAction()==MotionEvent.ACTION_DOWN){
                        mPaintView.startDraw((int)event.getX(), (int)event.getY(), 6, 0x806060FF);              
                        mIsDrawing=true;
                        return true;
                    }
                    else if(event.getAction()==MotionEvent.ACTION_UP){
                        mIsDrawing=false;
                        return true;
                    }
                    else if(event.getAction()==MotionEvent.ACTION_MOVE){
                        if(mIsDrawing){
    
                            //To demonstrate background change, change background color depending on X-Y position
                            int r = (int)(255f*event.getX()/dispWidth);
                            int g = (int)(255f*event.getY()/dispHeight);
                            mBackgroundColor = Color.argb(0xFF, r,g, 0x00);
                            Log.d("DEBUG1", "Color channels: (r, g) = ("+String.valueOf(r)+", "+String.valueOf(g)+")");
                            mPaintView.changeColor(mBackgroundColor);
    
                            //now, draw stuff where finger was dragging...
                            mPaintView.continueDraw((int)event.getX(), (int)event.getY());
                            return true;
                        }
                        else{
                            return false;
                        }
    
                    }
    
                    return false;
                }
    
            });
    
            setContentView(mPaintView);
        }
    
    
    
    
    }
    

提交回复
热议问题