gsapi_init_with_args 制作:-100

gsapi_init_with_args is made: -100

我正在尝试使用 Ghostscript.Net 构建 PostScript 到 PDF 转换器。 GetArgs return 的 Args 是我通常用来调用 gswin32c.exe 的那些,它们工作正常。

但是每次我调用 Process 时,我都会收到一个错误 Saying "An error occured when call to 'gsapi_init_with_args' is made: -100"。谷歌搜索该错误没有发现任何问题,所以我想我可以在这里问一下。

直接使用 Ghostscript.net 调用 .dll 时是否需要考虑不同的参数?还是我其他地方弄错了?

这是我的 class:

public class PdfConverter
{
    #region Private Fields
    private List<GhostscriptVersionInfo> _Versions = GhostscriptVersionInfo.GetInstalledVersions(GhostscriptLicense.GPL | GhostscriptLicense.AFPL | GhostscriptLicense.Artifex);
    #endregion


    #region Private Properties
    private GhostscriptVersionInfo Version { get; set; }
    #endregion


    #region Construction
    public PdfConverter()
    {
        Version = GhostscriptVersionInfo.GetLastInstalledVersion(); 
    }
    #endregion


    #region Public Members
    public bool ConvertToPdf(DirectoryInfo dir)
    {
        var d = dir;
        if(!d.Exists)
            return false;

        var postScriptFiles = d.GetFiles("*.ps");
        var pdfFiles        = postScriptFiles.Select(psf => new FileInfo(Path.ChangeExtension(psf.FullName, ".pdf")));

        foreach(var file in postScriptFiles) {
            //ThreadPool.QueueUserWorkItem(new WaitCallback((o) => { 
                Process(file, new FileInfo(Path.ChangeExtension(file.FullName, ".pdf")));
            //}));
        }

        pdfFiles.ForEach(pdf => pdf?.Refresh());
        return pdfFiles.All(pdf => pdf.Exists);
    }
    #endregion


    #region Private Helpers
    private void Process(FileInfo inputFile, FileInfo outputFile)
    {
        Console.WriteLine($"Converting {inputFile} to {outputFile}");
        var proc = new GhostscriptProcessor(Version, true);
        proc.Process(GetArgs(inputFile, outputFile).ToArray(), new ConsoleStdIO(true, true, true));
    }


    private IEnumerable<string> GetArgs(FileInfo inputFile, FileInfo outputFile)
    {
        return new [] {
            $"-q ",
            $"-sDEVICE=pdfwrite",
            $"-dSAFER",
            $"-dNOPAUSE",
            $"-dBATCH",
            $"-sPAPERSIZE=a4",
            $"-dEmbedAllFonts=true",
            $"-dAutoRotatePages=/None",
            $"-sOutputFile=\"{outputFile.FullName}\"",
            $"-dCompatibilityLevel#1.4",
            $"-c .setpdfwrite",
            $"-f \"{inputFile.FullName}\""
        };
    }
    #endregion
}

编辑: 我忘了提:要实现它,我必须制作自己的 GhostsdcriptStdIO class。我承认我不完全确定我这样做是否正确。尽管它确实无一例外地被实例化,并覆盖 StdOut(...) 被调用,并且输出按预期写入控制台。 override void StdError(...) 也被调用。并且还按预期写入控制台。 顺便说一句,错误的输出是:

“**** 无法打开文件 "c:\temp\test.pdf"” "**** 无法打开初始设备,正在退出。"

这是我的 ConsoleStdIO class:

public class ConsoleStdIO : Ghostscript.NET.GhostscriptStdIO
{
    #region Construction
    public ConsoleStdIO(bool handleStdIn, bool handleStdOut, bool handleStdError) : base(handleStdIn, handleStdOut, handleStdError) { }  
    #endregion


    #region Overrides
    public override void StdError(string error)
    {
        var foo    = Encoding.Default.GetBytes(error);
        var lenght = foo.Length;

        using (var err = Console.OpenStandardError()) {
            if(err.CanWrite)
                err.Write(foo, 0, lenght);
        }
    }

