Pintando sobre un bitmap en WPF

Una de las cosas que más llaman la atención de la aplicación que desarrollamos en el Web Day (Mi Bolsa) es la gráfica de cotizaciones.


La gráfica se genera en tiempo real en servidor y toma como parámetro el símbolo de la empresa y la fecha final. Aquí lo tenéis en un ejemplo en vivo, podéis poner cualquier símbolo de una empresa (ej. MSFT, AABC, MSN…) y una fecha. Al pinchar en el botón la gráfica se actualiza en servidor (por cierto los valores mostrados son aleatorios…):


mibolsa


 


La técnica utilizada para hacerlo es bastante antigua, pero con un toquecillo de WPF. En la página web sólo hay un elemento IMG cuya propiedad SRC se establece a una dirección de una página ASP.NET de servidor. Esta página toma como parámetros el ancho y alto, la empresa y la fecha y genera dinámicamente una imagen en el servidor en formato JPEG.


Los principales trucos para hacer que esto funcione:



  • Cambiar el MIME type de la página ASP.NET para que el browser la identifique correctamente como una imagen JPEG y no como una página HTML. Para hacer esto hay que establecer la propiedad ContentType de la respuesta. Si tienes el código fuente de Mi Bolsa puedes verlo en el archivo TickerChart.aspx, dentro de la función Page_Load:


Response.ContentType = «image/jpeg»



  • Generar la imagen en el servidor. Para darle vidilla hemos hecho la imagen con WPF. El concepto es muy parecido a usar GDI, se trata de generar un stream de bytes con la codificación de la imagen en JPEG. Una vez tengamos esta codificación la devolvemos en la página ASP.NET con un Response.Outputstream.Write.
    Otra historia es generar esa imagen desde WPF. La buena noticia es que cualquier renderización de WPF puede realizarse sobre una imagen en memoria en vez de sobre la pantalla. Para hacerlo tenemos que crear un objeto RenderTargetBitmap y llamar a su método Render con las primitivas que queramos pintar. El código que realiza esta operación está en el archivo ChartDrawer.cs:


public byte[] DrawChart()
{
      PixelFormat pf = PixelFormats.Bgr32;
      MemoryStream memStream = new MemoryStream();

      DrawingVisual drawingVisual = new DrawingVisual();
      DrawingContext drawingContext = drawingVisual.RenderOpen();

      DrawBackground(drawingContext);
      DrawAxis(drawingContext);
      DrawGrid(drawingContext);
      for(int i=0;i<_values.Count;i++)
            DrawValues(drawingContext, i);
      DrawAxisText(drawingContext);

      drawingContext.Close();

      RenderTargetBitmap renderBitmap = new RenderTargetBitmap
            (_width, _height, 96, 96, PixelFormats.Pbgra32);
      renderBitmap.Render(drawingVisual);

      JpegBitmapEncoder encoder = new JpegBitmapEncoder();
      encoder.Frames.Add(BitmapFrame.Create(renderBitmap));
      encoder.Save(memStream);

      return memStream.GetBuffer();
}

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *