栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

❤️Android 12 高斯模糊-RenderEffect❤️

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

❤️Android 12 高斯模糊-RenderEffect❤️

 Android 12 高斯模糊

        新功能:更易用的模糊、彩色滤镜等特效 。

        新的 API 让你能更轻松地将常见图形效果应用到视图和渲染结构上。

  • 使用 RenderEffect 将模糊、色彩滤镜等效果应用于 RenderNode 或 View。

  • 使用新的 Window.setBackgroundBlurRadius() API 为窗口背景创建雾面玻璃效果,

  • 使用 blurBehindRadius 来模糊窗口后面的所有内容。

        咱们一个一个玩。

 RenderEffect  实现效果
    private void setBlur(){
        View.setRenderEffect(RenderEffect.createBlurEffect(3, 3, Shader.TileMode.REPEAT));
        ...
    }

        使用特别简单,走你。

 X 轴的模糊效果图

咱再看看代码

    private void setBlur(){
        agb.iv1.setRenderEffect(RenderEffect.createBlurEffect(3, 0, Shader.TileMode.CLAMP));
        agb.iv2.setRenderEffect(RenderEffect.createBlurEffect(8, 0, Shader.TileMode.REPEAT));
        agb.iv3.setRenderEffect(RenderEffect.createBlurEffect(18, 0 ,Shader.TileMode.MIRROR));
        agb.iv4.setRenderEffect(RenderEffect.createBlurEffect(36, 0,Shader.TileMode.DECAL));
    }

RenderEffect.createBlurEffect()的四个参数:

  • radiusX 沿 X 轴的模糊半径

  • radiusY 沿 Y 轴的模糊半径

  • inputEffect 模糊一次(传入 RenderEffect)

  • edgeTreatment 用于如何模糊模糊内核边缘附近的内容

        下面两种仅看效果图。就不做代码设置了。

 Y 轴的模糊效果图

  XY同时模糊效果图

        第四个参数对边缘模糊,效果图如下:

        Shader.TileMode 提供了四个选项恕我没看出来。。

        这里还有一堆方法等你玩。

注意:注意如此完美的画面只能在 Android 12(SDK31)及以上的设备上使用,其他版本的设备使用会导致崩溃,谨记谨记。 效果有了,下面咱们一起看看源码。

 源码  View.setRenderEffect()
    public void setRenderEffect(@Nullable RenderEffect renderEffect) {
        ...
    }

        这个方法就是:renderEffect 应用于 View。 传入 null清除之前配置的RenderEffect 。这里咱们先看传入的 RenderEffect。

 RenderEffect.createBlurEffect()
    public static RenderEffect createBlurEffect(
            float radiusX,
            float radiusY,
            @NonNull RenderEffect inputEffect,
            @NonNull TileMode edgeTreatment
    ) {
        long nativeInputEffect = inputEffect != null ? inputEffect.mNativeRenderEffect : 0;
        return new RenderEffect(
                nativeCreateBlurEffect(
                        radiusX,
                        radiusY,
                        nativeInputEffect,
                        edgeTreatment.nativeInt
                )
            );
    }

        两个 createBlurEffect() 方法,分别为三参(模糊一次)和四参(模糊两次)。inputEffect 先进行了一次模糊。

