Sistema.Dibujo en ASP .NET ASP.NET Core

Hay muchas preguntas dedicadas al uso de la biblioteca System.Drawing en los servicios ASP.NET. La respuesta más común es que Microsoft no recomienda el uso de System.Drawing en los servicios ASP.NET.

En este artículo, aprenderá detalles sobre el uso de la interfaz de la biblioteca System.Drawing en los servicios ASP.NET con Aspose.Drawing for .NET. Las siguientes secciones estructuran toda la información relevante:

¿Por qué Aspose.Dibujo?

Microsoft no recomienda el uso de su biblioteca System.Drawing en los servicios ASP.NET. La página de inicio de System.Drawing documentación dice:

Las clases dentro del espacio de nombres System.Drawing no se admiten para su uso dentro de un servicio de Windows o ASP.NET. Intentar usar estas clases desde dentro de uno de estos tipos de aplicaciones puede resultar en excepciones de tiempo de ejecución y una disminución del rendimiento del servicio.

Hay dos problemas básicos que obligan a Microsoft a escribir sobre precaución. El primer problema es el uso de la biblioteca nativa GDI+ y, como resultado, el uso de identificadores GDI. Mientras que la segunda preocupación son los problemas de concurrencia. Por ejemplo, se produce un bloqueo de todo el proceso durante cualquier operación DrawImage(). Por lo tanto, no puede crear servicios ASP.NET rápidos y escalables utilizando la biblioteca System.Drawing de Microsoft.

Instalación de Aspose.Drawing for .NET API

Puede descargar fácilmente el archivo DLL desde la sección Descargas, o configurarlo a través del Administrador de paquetes NuGet con el siguiente comando:

PM> Install-Package Aspose.Drawing

Aspose.Drawing for .NET API - Introducción

Entendemos que System.Drawing es muy popular entre los desarrolladores debido a sus funciones de manipulación de imágenes. Por eso hemos creado una API similar y compatible sin problemas de compatibilidad. Para su comodidad y adaptabilidad, la API contiene los mismos nombres de clases, funciones, enumeraciones e interfaces. Simplemente puede cambiar la referencia del proyecto de System.Drawing a Aspose.Drawing y volver a compilar el programa.

Además, Aspose.Drawing es una biblioteca administrada disponible para NET Framework 2.0 y NET Core 2.0. A diferencia de System.Drawing, no tiene dependencias en ninguna plataforma como Linux, Azure, etc.

Uso de Aspose.Drawing en servicios ASP.NET

La implementación de Aspose.Drawing no depende de GDI o GDI+. No usa identificadores GDI y rara vez usa bloqueos de todo el proceso.

Demostración para usar Aspose.Drawing en ASP.NET Services

Vamos a crear una aplicación simple que explique los beneficios de usar la biblioteca Aspose.Drawing:

Imagine que decide crear una aplicación o servicio web completamente nuevo. La aplicación generará un conjunto de miniaturas con filtros adjuntos a la imagen del usuario.

Puede comenzar introduciendo algunas entidades nuevas:

///<summary>
/// Tipos de filtros disponibles.
///</summary>
public enum FilterType
{
    ///<summary>
    /// Filtro para generación de imagen saturada de color rojo.
    ///</summary>
    Red,

    ///<summary>
    /// Filtro para generación de imagen saturada de color verde.
    ///</summary>
    Green,

    ///<summary>
    /// Filtro para generación de imagen saturada de color azul.
    ///</summary>
    Blue,

    ///<summary>
    /// Filtro para la generación de una imagen en escala de grises.
    ///</summary>
    Grayscale,

    ///<summary>
    /// Filtro para generación de imagen en negativo.
    ///</summary>
    Negative,

    ///<summary>
    /// Filtro para generación de imagen sepia.
    ///</summary>
    Sepia,
}
///<summary>
/// El resultado de la generación de miniaturas filtradas.
///</summary>
public class FilterThumbnailResult
{
    ///<summary>
    /// Inicializa una nueva instancia de la clase FilterThumbnailResult.
    ///</summary>
    ///<param name="filterType"> El tipo de filtro aplicado a la miniatura.</param>
    ///<param name="pngData"> Los datos de la imagen en formato PNG.</param>
    ///<param name="width"> El ancho de la miniatura.</param>
    ///<param name="height"> La altura de la miniatura.</param>
    public FilterThumbnailResult(FilterType filterType, byte[] pngData, int width, int height)
    {
        this.FilterType = filterType;
        this.PngData = pngData;
        this.Width = width;
        this.Height = height;
    }

