位图未绘制消除锯齿

时间:2013-01-17 11:57:06

标签: android android-canvas android-custom-view

我有一个自定义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();
}

但是,我总是在Bitmap上出现锯齿状边缘。请注意,roudned矩形可以很好地消除锯齿边缘。此外,当我应用p.setFilterBitmap(true);时,这可以正常工作(位图表面被过滤/平滑)。我错过了什么吗?

No anti-aliasing on the photo

这是一个最小的Android项目,其中一个屏幕的隔离示例显示了绘制从资源加载的非消除锯齿的Bitmap的视图: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 个答案:

答案 0 :(得分:20)

我发现为什么我没有得到任何抗锯齿:硬件加速。在我(通过纯粹的意外)在我的Nexus One上测试后它突然起作用,而我的Nexus 7没有。事实证明,ANTI_ALIAS_FLAG在使用硬件加速绘制Canvas时不执行任何操作。凭借这种洞察力,我发现Romain Guy's answer on StackOverflow回答了我的问题。

解决方案似乎是:为每个位图添加透明边框(手动或动态)或“使用着色器执行某些操作”。对我来说都没有吸引力。而是使用setLayerType方法在我的自定义视图上disabled hardware acceleration。请注意,这可以从API级别11开始,但(不是偶然)您不必在任何方式之前处理硬件加速。所以我在视图构造函数中添加了:

    if (android.os.Build.VERSION.SDK_INT >= 11) {
        setLayerType(View.LAYER_TYPE_SOFTWARE, null);
    }

我已经为BitBucket更新了上面提到的开源项目给那些感兴趣的人。

答案 1 :(得分:19)

使用setFilterBitmap(true)。

paint_object.setFilterBitmap(true);

它对我也有用.. 我从这个问题中得到了它

Drawing rotated bitmap with anti alias

AntiAlias 标志和 FilterBitmap 标志设置为true,它们一起使位图的边缘平滑,我已经在Samsung Galaxy Ace,android 2.2上测试了它...

我的测试代码是

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

答案 2 :(得分:6)

就我而言,我这样做了,但可能就像你做的那样:

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

试试吧。

祝你好运!

答案 3 :(得分:3)

我测试了以前的建议,他们确实为我工作。也许问题出在你的位图中?也许在你的设备?这是一个内联创建位图的代码。检查此示例是否适合您。

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

答案 4 :(得分:3)

我遇到了同样的问题,并尝试了所有这些修复程序。最终有效的是全局禁用AndroidManifest.xml文件中的硬件加速:

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

然后在我加载我的图像位图时禁用inSampleSize,这样(我认为)图像将以足够高的质量加载以避免任何曲折,然后,对于我的实际ImageView,使用上述建议:设置图层键入View.LAYER_TYPE_SOFTWARE,使用绘制对象,将滤镜位图设置为true(如上所述)并消除锯齿。