【问题标题】:Image cropping and resizing ImageMagick vs GDI+ in C#C# 中的图像裁剪和调整 ImageMagick 与 GDI+ 的对比
【发布时间】:2012-06-10 12:55:36
【问题描述】:

我有一个网络应用程序,用户可以在其中上传图片以创建他们的画廊。多年前,当我编写应用程序时,我选择了ImageMagick,并使用 ImageMagick 完成了所有的裁剪和调整大小。

现在我正在从头开始重写应用程序,我将 ImageMagick 替换为原生 GDI+ 操作,但是我对 GDI+ 了解得越多,我就越害怕自己做出了错误的选择。 p>

我在任何地方都读到 GDI+ 是用于桌面的,不应该在服务器应用程序上使用。我不知道细节,但我猜是因为内存消耗,确实我可以看到 GDI+ 正在使用更多内存 来执行 相同的操作(裁剪和调整大小) 在 相同的图像 上比 ImageMagick(老实说 GDI+ 更快)。

我认为 GDI+、ImageMagick 或任何其他库对于这些基本操作应该或多或少相同,并且我喜欢使用原生 GDI+ 的想法,相信任何 MS 附带 .NET 至少应该没问题。

什么是正确的使用方法/工具?

这是我用来裁剪的代码:

internal Image Crop(Image image, Rectangle r)
{
    Bitmap bmpCrop;
    using (Bitmap bmpImage = new Bitmap(image))
    {
        bmpCrop = bmpImage.Clone(r, bmpImage.PixelFormat);
        bmpImage.Dispose();
    }
    return (Image)(bmpCrop);
}

这是我用来调整大小的代码:

internal Image ResizeTo(Image sourceImage, int width, int height)
{
    System.Drawing.Image newImage = new Bitmap(width, height);
    using (Graphics gr = Graphics.FromImage(newImage))
    {
        gr.SmoothingMode = SmoothingMode.AntiAlias;
        gr.InterpolationMode = InterpolationMode.HighQualityBicubic;
        gr.PixelOffsetMode = PixelOffsetMode.HighQuality;
        gr.DrawImage(sourceImage, new Rectangle(0, 0, width, height));
        gr.Dispose();
    }
    return newImage;
}

【问题讨论】:

  • 我在这里猜测,但 GDI+ 的某些部分可能依赖于包含有效桌面的环境,例如登录用户,而不是新台币服务。
  • 使用 Imagemagick 时,如果您保存为 jpg,您可以使用 jpg 提示加快处理速度或尝试使用 Imagick。 GDI+ 只能在 Windows 服务器上使用吗?
  • 猜对了,但无论如何我都在使用 IIS7 和 .Net。
  • 几年前我曾在服务器应用程序中使用 GDI+ 来完成此操作,并且它仍在运行。它处于轻到中等负载下。我也对在服务器上使用 GDI 持谨慎态度,但我完全没有遇到任何问题。

标签: c# .net imagemagick gdi+


【解决方案1】:

你能链接到人们说 GDI+ 不应该在服务器上使用的地方吗?也许他们知道一些我不知道的事情。

我对 GDI+ 的工作原理有一些了解,但对 ImageMagick 一无所知。我确实发生在描述 ImageMagick 架构的页面上:http://www.imagemagick.org/script/architecture.php

ImageMagick 似乎会在内部将图像转换为具有 4 个通道和特定位深度(通常为每个通道 16 位)的未压缩格式,并使用未压缩数据进行处理,这些数据可能在内存中或磁盘上,具体取决于大小. 'identify -version' 会告诉你你的位深度是多少。我的印象是,实际上 ImageMagick 通常会在内部使用 64 位 RGBA 缓冲区,除非您使用将使用 32 位 RGBA 的 Q8 版本。它也可以使用多个线程,但我怀疑这会很重要,除非你正在处理非常大的图像。 (如果您正在处理非常大的图像,ImageMagick 无疑是赢家。)

GDI+ 位图对象将始终将未压缩的数据存储在内存中,并且通常默认为 32 位 RGBA。那和 32 位 RGB 可能是最有效的格式。 GDI+ 是一个绘图库,它不是为大图像设计的,但至少 Bitmap 对象不会保存像素数据和图像元数据的内存以外的任何资源(与流行的看法相反,它们不包含 HBITMAP对象)。

所以他们看起来和我很相似。对于您的用例,我不能说一个明显优于另一个。如果您使用 imagemagick,您可能应该使用 Q8 构建来提高速度和内存,除非额外的精度对您很重要。

如果您的唯一操作是加载、保存、缩放和裁剪,您应该能够在以后轻松替换实现。

