Color ancho en Xamarin.iOS

En este artículo se describe el color ancho y cómo se puede usar en una aplicación de Xamarin.iOS o Xamarin.Mac.

iOS 10 y macOS Sierra mejoran la compatibilidad con formatos de píxeles de rango extendido y espacios de color de gama ancha en todo el sistema, incluidos marcos como Core Graphics, Core Image, Metal y AVFoundation. La compatibilidad con dispositivos con pantallas de color ancho se facilita aún más al proporcionar este comportamiento a lo largo de toda la pila de gráficos.

Catálogos de recursos

Compatibilidad del color ancho con catálogos de activos

En iOS 10 y macOS Sierra, Apple ha ampliado los catálogos de activos que se usan para incluir y clasificar el contenido de imágenes estáticas en el lote de la aplicación para admitir un color amplio.

El uso de catálogos de activos proporciona las siguientes ventajas para una aplicación:

  • Proporcionan la mejor opción de implementación para los recursos de imagen estáticos.
  • Admiten la corrección automática del color.
  • Admiten la optimización automática del formato de píxeles.
  • Admiten la segmentación de aplicaciones y la compresión de aplicaciones, lo que garantiza que solo se entregue el contenido pertinente al dispositivo del usuario final.

Apple ha realizado las siguientes mejoras en los catálogos de activos para obtener compatibilidad con colores anchos:

  • Admiten contenido de origen de 16 bits (por canal de color).
  • Admiten la catalogación de contenido mediante la visualización de la gama. El contenido se puede etiquetar para las gamas sRGB o Display P3.

El desarrollador tiene tres opciones para admitir contenido de color ancho en sus aplicaciones:

  1. No hacer nada: dado que el contenido de color ancho solo debe usarse en situaciones en las que la aplicación necesita mostrar colores vivos (donde mejorará la experiencia del usuario), el contenido fuera de este requisito debe dejarse tal cual. Se seguirá representando correctamente en todas las situaciones de hardware.
  2. Actualizar contenido existente para mostrar P3: esto requiere que el desarrollador reemplace el contenido de la imagen existente en su catálogo de activos por un nuevo archivo actualizado en el formato P3 y etiquetarlo como tal en el Editor de activos. En el tiempo de compilación, se generará una imagen derivada de sRGB a partir de estos recursos.
  3. Proporcionar contenido de activos optimizados: en esta situación, el desarrollador proporcionará un sRGB de 8 bits y una visión de display P3 de 16 bits de cada imagen en el catálogo de activos (etiquetada correctamente en el editor de recursos).

Implementación del catálogo de activos

Ocurrirá lo siguiente cuando el desarrollador envíe una aplicación a App Store con catálogos de activos que incluyan contenido de imagen de color ancho:

  • Cuando la aplicación se implementa en el usuario final, la segmentación de aplicaciones garantizará que solo se entregue la variante de contenido adecuada al dispositivo del usuario.
  • En el dispositivo que no admite el color ancho, no hay ningún costo de carga para incluir contenido de color ancho, ya que nunca se envía al dispositivo.
  • NSImage en macOS Sierra (y versiones posteriores) seleccionará automáticamente la mejor representación de contenido para la pantalla del hardware.
  • El contenido mostrado se actualizará automáticamente cuando cambie o si cambian las características de visualización del hardware de los dispositivos.

Almacenamiento del catálogo de activos

El almacenamiento del catálogo de activos tiene las siguientes propiedades e implicaciones para una aplicación:

  • En el tiempo de compilación, Apple intenta optimizar el almacenamiento del contenido de la imagen a través de conversiones de imágenes de alta calidad.
  • Se usan 16 bits por canal de color para contenido de color ancho.
  • La compresión de imágenes dependientes del contenido se usa para reducir los tamaños de contenido de entrega. Se han agregado nuevas compresiones de "pérdida" para optimizar aún más los tamaños de contenido.

Representación de imágenes fuera de pantalla en la aplicación

En función del tipo de aplicación que se crea, podría permitir al usuario incluir contenido de imagen que ha recopilado de Internet o crear contenido de imagen directamente dentro de la aplicación (por ejemplo, una aplicación de dibujo vectorial).

En ambos casos, la aplicación puede representar las imágenes necesarias fuera de pantalla en color ancho mediante características mejoradas agregadas tanto a iOS como a macOS.

Dibujar color ancho en iOS

Antes de analizar cómo dibujar correctamente una imagen de color ancho en iOS 10, eche un vistazo al siguiente código de dibujo común de iOS:

public UIImage DrawWideColorImage ()
{
    var size = new CGSize (250, 250);
    UIGraphics.BeginImageContext (size);

    ...

    UIGraphics.EndImageContext ();
    return image = UIGraphics.GetImageFromCurrentImageContext ();
    }

Hay problemas con el código estándar que deberá solucionarse antes de poder usarse para dibujar una imagen de color ancha. El método UIGraphics.BeginImageContext (size) usado para iniciar el dibujo de imágenes de iOS tiene las siguientes limitaciones:

  • No puede crear contextos de imagen con más de 8 bits por canal de color.
  • No puede representar colores en el espacio de color sRGB de rango extendido.
  • No tiene la capacidad de proporcionar una interfaz para crear contextos en un espacio de color que no sea sRGB debido a las rutinas de C de bajo nivel a las que se llama en segundo plano.

Para controlar estas limitaciones y dibujar una imagen de color ancho en iOS 10, use el código siguiente en su lugar:

