Introducción .NET Compact Framework es una API excelente, si no la mejor, para dispositivos móviles. Su motor gráfico está fuertemente acelerado para aumentar la velocidad de renderizado y reducir el consumo de memoria. Sin embargo, parece lejos de satisfacer las crecientes demandas de los usuarios de una mejor experiencia gráfica. Intentar obtener algunas de las capacidades avanzadas de representación de gráficos vectoriales en .NET Compact Framework puede ser una tarea tediosa. Los desarrolladores tienen dos opciones:
1. Recurrir al código nativo. Por ejemplo, la API de juegos de Pocket PC podría ser una buena opción. Su rendimiento es impresionante. Para obtener más información, consulte un artículo muy completo en: http://msdn.microsoft.com/mobility/samples/default.aspx?pull=/library/en-us/dnnetcomp/html/gmangame asp . El problema es que el código nativo no admite la representación de gráficos vectoriales y no es compatible con algunos dispositivos. Además, es posible que no funcione con emuladores de Pocket PC. Puedes imaginar lo difícil que es depurar un programa de este tipo.
2. Espere a que salga el motor de gráficos móviles de próxima generación. Hasta donde yo sé, Windows CE 5 contendrá un potente motor Direct3D Mobile. Esta es una buena noticia para los desarrolladores de juegos móviles, pero Direct3D no es adecuado para gráficos bidimensionales. Es demasiado complejo para ser utilizado en aplicaciones generales.
Lo que necesitamos es un motor de gráficos 2D potente y fácil de usar como GDI+. Por lo tanto, desarrollé el proyecto XrossOne GDI+ desde cero. Está escrito íntegramente en código administrado de C# y no contiene ningún código nativo o inseguro. Después de meses de arduo trabajo, finalmente puedo proporcionar la versión original descargable al comienzo de este artículo.
Primeros pasos Desde el comienzo de este proyecto, siempre tuve en mente que el motor XrossOne GDI+ debería ser neutral en diferentes plataformas y dispositivos portátiles. Como resultado, es compatible con Pocket PC, Windows CE, Smartphones, Windows .NET y Mono. Puede copiar el mismo tiempo de ejecución a un destino diferente y seguirá funcionando bien.
La siguiente tabla resume la arquitectura general.
Espacio de nombres de capaXrossOne GDI+ API XrossOne.Drawing
Motor gráfico bidimensional basado en punto fijo XrossOne.DrawingFP
16.16 Motor de cálculo de punto fijo XrossOne.FixedPoint
Hay tres capas en XrossOne GDI+. El nivel más bajo es el "motor informático de punto fijo 16.16". Una de las clases principales, MathFP, está adaptada de la biblioteca Beartronics J2ME. Se han optimizado varias funciones, incluidas sqrt, atan y PointFP.Distancecalculation. Bajo el espacio de nombres XrossOne.FixedPoint, hay otras tres clases: SingleFP, DoubleFP y MatrixFP. SingleFP es una clase auxiliar para números de punto fijo 16,16. Proporciona comodidad para convertir entre tipos de punto fijo y tipos estándar (int, float, string). MatrixFP está escrito para transformaciones 2D de punto fijo. Debido a que los cálculos de punto fijo son menos precisos, es posible que se pierda algo de precisión con las transformaciones en cascada. Por ejemplo, en la mayoría de los casos, dos operaciones de inversión no pueden restaurar la matriz original. DoubleFP existe para completar la biblioteca, pero aún no se utiliza.
El "motor de gráficos bidimensionales basado en punto fijo" es el núcleo de XrossOne GDI+. Implementa muchos algoritmos complejos de gráficos vectoriales, como dibujo suavizado, decoración de remates/juntas de líneas, transformaciones 2D, rellenos degradados, composición de canales alfa y más. La mayoría de las funciones avanzadas de GDI+ nativo se pueden encontrar aquí. Sin embargo, sólo deberías usarlo directamente en algunos casos porque su interfaz basada en punto fijo no es amigable para los programadores, pero no te preocupes demasiado por esta situación. Hay una API bien encapsulada disponible. Puede encontrarlos en el espacio de nombres XrossOne.Drawing. Las clases en XrossOne.Drawing son muy similares a las clases en System.Drawing, excepto que cada clase tiene una "X" al final. Por ejemplo, la clase XrossOne.Drawing.PenX es equivalente a System.Drawing.Pen. Hay un pequeño truco para convertir programas GDI+ a XrossOne GDI+. En la sección de uso, cambie el nombre de las clases XrossOne GDI+ a sus clases equivalentes. Por ejemplo:
usando Pluma = XrossOne.Drawing.PenX;
usando LinearGradientBrush = XrossOne.Drawing.LinearGradientBrushX;
usando Matriz = XrossOne.Drawing.MatrixX;
Características principales Dibujo de gráficos vectoriales suavizados
Se pueden representar todo tipo de formas geométricas bidimensionales a través de XrossOne Mobile GDI+, como segmentos de línea, rectángulos, polígonos, elipses, sectores, splines de Bézier, splines cardinales, etc. Sin embargo, los sectores, las splines de Bézier y las splines de base no están disponibles en .NET Compact Framework. Además, todos los gráficos se suavizan automáticamente cuando se renderizan. Esto ayuda a lograr una calidad súper suave. En .NET Compact Framework, el ancho del pincel se fija en 1 píxel. Esta limitación no existe en XrossOne GDI+. Se pueden aplicar diferentes tamaños de pinceles a los contornos de todas las formas, como se muestra en la Figura 1.
Figura 1. Dibujo de gráficos vectoriales suavizados
Ejemplo de código 1
//Borrar el fondo y restablecer el estado de transformación
gx.Clear(Color.Blanco);
gx.ResetTransform();
//Dibujar cuadrícula sesgada como fondo
Lápiz PenX = nuevo PenX(Utils.FromArgb(0x40, Color.LightGray), 5);
para (int i = -Alto; i < Ancho + Alto; i+=20)
{
gx.DrawLine(pluma, i, 0, i + Altura, Altura);
gx.DrawLine(pluma, i, 0, i - Altura, Altura);
}
//Dibuja un rectángulo DarkMagenta con un lápiz de 10,5 píxeles
Color c = Utils.FromArgb(0x80, Color.DarkMagenta);
pluma = nueva PenX(c, 10.5f);
gx.DrawRectangle(bolígrafo, 50, 20, 150, 200);
//Rellena un rectángulo verdeamarillo
c = Utils.FromArgb(0xA0, Color.VerdeAmarillo);
Pincel BrushX = nuevo SolidBrushX(c);
gx.FillRectangle(pincel, 120, 50, 90, 150);
//Dibuja una elipse azul violeta con un lápiz de 10,5 píxeles
c = Utils.FromArgb(0x80, Color.BlueViolet);
pluma = nueva PenX(c, 10.5f);
gx.DrawEllipse(bolígrafo, 50, 20, 150, 80);
//Rellena una elipse roja
c = Utils.FromArgb(0xA0, Color.Rojo);
pincel = nuevo SolidBrushX(c);
gx.FillEllipse(pincel, 20, 50, 80, 150);
//Dibuja un pastel HotPink desde 156,5 grados hasta -280,9 grados
pluma.Color = Utils.FromArgb(0xA0, Color.HotPink);
gx.DrawPie(bolígrafo, 3,6f, 120,3f, 200,8f, 130,1f, 156,5f, -280,9f);
//Dibujar curvas de Bézier naranja
c = Utils.FromArgb(0xA0, Color.Naranja);
pluma = nueva PlumaX(c, 16);
Punto de inicio = nuevo punto (70, 100);
Control de punto1 = nuevo punto(100, 10);
Control de punto2 = nuevo punto(150, 50);
Punto final1 = nuevo Punto(200, 200);
Control de punto3 = nuevo punto(100, 150);
Control de punto4 = nuevo punto(50, 200);
Punto final2 = nuevo Punto(10, 150);
Punto[] bezierPoints ={inicio, control1, control2, final1, control3, control4, final2};
pluma.EndCap = LineCapX.Round;
gx.DrawBeziers(bolígrafo, bezierPoints);
//Refrescar
Invalidar();
La salida de gráficos vectoriales de XrossOne GDI+ y GDI+ nativo es idéntica, con la excepción de las splines de base. Mi algoritmo está tomado del artículo Algoritmo de suavizado utilizando curvas de Bézier de Jean-Yves Queinec. Por lo tanto, es posible que encuentre algunas diferencias entre sus resultados, como se muestra en la Figura 2 a continuación.
Figura 2. Salida de DrawCurve/DrawClosedCurve
Aunque se han implementado la mayoría de las funciones de representación de gráficos vectoriales, todavía queda trabajo por hacer. Algunas funciones (DrawString, DrawImage, DrawPath, etc.) no estarán disponibles hasta la próxima versión.
relleno degradado
Hay cinco pinceles en GDI+ nativo: SolidBrush, LinearGradientBrush, PathGradientBrush, TextureBrush y HatchBrush. Sin embargo, en esta versión, sólo están disponibles SolidBrush y LinearGradientBrush. XrossOne GDI+ admite RadialGradientBrush pero no PathGradientBrush. La Figura 5 a continuación muestra un relleno degradado.
Figura 5. Relleno degradado
Ejemplo de código 4
//Borrar el fondo y restablecer el estado de transformación
gx.Clear(Color.Blanco);
gx.ResetTransform();
//Rellena un rectángulo con un LinearGradientBrushX blanco y negro
Rectángulo r = nuevo Rectángulo(20, 50, 300, 100);
Color c1 = Color.Negro;
Color c2 = Color.Blanco;
BrushX pincel1 = nuevo LinearGradientBrushX(r, c1, c2, 30F);
gx.FillRectangle(pincel1, r);
//Rellena un rectángulo con LinearGradientBrushX de 7 colores
r = nuevo Rectángulo(90, 100, 150, 100);
LinearGradientBrushX br = nuevo LinearGradientBrushX(r,Color.Negro,Color.Negro, 60F);
ColorBlendX cb = nuevo ColorBlendX();
cb.Positions=nuevo flotador[7];
int i=0;
para(flotador f=0;f<=1;f+=1.0f/6)
cb.Posiciones[i++]=f;
cb.Colors=nuevo color[]
{Color.Rojo,Color.Naranja,Color.Amarillo,Color.Verde,Color.Azul,Color.Índigo,Color.Violeta};
br.InterpolationColors=cb;
gx.TranslateTransform(160, 10);
gx.RotateTransform(60F);
gx.FillRectangle(br, r);
//Rellena un rectángulo con un RadialGradientBrushX de 7 colores
rY+= 50;
RadialGradientBrushX brush2 = nuevo RadialGradientBrushX(r, Color.Black,Color.Black, 220F);
pincel2.InterpolationColors = cb;
gx.RotateTransform(-45F);
gx.TranslateTransform(-200, -170);
gx.FillRectangle(pincel2, r);
//Refrescar
Invalidar();
Composición del canal alfa
La estructura Color en el espacio de nombres System.Drawing está disponible tanto en .NET Framework como en .NET Compact Framework. La diferencia es que el componente alfa está deshabilitado y el valor de Tono-Saturación-Brillo (HSB) no está disponible en .NET Compact Framework. Afortunadamente, la composición del canal alfa funciona perfectamente con XrossOne GDI+ (como habrás deducido del ejemplo de gráficos anterior).
actuación 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 211,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 %
Es cierto que las CPU de PC portátiles suelen ser mucho menos potentes que las CPU de PC estándar. Los cálculos pesados pueden hacer que los dispositivos portátiles tengan menos capacidad de respuesta, lo que puede resultar frustrante para los usuarios. En otras palabras, el rendimiento es fundamental para el software de dispositivos portátiles. Por lo tanto, antes de utilizar XrossOne Mobile GDI+ en una situación importante, es posible que desees analizar su rendimiento general. Debido a que la mayoría de las funciones equivalentes en GDI+ para .NET Compact Framework no están disponibles, las pruebas comparativas se realizaron entre XrossOne Mobile GDI+ y GDI+ para .NET Framework. Se realizaron pruebas en las siguientes categorías: representación de gráficos vectoriales, transformaciones 2D y rellenos degradados. Los escenarios de prueba se ejecutaron en las mismas condiciones. Puede encontrar los programas de referencia en el paquete de descarga y puede ver rápidamente su resultado gráfico en http://www.xrossone.com/projects.php?menu=4.
XrossOne Mobile GDI+ está escrito completamente en código administrado C# y su rendimiento general es aceptable (consulte la tabla a continuación), aunque las transformaciones 2D y los rellenos de degradado necesitarán una mayor optimización en versiones futuras.
Solución 66,7 % DrawBezier