在参数中使用 Unicode 字符的 Windows 中使用 GhostScript 9.10

Posted

技术标签:

【中文标题】在参数中使用 Unicode 字符的 Windows 中使用 GhostScript 9.10【英文标题】:Using GhostScript 9.10 in Windows with Unicode characters in parameters 【发布时间】:2014-01-21 07:32:32 【问题描述】:

我想在 .NET / C# 应用程序中使用 Ghostscript 将 .tiff 文件转换为 PDF。 我的问题:当文件路径包含非ansi字符(例如元音变音)时,函数

gsapi_init_with_args 

失败。 (使用 GS 8.x,它可以正常工作!)。 我发现了在 9.x 中行为发生了变化的信息,并且我还发现了一个名为

的函数
gsapi_init_with_argsW

而且这个函数应该可以在 .NET 上正常工作(参见http://permalink.gmane.org/gmane.comp.printing.ghostscript.cvs/31721)

所以我使用以下 DLLImport:

[DllImport(@"gsdll32.dll")]
public static extern int gsapi_init_with_argsW( IntPtr instace, int argc, string[] argv);

但这仍然不起作用,我收到错误:

Error: /undefinedfilename
in (C:\\304NDERUNGEN\\TEST.PDF)

文件名应该是

C:\\ÄNDERUNGEN\\TEST.PDF

因此无法正确识别变音符号“Ä”。

我在网上搜索了很多,但没有找到解决方案。

有什么想法吗? 谢谢!

【问题讨论】:

DllImport(@"gsdll32.dll", CharSet=CharSet.Unicode) 怎么样? 如果我这样做,应用程序在调用gsapi_init_with_args时会挂起,我不知道为什么......我意识到标准ghost DLL中不存在gsapi_init_with_argsW(DLLImport会自动回退到gsapi_init_with_args中在这种情况下,我没有收到错误但使用了标准的 gsapi_init_with_args 函数),所以我现在在调用 gsapi_init_with_args 之前直接调用 gsapi_set_arg_encoding(instance, 2)。这仍然会导致上述相同的问题。 unicode 的 gsapi_set_arg_encoding 是否默认为 UTF8? .NET 使用 UTF-16,您是否指定了正确的编码?不得已:使用转换为 UTF8 的内存字节指针传递自定义构造的内存指针数组? gsapi_set_arg_encoding 调用中的“2”代表 UTF-16。如果 1 是 UTF-8,0 是 ANSI。 这可能是 gsapi 中的错误。您是否尝试过将其作为命令行进程运行? 【参考方案1】:

我怀疑您需要在此处使用 UTF-8。通过GS_ARG_ENCODING_UTF8 拨打gs_set_arg_encoding

您传递给 Ghostscript 的任何字符串都应声明为 IntPtr。要将 C# 字符串转换为以 null 结尾的 UTF-8 编码字符串,请使用此 function provided by Hans Passant:

public static IntPtr NativeUtf8FromString(string managedString) 

    int len = Encoding.UTF8.GetByteCount(managedString);
    byte[] buffer = new byte[len + 1]; // null-terminator allocated
    Encoding.UTF8.GetBytes(managedString, 0, managedString.Length, buffer, 0);
    IntPtr nativeUtf8 = Marshal.AllocHGlobal(buffer.Length);
    Marshal.Copy(buffer, 0, nativeUtf8, buffer.Length);
    return nativeUtf8;

确保您记得致电Marshal.FreeHGlobal 进行清理。

整体代码可能有点像这样:

public class Ghostscript

    public const int GS_ARG_ENCODING_LOCAL = 0;
    public const int GS_ARG_ENCODING_UTF8 = 1;

    [DllImport("gsdll32.dll")]
    private static extern int gsapi_new_instance(out IntPtr inst, IntPtr handle);

    [DllImport("gsdll32.dll")]
    private static extern int gsapi_set_arg_encoding(IntPtr inst, int encoding);

    [DllImport("gsdll32.dll")]
    private static extern int gsapi_init_with_args(IntPtr inst, int argc, IntPtr[] argv);

    [DllImport("gsdll32.dll")]
    private static extern int gsapi_exit(IntPtr inst);

    [DllImport("gsdll32.dll")]
    private static extern void gsapi_delete_instance(IntPtr inst);

    private static void checkReturnValue(int retval)
    
        if (retval != 0)
            throw ...; // implement error handling here
    

    public static void run(string[] argv)
    
        IntPtr inst;
        checkReturnValue(gsapi_new_instance(out inst, IntPtr.Zero));
        try
        
            IntPtr[] utf8argv = new IntPtr[argv.length];
            for (int i=0; i<utf8argv.Length; i++)
                utf8argv[i] = NativeUtf8FromString(argv[i]);
            try
            
                checkReturnValue(gsapi_set_arg_encoding(inst, GS_ARG_ENCODING_UTF8));
                checkReturnValue(gsapi_init_with_args(inst, utf8argv.Length, utf8argv));
                checkReturnValue(gsapi_exit(inst));
            finally
            
                for (int i=0; i<utf8argv.Length; i++)
                    Marshal.FreeHGlobal(utf8argv[i]);
            
        
        finally
        
            gsapi_delete_instance(inst);
        
    

【讨论】:

完美!立即生效。非常感谢! 好吧,我必须说我大吃一惊!我希望您至少需要进行一些调试和修复!无论如何,我很高兴能帮上忙。 原来的问题已经解决了,但是现在我在一些机器上遇到了 AccessViolationException。你有什么想法吗? 不。我想你需要一个包含所有相关细节的新问题。

以上是关于在参数中使用 Unicode 字符的 Windows 中使用 GhostScript 9.10的主要内容,如果未能解决你的问题,请参考以下文章

python中的字符问题

将长 Unicode 字符串传递给 FireDac TADQuery 参数

Tableau 设计提示4.0 在 Tableau 中使用 Unicode 字符

为啥记事本每次保存都说该文件含有unicode格式的字符?

使用from __future__ import unicode_literals

window.atob