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;
}
}
}
Related
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;
}
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);
}
In my android application, i want to provide tracing letter feature as shown in following image :
Here i want to provide tracing of letter-D and for that i need to draw arc between two points when user starts moving finger on arc. Here, if user starts moving finger from start point and stops at end point then only it should draw arc between those points. And it should also show arc while moving finger on arc path.For that i have written below code.The problem i am facing is that, when ACTION_UP event is fired on arc path, it still shows arc drawing on canvas. But i want to remove that drawing from path if it fires ACTION_UP event in between of arc path.
Here is my code :
public class DrawView extends View implements OnTouchListener {
List<Point> pointsD = new ArrayList<Point>();
pointsD.add(new Point(520, 70));
pointsD.add(new Point(520, 335));
pointsD.add(new Point(520, 70));
pointsD.add(new Point(520, 335));
public boolean onTouch(View view, 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(x, y);
invalidate();
break;
default:
break;
}
return true;
}
private void touch_start(float x, float y) {
if (checkPoint(x, y, mLastPointIndex)) {
mPath.reset();
isPathStarted = true;
} else {
isPathStarted = false;
}
}
private void touch_move(float x, float y) {
if (isPathStarted) {
mPath.reset();
Point p = null;
p = pointsD.get(mLastPointIndex);
mPath.moveTo(p.x, p.y);
float radius = 1;
RectF oval = new RectF();
oval.set(scalePointX((int) (486 - radius)),scalePointY(70), scalePointX((int) (686 + radius)),
scalePointY((int) (334 + radius)));
if (sweepAngelD <= 180 && startAngleD <= 360) {
mPath.arcTo(oval, startAngleD, sweepAngelD, true);
sweepAngelD += 1;
startAngleD += 2;
mCanvas.drawPath(mPath, mPaint);
}
mPath.reset();
}
private void touch_up(float x, float y) {
mPath.reset();
if (isPathStarted) {
float radius = 1;
RectF oval = new RectF();
oval.set(scalePointX((int) (486 - radius)),
scalePointY(70), scalePointX((int) (686 + radius)),
scalePointY((int) (334 + radius)));
Point p = pointsD.get(mLastPointIndex);
mPath.moveTo(p.x, p.y);
mPath.arcTo(oval, startAngleD, sweepAngelD, true);
mCanvas.drawPath(mPath, mPaint);
mPath.reset();
++mLastPointIndex;
} else {
sweepAngelD = 1;
startAngleD = 270;
mPath.reset();
}
isPathStarted = false;
}
private boolean checkPoint(float x, float y, int pointIndex){
if (pointIndex == pointsD.size()) {
// out of bounds
return false;
}
point = pointsD.get(pointIndex);
// EDIT changed point.y to poin.x in the first if statement
if (x > (point.x - TOUCH_TOLERANCE)
&& x < (point.x + TOUCH_TOLERANCE)) {
if (y > (point.y - TOUCH_TOLERANCE)
&& y < (point.y + TOUCH_TOLERANCE)) {
return true;
}
}
return false;
}
}
I edited my code as below and now it is working..
public class DrawView extends View implements OnTouchListener {
List<Point> pointsD = new ArrayList<Point>();
pointsD.add(new Point(520, 70));
pointsD.add(new Point(520, 335));
pointsD.add(new Point(520, 70));
pointsD.add(new Point(520, 335));
public boolean onTouch(View view, 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(x, y);
invalidate();
break;
default:
break;
}
return true;
}
private void touch_start(float x, float y) {
if (checkPoint(x, y, mLastPointIndex)) {
mPath.reset();
isPathStarted = true;
} else {
isPathStarted = false;
}
}
private void touch_move(float x, float y) {
if (isPathStarted) {
mPath.reset();
Point p = null;
p = pointsD.get(mLastPointIndex);
mPath.moveTo(p.x, p.y);
float radius = 1;
RectF oval = new RectF();
oval.set(scalePointX((int) (486 - radius)),scalePointY(70), scalePointX((int) (686 + radius)),
scalePointY((int) (334 + radius)));
if (sweepAngelD <= 180 && startAngleD <= 360) {
mPath.arcTo(oval, startAngleD, sweepAngelD, true);
sweepAngelD += 1;
startAngleD += 2;
}
mPath.reset();
}
private void touch_up(float x, float y) {
mPath.reset();
if (isPathStarted) {
float radius = 1;
RectF oval = new RectF();
oval.set(scalePointX((int) (486 - radius)),
scalePointY(70), scalePointX((int) (686 + radius)),
scalePointY((int) (334 + radius)));
Point p = pointsD.get(mLastPointIndex);
mPath.moveTo(p.x, p.y);
mPath.arcTo(oval, startAngleD, sweepAngelD, true);
mCanvas.drawPath(mPath, mPaint);
mPath.reset();
++mLastPointIndex;
} else {
sweepAngelD = 1;
startAngleD = 270;
mPath.reset();
}
isPathStarted = false;
}
private boolean checkPoint(float x, float y, int pointIndex){
if (pointIndex == pointsD.size()) {
// out of bounds
return false;
}
point = pointsD.get(pointIndex);
// EDIT changed point.y to poin.x in the first if statement
if (x > (point.x - TOUCH_TOLERANCE)
&& x < (point.x + TOUCH_TOLERANCE)) {
if (y > (point.y - TOUCH_TOLERANCE)
&& y < (point.y + TOUCH_TOLERANCE)) {
return true;
}
}
return false;
}
}
this is the code i made:
private void touch_start(float x, float y) {
mPath.reset();
mPath.moveTo(x, y);
undoPath = new Path();
undoPath.moveTo(x, y);
canvas.drawPoint(x, y, paint);
mX = x;
mY = y;
if (bitmaps.size() > 0) {
for (int i = 0; i < (bitmaps.size()); i++) {
System.out.println("CustomImage.touch_start(): " + i + "||" + bitmaps.get(i).rect + "ZZ: " + x + "|| " + y);
if (bitmaps.get(i).rect.contains((int) x, (int) y)) {
System.out.println("CustomImage.touch_start()2");
contains = true;
lastBitmap = i;
}
}
}
private void touch_move(float x, float y) {
float dx, dy;
dx = Math.abs(x - mX);
dy = Math.abs(y - mY);
if ((dx >= TOUCH_TOLERANCE) || (dy >= TOUCH_TOLERANCE)) {
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
undoPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
}
}
private void touch_up() {
mPath.lineTo(mX, mY);
mPath.moveTo(mX, mY);
undoPath.lineTo(mX, mY);
undoPath.moveTo(mX, mY);
canvas.drawPath(mPath, paint);
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);
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
When i press the undo button i do this:
public void setPaint2(Paint paint2) {
canvas.drawPath(undoPath, paint2);
invalidate();
}
where paint2 is:
paint2= new Paint();
paint2.setStrokeWidth(paint.getStrokeWidth()+5);
paint2.setColor(0x00000000);
paint2.setXfermode(clear);
paint2.setAlpha(0x00);
paint is the Paint() that i use to draw, paint2 is the one i use to erase(paints with alpha = 0 (transparent) over the first one.
The problem is that, even if it erases a part, it does not erase everything, what can I do?
This resolved my issues:
delPaint = new Paint();
delPaint.setColor(0x00000000);
delPaint.setXfermode(clear);
delPaint.setAlpha(0x00);
delPaint.setAntiAlias(true);
delPaint.setDither(true);
delPaint.setStyle(Paint.Style.STROKE);
delPaint.setStrokeJoin(Paint.Join.ROUND);
delPaint.setStrokeCap(Paint.Cap.ROUND);
Given below is my Java code. I want to capture the signature drawn in the bitmap and store it in a string array (X and Y coordinates of the signature).
package com.ust.mobile.android.jnj;
import java.util.ArrayList;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.view.MotionEvent;
import android.view.View;
public class SignatureFieldClass extends View{
private int nBitmapWidth = 700;
private int nBitmapHeight = 220;
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
private Paint mPaint = new Paint();
private ArrayList<String> signature=new ArrayList<String>();
public SignatureFieldClass(Context c) {
super(c);
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(4);
mBitmap = Bitmap.createBitmap(nBitmapWidth, nBitmapHeight, Bitmap.Config.ARGB_8888);
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(w, h, oldw, oldh);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(0xFF6386AD);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
}
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();
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;
}
public void ClearPath(){
mPath.reset();
invalidate();
}
}
we can store the X and Y coordinates of the bitmap to a string array.for dat we can use below code.
private int mX, mY;
private static final float TOUCH_TOLERANCE = 4;
private void touch_start(int x, int y) {
mPath.reset();
mPath.moveTo(x, y);
mX = x;
s=Integer.toString(mX);
//signatures=s;
sb.append(s);
sb.append(",");
//signature[0]=s;
mY = y;
s=Integer.toString(mY);
sb.append(s);
//signature[1]=s;
}
private void touch_move(int x, int 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;
s=Integer.toString(mX);
sb.append(",");
sb.append(s);
sb.append(",");
/* int l=signature.length;
signature[l]=s;*/
mY = y;
s=Integer.toString(mY);
sb.append(s);
/*l=signature.length;
signature[l]=s;*/
}
}
private void touch_up() {
mPath.lineTo(mX, mY);
s=Integer.toString(mX);
sb.append(",");
sb.append(s);
s=Integer.toString(mY);
sb.append(",");
sb.append(s);
sb.append(",");
// 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) {
int x = (int)event.getX();
int y = (int)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;
}
This is not full code.it s d part f code dat captures x and y coordinates.sb is a string buffer.we can copy d values in d string buffer to a string.