Creación de imágenes dinámicas en el servidor.


Conceptos.

Introducción

Cuando debemos generar imágenes a partir de datos que se extraen de una base de datos o datos ingresados desde el navegador debemos construir la imagen en dicho momento.
ASP.Net provee de clases orientadas a generar imágenes en memoria y su posterior materialización en un archivo.

Imágenes dinámicas

1 - Programa ?Hola Mundo?

Crearemos un sitio web llamado 'ejercicio020' y agregaremos el primer Web Form y le datemos como nombre holamundo.aspx.

Para crear una imagen en forma dinámica debemos seguir una serie de pasos:

a - Debemos modificar el archivo webform (holamundo.aspx) agregando: ContentType="image/gif"

<%@ Page ContentType="image/gif" Language="C#" AutoEventWireup="true" CodeFile="holamundo.aspx.cs" Inherits="holamundo" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    
    </div>
    </form>
</body>
</html>

b ? El archivo holamundo.aspx.cs es:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
//Importamos el espacio de nombre que declara la clase Bitmap, Graphics, Font y SolidBrush
using System.Drawing;
//Importamos el espacio de nombre que declara la clase ImageFormat
using System.Drawing.Imaging;
public partial class holamundo : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        //Creamos un objeto de la clase Bitmap
        Bitmap mapabit = new Bitmap(500, 300);
        Graphics lienzo;
        //Iicializamos la variable de tipo Graphics con el bitmap creado
        lienzo = Graphics.FromImage(mapabit);
        //Creamos una fuente
        Font fuente1 = new Font("Arial", 40);
        //Creamos un pincel
        SolidBrush pincel1 = new SolidBrush(Color.Red);
        //Graficamos dentro de la imagen
        lienzo.DrawString("Hola Mundo", fuente1, pincel1, 10, 10);
        //Enviamos la imagen al navegador que la solicitó
        mapabit.Save(Response.OutputStream, ImageFormat.Gif);
    }
}

El resultado de la ejecución es:

Es importante tener en cuenta que cuando ejecutamos este webform en realidad lo que retorna es una imagen con formato gif y no un archivo HTML. Fácilmente podemos comprobarlo tratando de ver el código fuente de la página presionando el botón derecho del mouse dentro del navegador.

2 ? Inserción de una imagen dinámica en un webform.

Para la incorporación de la imagen en una página propiamente dicha debemos hacer lo siguiente:
Creamos una segunda página llamada paginaholamundo.aspx con un código similar a este:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="paginaholamundo.aspx.cs" Inherits="paginaholamundo" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <img src="holamundo.aspx"  alt="prueba de imagen dinámica" />
    </div>
    </form>
</body>
</html>

Es decir que con el elemento HTML img indicamos en la propiedad src el nombre del archivo que genera la imagen.

3 ?Generación de un Captcha.

Captcha es el acrónimo de Completely Automated Public Turing text to tell Computers and Humans Apart (Prueba de Turing pública y automática para diferenciar a máquinas y humanos)
Se trata de una prueba desafío-respuesta utilizada en computación para determinar cuándo el usuario es o no humano.

Confeccionaremos una imagen con un número aleatorio entre 1000 y 9999 y para dificultar su lectura por un programa automático de lectura lo rayaremos con líneas de distintos colores.
Por último incorporaremos almacenaremos el valor en una variable de sesión y validaremos el valor que ingresa el usuario en un control de tipo TextBox.

a - Primero generamos un gráfico dinámico (captcha.aspx.cs y captcha.aspx):
Tener en cuenta que el archivo captcha.aspx solo debemos agregar la propiedad ContentType indicando que generará una imagen en formato gif):

<%@ Page ContentType="image/gif" Language="C#" AutoEventWireup="true" CodeFile="captcha.aspx.cs" Inherits="captcha" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    
    </div>
    </form>
</body>
</html>

Luego el código de la clase será:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Drawing;
using System.Drawing.Imaging;

public partial class captcha : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        Bitmap mapabit = new Bitmap(100, 40);
        Graphics lienzo;
        lienzo = Graphics.FromImage(mapabit);
        int nro;
        Random r = new Random();
        nro = r.Next(1, 10000);
        Font fuente1 = new Font("Arial", 22);
        SolidBrush pincel1 = new SolidBrush(Color.Red);
        lienzo.DrawString(nro.ToString(), fuente1, pincel1, 4, 4);
        //Dibujar lineas
        for (int f = 1; f <= 10; f++)
        {
            int x1 = r.Next(1, 100);
            int y1 = r.Next(1, 40);
            int x2 = r.Next(1, 100);
            int y2 = r.Next(1, 40);
            Pen lapiz1 = new Pen(Color.FromArgb(r.Next(1, 255), r.Next(1, 255), r.Next(1, 255)));
            lienzo.DrawLine(lapiz1, x1, y1, x2, y2);
        }
        Session["codigo"] = nro.ToString();
        mapabit.Save(Response.OutputStream, ImageFormat.Gif);
    }
}

