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

问题描述 投票:0回答:5

这就是我在 Android 应用程序中在

Bitmap
上绘制
Canvas
的方式:

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

但是,

Bitmap
缩放不平滑,未执行抗锯齿。如何启用抗锯齿功能?

android android-canvas antialiasing
5个回答
81
投票

试试这个:

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

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

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

2
投票

您是否尝试过创建一个

Paint
对象,在其上调用
setAntiAlias(true)
并将其作为第四个参数传递给
drawBitmap
方法?如果这不起作用,我想你应该缩小
drawBitmap
调用而不是缩放画布,例如通过使用
drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint)


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

重新缩放.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 行

© www.soinside.com 2019 - 2024. All rights reserved.