I define a custom canvas in a view,when running it will draw the background then draw some picture.and the background is an image too.When trigger onTouchEventmethod ,will refresh the canvas,then draw background then few picutures,but there will leave the moving trace of later pictures on the background,I don't know how to clear the moving trace ,and if I assign a color to background,there will be no trace leave,Could anyone help me solve this?thank you very much.:D
ADD:
canvas = new Canvas(bgbitmap);
draw background
canvas.drawColor(selectedColor);
if use drawBitmap draw background cause matter:
// canvas.drawBitmap(bgbitmap, 0, 0, null);
// draw picutre
for (int i = fbmpCount - 1; i >= 0; i--) {
FreeBitmap fb = findFreeBmpByPriority(i);
if (fb != null)
this.canvas.drawBitmap(fb.getBmp(), fb.getXpoint(), fb.getYpoint(),
null);
}
this.invalidate();
// onDraw method
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(bgbitmap, 0, 0, null);
}
You would have to clear the canvas before redrawing from my understanding.
Canvas.drawColor(Color.WHITE)
Related
i am new to android canvas and i failed to get solution of my problem,
the problem is:
I am using canvas in two modes AvoidXfermode.Mode.TARGET(to remove occurence of a single color) and PorterDuff.Mode.CLEAR(to erase a part of my canvas).
everything independently is working perfect
but in my code i want to use both of them in such a way that when i choose i want to erase a particular color it should erase it, and my code is doing so,
but after removing that particular color when i am switching my mode to eraser mode...everything which was deleted using AvoidXfermode comes back.
i am doing these things on a bitmap,
my onDraw method is:
#Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(DrawBitmap, 0, 0, DrawBitmapPaint);
if (flag != 1) {
setDrawingCacheEnabled(true);
for (Path p : paths) {
canvas.drawPath(p, mPaint);
Bitmap bitmap = getDrawingCache();
DrawBitmap = bitmap;
//
}
//canvas.setBitmap(bitmap.isMutable() ? bitmap : bitmap.copy(Bitmap.Config.ARGB_8888,true));
} else if (flag == 1) {
if (touchx > mCanvas.getWidth() || touchy > mCanvas.getHeight() || touchx < 0 || touchy < 0) {
return;
}
for (Path p : paths) {
color = DrawBitmap.getPixel(touchx, touchy);
mPaint.setXfermode(new AvoidXfermode(color, 100, AvoidXfermode.Mode.TARGET));
mPaint.setColor(Color.TRANSPARENT);
canvas.drawPaint(mPaint);
setDrawingCacheEnabled(true);
Bitmap bitmap = getDrawingCache();
DrawBitmap = bitmap;
}
}
}
everything is declared in onDraw for now just for the this question,
and the code where i switch my mode is:
case R.id.erase:
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
mPaint.setColor(Color.TRANSPARENT);
mPaint.setStrokeWidth(40);
flag = 0;
break;
case R.id.DELETE:
flag = 1;
break;
the code where i am creating my canvas is:
DrawBitmap = BitmapFactory.decodeResource(MainActivity.this.getResources(), R.drawable.sample);
DrawBitmap = DrawBitmap.copy(Bitmap.Config.ARGB_8888, true);
mCanvas = new Canvas(DrawBitmap);
mPath = new Path();
paths.add(mPath);
DrawBitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
i am wrong somewhere,but i don't know where, any suggestions would be helpful, thanks in advance.
Bitmap bitmap = getDrawingCache();
DrawBitmap = bitmap;
Your logic is a lot complicated. I specifically mean the above lines of code. You have mCanvas that is backed up with the DrawBitmap bitmap. Then you have the canvas of onDraw() which is backed by it's own bitmap. The thing you need to understand is whatever you draw in DrawBitmap stays or as you would call it "saved". Anything that is drawn via canvas is subjected to change during the next call to onDraw().
So if you want to save something in DrawBitmap use the mCanvas. The moment you want to save the state of the user's drawing, draw it in mCanvas. You could just draw everything on mCanvas and at the end of onDraw(), you can call canvas.drawBitmap(DrawBitmap, 0, 0, DrawBitmapPaint); This way everything that is done by the user is saved every step of the way.
I'm trying to create a view that draws a background colour with an image on top of it. The image should be transformed by a matrix. The background should not be.
The onDraw() method looks like this:
protected void onDraw(Canvas canvas) {
canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), paint);
Drawable drawable = getImageDrawable();
if (drawable == null) {
return;
}
int count = canvas.save();
if (clipRect != null) {
canvas.clipRect(clipRect);
}
canvas.concat(matrix);
drawable.draw(canvas);
canvas.restoreToCount(count);
}
On some of the devices I've tested on, the background above and to the left of the image is not drawn correctly. See video here:
https://youtu.be/rno2XxaeNUA You'll need to pause the video to see what's going on.
This problem was caused by accidentally overriding View.getMatrix()
I am learning on canvas and bitmap with paths and currently working on a drawing app where user can draw paths freely on the extended view.
The app also allow allowing user to import bitmap as the background and draw on it.
Extending the View named DoodleView:
public DoodleView(Context context, AttributeSet attrs)
{
super(context, attrs); // pass context to View's constructor
this.context_new=context;
setFocusable(true);
setFocusableInTouchMode(true);
} // end DoodleView constructor
onDraw:
#Override
protected void onDraw(Canvas canvas)
{
canvas.drawBitmap(bitmap, 0, 0, null);
for (Path p : paths)
{
paintLine.setColor(colorsMap.get(p));
canvas.drawPath(p, paintLine);
}
paintLine.setColor(selectedColor);
canvas.drawPath(mPath, paintLine);
if (ConvertCanvasToBitmap == true)
{
canvas.drawBitmap(bitmap, 0, 0, paintLine);
ConvertCanvasToBitmap = false;
}
}
FlipHorizontally:
public void flipImageHorizontally()
{
ConvertCanvasToBitmap = true;
invalidate();
Matrix flipHorizontalMatrix = new Matrix();
flipHorizontalMatrix.setScale(-1,1);
flipHorizontalMatrix.postTranslate(bitmap.getWidth(),0);
Bitmap HorizontalFlipped = Bitmap.createBitmap
(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), flipHorizontalMatrix, true);
bitmap = HorizontalFlipped;
invalidate();
}
Question:
My goal is that for the paths that are already drawn, when the user tries to flip the image, the paths drawn would also be flipped. (i.e. the paths become part of the image already, and user are disallows to undo the paths anymore).
However, I have tested using the above codes, when the flip button is pressed, the bitmap background can be flipped, yet the drawn would disappear. And then when further drawn on it, the paths will appear again, but stay unflipped.
In short, how to make the paths to become part of the bitmap when the flip button is pressed?
Thanks!
Edit:
Based on the Android 2.1 View's getDrawingCache() method always returns null, I have modified the onDraw with the following code, but got
02-22 21:38:34.685: E/AndroidRuntime(18617): java.lang.NullPointerException
02-22 21:38:34.685: E/AndroidRuntime(18617): at android.graphics.Bitmap.createBitmap(Bitmap.java:455)
02-22 21:38:34.685: E/AndroidRuntime(18617): at com.pearmak.drawing.DoodleView.onDraw(DoodleView.java:148)
Modified code:
#Override
protected void onDraw(Canvas canvas)
{
canvas.drawBitmap(bitmap, 0, 0, null); // draw the background screen
for (Path p : paths)
{
paintLine.setColor(colorsMap.get(p));
paintLine.setStrokeWidth(widthMap.get(p));
canvas.drawPath(p, paintLine);
}
paintLine.setColor(selectedColor);
paintLine.setStrokeWidth(selectedWidth);
canvas.drawPath(mPath, paintLine);
if (ConvertCanvasToBitmap == true)
{
//Method 1
// RelativeLayout page = (RelativeLayout) findViewById(R.id.doodleView);
// Bitmap screenshot = Bitmap.createBitmap(page.getWidth(), page.getHeight(), Config.ARGB_8888);
// bitmap = screenshot;
// ConvertCanvasToBitmap = false;
//Method 2
Bitmap screenshot2;
layout(0, 0, DoodlzViewWidth, DoodlzViewHeight);
setDrawingCacheEnabled(true);
screenshot2 = Bitmap.createBitmap(getDrawingCache()); // LINE 148
setDrawingCacheEnabled(false);
bitmap = screenshot2;
}
}
you need to create the bitmap from that view
please refer to drawingcache like here
Android 2.1 View's getDrawingCache() method always returns null
now try to flip this bitmap
I have prepared one paint app.In my app we can draw any thing.It is working fine.Here i want prepare finger erase for erase paint.Eraser is working,but it is eraser all the drawn paint.I want to eraser only where i touch if drawn paint is there for that i wrote some code,
this my ondraw method,
public void onDraw(Canvas canvas) {
if (myDrawBitmap == null) {
myDrawBitmap = Bitmap.createBitmap(480, 800,
Bitmap.Config.ARGB_8888);
mBmpDrawCanvas = new Canvas(myDrawBitmap);
mIntDrawArray = new int[myDrawBitmap.getWidth()
* myDrawBitmap.getHeight()];
}
if (mBmpDrawCanvas != null) {
myDrawBitmap.getPixels(mIntDrawArray, 0, myDrawBitmap.getWidth(),
0, 0, myDrawBitmap.getWidth(), myDrawBitmap.getHeight());
for (Path path : ILearnPaintActivity.mArryLstPath) {
if (ILearnPaintActivity.mArryLstPath.contains(path)
&& ILearnPaintActivity.paintAndEraserFlag == 1) {
mPaint.setXfermode(new PorterDuffXfermode(
PorterDuff.Mode.CLEAR));
mBmpDrawCanvas.drawPath(ILearnPaintActivity.mPath, mPaint);
} else {
mBmpDrawCanvas.drawPath(ILearnPaintActivity.mPath, mPaint);
}
}
if (myDrawBitmap != null)
canvas.drawBitmap(myDrawBitmap, 0, 0, null);
}
}
draw paint is working fine.In same activity i have one button "Eraser". when we click on eraser button i assign flag for difference.Please help me how to do this...
first u need to make clear what erase.
for vector base canvas it's delete vector element.
for pixel base canvas it's mean draw with backgournd color. (or make it's transparency)
so in my point of view. when erase. you can change a Paint with backgournd color. and continue draw a very bold line on bitmap by touch.
try like this
mBitmap.eraseColor(Color.TRANSPARENT); // Bitmap erase color
mPath.reset(); // your path
mView.invalidate(); // your View Path
Good Day Everyone
I was hoping if you could help me understand the concepts of understanding how to add an image into a canvas on a OnTouchEvent implemented on a View. So far, this is what i've come up with.
parent is the Activity where in this customized view is instantiated and is added into.
#Override
protected void onDraw(Canvas canvas)
{
// TODO Auto-generated method stub
super.onDraw(canvas);
}
public void insertImage()
{
if (parent.selected_icon.contentEquals("image1"))
{
image = getResources().getDrawable(R.drawable.image1);
}
else if (parent.selected_icon.contentEquals("image1"))
{
image = getResources().getDrawable(R.drawable.image2);
}
else if (parent.selected_icon.contentEquals("iamge3"))
{
image = getResources().getDrawable(R.drawable.image3);
}
Rect srcRect = new Rect(0, 0, image.getIntrinsicWidth(),
image.getIntrinsicHeight());
Rect dstRect = new Rect(srcRect);
Bitmap bitmap = Bitmap.createBitmap(image.getIntrinsicWidth(),
image.getIntrinsicHeight(), Bitmap.Config.ALPHA_8);
Canvas canvas = new Canvas();
canvas.drawBitmap(bitmap, srcRect, dstRect, null);
invalidate();
}
When you want to draw over a view, you have to do that in onDraw(), using the Canvas passed there. That Canvas is already bound to the Bitmap that is the actual drawing of your view.
I had to do something similar and my approach was like this:
I had a list of "things to be drawn over the view" as a member of the class.
whenever I added something to that list, I called invalidate(), so that onDraw() would get called.
My onDraw() looked like this:
...
protected void onDraw(Canvas canvas) {
super.onDraw(canvas); // the default drawing
for(ThingToBeDrawn thing : mListOfThingsToBeDrawn) {
thing.drawThing(canvas); // draw each thing over the view
}
}
A Canvas is just a tool used to draw a Bitmap, and it works quite differently than SurfaceView.