    ///<summary>
    /// Obtiene el tipo de filtro aplicado a la miniatura.
    ///</summary>
    public FilterType FilterType { get; }

    ///<summary>
    /// Obtiene los datos de la imagen en formato PNG.
    ///</summary>
    public byte[] PngData { get; }

    ///<summary>
    /// Obtiene el ancho de la miniatura.
    ///</summary>
    public int Width { get; }

    ///<summary>
    /// Obtiene la altura de la miniatura.
    ///</summary>
    public int Height { get; }
}

Ahora puede definir la interfaz para la generación de miniaturas con filtros adjuntos:

using System.Collections.Generic;

///<summary>
/// La interfaz para la generación de imágenes en miniatura.
///</summary>
public interface IThumbnailGenerator
{
    ///<summary>
    /// Genera un conjunto de miniaturas para todos los filtros disponibles.
    ///</summary>
    ///<param name="sourceImage"> Bytes de la imagen de origen.</param>
    ///<param name="width"> Ancho solicitado de las imágenes de vista previa.</param>
    ///<param name="height"> Altura solicitada de las imágenes de vista previa.</param>
    ///<returns> Un conjunto de miniaturas.</returns>
    IEnumerable<FilterThumbnailResult> GenerateAllThumbnails(byte[] sourceImage, int width, int height);
}

Pasando a la implementación, suponga que implementa la interfaz IThumbnailGenerator mediante la biblioteca System.Drawing. Se verá como el siguiente fragmento de código:

///<summary>
/// Implementación de la interfaz IThumbnailGenerator usando System.Drawing.
///</summary>
public class ThumbnailGenerator
    : IThumbnailGenerator
{
    ///<summary>
    /// Un conjunto de procesadores de miniaturas.
    ///</summary>
    private static readonly FilterThumbnailProcessor[] Processors = new FilterThumbnailProcessor[] 
    {
        ApplyRedFilter,
        ApplyGreenFilter,
        ApplyBlueFilter,
        ApplyGrayFilter,
        ApplyNegativeFilter,
        ApplySepiaFilter,
    };

    ///<summary>
    /// Delegado para procesamiento de miniaturas.
    ///</summary>
    ///<param name="thumbnail"> Miniatura de la imagen original.</param>
    ///<returns> Resultado de la generación de miniaturas filtradas.</returns>
    private delegate FilterThumbnailResult FilterThumbnailProcessor(Bitmap thumbnail);

    ///<summary>
    /// Genera un conjunto de miniaturas para todos los filtros disponibles.
    ///</summary>
    ///<param name="sourceImage"> Bytes de la imagen de origen.</param>
    ///<param name="width"> Ancho solicitado de las imágenes de vista previa.</param>
    ///<param name="height"> Altura solicitada de las imágenes de vista previa.</param>
    ///<returns> Un conjunto de miniaturas.</returns>
    public IEnumerable<FilterThumbnailResult> GenerateAllThumbnails(byte[] sourceImage, int width, int height)
    {
        using (MemoryStream ms = new MemoryStream(sourceImage))
        using (Bitmap bitmap = new Bitmap(ms))
        {
            foreach (var processor in Processors)
            {
                using (Bitmap previewBitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb))
                using (Graphics graphics = Graphics.FromImage(previewBitmap))
                {
                    graphics.DrawImage(bitmap, 0, 0, width, height);

                    yield return processor(previewBitmap);
                }
            }
        }
    }

    ///<summary>
    /// Aplica un filtro rojo a la miniatura.
    ///</summary>
    ///<param name="thumbnail"> Miniatura de la imagen original.</param>
    ///<returns> Resultado de la generación de miniaturas filtradas.</returns>
    private static FilterThumbnailResult ApplyRedFilter(Bitmap thumbnail)
    {
    ...
    }

    ///<summary>
    /// Aplica un filtro verde a la miniatura.
    ///</summary>
    ///<param name="thumbnail"> Miniatura de la imagen original.</param>
    ///<returns> Resultado de la generación de miniaturas filtradas.</returns>
    private static FilterThumbnailResult ApplyGreenFilter(Bitmap thumbnail)
    {
    ...
    }

    ///<summary>
    /// Aplica un filtro azul a la miniatura.
    ///</summary>
    ///<param name="thumbnail"> Miniatura de la imagen original.</param>
    ///<returns> Resultado de la generación de miniaturas filtradas.</returns>
    private static FilterThumbnailResult ApplyBlueFilter(Bitmap thumbnail)
    {
    ...
    }

    ///<summary>
    /// Aplica un filtro gris a la miniatura.
    ///</summary>
    ///<param name="thumbnail"> Miniatura de la imagen original.</param>
    ///<returns> Resultado de la generación de miniaturas filtradas.</returns>
    private static FilterThumbnailResult ApplyGrayFilter(Bitmap thumbnail)
    {
    ...
    }

    ///<summary>
    /// Aplica un filtro negativo a la miniatura.
    ///</summary>
    ///<param name="thumbnail"> Miniatura de la imagen original.</param>
    ///<returns> Resultado de la generación de miniaturas filtradas.</returns>
    private static FilterThumbnailResult ApplyNegativeFilter(Bitmap thumbnail)
    {
    ...
    }

    ///<summary>
    /// Aplica un filtro sepia a la miniatura.
    ///</summary>
    ///<param name="thumbnail"> Miniatura de la imagen original.</param>
    ///<returns> Resultado de la generación de miniaturas filtradas.</returns>
    private static FilterThumbnailResult ApplySepiaFilter(Bitmap thumbnail)
    {
    ...
    }
}

