硬件加速下的画布抗锯齿(Android API 11及以上版本)

6

我有一个简单的位图,在画布内绘制并使用矩阵旋转。

问题在于,当使用硬件加速时,旋转后的边缘没有反锯齿效果(关闭硬件加速时可以完美工作)。

当然,像“setDrawFilter”之类的东西在打开硬件加速时被忽略了!

canvas.setDrawFilter(new PaintFlagsDrawFilter(1, Paint.ANTI_ALIAS_FLAG));

我是否遗漏了什么或只是硬件渲染方法的限制?是否有其他选择?
3个回答

9

在绘制中设置抗锯齿标志也无济于事。要在旋转位图时获得抗锯齿边框,您应该在其周围添加一个1像素的透明边框。


1
我确实通过这个巧妙的解决方法成功地获得了抗锯齿效果。然而,使用这种过滤方式来获得抗锯齿效果会增加一些复杂性,并且在使用缩放/缩放不良的位图源或使用某些“xfermode”(例如“clear”)时会产生一些令人讨厌的伪影。 无论如何,非常感谢Romain为Android社区提供答案并投入时间。 - VeV
我思考了一段时间,关于在上传到OpenGL纹理时自动烘焙空边框,以便自动获得边框抗锯齿效果,但这确实可能会导致一些有趣的问题。另一个解决方案是在着色器中以某种方式处理它。 - Romain Guy
供参考:我通过在自定义视图上禁用硬件加速来解决了这个问题。请参见https://dev59.com/mWYq5IYBdhLWcg3wkRYo#14459129。 - Eric Kok
我遇到了类似的问题,但是在NinePatchDrawable上不幸的是,我无法添加1像素的边框 :( - gMale
1
七年过去了,我仍然遇到这个问题,而我仍然使用这个hack来解决它... - Oknesif

0
添加这个1像素透明边框并不像我想象的那么容易。在运行时添加它真的很混乱。我的应用程序加载了很多位图,为了添加这个边框,我需要分配更多的位图来重新绘制它们。这真的会使堆栈溢出,但是由于我非常注意避免任何内存泄漏,所以它按预期工作。真正困扰我的是这引入的“卡顿”。我追踪到这种流畅性的丢失是由于垃圾回收造成的。最后一个似乎在回收位图时减慢了UI线程的速度。 使用缓存也不是解决方案。这是性能的最佳方式,但存储500x500的PNG(alpha强制)是过于夸张的。 所以,我碰到了瓶颈。我还没有尝试过“绘制时间”的方法,但我猜测绘制到一个屏幕外的位图缓冲区,我认为不会是硬件加速的。(如果我错了,请纠正我)这对我的事业没有帮助。
拥有一个“AA着色器”的想法确实很诱人,我在这里看到了几个优点。它得到了硬件加速的很好支持,当然对于内存来说将是一大神器(不再需要野蛮位图分配),并且可以完全独立于位图缩放。 我进行了快速测试,这绝对是我曾经获得的最佳AA(我指的是质量)......而且速度很快......这个快速摘要使用了着色器来进行AA处理。
        BitmapShader bitmapShader = new BitmapShader(mBitmap,
                TileMode.CLAMP, TileMode.CLAMP);
        Matrix m = new Matrix(); 
        m.postTranslate(0, 1); 
        bitmapShader.setLocalMatrix(m); 

        final LinearGradient AAshader = new LinearGradient(0, 0, 0, 1, 0x00000000, 0xffffffff, TileMode.CLAMP);

        ComposeShader compositor = new ComposeShader(bitmapShader,
                AAshader, PorterDuff.Mode.DST_IN);

        mPaint.setShader(compositor);
        canvas.drawRect(this.getBounds(), mPaint);

现在的大问题是!如何获得4边AA :) ??? 我们可能可以使用多步渐变来管理上/下边缘AA,但这仍然很糟糕。一个好的方法是将源位图与某种9-patch组合以获取透明边框,但我们不能组合2个bitmapShader… 所以,我又来了。如何获得这个掩码着色器!该死的墙壁 ;)


-1

在我的情况下有效的修复方法:

private void fixAntiAlias(View viewFromThe80s) {
    if (Build.VERSION.SDK_INT > 10) {
        Paint p = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG | Paint.FILTER_BITMAP_FLAG);
        viewFromThe80s.setLayerType(View.LAYER_TYPE_SOFTWARE, p);
        ((View) viewFromThe80s.getParent()).setLayerType(View.LAYER_TYPE_SOFTWARE, p);
    }
}

细节:

我的TextView使用了9-patch作为背景,因此我无法添加透明的1像素边框而不影响9-patch像素。所以,相反地,我通过禁用给定视图及其父级的硬件加速来使其正常工作:

我在视图膨胀后立即调用此函数。具体来说,在我的情况下是在onCreateViewHolder中(确切地说是在viewholder构造函数中)。这修复了我的旋转TextView,它使用类似以下内容的NinePatchDrawable背景:

<TextView
    android:id="@+id/text_new_feature"
    android:layout_height="wrap_content"
    android:layout_width="wrap_content"
    android:rotation="-30"
    android:background="@drawable/background_new_feature"/>

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