Canvas drawtext positioning - android

I am creating a drawing tool, where user add text to image. While making the text draw to bitmap via canvas position is not being set properly.
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.RED);
paint.setTypeface(tf);
paint.setTextAlign(Paint.Align.LEFT);
paint.setTextSize(30);
int xPos = layoutTextViewContainer.getLeft();
int yPos = layoutTextViewContainer.getTop();
canvas.drawText(text, xPos, yPos, paint);
Paint
Rect textRect = new Rect();
paint.getTextBounds(text, 0, text.length(), textRect);
textRect.offset(0, -textRect.top);
Canvas canvas = new Canvas(bm);
layoutTextViewContainer holds the edit text.
Screen shot for more clarification.
Black text is written and Red text is preview of embed in image

Got the solution. the values should be pixel independent
convert xPos and yPos as below before passing to drawText
xPos = (int) (xPos / getResources().getDisplayMetrics().density);
yPos = (int) (yPos / getResources().getDisplayMetrics().density);

Its even better to use Drawing cache and save that to any file location.
In this case we dont have to much bother about positioning.
Wrap all in one layout and get the
view.getDrawingCache()

Related

Draw text inside a filled rectangle using Canvas Android

How to draw a filled rectangle with specified bounds and inside that rectangle text to be drawn using Canvas Android ?? I tried
mPaint.setColor(Color.GREEN);
canvas.drawText(mText, x, y, mPaint);
mPaint.setColor(Color.BLACK);
canvas.drawRect(x, y, x + w, y + h, mPaint);
but text is not inside of that rectangle. Can any buddy tell me how to draw a rectangle surrounding specified text with consideration of text size ??
Here i have hardcoded x and y values. You can change them
mpaint= new Paint();
mpaint.setColor(Color.RED);
mpaint.setStyle(Style.FILL);
paint2= new Paint();
paint2.setColor(Color.GREEN);
paint2.setTextSize(50); //set text size
float w = paint2.measureText(s)/2;
float textSize = paint2.getTextSize();
#Override
protected void onDraw(Canvas canvas) {
paint2.setTextAlign(Paint.Align.CENTER);
canvas.drawRect(300-w, 300 - textsize, 300 + w, 300, mpaint);
canvas.drawText(s, 300, 300 ,paint2); //x=300,y=300
}
Edit :
Its bad a idea to call measureText in onDraw. You can do that outside of onDraw.
There is a video on also about performance and why you should avoid allocations in onDraw. https://www.youtube.com/watch?v=HAK5acHQ53E
Resulting snap shot
If you have to center the text inside de rect you have use this code
mpaint= new Paint();
mpaint.setColor(Color.RED);
mpaint.setStyle(Style.FILL);
paint2= new Paint();
paint2.setColor(Color.GREEN);
paint2.setTextSize(50); //set text size
float w = paint2.measureText(s)/2;
float textSize = paint2.getTextSize();
#Override
protected void onDraw(Canvas canvas) {
paint2.setTextAlign(Paint.Align.CENTER);
Rect rect = new Rect(300-w, 300 - textsize, 300 + w, 300);
canvas.drawRect(rect, mpaint);
canvas.drawText(s, rect.centerX(), rect.centerY() ,paint2); // center text inside rect
}
This might be very late for this particular query but I think many will find this answer useful. So, the problem with the Canvas for any CustomView is that, you can get the width for a particular text, but it's not that easy to get the height of the text. Also if you are using canvas.drawText(....) with simple Paint object, you can not draw multi line text. So, use the below code within your onDraw() method.
String displayText = "Hello World";
int mainTextPositionX = getWidth() / 2 ;
int mainTextPositionY = getHeight() / 2;
StaticLayout textStaticLayout;
TextPaint textPaint;
textPaint = new TextPaint();
textPaint.setTextAlign(Paint.Align.CENTER);
textPaint.setColor(Color.BLUE);
textPaint.setAntiAlias(true);
textPaint.setTextSize(convertDpToPixel(30, context));
textPaint.setTextAlign(Paint.Align.CENTER);
highlightedRectPaint = new Paint();
highlightedRectPaint.setStrokeWidth(12);
highlightedRectPaint.setStyle(Paint.Style.STROKE);
highlightedRectPaint.setColor(Color.RED);
highlightedRectPaint.setAntiAlias(true);
if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
textStaticLayout = StaticLayout
.Builder
.obtain(displayText, 0, displayText.length(), textPaint, (int) textPaint.measureText(displayText))
.build();
}else{
textStaticLayout = new StaticLayout(
displayText, textPaint, (int)textPaint.measureText(displayText), Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false);
}
Rect highlightedTextBorderRect = new Rect();
highlightedTextBorderRect.top = mainTextPositionY-20;
highlightedTextBorderRect.left = mainTextPositionX-
((int)textPaint.measureText(displayText)/2)-20;
highlightedTextBorderRect.right = mainTextPositionX+
((int)textPaint.measureText(displayText)/2) + 20;
highlightedTextBorderRect.bottom = mainTextPositionY+
(int)textStaticLayout.getHeight()+20;
canvas.save();
canvas.translate(mainTextPositionX, mainTextPositionY);
textStaticLayout.draw(canvas);
canvas.restore();
canvas.drawRect(highlightedTextBorderRect,highlightedRectPaint);
just make sure that, you declare all the objects and variable outside of the draw() method. And this will draw a rectangle outline around the text with multi line support. If you want the rectangle to have a fill, then just use the highlightedRectPaint and change the setStyle(Paint.Style.FILL). Hope that helps.

