How to delete the image drawn in Canvas? - android

How will I delete the image drawn on my canvas if my code is this? Where will I put the delete process here? I've tried using the canvas.drawColor(Color.BLACK); but it is not working.
#Override
protected void onDraw(Canvas canvas) {
canvas.drawPath(path, paint);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float eventX = event.getX();
float eventY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
path.moveTo(eventX, eventY);
return true;
case MotionEvent.ACTION_MOVE:
path.lineTo(eventX, eventY);
break;
case MotionEvent.ACTION_UP:
// nothing to do
break;
default:
return false;
}
// Schedules a repaint.
invalidate();
return true;
}
}

Old thread I know, but I was mucking around with API fingerpaint demo and wanted to clear canvas but not fill with solid colour (I had a background). Building on #coder_For_Life22 answer above I included following method:
protected void clear(){
Xfermode x = mPaint.getXfermode();
mPaint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
mCanvas.drawPaint(mPaint);
mPaint.setXfermode(x);
//Schedule redraw()
invalidate();
}

Try this with your Paint object..
Paint paint = new Paint();
paint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
canvas.drawPaint(paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC));

When invalidate() (or postInvalidate() from another thread) is called, onDraw() is subsequently called to redraw the entire area of the image. The Canvas object that is passed to onDraw() is backed with a bitmap that is already blank.
I realise that this doesn’t directly answer your question, but from reading your question I wonder if you’re misunderstanding the sequence of events that happen with invalidate() and onDraw(), together with the fact that you’re given a blank Canvas each time meaning you shouldn’t have a need to erase it.
It seems to me that what you're doing is you're trying to build up a Path vector representing the screen MotionEvents. Looking at your code as it stands, it seems to me that you may want to erase all drawn graphics by clearing all segments from your Path object.

canvas.drawColor(0xff000000); // i can't see why it should not work except the clip rect mentioned below
or
Paint paint = new Paint();
paint.setStyle(Style.FILL);
paint.setColor(0xff000000); // Specify the drawing color here
canvas.drawRect(0,0,w,h, paint);
always make sure that you did not set a clip that would influence the drawing behaviour.

Related

Background image color detection with Android Paint

When I start painting , it colors the whole background , I mean it should only paint the white spots.
Application screenshot is as follows.
Using Android Paint ,I want to paint only white spots on background-drawable[Panda] and skip any other color.
onDraw() function is:
protected void onDraw(Canvas canvas) {
canvas.drawPath(path, paint);
canvas.drawPath(circlePath, circlePaint);
for (Pair<Path,Integer> path_clr : path_color_list ){
paint.setColor(path_clr.second);
canvas.drawPath( path_clr.first, paint);
}
for (Pair<Path,Integer> path_clr : circular_path_color_list ){
circlePaint.setColor(path_clr.second);
canvas.drawPath( path_clr.first, paint);
}
}
and onTouchEvent function is:
public boolean onTouchEvent(MotionEvent event) {
float pointX = event.getX();
float pointY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
circlePath.reset();
path.moveTo(pointX, pointY);
return true;
case MotionEvent.ACTION_MOVE:
path.lineTo(pointX, pointY);
circlePath.reset();
circlePath.addCircle(pointX, pointY, 10, Path.Direction.CW);
break;
case MotionEvent.ACTION_UP:
circlePath.reset();
break;
default:
return false;
}
postInvalidate();
return true;
}
The thing you're describing is called masking. You need a mask (white areas) and a masked image (your strokes). When drawing, you have to use the mask to cut your strokes to a shape of the mask. It can be done using PorterDuff modes. See the pseudocode:
Bitmap panda;
Bitmap whiteAreas;
Bitmap strokes;
Canvas strokesCanvas;
Paint paint;
private void init() {
strokesCanvas = new Canvas(strokes);
paint = new Paint();
}
private void addStroke(Path stroke){
paint.setXfermode(null);
strokesCanvas.drawPath(stroke,paint);
invalidate();
}
#Override
public void draw(Canvas canvas) {
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
strokesCanvas.drawBitmap(whiteAreas,0,0,paint);
paint.setXfermode(null);
canvas.drawBitmap(panda,0,0,paint);
canvas.drawBitmap(strokes,0,0,paint);
}
See the link for more info: http://ssp.impulsetrain.com/porterduff.html
EDIT: Here's an image how it works. Blue areas should be transparent. Multiplication between the mask and the strokes is what's called masking.

Can I draw alpha using just one bitmap?

