I have a list of contacts and I want to show in each contact's QuickContactBadge the first letter of his name.
Can I create the images in runtime?
This is like Android Lollipop, where contacts and dialer uses QuickContactBadge with letters:
I use a function to generate these images.
public static Bitmap generateCircleBitmap(Context context, int circleColor, float diameterDP, String text){
final int textColor = 0xffffffff;
DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
float diameterPixels = diameterDP * (metrics.densityDpi / 160f);
float radiusPixels = diameterPixels/2;
// Create the bitmap
Bitmap output = Bitmap.createBitmap((int) diameterPixels, (int) diameterPixels,
Bitmap.Config.ARGB_8888);
// Create the canvas to draw on
Canvas canvas = new Canvas(output);
canvas.drawARGB(0, 0, 0, 0);
// Draw the circle
final Paint paintC = new Paint();
paintC.setAntiAlias(true);
paintC.setColor(circleColor);
canvas.drawCircle(radiusPixels, radiusPixels, radiusPixels, paintC);
// Draw the text
if (text != null && text.length() > 0) {
final Paint paintT = new Paint();
paintT.setColor(textColor);
paintT.setAntiAlias(true);
paintT.setTextSize(radiusPixels * 2);
Typeface typeFace = Typeface.createFromAsset(context.getAssets(),"fonts/Roboto-Thin.ttf");
paintT.setTypeface(typeFace);
final Rect textBounds = new Rect();
paintT.getTextBounds(text, 0, text.length(), textBounds);
canvas.drawText(text, radiusPixels - textBounds.exactCenterX(), radiusPixels - textBounds.exactCenterY(), paintT);
}
return output;
}
I pass the contact's name into the following getMaterialColor function to select a color.
private static List<Integer> materialColors = Arrays.asList(
0xffe57373,
0xfff06292,
0xffba68c8,
0xff9575cd,
0xff7986cb,
0xff64b5f6,
0xff4fc3f7,
0xff4dd0e1,
0xff4db6ac,
0xff81c784,
0xffaed581,
0xffff8a65,
0xffd4e157,
0xffffd54f,
0xffffb74d,
0xffa1887f,
0xff90a4ae
);
public static int getMaterialColor(Object key) {
return material.get(Math.abs(key.hashCode()) % materialColors.size());
}
Related
How can we check selected language support on the Android device? or How to get currently supported language in Android device
I have created one method for checking particular language supported or not.
public static boolean isLanSupported(Context context, String text) {
final int WIDTH_PX = 200;
final int HEIGHT_PX = 80;
int w = WIDTH_PX, h = HEIGHT_PX;
Resources resources = context.getResources();
float scale = resources.getDisplayMetrics().density;
Bitmap.Config conf = Bitmap.Config.ARGB_8888;
Bitmap bitmap = Bitmap.createBitmap(w, h, conf);
Bitmap orig = bitmap.copy(conf, false);
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.rgb(0, 0, 0));
paint.setTextSize((int) (14 * scale));
// draw text to the Canvas
Rect bounds = new Rect();
paint.getTextBounds(text, 0, text.length(), bounds);
int x = (bitmap.getWidth() - bounds.width()) / 2;
int y = (bitmap.getHeight() + bounds.height()) / 2;
canvas.drawText(text, x, y, paint);
boolean res = !orig.sameAs(bitmap);
orig.recycle();
bitmap.recycle();
return res;
}
following way to call a method
isLanSupported(getActivity(),"ગુજરાતી")
isLanSupported(getActivity(),"हिंदी")
isLanSupported(getActivity(),"English")
You can get the default language with de Locale object
Locale.getDefault() for the default, and Locale.getAvailableLocales() for available langages.
(See this other post)
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));
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 want to show the value of the current progress point in the thumb of an Android SeekBar. This is what I have tried so far:
SeekBar progBar = (SeekBar)FindViewById(Resource.Id.seekBar1);
progBar.ProgressChanged += (object sender, SeekBar.ProgressChangedEventArgs e) =>
{
if (e.FromUser)
{
Drawable d = ContextCompat.GetDrawable(this, Resource.Drawable.thumb);
Bitmap bitmap = BitmapFactory.DecodeResource(Resources, Resource.Drawable.thumb);
Bitmap bmp = bitmap.Copy(Bitmap.Config.Argb8888, true);// this line gives me a System.NullReferenceException: Object reference not set to an instance of an object. error
Canvas c = new Canvas(bmp);
Canvas c = new Canvas(bmp);
string text = Integer.ToString(progBar.Progress);
Paint p = new Paint();
p.SetTypeface(Typeface.DefaultBold);
p.TextSize = 14;
p.Color = Color.White;
int width = (int)p.MeasureText(text);
int yPos = (int)((c.Height / 2) - ((p.Descent() + p.Ascent()) / 2));
c.DrawText(text, (bmp.Width - width) / 2, yPos, p);
progBar.SetThumb(new BitmapDrawable(Resources, bmp));
}
};
Then when I got the type of Drawable d, it's a Gradient Drawable. I researched but I couldn't find a way to convert a gradient Drawable to bitmap.
Drawable d = ContextCompat.GetDrawable(this, Resource.Drawable.thumb);
Canvas c = new Canvas();
Bitmap bitmap = Bitmap.CreateBitmap(d.IntrinsicWidth, d.IntrinsicHeight, Bitmap.Config.Argb8888);
c.SetBitmap(bitmap);
d.SetBounds(0, 0, d.IntrinsicWidth, d.IntrinsicHeight);
d.Draw(c);
//Bitmap bmp = bitmap.Copy(Bitmap.Config.Argb8888, true);
string text = Integer.ToString(progress) + "%";
Paint p = new Paint();
p.SetTypeface(Typeface.CreateFromAsset(Assets, "fonts/Brandon_bld.otf"));
p.TextSize = 18;
p.Color = Color.White;
int width = (int)p.MeasureText(text);
int yPos = (int)((c.Height / 2) - ((p.Descent() + p.Ascent()) / 2));
c.DrawText(text, (bitmap.Width - width) / 2, yPos, p);
progBar.SetThumb(new BitmapDrawable(Resources, bitmap));
using the canvas to create the bitmap worked
In the following code, I'm trying to draw an oval which be enlarged with time.
Bitmap currBitmap = null;
Canvas currCanvas = null;
//Config Paint Case2
final Paint currPaint = new Paint();
List BlocksList = null;
boolean bSet = false;
public void DrawOval(Bitmap src, int nRadiusprct)
{
// image size
int width = src.getWidth();
int height = src.getHeight();
//create bitmap output
if(currBitmap == null)
currBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
// set canvas for painting
if(currCanvas == null)
{
currCanvas = new Canvas(currBitmap);
currCanvas.drawARGB(0, 0, 0, 0);
MainActivity.imgMain.setImageBitmap(currBitmap);
}
// config paint Case1
/*final Paint currPaint = new Paint();
currPaint.setAntiAlias(true);
currPaint.setColor(Color.BLACK);*/
// config paint Case2
if(!bSet)
{
currPaint.setAntiAlias(true);
currPaint.setColor(Color.BLACK);
// create Xfer mode
currPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
bSet = true;
}
// config rectangle for embedding
int nMidWidth = width/2;
int nMidHeight = height/2;
float fPercent = (nRadiusprct / 100.0f);
float fLeft = nMidWidth * (1 - fPercent);
float fRight = nMidWidth * (1 + fPercent);
float fTop = nMidHeight * (1 - fPercent);
float fBottom = nMidHeight * (1 + fPercent);
final Rect rect = new Rect(0, 0, width, height);
final RectF rectF = new RectF(fLeft, fTop, fRight, fBottom);
currCanvas.drawOval(rectF, currPaint);
// create Xfer mode, Config Paint Case1
//currPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
currCanvas.drawBitmap(src, rect, rect, currPaint);
MainActivity.imgMain.invalidate();
}
Now, As you can see write a comment "Config Paint Case1" or "Config Paint Case2", case1 represents the case where I create a paint instance each time the method is called, while case 2 represents where I define a member object in the class so I can use it whenever I need, the problem that when I'm using the first case everything is working perfectly and accurate, while when I'm using the second case nothing happened, The main thing that in my opinion I don't need to create a paint object each time so I need to optimize my code more and more, but why this happened here.....
Finally I got an answer to this question, A great help by this article Transparency with JPEGs done right that describes how PorterDuff modes are work, In that article I found this Xfermodes Example which gives me where is the error and here is the description.
Actually, I don't need to create a paint object everytime, what I need is to deal with the xfermodes in a correct way, the perfect code is:
Bitmap currBitmap = null;
Canvas currCanvas = null;
//Config Paint Case2
final Paint currPaint = new Paint();
List BlocksList = null;
boolean bSet = false;
public void DrawOval(Bitmap src, int nRadiusprct)
{
// image size
int width = src.getWidth();
int height = src.getHeight();
//create bitmap output
if(currBitmap == null)
currBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
// set canvas for painting
if(currCanvas == null)
{
currCanvas = new Canvas(currBitmap);
MainActivity.imgMain.setImageBitmap(currBitmap);
}
// config paint Case2
if(!bSet)
{
currPaint.setAntiAlias(true);
currPaint.setColor(Color.BLACK);
bSet = true;
}
// config rectangle for embedding
int nMidWidth = width/2;
int nMidHeight = height/2;
float fPercent = (nRadiusprct / 100.0f);
float fLeft = nMidWidth * (1 - fPercent);
float fRight = nMidWidth * (1 + fPercent);
float fTop = nMidHeight * (1 - fPercent);
float fBottom = nMidHeight * (1 + fPercent);
final Rect rect = new Rect(0, 0, width, height);
final RectF rectF = new RectF(fLeft, fTop, fRight, fBottom);
Xfermode BeforEPaintXferMode = currPaint.getXfermode();
currCanvas.drawOval(rectF, currPaint);
// create Xfer mode
currPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
// draw source image to canvas
currCanvas.drawBitmap(src, rect, rect, currPaint);
currPaint.setXfermode(BeforEPaintXferMode);
MainActivity.imgMain.invalidate();
}
Now, as you can see I just storing the current xfermode before painting, then I set it to SRC_IN mode and finally, I go back to the original one. and everything is working perfectly.