【发布时间】:2021-05-01 06:51:29
【问题描述】:
我正在尝试将多张图片合并为一张。这是我现在的代码:
public static Bitmap Merge(List<Image> imgs)
{
int outputImageWidth = 0;
int outputImageHeight = 0;
foreach (var img in imgs)
{
if(outputImageWidth < img.Width)
{
outputImageWidth = img.Width;
}
outputImageHeight += img.Height;
}
outputImageHeight += 1;
using (Bitmap outputImage = new Bitmap(outputImageWidth, outputImageHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb))
{
foreach (var img in imgs)
{
Graphics graphics = Graphics.FromImage(outputImage);
graphics.DrawImage(img, new Rectangle(new Point(0, outputImage.Height + 1), img.Size), new Rectangle(new Point(), img.Size), GraphicsUnit.Pixel);
graphics.Dispose();
graphics = null;
img.Dispose();
}
foreach (var img in imgs)
{
img.Dispose();
}
GC.Collect();
return (Bitmap)outputImage.Clone();
}
}
在调试时,我发现,每当我调用graphics.DrawImage(...) 时,都会分配大约 100-300mb 的内存。我希望每当我处理对象时它都会被释放,但是每次迭代时,进程都会分配更多内存,直到我得到内存不足异常(大约在 32 位进程的 30 页之后)。
有什么想法吗?
【问题讨论】:
-
您对
Dispose的使用对我来说似乎有点奇怪(循环中的双重处理)。我不认为有问题,但很奇怪。另外,为什么要克隆输出图像然后处理它?为什么不直接返回而不克隆(这样可以避免一些内存压力)。 -
您应该在循环外创建图形对象(并将其放在
using(...)中),然后重用它。 -
请告诉我们有多少图像以及结果的宽度/高度! - 顺便说一句:源图像来自一个列表,因此它们已经被分配并且很可能不是问题。创建一个拥抱位图通常是浪费/泄漏 GDI 资源..
-
@TaW 除非我误读了算法,否则它会垂直堆叠 N 个图像(它们的高度之和),宽度是所有图像宽度的最大值。
-
121000 确实很多,可能太多了。它必须被创建为连续内存。 GDI 资源不是你的问题,因为每个位图只会用完一个,所以你有 list.count +1 加上一些额外的资源。一种解决方法可能是创建 2 或 3 个较小的图像,并找到一种无需 GDI 将它们拼接在一起的方法;也许一个库会有所帮助。在 winforms 和 GDI+ 中搜索位图大小限制!