1

I am trying to capture the digital signature by following the below links which use bezier class.

http://corner.squareup.com/2010/07/smooth-signatures.html

http://corner.squareup.com/2012/07/smoother-signatures.html

I could able to draw the signature properly when the signature was without lifting the finger. But when i lift the finger and start the signature again, its drawing a line joining the previous point and the new point. enter image description here

In the picture above i have put 5 dots. But instead of dots its drawing a line from the first dot to the other.

Bezier.java

public class Bezier {
private Point controlPointOne;
private Point controlPointTwo;
private int drawSteps;
private Point endPoint;
private int mColor;
private Point startPoint;`


public Bezier() {
}
public Bezier(Point paramPoint1, Point paramPoint2, Point paramPoint3,
        Point paramPoint4) {
    this.startPoint = paramPoint1;
    this.controlPointOne = paramPoint2;
    this.controlPointTwo = paramPoint3;
    this.endPoint = paramPoint4;
    this.drawSteps = ((int) (paramPoint1.distanceTo(paramPoint2)
            + paramPoint2.distanceTo(paramPoint3) + paramPoint3
            .distanceTo(paramPoint4)));
}

public void draw(Canvas canvas, Paint paint, float startWidth, float endWidth) {
    float originalWidth = paint.getStrokeWidth();
    float widthDelta = endWidth - startWidth;

    for (int i = 0; i < drawSteps; i++) {
        float t = ((float) i) / drawSteps;
        float tt = t * t;
        float ttt = tt * t;
        float u = 1 - t;
        float uu = u * u;
        float uuu = uu * u;

        float x = uuu * startPoint.x;
        x += 3 * uu * t * getControlPointOne().x;
        x += 3 * u * tt * getControlPointTwo().x;
        x += ttt * endPoint.x;

        float y = uuu * startPoint.y;
        y += 3 * uu * t * getControlPointOne().y;
        y += 3 * u * tt * getControlPointTwo().y;
        y += ttt * endPoint.y;

        paint.setStrokeWidth(startWidth + ttt * widthDelta);
        canvas.drawPoint(x, y, paint);
    }

    paint.setStrokeWidth(originalWidth);
}
public int getColor() {
    return this.mColor;
}

public Point getControlPointOne() {
    return this.controlPointOne;
}

public Point getControlPointTwo() {
    return this.controlPointTwo;
}

public int getDrawSteps() {
    return this.drawSteps;
}

public Point getEndPoint() {
    return this.endPoint;
}

public Point getStartPoint() {
    return this.startPoint;
}

public void setColor(int paramInt) {
    this.mColor = Color.BLACK;
}

public void setControlPointOne(Point paramPoint) {
    this.controlPointOne = paramPoint;
}

public void setControlPointTwo(Point paramPoint) {
    this.controlPointTwo = paramPoint;
}

public void setDrawSteps(int paramInt) {
    this.drawSteps = paramInt;
}

public void setEndPoint(Point paramPoint) {
    this.endPoint = paramPoint;
}

public void setStartPoint(Point paramPoint) {
    this.startPoint = paramPoint;
}

}

SignatureView.java

public class SignatureViewDemo extends View {
    private int color = Color.BLACK;
    private Bitmap m_Bitmap;
    private final Paint m_BorderPaint;
    private Canvas m_Canvas;
    private Point m_CropBotRight;
    private Point m_CropTopLeft;
    private float m_CurrentX;
    private float m_CurrentY;
    private final float m_DesiredDash;
    private float m_LastWidth = 6.5F;
    private Paint m_PenPaint;
    private int m_PointIndex = 0;
    private ArrayList<Point> m_Points = new ArrayList<Point>();
    private final float m_StrokeWidth;
    boolean m_Empty;



public SignatureViewDemo(Context paramContext) {

    this(paramContext, null);
}

public SignatureViewDemo(Context paramContext,
        AttributeSet paramAttributeSet) {
    this(paramContext, paramAttributeSet, 0);
}



public SignatureViewDemo(Context paramContext,
        AttributeSet paramAttributeSet, int paramInt) 

    super(paramContext, paramAttributeSet, paramInt);
    setFocusable(true);
    this.m_PenPaint = new Paint();
    this.m_PenPaint.setAntiAlias(true);
    this.m_PenPaint.setColor(Color.BLACK);
    this.m_PenPaint.setStrokeWidth(5.0F);
    this.m_PenPaint.setStrokeJoin(Paint.Join.ROUND);
    this.m_PenPaint.setStrokeCap(Paint.Cap.ROUND);
    this.m_CurrentY = (0.0F / 0.0F);
    this.m_CurrentX = (0.0F / 0.0F);
    this.m_StrokeWidth = 5.0F;
    this.m_DesiredDash = 10.0F;
    this.m_BorderPaint = new Paint();
    this.m_BorderPaint.setColor(Color.BLACK);
    this.m_BorderPaint.setStyle(Paint.Style.STROKE);
    this.m_BorderPaint.setStrokeWidth(this.m_StrokeWidth);
}

public void addBezier(Bezier paramBezier, float paramFloat1,
        float paramFloat2) {
    if (this.m_Bitmap == null) {
        this.m_Bitmap = Bitmap.createBitmap(getWidth(), getHeight(),
                Bitmap.Config.ARGB_8888);
        this.m_Canvas = new Canvas(this.m_Bitmap);
    }
    paramBezier.draw(this.m_Canvas, this.m_PenPaint, paramFloat1,
            paramFloat2);
}

public void addPoint(Point paramPoint) {
    if ((paramPoint.getX() < this.m_CropTopLeft.getX())
            && (paramPoint.getX() >= 0.0F))
        this.m_CropTopLeft.setX(paramPoint.getX());
    if ((paramPoint.getY() < this.m_CropTopLeft.getY())
            && (paramPoint.getY() >= 0.0F))
        this.m_CropTopLeft.setY(paramPoint.getY());
    if ((paramPoint.getX() > this.m_CropBotRight.getX())
            && (paramPoint.getX() <= this.m_Canvas.getWidth()))
        this.m_CropBotRight.setX(paramPoint.getX());
    if ((paramPoint.getY() > this.m_CropBotRight.getY())
            && (paramPoint.getY() <= this.m_Canvas.getHeight()))
        this.m_CropBotRight.setY(paramPoint.getY());
    this.m_Points.add(paramPoint);
    drawPoints();
}

// public void clear() {
// if (this.m_Canvas == null)
// this.m_Canvas.drawColor(0, PorterDuff.Mode.CLEAR);
// invalidate();
// // return;
// }

public void clear() {
    if (this.m_Canvas == null)
        return;
    while (m_Empty) {
        m_Canvas.drawColor(0, PorterDuff.Mode.CLEAR);
        m_Empty = true;
        invalidate();
        return;
    }
}

public void drawBitmap(Bitmap paramBitmap) {
    clear();
    if ((paramBitmap != null) && (this.m_Canvas != null)
            && (this.m_Canvas.getWidth() != 0)
            && (this.m_Canvas.getHeight() != 0)) {
        Matrix localMatrix = new Matrix();
        localMatrix.setRectToRect(
                new RectF(0.0F, 0.0F, paramBitmap.getWidth(), paramBitmap
                        .getHeight()),
                new RectF(0.0F, 0.0F, this.m_Canvas.getWidth(),
                        this.m_Canvas.getHeight()),
                Matrix.ScaleToFit.CENTER);
        this.m_Canvas.drawBitmap(paramBitmap, localMatrix, null);
        m_Empty = false;
    }
    invalidate();
}

public void drawPoints() {
    if ((m_Points.size() >= 4)
            && (4 + this.m_PointIndex <= this.m_Points.size())) {
        Point localPoint1 = (Point) this.m_Points.get(this.m_PointIndex);
        Point localPoint2 = (Point) this.m_Points
                .get(1 + this.m_PointIndex);
        Point localPoint3 = (Point) this.m_Points
                .get(2 + this.m_PointIndex);
        Point localPoint4 = (Point) this.m_Points
                .get(3 + this.m_PointIndex);
        Bezier localBezier = new Bezier(localPoint1, localPoint2,
                localPoint3, localPoint4);
        localBezier.setColor(Color.GREEN);
        float f = strokeWidth(8.0F / localPoint4.velocityFrom(localPoint1));
        addBezier(localBezier, this.m_LastWidth, f);
        invalidate();
        this.m_LastWidth = f;
        this.m_PointIndex = (3 + this.m_PointIndex);
        m_Empty = false;
    }
}

public boolean isEmpty() {
    return m_Empty;
}

public Bitmap getBitmap() {
    return this.m_Bitmap;
}

public int getColor() {
    return this.color;
}

protected void onDraw(Canvas paramCanvas) {
    if (this.m_Bitmap != null)
        paramCanvas.drawBitmap(this.m_Bitmap, 0.0F, 0.0F, null);
}

protected void onMeasure(int paramInt1, int paramInt2) {
    int i = View.MeasureSpec.getSize(paramInt1);
    int j = View.MeasureSpec.getSize(paramInt2);
    this.m_CropTopLeft = new Point(i, j);
    this.m_CropBotRight = new Point(0.0F, 0.0F);
    setMeasuredDimension(i, j);
}

protected void onSizeChanged(int paramInt1, int paramInt2, int paramInt3,
        int paramInt4) {
    Bitmap localBitmap = Bitmap.createBitmap(paramInt1, paramInt2,
            Bitmap.Config.ARGB_8888);
    this.m_Canvas = new Canvas(localBitmap);
    float f1 = 2.0F * (this.m_Canvas.getWidth() + this.m_Canvas.getHeight() - 2.0F * this.m_StrokeWidth);
    float f2 = f1
            * this.m_DesiredDash
            / (Math.round(f1 / (4.0F * this.m_DesiredDash)) * (4.0F * this.m_DesiredDash));
    Paint localPaint = this.m_BorderPaint;
    float[] arrayOfFloat = new float[2];
    arrayOfFloat[0] = f2;
    arrayOfFloat[1] = f2;
    localPaint.setPathEffect(new DashPathEffect(arrayOfFloat, f2 / 2.0F));
    clear();
    if (this.m_Bitmap != null) {
        Rect localRect = new Rect(0, 0, this.m_Canvas.getWidth(),
                this.m_Canvas.getHeight());
        this.m_Canvas.drawBitmap(this.m_Bitmap, null, localRect, null);
        m_Empty = false;
    }
    this.m_Bitmap = localBitmap;
}

public boolean onTouchEvent(MotionEvent paramMotionEvent) {
    int i = 0xFF & paramMotionEvent.getAction();
    if (i == 0) {
        this.m_CurrentX = paramMotionEvent.getX();
        this.m_CurrentY = paramMotionEvent.getY();
        addPoint(new Point(this.m_CurrentX, this.m_CurrentY,
                paramMotionEvent.getEventTime()));
        getParent().requestDisallowInterceptTouchEvent(true);
    }
    // while (m_Empty) {
    if ((i == 1) || (i == 3)) {
        this.m_CurrentY = (0.0F / 0.0F);
        this.m_CurrentX = (0.0F / 0.0F);
        this.m_Points.clear();
        this.m_PointIndex = 0;
        getParent().requestDisallowInterceptTouchEvent(false);
    }
    // if ((this.m_Points.size() < 4) || (4 + this.m_PointIndex >
    // this.m_Points.size()))
    // while (1 + this.m_PointIndex <= this.m_Points.size())
    drawPoints();
    if ((i == 2) || (i == 1)) {
        for (int j = 0; j < paramMotionEvent.getHistorySize(); j++)
            addPoint(new Point(paramMotionEvent.getHistoricalX(j),
                    paramMotionEvent.getHistoricalY(j),
                    paramMotionEvent.getHistoricalEventTime(j)));
        addPoint(new Point(paramMotionEvent.getX(),
                paramMotionEvent.getY(), paramMotionEvent.getEventTime()));

    }
    // }
    return true;
}

public void setColor(int paramInt) {
    this.color = Color.BLACK;
}

public Point getCropBotRight() {
    return this.m_CropBotRight;
}

public Point getCropTopLeft() {
    return this.m_CropTopLeft;
}

// public float strokeWidth(float paramFloat) {
// if (paramFloat > 11.0F)
// paramFloat = 10.0F;
// if (paramFloat < 5.0F)
// paramFloat = 6.0F;
// return paramFloat;
// }

public float strokeWidth(float paramFloat) {
    if (paramFloat > 11.0F)
        paramFloat = 10.0F;
    while (m_Empty) {
        if (paramFloat < 5.0F)
            paramFloat = 6.0F;
        return paramFloat;
    }
    return paramFloat;
}

Point.java

    public class Point {

    private long time;
    float x;
    float y;


    public Point(float paramFloat1, float paramFloat2) {
        this.x = paramFloat1;
        this.y = paramFloat2;
    }

    public Point(float paramFloat1, float paramFloat2, long paramLong) {
        this.x = paramFloat1;
        this.y = paramFloat2;
        this.time = paramLong;
    }

    protected float distanceTo(Point paramPoint) {
        float f1 = this.x - paramPoint.getX();
        float f2 = this.y - paramPoint.getY();
        return FloatMath.sqrt(f1 * f1 + f2 * f2);
    }

    public long getTime() {
        return this.time;
    }

    public float getX() {
        return this.x;
    }

    public float getY() {
        return this.y;
    }

    public void setX(float paramFloat) {
        this.x = paramFloat;
    }

    public void setY(float paramFloat) {
        this.y = paramFloat;
    }

    public float velocityFrom(Point start) {
        return distanceTo(start) / (this.time - start.time);
      }
}           
divanov
  • 6,173
  • 3
  • 32
  • 51
Rahul Kalidindi
  • 4,666
  • 14
  • 56
  • 92
  • curve through code with finger speed = you don't want Bezier curves at all, you want Catmull-Rom. They're specifically defined by going through points, at specific speed. (Both are Hermite curves, and can convert to each other without loss of precision, but you really just want to use Catmull-Rom straight away) – Mike 'Pomax' Kamermans Jan 29 '14 at 06:29
  • But as shown in the sample link, when the user wants to sign two seperate words then its not joining the two words with a line. – Rahul Kalidindi Jan 29 '14 at 07:00
  • @RahulVarma Were you able to solve the issue ? – Shobhit Puri May 20 '15 at 18:27

1 Answers1

0

In the onTouchEvent event handler you should watch for MotionEvent.ACTION_DOWN and MotionEvent.ACTION_UP events as they mark beginning and end of a gesture.

private boolean drawing = false;

@Override
public boolean onTouchEvent(MotionEvent event) {
    float eventX = event.getX();
    float eventY = event.getY();

    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
        // Mark drawing as started
        drawing = true;
        path.moveTo(eventX, eventY);
        return true;
    case MotionEvent.ACTION_MOVE:
        // Draw after ACTION_DOWN
        if (drawing) {
            path.lineTo(eventX, eventY);
        }
        break;
    case MotionEvent.ACTION_UP:
        if (drawing) {
            path.lineTo(eventX, eventY);
            // Mark drawing as finished
            drawing = false;
        }
        break;
    default:
        return false;
    }

    if (drawing) {
        // Schedules a repaint.
        invalidate();
    }
    return true;
}

Avoid using values of named constants and dividing by zero.

divanov
  • 6,173
  • 3
  • 32
  • 51