Question

I want to use Ghostscript in a .NET / C# application to convert a .tiff file to PDF. My problem: When the file path contains non-ansi characters (e.g. Umlaute), the function

gsapi_init_with_args 

fails. (With GS 8.x, it works fine!). I found information that the behaviour was changed in 9.x, and I also found a function called

gsapi_init_with_argsW

And this function should work with .NET without any problems (see http://permalink.gmane.org/gmane.comp.printing.ghostscript.cvs/31721)

So I use the following DLLImport:

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

but this still does not work, I get the error:

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

The name of the file schould be

C:\\ÄNDERUNGEN\\TEST.PDF

so the umlaut "Ä" is not recognized correctly.

I´ve search the web a lot but did not found a solution.

Any idea? Thank you!

Was it helpful?

Solution

I suspect that you will need to use UTF-8 here. Make a call to gs_set_arg_encoding passing GS_ARG_ENCODING_UTF8.

Any strings that you pass to Ghostscript should be declared as IntPtr. To convert from a C# string to a null-terminated UTF-8 encoded string use this 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;
}

Make sure that you remember to clean up with a call to Marshal.FreeHGlobal.

The overall code might look a little like this:

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);
        }
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top