summaryrefslogtreecommitdiff
path: root/platform/windows/gsview/ghostsharp.cs
diff options
context:
space:
mode:
Diffstat (limited to 'platform/windows/gsview/ghostsharp.cs')
-rw-r--r--platform/windows/gsview/ghostsharp.cs1165
1 files changed, 1165 insertions, 0 deletions
diff --git a/platform/windows/gsview/ghostsharp.cs b/platform/windows/gsview/ghostsharp.cs
new file mode 100644
index 00000000..168ce476
--- /dev/null
+++ b/platform/windows/gsview/ghostsharp.cs
@@ -0,0 +1,1165 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+//using System.Threading.Tasks;
+using System.Runtime.InteropServices;
+using System.IO;
+using System.Security;
+using System.ComponentModel;
+
+namespace gsview
+{
+ /* Warning. This list is in a particular order. The devices before
+ * psdrgb do not support multiple pages. Those including psdrgb do
+ * support multiple pages. This is used in the conversion process.
+ * Also note that mupdf devices go at the beginning of the list */
+ public enum gsDevice_t
+ {
+ svg,
+ pnm,
+ pclbitmap,
+ pwg,
+ bmp16, /* Add mupdf devices before this one */
+ bmp16m,
+ bmp256,
+ bmp32b,
+ bmpgray,
+ bmpmono,
+ eps2write,
+ jpeg,
+ jpegcmyk,
+ jpeggray,
+ pamcmyk32,
+ pamcmyk4,
+ pbm,
+ pgm,
+ png16,
+ png16m,
+ png256,
+ pngalpha,
+ pnggray,
+ pngmono,
+ psdcmyk,
+ psdrgb, /* Add single page gs devices before this device */
+ pdfwrite,
+ ps2write,
+ pxlcolor,
+ pxlmono,
+ tiff12nc,
+ tiff24nc,
+ tiff32nc,
+ tiff64nc,
+ tiffcrle,
+ tiffg3,
+ tiffg32d,
+ tiffg4,
+ tiffgray,
+ tifflzw,
+ tiffpack,
+ tiffsep,
+ txtwrite,
+ xpswrite
+ };
+
+ public enum GS_Task_t
+ {
+ PS_DISTILL,
+ CREATE_XPS,
+ SAVE_RESULT
+ }
+
+ public enum GS_Result_t
+ {
+ gsOK,
+ gsFAILED,
+ gsCANCELLED
+ }
+
+ /* Parameters */
+ public struct gsParams_t
+ {
+ public String init_string;
+ public String init_file;
+ public int resolution;
+ public gsDevice_t device;
+ public String devicename;
+ public String outputfile;
+ public String inputfile;
+ public GS_Task_t task;
+ public GS_Result_t result;
+ public int num_pages;
+ public String options;
+ public bool need_multi_page;
+ public System.Collections.IList pages;
+ public int firstpage;
+ public int lastpage;
+ public int currpage; /* valid only when pages != null */
+ };
+
+ public class gsEventArgs : EventArgs
+ {
+ private bool m_completed;
+ private int m_progress;
+ private gsParams_t m_param;
+
+ public bool Completed
+ {
+ get { return m_completed; }
+ }
+
+ public gsParams_t Params
+ {
+ get { return m_param; }
+ }
+
+ public int Progress
+ {
+ get { return m_progress; }
+ }
+
+ public gsEventArgs(bool completed, int progress, gsParams_t param)
+ {
+ m_completed = completed;
+ m_progress = progress;
+ m_param = param;
+ }
+ }
+
+ /* from gs */
+ public struct gsapi_revision_t
+ {
+ public IntPtr product;
+ public IntPtr copyright;
+ public int revision;
+ public int revisiondate;
+ }
+
+ public enum gsEncoding {
+ GS_ARG_ENCODING_LOCAL = 0,
+ GS_ARG_ENCODING_UTF8 = 1,
+ GS_ARG_ENCODING_UTF16LE = 2
+ };
+
+ public enum gsStatus
+ {
+ GS_READY,
+ GS_BUSY,
+ GS_ERROR
+ };
+
+ static class gsConstants
+ {
+ public const int E_QUIT = -101;
+ public const int GS_READ_BUFFER = 32768;
+ }
+
+ [SuppressUnmanagedCodeSecurity]
+ class ghostsharp
+ {
+ /* Callback proto for stdio */
+ public delegate int gsStdIOHandler(IntPtr caller_handle, IntPtr buffer,
+ int len);
+
+ #region DLLInterface
+ /* Ghostscript API */
+ [DllImport("gsdll64.dll", EntryPoint = "gsapi_revision", CharSet = CharSet.Ansi,
+ CallingConvention = CallingConvention.StdCall)]
+ private static extern int gsapi_revision64(ref gsapi_revision_t vers, int size);
+
+ [DllImport("gsdll64.dll", EntryPoint="gsapi_new_instance", CharSet = CharSet.Ansi,
+ CallingConvention = CallingConvention.StdCall)]
+ private static extern int gsapi_new_instance64(out IntPtr pinstance,
+ IntPtr caller_handle);
+
+ [DllImport("gsdll64.dll", EntryPoint = "gsapi_delete_instance", CharSet = CharSet.Ansi,
+ CallingConvention = CallingConvention.StdCall)]
+ private static extern void gsapi_delete_instance64(IntPtr instance);
+
+ [DllImport("gsdll64.dll", EntryPoint = "gsapi_init_with_args", CharSet = CharSet.Ansi,
+ CallingConvention = CallingConvention.StdCall)]
+ private static extern int gsapi_init_with_args64(IntPtr instance, int argc,
+ IntPtr argv);
+
+ [DllImport("gsdll64.dll", EntryPoint = "gsapi_exit", CharSet = CharSet.Ansi,
+ CallingConvention = CallingConvention.StdCall)]
+ private static extern int gsapi_exit64(IntPtr instance);
+
+ [DllImport("gsdll64.dll", EntryPoint = "gsapi_set_arg_encoding", CharSet = CharSet.Ansi,
+ CallingConvention = CallingConvention.StdCall)]
+ private static extern int gsapi_set_arg_encoding64(IntPtr instance,
+ int encoding);
+
+ [DllImport("gsdll64.dll", EntryPoint = "gsapi_set_stdio", CharSet = CharSet.Ansi,
+ CallingConvention = CallingConvention.StdCall)]
+ private static extern int gsapi_set_stdio64(IntPtr instance,
+ gsStdIOHandler stdin, gsStdIOHandler stdout, gsStdIOHandler stderr);
+
+ [DllImport("gsdll64.dll", EntryPoint = "gsapi_run_string_begin", CharSet = CharSet.Ansi,
+ CallingConvention = CallingConvention.StdCall)]
+ private static extern void gsapi_run_string_begin64(IntPtr instance,
+ int usererr, ref int exitcode);
+
+ [DllImport("gsdll64.dll", EntryPoint = "gsapi_run_string_continue", CharSet = CharSet.Ansi,
+ CallingConvention = CallingConvention.StdCall)]
+ private static extern void gsapi_run_string_continue64(IntPtr instance,
+ IntPtr command, int count, int usererr, ref int exitcode);
+
+ [DllImport("gsdll64.dll", EntryPoint = "gsapi_run_string_end", CharSet = CharSet.Ansi,
+ CallingConvention = CallingConvention.StdCall)]
+ private static extern void gsapi_run_string_end64(IntPtr instance,
+ int usererr, ref int exitcode);
+
+ /* 32 Bit DLL */
+ [DllImport("gsdll32.dll", EntryPoint = "gsapi_revision", CharSet = CharSet.Ansi,
+ CallingConvention = CallingConvention.StdCall)]
+ private static extern int gsapi_revision32(ref gsapi_revision_t vers, int size);
+
+ [DllImport("gsdll32.dll", EntryPoint = "gsapi_new_instance", CharSet = CharSet.Ansi,
+ CallingConvention = CallingConvention.StdCall)]
+ private static extern int gsapi_new_instance32(out IntPtr pinstance,
+ IntPtr caller_handle);
+
+ [DllImport("gsdll32.dll", EntryPoint = "gsapi_delete_instance", CharSet = CharSet.Ansi,
+ CallingConvention = CallingConvention.StdCall)]
+ private static extern void gsapi_delete_instance32(IntPtr instance);
+
+ [DllImport("gsdll32.dll", EntryPoint = "gsapi_init_with_args", CharSet = CharSet.Ansi,
+ CallingConvention = CallingConvention.StdCall)]
+ private static extern int gsapi_init_with_args32(IntPtr instance, int argc,
+ IntPtr argv);
+
+ [DllImport("gsdll32.dll", EntryPoint = "gsapi_exit", CharSet = CharSet.Ansi,
+ CallingConvention = CallingConvention.StdCall)]
+ private static extern int gsapi_exit32(IntPtr instance);
+
+ [DllImport("gsdll32.dll", EntryPoint = "gsapi_set_arg_encoding", CharSet = CharSet.Ansi,
+ CallingConvention = CallingConvention.StdCall)]
+ private static extern int gsapi_set_arg_encoding32(IntPtr instance,
+ int encoding);
+
+ [DllImport("gsdll32.dll", EntryPoint = "gsapi_set_stdio", CharSet = CharSet.Ansi,
+ CallingConvention = CallingConvention.StdCall)]
+ private static extern int gsapi_set_stdio32(IntPtr instance,
+ gsStdIOHandler stdin, gsStdIOHandler stdout, gsStdIOHandler stderr);
+
+ [DllImport("gsdll32.dll", EntryPoint = "gsapi_run_string_begin", CharSet = CharSet.Ansi,
+ CallingConvention = CallingConvention.StdCall)]
+ private static extern void gsapi_run_string_begin32(IntPtr instance,
+ int usererr, ref int exitcode);
+
+ [DllImport("gsdll32.dll", EntryPoint = "gsapi_run_string_continue", CharSet = CharSet.Ansi,
+ CallingConvention = CallingConvention.StdCall)]
+ private static extern void gsapi_run_string_continue32(IntPtr instance,
+ IntPtr command, int count, int usererr, ref int exitcode);
+
+ [DllImport("gsdll32.dll", EntryPoint = "gsapi_run_string_end", CharSet = CharSet.Ansi,
+ CallingConvention = CallingConvention.StdCall)]
+ private static extern void gsapi_run_string_end32(IntPtr instance,
+ int usererr, ref int exitcode);
+ #endregion DLLInterface
+
+ #region DLLErrorCatch
+ /* In case the DLL is not found we need to wrap the methods up with
+ * a try/catch. Also select 32 or 64 bit DLL at this time. This
+ * C# code is compiled as ANYCPU type */
+ private int tc_gsapi_revision(ref gsapi_revision_t vers, int size)
+ {
+ int code = 0;
+ try
+ {
+ if (is64bit)
+ code = gsapi_revision64(ref vers, size);
+ else
+ code = gsapi_revision32(ref vers, size);
+ }
+ catch (DllNotFoundException)
+ {
+ /* DLL not found */
+ String output = "DllNotFoundException: Ghostscript DLL not found";
+ gsDLLProblemMain(this, output);
+ return -1;
+ }
+ catch (BadImageFormatException)
+ {
+ /* Using 32 bit with 64 or vice versa */
+ String output = "BadImageFormatException: Incorrect Ghostscript DLL";
+ gsDLLProblemMain(this, output);
+ return -1;
+ }
+ return code;
+ }
+
+ private int tc_gsapi_new_instance(out IntPtr pinstance, IntPtr caller_handle)
+ {
+ int code = 0;
+ pinstance = IntPtr.Zero;
+ try
+ {
+ if (is64bit)
+ code = gsapi_new_instance64(out pinstance, caller_handle);
+ else
+ code = gsapi_new_instance32(out pinstance, caller_handle);
+ }
+ catch (DllNotFoundException)
+ {
+ /* DLL not found */
+ String output = "DllNotFoundException: Ghostscript DLL not found";
+ gsDLLProblemMain(this, output);
+ return -1;
+ }
+ catch (BadImageFormatException)
+ {
+ /* Using 32 bit with 64 or vice versa */
+ String output = "BadImageFormatException: Incorrect Ghostscript DLL";
+ gsDLLProblemMain(this, output);
+ return -1;
+ }
+ return code;
+ }
+
+ private int tc_gsapi_delete_instance(IntPtr instance)
+ {
+ try
+ {
+ if (is64bit)
+ gsapi_delete_instance64(instance);
+ else
+ gsapi_delete_instance32(instance);
+ }
+ catch (DllNotFoundException)
+ {
+ /* DLL not found */
+ String output = "DllNotFoundException: Ghostscript DLL not found";
+ gsDLLProblemMain(this, output);
+ return -1;
+ }
+ catch (BadImageFormatException)
+ {
+ /* Using 32 bit with 64 or vice versa */
+ String output = "BadImageFormatException: Incorrect Ghostscript DLL";
+ gsDLLProblemMain(this, output);
+ return -1;
+ }
+ return 0;
+ }
+
+ private int tc_gsapi_init_with_args(IntPtr instance, int argc, IntPtr argv)
+ {
+ int code;
+
+ try
+ {
+ if (is64bit)
+ code = gsapi_init_with_args64(instance, argc, argv);
+ else
+ code = gsapi_init_with_args32(instance, argc, argv);
+ }
+ catch (DllNotFoundException)
+ {
+ /* DLL not found */
+ String output = "DllNotFoundException: Ghostscript DLL not found";
+ gsDLLProblemMain(this, output);
+ return -1;
+ }
+ catch (BadImageFormatException)
+ {
+ /* Using 32 bit with 64 or vice versa */
+ String output = "BadImageFormatException: Incorrect Ghostscript DLL";
+ gsDLLProblemMain(this, output);
+ return -1;
+ }
+ catch(System.Reflection.TargetInvocationException ee)
+ {
+ String output = "TargetInvocationException";
+ gsDLLProblemMain(this, output);
+ return -1;
+ }
+
+ return code;
+ }
+
+ private int tc_gsapi_exit(IntPtr instance)
+ {
+ int code;
+ try
+ {
+ if (is64bit)
+ code = gsapi_exit64(instance);
+ else
+ code = gsapi_exit32(instance);
+ }
+ catch (DllNotFoundException)
+ {
+ /* DLL not found */
+ String output = "DllNotFoundException: Ghostscript DLL not found";
+ gsDLLProblemMain(this, output);
+ return -1;
+ }
+ catch (BadImageFormatException)
+ {
+ /* Using 32 bit with 64 or vice versa */
+ String output = "BadImageFormatException: Incorrect Ghostscript DLL";
+ gsDLLProblemMain(this, output);
+ return -1;
+ }
+ return code;
+ }
+
+ private int tc_gsapi_set_arg_encoding(IntPtr instance, int encoding)
+ {
+ int code;
+ try
+ {
+ if (is64bit)
+ code = gsapi_set_arg_encoding64(instance, encoding);
+ else
+ code = gsapi_set_arg_encoding32(instance, encoding);
+ }
+ catch (DllNotFoundException)
+ {
+ /* DLL not found */
+ String output = "DllNotFoundException: Ghostscript DLL not found";
+ gsDLLProblemMain(this, output);
+ return -1;
+ }
+ catch (BadImageFormatException)
+ {
+ /* Using 32 bit with 64 or vice versa */
+ String output = "BadImageFormatException: Incorrect Ghostscript DLL";
+ gsDLLProblemMain(this, output);
+ return -1;
+ }
+ return code;
+ }
+
+ private int tc_gsapi_set_stdio(IntPtr instance, gsStdIOHandler stdin,
+ gsStdIOHandler stdout, gsStdIOHandler stderr)
+ {
+ int code;
+ try
+ {
+ if (is64bit)
+ code = gsapi_set_stdio64(instance, stdin, stdout, stderr);
+ else
+ code = gsapi_set_stdio32(instance, stdin, stdout, stderr);
+ }
+ catch (DllNotFoundException)
+ {
+ /* DLL not found */
+ String output = "DllNotFoundException: Ghostscript DLL not found";
+ gsDLLProblemMain(this, output);
+ return -1;
+ }
+ catch (BadImageFormatException)
+ {
+ /* Using 32 bit with 64 or vice versa */
+ String output = "BadImageFormatException: Incorrect Ghostscript DLL";
+ gsDLLProblemMain(this, output);
+ return -1;
+ }
+ return code;
+ }
+
+ private int tc_gsapi_run_string_begin(IntPtr instance, int usererr,
+ ref int exitcode)
+ {
+ try
+ {
+ if (is64bit)
+ gsapi_run_string_begin64(instance, usererr, ref exitcode);
+ else
+ gsapi_run_string_begin32(instance, usererr, ref exitcode);
+ }
+ catch (DllNotFoundException)
+ {
+ /* DLL not found */
+ String output = "DllNotFoundException: Ghostscript DLL not found";
+ gsDLLProblemMain(this, output);
+ return -1;
+ }
+ catch (BadImageFormatException)
+ {
+ /* Using 32 bit with 64 or vice versa */
+ String output = "BadImageFormatException: Incorrect Ghostscript DLL";
+ gsDLLProblemMain(this, output);
+ return -1;
+ }
+ return 0;
+ }
+
+ private int tc_gsapi_run_string_continue(IntPtr instance, IntPtr command,
+ int count, int usererr, ref int exitcode)
+ {
+ try
+ {
+ if (is64bit)
+ gsapi_run_string_continue64(instance, command, count, usererr,
+ ref exitcode);
+ else
+ gsapi_run_string_continue32(instance, command, count, usererr,
+ ref exitcode);
+ }
+ catch (DllNotFoundException)
+ {
+ /* DLL not found */
+ String output = "DllNotFoundException: Ghostscript DLL not found";
+ gsDLLProblemMain(this, output);
+ return -1;
+ }
+ catch (BadImageFormatException)
+ {
+ /* Using 32 bit with 64 or vice versa */
+ String output = "BadImageFormatException: Incorrect Ghostscript DLL";
+ gsDLLProblemMain(this, output);
+ return -1;
+ }
+ return 0;
+ }
+
+ private int tc_gsapi_run_string_end(IntPtr instance, int usererr,
+ ref int exitcode)
+ {
+ try
+ {
+ if (is64bit)
+ gsapi_run_string_end64(instance, usererr, ref exitcode);
+ else
+ gsapi_run_string_end32(instance, usererr, ref exitcode);
+ }
+ catch (DllNotFoundException)
+ {
+ /* DLL not found */
+ String output = "DllNotFoundException: Ghostscript DLL not found";
+ gsDLLProblemMain(this, output);
+ return -1;
+ }
+ catch (BadImageFormatException)
+ {
+ /* Using 32 bit with 64 or vice versa */
+ String output = "BadImageFormatException: Incorrect Ghostscript DLL";
+ gsDLLProblemMain(this, output);
+ return -1;
+ }
+ return 0;
+ }
+ #endregion DLLErrorCatch
+
+ private int StdInCallback(IntPtr handle, IntPtr pointer, int count)
+ {
+ String output = Marshal.PtrToStringAnsi(pointer);
+ return count;
+ }
+
+ private int StdOutCallback(IntPtr handle, IntPtr pointer, int count)
+ {
+ String output = Marshal.PtrToStringAnsi(pointer);
+ gsIOUpdateMain(this, output, count);
+ if (m_params.task != GS_Task_t.PS_DISTILL)
+ {
+ /* See if we have a page number */
+ if (count >= 7 && output.Substring(0, 4) == "Page")
+ {
+ String page = output.Substring(5, count - 6);
+ int numVal;
+ try
+ {
+ double perc = 0.0;
+ numVal = System.Convert.ToInt32(page);
+ if (m_params.firstpage == -1 && m_params.lastpage == -1 &&
+ m_params.pages == null)
+ {
+ /* Doing full document */
+ perc = 100.0 * (double)numVal / (double)m_params.num_pages;
+ }
+ else
+ {
+ if (m_params.pages != null)
+ {
+ perc = 100.0 * ((double)numVal - m_params.currpage) / (double)m_params.num_pages;
+ m_params.currpage = m_params.currpage + 1;
+ }
+ else
+ {
+ /* continugous set of pages */
+ perc = 100.0 * ((double)numVal - m_params.firstpage + 1) / (double)m_params.num_pages;
+ }
+ }
+ m_worker.ReportProgress((int)perc);
+ }
+ catch (FormatException e)
+ {
+ Console.WriteLine("XPSPrint Error: Input string is not a sequence of digits.");
+ }
+ catch (OverflowException e)
+ {
+ Console.WriteLine("XPSPrint Error: The number cannot fit in an Int32.");
+ }
+
+ }
+ }
+ return count;
+ }
+
+ private int StdErrCallback(IntPtr handle, IntPtr pointer, int count)
+ {
+ String output = Marshal.PtrToStringAnsi(pointer);
+ gsIOUpdateMain(this, output, count);
+ return count;
+ }
+
+ IntPtr gsInstance;
+ BackgroundWorker m_worker;
+ bool is64bit;
+ gsParams_t m_params;
+ /* Callbacks to Main */
+ internal delegate void gsDLLProblem(object gsObject, String mess);
+ internal event gsDLLProblem gsDLLProblemMain;
+ internal delegate void gsIOCallBackMain(object gsObject, String mess, int len);
+ internal event gsIOCallBackMain gsIOUpdateMain;
+ internal delegate void gsCallBackMain(object gsObject, gsEventArgs info);
+ internal event gsCallBackMain gsUpdateMain;
+ /* These need to be declared as members, to keep a reference and avoid GC
+ * You do not pin delegates */
+ gsStdIOHandler RaiseStdInCallback;
+ gsStdIOHandler RaiseStdOutCallback;
+ gsStdIOHandler RaiseStdErrCallback;
+
+ public ghostsharp()
+ {
+ /* Determine now if we are 64 or 32 bit */
+ is64bit = Environment.Is64BitOperatingSystem &&
+ Environment.Is64BitProcess;
+ m_worker = null;
+ gsInstance = IntPtr.Zero;
+
+ /* Go ahead and do the assignment here */
+ RaiseStdInCallback = StdInCallback;
+ RaiseStdOutCallback = StdOutCallback;
+ RaiseStdErrCallback = StdErrCallback;
+ }
+
+ private List<String> GetOptions(String options)
+ {
+ List<String> optionlist = new List<String>();
+
+ if (options != "")
+ {
+ string[] words = options.Split(' ');
+ for (int k = 0; k < words.Length; k++)
+ {
+ if (words[k].Length > 0)
+ {
+ optionlist.Add(words[k]);
+ }
+ }
+ }
+ return optionlist;
+ }
+
+ /* A standard command line approach to using gs API */
+ private void gsWork1(object sender, DoWorkEventArgs e)
+ {
+ gsParams_t gsparams = (gsParams_t) e.Argument;
+ String out_file = gsparams.outputfile;
+ String in_file = gsparams.inputfile;
+ int num_params = 8; /* base number */
+ int rend_count = 1;
+ String options;
+ int count;
+ List<String> optionlist;
+
+ optionlist = GetOptions(gsparams.options);
+ num_params = num_params + optionlist.Count;
+ if (gsparams.pages != null)
+ {
+ rend_count = gsparams.pages.Count;
+ num_params = num_params + 2;
+ }
+ if (gsparams.init_file != null)
+ num_params = num_params + 1;
+ if (gsparams.init_string != null)
+ num_params = num_params + 2;
+
+ var argParam = new GCHandle[num_params];
+ var argPtrs = new IntPtr[num_params];
+ String[] strParams = new String[num_params];
+ List<byte[]> CharacterArray = new List<byte[]>(num_params);
+ GCHandle argPtrsStable;
+
+ /* New instance */
+ int code = tc_gsapi_new_instance(out gsInstance, IntPtr.Zero);
+ if (code < 0)
+ {
+ gsparams.result = GS_Result_t.gsFAILED;
+ e.Result = gsparams;
+ return;
+ }
+
+ code = tc_gsapi_set_stdio(gsInstance, RaiseStdInCallback,
+ RaiseStdOutCallback, RaiseStdErrCallback);
+ code = tc_gsapi_set_arg_encoding(gsInstance, (int)gsEncoding.GS_ARG_ENCODING_UTF8);
+
+ if (code == 0)
+ {
+ for (int jj = 0; jj < rend_count; jj++)
+ {
+ strParams[0] = "gs"; /* This does not matter */
+ strParams[1] = "-dNOPAUSE";
+ strParams[2] = "-dBATCH";
+ if (gsparams.devicename != null)
+ {
+ strParams[3] = "-sDEVICE=" + gsparams.devicename;
+ }
+ else
+ {
+ strParams[3] = "-sDEVICE=" + Enum.GetName(typeof(gsDevice_t), gsparams.device);
+ }
+ strParams[4] = "-r" + gsparams.resolution;
+ /* Create temp file if file not specified */
+ if (out_file == null)
+ {
+ out_file = Path.GetTempFileName();
+ gsparams.outputfile = out_file;
+ }
+ count = 5;
+ /* Add in the options */
+ for (int kk = 0; kk < optionlist.Count; kk++)
+ {
+ strParams[count] = optionlist[kk];
+ count++;
+ }
+ /* We have discontinuous page selection */
+ if (gsparams.pages != null)
+ {
+ String firstpage, lastpage;
+ options = gsparams.options;
+ SelectPage curr_page = (SelectPage)(gsparams.pages[jj]);
+ firstpage = "-dFirstPage=" + curr_page.Page;
+ lastpage = "-dLastPage=" + curr_page.Page;
+ strParams[count] = firstpage;
+ count++;
+ strParams[count] = lastpage;
+ count++;
+ /* Look for file extension. */
+ string extension = System.IO.Path.GetExtension(out_file);
+ int len = extension.Length;
+ String new_out_file = out_file.Substring(0, out_file.Length - len);
+ strParams[count] = "-o" + new_out_file + "_page" + curr_page.Page + extension;
+ }
+ else
+ {
+ if (gsparams.need_multi_page)
+ {
+ /* Look for file extension. */
+ string extension = System.IO.Path.GetExtension(out_file);
+ int len = extension.Length;
+ String new_out_file = out_file.Substring(0, out_file.Length - len);
+ strParams[count] = "-o" + new_out_file + "_page%d" + extension;
+ }
+ else
+ strParams[count] = "-o" + out_file;
+ }
+ if (gsparams.init_string != null)
+ {
+ count++;
+ strParams[count] = "-c";
+ count++;
+ strParams[count] = gsparams.init_string;
+ }
+ count++;
+ strParams[count] = "-f";
+ if (gsparams.init_file != null)
+ {
+ count++;
+ strParams[count] = gsparams.init_file;
+ }
+ count++;
+ strParams[count] = in_file;
+
+ /* Now convert our Strings to char* and get pinned handles to these.
+ * This keeps the c# GC from moving stuff around on us */
+ for (int k = 0; k < num_params; k++)
+ {
+ CharacterArray.Add(System.Text.Encoding.UTF8.GetBytes(strParams[k].ToCharArray()));
+ argParam[k] = GCHandle.Alloc(CharacterArray[k], GCHandleType.Pinned);
+ argPtrs[k] = argParam[k].AddrOfPinnedObject();
+ }
+ /* Also stick the array of pointers into memory that will not be GCd */
+ argPtrsStable = GCHandle.Alloc(argPtrs, GCHandleType.Pinned);
+
+ code = tc_gsapi_init_with_args(gsInstance, num_params, argPtrsStable.AddrOfPinnedObject());
+ /* All the pinned items need to be freed so the GC can do its job */
+ for (int k = 0; k < num_params; k++)
+ {
+ argParam[k].Free();
+ }
+ argPtrsStable.Free();
+ /* Free the character array list in case we have multiple runs */
+ CharacterArray.Clear();
+
+ if (code < 0)
+ break;
+ }
+ }
+
+ int code1 = tc_gsapi_exit(gsInstance);
+ if ((code == 0) || (code == gsConstants.E_QUIT))
+ code = code1;
+
+ tc_gsapi_delete_instance(gsInstance);
+ if ((code == 0) || (code == gsConstants.E_QUIT))
+ {
+ gsparams.result = GS_Result_t.gsOK;
+ e.Result = gsparams;
+ return;
+ }
+
+ gsparams.result = GS_Result_t.gsFAILED;
+ e.Result = gsparams;
+ return;
+ }
+
+ /* Feeding gs piecemeal so that we can have some progress callback */
+ /* Used only for PS Distill */
+ private void gsWork2(object sender, DoWorkEventArgs e)
+ {
+ gsParams_t Params = (gsParams_t)e.Argument;
+ String out_file = Params.outputfile;
+ String in_file = Params.inputfile;
+ int num_params = 6;
+ if (Params.options.Length > 0)
+ num_params = num_params + 1;
+
+ int exitcode = 0;
+ var argParam = new GCHandle[num_params];
+ var argPtrs = new IntPtr[num_params];
+ var Feed = new GCHandle();
+ var FeedPtr = new IntPtr();
+ String[] strParams = new String[num_params];
+ List<byte[]> CharacterArray = new List<byte[]>(num_params);
+ GCHandle argPtrsStable;
+ Byte[] Buffer = new Byte[gsConstants.GS_READ_BUFFER];
+ BackgroundWorker worker = sender as BackgroundWorker;
+
+ /* Open the file */
+ var fs = new FileStream(in_file, FileMode.Open);
+ var len = (int) fs.Length;
+ /* New instance */
+ int code = tc_gsapi_new_instance(out gsInstance, IntPtr.Zero);
+ if (code < 0)
+ {
+ Params.result = GS_Result_t.gsFAILED;
+ e.Result = Params;
+ return;
+ }
+
+ code = tc_gsapi_set_stdio(gsInstance, RaiseStdInCallback,
+ RaiseStdOutCallback, RaiseStdErrCallback);
+ code = tc_gsapi_set_arg_encoding(gsInstance, (int)gsEncoding.GS_ARG_ENCODING_UTF8);
+
+ if (code == 0)
+ {
+ strParams[0] = "gs"; /* This does not matter */
+ strParams[1] = "-dNOPAUSE";
+ strParams[2] = "-dBATCH";
+ if (Params.devicename != null)
+ {
+ strParams[3] = "-sDEVICE=" + Params.devicename;
+ }
+ else
+ {
+ strParams[3] = "-sDEVICE=" + Enum.GetName(typeof(gsDevice_t), Params.device);
+ }
+ strParams[4] = "-r" + Params.resolution;
+ /* Create temp file if file not specified */
+ if (out_file == null)
+ {
+ out_file = Path.GetTempFileName();
+ Params.outputfile = out_file;
+ }
+ if (Params.options.Length > 0)
+ {
+ strParams[5] = Params.options;
+ strParams[6] = "-o" + out_file;
+ } else
+ strParams[5] = "-o" + out_file;
+
+ /* Now convert our Strings to char* and get pinned handles to these.
+ * This keeps the c# GC from moving stuff around on us */
+ for (int k = 0; k < num_params; k++)
+ {
+ CharacterArray.Add(System.Text.Encoding.UTF8.GetBytes(strParams[k].ToCharArray()));
+ argParam[k] = GCHandle.Alloc(CharacterArray[k], GCHandleType.Pinned);
+ argPtrs[k] = argParam[k].AddrOfPinnedObject();
+ }
+ /* Also stick the array of pointers into memory that will not be GCd */
+ argPtrsStable = GCHandle.Alloc(argPtrs, GCHandleType.Pinned);
+
+ code = tc_gsapi_init_with_args(gsInstance, num_params, argPtrsStable.AddrOfPinnedObject());
+
+ /* First pin the data buffer */
+ Feed = GCHandle.Alloc(Buffer, GCHandleType.Pinned);
+ FeedPtr = Feed.AddrOfPinnedObject();
+
+ /* Now start feeding the input piece meal and do a call back
+ * with our progress */
+ if (code == 0)
+ {
+ int count;
+ double perc;
+ int total = 0;
+
+ tc_gsapi_run_string_begin(gsInstance, 0, ref exitcode);
+ while ((count = fs.Read(Buffer, 0, gsConstants.GS_READ_BUFFER)) > 0)
+ {
+ tc_gsapi_run_string_continue(gsInstance, FeedPtr, count, 0, ref exitcode);
+ if (exitcode < 0)
+ {
+ code = exitcode;
+ break;
+ }
+ total = total + count;
+ perc = 100.0 * (double) total / (double) len;
+ worker.ReportProgress((int)perc);
+ if (worker.CancellationPending == true)
+ {
+ e.Cancel = true;
+ break;
+ }
+ }
+ tc_gsapi_run_string_end(gsInstance, 0, ref exitcode);
+ if (code == 0)
+ code = exitcode;
+ }
+
+ /* All the pinned items need to be freed so the GC can do its job */
+ for (int k = 0; k < num_params; k++)
+ {
+ argParam[k].Free();
+ }
+ argPtrsStable.Free();
+ Feed.Free();
+ }
+
+ int code1 = tc_gsapi_exit(gsInstance);
+ if ((code == 0) || (code == gsConstants.E_QUIT))
+ code = code1;
+
+ tc_gsapi_delete_instance(gsInstance);
+ if ((code == 0) || (code == gsConstants.E_QUIT))
+ {
+ Params.result = GS_Result_t.gsOK;
+ e.Result = Params;
+ return;
+ }
+ Params.result = GS_Result_t.gsFAILED;
+ e.Result = Params;
+ return;
+ }
+
+ /* Callback */
+ private void gsCompleted(object sender, RunWorkerCompletedEventArgs e)
+ {
+ gsParams_t Value;
+ gsEventArgs info;
+ gsParams_t Params;
+
+ try
+ {
+ Params = (gsParams_t)e.Result;
+ }
+ catch(System.Reflection.TargetInvocationException ee)
+ {
+ /* Something went VERY wrong with GS */
+ /* Following is to help debug these issues */
+ /* var inner = ee.InnerException;
+ var message = ee.Message;
+ var inner_message = inner.Message;
+ String bound = "\n************\n";
+ gsIOUpdateMain(this, bound, bound.Length);
+ gsIOUpdateMain(this, message, message.Length);
+ gsIOUpdateMain(this, bound, bound.Length);
+ gsIOUpdateMain(this, inner_message, inner_message.Length);
+ gsIOUpdateMain(this, bound, bound.Length);
+ var temp = inner.Source;
+ gsIOUpdateMain(this, bound, bound.Length);
+ gsIOUpdateMain(this, temp, temp.Length);
+ var method = inner.TargetSite;
+ gsIOUpdateMain(this, bound, bound.Length);
+ var method_name = method.Name;
+ gsIOUpdateMain(this, method_name, method_name.Length);
+ var stack = inner.StackTrace;
+ gsIOUpdateMain(this, bound, bound.Length);
+ gsIOUpdateMain(this, stack, stack.Length); */
+ String output = "Ghostscript DLL Invalid Access.";
+ gsDLLProblemMain(this, output);
+ return;
+ }
+
+ if (Params.task == GS_Task_t.PS_DISTILL)
+ m_worker.DoWork -= new DoWorkEventHandler(gsWork2);
+ else
+ m_worker.DoWork -= new DoWorkEventHandler(gsWork1);
+
+ if (e.Cancelled)
+ {
+ Value = new gsParams_t();
+ Value.result = GS_Result_t.gsCANCELLED;
+ info = new gsEventArgs(true, 100, Value);
+ }
+ else
+ {
+ Value = (gsParams_t)e.Result;
+ info = new gsEventArgs(true, 100, Value);
+ }
+ gsUpdateMain(this, info);
+ }
+
+ private void gsProgressChanged(object sender, ProgressChangedEventArgs e)
+ {
+ /* Callback with progress */
+ gsParams_t Value = new gsParams_t();
+ gsEventArgs info = new gsEventArgs(false, e.ProgressPercentage, Value);
+ gsUpdateMain(this, info);
+ }
+
+ public gsStatus DistillPS(String fileName, int resolution)
+ {
+ gsParams_t gsparams = new gsParams_t(); ;
+
+ gsparams.init_file = null;
+ gsparams.init_string = null;
+ gsparams.device = gsDevice_t.pdfwrite;
+ gsparams.devicename = null;
+ gsparams.outputfile = null;
+ gsparams.resolution = resolution;
+ gsparams.inputfile = fileName;
+ gsparams.num_pages = -1;
+ gsparams.task = GS_Task_t.PS_DISTILL;
+ gsparams.options = "";
+ gsparams.need_multi_page = false;
+ gsparams.pages = null;
+ gsparams.firstpage = -1;
+ gsparams.lastpage = -1;
+ gsparams.currpage = -1;
+ return RunGhostscript(gsparams);
+ }
+
+ public gsStatus CreateXPS(String fileName, int resolution, int num_pages)
+ {
+ gsParams_t gsparams = new gsParams_t();
+
+ gsparams.init_file = null;
+ gsparams.init_string = null;
+ gsparams.device = gsDevice_t.xpswrite;
+ gsparams.outputfile = null;
+ gsparams.resolution = resolution;
+ gsparams.inputfile = fileName;
+ gsparams.task = GS_Task_t.CREATE_XPS;
+ gsparams.num_pages = num_pages;
+ gsparams.options = "-dNOCACHE";
+ gsparams.need_multi_page = false;
+ gsparams.pages = null;
+ gsparams.firstpage = -1;
+ gsparams.lastpage = -1;
+ gsparams.currpage = -1;
+ return RunGhostscript(gsparams);
+ }
+
+ public gsStatus Convert(String fileName, String options, String device,
+ String outputFile, int num_pages, int resolution,
+ bool multi_page_needed, System.Collections.IList pages,
+ int firstpage, int lastpage, String init_file, String init_string)
+ {
+ gsParams_t gsparams = new gsParams_t();
+
+ gsparams.init_file = init_file;
+ gsparams.init_string = init_string;
+ gsparams.devicename = device;
+ gsparams.outputfile = outputFile;
+ gsparams.inputfile = fileName;
+ gsparams.task = GS_Task_t.SAVE_RESULT;
+ gsparams.num_pages = num_pages;
+ gsparams.options = options;
+ gsparams.resolution = resolution;
+ gsparams.need_multi_page = multi_page_needed;
+ gsparams.pages = pages;
+ gsparams.firstpage = firstpage;
+ gsparams.lastpage = lastpage;
+ gsparams.currpage = 1;
+ return RunGhostscript(gsparams);
+ }
+
+ public gsStatus GetStatus()
+ {
+ if (m_worker != null && m_worker.IsBusy)
+ return gsStatus.GS_BUSY;
+ else
+ return gsStatus.GS_READY;
+ }
+
+ public String GetVersion()
+ {
+ gsapi_revision_t vers;
+ vers.copyright = IntPtr.Zero;
+ vers.product = IntPtr.Zero;
+ vers.revision = 0;
+ vers.revisiondate = 0;
+ int size = System.Runtime.InteropServices.Marshal.SizeOf(vers);
+
+ if (tc_gsapi_revision(ref vers, size) == 0)
+ {
+ String product = Marshal.PtrToStringAnsi(vers.product);
+ String output;
+ int major = vers.revision / 100;
+ int minor = vers.revision - major * 100;
+ String versnum = major + "." + minor;
+ output = product + " " + versnum;
+ return output;
+ }
+ else
+ return null;
+ }
+
+ private gsStatus RunGhostscript(gsParams_t Params)
+ {
+ try
+ {
+ if (m_worker != null && m_worker.IsBusy)
+ {
+ m_worker.CancelAsync();
+ return gsStatus.GS_BUSY;
+ }
+ if (m_worker == null)
+ {
+ m_worker = new BackgroundWorker();
+ m_worker.WorkerReportsProgress = true;
+ m_worker.WorkerSupportsCancellation = true;
+ m_worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(gsCompleted);
+ m_worker.ProgressChanged += new ProgressChangedEventHandler(gsProgressChanged);
+ }
+
+ if (Params.task == GS_Task_t.PS_DISTILL)
+ m_worker.DoWork += new DoWorkEventHandler(gsWork2);
+ else
+ m_worker.DoWork += new DoWorkEventHandler(gsWork1);
+
+ m_params = Params;
+ m_worker.RunWorkerAsync(Params);
+ return gsStatus.GS_READY;
+ }
+ catch (OutOfMemoryException e)
+ {
+ Console.WriteLine("Memory allocation failed during gs rendering\n");
+ return gsStatus.GS_ERROR;
+ }
+ }
+
+ public void Cancel()
+ {
+ m_worker.CancelAsync();
+ }
+ }
+}