Cor ampla no Xamarin.iOS

Este artigo aborda cores amplas e como ela pode ser usada em um aplicativo Xamarin.iOS ou Xamarin.Mac.

O iOS 10 e o macOS Sierra aprimoram o suporte para formatos de pixel de longo alcance e espaços de cores de gama ampla em todo o sistema, incluindo estruturas como Core Graphics, Core Image, Metal e AVFoundation. O suporte para dispositivos com telas de cores largas é ainda mais facilitado fornecendo esse comportamento em toda a pilha de gráficos.

Catálogos de ativos

Suporte a cores amplas com catálogos de ativos

No iOS 10 e no macOS Sierra, a Apple expandiu os Catálogos de Ativos usados para incluir e categorizar o conteúdo de imagem estática no pacote do aplicativo para dar suporte a cores amplas.

O uso de Catálogos de Ativos oferece os seguintes benefícios para um aplicativo:

  • Eles fornecem a melhor opção de implantação para ativos de imagem estática.
  • Eles dão suporte à correção automática de cores.
  • Eles dão suporte à otimização automática de formato de pixel.
  • Eles dão suporte à Divisão de Aplicativos e ao Afinamento de Aplicativos, o que garante que apenas o conteúdo relevante seja entregue ao dispositivo do usuário final.

A Apple fez os seguintes aprimoramentos nos Catálogos de Ativos para suporte a cores amplas:

  • Eles dão suporte ao conteúdo de origem de 16 bits (por canal de cor).
  • Eles dão suporte à catalogação de conteúdo por gama de exibição. O conteúdo pode ser marcado para as gamas sRGB ou Display P3.

O desenvolvedor tem três opções para dar suporte a conteúdo de cores amplas em seus aplicativos:

  1. Não fazer nada – como o conteúdo de cores largas só deve ser usado em situações em que o aplicativo precisa exibir cores vívidas (em que aprimorarão a experiência do usuário), o conteúdo fora desse requisito deve ser deixado como está. Ele continuará sendo renderizado corretamente em todas as situações de hardware.
  2. Atualizar conteúdo existente para Exibir P3 – isso exige que o desenvolvedor substitua o conteúdo de imagem existente em seu Catálogo de Ativos por um novo arquivo atualizado no formato P3 e marque-o como tal no Editor de Ativos. No momento da compilação, uma imagem derivada sRGB será gerada a partir desses ativos.
  3. Fornecer conteúdo de ativo otimizado – nessa situação, o desenvolvedor fornecerá um sRGB de 8 bits e uma visão P3 de exibição de 16 bits de cada imagem no Catálogo de Ativos (marcado corretamente no editor de ativos).

Implantação do Catálogo de Ativos

O seguinte ocorrerá quando o desenvolvedor enviar um aplicativo para o App Store com Catálogos de Ativos que incluem conteúdo de imagem de cores amplas:

  • Quando o aplicativo for implantado no usuário final, o App Slicing garantirá que apenas a variante de conteúdo apropriada seja entregue ao dispositivo do usuário.
  • No dispositivo que não dá suporte a cores largas, não há nenhum custo de carga para incluir conteúdo de cores largas, pois ele nunca é enviado para o dispositivo.
  • NSImage no macOS Sierra (e posterior) selecionará automaticamente a melhor representação de conteúdo para a exibição do hardware.
  • O conteúdo exibido será atualizado automaticamente quando ou se as características de exibição de hardware dos dispositivos forem alteradas.

Armazenamento do Catálogo de Ativos

O armazenamento do Catálogo de Ativos tem as seguintes propriedades e implicações para um aplicativo:

  • No momento da compilação, a Apple tenta otimizar o armazenamento do conteúdo da imagem por meio de conversões de imagem de alta qualidade.
  • 16 bits são usados por canal de cores para conteúdo de cores largas.
  • A compactação de imagem dependente de conteúdo é usada para reduzir os tamanhos de conteúdo que podem ser entregues. Novas compactações "com perda" foram adicionadas para otimizar ainda mais os tamanhos de conteúdo.

Renderizando imagens Off-Screen no aplicativo

Com base no tipo de aplicativo que está sendo criado, ele pode permitir que o usuário inclua o conteúdo da imagem coletado da Internet ou crie conteúdo de imagem diretamente dentro do aplicativo (como um aplicativo de desenho de vetor, por exemplo).

Em ambos os casos, o aplicativo pode renderizar as imagens necessárias fora da tela em cores amplas usando recursos aprimorados adicionados ao iOS e ao macOS.

Desenhando cores largas no iOS

