System.Drawing em ASP .NET ASP.NET Core

Existem muitas questões dedicadas ao uso da biblioteca System.Drawing em serviços ASP.NET. A resposta mais comum é que a Microsoft não recomenda o uso de System.Drawing em serviços ASP.NET.

Neste artigo, você aprenderá detalhes sobre como usar a interface da biblioteca System.Drawing em serviços ASP.NET com Aspose.Drawing for .NET. As seções a seguir estruturam todas as informações relevantes:

Por que Aspose.Drawing?

A Microsoft não recomenda o uso de sua biblioteca System.Drawing em serviços ASP.NET. A página inicial do System.Drawing documentação diz:

Não há suporte para classes dentro do namespace System.Drawing para uso em um serviço Windows ou ASP.NET. A tentativa de usar essas classes em um desses tipos de aplicativo pode resultar em exceções de tempo de execução e desempenho de serviço reduzido.

Existem dois problemas básicos que obrigam a Microsoft a escrever acima de cautela. O primeiro problema é o uso da biblioteca nativa GDI+ e, como resultado, o uso de handles GDI. Enquanto a segunda preocupação é questões de simultaneidade. Por exemplo, um bloqueio em todo o processo ocorre durante qualquer operação DrawImage(). Portanto, você não pode criar serviços ASP.NET rápidos e escaláveis usando a biblioteca System.Drawing da Microsoft.

Instalando o Aspose.Drawing para .NET API

Você pode facilmente baixar o arquivo DLL da seção Downloads, ou configurá-lo através do gerenciador de pacotes NuGet com o seguinte comando:

PM> Install-Package Aspose.Drawing

Aspose.Drawing para .NET API - Introdução

Entendemos que System.Drawing é muito popular entre os desenvolvedores por causa de seus recursos de manipulação de imagens. É por isso que criamos uma API semelhante e compatível sem problemas de compatibilidade. Para sua conveniência e adaptabilidade, a API contém os mesmos nomes de classes, funções, enumerações e interfaces. Você pode simplesmente alterar a referência do projeto de System.Drawing para Aspose.Drawing e recompilar o programa.

Além disso, Aspose.Drawing é uma biblioteca gerenciada disponível para NET Framework 2.0 e NET Core 2.0. Ao contrário do System.Drawing, ele não tem dependências em nenhuma plataforma como Linux, Azure, etc.

Usando Aspose.Drawing em ASP.NET Services

A implementação do Aspose.Drawing não depende de GDI ou GDI+. Ele não usa identificadores GDI e raramente usa bloqueios em todo o processo.

Demonstração para usar o Aspose.Drawing no ASP.NET Services

Vamos criar um aplicativo simples que explica os benefícios de usar a biblioteca Aspose.Drawing:

Imagine que você decida criar um serviço ou aplicativo da Web totalmente novo. O aplicativo irá gerar um conjunto de miniaturas com filtros anexados a elas a partir da imagem do usuário.

Você pode começar apresentando algumas novas entidades:

///<summary>
/// Tipos de filtros disponíveis.
///</summary>
public enum FilterType
{
    ///<summary>
    /// Filtro para geração de imagem saturada com cor vermelha.
    ///</summary>
    Red,

    ///<summary>
    /// Filtro para geração de imagem saturada com cor verde.
    ///</summary>
    Green,

    ///<summary>
    /// Filtro para geração de imagem saturada com cor azul.
    ///</summary>
    Blue,

    ///<summary>
    /// Filtro para geração de imagem em tons de cinza.
    ///</summary>
    Grayscale,

    ///<summary>
    /// Filtro para geração de imagem negativa.
    ///</summary>
    Negative,

    ///<summary>
    /// Filtro para geração de imagem sépia.
    ///</summary>
    Sepia,
}
///<summary>
/// O resultado da geração de miniaturas filtradas.
///</summary>
public class FilterThumbnailResult
{
    ///<summary>
    /// Inicializa uma nova instância da classe FilterThumbnailResult.
    ///</summary>
    ///<param name="filterType"> O tipo de filtro aplicado à miniatura.</param>
    ///<param name="pngData"> Os dados da imagem no formato PNG.</param>
    ///<param name="width"> A largura da miniatura.</param>
    ///<param name="height"> A altura da 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>
    /// Obtém o tipo de filtro aplicado à miniatura.
    ///</summary>
    public FilterType FilterType { get; }

    ///<summary>
    /// Obtém os dados da imagem no formato PNG.
    ///</summary>
    public byte[] PngData { get; }

    ///<summary>
    /// Obtém a largura da miniatura.
    ///</summary>
    public int Width { get; }

    ///<summary>
    /// Obtém a altura da miniatura.
    ///</summary>
    public int Height { get; }
}

Agora você pode definir a interface para a geração de miniaturas com filtros anexados:

using System.Collections.Generic;

///<summary>
/// A interface para geração de imagens em miniatura.
///</summary>
public interface IThumbnailGenerator
{
    ///<summary>
    /// Gera um conjunto de miniaturas para todos os filtros disponíveis.
    ///</summary>
    ///<param name="sourceImage"> Bytes da imagem de origem.</param>
    ///<param name="width"> Largura solicitada das imagens de visualização.</param>
    ///<param name="height"> Altura solicitada das imagens de visualização.</param>
    ///<returns> Um conjunto de miniaturas.</returns>
    IEnumerable<FilterThumbnailResult> GenerateAllThumbnails(byte[] sourceImage, int width, int height);
}

