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);
Related
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;
}
}
}
I am trying to draw the line following by the users finger(touch). It is quite easy task to implement if there is no scaling.
Drawing without scaling works perfectly here is an screenshot
Works well. As you can see.
But if I scale an canvas it begins to draw points with some margin/measurement error/tolerance. It seems that I have not taken some value in advance while calculating scaled touch points, I have tried a lot of different formulas, but nothing helped.
Here is the result of zooming the canvas.
It seems that the problem in some delta value that I have to take into consideration
Because if I use this version of scale function it works well but scales only to the left top corner.
canvas.scale(mScaleFactor, mScaleFactor);
With this scaling
canvas.scale(mScaleFactor, mScaleFactor, scalePointX, scalePointY);
Multitouch zoom (pinch) works well but coordinates are not correct.
Please help to solve the problem, it seems that I have to take these scalePointX, scalePointY variables when calculating scaled x and y.
Here is my code. Any help will be highly appreciated.
private void initWorkSpace(Context context) {
mPaint = new Paint();
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
mRect = new Rect();
mPath = new Path();
mPaint.setAntiAlias(true);
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeWidth(10f);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.getClipBounds(mRect);
canvas.save();
canvas.scale(mScaleFactor, mScaleFactor, scalePointX, scalePointY);
canvas.translate(mRect.top,mRect.left);
canvas.drawPath(mPath, mPaint);
canvas.restore();
}
// when ACTION_DOWN start touch according to the x,y values
private void startTouch(float x, float y) {
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) {
mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
mX = x;
mY = y;
}
}
public void clearCanvas() {
mPath.reset();
invalidate();
}
// when ACTION_UP stop touch
private void upTouch() {
mPath.lineTo(mX, mY);
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
// Let the ScaleGestureDetector inspect all events.
mScaleDetector.onTouchEvent(ev);
final int action = ev.getAction();
Log.e("TOUCH","REAL X :" + ev.getX() + " REAL Y : " + ev.getY());
Log.e("TOUCH","RECT TOP :" + mRect.top + " RECT LEFT : " + mRect.left + " RECT RIGHT : " + mRect.right + " RECT BOTTOM :" + mRect.bottom);
final float scaledX = ev.getX()/mScaleFactor+mRect.left*mScaleFactor;
final float scaledY = ev.getY()/mScaleFactor+mRect.top*mScaleFactor;
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
/*final float x = (ev.getX() - scalePointX) / mScaleFactor;
final float y = (ev.getY() - scalePointY) / mScaleFactor;
cX = x - mPosX + scalePointX; // canvas X
cY = y - mPosY + scalePointY; // canvas Y*/
// Remember where we started
mLastTouchX = scaledX;
mLastTouchY = scaledY;
Log.e("DOWN","Scale FACTOR : " + mScaleFactor);
Log.e("DOWN","X : " +mLastTouchX + " Y :" + mLastTouchY + " scalePointX : " + scalePointX + " scalePointY : " + scalePointY );
Log.e("DOWN","Last X : " + mLastTouchY + " Last Y :" + mLastTouchY);
startTouch(mLastTouchX, mLastTouchY);
invalidate();
break;
}
case MotionEvent.ACTION_MOVE: {
/* final float x = (ev.getX() - scalePointX) / mScaleFactor;
final float y = (ev.getY() - scalePointY) / mScaleFactor;
cX = x - mPosX + scalePointX; // canvas X
cY = y - mPosY + scalePointY; // canvas Y
// Only move if the ScaleGestureDetector isn't processing a gesture.
if (!mScaleDetector.isInProgress()) {
final float dx = x - mLastTouchX; // change in X
final float dy = y - mLastTouchY; // change in Y
mPosX += dx;
mPosY += dy;
invalidate();
}*/
Log.e("ACTION_MOVE","Scale FACTOR : " + mScaleFactor);
Log.e("ACTION_MOVE","X : " + scaledX + " Y :" + scaledY + " cX : " + cX + " cY : " + cY );
Log.e("ACTION_MOVE","Last X : " + mLastTouchX + " Last Y :" + mLastTouchY);
mLastTouchX = scaledX;
mLastTouchY = scaledY;
moveTouch(scaledX, scaledY);
invalidate();
break;
}
case MotionEvent.ACTION_UP: {
mLastTouchX = 0;
mLastTouchY = 0;
upTouch();
invalidate();
}
}
return true;
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector detector) {
mScaleFactor *= detector.getScaleFactor();
scalePointX = detector.getFocusX();
scalePointY = detector.getFocusY();
// Don't let the object get too small or too large.
mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 10.0f));
mScaleFactor = (mScaleFactor < 1 ? 1 : mScaleFactor);
invalidate();
return true;
}
}
You just need to convert the screen coordinates to the modified canvas coordinates:
Do these ways:
//If you have moved(transleted) the canvas:
TouchX = TouchX-translatedX;
TouchY=TouchY - translatedY;
// if you have scaled the canvas:
TouchX = TouchX/scaleFactor;
TouchY = TouchY/scaleFactor;
//if you have translated and scaled the canvas:
TouchX= (TouchX-translatedX)/scaleFactor;
TouchY = (TouchY-translatedY)/scaleFactor;
//And then draw with this TouchX and TouchY.
I hope this helps.
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;
}
}
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.