Android Canvas Paint Signature Application - android

I am working on android paint signature application where it has the flexibility to clear the paint and save the canvas as bitmap image. I am facing an issue in this app, whenever i want to save the canvas as bitmap i need to check whether the signature is lengthy enough or not.
If the signature is too short them i have to ask the user to put a signature again. The following is my code:
There are two classes in this.
FingerPaintActivity
public class FingerPaintActivity extends Activity implements OnClickListener{
private Button clearBtn, saveBtn;
private View myView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
myView = findViewById(R.id.myView);
clearBtn = (Button) findViewById(R.id.clearBtn);
clearBtn.setOnClickListener(this);
saveBtn = (Button) findViewById(R.id.submitBtn);
saveBtn.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if (v == clearBtn) {
MyView.clearCanvas();
myView.invalidate();
myView.refreshDrawableState();
} else {
myView.setDrawingCacheEnabled(true);
myView.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
myView.layout(0, 0, myView.getWidth(), myView.getHeight());
myView.buildDrawingCache(true);
Bitmap bm = Bitmap.createBitmap(myView.getDrawingCache());
myView.setDrawingCacheEnabled(false);
if (bm != null) {
try {
String path = Environment.getExternalStorageDirectory().toString();
OutputStream fOut = null;
File file = new File(path, "screentest.jpg");
fOut = new FileOutputStream(file);
bm.compress(Bitmap.CompressFormat.JPEG, 85, fOut);
fOut.flush();
fOut.close();
Log.e("ImagePath", "Image Path : " + MediaStore.Images.Media.insertImage( getContentResolver(), file.getAbsolutePath(), file.getName(), file.getName()));
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"+ Environment.getExternalStorageDirectory())));
}
catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
This is the second class:
MyView
public class MyView extends View {
// private static final float MINP = 0.25f;
// private static final float MAXP = 0.75f;
private Bitmap mBitmap;
private static Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
private Paint mPaint;
public MyView(Context c) {
super(c);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(6);
mBitmap = Bitmap.createBitmap(320, 480, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
}
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#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(0xFFAAAAAA);
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 static void clearCanvas() {
Paint paint = new Paint();
paint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
mCanvas.drawPaint(paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC));
}
}
The only problem i am facing is while saving the signature i have to check the size of bitmap or canvas or paint before saving it. i don't know which one to check for
If anyone has idea please help me out.

A simple approach would be to sum up the distances between touch coordinates, and only accept the signature if the sum is greater than a certain threshold.
So, keep a running sum of the total distance drawn in touch_move()
mTotal += Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
then later on
if(mTotal >= MINIMUM_SIGNATURE_LENGTH)
{
acceptSignature();
}

Related

Erase drawing in canvas

I have written an Android application with a Canvas for drawing with a stylus. It works well. When I'm pushing the upper function key of my stylus I would like to erase the drawing by brushing over the text. The normal drawing is in black, so I thought to do the erase with white (on top of the black line). My problem is that all lines change the color when I press the upper function key of the stylus (i.e. all lines are then white) instead of just painting the new draw line in white.
Another option would be to delete elements from the path for the erase. If somebody has a solution for this, I would be happy too.
The layout looks as follows:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
tools:context="StylusBaselineA">
<inf.ethz.ch.affectivestudy.CanvasView
android:id="#+id/baselineACanvas"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:textColor="#FFFFFF" />
</android.support.constraint.ConstraintLayout>
The CanvasView class look as follows:
public class CanvasView extends View {
public int width;
public int height;
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Path mPathErase;
Context context;
private Paint mPaint;
private Paint mPaintErase;
private float mX, mY;
private static final float TOLERANCE = 5;
private boolean erase = false;
public CanvasView(Context c, AttributeSet attrs) {
super(c, attrs);
context = c;
// we set a new Path
mPath = new Path();
mPathErase = new Path();
// and we set a new Paint with the desired attributes
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeWidth(4f);
mPaintErase = new Paint();
mPaintErase.setAntiAlias(true);
mPaintErase.setColor(Color.WHITE);
mPaintErase.setStyle(Paint.Style.STROKE);
mPaintErase.setStrokeJoin(Paint.Join.ROUND);
mPaintErase.setStrokeWidth(4f);
}
// override onSizeChanged
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// your Canvas will draw onto the defined Bitmap
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
// override onDraw
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// draw the mPath with the mPaint on the canvas when onDraw
if (erase) {
canvas.drawPath(mPathErase, mPaintErase);
} else {
canvas.drawPath(mPath, mPaint);
}
}
// when ACTION_DOWN start touch according to the x,y values
private void startTouch(float x, float y) {
if (erase) {
mPathErase.moveTo(x, y);
} else {
mPath.moveTo(x, y);
}
mX = x;
mY = y;
}
// when ACTION_MOVE move touch according to the x,y values
private void moveTouch(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOLERANCE || dy >= TOLERANCE) {
if (erase) {
mPathErase.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
} else {
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
}
mX = x;
mY = y;
}
}
public void clearCanvas() {
mPath.reset();
mPathErase.reset();
invalidate();
}
// when ACTION_UP stop touch
private void upTouch() {
if (erase) {
mPathErase.lineTo(mX, mY);
} else {
mPath.lineTo(mX, mY);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
if (event.getToolType(0) == MotionEvent.TOOL_TYPE_ERASER) {
// Upper function key of stylus
erase = true;
} else if (event.getToolType(0) == MotionEvent.TOOL_TYPE_FINGER) {
// Touch input
erase = false;
return false;
} else {
erase = false;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startTouch(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
moveTouch(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
upTouch();
invalidate();
break;
}
return true;
}
}
Try this.
public class CanvasActivity extends AppCompatActivity {
private Paint mPaint;
View mView;
Button clear;
private Canvas mCanvas;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_canvas);
RelativeLayout layout = (RelativeLayout) findViewById(R.id.Linear_layout);
mView = new DrawingView(this);
layout.addView(mView, new LayoutParams(
RelativeLayout.LayoutParams.MATCH_PARENT,
RelativeLayout.LayoutParams.MATCH_PARENT));
clear= (Button) findViewById(R.id.clear);
clear.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mCanvas.drawColor(Color.WHITE);
}
});
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.GREEN);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(12);
}
public class DrawingView extends View {
public int width;
public int height;
private Bitmap mBitmap;
private Path mPath;
private Paint mBitmapPaint;
Context context;
private Paint circlePaint;
private Path circlePath;
public DrawingView(Context c) {
super(c);
context=c;
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
circlePaint = new Paint();
circlePath = new Path();
circlePaint.setAntiAlias(true);
circlePaint.setColor(Color.BLUE);
circlePaint.setStyle(Paint.Style.STROKE);
circlePaint.setStrokeJoin(Paint.Join.MITER);
circlePaint.setStrokeWidth(4f);
}
#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);
}
#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 implement undo, redo and erase in Android canvas

