位图绘制未开启抗锯齿功能

23

我有一个自定义的View,总是在固定的旋转角度下绘制一个Bitmap。 我重写了onDraw方法,旋转Canvas并使用抗锯齿Paint绘制位图。

public RotatedImageView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    someBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.placeholder);
}

@Override
protected void onDraw(Canvas canvas) {

    // Save and rotate canvas
    canvas.save();
    canvas.rotate(3F, getWidth() / 2, getHeight());

    // Draw the icon
    Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
    canvas.drawBitmap(someBitmap, 0, 0, p);
    canvas.drawRoundRect(new RectF(75, 50, 225, 200), 10, 10, p);

    // All done; restore canvas
    canvas.restore();
}

然而,我在位图上总是得到了锯齿状的边缘。请注意,圆角矩形的边缘得到了很好的反锯齿处理。此外,当我应用p.setFilterBitmap(true);时,这个方法可以正确地过滤/平滑位图表面。我错过了什么吗?

No anti-aliasing on the photo

这是一个最小化的Android项目,其中包含一个屏幕的被隔离的例子,演示了从资源中加载的未抗锯齿位图的绘制View:https://bitbucket.org/erickok/antialiastest

更新:我也尝试了以下操作:

    Paint p = new Paint();
    p.setAntiAlias(true);
    p.setFilterBitmap(true);
    p.setDither(true);
    canvas.drawBitmap(someBitmap, 0, 0, p);

但是这并没有帮助,因为setFilterBitmap只过滤表面;它不会抗锯齿边缘。而且,setAntiAlias与直接在Paint构造函数中设置标志相同。如果有疑问,请尝试我的最小测试项目。非常感谢您的任何帮助!

5个回答

22

使用 setFilterBitmap(true)。

paint_object.setFilterBitmap(true);

这对我也有效...我从这个问题中学到了它:

使用抗锯齿绘制旋转的位图

AntiAlias标志和FilterBitmap标志都设置为true,它们一起可以使位图边缘变得平滑。我已在三星Galaxy Ace上测试过,Android 2.2...

我的测试代码是:

Paint p = new Paint();
p.setAntiAlias(true);
p.setFilterBitmap(true);
canvas.drawBitmap(someBitmap, new Matrix(), p);

1
抱歉,不行。位图的过滤会平滑图像的内容表面,但不会反锯齿边缘。我已更新我的问题以反映这一点。 - Eric Kok
1
setFilterBitmap() 结合 setLayerType(View.LAYER_TYPE_SOFTWARE, null) 对我来说非常有效。仅使用软件层仍然存在一些伪影。 - Brian

19
我找到了为什么没有得到任何反锯齿的原因:硬件加速。在我(纯属偶然)测试我的Nexus One时,它突然工作了,而我的Nexus 7则没有。原来当使用硬件加速绘制Canvas时,ANTI_ALIAS_FLAG不起作用。有了这个见解,我发现了Romain Guy在StackOverflow上的答案,回答了我的问题。
解决方案似乎是:为每个位图添加透明边框(手动或即时生成),或者“对着色器进行处理”。这两种方法都不太吸引人。相反,我使用setLayerType方法禁用了自定义视图上的硬件加速。官方文档中关于Android硬件加速的说明。请注意,这是从API级别11开始提供的,但(不是偶然的)无论如何,在此之前您不必处理硬件加速。所以我在视图构造函数中添加了以下内容:
    if (android.os.Build.VERSION.SDK_INT >= 11) {
        setLayerType(View.LAYER_TYPE_SOFTWARE, null);
    }

对于那些感兴趣的人,我已经在BitBucket上更新了上述提到的开源项目。


5

在我的情况下,我这样做了,但也许你的情况不同:

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

只要尝试一下。

祝你好运!


谢谢回复。不幸的是,这与我所做的相同,因此对锯齿状边缘没有影响(或者说,没有效果)。 - Eric Kok

4

我测试了之前的建议,它们对我有效。也许问题在于您的位图?或者是您的设备?这里有一段创建内联位图的代码。请检查此示例是否适用于您。

public class BitmapRotateActivity extends Activity { 

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(new MyView(this));
  }
  class MyView extends View {

    Bitmap bitmap;
    public MyView(Context context) {
      super(context);

      bitmap = Bitmap.createBitmap(160, 160, Bitmap.Config.RGB_565);
      Paint p = new Paint();
      p.setColor(Color.RED);
      p.setStyle(Paint.Style.FILL);
      Canvas c = new Canvas(bitmap);
      c.drawRect(0, 0, bitmap.getWidth(), bitmap.getHeight(), p);
    }

    @Override
    protected void onDraw(Canvas canvas) {
      Paint pbg = new Paint();
      pbg.setStyle(Paint.Style.FILL);
      pbg.setColor(0xffe0e0ff);
      canvas.drawRect(0, 0, getWidth(), getHeight(), pbg);

      Paint p = new Paint();
      p.setAntiAlias(true);
      p.setFilterBitmap(true);

      canvas.save();
      canvas.rotate(3F, getWidth() / 2, getHeight() / 2);
      canvas.drawBitmap(bitmap, 30, 30, p);
      canvas.restore();
    }
  }
}

尽管你的回答并没有直接回答我的问题,但是“也许是你的设备?”这句话(以及我意外地在我的Nexus One上测试)让我找到了正确的方向,所以我会授予你赏金。感谢你(所有人)的时间! - Eric Kok

2

我遇到了同样的问题,尝试了所有解决方法。最终有效的方法是在AndroidManifest.xml文件中全局禁用硬件加速:

 <application
       android:hardwareAccelerated="false" 
  ...
 >

然后在加载图像位图时禁用inSampleSize,以便(我推测)图像以足够高的质量加载,避免任何锯齿,然后对于我的实际ImageView,使用上述建议:将图层类型设置为View.LAYER_TYPE_SOFTWARE,并使用一个带有滤镜位图设置为true(如上所述)和抗锯齿的绘画对象。


2
正如@eric-kok所说:仅禁用自定义视图就足够了...您可能不会减慢整个应用程序的速度。 - martyglaubitz

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