1
Vote

GhostScript Interpreter is not multi-threaded on same pdf file

description

I've noticed that when GhostscriptRasterizer.GetPage is called for two different pages from the same pdf file at the same time, it typically throws an exception. It seems that there is some sort of problem that you can't create two interpreters that are both opening the same file.

For example, if you call it this way
        public static readonly GhostscriptVersionInfo LastInstalledVersion =
            GhostscriptVersionInfo.GetLastInstalledVersion(GhostscriptLicense.GPL, GhostscriptLicense.GPL);

        public static string PathVar = Path.GetFullPath(@"..\..\..\Pdfs\MyPdf.pdf");
        public static readonly object SyncRoot = new object();

        static void Main()
        {
            IEnumerable<Task<Bitmap>> images = (from i in Enumerable.Range(1, 10) select 
                      GetPageAsync_Safe(i));       // comment this for unsafe version
                      //GetPageAsync_Unsafe(i)); // uncomment this for unsafe version
            Task.WaitAll(images.ToArray());
            Console.WriteLine(@"Press enter to exit.");
            Console.ReadLine();
        }
Then this code will work, but only because of the lock:

        public static async Task<Bitmap> GetPageAsync_Safe(int pageNum)
        {
            return await Task.Run(() =>
            {
                const int defaultDpi = 400;
                Bitmap pdfPage;
                lock (SyncRoot)
                {
                    using (GhostscriptRasterizer rasterizer = new GhostscriptRasterizer())
                    {
                        rasterizer.Open(PathVar, LastInstalledVersion, false);
                        pdfPage = (Bitmap)rasterizer.GetPage(defaultDpi, defaultDpi, pageNum);
                        // also you have to clone pdfPage because the original pdf gets disposed or something
                        pdfPage = (Bitmap) pdfPage.Clone();
                    }
                }
                return pdfPage;
            });
        }
However, this code doesn't:
        public static async Task<Bitmap> GetPageAsync_Unsafe(int pageNum)
        {
            return await Task.Run(() =>
            {
                const int defaultDpi = 400;
                Bitmap pdfPage;
                using (GhostscriptRasterizer rasterizer = new GhostscriptRasterizer())
                {
                    rasterizer.Open(PathVar, LastInstalledVersion, false);
                    pdfPage = (Bitmap)rasterizer.GetPage(defaultDpi, defaultDpi, pageNum);
                    // also you have to clone pdfPage because the original pdf gets disposed or something
                    pdfPage = (Bitmap) pdfPage.Clone();
                }
                return pdfPage;
            });
        }
After wrapping the using block in the unsafe method with catch(Exception e){throw e} and then capturing the stack trace, this is what I got:
Ghostscript.NET.GhostscriptAPICallException was caught
  HResult=-2146233088
  Message=An error occured when call to 'gsapi_new_instance' is made: -100
  Source=Ghostscript.NET
  Code=-1000
  CodeName=""
  StackTrace:
       at Ghostscript.NET.Interpreter.GhostscriptInterpreter.Initialize()
       at Ghostscript.NET.Interpreter.GhostscriptInterpreter..ctor(GhostscriptVersionInfo version, Boolean fromMemory)
       at Ghostscript.NET.Viewer.GhostscriptViewer.Open(String path, GhostscriptVersionInfo versionInfo, Boolean dllFromMemory)
       at Ghostscript.NET.Rasterizer.GhostscriptRasterizer.Open(String path, GhostscriptVersionInfo versionInfo, Boolean dllFromMemory)
       at TestApp.Program.<>c__DisplayClassd.<GetPageAsync>b__c() in XXXXXX
  InnerException: 
Lastly, my version information so you can reproduce:
GhostScript version info
Licence: GPL, Version: 9.15, 
Dll: C:\Program Files\gs\gs9.15\bin\gsdll64.dll, 
Lib: C:\Program Files\gs\gs9.15\bin;C:\Program Files\gs\gs9.15\lib;C:\Program Files\gs\gs9.15\fonts

GhostScript.NET Version 1.1.9 

C#: .NET Framework 4.5, 64 bit project (not 32 bit)

comments

sjdixon wrote Nov 14, 2014 at 11:38 PM

I fixed my own issue so I would like to request that this ticket be canceled.

Instead of rasterizer.Open(PathVar, LastInstalledVersion, false); all you have to do is call rasterizer.Open(PathVar, LastInstalledVersion, true);

My bad.