I have the following code to draw on a canvas. That code is taken from SO and Android SDK demos and I have skimmed it down to better explain my problem. The code is essentially working, but it makes older parts of the alpha drawings get darker over time because it draws the bitmap over and over in onDraw() (which is not a problem while using solid lines as demonstrated in the SDK, but which becomes one when using alpha).
public class CanvasView extends View {
public void init() {
bitmap = Bitmap.createBitmap(1280, 720, Bitmap.Config.ARGB_8888); // a bitmap is created
canvas = new Canvas(bitmap); // and a canvas is instantiated
}
// Events
#Override public boolean onTouchEvent(#Nonnull MotionEvent event) {
float x = event.getX(); float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: // when the user touches down
path.reset(); // the previous path is reset (if any)
drawingTool.down(); // my own class which encapsulates path.moveTo()
break;
case MotionEvent.ACTION_MOVE: // when the user paints
Rect dirtyRect = drawingTool.move(x, y); // encapsulates path.quadTo() // the path is built
if (dirtyRect != null) { invalidate(dirtyRect); } // and the dirty rectangle is invalidated
break;
case MotionEvent.ACTION_UP: // when the user lifts the finger
canvas.drawPath(path, paint); // the final path is drawn
path.reset();
invalidate(); // and the full area invalidated (just to make sure the final drawing looks as it should)
break;
}
return true;
}
#Override protected void onDraw(#Nonnull Canvas canvas) { // after every move or up event
super.onDraw(canvas);
canvas.drawBitmap(bitmap, 0, 0, null); // the previous bitmap is drawn [here is the problem]
canvas.drawPath(path, paint); // and the new path is added
}
}
The problem happens in onDraw(), because the bitmap is drawn over and over. So every time a new path is finished, the previous drawing becomes darker.
I know I could take a second bitmap and cache the results after each path is drawn, and then apply that "clean" bitmap for each new path. But this would be expensive.
Is there a way to draw alpha lines without using a second bitmap or re-drawing everything after each path? I am looking for an inexpensive solution.
Problem here is that bitmap and canvas are directly coupled, so when I draw on the canvas, the result immediately reflects in the bitmap. So I can't just clear one or the other?
I played with this for some time and I realized that the solution is as simple as switching the two commands in onDraw.
Instead of
canvas.drawBitmap(bitmap, 0, 0, null);
canvas.drawPath(path, paint);
use
canvas.drawPath(path, paint);
canvas.drawBitmap(bitmap, 0, 0, null);
Drawing the bitmap last solves the problem. It is still too dark while being painted, so it needs some more tweaking, but the main problem is solved.
Plus, the good thing about it is that I won't need a second bitmap. But it is also clear that a second bitmap wouldn't have made much sense, as my bitmap is caching the image already and onDraw() just draws it into the view.
Actually you can set alpha level to Paint object. For example:
Paint transparentpaint = new Paint();
transparentpaint.setAlpha(100); // 0 - 255
canvas.drawBitmap(bitmap, 0, 0, transparentpaint);
Try to paste this instead of canvas.drawBitmap(bitmap, 0, 0, null);

Erase paths that are redrawn out of a List

I've been working on a drawing app for Android lately and I am now facing a problem I cannot solve.
The idea is to be able to draw on two drawing layers. When changing to the 2nd layer you only see the drawings of this layer, while being in the 1st layer you see both layers with the 2nd being slightly transparent.
To do this I have two lists which save the drawn paths and paints.
case MotionEvent.ACTION_DOWN:
//save a path to the list
Paint strokePaint=new Paint();
Path strokePath=new Path();
setupDrawingPaint(strokePaint); //some initialization
stroke = new Stroke(strokePath, strokePaint); //object to save the paths
stroke.movePath(touchX, touchY);
if(drawingLayer==1){
strokeListL1.add(stroke);
}
else{
strokeListL2.add(stroke);
}
//draw the path
drawingPath.moveTo(touchX, touchY);
break;
case MotionEvent.ACTION_MOVE:
stroke.linePath(touchX, touchY);
drawingPath.lineTo(touchX, touchY);
break;
case MotionEvent.ACTION_UP:
canvas.drawPath(drawingPath, drawingPaint);
drawingPath.reset()
break;
invalidate();
Now in the onDraw()-Method the path is drawn normally except when the layer was changed, then the stroke objects from the list are drawn.
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
//draw the layer(s)
if(layerChanged)
{
if(drawingLayer==1){
for(Stroke stroke : strokeListL1)
canvas.drawPath(stroke.getPath(), stroke.getPaint());
for(Stroke stroke : strokeListL2){
Paint paint = stroke.getPaint();
paint.setAlpha(50);
canvas.drawPath(stroke.getPath(), paint);
}
}
else{
for(Stroke stroke : strokeListL2){
Paint paint = stroke.getPaint();
paint.setAlpha(255);
canvas.drawPath(stroke.getPath(), paint);
}
}
}
else
canvas.drawPath(drawingPath, drawingPaint);
layerChanged=false;
And here start the problems. As long as I dont change the layers erasing is working fine but as soon as i do change the layers instead of erasing it just clears the whole canvas.
The erase method looks like this:
public void setErase(boolean erase){
eraseMode=erase;
if(eraseMode)
drawingPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
else
drawingPaint.setXfermode(null);
}
If I do some erasing before a layer change the "erasing strokes" will be drawn in a color too, once i change back to that layer. I am not sure if i maneuvered myself into a dead end or if I am just not getting it. Hope you guys can help me out.
So far
Okay so this error was dumb. The problem was the Paint object being reinitialized everytime a new Path is drawn by the User. That, of course, will unset the set Xfermode.
case MotionEvent.ACTION_DOWN:
Paint strokePaint=new Paint();
The solution is to give the current Paint object to the constructor.
Paint strokePaint=new Paint(drawingPaint);

