使用GhostScript打印PDF

5

我需要您在以下问题上的支持,因为这个问题已经困扰我一段时间了。我们有一个小的 c# 实用程序,它使用 GhostScript 打印给定的 PDF 。这个工具可以正常打印,但无法保留页面格式。然而,当我将 Adobe Acrobat 替换为 GhostScript 时,页面会按预期打印。因此,我认为,在GhostScript的命令行参数上犯了一些明显的错误。

背景

以下是核心 c# 逻辑,它以不同的样式打印给定的PDF文件中的每个页面。给定的PDF文件包含以下页面:

  1. 字体样式和颜色不一致的页面
  2. 一些页面具有普通字号,而其他页面则采用特别小的字号打印
  3. 一些页面具有建议的边距,而其他页面则具有非常小的边距
  4. 一些页面是彩色的,其余页面是灰色的。
  5. 一些页面是横向的,而其他页面是纵向的

简而言之,我要打印的PDF只是众多小型PDF文档(将单个PDF合并成一个大型PDF)的汇总,这些文档具有不同的字体样式、大小和边距。

问题

以下逻辑使用 GhostScript(v9.02)打印PDF文件。虽然以下逻辑可以打印任何给定的PDF,但它无法保留页面格式,包括页眉、页脚、字号、页边距、方向(我的PDF文件有横向和纵向的页面)。

有趣的是,如果我使用Acrobat Reader打印相同的PDF,则会按预期打印,并保留所有页面级格式。

PDF样本:第一部分第二部分

  void PrintDocument()
    {
         var psInfo = new ProcessStartInfo();
                psInfo.Arguments =
                    String.Format(
                        " -dPrinted -dBATCH -dNOPAUSE -dNOSAFER -q -dNumCopies=1 -sDEVICE=ljet4 -sOutputFile=\"\\\\spool\\{0}\" \"{1}\"",
                        GetDefaultPrinter(), @"C:\PDFOutput\test.pdf");
                psInfo.FileName = @"C:\Program Files\gs\gs9.10\bin\gswin64c.exe";
                psInfo.UseShellExecute = false;

        using (var process= Process.Start(psInfo))
        {
            process.WaitForExit();
        }
    }

