Android应用开发(34)启用广色域(wideColorGamut)

文章介绍了Android8.0及以上版本如何启用广色域颜色模式,提升图像显示效果。通过检查设备是否支持广色域,以及如何处理广色域图片资源,开发者可以优化应用以适应现代高色域屏幕。同时,提供了启用广色域模式的方法,包括在AndroidManifest.xml中设置colorMode和代码中调用setColorMode。
摘要由CSDN通过智能技术生成

Android应用开发学习笔记——目录索引

 参考android官网:

使用广色域内容增强图形效果  |  Android 开发者  |  Android Developers

ColorSpace  |  Android Developers

Wide Color Photos Are Coming to Android: Things You Need to Know to be Prepared

Android 现已迎来新一轮的图像革新, Android 8.0(API 级别 26)或更高的 Android 版本上,应用可为 Activity 启用广色域颜色模式,色域更宽的画面意味着,能给用户呈现更加实景的丰富的色彩。

切入正题之前,让我先解答一下大家的疑惑: 为什么要支持广色域呢?实际上,移动设备的屏幕与摄像头传感器每年都在更新换代,越来越多的新机型即将搭载校准显示面板,其中部分还会提供广色域支持。现代摄像头感应器能够捕捉到 sRGB 范围以外的颜色,然后生成广色域图片。屏幕与传感器的双重升级将带给用户端到端的摄影体验,让他们用更鲜明的色彩留影真实世界。

从技术层面来说,这意味着应用需要处理的图片与之前不同了。图片内嵌的 ICC 配置文件将不再采用 sRGB 色彩空间,而是转用其它色域更加丰富的格式,如 Display P3 和 Adobe RGB。对于消费者而言,广色域能让照片看上去更加真实。

一、查看广色域支持情况

1. 查看设备是否支持广色域

如果是debug,可以使用adb shell dumpsys SurfaceFlinger --wide-color

使用xiaomi 13 Ultra(android 13 API 级别 33)运行命令输出如下:

使用MIX 2S(android API 级别 29)运行命令输出如下:

显示屏是否支持广色域,请调用 isWideColorGamut() 方法。

应用还可以调用 isScreenWideColorGamut()

mDisplay = getWindowManager().getDefaultDisplay();
Log.d(TAG, "isWideColorGamut(): " + mDisplay.isWideColorGamut());

boolean isWcgSupport = 
        getResources().getConfiguration().isScreenWideColorGamut();
Log.d(TAG, "isScreenWideColorGamut(): " + isWcgSupport);

 使用xiaomi 13 Ultra(android 13 API 级别 33)log打印:

07-31 00:21:49.959 13998 13998 D lzl-test: isWideColorGamut(): true
07-31 00:21:49.959 13998 13998 D lzl-test: isScreenWideColorGamut(): true

 使用MIX 2S(android API 级别 29)log打印:

07-31 00:17:49.405 13998 13998 D lzl-test: isWideColorGamut(): false
07-31 00:17:49.405 13998 13998 D lzl-test: isScreenWideColorGamut(): false

 2. 查看图片资源是否是广色域

图片文件,使用 EXIF信息查看器(图虫EXIF查看器),看如果是否是P3广色域图片

        ImageDecoder.Source source = ImageDecoder.createSource(getResources(), R.drawable.id);
        try {
            Bitmap bitmap = ImageDecoder.decodeBitmap(source,
                    new ImageDecoder.OnHeaderDecodedListener() {
                        @Override
                        public void onHeaderDecoded(ImageDecoder decoder,
                                                    ImageDecoder.ImageInfo info,
                                                    ImageDecoder.Source source) {
                            ColorSpace cs = info.getColorSpace();
                            // Do something...
                            Log.d(TAG, "getColorSpace: " + cs.toString());
                        }
                    });
        } catch (IOException e) {
            // handle exception.
        }

二、启用广色域模式

为了妥善处理图片,除上述必要check之外,如果是一个图像类应用,可用通过如下方式启用广色域模式,来实现图片的全彩色域显示:

  1.  AndroidManifest.xml 在 activity 文件中的 colorMode 属性设定为 wideColorGamut

  2. 调用API setColorMode(ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT);

1. AndroidManifest.xml 中配置android:colorMode="wideColorGamut"

如需在 activity 中启用广色域,请将 AndroidManifest.xml 文件中的 colorMode 属性设定为 wideColorGamut。请注意,您需要为每一个启用广色域模式的 activity 重复以上设置。


        <activity
            android:name=".WideColorActivity"
            android:colorMode="wideColorGamut"
            android:exported="true">
            ...
        </activity>

        <activity
            android:name=".WideColorActivity2"
            android:colorMode="wideColorGamut"
            android:exported="false">
            ...
        </activity>

2. 调用setColorMode(int)方法并传入COLOR_MODE_WIDE_COLOR_GAMUT

通过代码setColorMode(ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT)设置一个 Display P3 surface,来实现图片的全彩色域显示。 

getWindow().setColorMode(ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT);
Log.d(TAG, "getWindow().getColorMode(): " + getWindow().getColorMode());

广色域启用为可选,因它需更多系统资源(可能致应用性能下降),开发者文档强调:

