在画布上平滑缩放地绘制位图。

33

这是我在我的Android应用程序中如何在Canvas上绘制Bitmap的方法:

canvas.save();
canvas.scale(scale, scale, x, y);
canvas.drawBitmap(bitmap, x, y, null);
canvas.restore();

然而Bitmap没有平滑缩放,也没有执行反锯齿处理。我该如何启用反锯齿?


1
只是一条提示。如果您想要简单地得到一个正方形的结果,无论您需要缩放还是放大,请使用这个非常方便的技巧... stackoverflow.com/a/17733530/294884 希望能帮助到某些人。 - Fattie
5个回答

81

试试这个:

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

canvas.drawBitmap(bitmap, x, y, paint);

17
谢谢,它起作用了,我只是使用了 Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG); - fhucho
4
我无法翻译这段文字,因为它已经是英文。请提供需要翻译的中文内容。 - teedyay
我觉得我可以插一句,除了使用setAntiAlias(true)之外,添加setFilterBitmap(true)和setDither(true)对于Wear设备来说会有很大的改善。 - John Smith
运行正常!谢谢! - Viktor Apoyan

19

Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG);paint.setFilterBitmap(true);都能够使用,但是要非常小心。在我的游戏中使用这些方法将FPS从30FPS降至17FPS。因此,如果要在游戏等关键绘制中使用,则最好在加载时对图像进行缩放。我是以以下方式实现的:

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;
}

createScaledBitmap是为我产生了平滑边缘的唯一解决方案。谢谢! - Bitcoin Cash - ADA enthusiast

2

0
API 33中提供了行和列跳过功能。共享的源代码无法正常工作。平滑缩放不适用于动态游戏图形的实际算法。这个算法在预定义图形中很有用。如果有找到者,请分享一下。

编辑:马赛克重新缩放算法适用于Bitmap对象:

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;
  }
 }

使用过滤器:

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

-1

你只需要一行代码:

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

不是5行


请不要只添加代码,也要提供一些解释。 - Rohan Kandwal
@Rohan:问题是:“在画布上平滑缩放位图”,那么你可以使用canvas.drawBitmap(source, 0, 0, new Paint(Paint.ANTI_ALIAS_FLAG)); 来实现。现在你明白了吗? - Ingo
@Rohan:另一方面,为什么我要在这里提供冗余代码?请先阅读其他答案。 - Ingo
6
你误解了我的意思。我只是想让你添加一点解释,这会对像新手这样的人有很大帮助,比如使用“Paint.ANTI_ALIAS_FLAG”标志,该标志用于消除锯齿和平滑边缘。类似这样的内容。(然后你需要添加代码) - Rohan Kandwal
如果你不理解这段代码,那么你需要进行训练。但这并不是将其踩到地板的理由。 - Ingo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接