Geniş renkli içerikle grafikleri geliştirin

Android 8.0 (API düzeyi 26), uyumlu ekranlı cihazlarda grafik oluşturmaya yönelik standart RGB (sRGB) ve ek renk alanları için renk yönetimi desteği sundu. Bu destek sayesinde uygulamanız, Java veya yerel kod aracılığıyla PNG, JPEG ve WebP dosyalarından yüklenen, yerleştirilmiş geniş renk profilleriyle bit eşlemler oluşturabilir. OpenGL veya Vulkan kullanan uygulamalar doğrudan geniş renk gamı içeriği oluşturabilir (Display P3 ve scRGB ile). Bu özellik, resim ve video düzenleme uygulamaları gibi yüksek kalitede renk üretimi içeren uygulamalar oluşturmak için yararlıdır.

Geniş renk gamı modunu anlama

Geniş renk profilleri, sRGB'den daha geniş bir renk aralığını temsil edebilen Adobe RGB, Pro Photo RGB ve DCI-P3 gibi ICC profilleridir. Geniş renk profillerini destekleyen ekranlarda, resimler daha derin birincil renklere (kırmızı, yeşil ve mavi) ve daha zengin ikincil renklere (ör. macenta, yeşil ve sarı) sahip olabilir.

Uygulamanız, Android 8.0 (API düzeyi 26) veya sonraki sürümleri çalıştıran Android cihazlarda, uygulamanız bir etkinlik için geniş renk gamı renk modunu etkinleştirebilir. Böylece sistem, yerleştirilmiş geniş renk profillerine sahip bit eşlem resimlerini tanır ve doğru şekilde işler. ColorSpace.Named sınıfı, Android'in desteklediği yaygın olarak kullanılan renk alanlarının kısmi listesini sıralar.

Not: Geniş renk gamı modu etkinleştirildiğinde, etkinlik penceresi ekran bileşimi için daha fazla bellek ve GPU işleme kullanır. Geniş renk gamı modunu etkinleştirmeden önce, etkinliğin bu moddan gerçekten fayda sağlayıp sağlamayacağını dikkatlice değerlendirmelisiniz. Örneğin, fotoğrafları tam ekranda görüntüleyen bir etkinlik, geniş renk gamı modu için iyi bir adaydır, ancak küçük küçük resimleri gösteren bir etkinlik uygun değildir.

Geniş renk gamı modunu etkinleştir

Etkinliğin uyumlu cihazlarda geniş renk gamı modunda gösterilmesini istemek için colorMode özelliğini kullanın. Geniş renk gamı modunda, bir pencere daha canlı renkler göstermek için sRGB gamının dışında oluşturulabilir. Cihaz geniş renk gamı oluşturmayı desteklemiyorsa bu özelliğin bir etkisi olmaz. Uygulamanızın, belirli bir ekranın geniş renk gamına sahip olup olmadığını belirlemesi gerekiyorsa isWideColorGamut() yöntemini çağırın. Uygulamanız ayrıca isScreenWideColorGamut() işlevini de çağırabilir. Bu çağrı, yalnızca ekran geniş renk gamı özelliklerine sahipse ve cihaz geniş renk gamı renk oluşturmayı destekliyorsa true değerini döndürür.

Bir ekran, geniş renk gamı özelliğine sahip olabilir ancak renk yönetilemez. Bu durumda, sistem bir uygulamaya geniş renk gamı modunu vermez. Bir ekran renklerle yönetilmediğinde (Android'in 8.0'dan önceki tüm sürümlerinde olduğu gibi) sistem, uygulamanın çizdiği renkleri ekran gamına yeniden eşler.

Etkinliğinizde geniş renk gamını etkinleştirmek için AndroidManifest.xml dosyanızda colorMode özelliğini wideColorGamut olarak ayarlayın. Bunu, geniş renk modunu etkinleştirmek istediğiniz her etkinlik için yapmanız gerekir.

android:colorMode="wideColorGamut"

Renk modunu, setColorMode(int) yöntemini çağırıp COLOR_MODE_WIDE_COLOR_GAMUT ileterek etkinliğinizde programatik olarak da ayarlayabilirsiniz.

Geniş renk gamı içeriği oluştur

Şekil 1. Display P3 (turuncu) ve sRGB (beyaz) renk alanları

