System.Drawing в ASP .NET ASP.NET Core

Є багато питань, пов’язаних з використанням бібліотеки System.Drawing в сервісах ASP.NET. Найпоширенішою відповіддю є те, що Microsoft не рекомендує використовувати System.Drawing у службах ASP.NET.

У цій статті ви дізнаєтеся подробиці про використання інтерфейсу бібліотеки System.Drawing у службах ASP.NET із Aspose.Drawing for .NET. Наступні розділи структурують всю відповідну інформацію:

Чому Aspose.Drawing?

Microsoft не рекомендує використовувати свою бібліотеку System.Drawing у службах ASP.NET. На домашній сторінці System.Drawing документація зазначено:

Класи в просторі імен System.Drawing не підтримуються для використання в службі Windows або ASP.NET. Спроба використовувати ці класи в одному з цих типів програм може призвести до винятків під час виконання та зниження продуктивності служби.

Є дві основні проблеми, які змушують Microsoft написати вище застереження. Перша проблема полягає у використанні рідної бібліотеки GDI+ і, як результат, у використанні дескрипторів GDI. У той час як друге занепокоєння - це проблеми паралельності. Наприклад, блокування всього процесу відбувається під час будь-якої операції DrawImage(). Таким чином, ви не можете створити швидкі та масштабовані служби ASP.NET за допомогою бібліотеки System.Drawing від Microsoft.

Встановлення Aspose.Drawing for .NET API

Ви можете легко завантажити файл DLL із розділу Завантаження або налаштувати його за допомогою менеджера пакетів NuGet за допомогою такої команди:

PM> Install-Package Aspose.Drawing

Aspose.Drawing for .NET API – вступ

Ми розуміємо, що System.Drawing дуже популярний серед розробників завдяки функціям обробки зображень. Ось чому ми створили схожий і сумісний API без проблем із сумісністю. Для вашої зручності та адаптації API містить однакові назви класів, функцій, переліків та інтерфейсів. Ви можете просто змінити посилання на проект із System.Drawing на Aspose.Drawing і перекомпілювати програму.

Крім того, Aspose.Drawing — це керована бібліотека, доступна для NET Framework 2.0 і NET Core 2.0. На відміну від System.Drawing, він не залежить від жодної платформи, як-от Linux, Azure тощо.

Використання Aspose.Drawing у службах ASP.NET

Реалізація Aspose.Drawing не залежить від GDI або GDI+. Він не використовує ручки GDI і рідко використовує блокування для всього процесу.

Демонстрація використання Aspose.Drawing у службах ASP.NET

Давайте створимо просту програму, яка пояснює переваги використання бібліотеки Aspose.Drawing:

Уявіть, що ви вирішили створити абсолютно новий веб-сервіс або додаток. Додаток створить набір мініатюр із прикріпленими до них фільтрами із зображення користувача.

Ви можете почати з введення кількох нових сутностей:

///<summary>
/// Доступні типи фільтрів.
///</summary>
public enum FilterType
{
    ///<summary>
    /// Фільтр для створення зображення насиченого червоного кольору.
    ///</summary>
    Red,

    ///<summary>
    /// Фільтр для створення зображення насиченого зеленого кольору.
    ///</summary>
    Green,

    ///<summary>
    /// Фільтр для створення зображення насиченого синього кольору.
    ///</summary>
    Blue,

    ///<summary>
    /// Фільтр для створення сірого зображення.
    ///</summary>
    Grayscale,

    ///<summary>
    /// Фільтр для генерації негативного зображення.
    ///</summary>
    Negative,

    ///<summary>
    /// Фільтр для створення зображення сепії.
    ///</summary>
    Sepia,
}
///<summary>
/// Результат створення відфільтрованих мініатюр.
///</summary>
public class FilterThumbnailResult
{
    ///<summary>
    /// Ініціалізує новий екземпляр класу FilterThumbnailResult.
    ///</summary>
    ///<param name="filterType"> Тип фільтра, застосованого до мініатюри.</param>
    ///<param name="pngData"> Дані зображення у форматі PNG.</param>
    ///<param name="width"> Ширина мініатюри.</param>
    ///<param name="height"> Висота мініатюри.</param>
    public FilterThumbnailResult(FilterType filterType, byte[] pngData, int width, int height)
    {
        this.FilterType = filterType;
        this.PngData = pngData;
        this.Width = width;
        this.Height = height;
    }

    ///<summary>
    /// Отримує тип фільтра, застосованого до мініатюри.
    ///</summary>
    public FilterType FilterType { get; }

    ///<summary>
    /// Отримує дані зображення у форматі PNG.
    ///</summary>
    public byte[] PngData { get; }

    ///<summary>
    /// Отримує ширину мініатюри.
    ///</summary>
    public int Width { get; }

    ///<summary>
    /// Отримує висоту мініатюри.
    ///</summary>
    public int Height { get; }
}

Тепер ви можете визначити інтерфейс для генерації мініатюр із доданими фільтрами:

using System.Collections.Generic;

///<summary>
/// Інтерфейс для створення мініатюр зображень.
///</summary>
public interface IThumbnailGenerator
{
    ///<summary>
    /// Створює набір мініатюр для всіх доступних фільтрів.
    ///</summary>
    ///<param name="sourceImage"> Байти вихідного зображення.</param>
    ///<param name="width"> Запитана ширина зображень попереднього перегляду.</param>
    ///<param name="height"> Запитана висота зображень попереднього перегляду.</param>
    ///<returns> Набір мініатюр.</returns>
    IEnumerable<FilterThumbnailResult> GenerateAllThumbnails(byte[] sourceImage, int width, int height);
}

