33

奇妙な GDI+ エラーを数日間追跡した後、 MSDNでこの小さな宝石を見つけました。

System.Drawing 名前空間内のクラスは、Windows または ASP.NET サービス内での使用はサポートされていません。これらのアプリケーション タイプのいずれかからこれらのクラスを使用しようとすると、サービス パフォーマンスの低下やランタイム例外など、予期しない問題が発生する可能性があります。

このコンテキストで「ASP.NET サービス」が「Web アプリケーション」を意味するかどうかはわかりませんが、「サービス パフォーマンスの低下」は、「GDI+ で一般的なエラーが発生しました」エラーと「メモリ不足」エラーのランダムな組み合わせをカバーしているようです。私のアプリがスローしていること - 多くの場合、最初に System.Drawing.Imaging によって実際に作成された JPEG 画像の読み取りと書き込みの断続的で再現性のないエラー。

では、Web アプリで GDI+ が JPEG ファイルを確実に読み書きできない場合、代わりに何を使用すればよいでしょうか?

ユーザーが画像をアップロードし (JPEG が必要、その他の形式があると便利)、それらを確実に再サンプリングし、問題が発生した場合に有用なエラー メッセージを表示できるようにしたいと考えています。何か案は?WPF の System.Media 名前空間は検討する価値がありますか?

編集:ええ、GDI +が「ほとんどの場合」機能することは知っています。失敗した場合、正常に分離または回復することが不可能な方法で失敗するため、これでは十分ではありません。あなたに役立つ GDI+ コードの例には興味がありません。画像処理に使用する代替ライブラリを探しています。

4

8 に答える 8

11

TopTen Software Blogには、相互運用によるImageMagick グラフィックス ライブラリの使用に関する C# コードを含む優れたブログ記事があります。この記事では特に、mono 環境の Linux で ASP.net を実行する方法について説明します。ただし、C# コードは完全にコピー アンド ペースト可能である必要があります。ウィンドウ バイナリ (DLL) を参照するウィンドウで実行している場合、変更する必要があるのは Interop 属性だけです。

ImageMagick® は、ビットマップ イメージを作成、編集、構成、または変換するためのソフトウェア スイートです。DPX、EXR、GIF、JPEG、JPEG-2000、PDF、PhotoCD、PNG、Postscript、SVG、TIFF など、さまざまな形式 (100 以上) の画像を読み書きできます。ImageMagick を使用して、画像のサイズ変更、反転、鏡像化、回転、ゆがみ、せん断、変換、画像の色の調整、さまざまな特殊効果の適用、またはテキスト、線、多角形、楕円、ベジエ曲線の描画を行います。

すべてをまとめた codeplexのImageMagick .Net 開発プロジェクトもあります。ただし、2009 年以降は活発な開発が行われていないため、現在の ImageMagick ライブラリのバージョンよりも遅れている可能性があります。小さな些細なサイズ変更ルーチンの場合、おそらく相互運用に固執します。実装を注意深く監視して、独自のメモリ リークや未リリースのリソースを監視する必要があります (ライブラリ自体は、コミュニティによって十分にテストおよび精査されています)。

ライブラリは無料でオープンソースです。Apache 2 ライセンスは、個人目的と商用目的の両方に対応しているようです。ImageMagick ライセンス ページを参照してください。

このライブラリは完全にクロス プラットフォームであり、GDI+ には見られない (または mono では実装されていない) 多くの強力な画像処理および変換ルーチンを実装しており、ASP.net 画像処理の代替として高い評価を得ています。

更新: ここに .NET ラッパーの更新バージョンがあるようです: http://magick.codeplex.com/

于 2012-08-16T16:00:38.783 に答える
9

はい、WPFSystem.Windows.Mediaクラスを使用します。完全に管理されているため、GDI のものと同じ問題に悩まされることはありません。

以下は、グラデーションをレンダリングするために使用する MVC コードからの抜粋です。これにより、WPFVisualから PNGに変換する方法がわかります。

using System;
using System.IO;
using System.Web.Mvc;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace MyMvcWebApp.Controllers
{
    public class ImageGenController : Controller
    {
        // GET: ~/ImageGen/Gradient?color1=red&color2=pink
        [OutputCache(CacheProfile = "Image")]
        public ActionResult Gradient(Color color1, Color color2, int width = 1, int height = 30, double angle = 90)
        {
            var visual = new DrawingVisual();
            using (DrawingContext dc = visual.RenderOpen())
            {
                Brush brush = new LinearGradientBrush(color1, color2, angle);
                dc.DrawRectangle(brush, null, new Rect(0, 0, width, height));
            }

            return new FileStreamResult(renderPng(visual, width, height), "image/png");
        }

        static Stream renderPng(Visual visual, int width, int height)
        {
            var rtb = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Default);
            rtb.Render(visual);

            var frame = BitmapFrame.Create(rtb);
            var encoder = new PngBitmapEncoder();
            encoder.Frames.Add(frame);

            var stream = new MemoryStream();
            encoder.Save(stream);
            stream.Position = 0;

            return stream;
        }
    }
}
于 2011-10-12T11:44:03.583 に答える
9