Hacemos el import de los dos espacios de nombres:

using System.Drawing;
using System.Drawing.Imaging;

En el método Page_Load creamos un objeto de la clase BitMap indicando el ancho y el alto en píxeles.
Obtenemos una referencia de la imagen almacenándola en una variable de tipo Graphics.

        Bitmap mapabit = new Bitmap(100, 40);
        Graphics lienzo;
        lienzo = Graphics.FromImage(mapabit);

Generamos un valor aleatorio:

        int nro;
        Random r = new Random();
        nro = r.Next(1, 10000);

Imprimimos el número dentro de la imagen:

        Font fuente1 = new Font("Arial", 22);
        SolidBrush pincel1 = new SolidBrush(Color.Red);
        lienzo.DrawString(nro.ToString(), fuente1, pincel1, 4, 4);

Dibujamos 10 líneas de distintos colores en forma aleatoria tapando parcialmente el número aleatorio:

        for (int f = 1; f <= 10; f++)
        {
            int x1 = r.Next(1, 100);
            int y1 = r.Next(1, 40);
            int x2 = r.Next(1, 100);
            int y2 = r.Next(1, 40);
            Pen lapiz1 = new Pen(Color.FromArgb(r.Next(1, 255), r.Next(1, 255), r.Next(1, 255)));
            lienzo.DrawLine(lapiz1, x1, y1, x2, y2);
        }

Almacenamos el valor en una variable de sesión para poder recuperarlo en otra página y poder compararlo con el que ingresa el usuario por teclado:

        Session["codigo"] = nro.ToString();

Enviamos la imagen al navegador que lo solicitó:

        mapabit.Save(Response.OutputStream, ImageFormat.Gif);

b ? Creamos un formulario web (formulariocaptcha.aspx) donde insertamos el Captcha (imagen) y disponemos además un control de tipo textbox y un button:
Debemos generar un webform semejante a este:


Disponemos un objeto de la clase Image e inicializamos la propiedad ImageUrl con el nombre del archivo que genera el gráfico dinámico llamado captcha.aspx.

Para el evento Click del objeto Button1 disponemos el siguiente código:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class formulariocaptcha : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {

    }

    protected void Button1_Click(object sender, EventArgs e)
    {
        if (Session["codigo"].ToString() == this.TextBox1.Text)
        {
            Label1.Text = "Ingresó el codigo correcto";
        }
        else
        {
            Label1.Text = "Incorrecto";
        }
    }
}

Luego mediante un if controlamos el valor del captcha y el valor ingresado por el usuario en el textbox1. Mostramos en un label el resultado de la comparación.

Cuando ejecutamos podemos ver que la imágen dinámica aparece en el formulario:


4 ?Gráfico de tarta.

Para implementar un gráfico de tarta debemos emplear el método FillPie de la clase Graphics.
Desarrollaremos una aplicación que solicite en un webform (crear el archivo formulariotarta.aspx) tres valores enteros por teclado y llamaremos a un gráfico dinámico que mostrará un gráfico de tarta rescatando los valores del webform.
El webform envía mediante parámetros los datos ingresados.

El webform tiene la siguiente interfaz:


Y el código que debemos implementar para el evento Click del objeto Button es:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class formulariotarta : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {

    }

    protected void Button1_Click(object sender, EventArgs e)
    {
        this.Response.Redirect("graficotarta.aspx?v1=" + this.TextBox1.Text + 
                               "&v2=" + this.TextBox2.Text + 
                               "&v3=" + this.TextBox3.Text);
    }
}

Es decir redireccionamos al archivo graficotarta.aspx pasando 3 parámetros en la cabecera de la llamada.
El archivo que genera la imagen dinámica (graficotarta.aspx.cs) es el siguiente:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Drawing;
using System.Drawing.Imaging;

