ASP .NET ASP.NET Core의 System.Drawing

ASP.NET 서비스에서 System.Drawing 라이브러리를 사용하는 것과 관련된 많은 질문이 있습니다. 가장 일반적인 대답은 Microsoft가 ASP.NET 서비스에서 System.Drawing 사용을 권장하지 않는다는 것입니다.

이 기사에서는 Aspose.Drawing for .NET과 함께 ASP.NET 서비스에서 System.Drawing 라이브러리의 인터페이스를 사용하는 방법에 대해 자세히 설명합니다. 다음 섹션에서는 모든 관련 정보를 구성합니다.

왜 Aspose.Drawing?

Microsoft는 ASP.NET 서비스에서 System.Drawing 라이브러리의 사용을 권장하지 않습니다. System.Drawing 문서의 홈 페이지는 다음과 같습니다.

System.Drawing 네임스페이스 내의 클래스는 Windows 또는 ASP.NET 서비스 내에서 사용하도록 지원되지 않습니다. 이러한 응용 프로그램 유형 중 하나에서 이러한 클래스를 사용하려고 하면 런타임 예외가 발생하고 서비스 성능이 저하될 수 있습니다.

Microsoft가 위의 주의 사항을 작성하도록 하는 두 가지 기본 문제가 있습니다. 첫 번째 문제는 GDI+ 네이티브 라이브러리의 사용과 결과적으로 GDI 핸들의 사용입니다. 두 번째 관심사는 동시성 문제입니다. 예를 들어 모든 DrawImage() 작업 중에 프로세스 전체 잠금이 발생합니다. 따라서 Microsoft의 System.Drawing 라이브러리를 사용하여 빠르고 확장 가능한 ASP.NET 서비스를 만들 수 없습니다.

.NET API용 Aspose.Drawing 설치

다운로드 섹션에서 DLL 파일을 쉽게 다운로드하거나 다음 명령을 사용하여 NuGet 패키지 관리자를 통해 구성할 수 있습니다.

PM> Install-Package Aspose.Drawing

.NET API용 Aspose.Drawing - 소개

System.Drawing은 이미지 조작 기능으로 인해 개발자들 사이에서 매우 인기가 있습니다. 그렇기 때문에 호환성 문제 없이 유사하고 호환되는 API를 만들었습니다. 사용자의 편의와 적응성을 위해 API에는 동일한 이름의 클래스, 함수, 열거형 및 인터페이스가 포함되어 있습니다. 프로젝트 참조를 System.Drawing에서 Aspose.Drawing으로 변경하고 프로그램을 다시 컴파일하면 됩니다.

또한 Aspose.Drawing은 NET Framework 2.0 및 NET Core 2.0에서 사용할 수 있는 관리되는 라이브러리입니다. System.Drawing과 달리 Linux, Azure 등과 같은 플랫폼에 종속되지 않습니다.

ASP.NET 서비스에서 Aspose.Drawing 사용

Aspose.Drawing 구현은 GDI 또는 GDI+에 의존하지 않습니다. GDI 핸들을 사용하지 않으며 프로세스 전체 잠금을 거의 사용하지 않습니다.

ASP.NET 서비스에서 Aspose.Drawing 사용에 대한 데모

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);
}

구현으로 넘어가서 System.Drawing 라이브러리를 사용하여 IThumbnailGenerator 인터페이스를 구현한다고 가정합니다. 다음 코드 조각처럼 보일 것입니다.

///<summary>
/// System.Drawing을 사용한 IThumbnailGenerator 인터페이스 구현.
///</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+ 라이브러리를 기반으로 하므로 여러 CPU 코어가 있는 경우 리소스를 낭비할 수 있습니다.

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;
    }
}

이 코드는 이제 원본 소스 코드를 크게 변경하지 않고도 여러 CPU 코어를 사용할 수 있습니다. System.Drawing을 Aspose.Drawing으로 교체하면 애플리케이션 및 서비스의 성능이 빨라집니다.

소스 코드 다운로드

참고용으로 이 예제와 관련된 소스 코드를 다운로드할 수 있습니다.

무료 API 평가 라이선스

API를 전체 용량으로 테스트하려면 무료 임시 라이선스를 요청할 수 있습니다.

결론

결론적으로, ASP.NET 및 ASP.NET Core 서비스에서 Aspose.Drawing 라이브러리를 사용하는 것이 얼마나 간단한지 예제를 통해 배웠습니다. 또한 Aspose.Drawing에는 System.Drawing에 존재하는 문제나 외부 종속성이 없습니다. 또한 Documentation을 통해 API를 자세히 탐색할 수 있습니다. 궁금한 사항은 무료 지원 포럼을 통해 언제든지 문의해 주세요!

또한보십시오