除非您需要使用元文件,否则您可能应该在内部使用位图对象而不是图像。然后,您不必在 Crop 函数中创建中间位图对象。该中间对象可能是您观察到的一些额外内存消耗的原因。如果您从外部来源获取 Image 对象,我建议您尝试将它们转换为 Bitmap 并在这不起作用时创建一个新的 Bitmap。

此外,“using”语句会自动调用 Dispose,因此无需显式调用它。

【讨论】:

  • "System.Drawing 命名空间中的类不支持在 Windows 或 ASP.NET 服务中使用。尝试从这些应用程序类型之一中使用这些类可能会产生意外问题,例如减少服务性能和运行时异常。” msdn.microsoft.com/en-us/library/system.drawing.aspx
【解决方案2】:

我自己写了一些东西:

public void ResizeImageAndRatio(string origFileLocation, string newFileLocation, string origFileName, string newFileName, int newWidth, int newHeight, bool resizeIfWider)
{
    System.Drawing.Image initImage = System.Drawing.Image.FromFile(origFileLocation + origFileName);
    int templateWidth = newWidth;
    int templateHeight = newHeight;
    double templateRate = double.Parse(templateWidth.ToString()) / templateHeight;
    double initRate = double.Parse(initImage.Width.ToString()) / initImage.Height;
    if (templateRate == initRate)
    {
        System.Drawing.Image templateImage = new System.Drawing.Bitmap(templateWidth, templateHeight);
        System.Drawing.Graphics templateG = System.Drawing.Graphics.FromImage(templateImage);
        templateG.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
        templateG.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
        templateG.Clear(Color.White);
        templateG.DrawImage(initImage, new System.Drawing.Rectangle(0, 0, templateWidth, templateHeight), new System.Drawing.Rectangle(0, 0, initImage.Width, initImage.Height), System.Drawing.GraphicsUnit.Pixel);
        templateImage.Save(newFileLocation + newFileName, System.Drawing.Imaging.ImageFormat.Jpeg);
    }
    else
    {
        System.Drawing.Image pickedImage = null;
        System.Drawing.Graphics pickedG = null;

        Rectangle fromR = new Rectangle(0, 0, 0, 0);
        Rectangle toR = new Rectangle(0, 0, 0, 0);

        if (templateRate > initRate)
        {
            pickedImage = new System.Drawing.Bitmap(initImage.Width, int.Parse(Math.Floor(initImage.Width / templateRate).ToString()));
            pickedG = System.Drawing.Graphics.FromImage(pickedImage);

            fromR.X = 0;
            fromR.Y = int.Parse(Math.Floor((initImage.Height - initImage.Width / templateRate) / 2).ToString());
            fromR.Width = initImage.Width;
            fromR.Height = int.Parse(Math.Floor(initImage.Width / templateRate).ToString());

            toR.X = 0;
            toR.Y = 0;
            toR.Width = initImage.Width;
            toR.Height = int.Parse(Math.Floor(initImage.Width / templateRate).ToString());
        }
        else
        {
            pickedImage = new System.Drawing.Bitmap(int.Parse(Math.Floor(initImage.Height * templateRate).ToString()), initImage.Height);
            pickedG = System.Drawing.Graphics.FromImage(pickedImage);

            fromR.X = int.Parse(Math.Floor((initImage.Width - initImage.Height * templateRate) / 2).ToString());
            fromR.Y = 0;
            fromR.Width = int.Parse(Math.Floor(initImage.Height * templateRate).ToString());
            fromR.Height = initImage.Height;

            toR.X = 0;
            toR.Y = 0;
            toR.Width = int.Parse(Math.Floor(initImage.Height * templateRate).ToString());
            toR.Height = initImage.Height;
        }

        pickedG.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
        pickedG.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;

        pickedG.DrawImage(initImage, toR, fromR, System.Drawing.GraphicsUnit.Pixel);

        System.Drawing.Image templateImage = new System.Drawing.Bitmap(templateWidth, templateHeight);
        System.Drawing.Graphics templateG = System.Drawing.Graphics.FromImage(templateImage);
        templateG.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
        templateG.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
        templateG.Clear(Color.White);
        templateG.DrawImage(pickedImage, new System.Drawing.Rectangle(0, 0, templateWidth, templateHeight), new System.Drawing.Rectangle(0, 0, pickedImage.Width, pickedImage.Height), System.Drawing.GraphicsUnit.Pixel);
        templateImage.Save(newFileLocation + newFileName, System.Drawing.Imaging.ImageFormat.Jpeg);

        templateG.Dispose();
        templateImage.Dispose();

        pickedG.Dispose();
        pickedImage.Dispose();
    }
    initImage.Dispose();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-03-21
    • 1970-01-01
    • 1970-01-01
    • 2012-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多