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

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

我不知道“ ASP.NET服务”是否在这种情况下是指“ Web应用程序”,但是“服务性能降低”肯定涵盖了随机的“ GDI+”中发生的“通用错误”和“ OUT OUT OUT NOR MEMORY”错误我的应用程序正在投掷 - 间歇性,不可复制的错误读取和编写JPEG图像 - 在许多情况下 - 实际上是通过System.Drawing.Imaging创建的。

因此 - 如果GDI+无法在Web应用程序中可靠地读取和编写JPEG文件,那么我应该使用什么?

我希望用户能够上传图像(需要JPEG,其他格式不错),重新采样 可靠, ,并显示有用的错误消息,如果有任何问题。有任何想法吗? WPF中的system.media名称空间值得考虑吗?

编辑: 是的,我知道GDI+在“大多数情况下”工作。这还不够好,因为当它失败时,它以一种不可能优雅地隔离或恢复的方式这样做。我对适合您的GDI+代码的示例不感兴趣:我正在寻找 用于图像处理的替代库。

有帮助吗?

解决方案

有一篇出色的博客文章,包括有关使用的C#代码 ImageMagick图形库 通过互动 Topten软件博客. 。这篇文章专门涉及在Mono下的Linux上运行ASP.NET;但是,C#代码应该是完美的复制 - 可复制,您唯一需要更改的是,如果您在Windows引用窗口二进制(DLL)下运行,则需要更改的Interop属性。

ImageMagick®是一套软件套件,可创建,编辑,撰写或转换位图图像。它可以以多种格式(超过100)的读写图像,包括DPX,EXR,GIF,JPEG,JPEG-2000,PDF,PhotoCD,PNG,Postscript,Postscript,SVG和TIFF。使用ImageMagick来调整,翻转,镜像,旋转,扭曲,剪切和转换图像,调整图像颜色,应用各种特殊效果或绘制文本,线条,多边形,椭圆形和Bézier曲线。

还有一个 ImageMagick .NET开发项目 在Codeplex上,为您结束了所有内容。但是它并没有显示自2009年以来的积极发展,因此它可能落后于当前的ImageMagick库版本。对于一个小的琐碎的调整例程,我可能会坚持使用Interop。您只需要仔细观察您自己的内存泄漏或未发布资源的实施(图书馆本身经过了经过良好的测试和经过社区的审查)。

该库是免费的和开源的。 Apache 2许可证似乎与个人和商业目的兼容。看 ImageMagick许可页面.

该库是完全跨平台,并实现了许多强大的图像处理和转换例程,这些例程在GDI+(或在单声道下未实现)中未找到,并且在ASP.NET图像处理中享有良好的声誉。

更新:看起来有一个.NET包装器的更新版本: http://magick.codeplex.com/

其他提示

是的,使用WPF System.Windows.Media 课程。完全管理,他们不会遭受与GDI东西相同的问题。

这是我用来渲染梯度的一些MVC代码的摘录 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;
        }
    }
}

您可以在此处找到Microsoft员工的非常好的文章: 使用WPF/WIC而不是GDI+调整服务器的图像大小 这建议使用WPF代替GDI+。这更多是关于缩略图,但总体上是同样的问题。

无论如何,最后它说明了:

我联系了WPF团队,以了解是否得到支持。不幸的是,它不是,并且文档正在相应地更新。我对这可能引起的任何混乱感到歉意。我们正在寻找使这个故事在将来更加可接受的方法。

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

Imagessharp

Imagessharp 是一个开源跨平台2D图形库。它以C#编写在新的.NET标准之上,不依赖任何特定的API。

目前,它仍在Myget上发布(您必须在VS选项或Nuget.config文件中添加软件包源),但是我们已经在使用它并获得一些非常积极的结果。

我读过的有关资源的大多数问题都无法正确处理。

我一次又一次地使用了此代码的变体,没有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);
    }

}

您可能会看看 http://gd-sharp.sourceforge.net/ 这是GD库的包装纸。我没有测试过,但似乎很有希望。

我在ASP.NET WebServer环境中的开罗图书馆(http://www.cairographics.org)中的行为良好。由于WPF对基于Web的东西的不良内存使用模型,我实际上从WPF搬到了开罗。

WPF实际上倾向于将您的工作过程从内存中运行。 WPF对象没有一个 IDisposable, ,其中许多人参考了只有通过最终制度释放的非管理记忆。大量使用WPF(尤其是如果您的服务器显着征用CPU)最终将使您失去内存,因为您的最终器队列已饱和。例如,当我对应用程序进行分析时,最终确定队列上有50,000个对象,其中许多对象都持有对不受管理的内存的参考。开罗对我的行为表现要好得多,它的内存使用模式比WPF更容易预测。

如果您有兴趣使用开罗,请从GTK+的网站上获取LIBS。他们有X86以及X64二进制组。

唯一的缺点是开罗无法本地读/写JPG。但是,您可以轻松地调整WPF的内容以读/编写JPG,并使用开罗进行重采样/缩放/绘图/其他任何内容。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top