System.Drawing w ASP .NET ASP.NET Core

Istnieje wiele pytań poświęconych wykorzystaniu biblioteki System.Drawing w usługach ASP.NET. Najczęstszą odpowiedzią jest to, że Microsoft nie zaleca używania System.Drawing w usługach ASP.NET.

W tym artykule poznasz szczegóły wykorzystania interfejsu biblioteki System.Drawing w usługach ASP.NET z Aspose.Drawing for .NET. Poniższe sekcje porządkują wszystkie istotne informacje:

Dlaczego Aspose.Drawing?

Firma Microsoft nie zaleca używania swojej biblioteki System.Drawing w usługach ASP.NET. Strona główna System.Drawing dokumentacja brzmi:

Klasy w przestrzeni nazw System.Drawing nie są obsługiwane w usługach Windows lub ASP.NET. Próba użycia tych klas z jednego z tych typów aplikacji może spowodować wyjątki w czasie wykonywania i zmniejszoną wydajność usługi.

Istnieją dwa podstawowe problemy, które zmuszają Microsoft do napisania powyżej ostrożności. Pierwszym problemem jest użycie natywnej biblioteki GDI+ iw efekcie użycie uchwytów GDI. Podczas gdy drugim problemem są problemy z współbieżnością. Na przykład podczas dowolnej operacji DrawImage() występuje blokada obejmująca cały proces. Dlatego nie można tworzyć szybkich i skalowalnych usług ASP.NET przy użyciu biblioteki System.Drawing firmy Microsoft.

Instalowanie Aspose.Drawing dla interfejsu API platformy .NET

Możesz łatwo pobrać plik DLL z sekcji Downloads lub skonfigurować go za pomocą menedżera pakietów NuGet za pomocą następującego polecenia:

PM> Install-Package Aspose.Drawing

Aspose.Drawing dla interfejsu API platformy .NET — wprowadzenie

Rozumiemy, że System.Drawing jest bardzo popularny wśród programistów ze względu na jego funkcje manipulacji obrazami. Dlatego stworzyliśmy podobne i kompatybilne API bez żadnych problemów ze zgodnością. Dla Twojej wygody i możliwości adaptacji interfejs API zawiera te same nazwy klas, funkcji, wyliczeń i interfejsów. Możesz po prostu zmienić odniesienie do projektu z System.Drawing na Aspose.Drawing i ponownie skompilować program.

Co więcej, Aspose.Drawing jest zarządzaną biblioteką dostępną dla NET Framework 2.0 i NET Core 2.0. W przeciwieństwie do System.Drawing nie ma zależności od żadnej platformy, takiej jak Linux, Azure itp.

Używanie Aspose.Drawing w usługach ASP.NET

Implementacja Aspose.Drawing nie zależy od GDI ani GDI+. Nie używa uchwytów GDI i rzadko używa blokad obejmujących cały proces.

Demonstracja użycia Aspose.Drawing w usługach ASP.NET

Stwórzmy prostą aplikację wyjaśniającą korzyści płynące z korzystania z biblioteki Aspose.Drawing:

Wyobraź sobie, że postanawiasz stworzyć zupełnie nową usługę internetową lub aplikację. Aplikacja wygeneruje zestaw miniaturek z dołączonymi do nich filtrami z obrazu użytkownika.

Możesz zacząć od wprowadzenia kilku nowych podmiotów:

///<summary>
/// Dostępne rodzaje filtrów.
///</summary>
public enum FilterType
{
    ///<summary>
    /// Filtr do generowania obrazu nasyconego kolorem czerwonym.
    ///</summary>
    Red,

    ///<summary>
    /// Filtr do generowania obrazu nasyconego kolorem zielonym.
    ///</summary>
    Green,

    ///<summary>
    /// Filtr do generowania obrazu nasyconego kolorem niebieskim.
    ///</summary>
    Blue,

    ///<summary>
    /// Filtr do generowania obrazu w skali szarości.
    ///</summary>
    Grayscale,

