ASP .NETASP.NETCoreでの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に上記の注意を書かせざるを得ない2つの基本的な問題があります。最初の問題は、GDI +ネイティブライブラリの使用であり、その結果、GDIハンドルの使用です。 2番目の懸念は並行性の問題です。たとえば、プロセス全体のロックは、DrawImage()操作中に発生します。したがって、MicrosoftのSystem.Drawingライブラリを使用して、高速でスケーラブルなASP.NETサービスを作成することはできません。

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は、NETFramework2.0およびNETCore2.0で使用できるマネージドライブラリです。 System.Drawingとは異なり、Linux、Azureなどのプラットフォームには依存しません。

ASP.NETサービスでのAspose.Drawingの使用

Aspose.Drawingの実装は、GDIまたはGDI+に依存しません。 GDIハンドルを使用せず、プロセス全体のロックを使用することはめったにありません。

ASP.NETサービスでAspose.Drawingを使用するためのデモンストレーション

Aspose.Drawingライブラリを使用する利点を説明する簡単なアプリケーションを作成しましょう。

まったく新しいWebサービスまたはアプリケーションを作成することにしたと想像してみてください。アプリケーションは、ユーザーの画像からフィルターがアタッチされたサムネイルのセットを生成します。

いくつかの新しいエンティティを導入することから始めることができます。

///<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)
    {
    ...
    }
}

コードは正常に機能しますが、1つの欠点があります。それは、すべてのサムネイルを順番に生成することです。 System.Drawingライブラリは、シングルスレッドライブラリとして設計された非常に古いGDI +ライブラリに基づいているため、複数のCPUコアがある場合にリソースを浪費する可能性があります。

Aspose.Drawingを使用すると、シングルスレッドに関連する制限がないため、パフォーマンスを大幅に向上させることができます。 1つの機能のみを変更してみてください。

///<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.NETCoreサービスでAspose.Drawingライブラリを使用するのがいかに簡単であるかを例を挙げて学びました。さらに、Aspose.Drawingには、System.Drawingに存在する問題や外部依存関係はありません。さらに、ドキュメントを参照することで、APIを詳細に調べることができます。ご不明な点がございましたら、無料サポートフォーラムからいつでもお気軽にお問い合わせください。

関連項目