根据我们项目的经验,GhostScript/GhostPDL(PCL)/GhostXPS在字体支持方面实际上非常不一致,除非它是面向Ghost DTP核心的,否则在生产周期中都不应该使用。 - kagali-san
@KenS,当我比较Adobe和GhostScript的打印输出时,唯一的区别在于字体大小。这意味着两者都使用相同的字体进行打印,但Ghost打印的略大于Adobe,因此我有一行被切掉了。同时,你知道如何控制字体大小吗? - S.N
@KenS,感谢您一直以来的支持。现在我正在朝着一个方向前进,可以找到fontmap文件并了解如何映射其中的字体。 - S.N
文本不是像在文本文件中一样逐行编写的,而是放置在页面上,因此字体大小没有影响。如果字体比预期的大,则字形会碰撞,但文本位置仍然正确。我看不出字体如何对此产生影响。可能会有影响的是媒体大小,很可能您已将Acrobat的打印对话框设置为“缩小以适应”或类似的选项,这会减小实际页面大小,使其适合打印页面(考虑到边距)。我不确定mswinpr2设备是否提供此功能。 - KenS
@KenS,我尝试通过GSview UI打印文档(完全避免调用GhostScript的C#代码),并启用mswinpr2作为打印方法。还将“缩小以适应页面大小”设置为“是”。但仍然没有成功。你知道除Adobe之外的其他PDF打印软件吗? - S.N
显示剩余8条评论
4个回答

3

答案 - 更新于2013年12月16日

我已经成功解决了问题,并希望提供可行的解决方案,以帮助其他人。特别感谢“KenS”,因为他花费了很多时间指导我。

总结一下,我最终决定使用GSView和GhostScript打印PDF文件,以避免使用Adobe。以下是核心逻辑:

 //PrintParamter is a custom data structure to capture file related info
private void PrintDocument(PrintParamter fs, string printerName = null)
        {
            if (!File.Exists(fs.FullyQualifiedName)) return;

            var filename = fs.FullyQualifiedName ?? string.Empty;
            printerName = printerName ?? GetDefaultPrinter(); //get your printer here

            var processArgs = string.Format("-dAutoRotatePages=/All -dNOPAUSE -dBATCH -sPAPERSIZE=a4 -dFIXEDMEDIA -dPDFFitPage -dEmbedAllFonts=true -dSubsetFonts=true -dPDFSETTINGS=/prepress -dNOPLATFONTS -sFONTPATH=\"C:\\Program Files\\gs\\gs9.10\\fonts\" -noquery -dNumCopies=1 -all -colour -printer \"{0}\" \"{1}\"", printerName, filename);
            try
            {

                var gsProcessInfo = new ProcessStartInfo
                                        {
                                            WindowStyle = ProcessWindowStyle.Hidden,
                                            FileName = gsViewEXEInstallationLocation,
                                            Arguments = processArgs
                                        };
                using (var gsProcess = Process.Start(gsProcessInfo))
                {

                    gsProcess.WaitForExit();

                }

        }

2

您可以使用 GSPRINT

我已经成功地使它工作,只需要将 gsprint.exe / gswin64c.exe / gsdll64.dll 复制到一个目录中,并从那里启动它。

示例代码:

    // This uses gsprint (mind the paths)
    private const string gsPrintExecutable = @"C:\gs\gsprint.exe";
    private const string gsExecutable = @"C:\gs\gswin64c.exe";

    string pdfPath = @"C:\myShinyPDF.PDF"
    string printerName = "MY PRINTER";


    string processArgs = string.Format("-ghostscript \"{0}\" -copies=1 -all -printer \"{1}\" \"{2}\"", gsExecutable, printerName, pdfPath );

            var gsProcessInfo = new ProcessStartInfo
                                    {
                                        WindowStyle = ProcessWindowStyle.Hidden,
                                        FileName = gsPrintExecutable ,
                                        Arguments = processArgs
                                    };
            using (var gsProcess = Process.Start(gsProcessInfo))
            {

                gsProcess.WaitForExit();

            }

2

我认为你之前问过这个问题,从你的代码样例中可以清楚地看出你正在使用 GSView,而不是 Ghostscript

虽然 GSView 使用 Ghostscript 来完成重要工作,但你无法区分这两个应用程序,这是一个问题。

你仍未提供示例 PDF 文件以查看,也没有提供命令行,尽管你现在至少已经引用了 Ghostscript 版本。你需要同时给出命令行(我不准备从阅读你的代码中组装它),并且应该从命令行中尝试,而不是在你自己的应用程序内部尝试,以显示这不是你的应用程序导致错误。

你应该考虑升级 Ghostscript 至当前版本。

请注意,快速审阅你的代码表明,你正在指定许多命令行选项(例如 -dPDFSETTINGS),这些选项仅适用于将文件转换为 PDF,而不适用于任何其他用途(例如打印)。

所以,就像我之前说的那样,请提供一个可重现问题的样本文件和命令行(最好是 Ghostscript 命令行)来引起问题。知道你使用的打印机可能也很有用,尽管我很可能没有重复测试的打印机。


感谢您的回复。(1) 在通过搜索引擎后,我认为GsView使用GhostScript打印PDF文件。我想我需要重新审视一下我的理解。(2) 您能否帮助我或指导我如何在没有使用GsView的情况下使用GhostScript来打印PDF文件?(3) 至于样例PDF文档,我可以向您保证其中含有NDA和财务信息,因此我不能分享它。非常抱歉。但是,我肯定会寻找一些过时/旧的PDF文件。(4) 您说得很对,我由于知识不足尝试了一些随机的命令行选项。 - S.N
根据您的建议,我修改了我的初始帖子和应用程序,替换了GSView的使用,现在完全依赖于GhostScript。然而,问题仍然存在。有任何帮助吗? - S.N
GSView确实使用Ghostscript,但命令行参数不同。如果您无法共享导致问题的文档,则我无法提供进一步的帮助。也许您可以创建一个可以共享的文档。在Windows下使用Ghostscript打印文件需要使用mswinpr2设备。 - KenS
我附上了文件的样本。实际上,在打印之前,我们将这些文件连接在一起。但是这个连接过程是由第三方完成的,因此我无法控制它。然而,这些单独的文件足以重现问题。另外,正如您建议的那样,我可以使用GhostScript或GSView与GhostScript来打印这些文件。 - S.N
app1.pdf有问题,它包含2个%%EOF和2个startxref指令(应该只有1个)。Ghostscript在读取文件时会修复这个问题。主要的问题是这两个文件都使用了字体,但它们没有提供字体文件。无论使用Acrobat还是其他软件,当出现这种情况时,都会进行字体替换。Acrobat表现不同的原因是在安装时将Windows字体文件夹中的字体添加到可用字体列表中。你也可以通过添加-sFONTPATH=参数和可能修改fontmap.gs文件(需要下载GS源代码)来实现Ghostscript的相同效果。 - KenS
这里已经有很多关于将字体添加到GS的答案,所以我不会再详细解释。你还看到这些文件有什么其他问题吗? - KenS

0

Process.Start() 中尝试以下命令:

gswin32c.exe -sDEVICE=mswinpr2 -dBATCH -dNOPAUSE -dNOPROMPT -dNoCancel -dPDFFitPage -sOutputFile="%printer%\\[printer_servername]\[printername]" "[filepath_to_pdf]"

在C#中应该是这样的:

string strCmdText = "gswin32c.exe -sDEVICE=mswinpr2 -dBATCH -dNOPAUSE -dNOPROMPT -dNoCancel -dPDFFitPage -sOutputFile=\"%printer%\\\\[printer_servername]\\[printername]\" \"[filepath_to_pdf]\"";
System.Diagnostics.Process.Start("CMD.exe", strCmdText);

这将把指定的PDF文件放入打印队列。

注意 - 你的gswin32c.exe必须与你的C#程序在同一个目录下。我还没有测试过这段代码。


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