Passando para a implementação, suponha a implementação da interface IThumbnailGenerator usando a biblioteca System.Drawing. Será parecido com o próximo trecho de código:

///<summary>
/// Implementação da interface IThumbnailGenerator usando System.Drawing.
///</summary>
public class ThumbnailGenerator
    : IThumbnailGenerator
{
    ///<summary>
    /// Um conjunto de processadores de miniaturas.
    ///</summary>
    private static readonly FilterThumbnailProcessor[] Processors = new FilterThumbnailProcessor[] 
    {
        ApplyRedFilter,
        ApplyGreenFilter,
        ApplyBlueFilter,
        ApplyGrayFilter,
        ApplyNegativeFilter,
        ApplySepiaFilter,
    };

    ///<summary>
    /// Delegado para processamento de miniaturas.
    ///</summary>
    ///<param name="thumbnail"> Miniatura da imagem original.</param>
    ///<returns> Resultado da geração de miniaturas filtradas.</returns>
    private delegate FilterThumbnailResult FilterThumbnailProcessor(Bitmap thumbnail);

    ///<summary>
    /// Gera um conjunto de miniaturas para todos os filtros disponíveis.
    ///</summary>
    ///<param name="sourceImage"> Bytes da imagem de origem.</param>
    ///<param name="width"> Largura solicitada das imagens de visualização.</param>
    ///<param name="height"> Altura solicitada das imagens de visualização.</param>
    ///<returns> Um 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 um filtro vermelho à miniatura.
    ///</summary>
    ///<param name="thumbnail"> Miniatura da imagem original.</param>
    ///<returns> Resultado da geração de miniaturas filtradas.</returns>
    private static FilterThumbnailResult ApplyRedFilter(Bitmap thumbnail)
    {
    ...
    }

    ///<summary>
    /// Aplica um filtro verde à miniatura.
    ///</summary>
    ///<param name="thumbnail"> Miniatura da imagem original.</param>
    ///<returns> Resultado da geração de miniaturas filtradas.</returns>
    private static FilterThumbnailResult ApplyGreenFilter(Bitmap thumbnail)
    {
    ...
    }

    ///<summary>
    /// Aplica um filtro azul à miniatura.
    ///</summary>
    ///<param name="thumbnail"> Miniatura da imagem original.</param>
    ///<returns> Resultado da geração de miniaturas filtradas.</returns>
    private static FilterThumbnailResult ApplyBlueFilter(Bitmap thumbnail)
    {
    ...
    }

    ///<summary>
    /// Aplica um filtro cinza à miniatura.
    ///</summary>
    ///<param name="thumbnail"> Miniatura da imagem original.</param>
    ///<returns> Resultado da geração de miniaturas filtradas.</returns>
    private static FilterThumbnailResult ApplyGrayFilter(Bitmap thumbnail)
    {
    ...
    }

    ///<summary>
    /// Aplica um filtro negativo à miniatura.
    ///</summary>
    ///<param name="thumbnail"> Miniatura da imagem original.</param>
    ///<returns> Resultado da geração de miniaturas filtradas.</returns>
    private static FilterThumbnailResult ApplyNegativeFilter(Bitmap thumbnail)
    {
    ...
    }

    ///<summary>
    /// Aplica um filtro sépia à miniatura.
    ///</summary>
    ///<param name="thumbnail"> Miniatura da imagem original.</param>
    ///<returns> Resultado da geração de miniaturas filtradas.</returns>
    private static FilterThumbnailResult ApplySepiaFilter(Bitmap thumbnail)
    {
    ...
    }
}

O código funcionará bem, mas tem uma desvantagem - ele gera todas as miniaturas sequencialmente. A biblioteca System.Drawing é baseada na biblioteca GDI+ bastante antiga, que foi projetada como uma biblioteca de thread único para que possa desperdiçar recursos quando houver vários núcleos de CPU.

O uso do Aspose.Drawing pode ajudar a melhorar significativamente o desempenho, pois não possui limitações relacionadas a um único thread. Por favor, tente alterar apenas uma função:

///<summary>
/// Gera um conjunto de miniaturas para todos os filtros disponíveis.
///</summary>
///<param name="sourceImage"> Bytes da imagem de origem.</param>
///<param name="width"> Largura solicitada das imagens de visualização.</param>
///<param name="height"> Altura solicitada das imagens de visualização.</param>
///<returns> Um 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;
    }
}

Esse código agora pode usar vários núcleos de CPU sem alterações significativas no código-fonte original. Substituir System.Drawing por Aspose.Drawing agiliza o desempenho de seus aplicativos e serviços.

Baixar código fonte

Você pode baixar o Código-fonte relacionado a este exemplo para sua referência.

Licença de avaliação de API gratuita

Você pode solicitar uma Licença Temporária Gratuita para testar a API em sua capacidade total.

Conclusão

Concluindo, você aprendeu com o exemplo como é simples usar a biblioteca Aspose.Drawing em seus serviços ASP.NET e ASP.NET Core. Além disso, Aspose.Drawing não tem problemas ou dependências externas que existem em System.Drawing. Além disso, você pode explorar a API em detalhes acessando a Documentação. Sinta-se à vontade para entrar em contato conosco a qualquer momento através do Fórum de suporte gratuito para qualquer dúvida!

Veja também