O Android 8.0 (API de nível 26) introduziu suporte ao gerenciamento de cores para espaços de cor além padrão RGB (sRGB) para renderizar gráficos em dispositivos com telas compatíveis. Com esse apoio, seu app pode renderizar bitmaps com perfis de cores amplos incorporados carregados de arquivos PNG, JPEG e WebP. via Java ou código nativo. Apps que usam OpenGL ou Vulkan podem gerar diretamente conteúdos com uma ampla gama de cores (usando o Display P3 e scRGB). Esse recurso útil para criar aplicativos que envolvem reprodução de cores de alta fidelidade, como imagens e vídeos e edição de texto.
Compreender o modo ampla gama de cores
Perfis de cores amplos são Perfis ICC, como RGB da Adobe, Pro Photo RGB DCI-P3, que são capazes de representar uma gama mais ampla de cores do que sRGB. Telas com suporte a perfis de cores amplos pode exibir imagens com cores primárias mais profundas (vermelhos, verdes e azuis), bem como cores primárias mais ricas cores (como magentas, ciano e amarelo).
Em dispositivos com o Android 8.0 (nível 26 da API) ou versões mais recentes, seu app pode
ativar o modo ampla gama de cores para uma atividade na qual o sistema reconhece e
processar corretamente imagens bitmap com perfis de cores amplos incorporados. A
A classe ColorSpace.Named
enumera uma lista parcial de objetos comumente usados
espaços de cor compatíveis com o Android.
Observação:quando o modo ampla gama de cores estiver ativado, o método usa mais memória e processamento de GPU para a composição da tela. Antes de ativar a ampla gama de cores você deve considerar cuidadosamente se a atividade realmente se beneficia dele. Por exemplo, uma atividade que exibe fotos em tela cheia é uma boa candidata para o modo ampla gama de cores, mas uma atividade que mostra miniaturas pequenas não é.
Ativar o modo ampla gama de cores
Use o atributo colorMode
para solicitar que a atividade seja mostrada.
no modo ampla gama de cores em dispositivos compatíveis. No modo ampla gama de cores, uma janela pode renderizar
fora da gama sRGB para exibir cores mais vibrantes. Se o dispositivo não oferecer suporte à ampla gama de cores
renderização de gama, esse atributo não terá efeito. Caso seu app precise determinar se uma
tela é compatível com a ampla gama de cores, chame o método
isWideColorGamut()
. O app também pode chamar
isScreenWideColorGamut()
, que retorna true
somente se a tela for compatível com a ampla gama de cores e o dispositivo oferecer suporte a essa ampla gama de cores
renderização de cores.
Uma tela pode ser compatível com a ampla gama de cores, mas não ser gerenciada por cores. Nesse caso, a sistema não vai conceder a um app o modo ampla gama de cores. Quando uma tela não é gerenciada por cores (como era o caso de todas as versões do Android anteriores à 8.0), o sistema remapeia o cores desenhadas pelo app na gama da tela.
Para ativar a ampla gama de cores na sua atividade, defina a colorMode
como wideColorGamut
no arquivo AndroidManifest.xml
. Você
precisa fazer isso para cada atividade para a qual deseja ativar o modo de gama ampla de cores.
android:colorMode="wideColorGamut"
Você também pode definir o modo de cores de forma programática na sua atividade chamando o método
setColorMode(int)
e transmitindo
COLOR_MODE_WIDE_COLOR_GAMUT
.
Renderizar conteúdos de ampla gama de cores
Para renderizar conteúdo da ampla gama de cores, seu app precisa carregar um bitmap de cores ampla, que é um bitmap com um perfil de cor com um espaço de cor maior do que sRGB. Os perfis de cores amplos comuns incluem Adobe RGB, DCI-P3 e Display P3.
Seu app pode consultar o espaço de cores de um bitmap chamando
getColorSpace()
: Para determinar se o sistema reconhece
espaço de cores específico para ter ampla gama, você pode chamar
isWideGamut()
.
A classe Color
permite representar uma cor com quatro componentes.
em um valor de 64 bits, em vez da representação mais comum que usa um número inteiro
. Usando valores longos, você pode definir cores com
maior precisão do que valores inteiros. Se você precisar criar ou codificar uma cor como um valor longo, use
um dos métodos pack()
na classe Color
.
Você pode verificar se o app solicitou corretamente o modo ampla gama de cores conferindo
o método getColorMode()
retorna
COLOR_MODE_WIDE_COLOR_GAMUT
(esse método não indica,
no entanto, se o modo de gama ampla de cores foi realmente concedido).
Usar a compatibilidade com a ampla gama de cores no código nativo
Esta seção descreve como ativar o modo ampla gama de cores com o OpenGL (em inglês) e APIs Vulkan se o app usar código nativo.
OpenGL
Para usar o modo de gama ampla de cores no OpenGL, seu app precisa incluir a biblioteca EGL 1.4 com uma das seguintes extensões:
Para ativar o recurso, é preciso primeiro criar um contexto de GL via
eglChooseConfig
, sendo que um dos três é compatível
formatos de buffer de cores para cores amplas nos atributos. O formato do buffer de cores para modelos amplos
a cor precisa ser um destes conjuntos de valores RGBA:
- 8, 8, 8, 8
- 10, 10, 10, 2
- FP16, FP16, FP16, FP16
Em seguida, solicite a extensão do espaço de cores P3 ao criar seu destinos de renderização, conforme mostrado no snippet de código a seguir:
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
O suporte do Vulkan à ampla gama de cores é fornecido pelo
VK_EXT_swapchain_colorspace
.
Antes de ativar o suporte à ampla gama de cores no seu código Vulkan, verifique se o elemento
tem suporte em
vkEnumerateInstanceExtensionProperties
:
Se a extensão estiver disponível, você precisará ativá-la durante
vkCreateInstance
antes de criar imagens de cadeia de troca que
use os espaços de cor adicionais definidos pela extensão.
Antes de criar a cadeia de troca, é preciso escolher o espaço de cores desejado e passar pelas nas superfícies de dispositivos físicos disponíveis e escolha um formato de cor válido espaço de cores.
Em dispositivos Android, o Vulkan oferece suporte à ampla gama de cores com os seguintes espaços de cor e
Formatos de cor VkSurfaceFormatKHR
:
- Espaços de cor da gama ampla de cores do Vulkan:
VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT
VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT
- Formatos de cores do Vulkan compatíveis com ampla gama de cores:
VK_FORMAT_R16G16B16A16_SFLOAT
VK_FORMAT_A2R10G10B10_UNORM_PACK32
VK_FORMAT_R8G8B8A8_UNORM
O snippet de código a seguir mostra como verificar se o dispositivo é compatível com o Display P3. espaço de cores:
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 }
O snippet de código a seguir mostra como solicitar uma cadeia de troca do Vulkan com
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; }