Ghostscript problem converting pdf to images C#

76 views Asked by At

I have a project that performs some actions by calling code from my nuget packages. The code from the packages is executed using .NET Executor that runs in a 32bit process (and only that).

So I have a problem with the action that converts a pdf to images. I want the action to run at 300 dpi. And most pdfs are converted at that resolution with no problem. But there are some pdfs with huge images inside. That's when my code falls down. Here is a slightly simplified version of my code:

using System;
using System.Drawing.Imaging;
using System.Drawing;
using System.IO;
using Ghostscript.NET;
using Ghostscript.NET.Rasterizer;

namespace PDF
{
    public enum ImageConvertingFormat
    {
        Jpeg, Png
    }
    
    public static class PdfConverter
    {
        private const string DllRelPath32 = @"Ronz.GSDLL.17.9.26.2\content\gsdll32.dll";
        private const string DllRelPath64 = @"Ronz.GSDLL.17.9.26.2\content\gsdll64.dll";
        
        private const int RequiredDpi = 300;
        private const int OptimumDpi = 150;

        public static void ConvertToImages(string pdfPath, string imagesFolderPath, ImageConvertingFormat format)
        {
            string pdfName = Path.GetFileNameWithoutExtension(pdfPath);
            string dllPath = GetDllPath();
            ImageFormat imageFormat = GetFormat(format);    
            string extension = GetExtension(format);

            var version = new GhostscriptVersionInfo(new Version(0, 0, 0),
                dllPath, string.Empty, GhostscriptLicense.GPL);
            using var streamOpen = new FileStream(pdfPath, FileMode.Open, FileAccess.Read);
            using var rasterizer = new GhostscriptRasterizer();
            rasterizer.Open(streamOpen, version, dllFromMemory: false);
            
            for (var i = 1; i <= rasterizer.PageCount; i++)
            {
                string pageImgPath = Path.Combine(imagesFolderPath, $"{pdfName}-{i}{extension}");
                Image rasterizedPage = GetRasterizedPage(rasterizer, pageNumber: i);
                
                using var fileStream = new FileStream(pageImgPath, FileMode.Create);
                rasterizedPage.Save(fileStream, imageFormat);
                fileStream.Close();
            }
        }
        
        private static string GetDllPath()
        {
            const string nugetFolder = @"C:\Users\User\Packages\Nuget";
            
            return Path.Combine(nugetFolder, Environment.Is64BitProcess
                ? DllRelPath64
                : DllRelPath32);
        }

        private static ImageFormat GetFormat(ImageConvertingFormat format)
            => format switch
            {
                ImageConvertingFormat.Jpeg => ImageFormat.Jpeg,
                ImageConvertingFormat.Png => ImageFormat.Png,
            };
        
        private static string GetExtension(ImageConvertingFormat format)
            => format switch
            {
                ImageConvertingFormat.Jpeg => ".jpg",
                ImageConvertingFormat.Png => ".png",
            };

        private static Image GetRasterizedPage(GhostscriptRasterizer rasterizer, int pageNumber)
        {
            try
            {
                return rasterizer.GetPage(RequiredDpi, pageNumber);
            }
            catch
            {
                return rasterizer.GetPage(OptimumDpi, pageNumber);
            }
        }
    }
}

The code crashes on the line rasterizer.GetPage(RequiredDpi, pageNumber); (System.OutOfMemoryException: Insufficient memory to continue the execution of the program.). I tried to wrap this line in a try-catch in the GetRasterizedPage method. But the rasterizer starts always throwing exceptions on all rasterizer's methods after first crash. Even if I try to dispose it (System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.).

If I try to perform this action with OptimumDpi, it succeeds.

It's also worth noting that this only happens when running in a 32bit process (unfortunately, in my project I can only run this action that way). If I run the ConvertToImages method in tests, everything runs successfully.

Is there any way to solve my problem? Many thanks in advance!

0

There are 0 answers