In this Image I want text to totally be in the triangle with CYAN color.
I have created my own ImageView:
public class BookImageView extends android.support.v7.widget.AppCompatImageView {
private static final Float DISCOUNT_SIDE_SIZE = 0.33333F;
private Bitmap bitmap;
private Paint drawPaint = new Paint();
private Paint trianglePaint = new Paint();
{
trianglePaint.setColor(Constants.DISCOUNT_COLOR);
trianglePaint.setStyle(Paint.Style.FILL);
trianglePaint.setShadowLayer(10.0f, 10.0f, 10.0f, Color.parseColor("#7f000000"));
trianglePaint.setAntiAlias(true);
drawPaint.setColor(Color.BLACK);
drawPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
drawPaint.setShadowLayer(1f, 0f, 1f, Color.BLACK);
}
// Constractors ...
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (bitmap != null) {
Bitmap tempBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.RGB_565);
Canvas tempCanvas = new Canvas(tempBitmap);
tempCanvas.drawBitmap(bitmap, 0, 0, null);
Path path = new Path();
path.setFillType(Path.FillType.EVEN_ODD);
float size = bitmap.getWidth() * DISCOUNT_SIDE_SIZE;
path.lineTo(size, 0);
path.lineTo(0, size);
path.lineTo(0, 0);
path.close();
tempCanvas.drawPath(path, trianglePaint);
float scale = getResources().getDisplayMetrics().density;
drawPaint.setTextSize((int) (14 * scale));
Rect textBounds = new Rect();
drawPaint.getTextBounds("50%", 0, "50%".length(), textBounds);
int x = (int) (size / 2) - textBounds.width() / 2;
int y = (int) (size / 2) - textBounds.height() / 2;
tempCanvas.save();
tempCanvas.rotate(-45, x, y);
tempCanvas.drawText("50%", x, y, drawPaint);
tempCanvas.restore();
setImageDrawable(new BitmapDrawable(getContext().getResources(), tempBitmap));
}
}
#Override
public void setImageBitmap(Bitmap bitmap) {
this.bitmap = bitmap;
invalidate();
}
}
what can I do to solve this problem ?
You can try something like this
1) Measure the width of your text
Use measureText
2) From the point you are drawing calculate the width remaining to draw
3) Now depending on the use case you can curtail the length of text or scale the text as needed
int textWidthRequired = (int) drawPaint.measureText(textToDraw);
int widthRemainingToDraw = totalWidth/2 - textDrawX;
if(textWidthRequired > widthRemainingToDraw){
//handling
}
// draw text
tempCanvas.drawText(textToDraw,textDrawX, textDrawY, drawPaint);
Depending on how high up you want the text to be, you can use properties of similar triangles to first determine the maximum width of the text. In your case, size = the triangle's base, and size = the triangle's height/altitude. Let's define two variables:
Correction: The altitude won't be equal to the base. You'd need to calculate the altitude in order to use the below solution.
float triangleBase = size; // triangle base
float triangleAltitude = size; // Calculate this.
Let's say we want the text to be halfway up the center of the triangle:
float textYHeight = triangleHeight/2;
We figure out the width of the triangle at this point by using the following formula since the sides of similar triangles are proportional:
baseOfTriangleA/baseOfTriangleB = altitudeOfTriangleA/altitudeOfTriangleB;
float triangleWidthAtTextYLocation = (textYHeight * triangleBase)/triangleAltitude;
Now that we know what the width of the triangle is at this location, we can just iterate through different text scales until the text width is less than the value triangleWidthAtTextYlocation.
float scale = getResources().getDisplayMetrics().density;
int scaleFactor = 0;
drawPaint.setTextSize((int) (scaleFactor * scale));
Rect textBounds = new Rect();
drawPaint.getTextBounds("50%", 0, "50%".length(), textBounds);
while(textBounds.length < triangleWidthAtTextYLocation){
// Re-measure the text until it exceeds the width
scaleFactor++;
drawPaint.setTextSize((int) (scaleFactor * scale));
drawPaint.getTextBounds("50%", 0, "50%".length(), textBounds);
}
// Once we know the scaleFactor that puts it over the width of the triangle
// at that location, we reduce it by 1 to be just under that width:
scaleFactor = Maths.abs(scaleFactor - 1);
// final text size:
drawPaint.setTextSize((int) (scaleFactor * scale));
Related
I am trying to convert text into image using below code :
public Bitmap textAsBitmap(String text, float textSize) {
Paint paint = new Paint(ANTI_ALIAS_FLAG);
paint.setTextSize(textSize);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.FILL_AND_STROKE);
paint.setTextAlign(Paint.Align.CENTER);
float baseline = -paint.ascent(); // ascent() is negative
int width = (int) (paint.measureText(text) + 0.5f); // round
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;
}
Its convert text into image but problem is show half text.It should show "favorite subject is english"!
what i am doing wrong ? or how should i solve this problem
Choose your width & height wisely,
Something like I did in my case
public Bitmap textAsBitmap(String text, float textSize) {
Paint paint = new Paint(ANTI_ALIAS_FLAG);
paint.setTextSize(textSize);
paint.setColor(Color.BLACK);
paint.setTextAlign(Paint.Align.LEFT);
float baseline = -paint.ascent(); // ascent() is negative
int width = (int) (paint.measureText(text) + 0.0f); // round
int height = (int) (baseline + paint.descent() + 0.0f);
int actualWidth = width;
if (width > height)
height = width;
else
width = height;
Bitmap image = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(image);
canvas.drawText(text, width / 2 - actualWidth / 2, baseline, paint);
return image;
}
Problem is with paint.setTextAlign(Paint.Align.CENTER);, this property considers center as (0,0). So your text is actually at center according to (0,0).
Just remove paint.setTextAlign(Paint.Align.CENTER); and your code is working!!
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;
}
I'm trying to draw the spectrum of an audio file on a circle. Like this:
So on the circle I just want rectangles drawn like you see on the image.
I've got this code:
public void onRender(Canvas canvas, FFTData data, Rect rect) {
canvas.drawCircle(rect.width()/2, rect.height()/2, 200, mPaint);
for (int i = 0; i < data.bytes.length / mDivisions; i++) {
byte rfk = data.bytes[mDivisions * i];
byte ifk = data.bytes[mDivisions * i + 1];
float magnitude = (rfk * rfk + ifk * ifk);
int dbValue = (int) (10 * Math.log10(magnitude));
}
}
Where FFTData is the Fast Fourier Transformation data that Android gives me. Now in my dbValue I got the strength of the signal. mDivisions is how much bars I want. Currently set on 16 because I don't know how much I can set on the circle.
I'm stuck on how I can draw the rectangle with his center on the circle line... So I want a rectangle whose height is based on the dbValue so that I get high and low rectangles. And the center must be placed on my circle line.
Can someone help me on this math formula?
Run a loop over all 360 degrees of the circle (at wanted step), and, for each point, convert Polar (this angle and the radius of the circle) coordinates into Cartesian, as described here, for instance. This way you get the location of the centre of your rectangle.
Translate the system of the coordinates, making origin to be at the wanted point on the circle line and then rotate by the circle angle at that point.
Alternatively, you can build a trapezoid by getting corners at angle +- some offset and radius +- some offset (proportional to your value to plot). It will have shorter inner edge and longer outer edge. Such trapezoids may look better if painted side by side.
i think all you have needed is a pencil and a paper and a little math and also some free time to play :-)
public class MainActivity extends Activity {
ImageView drawingImageView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
drawingImageView = (ImageView) this.findViewById(R.id.DrawingImageView);
Paint paint;
paint = new Paint();
paint.setColor(Color.GREEN);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(16);
final Bitmap bitmap = Bitmap.createBitmap((int) getWindowManager()
.getDefaultDisplay().getWidth(), (int) getWindowManager()
.getDefaultDisplay().getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
int centerX =400;
int centerY =400;
int R = 200;
canvas.drawCircle(centerX, centerY, R, paint);
int h = 100;
paint.setColor(Color.RED);
Path p = new Path();
p.moveTo(centerX + R - h/2, centerY);
p.lineTo(centerX + R + h/2, centerY);
canvas.drawPath(p, paint);
p = mySpectrumDrawer(centerX,centerY,R,h,15);
canvas.drawPath(p, paint);
h = 50;
p = mySpectrumDrawer(centerX,centerY,R,h,30);
canvas.drawPath(p, paint);
h = 60;
p = mySpectrumDrawer(centerX,centerY,R,h,60);
canvas.drawPath(p, paint);
h = 80;
p = mySpectrumDrawer(centerX,centerY,R,h,90);
canvas.drawPath(p, paint);
drawingImageView.setImageBitmap(bitmap);
}
private Path mySpectrumDrawer(int centerX, int centerY,int R,int height, int angel){
Path p = new Path();
int dX = (int) (R*(Math.cos(Math.toRadians(angel))));
int dY = (int) (R*(Math.sin(Math.toRadians(angel))));
int dhx = (int) (height/2*(Math.cos(Math.toRadians(angel))));
int dhy = (int) (height/2*(Math.sin(Math.toRadians(angel))));
p.moveTo(centerX + dX - dhx , centerY - dY + dhy);
p.lineTo(centerX + dX + dhx , centerY - dY - dhy);
return p;
}
}
I am displaying two points in google-map. and draw a line between two points. Now i have distance value and want to display at center of line.
what should i need to do?
Polyline line = mMap.addPolyline(new PolylineOptions()
.add(geo, new LatLng(28.549961,77.4107057))
.width(2)
.color(Color.BLUE).geodesic(true));
Above it the code of draw a line
Create a Png with a invisible background and import it to your drawable folder. After that use this code:
obm = writeTextOnDrawable(R.drawable.text_background, yourtexthere);
LatLng point=new LatLng((latitude1+latitude2)/2,(longitude1+longitude2)/2);
MarkerOptions markerOptions = new MarkerOptions().icon(
BitmapDescriptorFactory.fromBitmap(obm))
.position(point);
mMap.addMarker(markerOptions));
private Bitmap writeTextOnDrawable(int drawableId, String text) {
Bitmap bm = BitmapFactory.decodeResource(getResources(), drawableId)
.copy(Bitmap.Config.ARGB_8888, true);
Typeface tf = Typeface.create("Helvetica", Typeface.BOLD);
Paint paint = new Paint();
paint.setStyle(Style.FILL);
paint.setColor(Color.WHITE);
paint.setColor(Color.BLACK);
paint.setTypeface(font);
paint.setTextAlign(Align.CENTER);
paint.setTextSize(convertToPixels(this, 11));
Rect textRect = new Rect();
paint.getTextBounds(text, 0, text.length(), textRect);
Canvas canvas = new Canvas(bm);
// If the text is bigger than the canvas , reduce the font size
if (textRect.width() >= (canvas.getWidth() - 4)) // the padding on
// either sides is
// considered as 4,
// so as to
// appropriately fit
// in the text
paint.setTextSize(convertToPixels(this, 7)); // Scaling needs to be
// used for
// different dpi's
// Calculate the positions
int xPos = (canvas.getWidth() / 2) - 2; // -2 is for regulating the x
// position offset
// "- ((paint.descent() + paint.ascent()) / 2)" is the distance from the
// baseline to the center.
int yPos = (int) ((canvas.getHeight() / 2) - ((paint.descent() + paint
.ascent()) / 2));
canvas.drawText(text, xPos, yPos, paint);
return bm;
}
public static int convertToPixels(Context context, int nDP) {
final float conversionScale = context.getResources()
.getDisplayMetrics().density;
return (int) ((nDP * conversionScale) + 0.5f);
}
edit the yourtexthere and point variables and the png resource name to your liking
You could use a custom marker that you set where you need it to be. You'll have to figure out an algorithm for that.
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.