【问题标题】:Canvas antialiasing with hardware acceleration (Android API 11 and Later)带硬件加速的画布抗锯齿(Android API 11 及更高版本)
【发布时间】:2012-03-16 00:33:53
【问题描述】:

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

我遇到的问题是,使用硬件加速时,边缘在旋转时没有消除锯齿(这在关闭硬件加速的情况下完美工作)。 当然,像“setDrawFilter”这样的东西是没用的,因为当硬件加速打开时它们会被忽略!

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

是我遗漏了什么还是只是硬件渲染方法的限制?有没有其他选择?

【问题讨论】:

    标签: android android-3.0-honeycomb


    【解决方案1】:

    在油漆上设置抗锯齿标志无论如何也无济于事。要在旋转位图时获得抗锯齿边框,您应该在它们周围添加一个 1px 的透明边框。

    【讨论】:

    • 我确实设法通过这种偷偷摸摸的解决方法获得抗锯齿效果。然而,这个从过滤中获得抗锯齿效果的技巧增加了一些复杂性,并且无论何时使用缩放/严重缩放的位图源,或者使用一些“xfermode”,例如“clear”,都会给你带来一些令人讨厌的伪影。无论如何,非常感谢 Romain 的回答以及您为 Android 社​​区付出的时间。
    • 我想了一会儿,当位图上传到 OpenGL 纹理时,自动烘焙一个空边框,这样你就可以自动获得边框抗锯齿,但这确实会导致一些有趣的问题。另一种解决方案是在着色器中以某种方式进行。
    • 供参考:我通过在自定义视图上禁用硬件加速解决了这个问题。见stackoverflow.com/questions/14378573/…
    • 有类似的问题,但使用 9patch,不幸的是,我无法在 NinePatchDrawable 上添加 1px 边框:(
    • 7 年过去了,我仍然遇到这个问题,我仍然使用这个 hack 来修复它......
    【解决方案2】:

    添加这个 1px 透明边框并不像我想象的那么容易。在运行时添加它真的很麻烦。我的应用程序加载了很多位图,为了添加这个边框,我需要分配更多的位图来重绘它们。这确实破坏了堆,但是当我小心避免任何内存泄漏时,它按预期工作。真正让我丧命的是它引入的“滞后”。我追踪到了 GC 丢失的这种流动性。当他收回回收的位图时,最后一个似乎正在减慢 UI 线程。 使用缓存也不是解决方案。这是提高性能的最佳方式,但存储 500x500 PNG(需要 alpha)是不成比例的。 所以,我在这里,撞墙。我还没有尝试过“绘制时间”方式,但我的猜测是绘制到我认为不会是 HW acc 的屏幕外位图缓冲区。 (如果我错了,请纠正我)对我的事业没有帮助。

    拥有“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 个位图着色器……所以,我又来了。如何获得这个面具着色器!该死的墙;)

    【讨论】:

      【解决方案3】:

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

      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 作为背景,因此我无法在不影响 9-patch 像素的情况下添加透明的 1px 边框。因此,相反,我可以通过禁用给定视图及其父视图的硬件加速来实现此功能:

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

      <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"/>
      

      【讨论】:

        猜你喜欢
        • 2011-08-27
        • 1970-01-01
        • 2013-03-26
        • 2016-04-24
        • 1970-01-01
        • 2011-05-14
        • 1970-01-01
        • 1970-01-01
        • 2023-03-29
        相关资源
        最近更新 更多