0

我正在使用 ImageMagick.NET(从这里:https ://www.nuget.org/packages/Magick.NET-Q8-AnyCPU/ )和 GhostScript(从这里:https ://www.ghostscript.com/ download.html ) 将 pdf 转换为图像缩略图:

        var thumbnailStream = new MemoryStream();
        using (var images = new MagickImageCollection())
        {
            // Read the frames into the collection
            resource.ResourceStream.Seek(0, SeekOrigin.Begin);
            var settings = new MagickReadSettings() { FrameIndex = 0, FrameCount = 1 };
            images.Read(resource.ResourceStream, settings); // WARNING - NOT THREAD SAFE!!

            // Take the first page and make a thumbnail out of it
            var image = images[0];

            // Scale thumbnail to proper width
            var geometry = new MagickGeometry(){ Width = ThumbnailWidth };
            image.Scale(geometry);

            // Write the thumbnail to a MemoryStream
            image.Write(thumbnailStream);
        }

只是按原样运行代码会间歇性地导致:

  HResult=0x80131500
  Message=FailedToExecuteCommand `...gswin64c.exe" -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 "-sDEVICE=pngalpha" -dTextAlphaBits=4 -dGraphicsAlphaBits=4 "-r300x300" -dFirstPage=1 -dLastPage=1 "-sOutputFile=... 
(The system cannot find the file specified.) @ error/delegate.c/ExternalDelegateCommand/475

如果根本没有安装 GhostScript,就会出现同样的错误。似乎 ghostscript 可执行文件 (gswin64c.exe)间歇性不可用。但是,如果我将“读取”调用包装在锁中,如下所示:

            private static readonly object ImageMagickReadLock = new object();

            // LOCK THE THREAD-UNSAFE CODE!!
            lock (ImageMagickReadLock)
            {
                images.Read(resource.ResourceStream, settings);
            }

...一切都按预期工作!然而,这不是一个可扩展的解决方案(负载性能测试表明资源匮乏,这可能导致这个平均时间为 1.5 秒的进程飙升至超过 20 秒!!),所以我正在寻找一种线程安全的方式来通过 ImageMagick 使用 GhostScript( 。网)。

这里有一个 7 年历史的线程,表明可以获取 GhostScript 的源代码并使用特殊标志自行编译。(不知道为什么线程安全不是默认设置,但这是一个单独的讨论)。然而,由于线程的年龄和解决方案从未被接受,我对此表示怀疑 - 事实上,提问者报告了解决方案的问题。此外,我不相信用户正在使用 ImageMagick,所以我什至不确定我是否能让它工作,如果它对我有帮助的话。

所以,我在这里再次问:有没有一种线程安全的方式来通过 ImageMagick (.NET) 使用 GhostScript?

更新:

经过 dlemstra 的一些测试和帮助后,我仍然看到一个问题,尽管它与以前不同(我希望这意味着我更接近了!)。

我的问题之一是我依赖 ghostscript .dll 来处理非锁定情况下的多线程请求,当使用 .dll 的线程被占用时,ImageMagick 会查找 .exe 以填充任何后续并发线程. 这解释了我上面描述的“找不到文件”错误 - 即使存在 .dll,也需要 .dll 和 .exe ghostscipts。所以我添加了.exe。

但是,我仍然得到FailedToExecuteCommand,但是这次它能够找到文件并且详细信息说error/ghostscript-private.h/InvokeGhostscriptDelegate/143

完整的错误信息:

ImageMagick.MagickDelegateErrorException
  HResult=0x80131500
  Message=FailedToExecuteCommand `".../GhostScript/gswin64c.exe" -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 "-sDEVICE=pngalpha" -dTextAlphaBits=4 -dGraphicsAlphaBits=4 "-r300x300" -dFirstPage=1 -dLastPage=1 "-sOutputFile=.../temp/magick-10252ZvAOzMMOsCXz%d" "-f...temp/magick-10252gRfuzynqR0Pe" "-f...temp/magick-10252Bp3xSsSeS1Ol"' (1) @ error/ghostscript-private.h/InvokeGhostscriptDelegate/143
  Source=Magick.NET-Q8-AnyCPU
  StackTrace:
   at ImageMagick.MagickImageCollection.NativeMagickImageCollection.ReadBlob(MagickSettings settings, Byte[] data, Int32 offset, Int32 length)
   at ImageMagick.MagickImageCollection.AddImages(Byte[] data, Int32 offset, Int32 count, MagickReadSettings readSettings, Boolean ping)
   at ImageMagick.MagickImageCollection.AddImages(Stream stream, MagickReadSettings readSettings, Boolean ping)
4

0 回答 0