C# MVC 图片上传调整大小服务端

7
我有一个Web应用程序,用户可以上传图片。目前遇到的问题是,上传的图像以原始格式保存在数据库中。当图像在网页上使用时,这会导致很多性能问题。我使用了dotTrace来分析应用程序,发现从数据库处理图像时存在显着问题。
我的想法是,在上传到服务器时调整图像大小。当用户上传新图像时,我希望应用程序执行以下操作:
1. 用户上传图像 2. 图像被调整为7,500 x 7,500像素,72 dpi的大小 3. 图像被保存到数据库中 4. 原始文件被释放
只存储上述图像,并且Web应用程序包含技术以实时调整大小。
我已经在SO上阅读了几个主题。大多数指向ImageMagick的方向。这个工具在我的公司已经很熟悉,并在PHP项目中使用。但是,是否有好的、稳定的C#封装器发布了?我已经找到了下面的工具,但它们要么是Beta版本,要么是Alpha版本,要么当前没有更新。

ImageMagick.NET

ImageMagick 应用程序

我在 Stack Overflow 上也找到了this主题。在这个主题中提供了以下代码示例:

private static Image CreateReducedImage(Image imgOrig, Size newSize)
{
    var newBm = new Bitmap(newSize.Width, newSize.Height);
    using (var newGrapics = Graphics.FromImage(newBm))
    {
        newGrapics.CompositingQuality = CompositingQuality.HighSpeed;
        newGrapics.SmoothingMode = SmoothingMode.HighSpeed;
        newGrapics.InterpolationMode = InterpolationMode.HighQualityBicubic;
        newGrapics.DrawImage(imgOrig, new Rectangle(0, 0, newSize.Width, newSize.Height));
    }

    return newBm;
}

简而言之,我有以下问题:

  • 使用上述示例是否存在与性能相关的优势?
  • 是否有一个好的、可靠的 C# 封装程序可以用来完成这个任务?

欢迎提供与性能相关的其他好建议!


1
http://imageresizing.net 是一个不错的选择。它经过测试,可靠,并且在低信任环境下工作。它可以轻松处理各种格式,并且只需一行代码即可调用。这是一个非常灵活和功能强大的库。 - Lilith River
3个回答

3
我们采用后一种方法——我无法评论其性能,但它确实使处理依赖关系更简单。然而,需要注意的一点是,如果您的用户能够上传各种格式的图像,则上述代码可能过于简单。底层库(GDI +)在许多颜色格式上存在问题,而且还取决于操作系统版本。下面是我们使用的核心代码:
    // GDI+ has problems with lots of image formats, and it also chokes on unknown ones (like CMYK).
// Therefore, we're going to take a whitelist approach.
// see http://bmpinroad.blogspot.com/2006/04/file-formats-pixel-formats.html
// also see http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/c626a478-e5ef-4a5e-9a73-599b3b7a6ecc
PixelFormat format = originalImage.PixelFormat;

if (format == PixelFormat.Format16bppArgb1555 ||
    format == PixelFormat.Format64bppArgb)
{
    // try to preserve transparency
    format = PixelFormat.Format32bppArgb;
}
else if (format == PixelFormat.Format64bppPArgb)
{
    // try to preserve pre-multiplied transparency
    format = PixelFormat.Format32bppPArgb;
}
else if (format != PixelFormat.Format24bppRgb && format != PixelFormat.Format32bppRgb)
{
    format = PixelFormat.Format24bppRgb;
}


// GIF saving is probably still an issue.  If we ever need to tackle it, see the following:
// http://support.microsoft.com/kb/319061
// http://www.bobpowell.net/giftransparency.htm
// http://support.microsoft.com/kb/318343


using (Bitmap newImage = new Bitmap(newSize.Width, newSize.Height, format))
{
    using (Graphics Canvas = Graphics.FromImage(newImage))
    {
        using (ImageAttributes attr = new ImageAttributes())
        {
            attr.SetWrapMode(WrapMode.TileFlipXY);

            Canvas.SmoothingMode = SmoothingMode.AntiAlias;
            Canvas.InterpolationMode = InterpolationMode.HighQualityBicubic;
            Canvas.PixelOffsetMode = PixelOffsetMode.HighQuality;
            Canvas.DrawImage(originalImage, new Rectangle(new Point(0, 0), newSize), srcRect.X, srcRect.Y, srcRect.Width, srcRect.Height, GraphicsUnit.Pixel, attr);
            newImage.Save(outputImageStream, originalImage.RawFormat);
        }
    }
}

我们可以为客户确定上传格式。这个想法是在上传GIF(因为动画)和PNG(因为透明度)时保留原始文件。所有其他格式(主要是JPG,有时是BMP或TIFF)使用这种方法会导致任何问题吗?还是使用GDI+方法? - Rob
如果我想将像素格式设置为72DPI,我该如何实现?使用哪种格式? - Rob
1
Bitmap对象(在此示例中为newImage)具有可以修改的HorizontalResolution和VerticalResolution属性,以设置每英寸像素。 GIF可能更难处理。 您将不得不处理透明度并重新绘制带有其原始调色板的图像-请参见代码注释中的链接。 对于动画,我认为您可以使用originalImage.SelectActiveFrame()循环遍历图像的帧,但我尚未尝试过,也不确定完成后如何重新组合帧。 - super_seabass
没有使用这个方法的精确副本,但是被接受为解决方案,因为它是最接近的答案。感谢您的好帮助和示例。 - Rob

2
我从未使用过ImageMagick,但我使用过GDI+图像调整函数,包括在一个每天生成和调整超过100,000张图像的网站上使用,没有性能问题。 我认为使用GDI+方法就可以了,不用担心包装外部工具或框架。

目前正在尝试使用GDI+实现一个好的解决方案。将会告诉您结果。 - Rob
只要您在using(){}子句中处理所有内容并避免25个以上的错误,GDI方法就非常好用。参考链接:http://nathanaeljones.com/163/20-image-resizing-pitfalls/。 - Lilith River

1

我在Umbraco网站中使用了ImageGen。(它并不一定与Umbraco绑定,对于任何ASP.NET应用都很好用,只是我使用的一些Umbraco包需要它。) 它的使用方法很简单,你可能可以使用免费版本...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接