I want to create project like drawing which is needed to support drawing, undo, redo and eraser. Eraser must delete only for drawing view not delete background. Below code implements undo and redo functionality. I want to add eraser option but it's not done. How can implement eraser option using below code?
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import java.util.ArrayList;
public class CanvasView extends View {
private Paint mPenPainter;
public int width;
public int height;
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
Context context;
private Paint mPaint;
private float mX, mY;
private static final float TOLERANCE = 5;
private ArrayList<Path> paths = new ArrayList<Path>();
private ArrayList<Path> undonePaths = new ArrayList<Path>();
private int paintColor = 0xFF000000;
public CanvasView(Context c, AttributeSet attrs) {
super(c, attrs);
context = c;
// we set a new Path
mPath = new Path();
// and we set a new Paint with the desired attributes
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(paintColor);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeWidth(4f);
//float mEraserWidth = getResources().getDimension(R.dimen.eraser_size);
mPenPainter = new Paint();
mPenPainter.setColor(Color.BLUE);
}
// override onSizeChanged
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// your Canvas will draw onto the defined Bitmap
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
// override onDraw
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// draw the mPath with the mPaint on the canvas when onDraw
for (Path p : paths) {
canvas.drawPath(p, mPaint);
}
canvas.drawPath(mPath, mPaint);
// paths.add(mPath);
}
private void startTouch(float x, float y) {
undonePaths.clear();
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
}
public void onClickUndo() {
if (paths.size() > 0) {
undonePaths.add(paths.remove(paths.size() - 1));
invalidate();
} else {
//Util.Imageview_undo_redum_Status=false;
}
//toast the user
}
public void onClickRedo() {
if (undonePaths.size() > 0) {
paths.add(undonePaths.remove(undonePaths.size() - 1));
invalidate();
} else {
// Util.Imageview_undo_redum_Status=false;
}
//toast the user
}
// when ACTION_MOVE move touch according to the x,y values
private void moveTouch(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOLERANCE || dy >= TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
}
}
private void upTouch() {
mPath.lineTo(mX, mY);
mPath.lineTo(mX, mY);
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// kill this so we don't double draw
paths.add(mPath);
mPath = new Path();
}
//override the onTouchEvent
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
float mCurX;
float mCurY;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mX = event.getX();
mY = event.getY();
startTouch(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
moveTouch(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
upTouch();
invalidate();
break;
}
return true;
}
It seems a bit late answer but i finally made the solution after two days hardwork..
public class DrawView extends View {
public int width;
public int height;
private Bitmap mBitmap;
private Canvas mCanvas;
private Paint mBitmapPaint;
Context context;
private Paint circlePaint;
private Path circlePath;
Boolean eraserOn = false;
Boolean newAdded = false;
Boolean allClear = false;
private Path drawPath;
private ArrayList<Bitmap> bitmap = new ArrayList<>();
private ArrayList<Bitmap> undoBitmap = new ArrayList<>();
public DrawView(Context c) {
super(c);
context=c;
drawPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
circlePaint = new Paint();
circlePath = new Path();
circlePaint.setAntiAlias(true);
circlePaint.setColor(Color.BLUE);
circlePaint.setStyle(Paint.Style.STROKE);
circlePaint.setStrokeJoin(Paint.Join.MITER);
circlePaint.setStrokeWidth(4f);
drawPaint = new Paint();
drawPaint.setAntiAlias(true);
drawPaint.setDither(true);
drawPaint.setColor(Color.BLACK);
drawPaint.setStyle(Paint.Style.STROKE);
drawPaint.setStrokeJoin(Paint.Join.ROUND);
drawPaint.setStrokeCap(Paint.Cap.ROUND);
drawPaint.setStrokeWidth(20);
// drawPaint.setAlpha(80);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if(mBitmap==null) {
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// if(!eraserOn)
canvas.drawBitmap( mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(drawPath, drawPaint);
canvas.drawPath( circlePath, circlePaint);
}
public void onClickEraser(boolean isEraserOn)
{
if (isEraserOn) {
eraserOn = true;
drawPaint.setColor(getResources().getColor(android.R.color.transparent));
drawPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
}
else {
eraserOn = false;
drawPaint.setColor(mPaint.getColor());
drawPaint.setXfermode(null);
}
}
public void onClickUndo () {
if(newAdded) {
bitmap.add(mBitmap.copy(mBitmap.getConfig(), mBitmap.isMutable()));
newAdded=false;
}
if (bitmap.size()>1)
{
undoBitmap.add(bitmap.remove(bitmap.size()-1));
mBitmap= bitmap.get(bitmap.size()-1).copy(mBitmap.getConfig(),mBitmap.isMutable());
mCanvas = new Canvas(mBitmap);
invalidate();
if(bitmap.size()==1)
allClear=true;
}
else
{
}
//toast the user
}
public void onClickRedo (){
if (undoBitmap.size()>0)
{
bitmap.add(undoBitmap.remove(undoBitmap.size()-1));
mBitmap= bitmap.get(bitmap.size()-1).copy(mBitmap.getConfig(),mBitmap.isMutable());
mCanvas = new Canvas(mBitmap);
invalidate();
}
else
{
}
//toast the user
}
#Override
public boolean performClick() {
return super.performClick();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if(penSelected || eraserSelected) {
float touchX = event.getX();
float touchY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
newAdded = true;
if(!allClear)
bitmap.add(mBitmap.copy(mBitmap.getConfig(),mBitmap.isMutable()));
else allClear=false;
drawPath.moveTo(touchX, touchY);
break;
case MotionEvent.ACTION_MOVE:
if (eraserOn) {
drawPath.lineTo(touchX, touchY);
mCanvas.drawPath(drawPath, drawPaint);
drawPath.reset();
drawPath.moveTo(touchX, touchY);
} else {
drawPath.lineTo(touchX, touchY);
}
break;
case MotionEvent.ACTION_UP:
mCanvas.drawPath(drawPath, drawPaint);
drawPath.reset();
break;
case MotionEvent.ACTION_CANCEL:
return false;
default:
return false;
}
invalidate();
return true;
}
return false;
}
}
for erasing you need to find out intersect between current selection and draw paths. refer below code
package opensourcecode.com.paginationwebview;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.RectF;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import java.util.ArrayList;
/**
* Created by damodhar.meshram on 4/26/2017.
*/
public class CanvasView extends View {
private Paint mPenPainter;
public int width;
public int height;
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
Context context;
private Paint mPaint;
private float mX, mY;
private static final float TOLERANCE = 5;
private ArrayList<Path> paths = new ArrayList<Path>();
private ArrayList<Path> undonePaths = new ArrayList<Path>();
private boolean isErasemode = false;
private int paintColor = 0xFF000000;
public CanvasView(Context c, AttributeSet attrs) {
super(c, attrs);
context = c;
// we set a new Path
mPath = new Path();
// and we set a new Paint with the desired attributes
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(paintColor);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeWidth(4f);
//float mEraserWidth = getResources().getDimension(R.dimen.eraser_size);
mPenPainter = new Paint();
mPenPainter.setColor(Color.BLUE);
}
public CanvasView(Context c) {
super(c);
context = c;
// we set a new Path
mPath = new Path();
// and we set a new Paint with the desired attributes
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(paintColor);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeWidth(4f);
//float mEraserWidth = getResources().getDimension(R.dimen.eraser_size);
mPenPainter = new Paint();
mPenPainter.setColor(Color.BLUE);
}
// override onSizeChanged
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// your Canvas will draw onto the defined Bitmap
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
// override onDraw
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// draw the mPath with the mPaint on the canvas when onDraw
for (Path p : paths) {
canvas.drawPath(p, mPaint);
}
canvas.drawPath(mPath, mPaint);
// paths.add(mPath);
}
private void startTouch(float x, float y) {
undonePaths.clear();
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
}
public void onClickUndo() {
if (paths.size() > 0) {
undonePaths.add(paths.remove(paths.size() - 1));
invalidate();
} else {
//Util.Imageview_undo_redum_Status=false;
}
//toast the user
}
public void onEraser(){
if(!isErasemode){
isErasemode = true;
}else{
isErasemode = false;
}
}
private void remove(int index){
paths.remove(index);
invalidate();
}
public void onClickRedo() {
if (undonePaths.size() > 0) {
paths.add(undonePaths.remove(undonePaths.size() - 1));
invalidate();
} else {
// Util.Imageview_undo_redum_Status=false;
}
//toast the user
}
// when ACTION_MOVE move touch according to the x,y values
private void moveTouch(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOLERANCE || dy >= TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
}
}
private void upTouch() {
mPath.lineTo(mX, mY);
mPath.lineTo(mX, mY);
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// kill this so we don't double draw
paths.add(mPath);
mPath = new Path();
}
//override the onTouchEvent
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
float mCurX;
float mCurY;
if(isErasemode){
for(int i = 0;i<paths.size();i++){
RectF r = new RectF();
Point pComp = new Point((int) (event.getX()), (int) (event.getY() ));
Path mPath = paths.get(i);
mPath.computeBounds(r, true);
if (r.contains(pComp.x, pComp.y)) {
Log.i("need to remove","need to remove");
remove(i);
break;
}
}
return false;
}else {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mX = event.getX();
mY = event.getY();
startTouch(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
moveTouch(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
upTouch();
invalidate();
break;
}
return true;
}
}
}
I think you should use this pattern :
https://sourcemaking.com/design_patterns/command
I used it to my application to use undo/redo

