GhostscriptRasterizer对象返回0作为PageCount值

7
            txtStatus.Text = "";
            if (!File.Exists(txtOpenLocation.Text))
            {
                txtStatus.Text = "File Not Found";
                return;
            }

            txtStatus.Text = "File Found";



            const string DLL_32BITS = "gsdll32.dll";
            const string DLL_64BITS = "gsdll64.dll";

            //select DLL based on arch
            string NomeGhostscriptDLL;
            if (Environment.Is64BitProcess)
            {
                NomeGhostscriptDLL = DLL_64BITS;
            }
            else
            {
                NomeGhostscriptDLL = DLL_32BITS;
            }




            GhostscriptVersionInfo gvi = new GhostscriptVersionInfo(NomeGhostscriptDLL);
            var rasterizer = new GhostscriptRasterizer();
            try
            {              
                rasterizer.Open(txtOpenLocation.Text, gvi, true);

                Console.WriteLine(rasterizer.PageCount); //This line always prints 0
            } catch(Exception er)
            {
                txtStatus.AppendText("\r\nUnable to Load the File: "+ er.ToString());
                return;
            }

我已经在谷歌上搜索了它,但没有解决方案,也没有关于rasterizer.Open()函数的有用文档。无论我加载哪个pdf文件,Console.WriteLine(rasterizer.PageCount)始终打印0。txtStatus是UI中的多行文本框,txtOpenLocation是UI中的另一个文本框,由OpenFileDialog设置其值且用户无法编辑。我正在使用Visual Studio 2019社区版。我感觉值得提及的另一点是,在我的计算机上,对于每个pdf文件,当我尝试使用Adobe Acrobat DC或Foxit Reader打开任何pdf文件时,阅读器首先崩溃,'not responsive'约10至15秒,然后才打开pdf文件。

你没有说明你使用的Ghostscript版本,也没有提供反向通道输出(stderr和stdout),我猜测Ghostscript正在抛出错误,唯一的方法是查看它试图告诉你什么。 - KenS
Ghostscript版本为9.27。gsdll32.dllgsdll64.dll是从Ghostscript应用程序的安装目录中收集的。Ghostscript没有抛出任何错误。 - Muhammad Rasel Parvej
1
我从这里下载了ghostscript.net.1.2.1.nupkg。然后将其解压以获取Ghostscript.NET.dll。 - Muhammad Rasel Parvej
我完全是C#和.NET的新手。我可能错了,但我正在表达我的想法。我相信这是Ghostscript中的一个错误。如果您愿意,我可以发送给您整个项目。这是一个小项目,您不需要花费太多时间来浏览它。(我看到您在Artifex工作。) - Muhammad Rasel Parvej
1
在使用9.27或更新版本时,GhostScript.net库存在已知问题:https://github.com/jhabjan/Ghostscript.NET/issues/62 - Aharon Ohayon
显示剩余2条评论
6个回答

20

2
这对我很有帮助。你刚刚帮我完成了我的第一个C#/.NET应用程序。这是我遭受了两天的唯一问题。非常感谢你,兄弟。正如@KenS在他的答案中所述,这可能不是Ghostscript的错误。这很可能是Ghostscript.NET的问题,或者是由Ghostscript.NET定义的更改行为。 - Muhammad Rasel Parvej
再次感谢大家的帮助。花了这么多时间才实现了一件如此简单的事情。 - Euan Gordon
@Oswaldo Cotes Solano,在我的情况下,回滚到旧版本的Ghostscript并没有帮助。我尝试了26和25版本。此外,使用27版本时,PageCount始终为0,如果版本低于27,则会出现错误“找不到Ghostscript本地库”。 - Vasiliy

4

我怀疑这根本不是一个bug,(我肯定不认为这是一个Ghostscript的bug),而可能是一种行为改变。由于被报告的安全漏洞,Ghostscript开发人员一直在删除访问许多非标准PostScript扩展(仅限于Ghostscript)的能力。最近,已经安全地访问了处理PDF文件的字典。

我的怀疑是Ghostscript.NET(其没有由Ghostscript开发人员维护)正在使用一个或多个非标准扩展来完成检索页面计数的工作。当然,如果不知道当前具体使用了什么,就无法确定。

