Android - How to draw stroke bitmap? - android

I have a bitmap like in the picture. I want to add a border for it using Canvas. Can anyone help me?

You can draw a border using Paint.STYLE.STROKE. You need to do two separate calls to draw.
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.parseColor("#BAB399")); // set fill color
canvas.drawCircle(sbmp.getWidth() / 2+0.7f, sbmp.getHeight() / 2+0.7f,
sbmp.getWidth() / 2+0.1f, paint);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(10); // set stroke width
paint.setColor(Color.parseColor("#ffffff")); // set stroke color
canvas.drawCircle(sbmp.getWidth() / 2+0.7f, sbmp.getHeight() / 2+0.7f,
sbmp.getWidth() / 2+0.1f, paint);

If the image has a transparent background (png file) and the stroke size is not too large, you can just draw the bitmap with a color overlay applied to it 4 times -- left, top, right and bottom.
final float stroke = 20F; //stroke size in pixels.
//Load target image as bitmap.
BitmapFactory.Options options = new BitmapFactory.Options();
options.inMutable = true;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.shap, options);
//A new, clear bitmap with same size.
Bitmap newBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(newBitmap);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
//Overlay target bitmap with black color.
PorterDuffColorFilter filter = new PorterDuffColorFilter(Color.BLACK, PorterDuff.Mode.SRC_IN);
paint.setColorFilter(filter);
//Draw target bitmap over new bitmap.
canvas.drawBitmap(bitmap, -stroke, 0F, paint); //left
canvas.drawBitmap(bitmap, 0F, -stroke, paint); //top
canvas.drawBitmap(bitmap, stroke, 0F, paint); //right
canvas.drawBitmap(bitmap, 0F, stroke, paint); //bottom
//Remove overlay.
paint.setColorFilter(null);
//Draw target bitmap.
canvas.drawBitmap(bitmap, 0F, 0F, paint);
//Load new bitmap into ImageView.
ImageView iv = findViewById(R.id.iv);
iv.setImageBitmap(newBitmap);

Related

How to add border to bitmap image content instead of its background by using Canvas?

The feature of a bitmap image is that it has a transparent background and usually has a rectangular shape, so when we try to add a border to the image, instead of its content inside there will be a border, its background will have a border. For example, I have a bitmap image of a dog and I want it to have a border but instead, a rectangular background will have a border. I'm using Canvas to draw a bitmap and am having this problem. Can anyone help me?
Block code to create photo
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(10); // set stroke width
mPaint.setColor(getResources().getColor(R.color.black)); // set stroke color
mPaint.setAntiAlias(true);
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icons8_bus_36_2);
tempBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas tempCanvas = new Canvas(tempBitmap);
Rect rect = new Rect(
10 / 2,
10 / 2,
tempCanvas.getWidth() - 10 / 2,
tempCanvas.getHeight() - 10 / 2);
tempCanvas.drawRect(rect,mPaint);
tempCanvas.drawBitmap(bitmap, 0, 0, mPaint);
On this part:
Rect rect = new Rect(
10 / 2,
10 / 2,
tempCanvas.getWidth() - 10 / 2,
tempCanvas.getHeight() - 10 / 2);
change to
Rect rect = new Rect(
10 / 2,
10 / 2,
(tempCanvas.getWidth() - 10) / 2,
(tempCanvas.getHeight() - 10) / 2);
Thats because 10 is divided by two first
Also, draw bitmap first before you draw rect
OR
you could draw with this:
Path clipPath = new Path();
RectF rect = new RectF(0, 0, this.getWidth(), this.getHeight());
clipPath.addRoundRect(rect, radius, radius, Path.Direction.CW);
canvas.clipPath(clipPath);

Circular ImageView background is actually square and not circular?

