Grafiken mit Wide-Color-Inhalten optimieren

Mit Android 8.0 (API-Level 26) wurde neben dem Standard-RGB-Code (sRGB) für das Rendern von Grafiken auf Geräten mit kompatiblen Displays die Farbverwaltung für zusätzliche Farbräume unterstützt. Mit dieser Unterstützung kann Ihre App Bitmaps mit eingebetteten breiten Farbprofilen rendern, die aus PNG-, JPEG- und WebP-Dateien über Java oder nativen Code geladen wurden. Apps, die OpenGL oder Vulkan verwenden, können Inhalte mit Display P3 und scRGB direkt in einem großen Farbraum ausgeben. Diese Funktion ist nützlich, um Anwendungen zu erstellen, die eine High-Fidelity-Farbwiedergabe erfordern, z. B. Bild- und Videobearbeitungsanwendungen.

Informationen zum Wide-Farbraummodus

Breite Farbprofile sind ICC-Profile wie Adobe RGB, Pro Photo RGB und DCI-P3, die einen größeren Farbbereich als sRGB darstellen können. Bildschirme, die breite Farbprofile unterstützen, können Bilder mit tieferen Primärfarben (Rot, Grün und Blau) sowie satteren Sekundärfarben (wie Magenta, Cyans und Gelb) anzeigen.

Auf Android-Geräten mit Android 8.0 (API-Level 26) oder höher, die diese Funktion unterstützen, kann Ihre App den Farbmodus für die breite Farbskala für eine Aktivität aktivieren, bei der das System Bitmapbilder mit eingebetteten breiten Farbprofilen erkennt und korrekt verarbeitet. Die Klasse ColorSpace.Named listet eine unvollständige Liste häufig verwendeter Farbräume auf, die von Android unterstützt werden.

Hinweis:Wenn der Wide-Farbraum-Modus aktiviert ist, benötigt das Fenster der Aktivität für die Bildschirmzusammensetzung mehr Arbeitsspeicher und GPU-Verarbeitung. Bevor Sie den Modus für den Wide-Farbraum aktivieren, sollten Sie sorgfältig überlegen, ob die Aktivität wirklich davon profitiert. Eine Aktivität, bei der Fotos im Vollbildmodus angezeigt werden, eignet sich gut für den Modus für einen breiteren Farbschattier, eine Aktivität, bei der kleine Miniaturansichten angezeigt werden, jedoch nicht.

Modus für horizontalen Farbschatz aktivieren

Verwenden Sie das Attribut colorMode, um anzufordern, dass die Aktivität auf kompatiblen Geräten im Wide-Farbraum angezeigt wird. Im Wide-Farbraummodus kann ein Fenster außerhalb des sRGB-Gamuts gerendert werden, um leuchtendere Farben darzustellen. Wenn das Gerät das Rendering des breiten Farbraums nicht unterstützt, hat dieses Attribut keine Auswirkung. Wenn in deiner App ermittelt werden muss, ob ein bestimmtes Display einen Wide-Farbraum unterstützt, rufe die Methode isWideColorGamut() auf. Sie können auch isScreenWideColorGamut() aufrufen, das true nur dann zurückgibt, wenn die Anzeige einen breiten Farbraum unterstützt und das Gerät ein Farbrendering unterstützt.

Ein Display kann einen Wide-Farbraum unterstützen, aber nicht farblich verwaltet werden. In diesem Fall gewährt das System einer App keinen Wide-Farbraum-Modus. Wenn ein Display nicht farblich verwaltet wird, wie es bei allen Android-Versionen vor 8.0 der Fall war, ordnet das System die von der App gezeichneten Farben dem Umfang des Displays zu.

Um den breiten Farbraum in deiner Aktivität zu aktivieren, setze das Attribut colorMode in der AndroidManifest.xml-Datei auf wideColorGamut. Sie müssen dies für jede Aktivität tun, für die Sie den breiten Farbmodus aktivieren möchten.

android:colorMode="wideColorGamut"

Sie können den Farbmodus auch programmatisch in Ihrer Aktivität festlegen, indem Sie die Methode setColorMode(int) aufrufen und COLOR_MODE_WIDE_COLOR_GAMUT übergeben.

Inhalte in großem Farbraum rendern