Center text on a bitmap

I'm trying to draw a text on the center of a bitmap however I can't do it even though I used align.center. The code is:
public Bitmap drawTextToBitmap(Context gContext, String gText) {
Resources resources = gContext.getResources();
float scale = resources.getDisplayMetrics().density;
Bitmap bitmap =
BitmapFactory.decodeResource(resources, R.drawable.blank_marker);
android.graphics.Bitmap.Config bitmapConfig =
bitmap.getConfig();
// set default bitmap config if none
if(bitmapConfig == null) {
bitmapConfig = android.graphics.Bitmap.Config.ARGB_8888;
}
// resource bitmaps are imutable,
// so we need to convert it to mutable one
bitmap = bitmap.copy(bitmapConfig, true);
Canvas canvas = new Canvas(bitmap);
// new antialised Paint
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
// text color - #3D3D3D
paint.setColor(Color.rgb(61, 61, 61));
// text size in pixels
paint.setTextSize((int) (25 * scale));
// text shadow
paint.setShadowLayer(1f, 0f, 1f, Color.WHITE);
// draw text to the Canvas center
Rect bounds = new Rect();
paint.setTextAlign(Align.CENTER);
paint.getTextBounds(gText, 0, gText.length(), bounds);
int x = (bitmap.getWidth() - bounds.width())/2;
int y = (bitmap.getHeight() + bounds.height())/2;
canvas.drawText(gText, x * scale, y * scale, paint);
return bitmap;
}
What am I doing wrong?
It's a lot more straightforward than you think.
Draw the text at half the Bitmap's width and height (center point) in combination with Paint.setTextAlign(Align.CENTER).
The alignment property will take care of the rest.
I guess none of the answers given above are good enough so I post my answer. Try it out guys, it will work on all devices and is not complex at all:
String text = "Text"; //your string
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(activity.getResources().getColor(R.color.white));
paint.setTextSize(30);
// draw text to the Canvas center
Rect boundsText = new Rect();
paint.getTextBounds(text, 0, text.length(), boundsText);
int x = (bitmap.getWidth() - boundsText.width()) / 2;
int y = (bitmap.getHeight() + boundsText.height()) / 2;
canvas.drawText(text, x, y, paint);
Where is the text drawing? The issue might be since you changed the text align to Align.CENTER. Your code calculating x and y assumes the text rendering is using Align.LEFT, I believe.
Either use setTextAlign(Align.CENTER) and render at the actual bitmap center, or use setTextAlign(Align.LEFT) and use the current x and y calculations you are using.

Getting rendered text height, which is equivalent to rendered text width using paint.measureText

I have the following code to draw text.
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setTextSize(400);
paint.setColor(Color.WHITE);
paint.setAntiAlias(true);
paint.setTextAlign(Align.LEFT);
paint.setStyle(Style.FILL);
String text = "698";
Rect bounds = new Rect();
paint.getTextBounds(text, 0, text.length(), bounds);
int textWidth = bounds.width();
int textHeight = bounds.height();
Bitmap originalBitmap = Bitmap.createBitmap(textWidth,
textHeight, Bitmap.Config.ARGB_8888);
Canvas singleUseCanvas = new Canvas(originalBitmap);
singleUseCanvas.drawColor(Color.BLUE);
singleUseCanvas.drawText(text, 0, textHeight, paint);
canvas.drawBitmap(originalBitmap, 0, 0, null);
}
I am getting undesired outcome, which its right and bottom sides are being cropped.
I avoid right side cropping, by using
float textWidth = paint.measureText(text);
Bitmap originalBitmap = Bitmap.createBitmap((int)(textWidth + 0.5),
textHeight, Bitmap.Config.ARGB_8888);
I am getting the following improvement
Yet. My bottom still being cropped. May I know what is the correct way to obtained rendered text height, which is analogy to rendered text width using paint.measureText?
I think i would be helpful to have a look at this post:
Android Paint: .measureText() vs .getTextBounds()
It have a good survey about sizing of rendered text and also text height which is your concern.

measuring text on scaled canvas

