2012-06-10 71 views
3

我有一个Web应用程序,用户可以上传图片来创建他们的画廊。几年前,当我编写应用程序时,我选择ImageMagick,并且我做了所有裁剪并调整了ImageMagick的大小。图像裁剪和调整大小ImageMagick vs GDI +在C#

现在,我重写从头开始应用,我换成ImageMagick的原生GDI+操作,但我越了解周围GDI +我害怕我做出了错误的选择更多。

无处不在我读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; 
} 
+0

我在这里猜测,但GDI +的某些部分可能取决于包含有效桌面的环境,如使用登录用户而不是NT服务。 –

+0

如果您使用Imagemagick保存为jpg格式,则可以使用jpg提示来加速该过程或尝试使用Imagick。 GDI +只能在Windows服务器上使用吗? – Bonzo

+0

猜测,但我使用IIS7和.Net无论如何。 –

回答

2

你能链接到某个地方人们说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构建来提高速度和内存,除非额外的精度对你很重要。

看起来好像您的唯一操作是加载,保存,缩放和裁剪,您应该可以在以后轻松地替换实现。

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

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

+0

“System.Drawing命名空间中的类不支持在Windows或ASP.NET服务中使用。尝试从这些应用程序类型中使用这些类可能会产生意外问题,如服务性能下降和运行时异常“。 http://msdn.microsoft.com/en-us/library/system.drawing.aspx –

0

我写自己的东西:

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(); 
}