Draw smoothly scaled bitmaps on Canvas
Asked Answered
R

5

33

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?

Rooke answered 27/11, 2010 at 21:48 Comment(1)
Just a note. If you want simply a square result, whether you need to scale up or down, use this incredibly handy tip ... https://mcmap.net/q/50270/-android-crop-center-of-bitmap Hope it helps someoneShipper
P
81

Try this:

Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);

canvas.drawBitmap(bitmap, x, y, paint);
Patrinapatriot answered 27/11, 2010 at 22:12 Comment(4)
Thanks, it worked, I just used Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG);Rooke
I'm not having any joy with this. Are you scaling your images up or down?Multiplication
I just thought I'd chime in that adding setFilterBitmap(true) and setDither(true) IN ADDITION to setAntiAlias(true) makes a heck of difference on Wear devices.Dimond
Works Fine! Thanks!Golda
W
19

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;
}
Weighting answered 22/1, 2012 at 3:16 Comment(1)
createScaledBitmap is the only solution that produced a smooth edge for me. Thank you!Turnage
S
2

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).

Shushan answered 27/11, 2010 at 22:9 Comment(0)
H
0

Row and column skipping is available in API 33. Shared source codes didn't work correct. Smooth rescaling is not a practial algorithm for dynamic game graphics. This algorithm is useful with pre-defined graphics. If there is a finder, share it please.


Edit: Mosaic rescale algorithm is here for Bitmap objects:

UnpackedColor.java

import java.util.Random;
import android.graphics.Color;
import java.lang.Math;
public class UnpackedColor {
 public float A, R, G, B;
 public UnpackedColor(
  float A,
  float R,
  float G,
  float B
  ) {
  this.A = A;
  this.R = R;
  this.G = G;
  this.B = B;
  }
 public UnpackedColor(int packedColor) {
  A = Color.alpha(packedColor) / 255f;
  R = Color.red(packedColor) / 255f;
  G = Color.green(packedColor) / 255f;
  B = Color.blue(packedColor) / 255f;
  }
 public void sum(UnpackedColor ref) {
  if (ref == null) return;
  A += ref.A;
  R += ref.R;
  G += ref.G;
  B += ref.B;
  }
 public void div(float divider) {
  A /= divider;
  R /= divider;
  G /= divider;
  B /= divider;
  }
 public void pow(float value) {
  A *= value;
  R *= value;
  G *= value;
  B *= value;
  }
 public int pack() {
  int Ar = Math.round(255 * A);
  int Rr = Math.round(255 * R);
  int Gr = Math.round(255 * G);
  int Br = Math.round(255 * B);
  if (Ar > 255) Ar = 255;
  else if (Ar < 0) Ar = 0;
  if (Rr > 255) Rr = 255;
  else if (Rr < 0) Rr = 0;
  if (Gr > 255) Gr = 255;
  else if (Gr < 0) Gr = 0;
  if (Br > 255) Br = 255;
  else if (Br < 0) Br = 0;
  return Color.argb(Ar, Rr, Gr, Br);
  }
 }

Rescale.java

