Introdução O .NET Compact Framework é uma API excelente, senão a melhor, para dispositivos móveis. Seu mecanismo gráfico é fortemente acelerado para aumentar a velocidade de renderização e reduzir o consumo de memória. No entanto, parece longe de atender às crescentes demandas dos usuários por uma melhor experiência gráfica. Tentar obter alguns dos recursos avançados de renderização de gráficos vetoriais no .NET Compact Framework pode ser uma tarefa tediosa. Os desenvolvedores têm duas opções:
1. Usar código nativo. Por exemplo, a API do jogo Pocket PC pode ser uma boa escolha. Seu desempenho é impressionante. Para obter mais informações, consulte um artigo muito abrangente em: http://msdn.microsoft.com/mobility/samples/default.aspx?pull=/library/en-us/dnnetcomp/html/gmangame. O problema é que o código nativo não suporta renderização de gráficos vetoriais e não é compatível com alguns dispositivos. Além disso, pode não funcionar com emuladores de Pocket PC. Você pode imaginar como é difícil depurar tal programa.
2. Aguarde o lançamento do mecanismo gráfico móvel da próxima geração. Até onde eu sei, o Windows CE 5 conterá um poderoso mecanismo Direct3D Mobile. Esta é uma boa notícia para desenvolvedores de jogos móveis, mas Direct3D não é adequado para gráficos bidimensionais. É muito complexo para ser usado em aplicações gerais.
O que precisamos é de um mecanismo gráfico 2D poderoso e fácil de usar como o GDI+. Portanto, desenvolvi o projeto XrossOne GDI+ do zero. Ele foi escrito inteiramente em código gerenciado C# e não contém nenhum código nativo ou inseguro. Depois de meses de trabalho duro, posso finalmente fornecer a versão original para download no início deste artigo.
Introdução Desde o início deste projeto, sempre tive em mente que o mecanismo XrossOne GDI+ deveria ser neutro em diferentes dispositivos portáteis e plataformas. Como resultado, é compatível com Pocket PC, Windows CE, Smartphones, Windows .NET e Mono. Você pode copiar o mesmo tempo de execução para um destino diferente e ainda funcionará bem.
A tabela a seguir resume a arquitetura geral.
Namespace da camadaXrossOne GDI+ API XrossOne.Drawing
Motor gráfico bidimensional baseado em ponto fixo XrossOne.DrawingFP
16.16 Mecanismo de cálculo de ponto fixo XrossOne.FixedPoint
Existem três camadas no XrossOne GDI+. O nível mais baixo é o "mecanismo de computação de ponto fixo 16.16". Uma das classes principais – MathFP – é adaptada da biblioteca Beartronics J2ME. Várias funções foram otimizadas, incluindo sqrt, atan e PointFP.Distancecalculation. No namespace XrossOne.FixedPoint, existem três outras classes: SingleFP, DoubleFP e MatrixFP. SingleFP é uma classe auxiliar para números de ponto fixo 16.16. Ele fornece conveniência para conversão entre tipos de ponto fixo e tipos padrão (int, float, string). MatrixFP foi escrito para transformações 2D de ponto fixo. Como os cálculos de ponto fixo são menos precisos, alguma precisão pode ser perdida com transformações em cascata. Por exemplo, na maioria dos casos, duas operações de inversão não podem restaurar a matriz original. DoubleFP existe para completar a biblioteca, mas ainda não é utilizado.
"Mecanismo gráfico bidimensional baseado em ponto fixo" é o núcleo do XrossOne GDI+. Ele implementa muitos algoritmos gráficos vetoriais complexos, como desenho suavizado, decoração de extremidades/juntas de linha, transformações 2D, preenchimentos de gradiente, composição de canal alfa e muito mais. A maioria dos recursos avançados do GDI+ nativo podem ser encontrados aqui. No entanto, você só deve usá-lo diretamente em alguns casos porque sua interface baseada em ponto fixo não é amigável ao programador, mas não se preocupe muito com esta situação. Existe uma API bem encapsulada disponível. Você pode encontrá-los no namespace XrossOne.Drawing. As classes em XrossOne.Drawing são muito semelhantes às classes em System.Drawing, exceto que cada classe possui um “X” no final. Por exemplo, a classe XrossOne.Drawing.PenX é equivalente a System.Drawing.Pen. Existe um pequeno truque para converter programas GDI+ em XrossOne GDI+. Na seção de uso, renomeie as classes XrossOne GDI+ para suas classes equivalentes. Por exemplo:
usando Pen = XrossOne.Drawing.PenX;
usando LinearGradientBrush = XrossOne.Drawing.LinearGradientBrushX;
usando Matrix = XrossOne.Drawing.MatrixX;
Principais recursos Desenho de gráficos vetoriais com suavização de serrilhado
Todos os tipos de formas geométricas bidimensionais podem ser renderizados através do XrossOne Mobile GDI+, como segmentos de linha, retângulos, polígonos, elipses, setores, splines de Bezier, splines cardinais, etc. No entanto, setores, splines de Bezier e splines de base não estão disponíveis no .NET Compact Framework. Além disso, todos os gráficos são suavizados automaticamente quando renderizados. Isso ajuda a obter uma qualidade super suave. No .NET Compact Framework, a largura do pincel é fixada em 1 pixel. Esta limitação não existe no XrossOne GDI+. Diferentes tamanhos de pincéis podem ser aplicados nos contornos de todas as formas, conforme mostrado na Figura 1.
Figura 1. Desenho gráfico vetorial com suavização de serrilhado
Exemplo de código 1
//Limpa o fundo e redefine o estado de transformação
gx.Clear(Cor.Branco);
gx.ResetTransform();
//Desenha uma grade inclinada como plano de fundo
Caneta PenX = new PenX(Utils.FromArgb(0x40, Color.LightGray), 5);
for (int i = -Altura; i <Largura + Altura; i+=20)
{
gx.DrawLine(caneta, i, 0, i + Altura, Altura);
gx.DrawLine(caneta, i, 0, i - Altura, Altura);
}
//Desenhe um retângulo DarkMagenta com uma caneta de 10,5 pixels
Cor c = Utils.FromArgb(0x80, Color.DarkMagenta);
caneta = nova PenX(c, 10,5f);
gx.DrawRectangle(caneta, 50, 20, 150, 200);
//Preenche um retângulo VerdeAmarelo
c = Utils.FromArgb(0xA0, Color.GreenYellow);
Pincel BrushX = novo SolidBrushX(c);
gx.FillRectangle(pincel, 120, 50, 90, 150);
//Desenhe uma elipse BlueViolet com uma caneta de 10,5 pixels
c = Utils.FromArgb(0x80, Color.BlueViolet);
caneta = nova PenX(c, 10,5f);
gx.DrawEllipse(caneta, 50, 20, 150, 80);
//Preenche uma elipse vermelha
c = Utils.FromArgb(0xA0, Color.Red);
pincel = novo SolidBrushX(c);
gx.FillEllipse(pincel, 20, 50, 80, 150);
//Desenhe uma torta HotPink de 156,5 graus a -280,9 graus
caneta.Color = Utils.FromArgb(0xA0, Color.HotPink);
gx.DrawPie(caneta, 3,6f, 120,3f, 200,8f, 130,1f, 156,5f, -280,9f);
//Desenha curvas de Bézier Laranja
c = Utils.FromArgb(0xA0, Color.Orange);
caneta = nova PenX(c, 16);
Ponto inicial = new Point(70, 100);
Controle de ponto1 = novo Ponto(100, 10);
Controle de ponto2 = novo Ponto(150, 50);
Ponto final1 = novo Ponto(200, 200);
Controle de ponto3 = novo Ponto(100, 150);
Controle de ponto4 = novo Ponto(50, 200);
Ponto final2 = novo Ponto(10, 150);
Ponto[] bezierPoints ={início, controle1, controle2, fim1, controle3, controle4, fim2};
caneta.EndCap = LineCapX.Round;
gx.DrawBeziers(caneta, bezierPoints);
//Atualizar
Invalidar();
A saída de gráficos vetoriais do XrossOne GDI+ e do GDI+ nativo é idêntica, com exceção dos splines de raiz. Meu algoritmo foi retirado do artigo Smoothing Algorithm Using Bezier Curves, de Jean-Yves Queinec. Portanto, você poderá encontrar algumas diferenças entre suas saídas, conforme mostrado na Figura 2 abaixo.
Figura 2. Saída de DrawCurve/DrawClosedCurve
Embora a maioria das funções de renderização de gráficos vetoriais tenha sido implementada, ainda há algum trabalho a ser feito. Algumas funções (DrawString, DrawImage, DrawPath, etc.) não estarão disponíveis até a próxima versão.
preenchimento gradiente
Existem cinco pincéis no GDI+ nativo: SolidBrush, LinearGradientBrush, PathGradientBrush, TextureBrush e HatchBrush. Porém, nesta versão, apenas SolidBrush e LinearGradientBrush estão disponíveis. XrossOne GDI+ suporta RadialGradientBrush, mas não PathGradientBrush. A Figura 5 abaixo demonstra um preenchimento gradiente.
Figura 5. Preenchimento gradiente
Exemplo de código 4
//Limpa o fundo e redefine o estado de transformação
gx.Clear(Cor.Branco);
gx.ResetTransform();
//Preenche um retângulo com um LinearGradientBrushX preto e branco
Retângulo r = novo Retângulo(20, 50, 300, 100);
Cor c1 = Cor.Preto;
Cor c2 = Cor.Branco;
PincelX pincel1 = novo LinearGradientBrushX(r, c1, c2, 30F);
gx.FillRectangle(pincel1, r);
//Preenche um retângulo com um LinearGradientBrushX de 7 cores
r = novo retângulo(90, 100, 150, 100);
LinearGradientBrushX br = novo LinearGradientBrushX(r,Color.Black,Color.Black, 60F);
ColorBlendX cb = new ColorBlendX();
cb.Positions=new float[7];
int i=0;
para(float f=0;f<=1;f+=1.0f/6)
cb.Posições[i++]=f;
cb.Colors=nova cor[]
{Cor.Vermelho,Cor.Laranja,Cor.Amarelo,Cor.Verde,Cor.Azul,Cor.Índigo,Cor.Violeta};
br.InterpolationColors=cb;
gx.TranslateTransform(160, 10);
gx.RotateTransform(60F);
gx.FillRectangle(br, r);
//Preenche um retângulo com um RadialGradientBrushX de 7 cores
rY += 50;
Pincel RadialGradientBrushX2 = novo RadialGradientBrushX(r, Color.Black,Color.Black, 220F);
pincel2.InterpolationColors = cb;
gx.RotateTransform(-45F);
gx.TranslateTransform(-200, -170);
gx.FillRectangle(pincel2, r);
//Atualizar
Invalidar();
Composição de canal alfa
A estrutura Color no namespace System.Drawing está disponível no .NET Framework e no .NET Compact Framework. A diferença é que o componente alfa está desabilitado e o valor Hue-Saturation-Brightness (HSB) não está disponível no .NET Compact Framework. Felizmente, a composição de canal alfa funciona perfeitamente com o XrossOne GDI+ (como você pode ter deduzido do exemplo gráfico anterior).
desempenho 3,505 ms 1,602 ms 118,8 % DrawCurve 4,006 ms 1,402 ms 185,7% DrawPie 6,810 ms 2,003 ms 240,0% TranslateTransform 10,615 ms 3,405 ms 2 11,7% ScaleTransform 4,106 ms 0,801 ms 412,6 % RotateTransform 7,811 ms 1,803 ms 333,2% LinearGradient (1) 9,013 ms 2,103 ms 328,6% LinearGradient (2) 8,012 ms 1,803 ms 344,4%
É verdade que as CPUs de PCs portáteis costumam ser muito menos potentes que as CPUs de PCs padrão. Cálculos pesados podem tornar os dispositivos portáteis menos responsivos, o que pode ser frustrante para os usuários. Em outras palavras, o desempenho é fundamental para o software de dispositivos portáteis. Portanto, antes de usar o XrossOne Mobile GDI+ em uma situação grave, você pode querer analisar seu desempenho geral. Como a maioria das funções equivalentes no GDI+ para o .NET Compact Framework não estão disponíveis, os benchmarks foram realizados entre o XrossOne Mobile GDI+ e o GDI+ para o .NET Framework. Os testes foram realizados nas seguintes categorias: renderização de gráficos vetoriais, transformações 2D e preenchimentos de gradiente. Os cenários de teste foram executados nas mesmas condições. Você pode encontrar os programas de benchmark no pacote de download e visualizar rapidamente sua saída gráfica em http://www.xrossone.com/projects.php?menu=4.
O XrossOne Mobile GDI+ é escrito inteiramente em código gerenciado C# e seu desempenho geral é aceitável (veja a tabela abaixo), embora as transformações 2D e os preenchimentos de gradiente precisem de otimização adicional em versões futuras.
Solução 66,7 % DrawBezier