Alternativas al Sistema.Dibujo para uso con ASP.NET?


Después de varios días de rastrear extraños errores de GDI+ ,me he topado con esta pequeña joya en MSDN :

Clases dentro del Sistema.No se admiten espacios de nombres de dibujo para su uso dentro de una Ventana o ASP.NET servicio. Intentar usar estas clases desde uno de estos tipos de aplicaciones puede producir problemas inesperados, como rendimiento del servicio disminuido y excepciones en tiempo de ejecución.

No se si "ASP.NET servicio" significa " web aplicación "en este contexto, pero" rendimiento del servicio disminuido "ciertamente parece cubrir la variedad aleatoria de" Un error genérico ocurrió en GDI+ "y" Fuera de memoria " errores que mi aplicación está lanzando - intermitentes, errores no reproducibles de lectura y escritura de imágenes JPEG que-en muchos casos - fueron realmente creados por el Sistema.Dibujo.Imágenes en primer lugar.

Entonces, si GDI+ no puede leer y escribir archivos JPEG de manera confiable en una aplicación Web, ¿qué debería usar en su lugar?

Quiero que los usuarios puedan cargar imágenes (se requiere JPEG, otros formatos agradables), remuestrearlas de manera confiable y mostrar mensajes de error útiles si algo sale mal. Alguna idea? Son el Sistema.¿Vale la pena considerar los espacios de nombres de medios de WPF?

Gracias,

Dylan

EDIT: Sí, sé que GDI+ funciona "la mayor parte del tiempo". Eso no es suficiente, porque cuando falla, lo hace de una manera que es imposible de aislar o recuperar con gracia. Me no estoy interesado en ejemplos de código GDI+ que funcione para usted: estoy buscando bibliotecas alternativas para usar para el procesamiento de imágenes.

Author: rick schott, 2009-10-07

7 answers

Hay una excelente entrada de blog que incluye código C# sobre el uso de la biblioteca de gráficos ImageMagick a través de Interop en TopTen Software Blog. Este post trata específicamente de correr ASP.net en linux bajo mono; sin embargo, el código C# debería ser perfectamente copy-paste-able, lo único que tendrá que cambiar son los atributos Interop si se está ejecutando bajo windows haciendo referencia a un binario de ventana (DLL).

ImageMagick ® es una suite de software para crear, editar, componer o convertir imágenes de mapa de bits. Puede leer y escribir imágenes en una variedad de formatos (más de 100) incluyendo DPX, EXR, GIF, JPEG, JPEG-2000, PDF, PhotoCD, PNG, Postscript, SVG y TIFF. Usar ImageMagick para cambiar el tamaño, voltear, espejo, girar, distorsionar, cortar y transformar imágenes, ajustar la imagen colores, aplicar varios efectos especiales, o dibujar texto, líneas, polígonos, elipses y curvas de Bézier.

También hay un proyecto de desarrollo ImageMagick. Net en codeplex que envuelve todo. Pero no muestra un desarrollo activo desde 2009, por lo que puede estar rezagado con respecto a la versión actual de la biblioteca ImageMagick. Para una pequeña rutina de redimensionamiento trivial, probablemente me quedaría con la interop. Solo necesita observar su implementación cuidadosamente para detectar su propia fuga de memoria o recursos no publicados (la biblioteca en sí está bien probada y examinada por la comunidad).

La biblioteca es libre y de código abierto. La licencia Apache 2 parece ser compatible con ambos fines personales y comerciales. Vea La página de licencias de ImageMagick.

La biblioteca es totalmente multiplataforma e implementa muchas rutinas poderosas de manejo y transformación de imágenes que no se encuentran en GDI+ (o no se implementan bajo mono) y tiene una buena reputación como alternativa para ASP.net procesamiento de imágenes.

Actualización: Parece que hay una versión actualizada de un wrapper. NET aquí: http://magick.codeplex.com /

 9
Author: BenSwayne,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-12 17:21:13

Sí, utilice las clases WPF System.Windows.Media. Al estar totalmente gestionados, no sufren los mismos problemas que las cosas de GDI.

Aquí hay un extracto de algún código MVC que uso para renderizar degradados, para darle una idea de cómo pasar de un WPF Visual a un PNG:

using System;
using System.IO;
using System.Web.Mvc;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace MyMvcWebApp.Controllers
{
    public class ImageGenController : Controller
    {
        // GET: ~/ImageGen/Gradient?color1=red&color2=pink
        [OutputCache(CacheProfile = "Image")]
        public ActionResult Gradient(Color color1, Color color2, int width = 1, int height = 30, double angle = 90)
        {
            var visual = new DrawingVisual();
            using (DrawingContext dc = visual.RenderOpen())
            {
                Brush brush = new LinearGradientBrush(color1, color2, angle);
                dc.DrawRectangle(brush, null, new Rect(0, 0, width, height));
            }

            return new FileStreamResult(renderPng(visual, width, height), "image/png");
        }

        static Stream renderPng(Visual visual, int width, int height)
        {
            var rtb = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Default);
            rtb.Render(visual);

            var frame = BitmapFrame.Create(rtb);
            var encoder = new PngBitmapEncoder();
            encoder.Frames.Add(frame);

            var stream = new MemoryStream();
            encoder.Save(stream);
            stream.Position = 0;

            return stream;
        }
    }
}
 11
Author: Duncan Smart,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-10-12 11:44:03

Puede encontrar un artículo muy bueno de un empleado de Microsoft aquí: Cambiar el tamaño de las imágenes del servidor utilizando WPF/WIC en lugar de GDI+ que propone usar WPF en lugar de GDI+. Se trata más de miniaturas, pero en general son los mismos problemas.

