Donate

PdfSharpCore And ImageSharp - Memory Keeps Increasing Or Memory Leak When Adding Hundreds Of Images To Create PDF Book

Good day everyone!

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;
  }
Screenshot of the memory reaching up to 4GB.
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;
  }
Screenshot of the memory usage lowered to 1.4GB.


Cheers!

Comments

Donate

Popular Posts From This Blog

WPF CRUD Application Using DataGrid, MVVM Pattern, Entity Framework, And C#.NET

How To Insert Or Add Emojis In Microsoft Teams Status Message

Bootstrap Modal In ASP.NET MVC With CRUD Operations