Draw smoothly scaled bitmaps on Canvas - android

This is how I draw Bitmap on Canvas in my Android app:
canvas.save();
canvas.scale(scale, scale, x, y);
canvas.drawBitmap(bitmap, x, y, null);
canvas.restore();
However the Bitmap is not scaled smoothly, no anti-aliasing is performed. How can I enable anti-aliasing?

Try this:
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);
canvas.drawBitmap(bitmap, x, y, paint);

Both Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG); or paint.setFilterBitmap(true); worked for me but be very careful, on my game it cut down the FPS from 30FPS to 17FPS only. So if it is a mission critical drawing like in a game you better scale the image at loading time. Which I did in the following manner:
public Bitmap getImage (int id, int width, int height) {
Bitmap bmp = BitmapFactory.decodeResource( getResources(), id );
Bitmap img = Bitmap.createScaledBitmap( bmp, width, height, true );
bmp.recycle();
return img;
}

Have you tried creating a Paint object, calling setAntiAlias(true) on it and passing it to the drawBitmap method as the 4th parameter? If this does not work I guess you should scale down the drawBitmap call instead of scaling the Canvas, e.g. by using drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint).

You need only one Line of Code:
canvas.drawBitmap(bitmap, x, y, new Paint(Paint.ANTI_ALIAS_FLAG));
Not 5 Lines

Related

How to resize bitmap when drawing in canvas?

In my android app, I have this function that creates a new bitmap from an old one via canvas.
private static Bitmap convert(Bitmap bitmap, Bitmap.Config config, int width, int height) {
Bitmap convertedBitmap = Bitmap.createBitmap(width, height, config);
Canvas canvas = new Canvas(convertedBitmap);
Paint paint = new Paint();
paint.setColor(Color.BLACK);
canvas.drawBitmap(bitmap, 0, 0, paint);
bitmap.recycle();
return convertedBitmap;
}
The problem is when I draw the old bitmap onto the canvas, since the old bitmap is bigger in dimensions than the canvas, only the top left part of the bitmap gets drawn on the canvas. Is there a way I can make it so when it draws the bitmap on the canvas, it scales the bitmap so it fits perfectly in the canvas?
I don't want to resize the bitmap using createScaledBitmap. Is there a faster way?
OR Can I do createScaledBitmap but make it mutable at the same time? That is what I am trying to do overall, resize and make mutable at same time.
Thanks
You can call public void drawBitmap (Bitmap bitmap, Rect src, RectF dst, Paint paint) for this function (Android Doc). The code below should accomplish what you are trying to do:
canvas.drawBitmap(bitmap, null, new RectF(0, 0, canvasWidth, canvasHeight), null);

Specify Bitmap offset?

How do I specify an offset for the bitmap that will gave me the circle in another x, y position on the canvas?
Bitmap bitmap = Bitmap.createBitmap(size, size, Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
Rect rect = new Rect(120, 120, 150, 0);
canvas.drawCircle(size/2, size/2, size/2, paint);
canvas.drawBitmap(bitmap, rect, rect, paint);
For the Bitmap:
The second rect will be where the bitmap is drawn on the canvas.
Otherwise if you are drawing the entire bitmap you could use canvas.drawBitmap(bitmap, x, y, paint) Where x is a float specifying the left side position of the bitmap and y is a float specifying the top side position of the bitmap.
See Canvas.drawBitmap
As far as the drawCircle() goes. The first two parameters would be floats for the x and y position of the circle respectively.
See Canvas.drawCircle

Android : Constructing bitmap from RECT

Can we construct a bitmap from a rect.
I draw a bitmap in a rect and want strokes drawn on the bitmap image become part of the image.
I am wondering if I can construct a bitmap from a Rect so the new bitmap has the old image and the strokes as a single image.
Thank You
You can always take a canvas to help you create an already decoded bitmap the way you want:
Bitmap originalBmp = null;//Here goes original Bitmap...
ImageView img = null;//Any imageview holder you are using...
Bitmap modifiedBmp = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);//Configure with your proper size and color
Canvas canvas = new Canvas(modifiedBmp);
//At this point the modified bitmap has the original one, starting from here, you can add any overlay you want...
canvas.drawBitmap(originalBmp, 0, 0, new Paint());
//And do all the other modifications you want here...
canvas.drawLines(new float[]{}, null);
canvas.drawCircle(x, y, radius, null);
//At this point the modified bitmap will have anything you added
img.setImageBitmap(modifiedBmp);
// IF YOU ARE OVERRIDING ONDRAW METHOD
public void onDraw(Canvas canvas){
//Here DO your DRAW BITMAP NOTE: paint must be already created...
canvas.drawBitmap(bt, 0, 0, paint);
paint.setColor(Color.BLACK);
paint.setStrokeWidth(3);
canvas.drawRect(30, 30, 80, 80, paint);
super.onDraw(canvas);
}
Regards!
Yes you can , Using canvas you can draw something on your old bimtap .
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);
// do some canvas drawing
canvas.drawBitmap(bitmap, rect, rect, paint);