    ///<summary>
    /// Filtr do generowania negatywu.
    ///</summary>
    Negative,

    ///<summary>
    /// Filtr do generowania obrazu w sepii.
    ///</summary>
    Sepia,
}
///<summary>
/// Wynik generowania przefiltrowanych miniatur.
///</summary>
public class FilterThumbnailResult
{
    ///<summary>
    /// Inicjuje nową instancję klasy FilterThumbnailResult.
    ///</summary>
    ///<param name="filterType"> Typ filtra zastosowanego do miniatury.</param>
    ///<param name="pngData"> Dane obrazu w formacie PNG.</param>
    ///<param name="width"> Szerokość miniatury.</param>
    ///<param name="height"> Wysokość miniatury.</param>
    public FilterThumbnailResult(FilterType filterType, byte[] pngData, int width, int height)
    {
        this.FilterType = filterType;
        this.PngData = pngData;
        this.Width = width;
        this.Height = height;
    }

    ///<summary>
    /// Pobiera typ filtra zastosowanego do miniatury.
    ///</summary>
    public FilterType FilterType { get; }

    ///<summary>
    /// Pobiera dane obrazu w formacie PNG.
    ///</summary>
    public byte[] PngData { get; }

    ///<summary>
    /// Pobiera szerokość miniatury.
    ///</summary>
    public int Width { get; }

    ///<summary>
    /// Pobiera wysokość miniatury.
    ///</summary>
    public int Height { get; }
}

Teraz możesz zdefiniować interfejs do generowania miniatur z dołączonymi filtrami:

using System.Collections.Generic;

///<summary>
/// Interfejs do generowania miniatur obrazów.
///</summary>
public interface IThumbnailGenerator
{
    ///<summary>
    /// Generuje zestaw miniatur dla wszystkich dostępnych filtrów.
    ///</summary>
    ///<param name="sourceImage"> Bajty obrazu źródłowego.</param>
    ///<param name="width"> Żądana szerokość obrazów podglądu.</param>
    ///<param name="height"> Żądana wysokość obrazów podglądu.</param>
    ///<returns> Zestaw miniatur.</returns>
    IEnumerable<FilterThumbnailResult> GenerateAllThumbnails(byte[] sourceImage, int width, int height);
}

Przechodząc do implementacji, załóżmy implementację interfejsu IThumbnailGenerator z wykorzystaniem biblioteki System.Drawing. Będzie wyglądać jak następny fragment kodu:

