Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android: digital signature using Bezier

enter image description here
I am trying two draw digital signature using Bezier as show in above image.when i touch and try to draw line then the result is dot line but not getting continuous line. Simple signature done by using simple signature but I want to create more a smooth curve using Bezier with touch pressure. tried with this link

SignatureViewDemo.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

    private long time;
    private float x;
    private 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 paramPoint) {
            return distanceTo(paramPoint) / (this.time - paramPoint.time);
    }
}

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 paramCanvas, Paint paramPaint, float paramFloat1,
        float paramFloat2) {
    float f1 = paramFloat2 - paramFloat1;
    for (int i = 0; i < this.drawSteps; i++) {
        float f2 = i / this.drawSteps;
        float f3 = f2 * f2;
        float f4 = f3 * f2;
        float f5 = 1.0F - f2;
        float f6 = f5 * f5;
        float f7 = f6 * f5;
        float f8 = f7 * this.startPoint.getX() + f2 * (3.0F * f6)
                * this.controlPointOne.getX() + f3 * (3.0F * f5)
                * this.controlPointTwo.getX() + f4 * this.endPoint.getX();
        float f9 = f7 * this.startPoint.getY() + f2 * (3.0F * f6)
                * this.controlPointOne.getY() + f3 * (3.0F * f5)
                * this.controlPointTwo.getY() + f4 * this.endPoint.getY();
        paramPaint.setColor(getColor());
        paramPaint.setStrokeWidth(paramFloat1 + f4 * f1);
        paramCanvas.drawPoint(f8, f9, paramPaint);
    }
}

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;
}

}

like image 936
kyogs Avatar asked May 09 '13 06:05

kyogs


3 Answers

Change draw method in Bezier class to:

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);
}
like image 73
mdolanci Avatar answered Sep 23 '22 02:09

mdolanci


You need to see how many points are drawn in Bezier class and add them up.

From your code: You are collecting 4 points and draw a Bezier curve over them. This means that the algorithm - by design - will miss half of the sampled points.

Other options: 1. Create your own Bezier curve or lower order (say - order 3) - and then you'll miss only 1/3 of the points. This kinda renders the issue useless, as you want to conserve less data than sampled. 2. Create a high order Bezier curve that can approximate the whole signature.

You can, however, try to figure out what points you would like to select in order to get a Bezier curve which is closer to the signature : select the top of the letter 'l' as an end point of one Bezier curve and the start of another will yield better results.

like image 28
Henry Aloni Avatar answered Sep 19 '22 02:09

Henry Aloni


You can use simple

code

public class MySignatureView extends View

 {

private Path mPath;

private Paint mPaint;
private Bitmap mBitmap;
private Canvas mCanvas;
private int bgColor;

private float curX, curY;
private boolean isDragged = false;

private static final int TOUCH_TOLERANCE = 4;
private static final int STROKE_WIDTH = 2;

public MySignatureView(Context context) {
    super(context);
    init();
}

public MySignatureView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init();
}

public MySignatureView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init();
}

private void init() {
    setFocusable(true);
    bgColor = Color.WHITE;
    mPath = new Path();
    mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mPaint.setColor(bgColor ^ 0x00FFFFFF);
    mPaint.setStyle(Paint.Style.STROKE);
    mPaint.setStrokeWidth(STROKE_WIDTH);
}

public void setSigColor(int color) {
    mPaint.setColor(color);
}

public void setSigColor(int a, int r, int g, int b) {
    mPaint.setARGB(a, r, g, b);
}

public void clearSig() {
    if (mCanvas != null) {
        mCanvas.drawColor(bgColor);
        mCanvas.drawPaint(mPaint);
        mPath.reset();
        invalidate();
    }
}

public Bitmap getImage() {
    return this.mBitmap;
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    int bitW = mBitmap != null ? mBitmap.getWidth() : 0;
    int bitH = mBitmap != null ? mBitmap.getWidth() : 0;

    if (bitW >= w && bitH >= h) {
        return;
    }

    if (bitW < w)
        bitW = w;
    if (bitH < h)
        bitH = h;

    Bitmap newBitmap = Bitmap.createBitmap(bitW, bitH,
            Bitmap.Config.ARGB_8888);
    Canvas newCanvas = new Canvas();
    newCanvas.setBitmap(newBitmap);

    if (mBitmap != null) {
        newCanvas.drawBitmap(mBitmap, 0, 0, null);
    }

    mBitmap = newBitmap;
    mCanvas = newCanvas;
}

@Override
protected void onDraw(Canvas canvas) {
    canvas.drawBitmap(mBitmap, 0, 0, mPaint);
    canvas.drawPath(mPath, mPaint);
}

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

    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
        touchDown(x, y);
        break;
    case MotionEvent.ACTION_MOVE:
        touchMove(x, y);
        break;
    case MotionEvent.ACTION_UP:
        touchUp();
        break;
    }
    invalidate();
    return true;
}

private void touchDown(float x, float y) {
    mPath.reset();
    mPath.moveTo(x, y);
    curX = x;
    curY = y;
    isDragged = false;
}

private void touchMove(float x, float y) {
    float dx = Math.abs(x - curX);
    float dy = Math.abs(y - curY);
    if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
        mPath.quadTo(curX, curY, (x + curX) / 2, (y + curY) / 2);
        curX = x;
        curY = y;
        isDragged = true;
    }
}

private void touchUp() {
    if (isDragged) {
        mPath.lineTo(curX, curY);
    } else {
        mPath.lineTo(curX+2, curY+2);
    }
    mCanvas.drawPath(mPath, mPaint);
    mPath.reset();
}

  }
like image 1
naran z Avatar answered Sep 22 '22 02:09

naran z