Android 8.0 (API 級別 26) 推出了色彩管理支援功能,可為 多色空間 在具有相容顯示器的裝置上呈現圖形的標準 RGB (sRGB)。有了這項支援,應用程式就能透過 Java 或原生程式碼,從 PNG、JPEG 和 WebP 檔案載入嵌入式寬色彩設定檔,並轉譯位元陣列。使用 OpenGL 或 Vulkan 的應用程式可以直接輸出廣色域內容 (使用 Display P3 和 scRGB)。這項功能適用於建立涉及高保真色彩重現的應用程式,例如圖片和影片編輯應用程式。
瞭解廣色域模式
廣色域有 ICC 設定檔,例如 Adobe RGB、 專業相片 RGB DCI-P3,也就是 能夠呈現比 sRGB 更多的色彩範圍。支援廣色設定檔的螢幕 可顯示深層主色 (紅色、綠色和藍色) 的圖片,以及更豐富的次要顏色 顏色 (例如洋紅色、青色和黃色)。
在支援 Android 8.0 (API 級別 26) 以上版本的 Android 裝置上,應用程式可以
針對系統辨識且
能正確處理含內嵌廣色設定檔的點陣圖圖片。
ColorSpace.Named
類別列舉一部分的常用
Android 支援的色域
注意:啟用廣色域模式後,活動視窗會使用更多記憶體和 GPU 處理作業來進行螢幕合成。啟用寬色域模式前,請仔細考量活動是否確實能從中受益。舉例來說 以全螢幕顯示相片的活動是廣色域模式的理想選擇 顯示小型縮圖的活動則不屬於。
啟用廣色域模式
使用 colorMode
屬性要求顯示的活動
在相容裝置上支援廣色域模式。在廣色域模式下,視窗可轉譯 sRGB 以外的色域,顯示更加鮮豔的色彩。如果裝置不支援廣色
銀河算繪,這個屬性不會有任何作用。如果應用程式需要判斷
螢幕是廣色域功能
isWideColorGamut()
方法。您的應用程式也可以呼叫 isScreenWideColorGamut()
,但只有在螢幕支援廣色域且裝置支援廣色域色彩算繪時,才會傳回 true
。
螢幕可能是廣色可變色,但無法管理顏色。在這種情況下, 系統將不會授予應用程式廣色域模式。如果螢幕未經過色彩管理 (例如 8.0 之前的所有 Android 版本),系統會將應用程式繪製的顏色重新對應至螢幕的色域。
如要在活動中啟用廣色域,請在 AndroidManifest.xml
檔案中將 colorMode
屬性設為 wideColorGamut
。您必須針對要啟用廣色域模式的每個活動執行這項操作。
android:colorMode="wideColorGamut"
您也可以呼叫 setColorMode(int)
方法並傳入 COLOR_MODE_WIDE_COLOR_GAMUT
,以程式輔助方式在活動中設定色彩模式。
算繪廣色域內容
如要算繪廣色域的內容,應用程式必須載入寬色點陣圖, 包含大於 sRGB 色彩空間的色彩設定檔。常見的廣角色彩描述檔包括 Adobe RGB、DCI-P3 和 Display P3。
應用程式可以呼叫 getColorSpace()
,查詢位圖的色彩空間。如要判斷系統是否將特定色域視為廣色域,您可以呼叫 isWideGamut()
方法。
Color
類別可讓您以四個元件組成的 64 位元長值表示顏色,而非使用整數值的常見表示法。您可以使用長值定義顏色
精確度大於整數值如果您需要建立或將顏色編碼為長值,請使用 Color
類別中的其中一個 pack()
方法。
您可以檢查應用程式是否正確要求廣色域模式,方法是檢查
getColorMode()
方法會傳回
COLOR_MODE_WIDE_COLOR_GAMUT
(這個方法不會指出
但卻表示實際上是否授予廣色域模式)。
在原生程式碼中使用廣色域支援功能
如果應用程式使用原生程式碼,本節將說明如何使用 OpenGL 和 Vulkan API 啟用寬廣色域模式。
OpenGL
如要在 OpenGL 中使用寬廣色域模式,應用程式必須包含 EGL 1.4 程式庫,並使用下列其中一個擴充功能:
如要啟用這項功能,您必須先透過 eglChooseConfig
建立 GL 結構定義,並在屬性中使用三種支援的寬色緩衝區格式之一。寬度的顏色緩衝區格式
顏色必須是下列其中一個 RGBA 值組:
- 8、8、8、8
- 10、10、10、2
- FP16、FP16、FP16、FP16
接著,請在建立轉譯目標時要求 P3 色彩空間擴充功能,如以下程式碼片段所示:
std::vector<EGLint> attributes; attributes.push_back(EGL_GL_COLORSPACE_KHR); attributes.push_back(EGL_GL_COLORSPACE_DISPLAY_P3_EXT); attributes.push_back(EGL_NONE); engine->surface_ = eglCreateWindowSurface( engine->display_, config, engine->app->window, attributes.data());
Vulkan
Vulkan 支援廣色域,並透過 VK_EXT_swapchain_colorspace
擴充功能提供。
在 Vulkan 程式碼中啟用廣色支援前,請先檢查
擴充功能是透過
vkEnumerateInstanceExtensionProperties
。
如果可以使用擴充功能,請務必在更新期間啟用
請vkCreateInstance
,再建立任何交換鏈映像檔
使用擴充功能定義的額外色彩空間。
建立交換鏈之前,您需要選擇偏好的色域,然後繞行 可用的實體裝置介面,並為該元件選擇有效的顏色格式 色彩空間。
在 Android 裝置上,Vulkan 支援下列色域和下列色域:
VkSurfaceFormatKHR
種顏色格式:
- Vulkan 廣色域色彩空間:
VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT
VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT
- 支援廣色域的 Vulkan 色彩格式:
VK_FORMAT_R16G16B16A16_SFLOAT
VK_FORMAT_A2R10G10B10_UNORM_PACK32
VK_FORMAT_R8G8B8A8_UNORM
下列程式碼片段說明如何檢查裝置是否支援 Display P3 色彩空間:
uint32_t formatCount = 0; vkGetPhysicalDeviceSurfaceFormatsKHR( vkPhysicalDev, vkSurface, &formatCount, nullptr); VkSurfaceFormatKHR *formats = new VkSurfaceFormatKHR[formatCount]; vkGetPhysicalDeviceSurfaceFormatsKHR( vkPhysicalDev, vkSurface, &formatCount, formats); uint32_t displayP3Index = formatCount; for (uint32_t idx = 0; idx < formatCount; idx++) { if (formats[idx].format == requiredSwapChainFmt && formats[idx].colorSpace==VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT) { displayP3Index = idx; break; } } if (displayP3Index == formatCount) { // Display P3 is not supported on the platform // choose other format }
下列程式碼片段顯示如何使用 VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT
要求 Vulkan 交換鏈:
uint32_t queueFamily = 0; VkSwapchainCreateInfoKHR swapchainCreate { .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, .pNext = nullptr, .surface = AndroidVkSurface_, .minImageCount = surfaceCapabilities.minImageCount, .imageFormat = requiredSwapChainFmt, .imageColorSpace = VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT, .imageExtent = surfaceCapabilities.currentExtent, .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, .preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR, .imageArrayLayers = 1, .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE, .queueFamilyIndexCount = 1, .pQueueFamilyIndices = &queueFamily, .presentMode = VK_PRESENT_MODE_FIFO_KHR, .oldSwapchain = VK_NULL_HANDLE, .clipped = VK_FALSE, }; VkRresult status = vkCreateSwapchainKHR( vkDevice, &swapchainCreate, nullptr, &vkSwapchain); if (status != VK_SUCCESS) { // Display P3 is not supported return false; }