我正在使用 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)