I have a question regarding a circular ImageView. When I try to set the background color of my ImageView, it actually ends up being a square and not a circle when in reality I would want the ImageView to be a simple circular ImageView with some text as the image. Here was my attempt.
ImageView imageView = postViewHolder.fourthCommenter;
Bitmap b=Bitmap.createBitmap(30, 30, Bitmap.Config.ARGB_8888);
BitmapShader shader = new BitmapShader(b, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
Paint paint = new Paint();
paint.setShader(shader);
paint.setAntiAlias(true);
Canvas c = new Canvas(b);
c.drawCircle(b.getWidth()/2, b.getHeight()/2, b.getWidth()/2, paint);
c.drawText("+10",30,30,paint);
imageView.setBackgroundColor(ContextCompat.getColor(context, R.color.material_color_grey_200));
imageView.setImageBitmap(b);
All I want is to have the image show a grey circular Imageview with the word "+10" in it. What shows up is a simple square Imageview with no text in it. I can't see what I am doing wrong.
Any help would be apprecaited.
Thanks!
EDIT: Here is an example of what I would want. I want to have an image that looks exactly like the +16 image shown on this photo:
All I want is to have the image show a grey circular Imageview
Try this code
Bitmap picture = BitmapFactory.decodeResource(getResources(), R.mipmap.add_image);
ImageView imageView = (ImageView) findViewById(R.id.imgProfilePicture);
imageView.setImageBitmap(getRoundedBitmap(picture));
public Bitmap getRoundedBitmap(Bitmap bitmap){
Bitmap circleBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
BitmapShader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
Paint paint = new Paint();
paint.setShader(shader);
paint.setAntiAlias(true);
Canvas c = new Canvas(circleBitmap);
c.drawCircle(bitmap.getWidth() / 2, bitmap.getHeight() / 2, bitmap.getWidth() / 2, paint);
return circleBitmap;
}
Your xml file
<de.hdodenhof.circleimageview.CircleImageView
android:id="#+id/imgProfilePicture"
android:layout_width="110dp"
android:layout_height="110dp"
android:layout_marginBottom="20dp"
app:civ_border_width="3dp"
app:civ_border_color="#color/light_gray" />
and add this in build.gradle
compile 'de.hdodenhof:circleimageview:2.1.0'
Cirular ImageView Done !
Not sure if it's the proper way to do it , but it should work for your case :
First use this to create the bitmap with the required circle shape :
public Bitmap getCircledBmp(Context mContext,Bitmap bmp){
Canvas canvas = new Canvas(bmp);
int color = ContextCompat.getColor(mContext, R.color.material_color_grey_200);
Paint paint = new Paint();
Rect rect = new Rect(0, 0, bmp.getWidth(), bmp.getHeight());
RectF rectFloat = new RectF(rect);
paint.setAntiAlias(true);
paint.setColor(color);
canvas.drawARGB(0, 0, 0, 0);
canvas.drawOval(rectFloat, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bmp, rect, rect, paint);
return bmp;
}
Then add the text that you want :
public Bitmap drawText(String text, Bitmap bmp, int textSize) {
//text dimensions
TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
textPaint.setTextSize(textSize);
textPaint.setColor(Color.BLACK);
textPaint.setTextAlign(Paint.Align.CENTER);
StaticLayout mTextLayout = new StaticLayout(text, textPaint,
bmp.getWidth(), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
Canvas canvas = new Canvas(bmp);
//draw text
canvas.save();
canvas.translate((canvas.getWidth() / 2), (canvas.getHeight() / 2) -
((mTextLayout.getHeight() / 2)));
mTextLayout.draw(canvas);
canvas.restore();
return bmp;
}
In the end you should get your desired image like this :
Bitmap bmp = Bitmap.createBitmap(100,100,Bitmap.Config.ARGB_8888); //change the values whatever you like
ImageView imageView = postViewHolder.fourthCommenter;
imageview.setImageBitmap(drawText("+10",getCircledBmp(this,bmp),30));

Transparency made from interstection

Pulling my hear out over this one. I have a background bitmap that I want to overlay another bitmap on top of that has transparent cutouts. I have no problem doing that if the cutout is a basic shape, but I need the cutout to be the intersection of two circles (sort of a leaf shape). I tried making a third bitmap to produce the a cutout template but I can't even get a clean representation of the cutout let alone get it to work as a cutout template.
Anyone know how to do something like this? Here is my (simplified) attempt:
#Override
public void draw(Canvas canvas) {
float w = canvas.getWidth();
float h = canvas.getHeight();
// just used to set some proportions
float off = 300f;
Paint paint = new Paint();
// make a background bitmap with a yellow to green gradient
Bitmap bitmapBkg = Bitmap.createBitmap((int) w, (int) h, Bitmap.Config.ARGB_8888);
Canvas canvasBkg = new Canvas(bitmapBkg);
paint.reset();
paint.setShader(new LinearGradient(0, h/2 - off, 0, h/2 + off, Color.YELLOW, Color.GREEN, Shader.TileMode.CLAMP));
canvasBkg.drawRect(new RectF(0, 0, w, h), paint);
// make an overlay bitmap with a red to magenta gradient which will have the cutouts
Bitmap bitmapOver = Bitmap.createBitmap((int) w, (int) h, Bitmap.Config.ARGB_8888);
Canvas canvasOver = new Canvas(bitmapOver);
paint.reset();
paint.setShader(new LinearGradient(0, h/2 - off, 0, h/2 + off, Color.RED, Color.MAGENTA, Shader.TileMode.CLAMP));
canvasOver.drawRect(new RectF(0, 0, w, h), paint);
// make a bitmap of intersecting circles to be used as the cutout shape
Bitmap bitmapCut = Bitmap.createBitmap((int) w, (int) h, Bitmap.Config.ARGB_8888);
Canvas canvasCut = new Canvas(bitmapCut);
paint.reset();
paint.setColor(Color.BLACK);
//paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR));
canvasCut.drawCircle(w / 2 - (off / 2 ), h / 2, off, paint);
paint.reset();
paint.setColor(Color.BLACK);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR));
canvasCut.drawCircle(w / 2 + (off / 2), h / 2, off, paint);
// apply cutout to overlay
paint.reset();
paint.setColor(Color.BLACK);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP));
canvasOver.drawBitmap(bitmapCut, 0, 0, paint);
// draw background and overlay onto main canvas
paint.reset();
paint.setColor(Color.BLACK);
canvas.drawBitmap(bitmapBkg, 0, 0, paint);
canvas.drawBitmap(bitmapOver, 0, 0, paint);
}
Here is an image of what I am getting:
What I am trying to get would have the outside portion also red-magenta; only the eye-shape in the middle should be yellow-green.
Turns out the trick was adding yet another layer.
// make a secondary overlay that cuts out the whole circles
Bitmap bitmapOver2 = Bitmap.createBitmap((int) w, (int) h, Bitmap.Config.ARGB_8888);
Canvas canvasOver2 = new Canvas(bitmapOver2);
paint.reset();
paint.setShader(new LinearGradient(0, h / 2 - off, 0, h / 2 + off, Color.RED, Color.MAGENTA, Shader.TileMode.CLAMP));
canvasOver2.drawRect(new RectF(0, 0, w, h), paint);
paint.reset();
paint.setColor(Color.BLACK);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvasOver2.drawCircle(w / 2 - (off / 2), h / 2, off, paint);
canvasOver2.drawCircle(w / 2 + (off / 2), h / 2, off, paint);
Applying it like so:
// draw background and overlay onto main canvas
paint.reset();
paint.setColor(Color.BLACK);
canvas.drawBitmap(bitmapBkg, 0, 0, paint);
canvas.drawBitmap(bitmapOver2, 0, 0, paint);
canvas.drawBitmap(bitmapOver, 0, 0, paint);
Basically it is a bit of a trick. It draws the mid-tier backdrop twice, once with a full circle cutouts and the other with the eye-shape cutout. The two fit together just right to pull off the desired effect.
Of course #Rotwang, you are probably right. Using Path and arcTo() would be a much better solution. The only reason I avoided that approach is b/c arcTo() is an api 21+ feature. So far I've manged to keep the api to 17+. But if anyone else would like to provide an arcTo() solution for completeness that would be cool to compare.

