原先使用了使用RenderTargetBitmap+drawingVisual生成png长图,后来发现存在内存泄漏问题,通过各种方式都没办法释放内存,方式如下:
/// <summary>
/// 生成长图
/// </summary>
/// <param name="imageList"></param>
/// <param name="toPath"></param>
/// <returns></returns>
public async Task<bool> CreateLongGraphAsync(List<SlideImageData> imageList, string toPath)
var bitmapSource = await CreateLongBitmapAsync(imageList);
if (bitmapSource != null)
SaveBitmap(toPath, bitmapSource);
return true;
private async Task<RenderTargetBitmap> CreateLongBitmapAsync(List<SlideImageData> imageList)
if (imageList.Count <= 0) return null;
double sumHeight = 0;
int lineHeight = 5;
if (imageList.Count == 1)
sumHeight = imageList.First().Height;
sumHeight = imageList.Sum(img => img.Height) + lineHeight * (imageList.Count - 1);
double maxWidth = imageList.Max(img => img.Width);
var combineImg = new RenderTargetBitmap((int)maxWidth,
(int)sumHeight,
PixelFormats.Pbgra32);
var drawingVisual = new DrawingVisual();
using (var drawingContext = drawingVisual.RenderOpen())
int positionY = 0;
foreach (var image in imageList)
drawingContext.DrawImage(image.ImageSource, new Rect(0, positionY, image.Width, image.Height));
positionY += image.Height + lineHeight;
combineImg.Render(drawingVisual);
if (combineImg.CanFreeze)
combineImg.Freeze();
return combineImg;
/// <summary>
/// 保存位图
/// </summary>
/// <param name="savePath"></param>
/// <param name="getSource"></param>
private void SaveBitmap(string savePath, RenderTargetBitmap getSource)
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(getSource));
using FileStream fs = new FileStream(savePath, FileMode.Create, FileAccess.Read);
encoder.Save(fs);
getSource.Clear();
getSource = null;
GC.Collect();
跟踪主要是RenderTargetBitmap的内存没办法释放。所以替换了另一种方式Bitmap+Graphics生成png长图
/// <summary>
/// 生成长图
/// </summary>
/// <param name="imageList"></param>
/// <param name="toPath"></param>
/// <returns></returns>
public async Task<bool> CreateLongGraphAsync(List<SlideImageData> imageList, string toPath)
Bitmap mergedBitmap = MergeImages(imageList.Select(t => t.ImageSource).ToList());
mergedBitmap.Save(toPath, ImageFormat.Png);
//var bitmapSource = await CreateLongBitmapAsync(imageList);
//if (bitmapSource != null)
// SaveBitmap(toPath, bitmapSource);
return true;
// 定义合并图片的方法
private Bitmap MergeImages(List<ImageSource> images)
if (images.Count <= 0) return null;
double sumHeight = 0;
int lineHeight = 5;
if (images.Count == 1)
sumHeight = images.First().Height;
sumHeight = images.Sum(img => img.Height) + lineHeight * (images.Count - 1);
double maxWidth = images.Max(img => img.Width);
// 创建一个位图对象
Bitmap bitmap = new Bitmap((int)maxWidth, (int)sumHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
// 使用Graphics类绘制图片
using (Graphics g = Graphics.FromImage(bitmap))
int y = 0;
foreach (var image in images)
g.DrawImage(ImageSourceToBitmap(image), new System.Drawing.Rectangle(0, y, (int)image.Width, (int)image.Height));
y += (int)image.Height;
return bitmap;
// 定义将ImageSource转换为Bitmap的方法
private Bitmap ImageSourceToBitmap(ImageSource imageSource)
BitmapImage bitmapImage = (BitmapImage)imageSource;
Bitmap bitmap = new Bitmap(bitmapImage.PixelWidth, bitmapImage.PixelHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
BitmapData data = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
bitmapImage.CopyPixels(Int32Rect.Empty, data.Scan0, data.Height * data.Stride, data.Stride);
bitmap.UnlockBits(data);
return bitmap;
private BitmapImage ConvertRenderTargetBitmapToBitmapImage(RenderTargetBitmap wbm)
BitmapImage bmp = new BitmapImage();
using (MemoryStream stream = new MemoryStream())
BmpBitmapEncoder encoder = new BmpBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(wbm));
encoder.Save(stream);
bmp.BeginInit();
bmp.CacheOption = BitmapCacheOption.OnLoad;
bmp.CreateOptions = BitmapCreateOptions.PreservePixelFormat;
bmp.StreamSource = new MemoryStream(stream.ToArray()); //stream;
bmp.EndInit();
bmp.Freeze();
return bmp;
/// <summary>
/// 保存位图
/// </summary>
/// <param name="savePath"></param>
/// <param name="getSource"></param>
private void SaveBitmap(string savePath, RenderTargetBitmap getSource)
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(getSource));
using FileStream fs = new FileStream(savePath, FileMode.Create, FileAccess.Read);
encoder.Save(fs);
getSource.Clear();
getSource = null;
GC.Collect();