Draw with canvas Android

For now I want the canvas to just draw a color.
public class AndroidTentaTestActivity extends Activity {
private Bitmap bm;
private Canvas c;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.main);
bm = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
c = new Canvas(bm);
c.drawARGB(100, 0, 0, 150);
}
}
The code above is what I´ve written so far that obviously does not work. I suspect the Bitmap is somehow not connected to what I am doing but I don´t know how to fix it. How do I?
Change the desired color in mPaint.setColor().
public class AndroidTentaTestActivity extends AppCompatActivity {
MyView mv;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mv = new MyView(this);
mv.setDrawingCacheEnabled(true);
setContentView(mv);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(0xFFFF0000);
}
private Paint mPaint;
#Override
public void onClick(View v) {
}
public class MyView extends View {
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
Context context;
public MyView(Context c) {
super(c);
context = c;
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);
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(0xFFFFFFFF);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
canvas.drawPath(mPath, mPaint);
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 1;
private void touch_start(float x, float y) {
//showDialog();
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); //2,2.old values
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;
}
}
LinearLayout ll = (LinearLayout) findViewById(R.id.rect);
Paint paint = new Paint();
paint.setColor(Color.parseColor("#CD5C5C"));
Bitmap bg = Bitmap.createBitmap(ll.getWidth(),ll.getHeight() , Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bg);
canvas.drawARGB(200, 0, 225, 255);
ll.setBackgroundDrawable(new BitmapDrawable(bg));