How to keep drawn things in canvas after invalidate

for training, I'm writing something like 'achtung, die kurve' game. For now, I'm only about to simple drawing my 'kurve-snake' on screen. To turn I use accelerometer (and it does work in fact). I've custom view which has his own onDraw method.
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint2 = new Paint();
paint2.setAntiAlias(true);
paint2.setStrokeWidth(mPlayer.getLine().getmSize());
paint2.setColor(Color.GREEN);
float x = mPlayer.getLine().getmPosX();
float y = mPlayer.getLine().getmPosY();
mLogic.movePlayer(mBitmapPoint, mPlayer, mSensorY);
canvas.drawLine(x,y,mPlayer.getLine().getmPosX(), mPlayer.getLine().getmPosY(), paint2);
invalidate();
}
It does work properly, but this way I can't keep whole line (just the actual fragment of it).
I've tried other way: draw lines using bitmap.setpixel (bresenhams alg) and after it canvas.drawBitmap(...), but it's not effective.
I've tried too:
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint2 = new Paint();
paint2.setAntiAlias(true);
paint2.setStrokeWidth(mPlayer.getLine().getmSize());
paint2.setColor(Color.GREEN);
float x = mPlayer.getLine().getmPosX();
float y = mPlayer.getLine().getmPosY();
mLogic.movePlayer(mBitmapPoint, mPlayer, mSensorY);
canvas.drawLine(x,y,mPlayer.getLine().getmPosX(), mPlayer.getLine().getmPosY(), paint2);
invalidate();
mBitmapPoint = getDrawingCache();
}
but it gives error. Any idea how to achieve that?
I think you need to modify your draw code to look more like this:
Point start = myPlayer.getLine().getStartPoint();
for(Point p: myPlayer.getLine().getPoints()) {
if(start == p) {
continue;
}
canvas.drawLine(start.x,start.y,p.x,p.y, paint2);
start = p;
}
You'll need to create a list of points which represent the "joints" of your snake, and there's a lot of code there I won't put here, but this approach will draw your lines out for you.
Please refer this demo, used to redraw on the same canvas multiple times,
https://gitorious.org/freebroid/development/source/62e92d7a2a3fd2798901ec2e7c452ff0e4067163:samples/ApiDemos/src/com/example/android/apis/graphics/TouchPaint.java

ontouch in android-draw rectangle

in my application on touch event i want to drawrectangle-i tried this.butnot getting exactly how to draw.please help me.
i want to draw rectangle on points where is touched.
how can i use getX() and getY() in drawRect() method?
below is code-
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction()==MotionEvent.ACTION_DOWN) {
int X=event.getX(); int Y=event.getY();
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(getResources().getColor(R.color.Yellow)) ;
paint.setAlpha(opacity);
Canvas canvas1 = new Canvas(mutableimage1);
canvas1.drawRect(2.5f,2.5f,2.5f,2.5f, paint);
}
}
Don't instantiate a new object in the onTouch method : canvas1 = new Canvas(...)
It will cause freezes and lags. Create this canvas once for good at the creation of your view.
Be carefull I think your drawRect() call won't draw what you need :
you are drawing a rect with x=2.5 y = 2.5 width=2.5 height=2.5
I assume you need to position your rect according to the touch position :
//set the x and y pos according to the touch point
// by removing half the size of the rect we center it on this point ;)
canvas1.drawRect( X-1.25f, Y-1.25f, 2.5F, 2.5f, paint );
Otherwise that's quite correct, but be aware that you are drawing on a mutable bitmap ("mutableimage1") that won't necessary be displayed.
You probably want to add the display in the onDraw(Canvas viewCanvas) method of your view.
using :
viewCanvas.drawBitmap(mutableimage1, 0,0, aPreviouslyCreatedPaint);

Categories

Resources