我正在使用作为后台处理器运行的 32 位控制台应用程序。我正在处理的部分使用 GhostScript 在 PDF 上执行 OCR。PDF 的每一页都呈现为临时文件夹中的 PNG 图像,然后 OCR 阅读器读取该图像。OCR 文本保存到数据库中,然后删除临时文件夹中的文件。
问题在于 GhostScriptRasterizer 对象占用了处理器可用的所有内存。当我调用 GhostScriptRasterizer.GetPage(dpi, dpi, pageNumber) 方法时,我得到一个 OutOfMemory 异常或 System.ArgumentException 消息“参数无效”。我对第二个异常的研究告诉我,这确实是第一个异常的症状。方法调用会吃掉所有可用的内存。
GetPage 方法正在创建一个需要连续未分段内存的 System.Drawing.Bitmap 图像。问题代码从这里开始。
try
{
img = rasterizer.GetPage(dpi, dpi, pageNumber);
}
catch (OutOfMemoryException ex)
{
img = GetImage(rasterizer, dpi, pageNumber, ms);
}
catch (System.ArgumentException ex)
{
img = GetImage(rasterizer, dpi, pageNumber, ms);
}
我写的GetImage方法是这样的。
public Image GetImage(GhostscriptRasterizer rasterizer, int dpi, int pageNumber, MemoryStream ms)
{
rasterizer.Close();
rasterizer.Dispose();
rasterizer = new GhostscriptRasterizer();
rasterizer.Open(ms);
dpi = dpi - 50;
Image image = null;
if (dpi > 0)
{
try
{
image = rasterizer.GetPage(dpi, dpi, pageNumber);
}
catch (OutOfMemoryException ex)
{
image = GetImage(rasterizer, dpi, pageNumber, ms);
}
catch (System.ArgumentException ex)
{
image = GetImage(rasterizer, dpi, pageNumber, ms);
}
}
return image;
}
我一开始的 dpi 是 300,它适用于我们通过该系统的第一次测试运行的 95% 的文档。但是,对于某些页面,300 dpi 显然太高了,因为我得到了 Outofmemory 异常。看起来有些页面大约是 35 X 59 英寸。我无法控制这一点。对我来说,解决方案是继续尝试越来越低的 dpi,直到我有一些不会吃掉所有内存的东西。但是,所有这些内存都保留在光栅化器对象中,所以我需要以某种方式处理它。调用 rasterizer.Close() 给我以下错误。
托管调试助手“FatalExecutionEngineError”在“F:\Development\bin\Debug\Processor.Run.vshost.exe”中检测到问题。
附加信息:运行时遇到致命错误。错误地址位于线程 0x3e90 上的 0x7331e8c6。错误代码为 0xc0000005。此错误可能是 CLR 中的错误或用户代码的不安全或不可验证部分中的错误。此错误的常见来源包括 COM 互操作或 PInvoke 的用户封送错误,这可能会损坏堆栈。
删除 Close() 调用并调用 rasterizer.Dispose() 给了我:
Ghostscript.NET.dll 中出现“System.AccessViolationException”类型的未处理异常
附加信息:试图读取或写入受保护的内存。这通常表明其他内存已损坏。
我什至只是尝试在遇到异常并返回文件列表时中断,但这仍然要求我不使用光栅化器的 using 声明,因为我在 using 结束时遇到了相同的异常,因为它当然正在尝试处置对象。看起来垃圾收集器后来收集了该内存,但这并没有以任何方式解决我的问题。我仍然无法在同一个作业中对页面进行光栅化。
我能想到的唯一解决方案是以某种方式提前调整 pdf 的大小,但我希望有人知道一种处理该内存并以新的较低 dpi 重新光栅化的方法。