Abbildung 1. Display-P3-Farbräume (Orange) im Vergleich zu sRGB-Farbräumen (Weiß)

Zum Rendern von Inhalten in einem breiten Farbraum muss Ihre App eine Bitmap der breiten Farbpalette laden. Das ist eine Bitmap mit einem Farbprofil, das einen breiteren Farbraum als sRGB enthält. Zu den gängigen breiten Farbprofilen gehören Adobe RGB, DCI-P3 und Display P3.

Ihre App kann den Farbraum einer Bitmap durch Aufrufen von getColorSpace() abfragen. Wenn Sie feststellen möchten, ob das System einen bestimmten Farbraum als großformatig erkennt, können Sie die Methode isWideGamut() aufrufen.

Mit der Klasse Color können Sie eine Farbe mit vier Komponenten in einem 64-Bit-Wert darstellen, anstatt mit der gebräuchlichsten Darstellung, die eine Ganzzahl verwendet. Mit langen Werten können Sie Farben präziser als ganzzahlige Werte definieren. Wenn Sie eine Farbe als Long-Wert erstellen oder codieren müssen, verwenden Sie eine der pack()-Methoden in der Color-Klasse.

Sie können prüfen, ob Ihre App den Wide-Farbraum-Modus ordnungsgemäß angefordert hat. Dazu prüfen Sie, ob die getColorMode()-Methode COLOR_MODE_WIDE_COLOR_GAMUT zurückgibt. Diese Methode gibt jedoch nicht an, ob der Wide-Farbraum-Modus tatsächlich gewährt wurde.

Unterstützung für einen großen Farbraum im nativen Code verwenden

In diesem Abschnitt wird beschrieben, wie Sie den Wide-Farbraummodus mit den OpenGL APIs und Vulkan APIs aktivieren, wenn Ihre Anwendung nativen Code verwendet.

OpenGL

Wenn Sie den Wide-Farbraummodus in OpenGL verwenden möchten, muss Ihre App die EGL 1.4-Bibliothek mit einer der folgenden Erweiterungen enthalten:

Um das Feature zu aktivieren, müssen Sie zuerst über eglChooseConfig einen GL-Kontext mit einem der drei unterstützten Farbpufferformate für Wide Color in den Attributen erstellen. Das Farbpufferformat für die breite Farbe muss einem der folgenden RGBA-Werte entsprechen:

  • 8, 8, 8, 8
  • 10, 10, 10, 2
  • FP16, FP16, FP16, FP16

Fordern Sie dann beim Erstellen Ihrer Renderingziele die P3-Farbraumerweiterung an, wie im folgenden Code-Snippet gezeigt:

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-Unterstützung für einen großen Farbraum wird über die Erweiterung VK_EXT_swapchain_colorspace bereitgestellt.

Bevor Sie die Unterstützung für mehr Farben in Ihrem Vulkan-Code aktivieren, prüfen Sie zuerst, ob die Erweiterung über vkEnumerateInstanceExtensionProperties unterstützt wird. Wenn die Erweiterung verfügbar ist, müssen Sie sie während der vkCreateInstance aktivieren, bevor Sie Swapchain-Images erstellen, die die von der Erweiterung definierten zusätzlichen Farbräume verwenden.

Bevor Sie die Swapchain erstellen, müssen Sie den gewünschten Farbraum auswählen, dann die verfügbaren physischen Geräteoberflächen durchlaufen und ein gültiges Farbformat für diesen Farbraum auswählen.

Auf Android-Geräten unterstützt Vulkan einen großen Farbraum mit den folgenden Farbräumen und VkSurfaceFormatKHR-Farbformaten:

  • Farbräume in einem breiten Vulkan-Farbraum:
    • VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT
    • VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT
  • Vulkan-Farbformate, die einen breiten Farbraum unterstützen:
    • VK_FORMAT_R16G16B16A16_SFLOAT
    • VK_FORMAT_A2R10G10B10_UNORM_PACK32
    • VK_FORMAT_R8G8B8A8_UNORM

Das folgende Code-Snippet zeigt, wie Sie prüfen können, ob das Gerät den Display-P3-Farbraum unterstützt:

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
}

Das folgende Code-Snippet zeigt, wie Sie mit VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT eine Vulkan-Swapchain anfordern:

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