Paint Xfermode draws black line on andorid 2.2---->again - android

I want to erase a part of image and I setting XferMode to clear image. but when i testing on android >3.0 it works fine and it draws black line on android < 3.0 (2.2). I can't find solution for this problem. Can anyone explain me why ?
this is TouchView method:
public TouchView(Context context) {
super(context);
mPath = new Path();
Display display = getWindowManager().getDefaultDisplay();
#SuppressWarnings("deprecation")
int dWidth = display.getWidth();
#SuppressWarnings("deprecation")
int dHeight = display.getHeight();
int id = getIntent().getIntExtra("id", -1);
bgr1 = BitmapFactory.decodeResource(getResources(),BackgroundAdapter.mThumbIds[id]);
bgr = Bitmap.createScaledBitmap(bgr1, dWidth, dHeight, true);
overlay1 = BitmapFactory.decodeResource(getResources(),OverlayAdapter.mThumbIds[id]).copy(Config.ARGB_8888, true);
overlay = Bitmap.createScaledBitmap(overlay1, dWidth, dHeight, true);
c2 = new Canvas(
pTouch = new Paint(/*Paint.ANTI_ALIAS_FLAG*/);
pTouch.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
pTouch.setColor(Color.TRANSPARENT);
pTouch.setDither(true);
pTouch.setStrokeWidth(20);
pTouch.setAntiAlias(true);
pTouch.setFilterBitmap(true);
pTouch.setStyle(Paint.Style.STROKE);
pTouch.setMaskFilter(new BlurMaskFilter(10, Blur.
}
this sets paint to TouchView:
private void touch_start(float x, float y){
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
mDrawPoint = true;
mPath.moveTo(x, y); mX = x; mY = y;
}
private void touch_move(float x, float y){
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mPath.lineTo(mX, mY);
c2.drawPath(mPath, pTouch);
mPath.reset();
mPath.moveTo(mX, mY);
mX = x;
mY = y;
}
}
private void touch_up() {
mPath.reset();
}
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
and onDraw:
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(bgr, 0, 0, null);
Paint new_paint = new Paint();
new_paint.setXfermode(new PorterDuffXfermode(Mode.SRC_ATOP));
new_paint.setStyle(Paint.Style.STROKE );
new_paint.setFilterBitmap(true);
canvas.drawBitmap(overlay, 0, 0, new_paint);
canvas.drawColor(Color.TRANSPARENT);
canvas.isHardwareAccelerated();
c2.drawPath(mPath, pTouch);
}
i

This is an issue with hardware acceleration. Try doing this in your custom view's constructor:
if (android.os.Build.VERSION.SDK_INT >= 11)
{
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}

Related

Drawing without creating a continuous line in Android Studio

I made a class which lets me to draw, but it has two problems:
1)It makes a continuous line instead of separated ones. How can I improve it?
2)Is it possible to track the coordinates of the lines made by the user to check, for example, if there are symmetries in the draw?
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap( mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath( mPath, mPaint);
canvas.drawPath( circlePath, circlePaint);
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
private void touch_start(float x, float y) {
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
}
private void touch_move(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
mX = x;
mY = y;
circlePath.reset();
circlePath.addCircle(mX, mY, 30, Path.Direction.CW);
}
}
private void touch_up() {
mPath.lineTo(mX, mY);
circlePath.reset();
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// kill this so we don't double draw
mPath.reset();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
}
}

How to draw a smooth path of bitmap,without any breaks

i am working on a paint application and i want to draw a path of bitmap
my code is this:
private void onCanvasInitialization() {
// Main_Activity.paintButton.setEnabled(true);
mPaint = new Paint();
BlurMaskFilter bmf = new BlurMaskFilter(2, Blur.OUTER);
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setFilterBitmap(true);
mPaint.setColor(Main_Activity.colorchanger);
mCanvas = new Canvas();
mPath = new Path();
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setMaskFilter(bmf);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setAlpha(255);
bmp = Bitmap.createScaledBitmap(bmp, 30, 30, false);
bmp = bmp.copy(Config.ARGB_8888, true);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
public boolean onTouch(View arg0, MotionEvent event) {
float x = event.getX();
float y = event.getY();
if (true)
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
private void touch_start(float x, float y) {
Random rand = new Random();
float r = rand.nextFloat();
float g = rand.nextFloat();
float b = rand.nextFloat();
Random rnd = new Random();
mPaint.setColor(Color.rgb(rnd.nextInt(256), rnd.nextInt(256),
rnd.nextInt(256)));
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
}
private void touch_move(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
// mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
arrX[i] = mX;
arrY[i] = mY;
i++;
}
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (int k = 0; k < i; k++) {
canvas.drawBitmap(bmp, arrX[k], arrY[k], mPaint);
}
}
by this i am able to draw bitmap on canvas but the flow is not smooth it is not looks like a line .there is a gap between the two successive bitmaps.i want it to look like a path .
Why are you calling invalidate() method in every case: , try to call it out ot switch.
For Ex.
public boolean onTouch(View arg0, MotionEvent event) {
float x = event.getX();
float y = event.getY();
if (true)
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
break;
case MotionEvent.ACTION_UP:
touch_up();
break;
}
invalidate();
return true;
}