public partial class graficotarta : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        Bitmap mapabit = new Bitmap(800, 600);
        Graphics lienzo;
        lienzo = Graphics.FromImage(mapabit);
        float valor1 = float.Parse(this.Request.QueryString["v1"]);
        float valor2 = float.Parse(this.Request.QueryString["v2"]);
        float valor3 = float.Parse(this.Request.QueryString["v3"]);
        float total = valor1 + valor2 + valor3;
        float grados1 = valor1 / total * 360;
        SolidBrush pincel1 = new SolidBrush(Color.Red);
        lienzo.FillPie(pincel1, 100, 100, 400, 400, 0, grados1);
        float grados2 = valor2 / total * 360;
        SolidBrush pincel2 = new SolidBrush(Color.Blue);
        lienzo.FillPie(pincel2, 100, 100, 400, 400, grados1, grados2);
        float grados3 = valor3 / total * 360;
        SolidBrush pincel3 = new SolidBrush(Color.Green);
        lienzo.FillPie(pincel3, 100, 100, 400, 400, grados1 + grados2, grados3);
        //Referencias
        lienzo.FillRectangle(pincel1, 600, 500, 20, 20);
        Font fuente = new Font("Arial", 10);
        lienzo.DrawString(valor1.ToString(), fuente, pincel1, 630, 500);
        lienzo.FillRectangle(pincel2, 600, 530, 20, 20);
        lienzo.DrawString(valor2.ToString(), fuente, pincel2, 630, 530);
        lienzo.FillRectangle(pincel3, 600, 560, 20, 20);
        lienzo.DrawString(valor3.ToString(), fuente, pincel3, 630, 560);
        mapabit.Save(Response.OutputStream, ImageFormat.Gif);
    }
}

También recordemos que el archivo (graficotarta.aspx) agregar la propiedad contenttype:

<%@ Page ContentType="image/gif" Language="C#" AutoEventWireup="true"
 CodeFile="graficotarta.aspx.cs" Inherits="graficotarta" %>

Veamos el algoritmo para mostrar el gráfico de tarta dentro de la imagen. En el método Load generamos la imagen. Creamos un objeto de la clase Bitmap y obtenemos la referencia al objeto de la clase Graphics contenido en el mismo:

        Bitmap mapabit = new Bitmap(800, 600);
        Graphics lienzo;
        lienzo = Graphics.FromImage(mapabit);

Recuperamos los tres valores ingresados en el webform:

        float valor1 = float.Parse(this.Request.QueryString["v1"]);
        float valor2 = float.Parse(this.Request.QueryString["v2"]);
        float valor3 = float.Parse(this.Request.QueryString["v3"]);

Calculamos la cantidad de grados que le corresponde a cada valor y dibujamos el trozo de tarta respectivo:

        float total = valor1 + valor2 + valor3;
        float grados1 = valor1 / total * 360;
        SolidBrush pincel1 = new SolidBrush(Color.Red);
        lienzo.FillPie(pincel1, 100, 100, 400, 400, 0, grados1);
        float grados2 = valor2 / total * 360;
        SolidBrush pincel2 = new SolidBrush(Color.Blue);
        lienzo.FillPie(pincel2, 100, 100, 400, 400, grados1, grados2);
        float grados3 = valor3 / total * 360;
        SolidBrush pincel3 = new SolidBrush(Color.Green);
        lienzo.FillPie(pincel3, 100, 100, 400, 400, grados1 + grados2, grados3);

Dibujamos los recuadros de referencias con el valor que le corresponde a cada trozo de tarta:

        lienzo.FillRectangle(pincel1, 600, 500, 20, 20);
        Font fuente = new Font("Arial", 10);
        lienzo.DrawString(valor1.ToString(), fuente, pincel1, 630, 500);
        lienzo.FillRectangle(pincel2, 600, 530, 20, 20);
        lienzo.DrawString(valor2.ToString(), fuente, pincel2, 630, 530);
        lienzo.FillRectangle(pincel3, 600, 560, 20, 20);
        lienzo.DrawString(valor3.ToString(), fuente, pincel3, 630, 560);
        mapabit.Save(Response.OutputStream, ImageFormat.Gif);

El resultado del gráfico es:


4 ?Gráfico de barra horizontal.

Para implementar un gráfico de barra horizontal debemos emplear el método FillRect de la clase Graphics. Desarrollaremos una aplicación que solicite en un webform (formulariobarrahorizontal.aspx) tres valores enteros por teclado y llamaremos a un gráfico dinámico que mostrará un gráfico de barra rescatando los valores del webform.
El webform envía mediante parámetros los datos ingresados.