看效果图:

        模糊程度一样,但是实现方式不同:

    private void setBlur() {
        RenderEffect radiusXRenderEffect = RenderEffect.createBlurEffect(10, 0, Shader.TileMode.MIRROR);
        RenderEffect radiusYRenderEffect = RenderEffect.createBlurEffect(0, 10, Shader.TileMode.MIRROR);
        agb.iv1.setRenderEffect(RenderEffect.createBlurEffect(10, 10, Shader.TileMode.CLAMP));
        agb.iv2.setRenderEffect(RenderEffect.createBlurEffect(10, 10, Shader.TileMode.REPEAT));
        //自身radiusY 为 0 ,传入的radiusYRenderEffect设置的radiusY为10;
        agb.iv3.setRenderEffect(RenderEffect.createBlurEffect(10, 0, radiusYRenderEffect, Shader.TileMode.MIRROR));
        //自身radiusX 为 0 ,传入的radiusXRenderEffect设置的radiusX为10;
        agb.iv4.setRenderEffect(RenderEffect.createBlurEffect(0, 10, radiusXRenderEffect, Shader.TileMode.DECAL));
    }

        这个方法返回一个 new RenderEffect(nativeCreateBlurEffect(...)。

        那咱们去看看 nativeCreateBlurEffect()

 nativeCreateBlurEffect()

        frameworks/base/libs/hwui/jni/RenderEffect.cpp

static const JNINativeMethod gRenderEffectMethods[] = {
    ...
    {"nativeCreateBlurEffect", "(FFJI)J", (void*)createBlurEffect},
    ...
};

static jlong createBlurEffect(JNIEnv* env , jobject, jfloat radiusX,
        jfloat radiusY, jlong inputFilterHandle, jint edgeTreatment) {
    auto* inputImageFilter = reinterpret_cast(inputFilterHandle);
    sk_sp blurFilter =
            SkImageFilters::Blur(
                    Blur::convertRadiusToSigma(radiusX),
                    Blur::convertRadiusToSigma(radiusY),
                    static_cast(edgeTreatment),
                    sk_ref_sp(inputImageFilter),
                    nullptr);
    return reinterpret_cast(blurFilter.release());
}

        这里有两个函数来处理我们传过来的模糊的值,咱进去看看。

 convertRadiusToSigma(convertSigmaToRadius)
//该常数近似于在SkBlurMask::Blur()(1/sqrt(3)中,在软件路径的"高质量"模式下进行的缩放。
static const float BLUR_SIGMA_SCALE = 0.57735f;

float Blur::convertRadiusToSigma(float radius) {
    return radius > 0 ? BLUR_SIGMA_SCALE * radius + 0.5f : 0.0f;
}

float Blur::convertSigmaToRadius(float sigma) {
    return sigma > 0.5f ? (sigma - 0.5f) / BLUR_SIGMA_SCALE : 0.0f;
}
 sk_ref_sp(inputImageFilter)

        external/skia/include/core/SkRefCnt.h

template  sk_sp sk_ref_sp(T* obj) {
    //sk_sp :
    return sk_sp(SkSafeRef(obj));
}

//SkSafeRef:检查参数是否为非空,如果是,则调用 obj->ref() 并返回 obj。
template  static inline T* SkSafeRef(T* obj) {
    if (obj) {
        obj->ref();
    }
    return obj;
}
 SkImageFilters::Blur()
#define SK_Scalar1                  1.0f
#define SK_ScalarNearlyZero         (SK_Scalar1 / (1 << 12))

sk_sp SkImageFilters::Blur(
        SkScalar sigmaX, SkScalar sigmaY, SkTileMode tileMode, sk_sp input,
        const CropRect& cropRect) {
    if (sigmaX < SK_ScalarNearlyZero && sigmaY < SK_ScalarNearlyZero && !cropRect) {
        return input;
    }
    return sk_sp(
          new SkBlurImageFilter(sigmaX, sigmaY, tileMode, input, cropRect));
}

        附上最后的倔强

    constexpr sk_sp() : fPtr(nullptr) {}
    constexpr sk_sp(std::nullptr_t) : fPtr(nullptr) {}

    
    sk_sp(const sk_sp& that) : fPtr(SkSafeRef(that.get())) {}
    template ::value>::type>
    sk_sp(const sk_sp& that) : fPtr(SkSafeRef(that.get())) {}

    
    sk_sp(sk_sp&& that) : fPtr(that.release()) {}
    template ::value>::type>
    sk_sp(sk_sp&& that) : fPtr(that.release()) {}

    
    explicit sk_sp(T* obj) : fPtr(obj) {}

        createBlurEffect() 得到 long 类型的 native 分配的的非零地址, 传入 new RenderEffect()

 new RenderEffect()
    
    private RenderEffect(long nativeRenderEffect) {
        mNativeRenderEffect = nativeRenderEffect;
        RenderEffectHolder.RENDER_EFFECT_REGISTRY.registerNativeAllocation(
                this, mNativeRenderEffect);
    }

继续

    
    private static class RenderEffectHolder {
        public static final NativeAllocationRegistry RENDER_EFFECT_REGISTRY =
                NativeAllocationRegistry.createMalloced(
                        RenderEffect.class.getClassLoader(), nativeGetFinalizer());
    }
 NativeAllocationRegistry.createMalloced()

        libcore/luni/src/main/java/libcore/util/NativeAllocationRegistry.java

    @SystemApi(client = MODULE_LIBRARIES)
    public static NativeAllocationRegistry createMalloced(
            @NonNull ClassLoader classLoader, long freeFunction, long size) {
        return new NativeAllocationRegistry(classLoader, freeFunction, size, true);
    }
 NativeAllocationRegistry()

        libcore/luni/src/main/java/libcore/util/NativeAllocationRegistry.java

    private NativeAllocationRegistry(ClassLoader classLoader, long freeFunction, long size,
            boolean mallocAllocation) {
        if (size < 0) {
            throw new IllegalArgumentException("Invalid native allocation size: " + size);
        }
        this.classLoader = classLoader;
        this.freeFunction = freeFunction;
        this.size = mallocAllocation ? (size | IS_MALLOCED) : (size & ~IS_MALLOCED);
    }

        既然拿到 NativeAllocationRegistry 那就继续调用其 registerNativeAllocation() 方法。

 registerNativeAllocation ()
    @SystemApi(client = MODULE_LIBRARIES)
    @libcore.api.IntraCoreApi
    public @NonNull Runnable registerNativeAllocation(@NonNull Object referent, long nativePtr) {
        //当 referent 或nativePtr 为空
        ...
        CleanerThunk thunk;
        CleanerRunner result;
        try {
            thunk = new CleanerThunk();
            Cleaner cleaner = Cleaner.create(referent, thunk);
            result = new CleanerRunner(cleaner);
            registerNativeAllocation(this.size);
        } catch (VirtualMachineError vme ) {
            applyFreeFunction(freeFunction, nativePtr);
            throw vme;
        } 
        // Enable the cleaner only after we can no longer throw anything, including OOME.
        thunk.setNativePtr(nativePtr);
        // Ensure that cleaner doesn't get invoked before we enable it.
        Reference.reachabilityFence(referent);
        return result;
    }

        向 ART 注册新的 NativePtr 和关联的 Java 对象(也就是咱们设置的模糊类)。

        返回的 Runnable 可用于在引用变得无法访问之前释放本机分配。如果运行时或使用 runnable 已经释放了本机分配,则 runnable 将不起作用。

        RenderEffect 算是搞完了,咱们回到View.setRenderEffect()

 View.setRenderEffect()
    public void setRenderEffect(@Nullable RenderEffect renderEffect) {
        if (mRenderNode.setRenderEffect(renderEffect)) {
            //视图属性更改(alpha、translationXY 等)的快速失效。
            invalidateViewProperty(true, true);
        }
    }

        这里有个 mRenderNode.setRenderEffect(renderEffect)。咱们近距离观望一番。

 mRenderNode 的创建

        咱们先找找他是在什么地方创建的。

    public View(Context context) {
        ...
        //在View的构造方法中创建
        mRenderNode = RenderNode.create(getClass().getName(), new ViewAnimationHostBridge(this));
        ...
    }
    
 RenderNode.create()
    
    public static RenderNode create(String name, @Nullable AnimationHost animationHost) {
        return new RenderNode(name, animationHost);
    }
    
    private RenderNode(String name, AnimationHost animationHost) {
        mNativeRenderNode = nCreate(name);
        //注册 Native Allocation。
        NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativeRenderNode);
        mAnimationHost = animationHost;
    }    

        再往下感觉也看不到啥了 跟上面类似,看.cpp动态分配类的地址还是有点懵。让我缓缓~以后补充。

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号