启用广色域模式时活动窗口用更多内存GPU处理能力进行画面组合。启用广色域模式前应仔细考虑活动能否真正从中受益。全屏显示照片活动很适合采用广色域模式而显示缩略图界面不够适合。

代码简单分析:

//frameworks/base/core/java/android/view/Window.java
    /**
     * <p>Sets the requested color mode of the window. The requested the color mode might
     * override the window's pixel {@link WindowManager.LayoutParams#format format}.</p>
     *
     * <p>The requested color mode must be one of {@link ActivityInfo#COLOR_MODE_DEFAULT},
     * {@link ActivityInfo#COLOR_MODE_WIDE_COLOR_GAMUT} or {@link ActivityInfo#COLOR_MODE_HDR}.</p>
     *
     * <p>The requested color mode is not guaranteed to be honored. Please refer to
     * {@link #getColorMode()} for more information.</p>
     *
     * @see #getColorMode()
     * @see Display#isWideColorGamut()
     * @see Configuration#isScreenWideColorGamut()
     */
    public void setColorMode(@ActivityInfo.ColorMode int colorMode) {
        final WindowManager.LayoutParams attrs = getAttributes();
        attrs.setColorMode(colorMode);
        dispatchWindowAttributesChanged(attrs);
    }

    protected void dispatchWindowAttributesChanged(WindowManager.LayoutParams attrs) {
        if (mCallback != null) {
            mCallback.onWindowAttributesChanged(attrs);
        }
    }

// frameworks/base/core/java/android/view/WindowManager.java
        public void setColorMode(@ActivityInfo.ColorMode int colorMode) {
            mColorMode = colorMode;
        }


// Activity.java (android\frameworks\base\core\java\android\app)
    public void onWindowAttributesChanged(WindowManager.LayoutParams params) {
        // Update window manager if: we have a view, that view is
        // attached to its parent (which will be a RootView), and
        // this activity is not embedded.
        if (mParent == null) {
            View decor = mDecor;
            if (decor != null && decor.getParent() != null) {
                getWindowManager().updateViewLayout(decor, params);
                if (mContentCaptureManager != null) {
                    mContentCaptureManager.updateWindowAttributes(params);
                }
            }
        }
    }
    
// WindowManagerImpl.java (android\frameworks\base\core\java\android\view)
    public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        android.util.SeempLog.record_vg_layout(384,params);
        applyTokens(params);
        mGlobal.updateViewLayout(view, params);
    }
// WindowManagerGlobal.java (android\frameworks\base\core\java\android\view)
    public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;

        view.setLayoutParams(wparams);

        synchronized (mLock) {
            int index = findViewLocked(view, true);
            ViewRootImpl root = mRoots.get(index);
            mParams.remove(index);
            mParams.add(index, wparams);
            root.setLayoutParams(wparams, false);
        }
    }
// ViewRootImpl.java (android\frameworks\base\core\java\android\view)
    public void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
...

三、测试程序

package com.example.widecolorgamuttest;

import ...

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        boolean isWcgSupport = getResources().getConfiguration().isScreenWideColorGamut();

        Display display = getWindowManager().getDefaultDisplay();
        Log.d(TAG, "display.isWideColorGamut(): " + display.isWideColorGamut());

        Log.d(TAG, "getWindow().getColorMode(): " + getWindow().getColorMode());

        mImageView = (ImageView)findViewById(R.id.imageView);
        imageView.setImageResource(R.drawable.android_p3);

        getWindow().setColorMode(ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT);
        mTextView = (TextView)findViewById(R.id.textView);
        mTextView.setText("P3色域图片使用P3色域显示");
        mTextView.setTextColor(Color.RED);

        mButton_srgb = (Button)findViewById(R.id.button_srgb);
        mButton_srgb.setOnClickListener(this);
        mButton_p3 = (Button)findViewById(R.id.button_p3);
        mButton_p3.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        Button button = (Button)v;
        if (button == mButton_srgb) {
            // COLOR_MODE_DEFAULT for colorMode indicating that the activity
            // should use the default color mode (sRGB, low dynamic range).
            getWindow().setColorMode(ActivityInfo.COLOR_MODE_DEFAULT);
            mTextView.setText("P3色域图片使用sRGB色域显示");
            Log.d(TAG, "getWindow().getColorMode(): " + getWindow().getColorMode());
        } else if (button == mButton_p3) {
            // COLOR_MODE_WIDE_COLOR_GAMUT of colorMode indicating that the activity
            // should use a wide color gamut if the presentation display supports it.
            getWindow().setColorMode(ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT);
            mTextView.setText("P3色域图片使用P3色域显示");
            Log.d(TAG, "getWindow().getColorMode(): " + getWindow().getColorMode());
        } else {
            Log.e(TAG, "Unknown button id!");
        }
    }
}

使用xiaomi 13 Ultra运行

 使用adb shell dumpsys SurfaceFlinger --wide-color命令确认当前的Display color mode:

 使用adb shell dumpsys SurfaceFlinger命令确认input layer的datespace是DISPLAY_P3:

完整源码

百度网盘链接:百度网盘 请输入提取码 提取码:test 

WideColorGamutTest目录

对比测试

左边:xiaomi 13 Ultra(android 13 API 级别 33)      右边:MIX 2S(android API 级别 29)

点此查看Android应用开发学习笔记的完整目录

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

liuzl_2010

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值