El código funcionará bien, pero tiene una desventaja: genera todas las miniaturas secuencialmente. La biblioteca System.Drawing se basa en una biblioteca GDI+ bastante antigua que se diseñó como una biblioteca de un solo subproceso, por lo que puede desperdiciar recursos cuando hay varios núcleos de CPU.

El uso de Aspose.Drawing puede ayudar a mejorar significativamente el rendimiento porque no tiene limitaciones relacionadas con un solo hilo. Intente cambiar solo una función:

///<summary>
/// Genera un conjunto de miniaturas para todos los filtros disponibles.
///</summary>
///<param name="sourceImage"> Bytes de la imagen de origen.</param>
///<param name="width"> Ancho solicitado de las imágenes de vista previa.</param>
///<param name="height"> Altura solicitada de las imágenes de vista previa.</param>
///<returns> Un conjunto de miniaturas.</returns>
public IEnumerable<FilterThumbnailResult> GenerateAllThumbnails(byte[] sourceImage, int width, int height)
{
    using (MemoryStream ms = new MemoryStream(sourceImage))
    using (Bitmap bitmap = new Bitmap(ms))
    {
        ConcurrentBag<FilterThumbnailResult> collection = new ConcurrentBag<FilterThumbnailResult>();

        Parallel.ForEach(Processors, (processor) =>
        {
            using (Bitmap previewBitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb))
            using (Graphics graphics = Graphics.FromImage(previewBitmap))
            {
                graphics.DrawImage(bitmap, 0, 0, width, height);
                collection.Add(processor(previewBitmap));
            }
        });

        return collection;
    }
}

Este código ahora puede usar múltiples núcleos de CPU sin cambios significativos en el código fuente original. Reemplazar System.Drawing con Aspose.Drawing acelera el rendimiento de sus aplicaciones y servicios.

Descargar código fuente

Puede descargar el Código fuente relacionado con este ejemplo para su referencia.

Licencia de evaluación de API gratuita

Puede solicitar una Licencia temporal gratuita para probar la API en toda su capacidad.

Conclusión

En conclusión, ha aprendido con el ejemplo lo simple que es usar la biblioteca Aspose.Drawing en sus servicios ASP.NET y ASP.NET Core. Además, Aspose.Drawing no tiene problemas o dependencias externas que existen en System.Drawing. Además, puede explorar la API en detalle consultando la Documentación. ¡No dude en contactarnos en cualquier momento a través del Foro de soporte gratuito para cualquiera de sus consultas!

Ver también