C# 使用RenderTargetBitmap+drawingVisual生成png长图存在内存泄漏问题
原先使用了使用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; } else { 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, 96d, 96d, 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; } else { 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(); }