如果Ghostscript.NET的开发人员想联系我们并确认这是问题,那么我们可以讨论当前支持的方法来检索PDF文件中的页面计数。

将使用Ghostscript.NET的项目发送给我是没有帮助的,因为我对此一无所知。我也不是C#或.NET开发人员,因此代码对我来说可能毫无意义。

Ghostscript返回大量有关后端通道,stdout和/或stderr的信息。这些可以重定向到应用程序定义的数据接收器。我想Ghostscript.NET会为您提供一些检索这些信息的方法,如果您计划进行任何涉及Ghostscript的实际开发,我强烈建议您找出如何获取这些信息。

当您说“没有从Ghostscript抛出错误”时,我认为您可能正在混淆Ghostscript和Ghostscript.NET。如果没有看到来自Ghostscript的后端通道,我不知道您如何判断Ghostscript是否生成了错误。

请注意,如果您计划分发应用程序,则必须遵守AGPL版本3的条款(这是适用于Ghostscript的许可证),其中包括提供许可证副本以及某些通知用户可以获取原始许可证的手段。


正如我所说,我对C#和.NET完全是新手。是的,我应该学习有关stdout和/或stderr的知识。非常感谢! - Muhammad Rasel Parvej

3

1
请尝试在官方下载站点https://www.ghostscript.com/download/gsdnld.html下载,然后页面底部的链接会带您到旧版本https://github.com/ArtifexSoftware/ghostpdl-downloads/releases。这将带您回到3年前的9.18版本。正如我在答案中提到的那样,有人需要联系Ghostscript.NET包装器的作者,它需要更新。我不建议使用旧版本,因为它们存在安全漏洞。 - KenS
1
此外,我们的 Git 代码仓库(http://git.ghostscript.com/?p=ghostpdl.git;a=tags)具有用于构建早至 19 年前的版本 6.0 的源代码标签。 - KenS
@KenS 我在Ghostscript网站和相关的Github页面上找了很久,但什么都没找到。现在你给我看了,确实很明显,我不知道当时怎么会错过它。那天我的眼睛显然没有正常工作!谢谢。 - Stuart Aitken
1
这是一个微妙的链接,也许我们应该让它更明显,但老实说,我们通常建议人们使用最新版本。我知道如果不对Ghostscript.NET进行更改,这对你来说是行不通的。 - KenS
Ghostscript生态系统对于小型企业的.NET开发者是比较陌生的,而且他们无法承担购买Accusoft或Aspose用于OCR的软件包的费用。因此我们在搜索引擎上寻找解决方法,希望能够将PDF转成光栅图,并使用NuGet将该软件包整合到我们现有的项目中。目前,在Ghostscript.NET中封装的9.26版本可以很好地解决我们企业内部应用服务的难题,但是要找到这篇stack overflow文章并不容易。 - bkwdesign

1
这个问题已经在GhostScript.NET的最新版本v.1.2.2中得到解决。
修复方法是停止使用pdfdict和GS_PDF_ProcSet,如果版本超过9.26,则这两个函数由于安全原因被Ghostscript团队设为私有。

好知道。你可能有一个链接吗,对于那些想要更详细资料的人? - Mouse On Mars
确定GhostScript.Net的Issue 62链接作为一个发布者,我在Stack Overflow上是新手,不确定我的声望是否允许我这样做 :) - Jeff Powell

0

我对GhostScript或PostScript不是很熟悉,但是我已经在GhostScript.NET代码中追踪到了问题,该代码使用gsapi执行函数。正在执行并在gs上失败的函数位于GhostscriptViewerPdfFormatHandler.cs文件中,该文件属于GhostScript.NET项目。

通过使用Oswaldo Cotes Solano建议的gs9.26和使用测试脚本比较gs9.52的结果,我进行了进一步的测试,发现GS_PDF_ProcSet在gs 9.52上导致不可恢复的错误,退出代码为1。

这导致在使用gs9.52 API时失败,但这是有意设计的,自gs9.27以来添加了安全性。虽然不建议在生产就绪的应用程序中使用-dNOSAFER,但它可以解决我们的问题。

在gs9.26中工作的预期执行和结果示例应类似于:

gswin32c.exe -q -dNOSAFER -sPDFname=c:/pdfs/test.pdf c:/pdfs/pdfpagecount.ps
Executing:
/GSNETViewer_PDFpage {
(%GSNET_VIEWER_PDF_PAGE: ) print dup == flush
pdfgetpage /Page exch store
Page /MediaBox pget
{ (%GSNET_VIEWER_PDF_MEDIA: ) print == flush  }
if
Page /CropBox pget
{ (%GSNET_VIEWER_PDF_CROP: ) print == flush }
if
Page /Rotate pget not { 0 } if
(%GSNET_VIEWER_PDF_ROTATE: ) print == flush
} def
Executing:
/Page null def
/Page# 0 def
/PDFSave null def
/DSCPageCount 0 def
Executing:
GS_PDF_ProcSet begin
pdfdict begin
Executing: (C:/pdfs/Output.pdf) (r) file runpdfbegin
Executing: /FirstPage where { pop FirstPage } { 1 } ifelse
Executing: /LastPage where { pop LastPage } { pdfpagecount } ifelse
Executing: flush (%GSNET_VIEWER_PDF_PAGES: ) print exch =only ( ) print =only (
) print flush
%GSNET_VIEWER_PDF_PAGES: 1 1
Executing: process_trailer_attrs

Executing: 1 GSNETViewer_PDFpage
%GSNET_VIEWER_PDF_PAGE: 1
%GSNET_VIEWER_PDF_MEDIA: [0.0 0.0 612.0 792.0]
%GSNET_VIEWER_PDF_CROP: [0.0 0.0 612.0 792.0]
%GSNET_VIEWER_PDF_ROTATE: 0
Executing: Page pdfshowpage_init pdfshowpage_finish
Loading NimbusSans-Regular font from %rom%Resource/Font/NimbusSans-Regular... 4124032 2548352 5183568 3818848 3 done.
showpage, press <return> to continue

在运行2.52时,使用-dNOSAFER参数并将其添加到CLI中以避免文件访问错误,并使用GhostScript.NET源代码实现相同的功能。虽然-dNOSAFER选项不是理想的选择,可能存在漏洞,但为了进行测试而不深入研究,我使用了这种方法。

C:\Program Files\gs\-\bin>gswin64c.exe -q -dNOSAFER -sPDFname=test.pdf c:/pdfs/pdfpagecount.ps
Error: /undefined in GS_PDF_ProcSet
Operand stack:
Execution stack:
%interp_exit   .runexec2   --nostringval--   --nostringval--   --nostringval--   2   %stopped_push   --nostringval--   --nostringval--   --nostringval--   false   1   %stopped_push   1990   1   3   %oparray_pop   1989   1   3   %oparray_pop   1977   1   3   %oparray_pop   1833   1   3   %oparray_pop   --nostringval--   %errorexec_pop   .runexec2   --nostringval--   --nostringval--   --nostringval--   2   %stopped_push   --nostringval--
Dictionary stack:
--dict:738/1123(ro)(G)--   --dict:0/20(G)--   --dict:84/200(L)--
Current allocation mode is local
Current file position is 992
GPL Ghostscript 9.52: Unrecoverable error, exit code 1

最终在源代码的三个位置进行了微小的更改,使得9.52的工作解决方案得以实现。我将提交一个拉取请求,并在拉取请求发布时向社区更新信息,否则,您可以直接向我们的分支发起拉取请求。


0

我曾经遇到过同样的问题。我使用的是c# (.NET) Ghostscript.NET (版本1.2.3)。问题出在PDF文件名上。如果文件名中包含括号 ) 或 (,那么就会出现这个问题。 我不得不重命名PDF文件以避免这些字符。

using Ghostscript.NET.Rasterizer;
var strFilePath = "C:\PdfFile(.pdf";

using (var rasterizer = new GhostscriptRasterizer())
{
    rasterizer.Open(strFilePath);
    var strPageCount = rasterizer.PageCount; //return 0
}

var pattern = "[^A-Za-z0-9 .-]+";
var regEx = new Regex(pattern);
strFilePath = regEx.Replace(strFilePath, "");

using (var rasterizer = new GhostscriptRasterizer())
{
    rasterizer.Open(strFilePath);
    var strPageCount1 = rasterizer.PageCount; //return number of pages
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接