Microsoft 従業員からの非常に優れた記事をここで見つけることができます: GDI+ の代わりに WPF を使用することを提案する、GDI+ の代わりに WPF/WIC を使用してサーバーから画像をサイズ変更します。それはサムネイルに関するものですが、全体的に同じ問題です。

とにかく、最後に次のように述べています。

これがサポートされているかどうかについて最終的な意見を得るために、WPF チームに連絡しました。残念ながら、そうではなく、それに応じてドキュメントが更新されています。混乱を招きましたことをお詫び申し上げます。将来的には、そのストーリーをより受け入れられるようにする方法を検討しています。

したがって、WPFもWebアプリではサポートされていませんが、それでも私は信じています:-S

于 2012-08-16T17:42:24.970 に答える
1

私が読んだ問題のほとんどは、リソースが適切に破棄されていないことに関係しています。

このコードのバリアントを何度も何度も使用しましたが、Web アプリケーションの問題はありません。

public void GenerateThumbNail(HttpPostedFile fil, string sPhysicalPath, 
                              string sOrgFileName,string sThumbNailFileName,
                              System.Drawing.Imaging.ImageFormat oFormat, int rez)
{

    try
    {

        System.Drawing.Image oImg = System.Drawing.Image.FromStream(fil.InputStream);

        decimal pixtosubstract = 0;
        decimal percentage;

        //default
        Size ThumbNailSizeToUse = new Size();
        if (ThumbNailSize.Width < oImg.Size.Width || ThumbNailSize.Height < oImg.Size.Height)
        {
            if (oImg.Size.Width > oImg.Size.Height)
            {
                percentage = (((decimal)oImg.Size.Width - (decimal)ThumbNailSize.Width) / (decimal)oImg.Size.Width);
                pixtosubstract = percentage * oImg.Size.Height;
                ThumbNailSizeToUse.Width = ThumbNailSize.Width;
                ThumbNailSizeToUse.Height = oImg.Size.Height - (int)pixtosubstract;
            }
            else
            {
                percentage = (((decimal)oImg.Size.Height - (decimal)ThumbNailSize.Height) / (decimal)oImg.Size.Height);
                pixtosubstract = percentage * (decimal)oImg.Size.Width;
                ThumbNailSizeToUse.Height = ThumbNailSize.Height;
                ThumbNailSizeToUse.Width = oImg.Size.Width - (int)pixtosubstract;
            }

        }
        else
        {
            ThumbNailSizeToUse.Width = oImg.Size.Width;
            ThumbNailSizeToUse.Height = oImg.Size.Height;
        }

        Bitmap bmp = new Bitmap(ThumbNailSizeToUse.Width, ThumbNailSizeToUse.Height);
        bmp.SetResolution(rez, rez);
        System.Drawing.Image oThumbNail = bmp;

        bmp = null;

        Graphics oGraphic = Graphics.FromImage(oThumbNail);

        oGraphic.CompositingQuality = CompositingQuality.HighQuality;

        oGraphic.SmoothingMode = SmoothingMode.HighQuality;

        oGraphic.InterpolationMode = InterpolationMode.HighQualityBicubic;

        Rectangle oRectangle = new Rectangle(0, 0, ThumbNailSizeToUse.Width, ThumbNailSizeToUse.Height);

        oGraphic.DrawImage(oImg, oRectangle);

        oThumbNail.Save(sPhysicalPath  + sThumbNailFileName, oFormat);

        oImg.Dispose();

    }
    catch (Exception ex)
    {
        Response.Write(ex.Message);
    }

}
于 2009-10-07T00:35:08.977 に答える
0

ASP.Net Web サーバー環境で Cairo ライブラリ (http://www.cairographics.org) の動作が良好でした。私は実際に WPF から cairo に移動しました。これは、WPF の Web ベースのものに対する貧弱なメモリ使用モデルのためです。

実際、WPF はワーカー プロセスをメモリ不足で実行する傾向があります。を実装する WPF オブジェクトはIDisposableなく、その多くは、ファイナライザーによってのみ解放されるアンマネージ メモリを参照します。WPF を頻繁に使用すると (特にサーバーの CPU 負荷が高い場合)、ファイナライザー キューが飽和状態になるため、最終的にはメモリ不足になります。たとえば、アプリのプロファイリングを行っていたとき、ファイナライズ キューには 50,000 を超えるオブジェクトがあり、その多くはアンマネージ メモリへの参照を保持していました。Cairo の動作は私にとってはるかに優れており、そのメモリ使用パターンは WPF よりもはるかに予測可能です。

cairo の使用に興味がある場合は、GTK+ の Web サイトからライブラリを入手してください。x86 と x64 のバイナリ セットがあります。

唯一の欠点は、cairo が JPG をネイティブに読み書きできないことです。ただし、JPG の読み取り/書き込み用に WPF のものを簡単に適応させ、Cairo を使用してリサンプリング/スケーリング/描画などを行うことができます。

于 2012-08-21T21:13:01.093 に答える
0

You may have a look at http://gd-sharp.sourceforge.net/ which is a wrapper for the GD library. I haven't tested it but it seems promising.

于 2009-12-23T17:16:42.943 に答える
-1

Aspose.Drawingは、完全に管理され、Web アプリケーションで安全に使用できる System.Drawing のドロップイン代替品です。(私は開発者の一人です。)

于 2020-11-07T07:09:44.120 に答える