利用廣色內容增強圖像效果

Android 8.0 (API 級別 26) 推出了色彩管理支援功能,可為 多色空間 在具有相容顯示器的裝置上呈現圖形的標準 RGB (sRGB)。有了這項支援服務 您的應用程式可以透過從 PNG、JPEG 和 WebP 檔案載入的嵌入式廣色設定檔,來算繪點陣圖 透過 Java 或原生程式碼使用 OpenGL 或 Vulkan 的應用程式可以直接輸出廣色域內容 (使用 Display P3scRGB)。這項能力 適用於建立需要高保真色彩複製的應用程式,例如圖片和影片 編輯應用程式。

瞭解廣色域模式

廣色域有 ICC 設定檔,例如 Adobe RGB 專業相片 RGB DCI-P3,也就是 能夠呈現比 sRGB 更多的色彩範圍。支援廣色設定檔的螢幕 可顯示深層主色 (紅色、綠色和藍色) 的圖片,以及更豐富的次要顏色 顏色 (例如洋紅色、青色和黃色)。

在支援 Android 8.0 (API 級別 26) 以上版本的 Android 裝置上,應用程式可以 針對系統辨識且 能正確處理含內嵌廣色設定檔的點陣圖圖片。 ColorSpace.Named 類別列舉一部分的常用 Android 支援的色域

注意:啟用廣色域模式時,活動的 會耗用較多記憶體和 GPU 處理螢幕組成畫面。啟用廣色域前 模式,應審慎考量活動是否真的有益。舉例來說 以全螢幕顯示相片的活動是廣色域模式的理想選擇 顯示小型縮圖的活動則不屬於。

啟用廣色域模式

使用 colorMode 屬性要求顯示的活動 在相容裝置上支援廣色域模式。在廣色域模式下,視窗可 在 sRGB 色域之外,顯示更加鮮豔的色彩。如果裝置不支援廣色 銀河算繪,這個屬性不會有任何作用。如果應用程式需要判斷 螢幕是廣色域功能 isWideColorGamut() 方法。你也可以呼叫 isScreenWideColorGamut(),會傳回 true 只有在螢幕支援廣色域且裝置支援廣色域時 以及顏色呈現方式

螢幕可能是廣色可變色,但無法管理顏色。在這種情況下, 系統將不會授予應用程式廣色域模式。如果螢幕未採用顏色管理 - 就像所有 Android 8.0 之前版本一樣,系統會重新對應 應用程式繪製的色彩。

如要在活動中啟用廣色域,請設定 colorMode 屬性設為 wideColorGamutAndroidManifest.xml個人中心 請找出要啟用廣色模式的每個活動。

android:colorMode="wideColorGamut"

您也可以呼叫 setColorMode(int) 方法並傳入 COLOR_MODE_WIDE_COLOR_GAMUT

算繪廣色域內容

圖 1.Display P3 (橘色) 與 sRGB (白色) 色域

如要算繪廣色域的內容,應用程式必須載入寬色點陣圖, 包含大於 sRGB 色彩空間的色彩設定檔。常見的廣角色彩描述檔包括 Adobe RGB、DCI-P3 和 Display P3。

應用程式可以呼叫 getColorSpace()。判斷系統能否辨識 才能達到廣角 isWideGamut() 方法。

Color 類別可讓您使用四個元件表示顏色 包裝成 64 位元長值,而非使用整數的最常見表示 值。您可以使用長值定義顏色 精確度大於整數值如果您需要建立或編碼長值的顏色,請使用 Color 類別中的其中一個 pack() 方法。

您可以檢查應用程式是否正確要求廣色域模式,方法是檢查 getColorMode() 方法會傳回 COLOR_MODE_WIDE_COLOR_GAMUT (這個方法不會指出 但卻表示實際上是否授予廣色域模式)。

在原生程式碼中使用廣色域支援功能

本節說明如何使用 OpenGLVulkan API (如果應用程式使用原生程式碼)。

OpenGL

如要在 OpenGL 使用廣色域模式,應用程式必須加入 EGL 1.4 程式庫,內含: 下列任一副檔名:

如要啟用這項功能,您必須先透過 eglChooseConfig,包含支援的其中一種 屬性中的廣色顏色緩衝區格式。寬度的顏色緩衝區格式 顏色必須是下列其中一個 RGBA 值組:

  • 8、8、8、8
  • 10、10、10、2
  • FP16、FP16、FP16、FP16

然後在建立 顯示目標,如以下程式碼片段所示:

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:

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;
}