oct 18 2010

Solución al mensaje "Error genérico de GDI+" en aplicaciones Web que generan gráficos

José Manuel AlarconCategorías: ASP.NET [Leer sin negritas]

Este fin de semana he estado trabajando en una pequeña aplicación que en breve colgaré con código fuente para todo el mundo y que me dio el error que os comento en el título del post.

Aunque todo lo que utilicé era compatible con .NET 2.0, la desarrollé en mi equipo con Visual Studio 2010 y .NET 4.0, donde todo funcionaba a la perfección. Al subirla al servidor donde iba a estar albergada, de repente, me daba el error "Error genérico de GDI+" o -en inglés- "A generic error occurred in GDI+", sin más explicaciones, y con unas referencias muy raras a Remoting.

Mi código original generaba una imagen que posteriormente se devolvía al navegador en formato PNG. El código que estaba utilizando era similar al siguiente:

Bitmap img = new Bitmap(sRutaImagenPatron);
Graphics g = Graphics.FromImage(img);
Font f = new Font(fuente, tamanio, FontStyle.Bold);
Brush b = colorLetra;
g.DrawString(string.Format("{0:n0}", iDato), f, b, posX_Letra, posY_Letra);

context.Response.ContentType = "image/png";
img.Save(context.Response.OutputStream, ImageFormat.Png);

Las primeras líneas, antes de la que está en negrita al final, se encargan de generar el gráfico sobreponiendo un texto a partir de un gráfico inicial que tengo en disco. La línea importante es la última, que se encarga de guardar el gráfico resultante al flujo de salida de la petición actual, de modo que lo reciba el usuario en su navegador.

El motivo de que se produzca este error es que en las versiones anteriores de .NET el Stream de respuesta de ASP.NET no permite moverse adelante y atrás por él, es decir, lo que escribes ese añade al final y nada más. El caso es que el formato PNG para poder escribirse correctamente necesita moverse a lo largo del stream, y por eso rompe el código anterior al intentar escribir directamente en la salida de la respuesta actual (Response).

La solución que funciona siempre: generar el gráfico en un stream en memoria que siempre permiten el movimiento en todas direcciones, y luego enviar el resultado de una vez al Response. En código C# esto es así:

using (MemoryStream stream = new MemoryStream())
{
    img.Save(stream, ImageFormat.Png);
    stream.WriteTo(context.Response.OutputStream);
}

Si sustituimos la última línea anterior con este fragmento obtendremos el mismo resultado (la imagen enviada al cliente) pero sin que se produzca el error anterior, ya que el stream en memoria se puede mover adelante y atrás sin problema.

¡Espero que te resulte útil!

Tags:

Comentarios (3) -

1.
espinete espinete dice:

Interesante, bueno saber estas cosas, gracias !!! :-)

Sobre estos temas, existe la problemática de descargar imágenes (o ficheros en general) muy grandes, podrían aparecer errores OutOfMemory al utilizar MemoryStream.

Saludos.

2.
José Manuel Alarcón José Manuel Alarcón dice:

Hola Espinete:

Sí, con archivos muy grandes sería un problema, pero vamos, si cvas a enviar un PNG al cliente que pese algo más de unos cientos de KB deberías replantearte si estás haciendo algo mal en el programa :-)

Para otros tipos de archivos que leas secuencialmente de disco no tienes problema porque los puedes enviar por trozos directamente en el OutputStream.

Saludos

JM

3.
Braulio Megías Braulio Megías dice:

Es fantástico lo del "Error genérico de GDI+". Sirve para un roto y un descosido :P
Buen apunte, tomo nota porque alguna vez me he encontrado el puñetero error y averiguar qué lo causa te puede llevar un rato. Ésta es una posible causa más.

Agregar comentario

  Country flag

biuquote
  • Comentario
  • Vista previa
Loading