代码之家  ›  专栏  ›  技术社区  ›  Dylan Beattie

与ASP.NET一起使用的System.Drawing的替代项?

  •  32
  • Dylan Beattie  · 技术社区  · 17 年前

    在跟踪了几天奇怪的gdi+错误之后,我偶然发现了这个小宝石 MSDN :

    不支持在Windows或ASP.NET服务中使用System.Drawing命名空间中的类。尝试在其中一个应用程序类型中使用这些类可能会产生意外的问题,例如服务性能降低和运行时异常。

    我不知道“ASP.NET服务”在这种情况下是否意味着“Web应用程序”,但“服务性能降低”显然涵盖了“在GDI+中发生的一般性错误”和“内存不足”错误的随机分类,这些错误是我的应用程序正在抛出的-间歇性、不可复制的错误读取和写入jpeg图像,在许多情况下-W首先是由System.Drawing.Imaging实际创建的。

    所以-如果gdi+不能在Web应用程序中可靠地读写jpeg文件,我应该用什么来代替呢?

    我希望用户能够上传图片(需要jpeg,其他格式很好),重新取样。 可靠地 ,并在出现错误时显示有用的错误消息。有什么想法吗?WPF中的System.Media命名空间值得考虑吗?

    编辑: 是的,我知道GDI+大部分时间都在工作。这还不够好,因为当它失败时,它会以一种不可能从优雅中孤立或恢复的方式这样做。我对适用于您的gdi+代码示例不感兴趣:我正在寻找 用于图像处理的可选库。

    7 回复  |  直到 7 年前
        1
  •  9
  •   JakeD    9 年前

    有一篇优秀的博客文章,包括关于使用 ImageMagick graphics library 通过在上的互操作 TopTen Software Blog . 本文专门讨论在Mono下的Linux上运行ASP.NET;但是,C代码应该是完全可复制粘贴的,如果您在Windows下运行时引用了一个窗口二进制文件(DLL),那么您只需要更改互操作属性。

    ImageMagick_是用于创建、编辑、合成或转换的软件套件 位图图像。它可以以各种格式读取和写入图像 (超过100)包括dpx、exr、gif、jpeg、jpeg-2000、pdf、photocd, PNG、PostScript、SVG和TIFF。使用ImageMagick调整大小、翻转, 镜像、旋转、扭曲、剪切和变换图像,调整图像 颜色,应用各种特殊效果,或绘制文本、线条、多边形, 椭圆和b_)zier曲线。

    还有一个 ImageMagick .Net development project 在为你包装一切的密码丛上。但自2009年以来,它没有表现出积极的发展,因此它可能落后于当前的ImageMagick库版本。对于一个小小的调整程序,我可能会坚持使用interop。您只需要仔细观察您自己的内存泄漏或未释放的资源的实现(库本身经过了社区的良好测试和审查)。

    这个库是免费的、开源的。Apache2许可证似乎与个人和商业目的都兼容。见 ImageMagick License Page .

    该库是完全跨平台的,实现了许多功能强大的图像处理和转换例程,这些例程在GDI+中找不到(或未在Mono中实现),并且作为ASP.NET图像处理的替代方案享有良好声誉。

    更新:此处似乎有.NET包装的更新版本: http://magick.codeplex.com/

        2
  •  10
  •   Duncan Smart    15 年前

    是的,使用WPF System.Windows.Media 类。完全管理他们不会遇到与GDI一样的问题。

    下面是我用来呈现渐变的一些MVC代码的摘录,让您了解如何从WPF中获取渐变。 Visual 对于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;
            }
        }
    }
    
        3
  •  8
  •   Simon Mourier    11 年前

    您可以在这里找到一篇来自微软员工的非常好的文章: Resizing images from the server using WPF/WIC instead of GDI+ 建议使用wpf而不是gdi+。这更多的是拇指固定,但总的来说是相同的问题。

    总之,在结尾处,它指出:

    我联系了WPF小组,最后决定是否 支持。不幸的是,它不是,而且文档正在 相应更新。我对这件事可能造成的混乱表示歉意 引起。我们正在寻找方法让这个故事在 未来。

    因此,WPF在Web应用程序中也不受支持,我仍然相信这一点:

        4
  •  4
  •   Mathieu Renda    9 年前

    图像锐利

    ImageSharp 是一个开源的跨平台二维图形库。它是在新的.NET标准之上用C语言编写的,不依赖于任何特定于操作系统的API。

    它目前仍在myget的预发布版本中(您必须在vs选项或nuget.config文件中添加包源),但我们已经在使用它,并取得了一些非常积极的结果。

        5
  •  1
  •   Stefan Steiger Marco van de Voort    14 年前

    我读到的大多数问题都与资源处理不当有关。

    我一次又一次地使用此代码的变体,但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);
        }
    
    }
    
        6
  •  0
  •   alfred barthand    16 年前

    你可以看看 http://gd-sharp.sourceforge.net/ 它是gd库的包装器。我还没有测试过,但看起来很有希望。

        7
  •  0
  •   FMM    14 年前

    我在cairo库(http://www.cairographics.org)的ASP.NET Web服务器环境中表现良好。实际上,我是从WPF搬到开罗的,因为WPF对于基于Web的东西的内存使用模型很差。

    实际上,WPF倾向于将工作进程的内存耗尽。没有任何wpf对象实现 IDisposable ,其中许多引用了仅通过终结器释放的非托管内存。大量使用WPF(特别是在服务器需要大量CPU的情况下)最终会耗尽内存,因为终结器队列会饱和。例如,当我分析我的应用程序时,终结队列上有50000多个对象,其中许多对象包含对非托管内存的引用。cairo的行为对我来说要好得多,而且它的内存使用模式比wpf的更容易预测。

    如果您对使用cairo感兴趣,请从GTK+的网站上获取libs。它们有一个x86和一组x64二进制文件。

    唯一的缺点是cairo不能在本地读/写JPG;但是,您可以很容易地将wpf的内容改编为读/写JPG,并使用cairo执行重新采样/缩放/绘图/其他任何操作。

    推荐文章