Android: Draw on bitmap with finger in transparent color

I have an ImageView with a bitmap. What I want: When the user draws with the finger on the bitmap this part should become transparent(set Pixel alpha value to 0) that you can see the views under the imageview.
Can I work with an ImageView or should I implement a custom view?
How can I realize this? (just roughly)
You can use Canvas drawing. Create a custom view with mutable bitmap.
Erasing can be achieved by setting Paint object like this:
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.TRANSPARENT);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
Implement drawing:
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (w > 0 && h > 0) {
// Set up canvas - bitmap can be initialized with your Image
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mBitmap == null || mCanvas == null || mPath == null) {
return;
}
mCanvas.drawPath(mPath, mPaint);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(circlePath, circlePaint);
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
private void touchStart(float x, float y) {
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
}
private void touchMove(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
circlePath.reset();
circlePath.addCircle(mX, mY, 30, Path.Direction.CW);
}
}
private void touchUp() {
mPath.lineTo(mX + 1, mY + 1);
circlePath.reset();
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// kill this so we don't double draw
mPath.reset();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (!isEnabled()) {
return true;
}
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touchStart(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touchMove(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touchUp();
invalidate();
break;
}
return true;
}

How erase Paint with the finger

I want to erase by area where the finger is detected on the gray square bitmap but it don't works.
I display a bitmap with ic_launch as image then i display on the image a grey square Paint where i can to modify the color to the TRANSPARENT
What is the problem? Thank you
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
private Paint mPaint;
public CaseView(Context c) {
super(c);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(40);
mBitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
for (int i = 0; i < 100; i++) {
for (int j = 0; j < 100; j++) {
mBitmap.setPixel(i, j, Color.GRAY);
}
}
mCanvas = new Canvas(mBitmap);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(0, 0, oldw, oldh);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawRect(100, 100, 200, 200, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
Bitmap _scratch = BitmapFactory.decodeResource(getResources(),
R.drawable.ic_launcher);
canvas.drawColor(Color.WHITE);
// logo
canvas.drawBitmap(_scratch, 0, 100, null);
for (int i = 0; i < 100; i++) {
for (int j = 0; j < 100; j++) {
if ((mX < 100 && mX >= 0) && (mY < 100 && mY >= 0)) {
mBitmap.setPixel((int) mY,(int) mX, Color.TRANSPARENT);
}
}
}
canvas.drawBitmap(mBitmap, 0, 100, mBitmapPaint);
Bitmap mutableBitmap = Bitmap.createBitmap(_scratch.getWidth(),
_scratch.getHeight(), Bitmap.Config.ARGB_8888);
mutableBitmap.setPixel(50, 50, 124);
canvas.drawBitmap(mutableBitmap, 0, 100, null);
int pixelColor = mBitmap.getPixel(50, 50);
int red = Color.red(pixelColor);
int green = Color.green(pixelColor);
Log.v("red", "red:" + red + " /green:" + green);
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
private void touch_start(float x, float y) {
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
}
private void touch_move(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
}
}
private void touch_up() {
mPath.lineTo(mX, mY);
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// kill this so we don't double draw
mPath.reset();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
Log.v("onTouchEvent", "x:" + x + "/y:" + y);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
For Drawing you need to draw a path using one Paint class. But for erasing again you have to draw one path on your touch Coordinate like this
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
In android-sdk sample they had given a class FingerPaint that explain it very well

How to implement touch smooth image eraser in android?

I have already seen fingurePaint.java from API demos. I want to implement touch smooth eraser to erase parts of the image by touch move in android.
fingurePaint told me to implement this
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
But this is not working to erase the image. It is working to erase something which is drawn by touch.
public class SandboxView extends View implements OnTouchListener {
public final Bitmap bitmap;
private final int width;
private final int height;
private Matrix transform = new Matrix();
private Vector2D position = new Vector2D();
private float scale = 1;
private float angle = 0;
public boolean isInitialized = false;
private TouchManager touchManager = new TouchManager(2);
final GestureDetector mGesDetect;
// Debug helpers to draw lines between the two touch points
private Vector2D vca = null;
private Vector2D vcb = null;
private Vector2D vpa = null;
private Vector2D vpb = null;
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
private Path mPath;
private Canvas mCanvas;
private Paint mPaint;
private Paint mBitmapPaint;
public SandboxView(Context context, Bitmap bitmap) {
super(context);
this.bitmap = bitmap;
this.width = bitmap.getWidth();
this.height = bitmap.getHeight();
this.mGesDetect = new GestureDetector(context, new DoubleTapGestureDetector());
setOnTouchListener(this);
}
private float getDegreesFromRadians(float angle) {
return (float)(angle * 360.0 / Math.PI);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (!isInitialized) {
Bitmap mBitmap = bitmap.createBitmap(320, 480, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
mPaint = new Paint();
mPath = new Path();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(0xFFFF0000);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(12);
mPaint.setAlpha(0);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
mPaint.setAntiAlias(true);
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
int w = getWidth();
int h = getHeight();
position.set(w / 2, h / 2);
isInitialized = true;
}
if(isEraser==1){
canvas.drawColor(80000000);
canvas.drawBitmap(bitmap, transform, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
}
else{
Paint paint = new Paint();
transform.reset();
transform.postTranslate(-width / 2.0f, -height / 2.0f);
transform.postRotate(getDegreesFromRadians(angle));
transform.postScale(scale, scale);
transform.postTranslate(position.getX(), position.getY());
canvas.drawBitmap(bitmap, transform, paint);
try {
/*paint.setColor(0xFF007F00);
canvas.drawCircle(vca.getX(), vca.getY(), 64, paint);
paint.setColor(0xFF7F0000);
canvas.drawCircle(vcb.getX(), vcb.getY(), 64, paint);
paint.setColor(0xFFFF0000);
canvas.drawLine(vpa.getX(), vpa.getY(), vpb.getX(), vpb.getY(), paint);
paint.setColor(0xFF00FF00);
canvas.drawLine(vca.getX(), vca.getY(), vcb.getX(), vcb.getY(), paint);*/
}
catch(NullPointerException e) {
// Just being lazy here...
}
}
}
private void touch_start(float x, float y) {
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
}
private void touch_move(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
mX = x;
mY = y;
}
}
private void touch_up() {
mPath.lineTo(mX, mY);
mCanvas.drawPath(mPath, mPaint);
mPath.reset();
}
#Override
public boolean onTouch(View v, MotionEvent event) {
if(isEraser ==1){
float x = event.getX();
float y = event.getY();
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
else{
vca = null;
vcb = null;
vpa = null;
vpb = null;
mGesDetect.onTouchEvent(event);
try {
touchManager.update(event);
if (touchManager.getPressCount() == 1) {
vca = touchManager.getPoint(0);
vpa = touchManager.getPreviousPoint(0);
position.add(touchManager.moveDelta(0));
}
else {
if (touchManager.getPressCount() == 2) {
vca = touchManager.getPoint(0);
vpa = touchManager.getPreviousPoint(0);
vcb = touchManager.getPoint(1);
vpb = touchManager.getPreviousPoint(1);
Vector2D current = touchManager.getVector(0, 1);
Vector2D previous = touchManager.getPreviousVector(0, 1);
float currentDistance = current.getLength();
float previousDistance = previous.getLength();
if (previousDistance != 0) {
scale *= currentDistance / previousDistance;
}
angle -= Vector2D.getSignedAngleBetween(current, previous);
}
}
invalidate();
}
catch(Throwable t) {
// So lazy...
}
return true;
}
}
class DoubleTapGestureDetector extends GestureDetector.SimpleOnGestureListener {
#Override
public boolean onDoubleTap(MotionEvent e) {
colorseekbar.setVisibility(View.INVISIBLE);
opacityseekbar.setVisibility(View.INVISIBLE);
return true;
}
}
}
So please help me to erase the parts of image by using touch move.
Thanks in advance.
First Declar your paint with all property in your constructor.
Write this code in your onDraw() method
#Override
protected void onDraw(Canvas canvas)
{
System.out.println("come in on draw......");
canvas.drawColor(Color.TRANSPARENT);
canvas.drawBitmap(mBitmap, 0, 0, mPaint);
if(eraser==true)
mPaint.setColor(Color.TRANSPARENT):
else
mPaint.setColor(Color.RED):
canvas.drawPath(mPath, mPaint);
super.dispatchDraw(canvas);
}
second solution:
call below method in your touch_move() method
mBitmap.setPixel(x, y, Color.TRANSPARENT); This method will change your bitmap you have to pass only X,Y & COLOR
public void changeBitmap(int x, int y, Bitmap mBitmap)
{
Bitmap tempBitmap = Bitmap.createBitmap(mBitmap); //Edited code
tempBitmap.setPixel(x, y, Color.TRANSPARENT);
}
private void touch_move(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
mX = x;
mY = y;
changeBitmap(x, y, your_bitmap)
}
}
Isn't it better to invert this case ? Just paint on your image with background color and after all when saving, merge those layers if needed.
Define a temporary canvas and bitmap then draw your path or line, circle, image anything on touch events and then pass this temporary bitmap to canvas in onDraw your work will done properly, and also if you want to do erasing then do your erasing on that temporary canvas.
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
TemporaryBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_4444);
TemporaryCanvas = new Canvas(TemporaryBitmap);
}
TemporaryCanvas.drawColor(0, PorterDuff.Mode.clear);
public void onDraw(Canvas canv){
canv.drawBitmap(TemporaryBitmap, matrix, paint);

Categories

Resources