Efficiency when drawing an ImageView with rounded corners

I have an ImageView subclass that I use to draw images with rounded corners. The code is based on this answer, and is as follows:
public class ImageViewRoundedCorners extends ImageView {
...
#Override
protected void onDraw(Canvas canvas) {
Bitmap scaledBitmap = Bitmap.createBitmap(getMeasuredWidth(),
getMeasuredHeight(),
Bitmap.Config.ARGB_8888);
Canvas scaledCanvas = new Canvas(scaledBitmap);
super.onDraw(scaledCanvas);
drawRoundedCornerBitmap(canvas, scaledBitmap,
getMeasuredWidth(), getMeasuredHeight());
scaledBitmap.recycle();
}
protected void drawRoundedCornerBitmap(Canvas outputCanvas, Bitmap input, int w, int h) {
Bitmap output = Bitmap.createBitmap(w, h, Config.ARGB_8888);
Canvas canvas = new Canvas(output);
mPaint.reset();
mPaint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
mPaint.setStyle(Paint.Style.FILL);
canvas.drawPath(mClipPath, mPaint);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(input, 0, 0, mPaint);
outputCanvas.drawBitmap(output, 0, 0, null);
}
}
With this code, the image is drawn with properly rounded corners. To avoid the allocations on the first two lines of drawRoundedCornerBitmap, I want to draw directly to outputCanvas, which is the canvas originally passed to onDraw. The new implementation looks like this:
protected void drawRoundedCornerBitmap(...) {
mPaint.reset();
mPaint.setAntiAlias(true);
outputCanvas.drawARGB(0, 0, 0, 0);
mPaint.setStyle(Paint.Style.FILL);
outputCanvas.drawPath(mClipPath, mPaint);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
outputCanvas.drawBitmap(input, 0, 0, mPaint);
}
For some reason, this code seems to ignore the Porter-Duff mode, and instead just draws the image with normal (non-rounded) corners. Why is this the case? What is it about drawing to an intermediate Bitmap that makes the original code work?
Create a drawable Romain Guy has done this for you. We are not a link factory but his blog post explains it quite extensively and provides an efficient way of doing this. Rounded Corners
The real basic principle, is create a BitmapShader and attach it to a Paint object which draws in a custom Drawable that way you just apply that Drawable to the ImageView.
Using a drawable means that the Image is only painted to a canvas once, meaning that drawing the image is only done once, then all the ImageView does is just scale the drawable.

Android & cut (remove) shape from bitmap

How do you cut (remove) a section from a bitmap???
I want that section/shape to be removed.. leave transparent in place of section..
Say shape is cercle or square..
You should be able do this with a Porter-Duff color filter and a Canvas:
public void punchHole(Bitmap bitmap, float cx, float cy, float radius) {
Canvas c = new Canvas(bitmap);
Paint paint = new Paint();
paint.setColorFilter(new PorderDuffColorFilter(0, PorderDuff.Mode.CLEAR));
c.drawCircle(cx, cy, radius, paint);
}
Well, that was wrong. However, using a Porter-Duff transfer mode does work:
public void punchHole(Bitmap bitmap, float cx, float cy, float radius) {
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvas.drawCircle(cx, cy, radius, paint);
}
(The bitmap passed as an arg needs to be modifiable, of course.)
Use Bitmap.setPixel(x,y,Color) function to set the desired pixels to transparent
for example:
Bitmap bmp = ...;
bmp.setPixel (100,100,Color.TRANSPARENT);
for the pixel at x/y offset 100,100. Though you'll find this potentially slow to do this on many pixels...
Did you try drawing a circle with a transparent color,
ARGB = 0,0,0,0 ?

Categories

Resources