///<summary>
/// Implementacja interfejsu IThumbnailGenerator przy użyciu System.Drawing.
///</summary>
public class ThumbnailGenerator
    : IThumbnailGenerator
{
    ///<summary>
    /// Zestaw procesorów miniatur.
    ///</summary>
    private static readonly FilterThumbnailProcessor[] Processors = new FilterThumbnailProcessor[] 
    {
        ApplyRedFilter,
        ApplyGreenFilter,
        ApplyBlueFilter,
        ApplyGrayFilter,
        ApplyNegativeFilter,
        ApplySepiaFilter,
    };

    ///<summary>
    /// Delegat do przetwarzania miniatur.
    ///</summary>
    ///<param name="thumbnail"> Miniatura oryginalnego obrazu.</param>
    ///<returns> Wynik generowania przefiltrowanych miniatur.</returns>
    private delegate FilterThumbnailResult FilterThumbnailProcessor(Bitmap thumbnail);

    ///<summary>
    /// Generuje zestaw miniatur dla wszystkich dostępnych filtrów.
    ///</summary>
    ///<param name="sourceImage"> Bajty obrazu źródłowego.</param>
    ///<param name="width"> Żądana szerokość obrazów podglądu.</param>
    ///<param name="height"> Żądana wysokość obrazów podglądu.</param>
    ///<returns> Zestaw miniatur.</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>
    /// Stosuje czerwony filtr do miniatury.
    ///</summary>
    ///<param name="thumbnail"> Miniatura oryginalnego obrazu.</param>
    ///<returns> Wynik generowania przefiltrowanych miniatur.</returns>
    private static FilterThumbnailResult ApplyRedFilter(Bitmap thumbnail)
    {
    ...
    }

    ///<summary>
    /// Stosuje zielony filtr do miniatury.
    ///</summary>
    ///<param name="thumbnail"> Miniatura oryginalnego obrazu.</param>
    ///<returns> Wynik generowania przefiltrowanych miniatur.</returns>
    private static FilterThumbnailResult ApplyGreenFilter(Bitmap thumbnail)
    {
    ...
    }

    ///<summary>
    /// Stosuje niebieski filtr do miniatury.
    ///</summary>
    ///<param name="thumbnail"> Miniatura oryginalnego obrazu.</param>
    ///<returns> Wynik generowania przefiltrowanych miniatur.</returns>
    private static FilterThumbnailResult ApplyBlueFilter(Bitmap thumbnail)
    {
    ...
    }

    ///<summary>
    /// Stosuje szary filtr do miniatury.
    ///</summary>
    ///<param name="thumbnail"> Miniatura oryginalnego obrazu.</param>
    ///<returns> Wynik generowania przefiltrowanych miniatur.</returns>
    private static FilterThumbnailResult ApplyGrayFilter(Bitmap thumbnail)
    {
    ...
    }

    ///<summary>
    /// Stosuje filtr negatywny do miniatury.
    ///</summary>
    ///<param name="thumbnail"> Miniatura oryginalnego obrazu.</param>
    ///<returns> Wynik generowania przefiltrowanych miniatur.</returns>
    private static FilterThumbnailResult ApplyNegativeFilter(Bitmap thumbnail)
    {
    ...
    }

    ///<summary>
    /// Stosuje filtr sepii do miniatury.
    ///</summary>
    ///<param name="thumbnail"> Miniatura oryginalnego obrazu.</param>
    ///<returns> Wynik generowania przefiltrowanych miniatur.</returns>
    private static FilterThumbnailResult ApplySepiaFilter(Bitmap thumbnail)
    {
    ...
    }
}

Kod będzie działał dobrze, ale ma jedną wadę - generuje wszystkie miniatury po kolei. Biblioteka System.Drawing jest oparta na dość starej bibliotece GDI+, która została zaprojektowana jako biblioteka jednowątkowa, więc może marnować zasoby, gdy jest wiele rdzeni procesora.

Korzystanie z Aspose.Drawing może znacznie poprawić wydajność, ponieważ nie ma żadnych ograniczeń związanych z pojedynczym wątkiem. Spróbuj zmienić tylko jedną funkcję:

///<summary>
/// Generuje zestaw miniatur dla wszystkich dostępnych filtrów.
///</summary>
///<param name="sourceImage"> Bajty obrazu źródłowego.</param>
///<param name="width"> Żądana szerokość obrazów podglądu.</param>
///<param name="height"> Żądana wysokość obrazów podglądu.</param>
///<returns> Zestaw miniatur.</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;
    }
}

Ten kod może teraz wykorzystywać wiele rdzeni procesora bez żadnych znaczących zmian w oryginalnym kodzie źródłowym. Zamiana System.Drawing na Aspose.Drawing przyspiesza działanie aplikacji i usług.

Pobierz kod źródłowy

Możesz pobrać Kod źródłowy związany z tym przykładem w celach informacyjnych.

Bezpłatna licencja na ocenę interfejsu API

Możesz poprosić o Bezpłatną licencję tymczasową, aby przetestować interfejs API w pełni.

Wniosek

Podsumowując, nauczyłeś się na przykładzie, jak proste jest użycie biblioteki Aspose.Drawing w usługach ASP.NET i ASP.NET Core. Co więcej, Aspose.Drawing nie ma problemów ani zewnętrznych zależności, które istnieją w System.Drawing. Ponadto możesz szczegółowo zapoznać się z interfejsem API, przeglądając Dokumentację. W każdej chwili możesz skontaktować się z nami za pośrednictwem bezpłatnego forum pomocy technicznej w przypadku jakichkolwiek pytań!

Zobacz też