Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/310.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 图像大小调整性能:System.Drawing vs System.Windows.Media_C#_Wpf_Performance_Image_Resize - Fatal编程技术网

C# 图像大小调整性能:System.Drawing vs System.Windows.Media

C# 图像大小调整性能:System.Drawing vs System.Windows.Media,c#,wpf,performance,image,resize,C#,Wpf,Performance,Image,Resize,我遇到了一个需要调整大量图像大小的情况。这些图像当前以.jpg文件的形式存储在文件系统中,但我希望稍后在项目的内存中只存储byte[]。源图像大小是可变的,但是输出应该是3个不同的预定大小。应保留纵横比,用空白填充原始图像(即,一个非常高的图像将调整大小以适应方形目标图像大小,左右两侧有大面积的白色) 我最初以.NET2.0为目标构建项目,并使用System.Drawing类执行加载/调整大小/保存。有关守则包括: original = Image.FromFile(inputFile); //

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

我最初以.NET2.0为目标构建项目,并使用System.Drawing类执行加载/调整大小/保存。有关守则包括:

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);
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);
我想将此项目移植到.NET 3.5,因此尝试使用System.Windows.Media类执行相同的功能。我让它工作,但性能很差;每个图像的处理时间大约要长50倍。大部分时间都花在加载图像上。有关守则包括:

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);
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,这与性能问题相同。以前有人做过类似的事情,知道有没有更注重性能的方法?还是我只需要使用系统,还是画图?谢谢

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

希望这能帮助其他遇到这个问题的人

我认为MSDN页面上的这一点可能与此相关:

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

使用
System.Drawing
比使用以下方法更接近实际的基本图形功能:

定义了允许在Windows演示基础(WPF)应用程序中集成富媒体,包括绘图、文本和音频/视频内容的对象。


System.Drawing
仍然受支持,因此我坚持使用它。

我在您的代码中发现了一个有趣的情况。使用以下行中的删除

using(DrawingContext drawingContext = drawingVisual.RenderOpen())

我不知道为什么会有这样的代码加速,但你可以试试看。

你似乎做得很艰难。只需设置DecodePixelHeight和DecodePixelWidth,就可以让WPF为您完成这项工作。这将导致在图像加载过程中调整大小:

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无法实现该目标,因此我的解决方案无法回答您的问题


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

这会加快代码的速度,因为当您这样做时,它实际上不会渲染。在调用drawingContext.Close()或drawingContext超出范围(这是用户所做的)之前,绘图上下文实际上不会将您告诉它的内容绘制到参考底图视觉。