    public override void StdIn(out string input, int count)
    {
        byte[] bytes = new byte[0];
        using(var stdInput = Console.OpenStandardInput()) {
            stdInput.Read(bytes, 0, count);
        }
        input = Encoding.Default.GetString(bytes);
    }

    public override void StdOut(string output)
    {
        var foo    = Encoding.Default.GetBytes(output);
        var lenght = foo.Length;

        using (var err = Console.OpenStandardError()) {
            if(err.CanWrite)
                err.Write(foo, 0, lenght);
        }           
    }
    #endregion
}

再次:使用 gswin32c.exe 对完全相同的文件和参数执行相同的操作效果很好。 快乐黑客

错误-100是gs_error_Fatal,意思是'something catastrophic went wrong'。这表明该程序未能正常启动,我们无法确定原因。后台频道可能包含更多信息。

事实上,后台渠道会告诉您哪里出了问题:

**** 无法打开文件“c:\temp\test.pdf **** 无法打开初始设备,正在退出。

Ghostscript 无法打开输出文件,这意味着它无法打开 pdfwrite 设备(因为 需要 输出文件)所以它中止了操作。

Ghostscript 无法打开输出文件的原因可能有多种。我要做的第一件事是 trim 减少参数的数量;

当你试图调试一个问题时,你不希望-q(安静),你想要你能得到的所有信息。

我至少要删除 -dSAFER,因为这样可以防止 Ghostscript 访问当前工作目录和某些 'special' 目录之外的目录。它可能会阻止您访问临时目录。

当它与默认值相同时,您不需要设置EmbedAllFonts

您可以删除 CompatibilityLevel(请注意,您在此处使用了 # 而不是 =)开关,并在使其正常工作时删除 AutoRotatePages

-c .setpdfwrite -f”字符串多年来一直毫无意义,但人们仍在继续使用它。这些天所做的只是减慢处理的启动速度,放弃它。

最后,您可以尝试将反斜杠('\')字符更改为正斜杠('/'),以防您的字符串处理弄乱它,或者使用双反斜杠(我自己会使用正斜杠) .

您还应检查 c:\test\temp.pdf 是否不存在,或者如果它存在则不是只读的或已在其他应用程序中打开。

所以我解决了问题...
在接受了 KenS 的建议后,我可以 运行 没有 Ghostscript 的应用程序(不是 Ghostscript.NET)给我任何错误。但它没有生成实际的 PDF 文件。

所以 KenS 的回答并没有完全解决问题,但是由于 'less is more' 并且由于他花时间在 IRC 上与我交谈以验证我的参数本身是否正确,所以我会给出答案尽管如此。

真正解决我的问题如下:
这是我原来的 GetArgs(...)

    private IEnumerable<string> GetArgs(FileInfo inputFile, FileInfo outputFile)
    {
        return new [] {
            $"-sDEVICE=pdfwrite",
            $"-dNOPAUSE",
            $"-dBATCH",
            $"-sPAPERSIZE=a4",
            @"-sFONTPATH=" + System.Environment.GetFolderPath(System.Environment.SpecialFolder.Fonts),
            $"-sOutputFile={outputFile.FullName}",
            $"{inputFile.FullName}",
        };
    }

#csharp 中有人向我指出,在 c 中,第一个参数始终是命令的名称。所以他建议只把 "gs" 作为第一个参数(作为一个虚拟参数)并尝试......这就是真正解决我的问题的方法。

这就是 GetArgs(...) 的工作方式:

    private IEnumerable<string> GetArgs(FileInfo inputFile, FileInfo outputFile)
    {
        return new [] {
            $"gs",
            $"-sDEVICE=pdfwrite",
            $"-dNOPAUSE",
            $"-dBATCH",
            $"-sPAPERSIZE=a4",
            @"-sFONTPATH=" + System.Environment.GetFolderPath(System.Environment.SpecialFolder.Fonts),
            $"-sOutputFile={outputFile.FullName}",
            $"{inputFile.FullName}",
        };
    }