在参数中使用 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的主要内容,如果未能解决你的问题,请参考以下文章
将长 Unicode 字符串传递给 FireDac TADQuery 参数
Tableau 设计提示4.0 在 Tableau 中使用 Unicode 字符