Android 8.0 (API level 26) memperkenalkan dukungan pengelolaan warna untuk ruang warna selain RGB standar (sRGB) untuk merender grafis pada perangkat dengan tampilan yang kompatibel. Dengan dukungan ini, aplikasi Anda dapat merender bitmap dengan profil warna lebar tersemat yang dimuat dari file PNG, JPEG, dan WebP melalui Java atau kode native. Aplikasi yang menggunakan OpenGL atau Vulkan dapat langsung menghasilkan konten wide color gamut (menggunakan Display P3 dan scRGB). Kemampuan ini berguna untuk membuat aplikasi yang melibatkan reproduksi warna {i>high fidelity<i}, seperti gambar dan video aplikasi pengeditan.
Memahami mode wide color gamut
Profil warna yang lebar adalah Profil ICC, seperti Adobe RGB, Pro Photo RGB, dan DCI-P3, yang merupakan yang mampu merepresentasikan rentang warna yang lebih luas daripada sRGB. Layar yang mendukung profil warna lebar dapat menampilkan gambar dengan warna primer yang lebih dalam (merah, hijau, dan biru) serta warna sekunder yang lebih kaya (seperti magenta, cyan, dan kuning).
Pada perangkat Android yang menjalankan Android 8.0 (API level 26) atau yang lebih tinggi yang mendukungnya, aplikasi Anda dapat
mengaktifkan mode warna wide color gamut untuk aktivitas tempat sistem mengenali dan
memproses gambar bitmap dengan benar menggunakan profil warna lebar yang tersemat. Class
ColorSpace.Named
mengenumerasi sebagian daftar ruang warna
yang biasa digunakan dan didukung Android.
Catatan: Jika mode wide color gamut diaktifkan, jendela aktivitas akan menggunakan lebih banyak memori dan pemrosesan GPU untuk komposisi layar. Sebelum mengaktifkan wide color gamut Anda harus mempertimbangkan dengan cermat apakah aktivitas tersebut benar-benar memperoleh manfaat. Misalnya, aktivitas yang menampilkan foto dalam layar penuh adalah kandidat yang cocok untuk mode wide color gamut, tetapi aktivitas yang menampilkan thumbnail kecil tidak.
Mengaktifkan mode wide color gamut
Gunakan atribut colorMode
untuk meminta aktivitas ditampilkan
dalam mode gamut warna yang luas di perangkat yang kompatibel. Dalam mode gamut warna yang luas, jendela dapat merender
di luar gamut sRGB untuk menampilkan warna yang lebih cerah. Jika perangkat tidak mendukung rendering gamut
warna yang luas, atribut ini tidak akan memiliki pengaruh apa pun. Jika aplikasi Anda perlu menentukan apakah suatu
layarnya mampu menampilkan {i>wide color gamut<i}, panggil
Metode isWideColorGamut()
. Aplikasi Anda juga dapat memanggil
isScreenWideColorGamut()
, yang menampilkan true
hanya jika layar mampu menampilkan wide color gamut dan perangkat mendukung rendering warna
wide color gamut.
Layar mungkin mampu menampilkan {i>wide color gamut<i} tetapi tidak {i>color-managed<i}, dalam hal ini, sistem tidak akan memberi aplikasi mode wide color gamut. Saat layar tidak dikelola warna —seperti yang terjadi untuk semua versi Android sebelum 8.0—sistem akan memetakan ulang warna yang digambar oleh aplikasi ke gamut tampilan.
Untuk mengaktifkan wide color gamut dalam aktivitas Anda, tetapkan atribut colorMode
ke wideColorGamut
dalam file AndroidManifest.xml
. Anda
harus melakukan langkah ini untuk setiap aktivitas yang ingin Anda aktifkan mode warna lebarnya.
android:colorMode="wideColorGamut"
Anda juga dapat menetapkan mode warna secara terprogram dalam aktivitas dengan memanggil
metode setColorMode(int)
dan meneruskan
COLOR_MODE_WIDE_COLOR_GAMUT
.
Merender konten wide color gamut
Untuk merender konten wide color gamut, aplikasi Anda harus memuat bitmap warna lebar, yaitu bitmap dengan profil warna yang berisi ruang warna yang lebih luas dari sRGB. Profil warna lebar yang umum mencakup Adobe RGB, DCI-P3, dan Display P3.
Aplikasi Anda dapat mengkueri ruang warna bitmap, dengan memanggil
getColorSpace()
. Untuk menentukan apakah sistem mengenali
ruang warna tertentu menjadi gamut lebar (wide gamut), Anda bisa memanggil
Metode isWideGamut()
.
Class Color
memungkinkan Anda merepresentasikan warna dengan empat komponen
dikemas ke dalam nilai panjang 64-bit, alih-alih
representasi paling umum yang menggunakan bilangan bulat
dengan sejumlah nilai. Dengan nilai panjang, Anda dapat menentukan warna dengan
lebih presisi daripada dengan nilai bilangan bulat. Jika Anda perlu membuat atau mengenkode warna sebagai nilai yang panjang, gunakan
salah satu metode pack()
di class Color
.
Anda dapat memverifikasi apakah aplikasi telah meminta mode wide color gamut dengan benar, dengan memeriksa apakah
metode getColorMode()
menampilkan
COLOR_MODE_WIDE_COLOR_GAMUT
(tetapi metode ini tidak menunjukkan
apakah mode wide color gamut benar-benar diberikan atau tidak).
Menggunakan dukungan wide color gamut dalam kode native
Bagian ini menjelaskan cara mengaktifkan mode wide color gamut dengan API OpenGL dan Vulkan jika aplikasi Anda menggunakan kode native.
OpenGL
Untuk menggunakan mode gamut warna yang luas di OpenGL, aplikasi Anda harus menyertakan pustaka EGL 1.4 dengan salah satu ekstensi berikut:
Untuk mengaktifkan fitur ini, Anda harus membuat konteks GL terlebih dahulu melalui
eglChooseConfig
, dengan salah satu dari tiga format buffering warna
yang didukung untuk warna lebar pada atribut. Format buffering warna untuk warna lebar
harus berupa salah satu kumpulan nilai RGBA berikut:
- 8, 8, 8, 8
- 10, 10, 10, 2
- FP16, FP16, FP16, FP16
Lalu, minta ekstensi ruang warna P3 saat membuat target render, seperti yang ditampilkan dalam cuplikan kode berikut:
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
Dukungan Vulkan untuk wide color gamut disediakan melalui
VK_EXT_swapchain_colorspace
.
Sebelum mengaktifkan dukungan warna lebar pada kode Vulkan Anda, periksa terlebih dahulu apakah
ekstensi didukung melalui
vkEnumerateInstanceExtensionProperties
.
Jika ekstensi tersedia, Anda harus mengaktifkannya selama
vkCreateInstance
sebelum membuat gambar swapchain apa pun yang
menggunakan ruang warna tambahan yang ditentukan oleh ekstensi.
Sebelum membuat swapchain, Anda harus memilih ruang warna yang Anda inginkan, lalu ulang melalui antarmuka perangkat fisik yang tersedia dan pilih format warna yang valid untuk ruang warna tersebut.
Pada perangkat Android, Vulkan mendukung wide color gamut dengan ruang warna dan
Format warna VkSurfaceFormatKHR
:
- Ruang warna wide color gamut Vulkan:
VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT
VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT
- Format warna Vulkan dengan dukungan wide color gamut:
VK_FORMAT_R16G16B16A16_SFLOAT
VK_FORMAT_A2R10G10B10_UNORM_PACK32
VK_FORMAT_R8G8B8A8_UNORM
Cuplikan kode berikut menunjukkan cara memeriksa apakah perangkat mendukung ruang warna 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 }
Cuplikan kode berikut menunjukkan cara meminta swapchain Vulkan dengan
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; }