Crop images in circle shape with border around it

I want to have my image in circle shape and a stroke around it.
I use this code to crop my bitmap in circle, but i don't know how to put a border/stroke around it.
public static Bitmap getCroppedBitmap(Bitmap bitmap) {
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
bitmap.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final int color = 0xff424242;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
// canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
canvas.drawCircle(bitmap.getWidth() / 2, bitmap.getHeight() / 2,
bitmap.getWidth() / 2, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
//Bitmap _bmp = Bitmap.createScaledBitmap(output, 60, 60, false);
//return _bmp;
return output;
}
Paint paintStroke = new Paint(Paint.ANTI_ALIAS_FLAG); // create anti-aliased Paint
paintStroke.setStyle(Paint.Style.STROKE); // define paint style as Stroke
paintStroke.setStrokeWidth(1f); // set stroke widht to 1 px
paintStroke.setColor(0xFF00FF00); // set color
canvas.drawArc(rect, 0f, 360f, true, paintStroke); // draw arch from 0 to 360 degrees (i. e. closed circle)

Android - Cut a circle from a square Bitmap

I am trying to cut a circle from a square bitmap using following code
Canvas canvas=new Canvas(bitmapimg );
int circleXCoord = bitmapimg .getWidth() / 2;
int circleYCoord = bitmapimg .getHeight() / 2;
int circleRadius = bitmapimg .getWidth() / 2;
Rect rect = new Rect(circleXCoord - circleRadius, circleYCoord - circleRadius, circleXCoord + circleRadius, circleYCoord + circleRadius);
int width = rect.width();
int height = rect.height();
Paint paint = new Paint();
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.BLUE);
canvas.drawRect(rect, paint);
canvas.drawBitmap(bitmapimg , rect, rect, paint);
Path p = new Path();
p.addCircle(circleXCoord, circleYCoord, width / 2F, Path.Direction.CW);
canvas.clipPath(p, Region.Op.DIFFERENCE);
canvas.drawColor(0, PorterDuff.Mode.CLEAR);
The idea is to attach a square (rectangular) bitmap to canvas and then clip a circular path. Clear out the difference between the rectangle and circle (make it transparent).
The code works fine for Android 4, but on Android 2.3.3 device, the difference area is appearing black rather that transparent.
Am I missing something here or PorterDuff.Mode.CLEAR is not supported in gingerbread? Is there a better way to cut a circle from a square in Android?
Seems like PorterDuff.Mode.Clear did not work for gingerbread
Solved the problem (cut circle from square using this code)
public Bitmap BitmapCircularCroper(Bitmap bitmapimg){
Bitmap output = Bitmap.createBitmap(bitmapimg.getWidth(),
bitmapimg.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final int color = 0xff424242;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, bitmapimg.getWidth(),
bitmapimg.getHeight());
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawCircle(bitmapimg.getWidth() / 2,
bitmapimg.getHeight() / 2, bitmapimg.getWidth() / 2, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmapimg, rect, rect, paint);
return output;
}
import android.graphics.PorterDuff.Mode;
import android.graphics.Bitmap.Config;
public static Bitmap getCircularBitmap(Bitmap bitmap)
{
Bitmap output;
if (bitmap.getWidth() > bitmap.getHeight()) {
output = Bitmap.createBitmap(bitmap.getHeight(), bitmap.getHeight(), Config.ARGB_8888);
} else {
output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getWidth(), Config.ARGB_8888);
}
Canvas canvas = new Canvas(output);
final int color = 0xff424242;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
float r = 0;
if (bitmap.getWidth() > bitmap.getHeight()) {
r = bitmap.getHeight() / 2;
} else {
r = bitmap.getWidth() / 2;
}
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawCircle(r, r, r, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return output;
}
For anyone that's still looking at this, this answer will cause a few issues.
1.) The canvas that you are creating in this instance will not have hardware acceleration. Even though your Paint object has anti-aliasing, the canvas will not. This will cause artifacting when you decide to paint this back to your original canvas in your onDraw() call.
2.) This takes a lot more resources. You have to create a second Bitmap (which can cause OOM), and a secondary Canvas as well as all of the different alterations you have to do.
Please check out Romain Guy's answer. You create a BitmapShader and then create a RoundRect that gives you a Circle. You just need to know the dimensions of your RectF so that it can determine the circle properly.
This means that if you know the center point (x, y) and radius, you can easily determine the RectF.
left = x - radius;
top = y - radius;
right = x + radius;
bottom = y + radius;
This also means that with this solution posted below you only have to draw to the screen once, everything else is done in the off-screen buffer.
http://www.curious-creature.com/2012/12/11/android-recipe-1-image-with-rounded-corners/
The best solution is found here:
BitmapShader shader;
shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setShader(shader);
RectF rect = new RectF(0.0f, 0.0f, width, height);
// rect contains the bounds of the shape
// radius is the radius in pixels of the rounded corners
// paint contains the shader that will texture the shape
canvas.drawRoundRect(rect, radius, radius, paint);

Categories

Resources