public UIImage DrawWideColorImage ()
{
    var size = new CGSize (250, 250);
    var render = new UIGraphicsImageRenderer (size);

    var image = render.CreateImage ((UIGraphicsImageRendererContext context) => {
        var bounds = context.Format.Bounds;
        CGRect slice;
        CGRect remainder;
        bounds.Divide (bounds.Width / 2, CGRectEdge.MinXEdge, out slice, out remainder);

        var redP3 = UIColor.FromDisplayP3 (1.0F, 0.0F, 0.0F, 1.0F);
        redP3.SetColor ();
        context.FillRect (slice);

        var redRGB = UIColor.Red;
        redRGB.SetColor ();
        context.FillRect (remainder);
    });

    // Return results
    return image;
}

La nueva clase UIGraphicsImageRenderer crea un nuevo contexto de imagen que es capaz de controlar el espacio de color sRGB de rango extendido y tiene las siguientes características:

  • Está totalmente administrado de forma predeterminada.
  • Admite el espacio de color sRGB de rango extendido de forma predeterminada.
  • Decide de forma inteligente si debe representarse en el sRGB o en el espacio de colores de rango extendido sRGB en función de las funcionalidades del dispositivo iOS en el que se ejecuta la aplicación.
  • Administra completa y automáticamente la duración del contexto de la imagen (CGContext) para que el desarrollador no tenga que preocuparse por llamar a los comandos de contexto inicial y final.
  • Es compatible con el método UIGraphics.GetCurrentContext().

Se llama al método CreateImage de la clase UIGraphicsImageRenderer para crear una imagen de color ancho y pasar un controlador de finalización con el contexto de imagen en el que dibujar. Todo el dibujo se realiza dentro de este controlador de finalización de la siguiente manera:

  • El método UIColor.FromDisplayP3 crea un nuevo color rojo totalmente saturado en el espacio de color de pantalla de gama ancha P3 y se usa para dibujar la primera mitad del rectángulo.
  • La segunda mitad del rectángulo se dibuja en el color rojo normal sRGB totalmente saturado para la comparación.

Dibujar color ancho en macOS

La clase NSImage se ha expandido en macOS Sierra para admitir el dibujo de imágenes de color ancho. Por ejemplo:

var size = CGSize(250,250);
var wideColorImage = new NSImage(size, false, (drawRect) =>{
    var rects = drawRect.Divide(drawRect.Size.Width/2,CGRect.MinXEdge);

    var color = new NSColor(1.0, 0.0, 0.0, 1.0).Set();
    var path = new NSBezierPath(rects.Slice).Fill();

    color = new NSColor(1.0, 0.0, 0.0, 1.0).Set();
    path = new NSBezierPath(rects.Remainder).Fill();

    // Return modified
    return true;
});

Representación de imágenes en pantalla en la aplicación

Para representar imágenes de color ancho en pantalla, el proceso funciona de forma similar a dibujar una imagen de color de todo pantalla para macOS e iOS presentada anteriormente.

Representación en pantalla en iOS

Cuando la aplicación necesita representar una imagen en color ancho en pantalla en iOS, a el método Draw del UIView en cuestión como de costumbre. Por ejemplo:

using System;
using UIKit;
using CoreGraphics;

namespace MonkeyTalk
{
    public class MonkeyView : UIView
    {
        public MonkeyView ()
        {
        }

        public override void Draw (CGRect rect)
        {
            base.Draw (rect);

            // Draw the image to screen
        ...
        }
    }
}

Como iOS 10 hace con la clase UIGraphicsImageRenderer mostrada anteriormente, decide inteligentemente si debe representarse en el espacio de color sRGB o de intervalo extendido sRGB en función de las funciones del dispositivo iOS en el que se ejecuta la aplicación cuando se llama al método Draw. Además, también se ha administrado el color de UIImageView desde iOS 9.3.

Si la aplicación necesita saber cómo se realiza la representación en UIView o UIViewController, puede comprobar la nueva propiedad DisplayGamut de la clase UITraitCollection. Este valor será una enumeración UIDisplayGamut de lo siguiente:

  • P3
  • Srgb
  • Sin especificar

Si la aplicación quiere controlar qué espacio de color se usa para dibujar una imagen, puede usar una nueva propiedad ContentsFormat de CALayer para especificar el espacio de color deseado. Este valor puede ser una enumeración CAContentsFormat de lo siguiente:

  • Gray8Uint
  • Rgba16Float
  • Rgba8Uint

Representación en pantalla en macOS

Cuando la aplicación necesita representar una imagen en color ancho en pantalla en macOS, invalida el DrawRect del NSView en cuestión como de costumbre. Por ejemplo:

using System;
using AppKit;
using CoreGraphics;
using CoreAnimation;

namespace MonkeyTalkMac
{
    public class MonkeyView : NSView
    {
        public MonkeyView ()
        {
        }

        public override void DrawRect (CGRect dirtyRect)
        {
            base.DrawRect (dirtyRect);

            // Draw graphics into the view
            ...
        }
    }
}

De nuevo, decide inteligentemente si debe representarse en el sRGB o el espacio de color de intervalo extendido sRGB en función de las funcionalidades del hardware Mac en el que se ejecuta la aplicación cuando se llama al método DrawRect.

Si la aplicación quiere controlar qué espacio de color se usa para dibujar una imagen, puede usar una nueva propiedad DepthLimit de la clase NSWindow para especificar el espacio de color deseado. Este valor puede ser una enumeración NSWindowDepth de lo siguiente:

  • OneHundredTwentyEightBitRgb
  • SixtyfourBitRgb
  • TwentyfourBitRgb