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

Cha*_*vig 10 c# wpf performance resize image

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

我最初构建了面向.NET 2.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);
Run Code Online (Sandbox Code Playgroud)

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

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);
Run Code Online (Sandbox Code Playgroud)

我在这里做错了,花了这么多时间吗?我试过在BitmapImage上使用构造函数来获取URI,那里存在相同的性能问题.任何人之前做过这样的事情,知道是否有更具表现力的方式来做到这一点?或者我只是需要使用System.Drawing?谢谢!

Cha*_*vig 10

在输入所有内容之后,我发现我可以从MS加载System.Windows.Media类的符号,并逐步完成它的速度.马上找到了原因和解决方案.输入图像使用颜色配置文件保存,并且尝试加载每个图像的颜色配置文件(来自文件系统).通过在上面的代码中从BitmapCreateOptions.None切换到BitmapCreateOptions.IgnoreColorProfile,它不再这样做,并且执行速度与System.Drawing一样快.

希望这可以帮助其他遇到此问题的人!


Ray*_*rns 5

你似乎是在艰难地做这件事.您可以通过设置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);
Run Code Online (Sandbox Code Playgroud)

我还包括了我在代码中找到的IgnoreColorProfile解决方案.

更新我重新阅读您的问题,并意识到您使用DrawingVisual的原因是您需要在图像周围使用空白才能使其成为正方形.DecodePixelHeight和DecodePixelWidth无法实现这一目标,因此我的解决方案无法回答您的问题.

我会在这里留下我的答案,以防有人只需要一个没有空格的大小调整就会遇到这个问题.