El interfaz para la carga de los tres valores enteros en un webform es similar al problema del gráfico de tarta.
El código que debemos implementar para el evento Click del objeto Button es:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class formulariobarrahorizontal : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {

    }

    protected void Button1_Click(object sender, EventArgs e)
    {
        this.Response.Redirect("graficobarrahorizontal.aspx?v1=" + this.TextBox1.Text +
                               "&v2=" + this.TextBox2.Text +
                               "&v3=" + this.TextBox3.Text);

    }
}

Es decir redireccionamos al archivo graficobarrahorizontal.aspx pasando 3 parámetros en la cabecera de la llamada.
El archivo que genera la imagen dinámica (graficobarrahorizontal.aspx.cs) es la siguiente:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Drawing;
using System.Drawing.Imaging;

public partial class graficobarrahorizontal : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        Bitmap mapabit = new Bitmap(800, 400);
        Graphics lienzo;
        lienzo = Graphics.FromImage(mapabit);
        float valor1 = float.Parse(this.Request.QueryString["v1"]);
        float valor2 = float.Parse(this.Request.QueryString["v2"]);
        float valor3 = float.Parse(this.Request.QueryString["v3"]);
        float mayor = this.RetornarMayor(valor1, valor2, valor3);
        float largo1 = valor1 / mayor * 400;
        SolidBrush pincel1 = new SolidBrush(Color.Red);
        lienzo.FillRectangle(pincel1, 50, 50, 50 + largo1, 80);
        float largo2 = valor2 / mayor * 400;
        SolidBrush pincel2 = new SolidBrush(Color.Green);
        lienzo.FillRectangle(pincel2, 50, 150, 50 + largo2, 80);
        float largo3 = valor3 / mayor * 400;
        SolidBrush pincel3 = new SolidBrush(Color.Blue);
        lienzo.FillRectangle(pincel3, 50, 250, 50 + largo3, 80);
        //Cantidades
        SolidBrush pincel4 = new SolidBrush(Color.Black);
        Font fuente1 = new Font("Arial", 30);
        lienzo.DrawString(valor1.ToString(), fuente1, pincel4, 60, 80);
        lienzo.DrawString(valor2.ToString(), fuente1, pincel4, 60, 160);
        lienzo.DrawString(valor3.ToString(), fuente1, pincel4, 60, 260);
        mapabit.Save(Response.OutputStream, ImageFormat.Gif);
    }

    private float RetornarMayor(float x1, float x2, float x3)
    {
        if (x1 > x2 && x1 > x3)
            return x1;
        else
            if (x2 > x3)
            return x2;
        else
            return x3;
    }
}

El método RotornarMayor recibe como parámetros tres float y retorna el mayor de los mismos:

   private float RetornarMayor(float x1, float x2, float x3)
    {
        if (x1 > x2 && x1 > x3)
            return x1;
        else
            if (x2 > x3)
            return x2;
        else
            return x3;
    }

El método Load es el que crea el gráfico de barra horizontal propiamente dicho.
Para graficar cada barra:

        float largo1 = valor1 / mayor * 400;
        SolidBrush pincel1 = new SolidBrush(Color.Red);
        lienzo.FillRectangle(pincel1, 50, 50, 50 + largo1, 80);

Debemos dividir el valor correspondiente con respecto al mayor de los tres. Este valor como máximo puede ser 1. Luego multiplicamos este valor por 400 (este valor representa el largo de barra mayor)
Graficamos mediante el método FillRectangle.
Mostramos los valores enteros que les corresponde a cada barra:

        SolidBrush pincel4 = new SolidBrush(Color.Black);
        Font fuente1 = new Font("Arial", 30);
        lienzo.DrawString(valor1.ToString(), fuente1, pincel4, 60, 80);
        lienzo.DrawString(valor2.ToString(), fuente1, pincel4, 60, 160);
        lienzo.DrawString(valor3.ToString(), fuente1, pincel4, 60, 260);

Ejercicios propuestos

1 ? Confeccionar un gráfico dinámico que genere un gráfico de barras verticales.

2 ? Confeccionar un gráfico dinámico que genere una barra porcentual (mostrar los porcentajes que les corresponde a cada trozo fuera de la barra)

3 ? Generar una imagen a partir de otra y agregarle un texto en forma dinámica. En algunos casos cuando se quiere proteger la propiedad de imágenes es aplicarles un texto que indica que la imagen no puede ser usada en otro sitio para fines comerciales.

4 ? Confeccionar un algoritmo que permita ingresar los datos personales y luego genere una tarjeta personal con dichos datos:
ej:.


Retornar