De todos Modos, al final dice esto:

Me puse en contacto con el equipo de WPF para tener la última palabra sobre si esto es apoyar. Desafortunadamente, no lo es, y la documentación está siendo actualizado en consecuencia. Me disculpo por cualquier confusión que esto puede tener causar. Estamos buscando maneras de hacer que esa historia sea más aceptable en futuro.

Así que WPF también no es compatible con aplicaciones web y todavía lo es creo: - S

 8
Author: Simon Mourier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-21 16:38:18

ImageSharp

ImageSharp es una biblioteca de gráficos 2D multiplataforma de código abierto. Está escrito en C# sobre el nuevo estándar. NET, sin dependencia de ninguna API específica del sistema operativo.

Actualmente todavía está en pre-lanzamiento en MyGet (tendrá que agregar la fuente del paquete en las opciones VS o un NuGet.archivo de configuración), pero ya lo estamos usando con algunos resultados muy positivos.

 4
Author: Mathieu Renda,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-05 08:35:18

La mayoría de las cuestiones sobre las que he leído se refieren a recursos que no se han dispuesto adecuadamente.

He utilizado variantes de este código una y otra vez sin problemas de aplicaciones web:

public void GenerateThumbNail(HttpPostedFile fil, string sPhysicalPath, 
                              string sOrgFileName,string sThumbNailFileName,
                              System.Drawing.Imaging.ImageFormat oFormat, int rez)
{

    try
    {

        System.Drawing.Image oImg = System.Drawing.Image.FromStream(fil.InputStream);

        decimal pixtosubstract = 0;
        decimal percentage;

        //default
        Size ThumbNailSizeToUse = new Size();
        if (ThumbNailSize.Width < oImg.Size.Width || ThumbNailSize.Height < oImg.Size.Height)
        {
            if (oImg.Size.Width > oImg.Size.Height)
            {
                percentage = (((decimal)oImg.Size.Width - (decimal)ThumbNailSize.Width) / (decimal)oImg.Size.Width);
                pixtosubstract = percentage * oImg.Size.Height;
                ThumbNailSizeToUse.Width = ThumbNailSize.Width;
                ThumbNailSizeToUse.Height = oImg.Size.Height - (int)pixtosubstract;
            }
            else
            {
                percentage = (((decimal)oImg.Size.Height - (decimal)ThumbNailSize.Height) / (decimal)oImg.Size.Height);
                pixtosubstract = percentage * (decimal)oImg.Size.Width;
                ThumbNailSizeToUse.Height = ThumbNailSize.Height;
                ThumbNailSizeToUse.Width = oImg.Size.Width - (int)pixtosubstract;
            }

        }
        else
        {
            ThumbNailSizeToUse.Width = oImg.Size.Width;
            ThumbNailSizeToUse.Height = oImg.Size.Height;
        }

        Bitmap bmp = new Bitmap(ThumbNailSizeToUse.Width, ThumbNailSizeToUse.Height);
        bmp.SetResolution(rez, rez);
        System.Drawing.Image oThumbNail = bmp;

        bmp = null;

        Graphics oGraphic = Graphics.FromImage(oThumbNail);

        oGraphic.CompositingQuality = CompositingQuality.HighQuality;

        oGraphic.SmoothingMode = SmoothingMode.HighQuality;

        oGraphic.InterpolationMode = InterpolationMode.HighQualityBicubic;

        Rectangle oRectangle = new Rectangle(0, 0, ThumbNailSizeToUse.Width, ThumbNailSizeToUse.Height);

        oGraphic.DrawImage(oImg, oRectangle);

        oThumbNail.Save(sPhysicalPath  + sThumbNailFileName, oFormat);

        oImg.Dispose();

    }
    catch (Exception ex)
    {
        Response.Write(ex.Message);
    }

}
 1
Author: rick schott,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-09 22:34:15

Puede echar un vistazo a http://gd-sharp.sourceforge.net/ que es un contenedor para la biblioteca GD. No lo he probado, pero parece prometedor.

 0
Author: alfred barthand,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-23 17:16:42

He tenido buen comportamiento de la biblioteca de El Cairo (http://www.cairographics.org) en un ASP.Net entorno del servidor web. De hecho, me mudé a El Cairo desde WPF debido al pobre modelo de uso de memoria de WPF para cosas basadas en la web.

WPF en realidad tiende a ejecutar su proceso de trabajo sin memoria. Ninguno de los objetos WPF implementa IDisposable, y muchos de ellos hacen referencia a memoria no administrada que solo se libera a través de un finalizador. El uso intensivo de WPF (especialmente si su servidor está significativamente gravado por la CPU) eventualmente se ejecutará te quedas sin memoria porque tu cola de finalizadores se satura. Cuando estaba perfilando mi aplicación, por ejemplo, la cola de finalización tenía más de 50,000 objetos en ella, muchos de ellos con referencias a memoria no administrada. El Cairo se ha comportado mucho mejor para mí, y su patrón de uso de memoria ha sido mucho más predecible que el de WPF.

Si estás interesado en usar Cairo, toma las libs del sitio web de GTK+. Tienen un conjunto de binarios x86 y x64.

El único inconveniente es que cairo no puede leer / escribir JPG de forma nativa; sin embargo, puede adaptar fácilmente el material de WPF para leer/escribir JPG y hacer el remuestreo/escalado/dibujo/cualquier otra cosa usando Cairo.

 0
Author: FMM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-08-21 21:13:01