Drawing HTML with Paint - android

I'm trying to draw text on a Google Map Fragment by generating a bitmap and placing it as a marker. However the text needs to be stylized via HTML. I was wondering if this is possible.
public static Bitmap createPureTextIcon(String text){
Paint textPaint = new Paint();
//textPaint.setTypeface(TypefaceUtil.get(m))
textPaint.setTextSize(MAP_DISPLAY_TEXT_SIZE);
textPaint.setAntiAlias(true);
textPaint.setTextAlign(Paint.Align.LEFT);
float baseline = -textPaint.ascent(); // ascent() is negative
int width = (int) (textPaint.measureText(text) + 0.5f); // round
int height = (int) (baseline + textPaint.descent() + 0.5f);
CharSequence m = ViewUtil.noTrailingwhiteLines(Html.fromHtml(text));
//height * 2
Bitmap image = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(image);
canvas.drawText(m.toString(), 0, baseline, textPaint);
//canvas.translate(0, height*4);
return image;
}
Example HTML
I mainly need it to render the <br />
<p style=\"text-align: center;\">Looking<br />at Earth </p>

Use a StaticLayout
StaticLayout layout = new StaticLayout(Html.fromHtml(m.toString()), textPaint, width, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
layout.draw(canvas);

Try canvas.drawText(HTML.fromHtml(text), 0, baseline, textPaint); fromHTML converts a string of HTML into a Spannable that can be drawn.

Related

Android - Any library for adding repost label to bitmap

I have been trying to make a photo sharing app, with the ability to add your image and name to the image. I have been messing with Canvas for the whole day, but couldn't get good results. I was able to draw the name and bitmap, but they didn't look so good.
That's why I am here asking about is there any library or piece of code that could help me in making something similar to [this][1]. I wasn't able to find any thing for it.
EDIT: Sorry for not adding my own code
Here is my code from my latest try
public void AddText(Position2D pos){
//Position2D is an enum having the 4 corners of the image
bmWorking= bmOriginal.copy(Bitmap.Config.ARGB_8888,true);
Canvas canvas = new Canvas(bmWorking);
Paint paint = new Paint();
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.FILL);
Paint textPaint = new Paint();
textPaint.setColor(Color.BLACK);
float width = (35f/100f) * bmWorking.getWidth();
float height = (width/16f) * 3;
textPaint.setTextSize(height - 4); //I wanted to have some space (margin) above and below the text
textPaint.setTextAlign(Paint.Align.LEFT);
float [] coords = getPositionCoords(pos, width, height); //getPositionCoords returns a float array with the Left,Top,Right,Bottom position calculated based on the width and height
canvas.drawRect(coords[0],coords[1], coords[2], coords[3],paint);
username = "Haider Ali Punjabi";
canvas.drawText(username, coords[0] ,coords[3], textPaint);
bitmapView.setImageBitmap(bmWorking);
}
Here is the result
UPDATE:
#pskink gave me this code
which works nicely
if you want to customize it, then instead of solid white rectangle (like in your original code) use a Drawable and the result could be something like this:
the code:
// for int gravity: see android.view.Gravity, like Gravity.LEFT, Gravity.BOTTOM, etc
// for example:
// Bitmap out = addText(this, in, "Haider Ali Punjabi", android.R.drawable.alert_light_frame, Gravity.BOTTOM, new Point(10, 10));
public Bitmap addText(Context ctx, Bitmap in, String text, int resId, int gravity, Point pad) {
if (pad == null) pad = new Point();
Bitmap out = in.copy(Bitmap.Config.ARGB_8888, true);
Canvas canvas = new Canvas(out);
Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
textPaint.setColor(Color.BLACK);
textPaint.setTextAlign(Paint.Align.LEFT);
// textPaint.setTextSize(128);
Rect inBounds = new Rect();
textPaint.getTextBounds(text, 0, text.length(), inBounds);
float scale = out.getWidth() * 0.35f / inBounds.width();
Rect container = new Rect(0, 0, out.getWidth(), out.getHeight());
Rect outBounds = new Rect();
int w = (int) (inBounds.width() * scale);
int h = (int) (inBounds.height() * scale);
Gravity.apply(gravity, 2 * pad.x + w, 2 * pad.y + h, container, outBounds);
Drawable dr = ctx.getResources().getDrawable(resId);
Rect padding = new Rect();
dr.getPadding(padding);
dr.setBounds(outBounds.left - padding.left, outBounds.top - padding.top, outBounds.right + padding.right, outBounds.bottom + padding.bottom);
dr.draw(canvas);
Matrix matrix = new Matrix();
RectF src = new RectF(inBounds);
RectF dst = new RectF(outBounds);
dst.inset(pad.x, pad.y);
matrix.setRectToRect(src, dst, Matrix.ScaleToFit.CENTER);
canvas.concat(matrix);
canvas.drawText(text, 0, 0, textPaint);
return out;
}

Android drawText including text wrapping

