Android 在不丢失任何绘图的情况下更改画布背景颜色
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10268724/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Android change canvas background color without losing any drawings from it
提问by Android-Droid
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 which can draw on canvas and than save it as png. But when I set a new background to the current canvas, all drawings are gone. I'm using something like this :
我正在尝试找到一种方法来设置画布背景,并使用从自定义颜色选择器中提取的颜色,而无需删除其上的任何绘图。我正在尝试创建一个可以在画布上绘制而不是将其保存为 png 的应用程序。但是当我为当前画布设置新背景时,所有绘图都消失了。我正在使用这样的东西:
mCanvas.drawColor(picker.getColor());
mCanvas.drawColor(picker.getColor());
Any ideas how I can get things to work?
任何想法如何让事情发挥作用?
回答by epichorns
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...
已经对您的问题给出的答案都指向正确的方向:您确实需要在不同的图层中将背景色块和前景图分开,然后将它们合并,然后再将其全部保存在 .png 文件中。这也是 Adobe Photoshop 工作流程的设计方式......如果我们考虑一下,它确实有道理:例如像 MsPaint 这样的软件:因为它不使用图层,所以它必须依赖于诸如洪水填充算法之类的东西完成(尽管以不完整的方式)一些类似于背景变化的东西......
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.
实现这种事情的一种方法是实例化由 2 个不同位图支持的 2 个 Canvas 对象。第一个 Canvas-Bitmap 对将用于前景绘制,第二个 Canvas-Bitmap 对将用于合并图层绘制(即前景绘制 + 背景色块)。然后第二个位图将在您需要保存时保存到 .png 文件中。这样,我们的第一个 Canvas-Bitmap 对存储您的前景信息,如果需要更改背景颜色,这些信息不会被破坏。每次进行操作时,图层都可以合并到第二个 Canvas-Bitmap 对中,这样总有一个包含正确内容的 Bitmap 可以随时保存。
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:
这是我制作的自定义视图,以清除这种方法。它实现了一个简单的视图,用于使用手指在触摸屏上绘制蓝线,背景颜色根据所述手指的 XY 位置而变化,以演示背景颜色变化,而无需完整实现所固有的不必要的代码复杂性带有色轮/菜单/除其他外:
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:
为了测试这个视图,这里有一个使用PaintView
该类的测试 Activity 。这两个文件在 Android 项目中都是自给自足的,因此您可以在真实设备上轻松测试它:
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);
}
}
回答by omers
When you draw the color, it's drawn over your drawings. You need to draw the color, and then draw every thing else again.
当您绘制颜色时,它会绘制在您的图纸上。您需要绘制颜色,然后再次绘制所有其他东西。
回答by Tofeeq Ahmad
Look if you want to change in canvas then you have to call invalidate to apply these changes your screen.And if you call invalidate then your onDraw()
method will call.
看看如果你想改变画布,那么你必须调用 invalidate 来应用这些更改你的屏幕。如果你调用 invalidate 那么你的onDraw()
方法将调用。
If you want to change just background color of canvas from color picker then save color value in variable and call invalidate just after saving variable.Now your onDraw()
will call.Now change background of canvas by calling setBackgroundColor(color variable)
in onDraw()
and draw everything else you want
如果您只想从颜色选择器更改画布的背景颜色,则将颜色值保存在变量中,并在保存变量后立即调用 invalidate。现在您onDraw()
将调用setBackgroundColor(color variable)
。现在通过调用onDraw()
并绘制您想要的其他所有内容来更改画布的背景
回答by Pranav
use canvas.drawARGB(a,r,g,b) and it will work for definite
使用 canvas.drawARGB(a,r,g,b) 它将为确定的
回答by Deeps
@ Android-Droid
@安卓机器人
These two lines of code worked like charm for me. When ever user clicks on any color (Eg: Red ) set that color to mPaint like
这两行代码对我来说很有魅力。当用户点击任何颜色(例如: Red )时,将该颜色设置为 mPaint 之类的
mPaint.setColor(Color.RED);
and when ever you wish to change canvas color
当你想改变画布颜色时
dv.setBackgroundColor(mPaint.getColor());
where dv is the object of the class which extends view (Custom View). Try it and let me know if you face any issues.
其中 dv 是扩展视图(自定义视图)的类的对象。尝试一下,如果您遇到任何问题,请告诉我。
回答by JCarangoH
Maybe it's an old question but i want to contribute with this solution, In case you are taking the bitmap from a source, and then doing a drawable with canvas, maybe this can fit u:
也许这是一个老问题,但我想为这个解决方案做出贡献,如果您从源中获取位图,然后使用画布进行可绘制,也许这适合您:
@Override
public Bitmap transform(final Bitmap source) {
//Background for transparent images
Bitmap backg = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);
backg.eraseColor(Color.WHITE); // Any color you want...
Paint back = new Paint();
BitmapShader backshader = new BitmapShader(backg,
BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP);
back.setShader(backshader);
back.setAntiAlias(true);
// Image for the draw
final Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setShader(new BitmapShader(source, Shader.TileMode.CLAMP,
Shader.TileMode.CLAMP));
Bitmap output = Bitmap.createBitmap(source.getWidth(), source.getHeight(), source.getConfig());
Canvas canvas = new Canvas(output);
// IMPORTANT THING
canvas.drawRoundRect(new RectF(margin, margin, source.getWidth()
- margin, source.getHeight() - margin), radius, radius, back); // Draw the background first...
canvas.drawRoundRect(new RectF(margin, margin, source.getWidth()
- margin, source.getHeight() - margin), radius, radius, paint); // And then Draw the image, so it draws on top of the background
if (source != output) {
source.recycle();
}
// This is for if i want to put a border in the drawable, its optional
Paint paint1 = new Paint();
paint1.setColor(Color.parseColor("#CC6C7B8B"));
paint1.setStyle(Style.STROKE);
paint1.setAntiAlias(true);
paint1.setStrokeWidth(2);
canvas.drawRoundRect(new RectF(margin, margin, source.getWidth()
- margin, source.getHeight() - margin), radius, radius, paint1);
// and then, return the final drawable...
return output;
}
Hope it helps...
希望能帮助到你...
回答by Bondax
As long as your background is and will be in another color, you can do:
只要您的背景是并且将是另一种颜色,您就可以执行以下操作:
for (x...)
for (y...)
if (bitmap.getPixel(x,y) == oldBackgroundColor)
bitmap.setPixel(x,y,newBackgroundColor)
Or, you can draw your content on an offscreen bitmap, and draw the background and then the offscreen to the actual bitmap. That way you can change the backgroundcolor that will be used when the next two-step-drawing will happen.
或者,您可以在屏幕外位图上绘制您的内容,然后绘制背景,然后将屏幕外绘制到实际位图上。这样您就可以更改将在下一个两步绘制发生时使用的背景颜色。