首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >图像大小调整性能: System.Drawing与System.Windows.Media

图像大小调整性能: System.Drawing与System.Windows.Media
EN

Stack Overflow用户
提问于 2009-11-17 07:06:10
回答 4查看 13.7K关注 0票数 10

我遇到了需要调整大量图像大小的情况。目前,这些图像以.jpg文件的形式存储在文件系统中,但我希望稍后在项目的内存中只有byte[]。源图像的大小是可变的,但输出应该是3个不同的预定大小。应该保留纵横比,用空白填充原始图像(即,真正高的图像将调整大小以适应正方形目标图像大小,左侧和右侧有大片白色区域)。

我最初构建该项目的目标是.NET 2.0,并使用System.Drawing类执行加载/调整大小/保存。相关代码包括:

代码语言:javascript
复制
original = Image.FromFile(inputFile); //NOTE: Reused for each of the 3 target sizes
Bitmap resized = new Bitmap(size, size);
//Draw the image to a new image of the intended size
Graphics g = Graphics.FromImage(resized);
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.Clear(Color.White);
g.DrawImage(original, center - width / 2f, center - height / 2f, width, height);
g.Dispose();
//Save the new image to the output path
resized.Save(outputFile, ImageFormat.Jpeg);

我想将此项目移植到.NET 3.5,因此尝试使用System.Windows.Media类来执行相同的功能。我让它工作了,但是性能很糟糕;每个图像的处理时间大约增加了50倍。绝大多数时间都花在加载图像上。相关代码包括:

代码语言:javascript
复制
BitmapImage original = new BitmapImage(); //Again, reused for each of the 3 target sizes
original.BeginInit();
original.StreamSource = new MemoryStream(imageData); //imageData is a byte[] of the data loaded from a FileStream
original.CreateOptions = BitmapCreateOptions.None;
original.CacheOption = BitmapCacheOption.Default;
original.EndInit(); //Here's where the vast majority of the time is spent
original.Freeze();

// Target Rect for the resize operation
Rect rect = new Rect(center - width / 2d, center - height / 2d, width, height);

// Create a DrawingVisual/Context to render with
DrawingVisual drawingVisual = new DrawingVisual();
using (DrawingContext drawingContext = drawingVisual.RenderOpen())
{
    drawingContext.DrawImage(original, rect);
}

// Use RenderTargetBitmap to resize the original image
RenderTargetBitmap resizedImage = new RenderTargetBitmap(
    size, size,                         // Resized dimensions
    96, 96,                             // Default DPI values
    PixelFormats.Default);              // Default pixel format
resizedImage.Render(drawingVisual);

// Encode the image using the original format and save the modified image
SaveImageData(resizedImage, outputFile);

我是不是做错了什么,花了这么多时间?我已经尝试在BitmapImage上使用带有URI的构造函数,同样的性能问题也存在。有没有人以前做过类似的事情,知道有没有更注重性能的方法?或者我仍然需要使用System.Drawing?谢谢!

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2009-11-17 07:17:02

在输入所有这些内容之后,我突然想到我可以从MS加载System.Windows.Media类的符号,并逐步执行速度较慢的部分。立即找到了原因,并找到了解决办法。输入图像与颜色配置文件一起保存,并尝试加载每个图像的颜色配置文件(从文件系统)。通过在上面的代码中从BitmapCreateOptions.None切换到BitmapCreateOptions.IgnoreColorProfile,它不再这样做,并且执行起来和System.Drawing一样快。

希望这篇文章能帮助任何遇到这个问题的人!

票数 10
EN

Stack Overflow用户

发布于 2009-11-17 13:34:35

你似乎是在以一种艰难的方式来做这件事。只需设置DecodePixelHeight和DecodePixelWidth,就可以让WPF为您完成这项工作。这将导致在映像加载期间进行大小调整:

代码语言:javascript
复制
BitmapImage resizedImage = new BitmapImage
{
  StreamSource = new MemoryStream(imageData),
  CreateOptions = BitmapCreateOptions.IgnoreColorProfile,
  DecodePixelHeight = height,
  DecodePixelWidth = width,
}
resizedImage.BeginInit();  // Needed only so we can call EndInit()
resizedImage.EndInit();    // This does the actual loading and resizing

imageSaveImageData(resizedImage, outputFile);

我还包含了您在我的代码中找到的IgnoreColorProfile解决方案。

更新我重读了你的问题,我意识到你使用DrawingVisual的原因是你需要在你的图像周围留出空格来使它成为正方形。DecodePixelHeight和DecodePixelWidth无法实现该目标,因此我的解决方案没有回答您的问题。

我会在这里留下我的答案,以防那些只需要调整大小而不需要空格的人遇到这个问题。

票数 5
EN

Stack Overflow用户

发布于 2009-11-17 07:17:11

我认为MSDN上的System.Drawing页面上的这一点可能是相关的:

System.Drawing命名空间提供对GDI+基本图形功能的访问。System.Drawing.Drawing2D、System.Drawing.Imaging和System.Drawing.Text名称空间中提供了更高级的功能。Graphics类提供用于绘制到显示设备的方法。像Rectangle和Point这样的类封装了GDI+原语。Pen类用于绘制直线和曲线,而从抽象类Brush派生的类用于填充形状的内部。

与使用System.Windows.Media相比,使用System.Drawing更接近实际的基本图形功能:

定义的对象支持在Windows Presentation Foundation (WPF)应用程序中集成富媒体,包括绘图、文本和音频/视频内容。

System.Drawing仍然被支持,所以我会坚持使用它。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1745446

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档