I am currently creating an image editor and am attempting to draw text on top of on image using canvas.drawText(). So far I have been successful in doing this but when the user enters text that is too long, the text just continues on one line out of the page and doesn't wrap itself to the width of the screen. How would I go about doing this? I have tried using a static layout but cannot seem to get it to work, has anyone got a tutorial to do this?
My function for drawing on a canvas using static layout:
public Bitmap createImage(float scr_x,float scr_y,String user_text){
Canvas canvas = new Canvas(image);
scr_x = 100;
scr_y = 100;
final TextPaint tp = new TextPaint(Color.WHITE);
canvas.save();
StaticLayout sl = new StaticLayout("" + user_text, tp, originalBitmap.getWidth(), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
sl.draw(canvas);
return image;
}
Okay, I've updated my code, but when I try to draw on the image nothing happens at all, I have no idea why either:
public Bitmap createImage(String user_text) {
// canvas object with bitmap image as constructor
Canvas canvas = new Canvas(image);
TextPaint tp = new TextPaint();
tp.setColor(Color.RED);
tp.setTextSize(50);
tp.setTextAlign(Align.CENTER);
tp.setAntiAlias(true);
StaticLayout sl = new StaticLayout("" + user_text, tp,
canvas.getWidth(), Layout.Alignment.ALIGN_NORMAL, 1, 0, false);
canvas.translate(100, 100);
sl.draw(canvas);
return image;
}
Is staticlayout not meant to be used to draw on canvas?
Yes, StaticLayout is what you're meant to use to draw multi-line text on a Canvas. Save yourself a world of pain and don't think about breaking text yourself -- you're on the right path.
I'm not sure about the bitmap problem, but your second code above worked just fine to draw text on a canvas for me.
Learn to use StaticLayout , then draw the Layout object onto a canvas using the Layout.draw() method.
References
public Bitmap drawMultilineTextToBitmap(Context gContext,
int gResId,
String gText) {
// prepare canvas
Resources resources = gContext.getResources();
float scale = resources.getDisplayMetrics().density;
Bitmap bitmap = BitmapFactory.decodeResource(resources, gResId);
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 antialiased Paint
TextPaint paint=new TextPaint(Paint.ANTI_ALIAS_FLAG);
// text color - #3D3D3D
paint.setColor(Color.rgb(61, 61, 61));
// text size in pixels
paint.setTextSize((int) (14 * scale));
// text shadow
paint.setShadowLayer(1f, 0f, 1f, Color.WHITE);
// set text width to canvas width minus 16dp padding
int textWidth = canvas.getWidth() - (int) (16 * scale);
// init StaticLayout for text
StaticLayout textLayout = new StaticLayout(
gText, paint, textWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false);
// get height of multiline text
int textHeight = textLayout.getHeight();
// get position of text's top left corner
float x = (bitmap.getWidth() - textWidth)/2;
float y = (bitmap.getHeight() - textHeight)/2;
// draw text to the Canvas center
canvas.save();
canvas.translate(x, y);
textLayout.draw(canvas);
canvas.restore();
return bitmap;
}
source : http://www.skoumal.net/en/android-drawing-multiline-text-on-bitmap/
You should handle it yourself, calculating the text size and wrapping the content in some way (break line at max width or wrap last word).
I already did it on Java SE with the FontMetrics, never for Android; but you should take a look:
http://developer.android.com/reference/android/graphics/Paint.FontMetrics.html
As pointed by Lisa, StaticLayout is the way to go to measure text wrapping.

How to write text more than 10 letters using Canvas and paint on map?

Marking few markers and adding names using Canvas and Paint on map. But am able to see the text only 9 characters rest are hiding (not visible). How to do it?
private Bitmap drawTitleOnMarkerIcon(MarkingInfo markingInfo) {
Bitmap bm = BitmapFactory.decodeResource(getResources(), AddLocationTypeIcon.getIcon(markingInfo.getType())).copy(
Bitmap.Config.ARGB_8888, true);
Canvas canvas = new Canvas(bm);
Paint paint = new Paint();
paint.setColor(Color.BLUE);
paint.setAntiAlias(true);
paint.setFakeBoldText(true);
paint.setTextSize(16);
paint.setTextAlign(Align.LEFT);
canvas.drawText(markingInfo.getName(), 0, 60, paint);
BitmapDrawable draw = new BitmapDrawable(getResources(), bm);
return draw.getBitmap();
}
I should able to see complete text, When I have more than 15 character just I need to wrap it to next line. search many sites and posted query previously but I got no solution. please do help to achieve this task
private Bitmap textAsBitmap(String text, float textSize, int textColor) {
Paint paint = new Paint();
paint.setTextSize(textSize);
paint.setColor(textColor);
paint.setFakeBoldText(true);
paint.setTextAlign(Paint.Align.LEFT);
int width = (int) (paint.measureText(text) + 0.5f); // round
float baseline = (int) (-paint.ascent() + 0.5f); // ascent()is negative
int height = (int) (baseline + paint.descent() + 0.5f);
Bitmap image = Bitmap.createBitmap(width,height,Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(image);
canvas.drawText(text, 0, baseline, paint);
return image;
}
MarkerOptions().title(Name()).icon(BitmapDescriptorFactory.fromBitmap(textAsBitmap));

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.

Categories

Resources