Есть много вопросов, связанных с использованием библиотеки System.Drawing в сервисах ASP.NET. Самый распространенный ответ заключается в том, что Microsoft не рекомендует использовать System.Drawing в службах ASP.NET.
В этой статье вы узнаете подробности об использовании интерфейса библиотеки System.Drawing в службах ASP.NET с помощью Aspose.Drawing for .NET. В следующих разделах структурирована вся необходимая информация:
- Почему Aspose.Drawing?
- Установка Aspose.Drawing для .NET API
- Aspose.Drawing для .NET API — Введение
- Использование Aspose.Drawing в службах ASP.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 для .NET API
Вы можете легко загрузить файл DLL из раздела Загрузки или настроить его с помощью диспетчера пакетов NuGet с помощью следующей команды:
PM> Install-Package Aspose.Drawing
Aspose.Drawing для .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, просмотрев Документацию. Пожалуйста, не стесняйтесь обращаться к нам в любое время через Бесплатный форум поддержки по любым вопросам!