import android.graphics.Bitmap;
import java.lang.Math;
public class Rescale {
 public static Bitmap filterBitmap(Bitmap refBitmap, float ratio) {
  int newWidth = Math.round(refBitmap.getWidth() * ratio);
  int newHeight = Math.round(refBitmap.getHeight() * ratio);
  if (newWidth <= 0) {
   newWidth = 1;
   }
  if (newHeight <= 0) {
   newHeight = 1;
   }
  return Rescale.filterBitmap(refBitmap, newWidth, newHeight);
  }
 public static Bitmap filterBitmap(Bitmap refBitmap, float widthRatio, float heightRatio) {
  int newWidth = Math.round(refBitmap.getWidth() * widthRatio);
  int newHeight = Math.round(refBitmap.getHeight() * heightRatio);
  if (newWidth <= 0) {
   newWidth = 1;
   }
  if (newHeight <= 0) {
   newHeight = 1;
   }
  return Rescale.filterBitmap(refBitmap, newWidth, newHeight);
  }
 public static Bitmap filterBitmap(Bitmap refBitmap, int newWidth, int newHeight) {
  int width = refBitmap.getWidth();
  int height = refBitmap.getHeight();
  Bitmap ret = Bitmap.createBitmap(
   newWidth,
   newHeight,
   Bitmap.Config.ARGB_8888
   );
  int gridXPointer = 0;
  float gridXPointerF = 0.0f;
  float gridXPointerF2 = 0.0f;
  float gridYPointerF = 0.0f;
  float gridYPointerF2 = 0.0f;
  UnpackedColor loopTmpColor = null;
  UnpackedColor unpackedRetPixel = null;
  float retWeight = 0.0f;
  float tmpYWeight = 0.0f;
  float tmpWeight = 0.0f;
  float refXF = 0.0f;
  float refYF = 0.0f;
  float loopF = 0.0f;
  float loop2F = 0.0f;
  float loopFMod = 0.0f;
  float loop2FMod = 0.0f;
  int refXFInt = 0;
  int refYFInt = 0;
  float refXFMod = 0.0f;
  float refYFMod = 0.0f;
  float refXFFirstMod = 0.0f;
  float loopFInt = 0.0f;
  float loop2FInt = 0.0f;
  for (int gridYPointer = 0; gridYPointer < newHeight; gridYPointer++) {
   gridYPointerF = (gridYPointer * (float)height) / (float)newHeight;
   gridYPointerF2 = ((gridYPointer + 1) * (float)height) / (float)newHeight;
   gridXPointer = 0;
   for (; gridXPointer < newWidth; gridXPointer++) {
    unpackedRetPixel = new UnpackedColor(
     0.0f,
     0.0f,
     0.0f,
     0.0f
     );
    gridXPointerF = (gridXPointer * (float)width) / (float)newWidth;
    gridXPointerF2 = ((gridXPointer + 1) * (float)width) / (float)newWidth;
    retWeight = 0.0f;
    refYF = gridYPointerF;
    refYFMod = refYF % 1.0f;
    loopF = gridYPointerF2;
    loop2F = gridXPointerF2;
    loopFMod = loopF % 1.0f;
    loop2FMod = loop2F % 1.0f;
    loopFInt = (int)loopF;
    loop2FInt = (int)loop2F;
    retWeight = 0;
    for (; refYF < loopF; refYF += 1.0f) {
     refYFInt = (int)refYF;
     if (refYFInt == loopFInt) {
      tmpYWeight = loopFMod - refYFMod;
      }
     else if (refYFMod > 0.0f) {
      tmpYWeight = 1.0f - refYFMod;
      }
     else {
      tmpYWeight = 1.0f;
      }
     refXF = gridXPointerF;
     refXFMod = refXFFirstMod;
     for (; refXF < loop2F; refXF += 1.0f) {
      refXFInt = (int)refXF;
      loopTmpColor = new UnpackedColor(
       refBitmap.getPixel(
        refXFInt,
        refYFInt
        )
       );
      tmpWeight = tmpYWeight;
      if (refXFInt == loop2FInt) {
       tmpWeight *= loop2FMod - refXFMod;
       }
      else if (refXFMod > 0.0f) {
       tmpWeight *= 1.0f - refXFMod;
       }
      else {
       tmpWeight *= 1.0f;
       }
      loopTmpColor.pow(tmpWeight);
      unpackedRetPixel.sum(loopTmpColor);
      retWeight += tmpWeight;
      if (refXFMod > 0.0f) {
       refXF = refXFInt;
       refXFMod = 0.0f;
       }
      }
     if (refYFMod > 0.0f) {
      refYF = refYFInt;
      refYFMod = 0.0f;
      }
     }
    unpackedRetPixel.div(retWeight);
    ret.setPixel(
     gridXPointer,
     gridYPointer,
     unpackedRetPixel.pack()
     );
    }
   }
  return ret;
  }
 }

Using the filter:

Bitmap b = ((BitmapDrawable)getResources().getDrawable(R.mipmap.icon)).getBitmap();
b = Rescale.filterBitmap(b, 0.75f);
//Or
b = Rescale.filterBitmap(b, 0.75f, 1.25f);
//Or
b = Rescale.filterBitmap(b, 250, 500);
Hadrian answered 3/8, 2023 at 12:52 Comment(0)
C
-1

You need only one Line of Code:

canvas.drawBitmap(bitmap, x, y, new Paint(Paint.ANTI_ALIAS_FLAG)); 

Not 5 Lines

Chagall answered 10/10, 2014 at 2:8 Comment(5)
Please don't just add code, provide some explanation also.Hodgkin
@Rohan: The question was: "Draw smoothly scaled bitmaps on Canvas" then you could use e.g. canvas.drawBitmap(source, 0, 0, new Paint(Paint.ANTI_ALIAS_FLAG)); for this. Did you understand now?Chagall
@Rohan: on the other side: Why should I provide here redudant code? Please read the other Answeres before.Chagall
you are taking me wrongly. I just want you to add a bit of explanation, it will help a lot of newbies, like -- use the Paint.ANTI_ALIAS_FLAG flag, this flag is used for removing the jagged edges and smooth the edges. Something like this. (Then you add the code too)Hodgkin
If you don't understand this code, you have to train. But this is no argument to downvoteChagall

© 2022 - 2024 — McMap. All rights reserved.