Antes de discutir como desenhar corretamente uma imagem colorida ampla no iOS 10, dê uma olhada no seguinte código de desenho comum do iOS:

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

    ...

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

Há problemas com o código padrão que precisarão ser resolvidos antes que ele possa ser usado para desenhar uma imagem colorida ampla. O UIGraphics.BeginImageContext (size) método usado para iniciar o desenho de imagem do iOS tem as seguintes limitações:

  • Ele não pode criar contextos de imagem com mais de 8 bits por canal de cor.
  • Ele não pode representar cores no Espaço de Cor sRGB de Intervalo Estendido.
  • Ele não tem a capacidade de fornecer uma interface para criar contextos em um espaço de cor não sRGB devido às rotinas C de baixo nível que estão sendo chamadas em segundo plano.

Para lidar com essas limitações e desenhar uma imagem colorida ampla no iOS 10, use o seguinte código:

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

A nova UIGraphicsImageRenderer classe cria um novo contexto de imagem que é capaz de lidar com o Espaço de Cor sRGB de Intervalo Estendido e tem os seguintes recursos:

  • Ela é totalmente gerenciada por cor por padrão.
  • Ele dá suporte ao Espaço de Cor sRGB de Intervalo Estendido por padrão.
  • Ele decide de forma inteligente se deve renderizar no espaço de cores sRGB ou de intervalo estendido com base nos recursos do dispositivo iOS em que o aplicativo está sendo executado.
  • Ele gerencia totalmente e automaticamente o tempo de vida do contexto de imagem (CGContext) para que o desenvolvedor não precise se preocupar em chamar comandos de contexto de início e fim.
  • Ele é compatível com o UIGraphics.GetCurrentContext() método .

O CreateImage método da UIGraphicsImageRenderer classe é chamado para criar uma imagem de cor ampla e passou um manipulador de conclusão com o contexto de imagem para desenhar. Todo o desenho é feito dentro desse manipulador de conclusão da seguinte maneira:

  • O UIColor.FromDisplayP3 método cria uma nova cor vermelha totalmente saturada no espaço de cor de exibição P3 de gama larga e é usado para desenhar a primeira metade do retângulo.
  • A segunda metade do retângulo é desenhada na cor vermelha SRGB totalmente saturada normal para comparação.

Desenhando cores largas no macOS

A NSImage classe foi expandida no macOS Sierra para dar suporte ao desenho de imagens de Cores Largas. Por exemplo:

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

Renderizando imagens na tela no aplicativo

Para renderizar imagens de cores largas na tela, o processo funciona de forma semelhante ao desenho de uma imagem de cores largas fora da tela para macOS e iOS apresentados acima.

Renderizando na tela no iOS

Quando o aplicativo precisar renderizar uma imagem em cores largas na tela no iOS, substitua o Draw método do UIView em questão como de costume. Por exemplo:

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 o iOS 10 faz com a UIGraphicsImageRenderer classe mostrada acima, ele decide de forma inteligente se deve renderizar no espaço de cores sRGB ou de intervalo estendido com base nos recursos do dispositivo iOS em que o aplicativo está sendo executado quando o Draw método é chamado. Além disso, o UIImageView foi gerenciado por cores desde o iOS 9.3 também.

Se o aplicativo precisar saber como a renderização está sendo feita em um UIView ou UIViewController, ele poderá marcar a nova DisplayGamut propriedade da UITraitCollection classe . Esse valor será uma UIDisplayGamut enumeração do seguinte:

  • P3
  • Srgb
  • Não Especificado

Se o aplicativo quiser controlar qual Espaço de Cor é usado para desenhar uma imagem, ele poderá usar uma nova ContentsFormat propriedade do CALayer para especificar o Espaço de Cor desejado. Esse valor pode ser uma CAContentsFormat enumeração do seguinte:

  • Gray8Uint
  • Rgba16Float
  • Rgba8Uint

Renderização na tela no macOS

Quando o aplicativo precisar renderizar uma imagem em cores largas na tela no macOS, substitua o DrawRect método do NSView em questão como de costume. Por exemplo:

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

Novamente, ele decide de forma inteligente se deve renderizar no espaço de cores sRGB ou de intervalo estendido com base nos recursos do hardware Mac em que o aplicativo está sendo executado quando o DrawRect método é chamado.

Se o aplicativo quiser controlar qual Espaço de Cor é usado para desenhar uma imagem, ele poderá usar uma nova DepthLimit propriedade da NSWindow classe para especificar o Espaço de Cor desejado. Esse valor pode ser uma NSWindowDepth enumeração do seguinte:

  • OneHundredTwentyEightBitRgb
  • SixtyfourBitRgb
  • TwentyfourBitRgb