I've been struggling with text measuring and scaled canvases.
When the canvas is unscaled, getTextBounds and measureText deliver accurate results. However, when the canvas is scaled both methods do not deliver results that match the actual size of a printed text.
For testing I've created a subclass of View with the following onDraw method:
final float scaling = 0.51f;
final int fontSize = 50;
canvas.scale(scaling, scaling);
font = Typeface.create("Arial", Typeface.NORMAL);
Paint paint = new Paint();
paint.setColor(0xff4444ff);
paint.setTypeface(font);
paint.setTextSize(fontSize);
paint.setAntiAlias(true);
int x = 10;
int y = 100;
final String text = "Lorem ipsum dolor sit amet, consectetur adipisici elit...";
canvas.drawText(text, x, y, paint);
// draw border using getTextBounds
paint.setColor(0xffff0000);
paint.setStyle(Paint.Style.STROKE);
paint.setTypeface(font);
paint.setTextSize(fontSize);
Rect bounds = new Rect();
paint.getTextBounds(text, 0, text.length(), bounds);
bounds.offset(x, y);
paint.setColor(0x80ffff00);
canvas.drawRect(bounds, paint);
// draw border using measureText
float w = paint.measureText(text);
bounds.left = x;
bounds.right = (int) Math.ceil(bounds.left + w);
bounds.top -= 10;
bounds.bottom += 10;
paint.setColor(0x8000ffff);
paint.setPathEffect(new DashPathEffect(new float[] { 10, 10 }, 0));
canvas.drawRect(bounds, paint);
for scaling = 0.5 I get the following output:
for scaling = 0.51 the following result is shown:
The yellow solid border marks the rect delivered from getTextBounds, the dashed cyan rect is rendered using the width delivered from measureText.
As you can see, the text with scaling = 0.5 is smaller than the measured dimensions and with scaling=0.51 the drawn text is way bigger than the measured dimension.
Any help is appreciated!
Ok, just found out how to circumvent the issue.
The problem is that the Paint does not know about the Canvas scaling. Therefore measureText and getTextBounds deliver the unscaled result. But since the font size does not scale linearly (however, the drawn rect does ), you have to make up for that effect manually.
So the solution would be:
// paint the text as usual
Paint paint = new Paint();
paint.setTypeface(font);
paint.setTextSize(fontSize);
canvas.drawText(text, x, y, paint);
// measure the text using scaled font size and correct the scaled value afterwards
Paint paint = new Paint();
paint.setTypeface(font);
paint.setTextSize(fontSize * scaling);
float w = paint.measureText(text) / scaling;
Using Mono for Android I had to use display metrics as shown here:
public override System.Drawing.SizeF MeasureString(MyFont f, string text)
{
Rect r = new Rect();
f.DrawingFont.GetTextBounds(text, 0, text.Length, r);
//Manual scaling using DisplayMetrics due to Android
//issues for compatibility with older versions
Android.Util.DisplayMetrics metrics = new Android.Util.DisplayMetrics();
GetDisplay.GetMetrics(metrics);
return new System.Drawing.SizeF(r.Width(), r.Height() * metrics.Density);
}
Where f.DrawingFont is an Androdid.Text.TextPaint GetDisplay is:
private Display GetDisplay()
{
return this.GetSystemService(Android.Content.Context.WindowService).JavaCast<Android.Views.IWindowManager>().DefaultDisplay;
}
And the same method in Java is:
private Display getDisplay() {
return ((WindowManager) getContext().getSystemService(
Context.WINDOW_SERVICE)).getDefaultDisplay();
}

Not getting complete text while Animation on Canvas : Android,

I want to get an animated text in Android where it should run from left to right on the screen.
Eg.
I want to get this text
private static final String QUOTE =
"Nobody uses Java anymore. It's this big heavyweight ball and chain.";
running from right to left using animation.
However, this text gets truncated to "Nobody uses Java anymore. It's" in Portrait mode and to
"Nobody uses Java anymore. It's this big heavyweight" in landscape mode.
This is the code that I have used
Paint paint = new Paint();
paint.setColor(Color.BLUE);
private static final String QUOTE =
"Nobody uses Java anymore. It's this big heavyweight ball and chain.";
paint.setTextSize(20);
paint.setAntiAlias(true);
int len= QUOTE.length();
canvas.scale(1,-1);
canvas.drawText(QUOTE, 0, len-1, 100, 60, paint);
canvas.drawText(QUOTE,0,100 , paint);
createAnim(canvas);
private void createAnim(Canvas canvas) {
anim2= new TranslateAnimation(500,-500,30,30);
anim2.setRepeatCount(Animation.INFINITE);
anim2.setInterpolator(new AccelerateDecelerateInterpolator());
anim2.setRepeatMode(Animation.RESTART);
anim2.setDuration(1000L);
startAnimation(anim2);
}
How to do Text Animations using Android SDK?
Please refer this post for text animations.
Please check height and width of canvas ,
// Custom Font Text
Bitmap bitmap = Bitmap.createBitmap((int) getWindowManager()
.getDefaultDisplay().getWidth(),
(int) getWindowManager().getDefaultDisplay()
.getHeight() / 2, Bitmap.Config.ARGB_8888);
canvas = new Canvas(bitmap);
drawingImageView.setImageBitmap(bitmap);
paint = new Paint();
paint.setColor(Color.BLACK);
paint.setTextSize(150);
Typeface chops = Typeface.createFromAsset(this.getAssets(),
"WC_Speed_Bold_Bta.ttf");
paint.setTypeface(chops);
int xPos = (canvas.getWidth() / 2);
int yPos = (int) ((canvas.getHeight() / 2) - ((paint.descent() + paint
.ascent()) / 2));
canvas.drawText("Hello", xPos, yPos, paint);

Categories

Resources