PdfSharpCore And ImageSharp - Memory Keeps Increasing Or Memory Leak When Adding Hundreds Of Images To Create PDF Book
Good day everyone!
Screenshot of the memory reaching up to 4GB.
Screenshot of the memory usage lowered to 1.4GB.
Cheers!
We are currently upgrading our WPF Cataloging application that has a feature to generate pdf books with multiple pages on the fly and each book may contain thirty or more images and may reach even a hundred from .NET Framework to .NET 7. Upon printing of a book,we discovered that it consume lots of memory even reaching to 5GB per book. Because our logic in generating a catalog involves adding texts and loading several images in memory and then print those details on a single pdf file, it may have caused to memory usage to skyrocket at a tremendous result. The code below shows how we load images using PdfSharpCore and ImageSharp.
private ImageSource.IImageSource GetImageFromList<TPixel>(string key, string which, string name) where TPixel : unmanaged, IPixel<TPixel> { ImageSource.IImageSource rtn; int width; int height; width = 0; height = 0; if (ImageList.ContainsKey(key)) { rtn = ImageList[key]; } else { if (ImageSource.ImageSourceImpl == null) ImageSource.ImageSourceImpl = new ImageSharpImageSource<TPixel>(); if (which == "File") rtn = ImageSource.FromFile(key); else rtn = ImageSource.FromBinary(name, () => GetTemplateBuffer(key)); ImageList.Add(key, rtn); } return rtn; }
After days of investigation, reading the documentation, grabbing the code from github and creating a proof of concept we finally found a solution that is to reduce the size of the images maintaining it's aspect ration. We also modified the code by passing in a configuration object with values set to it's MemoryAllocator and PreferContiguousImageBuffers to ImageSharp Load() method. Once an image has been loaded, we then created a ResizeOptions object setting it's ResizeMode to Max, KnownSampler to Spline and the reduce image size. With these implementations, the memory usage went down significantly.
private ImageSource.IImageSource GetImageFromList<TPixel>(string key, string which, string name) where TPixel : unmanaged, IPixel<TPixel> { ImageSource.IImageSource rtn; int width; int height; width = 0; height = 0; rtn = null; if (ImageList.ContainsKey(key)) { rtn = ImageList[key]; } else { if (ImageSource.ImageSourceImpl == null) ImageSource.ImageSourceImpl = new ImageSharpImageSource<TPixel>(); Configuration customConfig = Configuration.Default.Clone(); customConfig.PreferContiguousImageBuffers = true; customConfig.MemoryAllocator = MemoryAllocator.Create(new MemoryAllocatorOptions() { MaximumPoolSizeMegabytes = 64 }); if (which == "File") { var image = SixLabors.ImageSharp.Image.Load<TPixel>(customConfig, key, out IImageFormat format); width = 1211; height = 1462; ResizeOptions options = new ResizeOptions { Mode = ResizeMode.Max, //Min, Crop, Max, Stretch... Size = new SixLabors.ImageSharp.Size(width, height), Sampler = KnownResamplers.Spline, }; image.Mutate(x => x.AutoOrient().Resize(options)); rtn = ImageSharpImageSource<TPixel>.FromImageSharpImage(image, format, 100); } else { var image = SixLabors.ImageSharp.Image.Load<TPixel>(customConfig, GetTemplateBuffer(key), out IImageFormat format); rtn = ImageSharpImageSource<TPixel>.FromImageSharpImage(image, format); } ImageList.Add(key, rtn); } return rtn; }
Cheers!
Comments
Post a Comment