Migliora la grafica con contenuti a colori ampi

Android 8.0 (livello API 26) ha introdotto il supporto della gestione del colore per spazi colore oltre a RGB (sRGB) standard per il rendering di grafica su dispositivi con display compatibili. Grazie a questo supporto, la tua app può eseguire il rendering delle bitmap con profili di colore larghi incorporati caricati da file PNG, JPEG e WebP tramite Java o codice nativo. Le app che utilizzano OpenGL o Vulkan possono produrre direttamente contenuti con ampia gamma di colori (utilizzando Display P3 e scRGB). Questa funzionalità è utile per creare app che richiedono una riproduzione dei colori ad alta fedeltà, come le app di editing di immagini e video.

Informazioni sulla modalità ad ampia gamma di colori

I profili di colore larghi vengono Profili ICC, ad esempio Adobe RGB, Foto professionale RGB e DCI-P3, ovvero in grado di rappresentare una gamma più ampia di colori rispetto a sRGB. Gli schermi che supportano profili di colori ampi possono visualizzare immagini con colori primari più intensi (rossi, verdi e blu) e colori secondari più vivaci (ad esempio magenta, ciano e giallo).

Sui dispositivi Android con Android 8.0 (livello API 26) o versioni successive che la supportano, la tua app può attivare la modalità colore con gamma di colori ampliata per un'attività in cui il sistema riconosce ed elabora correttamente le immagini bitmap con profili di colore ampliati incorporati. La classe ColorSpace.Named elenca un elenco parziale degli spazi di colore di uso comune supportati da Android.

Nota: quando la modalità di gamma di colori estesa è attivata, la finestra dell'attività utilizza più memoria e l'elaborazione della GPU per la composizione dello schermo. Prima di attivare un'ampia gamma di colori devi valutare attentamente se l'attività ne beneficia davvero. Ad esempio, un'attività che mostra le foto a schermo intero è una buona candidata per la modalità di gamma cromatica ampia, ma non un'attività che mostra piccole miniature.

Attivare la modalità con gamma di colori ampliata

Utilizza l'attributo colorMode per richiedere la visualizzazione dell'attività in modalità di gamma di colori estesa sui dispositivi compatibili. In modalità di gamma di colori estesa, una finestra può eseguire il rendering al di fuori della gamma sRGB per visualizzare colori più brillanti. Se il dispositivo non supporta il rendering in una gamma di colori ampia, questo attributo non ha effetto. Se la tua app deve determinare se un determinato il display supporta un'ampia gamma di colori, chiama isWideColorGamut(). L'app può anche chiamare isScreenWideColorGamut(), che restituisce true solo se il display supporta la gamma di colori estesa e il dispositivo supporta il rendering dei colori con gamma di colori estesa.

Un display potrebbe supportare un'ampia gamma di colori ma non una gestione del colore. In questo caso, non concederà a un'app la modalità ad ampia gamma di colori. Quando un display non è gestito a livello di colore, come accadeva per tutte le versioni di Android precedenti alla 8.0, il sistema rimappa i colori disegnati dall'app alla gamma del display.

Per attivare l'ampia gamma di colori nella tua attività, imposta colorMode a wideColorGamut nel file AndroidManifest.xml. Tu devi farlo per ogni attività per cui vuoi abilitare la modalità colore largo.

android:colorMode="wideColorGamut"

Puoi anche impostare la modalità di colore in modo programmatico nella tua attività chiamando il metodo setColorMode(int) e passando COLOR_MODE_WIDE_COLOR_GAMUT.

Visualizzazione di contenuti con ampia gamma di colori

Figura 1. Spazi colore Display P3 (arancione) e sRGB (bianco)

Per visualizzare contenuti con una gamma di colori ampia, la tua app deve caricare una bitmap a colori ampi, ovvero una bitmap con un profilo di colore contenente uno spazio di colore più ampio di sRGB. I profili di colore larghi più comuni includono Adobe RGB, DCI-P3 e Display P3.

La tua app può eseguire query sullo spazio colore di una bitmap chiamando getColorSpace(). Per determinare se il sistema riconosce un spazio di colore specifico come a gamma estesa, puoi chiamare il metodo isWideGamut().

La classe Color consente di rappresentare un colore con quattro componenti compressi in un valore lungo 64 bit, anziché la rappresentazione più comune che utilizza un valore intero. Utilizzando valori lunghi, puoi definire i colori con e maggiore precisione rispetto ai valori interi. Se devi creare o codificare un colore come valore long, utilizza uno dei metodi pack() della classe Color.

Puoi verificare se la tua app ha richiesto correttamente la modalità di gamma di colori estesa controllando che il metodo getColorMode() restituisca COLOR_MODE_WIDE_COLOR_GAMUT (tuttavia, questo metodo non indica se la modalità di gamma di colori estesa è stata effettivamente concessa).

Utilizzare il supporto dell'ampia gamma di colori nel codice nativo

In questa sezione viene descritto come attivare la modalità ad ampia gamma di colori con il OpenGL e API Vulkan se la tua app utilizza codice nativo.

OpenGL

Per utilizzare la modalità ad ampia gamma di colori in OpenGL, l'app deve includere la libreria EGL 1.4 con una delle seguenti estensioni:

Per attivare la funzionalità, devi prima creare un contesto GL tramite eglChooseConfig, con uno dei tre formati di buffer di colore supportati per il colore ampio negli attributi. Il formato del buffer di colore per le immagini il colore deve rientrare in uno dei seguenti insiemi di valori RGBA:

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

Poi, richiedi l'estensione dello spazio di colore P3 quando crei gli scopi di rendering, come mostrato nel seguente snippet di codice:

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

Il supporto di Vulkan per un'ampia gamma di colori viene fornito tramite la VK_EXT_swapchain_colorspace.

Prima di abilitare il supporto dei colori ampi nel codice Vulkan, verifica innanzitutto che è supportata tramite vkEnumerateInstanceExtensionProperties. Se l'estensione è disponibile, devi attivarla durante vkCreateInstance prima di creare immagini della catena di scambio che utilizzano gli spazi di colore aggiuntivi definiti dall'estensione.

Prima di creare la swapchain, devi scegliere lo spazio di colore che preferisci, quindi eseguire un ciclo per le superfici dei dispositivi fisici disponibili e scegliere un formato di colore valido per lo spazio di colore in questione.

Sui dispositivi Android, Vulkan supporta la gamma di colori estesa con i seguenti spazi colore e VkSurfaceFormatKHR formati di colore:

  • Spazi cromatici con gamma di colori Vulkan ampia:
    • VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT
    • VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT
  • Formati di colore Vulkan con supporto di un'ampia gamma di colori:
    • VK_FORMAT_R16G16B16A16_SFLOAT
    • VK_FORMAT_A2R10G10B10_UNORM_PACK32
    • VK_FORMAT_R8G8B8A8_UNORM

Il seguente snippet di codice mostra come verificare che il dispositivo supporti il Display P3 spazio colore:

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
}

Il seguente snippet di codice mostra come richiedere uno swapchain Vulkan con 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;
}