تحسين الرسومات باستخدام ألوان عريضة

قدّم الإصدار Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات) دعمًا لإدارة الألوان في مساحات ألوان إضافية إلى جانب نموذج أحمر أخضر أزرق (sRGB) عادي لعرض الرسومات على الأجهزة ذات الشاشات المتوافقة. ومن خلال هذا الدعم، يمكن لتطبيقك عرض الصور النقطية بتنسيقات ألوان عريضة مضمّنة يتم تحميلها من ملفات PNG وJPEG وWebP عبر لغة Java أو رمز أصلي. يمكن للتطبيقات التي تستخدم OpenGL أو Vulkan إخراج محتوى عريض من مجموعة ألوان مباشرةً (باستخدام Display P3 وscRGB). وهذه الإمكانية مفيدة في إنشاء التطبيقات التي تتضمن إعادة إنتاج ألوان عالية الدقة، مثل تطبيقات تعديل الصور والفيديوهات.

فهم وضع مجموعة الألوان العريضة

الملفات الشخصية للألوان العريضة هي ملفات ICC، مثل Adobe RGB و Pro Photo RGB وDCI-P3، والتي يمكنها تمثيل نطاق ألوان أوسع من sRGB. يمكن للشاشات التي تتيح استخدام ملفات تعريف الألوان العريضة أن تعرض الصور بألوان أساسية أغمق (الأحمر والأخضر والأزرق)، بالإضافة إلى ألوان ثانوية أغنى (مثل الأرجواني والأزرق الفاتح والأصفر).