How to create a Scratch Card in Android?

I need to create a "Scratch Card" App for my final project in school and can't find the way how to implement the scratching event (How do I create background image and put Grey rectangles over it, so when I will scratch those rectangles I will see the picture under them)
The Implementation must be in Android because I don't how to develop In Objective-C yet.
I saw a reference for Objective-C Implementation, but it's no good as I don't understand it.
My Code is:
public class FingerPaint extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
try {
MyView myView = new MyView(this);
myView.requestFocus();
myView.PaintObjectInit();
// setContentView(myView);
LinearLayout upper = (LinearLayout) findViewById(R.id.LinearLayout01);
upper.addView(myView);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
// MyImageView myImageView = new MyImageView(this);
// setContentView(myImageView);
}
}
public class MyView extends View {
private Paint mPaint;
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
public MyView(Context context) {
super(context);
this.mPaint = new Paint();
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
}
protected void PaintObjectInit() {
mPaint.setAntiAlias(true);
mPaint.setDither(true);
//mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
//mPaint.setColor(0xFFFF0000);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(12);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
try
{
//Bitmap bm1 = BitmapFactory.decodeResource(this.getResources(),R.drawable.scratch).copy(Bitmap.Config.ARGB_8888, true);;
//Bitmap bm2 = BitmapFactory.decodeResource(this.getResources(),R.drawable.main).copy(Bitmap.Config.ARGB_8888, true);;
//mBitmap = toTransparency(bm1, 0xFFAAAAAA, true, bm2);
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
}
catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(0xFFAAAAAA);
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;
}
}
Please help regarding this.
I come across this problem recently and then I created a library for this so everyone can have a quick implementation of scratch view, hope this can help those who still looking for answer
https://github.com/winsontan520/Android-WScratchView
I found this library very useful.
https://github.com/sharish/ScratchView
Very easy to integrate
<com.cooltechworks.views.ScratchImageView
android:id="#+id/sample_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#android:color/white"
android:src="#drawable/img_sample2"
/>
you can make "Scratch Card" application like this way. you need to follow the below code which is working code. you just need to required understand and implement your own logic.
public class MainActJava extends AppCompatActivity {
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
setContentView(new MyView(this, bitmap));
}
public class MyView extends View implements View.OnTouchListener {
private static final float TOUCH_TOLERANCE = 4;
private Paint mPaint;
private Bitmap oBitmap;
private Bitmap holder;
private Canvas mCanvas;
private Path mPath;
private Paint mBitmapPaint;
private float mX, mY;
public MyView(Context context) {
super(context);
}
public MyView(Context context, Bitmap bitmap) {
super(context);
setOnTouchListener(this);
this.oBitmap = bitmap;
this.mPaint = new Paint();
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
init();
}
protected void init() {
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(35);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
holder = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(holder);
}
#Override
protected void onDraw(Canvas canvas) {
onDrawing(canvas);
}
private void onDrawing(Canvas canvas) {
mCanvas.drawColor(0xFFAAAAAA);
mCanvas.drawPath(mPath, mPaint);
canvas.drawBitmap(oBitmap, getWidth()/2, getHeight()/2, mBitmapPaint);
canvas.drawBitmap(holder, 0, 0, mBitmapPaint);
}
private void touch_start(float x, float y) {
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);
}
#Override
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();
invalidate();
break;
}
return true;
}
}
}
Output:

How do I draw an image from drawable onto an imageview with Canvas - Android

I have an activity which has an ImageView in it. What I want to do is be able to draw where the user touches that Imageview with an image from the drawable folder. I've read that the best way is to use Canvas, but I'm not sure where and how I integrate the onDraw method with the onTouchListener. This is what I have so far:
public class Main extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final TextView textView = (TextView)findViewById(R.id.textView);
final ImageView image = (ImageView) findViewById(R.id.imageView2);
//Bitmap
Bitmap viewBitmap = Bitmap.createBitmap(image.getWidth(), image.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(viewBitmap);
image.draw(canvas);
image.setOnTouchListener(new View.OnTouchListener()
{
#Override
public boolean onTouch(View v, MotionEvent event)
{
textView.setText("Touch coordinates : " + String.valueOf(event.getX()) + "x" + String.valueOf(event.getY()));
return false;
}
});
}
}
So what I want to do is when the user touches the ImageView, an image will be drawn exactly where he touched it.
You're going to want to subclass ImageView in order to override its onDraw() method. By doing so, you can also to the custom touch handling in onTouchEvent() instead of attaching a listener. This is not a complete example, but something like the following:
public class CustomImageView extends ImageView {
private ArrayList<Point) mTouches;
private Bitmap mMarker;
//Java constructor
public CustomImageView(Context context) {
super(context);
init();
}
//XML constructor
public CustomImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
mTouches = new ArrayList<Point>();
mMarker = BitmapFactory.decodeResource(context.getResources(), R.drawable.my_marker_image);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
//Capture a reference to each touch for drawing
if(event.getAction() == MotionEvent.ACTION_DOWN) {
mTouches.add( new Point(event.getX(), event.getY()) );
return true;
}
return super.onTouchEvent(event);
}
#Override
protected void onDraw(Canvas c) {
//Let the image be drawn first
super.onDraw(c);
//Draw your custom points here
Paint paint = new Paint();
for(Point p : mTouches) {
c.drawBitmap(mMarker, p.x, p.y, paint);
}
}
}
HTH!
I edited your class like this and it works for me
public class MyImageView extends androidx.appcompat.widget.AppCompatImageView {
private Bitmap mMarker;
private Path mPath, circlePath ;
private Paint paint, circlePaint;
private Canvas mCanvas;
//Java constructor
public MyImageView(Context context) {
super(context);
init();
}
//XML constructor
public MyImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
mTouches = new ArrayList<Point>();
paint = new Paint();
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeWidth(12);
mPath = new Path();
Paint mBitmapPaint = new Paint(Paint.DITHER_FLAG);
circlePaint = new Paint();
circlePath = new Path();
circlePaint.setStyle(Paint.Style.STROKE);
circlePaint.setStrokeJoin(Paint.Join.MITER);
circlePaint.setStrokeWidth(4f);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mMarker = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mMarker);
}
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, paint);
// 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;
}
#Override
protected void onDraw(Canvas c) {
//Let the image be drawn first
super.onDraw(c);
c.drawBitmap(mMarker, 0, 0, paint);
c.drawPath( mPath, paint);
c.drawPath( circlePath, circlePaint);
}
}

Categories

Resources