Переходячи до реалізації, припустимо реалізацію інтерфейсу IThumbnailGenerator за допомогою бібліотеки System.Drawing. Це виглядатиме як наступний фрагмент коду:

///<summary>
/// Реалізація інтерфейсу IThumbnailGenerator за допомогою System.Drawing.
///</summary>
public class ThumbnailGenerator
    : IThumbnailGenerator
{
    ///<summary>
    /// Набір процесорів мініатюр.
    ///</summary>
    private static readonly FilterThumbnailProcessor[] Processors = new FilterThumbnailProcessor[] 
    {
        ApplyRedFilter,
        ApplyGreenFilter,
        ApplyBlueFilter,
        ApplyGrayFilter,
        ApplyNegativeFilter,
        ApplySepiaFilter,
    };

    ///<summary>
    /// Делегат для обробки мініатюр.
    ///</summary>
    ///<param name="thumbnail"> Мініатюра вихідного зображення.</param>
    ///<returns> Результат створення відфільтрованих мініатюр.</returns>
    private delegate FilterThumbnailResult FilterThumbnailProcessor(Bitmap thumbnail);

    ///<summary>
    /// Створює набір мініатюр для всіх доступних фільтрів.
    ///</summary>
    ///<param name="sourceImage"> Байти вихідного зображення.</param>
    ///<param name="width"> Запитана ширина зображень попереднього перегляду.</param>
    ///<param name="height"> Запитана висота зображень попереднього перегляду.</param>
    ///<returns> Набір мініатюр.</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>
    /// Застосовує червоний фільтр до мініатюри.
    ///</summary>
    ///<param name="thumbnail"> Мініатюра вихідного зображення.</param>
    ///<returns> Результат створення відфільтрованих мініатюр.</returns>
    private static FilterThumbnailResult ApplyRedFilter(Bitmap thumbnail)
    {
    ...
    }

    ///<summary>
    /// Застосовує зелений фільтр до мініатюри.
    ///</summary>
    ///<param name="thumbnail"> Мініатюра вихідного зображення.</param>
    ///<returns> Результат створення відфільтрованих мініатюр.</returns>
    private static FilterThumbnailResult ApplyGreenFilter(Bitmap thumbnail)
    {
    ...
    }

    ///<summary>
    /// Застосовує синій фільтр до мініатюри.
    ///</summary>
    ///<param name="thumbnail"> Мініатюра вихідного зображення.</param>
    ///<returns> Результат створення відфільтрованих мініатюр.</returns>
    private static FilterThumbnailResult ApplyBlueFilter(Bitmap thumbnail)
    {
    ...
    }

    ///<summary>
    /// Застосовує сірий фільтр до мініатюри.
    ///</summary>
    ///<param name="thumbnail"> Мініатюра вихідного зображення.</param>
    ///<returns> Результат створення відфільтрованих мініатюр.</returns>
    private static FilterThumbnailResult ApplyGrayFilter(Bitmap thumbnail)
    {
    ...
    }

    ///<summary>
    /// Застосовує негативний фільтр до мініатюри.
    ///</summary>
    ///<param name="thumbnail"> Мініатюра вихідного зображення.</param>
    ///<returns> Результат створення відфільтрованих мініатюр.</returns>
    private static FilterThumbnailResult ApplyNegativeFilter(Bitmap thumbnail)
    {
    ...
    }

    ///<summary>
    /// Застосовує фільтр сепії до мініатюри.
    ///</summary>
    ///<param name="thumbnail"> Мініатюра вихідного зображення.</param>
    ///<returns> Результат створення відфільтрованих мініатюр.</returns>
    private static FilterThumbnailResult ApplySepiaFilter(Bitmap thumbnail)
    {
    ...
    }
}

Код працюватиме добре, але він має один недолік — він генерує всі мініатюри послідовно. Бібліотека System.Drawing заснована на досить старій бібліотеці GDI+, яка була розроблена як однопотокова бібліотека, тому вона може витрачати ресурси за наявності кількох ядер ЦП.

Використання Aspose.Drawing може допомогти значно підвищити продуктивність, оскільки воно не має жодних обмежень, пов’язаних із одним потоком. Спробуйте змінити лише одну функцію:

///<summary>
/// Створює набір мініатюр для всіх доступних фільтрів.
///</summary>
///<param name="sourceImage"> Байти вихідного зображення.</param>
///<param name="width"> Запитана ширина зображень попереднього перегляду.</param>
///<param name="height"> Запитана висота зображень попереднього перегляду.</param>
///<returns> Набір мініатюр.</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;
    }
}

Цей код тепер може використовувати кілька ядер ЦП без суттєвих змін у вихідному коді. Заміна System.Drawing на Aspose.Drawing прискорює роботу ваших програм і служб.

Завантажити вихідний код

Ви можете завантажити вихідний код, пов’язаний із цим прикладом, для довідки.

Безкоштовна ліцензія на оцінку API

Ви можете надіслати запит на отримання безкоштовної тимчасової ліцензії, щоб протестувати API на повну потужність.

Висновок

Підсумовуючи, на прикладі ви дізналися, наскільки просто використовувати бібліотеку Aspose.Drawing у своїх службах ASP.NET і ASP.NET Core. Крім того, Aspose.Drawing не має проблем або зовнішніх залежностей, які існують у System.Drawing. Крім того, ви можете детально вивчити API, переглянувши Документацію. Будь ласка, не соромтеся зв’язуватися з нами в будь-який час через Безкоштовний форум підтримки для будь-яких запитів!

Дивись також