على أجهزة Android التي تعمل بالإصدار 8.0 من نظام التشغيل Android (المستوى 26 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث التي تتوافق مع هذا الوضع، يمكن لتطبيقك تفعيل وضع مجموعة الألوان العريضة لنشاط يتعرّف على صور الصور النقطية ويعالجها بشكل صحيح باستخدام ملفات تعريف ألوان عريضة مضمّنة. تسرد الفئة ColorSpace.Named قائمة جزئية بمساحات الألوان الشائعة الاستخدام المتوافقة مع Android.

ملاحظة: عند تفعيل وضع مجموعة الألوان العريضة، ستستهلك نافذة النشاط المزيد من عمليات المعالجة في الذاكرة ووحدة معالجة الرسومات لتكوين الشاشة. قبل تمكين وضع مجموعة الألوان العريضة، يجب أن تفكر بعناية في ما إذا كان النشاط يستفيد منه حقًا أم لا. على سبيل المثال، يعد النشاط الذي يعرض الصور في وضع ملء الشاشة مرشحًا جيدًا لوضع مجموعة الألوان العريضة، أما النشاط الذي يعرض الصور المصغّرة الصغيرة فهو غير مناسب.

تفعيل وضع مجموعة الألوان العريضة

استخدِم السمة colorMode لطلب عرض النشاط في وضع "مجموعة الألوان" العريضة على الأجهزة المتوافقة. في وضع مجموعة الألوان العريضة، يمكن عرض نافذة خارج مجموعة sRGB لعرض ألوان أكثر حيوية. وإذا كان الجهاز لا يتيح عرض مجموعة الألوان الواسعة، لن يكون لهذه السمة أي تأثير. إذا كان تطبيقك يحتاج إلى تحديد ما إذا كانت شاشة معيّنة تتوافق مع مجموعة ألوان عريضة، عليك طلب الإجراء isWideColorGamut(). يمكنك أيضًا استدعاء الدالة isScreenWideColorGamut()، الذي يعرض true فقط إذا كانت الشاشة متوافقة مع مجموعة ألوان عريضة وكان الجهاز يتيح عرض مجموعة ألوان عريضة.

قد تكون شاشة العرض متوافقة مع مجموعة ألوان عريضة ولكنها غير مُدارة حسب الألوان، وفي هذه الحالة، لن يمنح النظام التطبيق وضع مجموعة الألوان العريضة. عندما لا تكون الشاشة مُدارة بالألوان، كما كان الحال مع جميع إصدارات Android السابقة للإصدار 8.0، يعيد النظام ضبط الألوان التي رسمها التطبيق على السلسلة اللونية للشاشة.

لتفعيل مجموعة الألوان العريضة في نشاطك، اضبط السمة colorMode على wideColorGamut في ملف AndroidManifest.xml. عليك القيام بذلك لكل نشاط تريد تفعيل وضع الألوان العريض له.

android:colorMode="wideColorGamut"

يمكنك أيضًا ضبط وضع الألوان آليًا في نشاطك من خلال استدعاء طريقة setColorMode(int) وتمرير COLOR_MODE_WIDE_COLOR_GAMUT.

عرض محتوى مجموعة ألوان عريضة

الشكل 1. عرض P3 (اللون البرتقالي) مقابل مساحات الألوان sRGB (الأبيض)

لعرض محتوى مجموعة ألوان عريضة، يجب أن يحمل تطبيقك صورة نقطية ذات ألوان عريضة، وهي صورة نقطية ذات ملف تعريف لوني يحتوي على مساحة لون أعرض من sRGB. تشمل الملفات الشخصية للألوان الواسعة الشائعة Adobe RGB وDCI-P3 وDisplay P3.

يمكن لتطبيقك الاستعلام عن مساحة لون الصورة النقطية من خلال استدعاء getColorSpace(). ولتحديد ما إذا كان النظام يتعرّف على مساحة لون معيّنة بأنّها سلسلة واسعة، يمكنك استدعاء الطريقة isWideGamut().

تسمح لك الفئة Color بتمثيل اللون من خلال أربعة مكوّنات معبأة في قيمة بطول 64 بت، بدلاً من التمثيل الأكثر شيوعًا الذي يستخدم قيمة عدد صحيح. باستخدام القيم الطويلة، يمكنك تحديد الألوان بدقة أكثر من قيم الأعداد الصحيحة. إذا كنت بحاجة إلى إنشاء لون أو ترميزه كقيمة طويلة، استخدِم إحدى طرق pack() في الفئة Color.

يمكنك التحقق مما إذا كان تطبيقك قد طلب وضع مجموعة الألوان العريضة بشكلٍ صحيح، وذلك من خلال التحقق من أن طريقة getColorMode() تعرض COLOR_MODE_WIDE_COLOR_GAMUT (مع ذلك، لا تشير هذه الطريقة إلى ما إذا كان وضع مجموعة الألوان العريضة قد تم منحه فعليًا أم لا).

استخدام مجموعة الألوان العريضة في الرموز البرمجية الأصلية

يوضّح هذا القسم كيفية تفعيل وضع مجموعة الألوان العريضة باستخدام واجهات برمجة تطبيقات OpenGL وVulkan إذا كان تطبيقك يستخدم رمزًا برمجيًا أصليًا.

برنامج OpenGL

لاستخدام وضع مجموعة الألوان العريضة في OpenGL، يجب أن يتضمن تطبيقك مكتبة EGL 1.4 مع إحدى الإضافات التالية:

لتفعيل هذه الميزة، يجب أولاً إنشاء سياق GL من خلال eglChooseConfig، باستخدام أحد تنسيقات المخزن المؤقت الثلاثة المتوافقة للون العريض في السمات. يجب أن يكون تنسيق مخزن الألوان المؤقت للون العريض إحدى مجموعات قيم RGBA التالية:

  • 8، 8، 8، 8
  • 10، 10، 10، 2
  • FP16 وFP16 وFP16 وFP16

ثم اطلب إضافة مساحة اللون P3 عند إنشاء أهداف العرض، كما هو موضح في مقتطف الرمز التالي:

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 لسلسلة الألوان الواسعة من خلال الإضافة VK_EXT_swapchain_colorspace.

قبل تفعيل ميزة دعم الألوان العريضة في رمز Vulkan، تأكّد أولاً من أنّ الإضافة متوافقة من خلال vkEnumerateInstanceExtensionProperties. وإذا كانت الإضافة متاحة، يجب تفعيلها أثناء vkCreateInstance قبل إنشاء أي صور لسلسلة التبديل تستخدم مساحات الألوان الإضافية التي تحدّدها الإضافة.

قبل إنشاء سلسلة التبديل، تحتاج إلى اختيار مساحة اللون المطلوبة، ثم التنقل عبر أسطح الجهاز الفعلية المتاحة واختيار تنسيق لون صالح لمساحة اللون تلك.

على أجهزة Android، يتوافق Vulkan مع مجموعة ألوان عريضة مع مساحات الألوان التالية وVkSurfaceFormatKHR تنسيقات الألوان:

  • مساحات الألوان العريضة من Vulkan:
    • VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT
    • VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT
  • تنسيقات ألوان Vulkan مع إتاحة مجموعة ألوان واسعة:
    • VK_FORMAT_R16G16B16A16_SFLOAT
    • VK_FORMAT_A2R10G10B10_UNORM_PACK32
    • VK_FORMAT_R8G8B8A8_UNORM

يوضح مقتطف الرمز التالي كيفية التحقق من توافق الجهاز مع مساحة لون العرض 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
}

يعرض مقتطف الرمز التالي كيفية طلب سلسلة تبديل Vulkan باستخدام 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;
}