Geniş renk gamı içeriği oluşturmak için uygulamanızın geniş bir renk bit eşlemi (sRGB'den daha geniş bir renk alanı içeren bir renk profiline sahip bit eşlem) yüklemesi gerekir. Yaygın olarak kullanılan geniş renk profilleri arasında Adobe RGB, DCI-P3 ve Display P3 bulunur.

Uygulamanız getColorSpace() yöntemini çağırarak bit eşlemin renk alanını sorgulayabilir. Sistemin belirli bir renk alanını geniş yelpazede algılayıp tanımadığını belirlemek için isWideGamut() yöntemini çağırabilirsiniz.

Color sınıfı, tam sayı değerini kullanan en yaygın temsil yerine, 64 bit uzunluğundaki bir değere yerleştirilmiş dört bileşenden oluşan bir rengi temsil etmenize olanak tanır. Uzun değerler kullanarak renkleri tam sayı değerlerinden daha hassas bir şekilde tanımlayabilirsiniz. Bir rengi uzun değer olarak oluşturmanız veya kodlamanız gerekiyorsa Color sınıfındaki pack() yöntemlerinden birini kullanın.

getColorMode() yönteminin COLOR_MODE_WIDE_COLOR_GAMUT değerini döndürüp döndürmediğini kontrol ederek uygulamanızın geniş renk gamı modunu düzgün bir şekilde isteyip istemediğini doğrulayabilirsiniz (ancak bu yöntem, geniş renk gamı moduna gerçekten izin verilip verilmediğini göstermez).

Yerel kodda geniş renk gamı desteği kullanma

Bu bölümde, uygulamanız yerel kod kullanıyorsa OpenGL ve Vulkan API'leriyle geniş renk gamı modunun nasıl etkinleştirileceği açıklanmaktadır.

OpenGL

OpenGL'de geniş renk gamı modunu kullanmak için uygulamanızın aşağıdaki uzantılardan biriyle birlikte EGL 1.4 kitaplığını içermesi gerekir:

Bu özelliği etkinleştirmek için önce eglChooseConfig aracılığıyla, özelliklerde geniş renk için desteklenen üç renk arabelleği biçiminden biriyle bir GL bağlamı oluşturmanız gerekir. Geniş renk için renk arabelleği biçimi, aşağıdaki RGBA değer gruplarından biri olmalıdır:

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

Ardından, oluşturma hedeflerinizi oluştururken aşağıdaki kod snippet'inde gösterildiği gibi P3 renk alanı uzantısını isteyin:

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

Geniş renk gamı için Vulkan desteği VK_EXT_swapchain_colorspace uzantısıyla sağlanır.

Vulkan kodunuzda geniş renk desteğini etkinleştirmeden önce ilk olarak uzantının vkEnumerateInstanceExtensionProperties üzerinden desteklendiğini kontrol edin. Uzantı kullanılabiliyorsa uzantı tarafından tanımlanan ek renk alanlarını kullanan herhangi bir takas zinciri resimleri oluşturmadan önce vkCreateInstance sırasında etkinleştirmeniz gerekir.

Takas zincirini oluşturmadan önce, istediğiniz renk alanını seçmeniz, ardından mevcut fiziksel cihaz yüzeyleri arasında geçiş yapmanız ve bu renk alanı için geçerli bir renk biçimi seçmeniz gerekir.

Vulkan, Android cihazlarda aşağıdaki renk alanları ve VkSurfaceFormatKHR renk biçimleriyle geniş renk gamını destekler:

  • Vulkan geniş renk gamı renk alanları:
    • VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT
    • VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT
  • Geniş renk gamı desteğine sahip Vulkan renk biçimleri:
    • VK_FORMAT_R16G16B16A16_SFLOAT
    • VK_FORMAT_A2R10G10B10_UNORM_PACK32
    • VK_FORMAT_R8G8B8A8_UNORM

Aşağıdaki kod snippet'inde, cihazın Display P3 renk alanını destekleyip desteklemediğini nasıl kontrol edebileceğiniz gösterilmektedir:

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
}

Aşağıdaki kod snippet'inde VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT ile nasıl Vulkan takas zinciri isteğinde bulunabileceğiniz gösterilmektedir:

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