diff --git a/Examples/GhostscriptSharpExamples/Example1.cs b/Examples/GhostscriptSharpExamples/Example1.cs
new file mode 100644
index 0000000..4d1e2f5
--- /dev/null
+++ b/Examples/GhostscriptSharpExamples/Example1.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using GhostscriptSharp;
+using System.Runtime.InteropServices;
+
+namespace Examples
+{
+ ///
+ /// Example of using GS DLL as a ps2pdf converter.
+ ///
+ /// Port of Ghostscript Example code at http://pages.cs.wisc.edu/~ghost/doc/cvs/API.htm
+ class Example1
+ {
+ public const String KernelDllName = "kernel32.dll";
+ public const String GhostscriptDllDirectory = @"C:\Program Files\gs\gs8.71\bin";
+
+ [DllImport(KernelDllName, SetLastError = true)]
+ static extern int SetDllDirectory(string lpPathName);
+
+ static void Main(string[] args)
+ {
+ IntPtr minst;
+
+ int code, code1;
+ string[] gsargv = new string[10];
+ gsargv[0] = "ps2pdf"; /* actual value doesn't matter */
+ gsargv[1] = "-dNOPAUSE";
+ gsargv[2] = "-dBATCH";
+ gsargv[3] = "-dSAFER";
+ gsargv[4] = "-sDEVICE=pdfwrite";
+ gsargv[5] = "-sOutputFile=out.pdf";
+ gsargv[6] = "-c";
+ gsargv[7] = ".setpdfwrite";
+ gsargv[8] = "-f";
+ gsargv[9] = @"Files\input.ps";
+
+ SetDllDirectory(GhostscriptDllDirectory);
+
+ code = API.CreateAPIInstance(out minst, IntPtr.Zero);
+ if (code < 0)
+ {
+ System.Environment.Exit(1);
+ }
+ code = API.InitAPI(minst, gsargv.Length, gsargv);
+ code1 = API.ExitAPI(minst);
+ if ((code == 0) || (code == (int)API.GhostscriptErrorCode.e_Quit))
+ {
+ code = code1;
+ }
+
+ API.DeleteAPIInstance(minst);
+ if ((code == 0) || (code == (int)API.GhostscriptErrorCode.e_Quit))
+ {
+ System.Environment.Exit(0);
+ }
+ System.Environment.Exit(1);
+ }
+ }
+}
diff --git a/Examples/GhostscriptSharpExamples/Example2.cs b/Examples/GhostscriptSharpExamples/Example2.cs
new file mode 100644
index 0000000..552425b
--- /dev/null
+++ b/Examples/GhostscriptSharpExamples/Example2.cs
@@ -0,0 +1,107 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using GhostscriptSharp;
+using System.Runtime.InteropServices;
+
+namespace Examples
+{
+ ///
+ /// Similar to command line gs
+ ///
+ /// Port of Ghostscript Example code at http://pages.cs.wisc.edu/~ghost/doc/cvs/API.htm
+ class Example2
+ {
+ public const String KernelDllName = "kernel32.dll";
+ public const String GhostscriptDllDirectory = @"C:\Program Files\gs\gs8.71\bin";
+ public static String start_string = "systemdict /start get exec" + System.Environment.NewLine;
+
+ [DllImport(KernelDllName, SetLastError = true)]
+ static extern int SetDllDirectory(string lpPathName);
+
+ [DllImport(KernelDllName, EntryPoint = "RtlMoveMemory", SetLastError = true)]
+ static extern int CopyMemory(IntPtr dest, IntPtr source, Int64 count);
+
+ static void Main(string[] args)
+ {
+ #region StdIn Handler
+ StringBuilder sbInput = new StringBuilder();
+ // This is very slow, especially because Ghostscript asks for input 1 character at a time
+ API.StdinCallback stdin = (caller_handle, str, n) =>
+ {
+ if (n == 0)
+ {
+ str = IntPtr.Zero;
+ return 0;
+ }
+ if (sbInput.Length == 0)
+ {
+ sbInput.AppendLine(Console.ReadLine());
+ }
+ if (sbInput.Length > 0)
+ {
+ int len = (sbInput.Length < n) ? sbInput.Length : n;
+ byte[] b = ASCIIEncoding.ASCII.GetBytes(sbInput.ToString(0, len));
+ GCHandle cHandle = GCHandle.Alloc(b, GCHandleType.Pinned);
+ IntPtr cPtr = cHandle.AddrOfPinnedObject();
+ Int64 copyLen = (long)len;
+ CopyMemory(str, cPtr, copyLen);
+ cPtr = IntPtr.Zero;
+ cHandle.Free();
+ sbInput.Remove(0, len);
+ return len;
+ }
+ return 0;
+ };
+ #endregion
+ #region StdOut Handler
+ API.StdoutCallback stdout = (caller_handle, buf, len) =>
+ {
+ Console.Write(buf.Substring(0, len));
+ return len;
+ };
+ #endregion
+ #region StdErr Handler
+ API.StdoutCallback stderr = (caller_handle, buf, len) =>
+ {
+ Console.Error.Write(buf.Substring(0, len));
+ return len;
+ };
+ #endregion
+
+ string[] gsargv = new string[args.Length + 1];
+ gsargv[0] = "GhostscriptSharp"; /* actual value doesn't matter */
+ Array.Copy(args, 0, gsargv, 1, args.Length);
+
+ IntPtr minst;
+ int code, code1;
+ int exit_code;
+
+ SetDllDirectory(GhostscriptDllDirectory);
+
+ code = API.CreateAPIInstance(out minst, IntPtr.Zero);
+ if (code < 0)
+ {
+ System.Environment.Exit(1);
+ }
+ API.Set_Stdio(minst, stdin, stdout, stderr);
+ code = API.InitAPI(minst, gsargv.Length, gsargv);
+ if (code == 0)
+ {
+ API.RunString(minst, start_string, 0, out exit_code);
+ }
+ code1 = API.ExitAPI(minst);
+ if ((code == 0) || (code == (int)API.GhostscriptErrorCode.e_Quit))
+ {
+ code = code1;
+ }
+
+ API.DeleteAPIInstance(minst);
+ if ((code == 0) || (code == (int)API.GhostscriptErrorCode.e_Quit))
+ {
+ System.Environment.Exit(0);
+ }
+ System.Environment.Exit(1);
+ }
+ }
+}
diff --git a/Examples/GhostscriptSharpExamples/Example3.cs b/Examples/GhostscriptSharpExamples/Example3.cs
new file mode 100644
index 0000000..699003d
--- /dev/null
+++ b/Examples/GhostscriptSharpExamples/Example3.cs
@@ -0,0 +1,72 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using GhostscriptSharp;
+using System.Runtime.InteropServices;
+
+namespace Examples
+{
+ ///
+ /// Shows how to feed GhostscriptSharp piecemeal
+ ///
+ /// When feeding Ghostscript piecemeal buffers, one can use the normal operators to configure things and invoke library routines. The following example
+ /// would cause Ghostscript to open and process the file named "example.pdf" as if it had been passed as an argument to gsapi_init_with_args().
+ /// code = gsapi_run_string(minst, "(example.pdf) .runlibfile", 0, &exit_code);
+ /// Port of Ghostscript Example code at http://pages.cs.wisc.edu/~ghost/doc/cvs/API.htm
+ class Example3
+ {
+ public const String KernelDllName = "kernel32.dll";
+ public const String GhostscriptDllDirectory = @"C:\Program Files\gs\gs8.71\bin";
+ public static String command = "1 2 add == flush" + System.Environment.NewLine;
+
+ [DllImport(KernelDllName, SetLastError = true)]
+ static extern int SetDllDirectory(string lpPathName);
+
+ [DllImport(KernelDllName, EntryPoint = "RtlMoveMemory", SetLastError = true)]
+ static extern int CopyMemory(IntPtr dest, IntPtr source, Int64 count);
+
+ static void Main(string[] args)
+ {
+ string[] gsargv = new string[args.Length + 1];
+ gsargv[0] = "GhostscriptSharp"; /* actual value doesn't matter */
+ Array.Copy(args, 0, gsargv, 1, args.Length);
+
+ IntPtr minst;
+ int code, code1;
+ int exit_code;
+
+ SetDllDirectory(GhostscriptDllDirectory);
+
+ code = API.CreateAPIInstance(out minst, IntPtr.Zero);
+ if (code < 0)
+ {
+ System.Environment.Exit(1);
+ }
+ code = API.InitAPI(minst, gsargv.Length, gsargv);
+ if (code == 0)
+ {
+ API.RunStringBegin(minst, 0, out exit_code);
+ API.RunStringContinue(minst, command, Convert.ToUInt16(command.Length), 0, out exit_code);
+ API.RunStringContinue(minst, "qu", 2u, 0, out exit_code);
+ API.RunStringContinue(minst, "it", 2u, 0, out exit_code);
+ API.RunStringEnd(minst, 0, out exit_code);
+ }
+ code1 = API.ExitAPI(minst);
+ if ((code == 0) || (code == (int)API.GhostscriptErrorCode.e_Quit))
+ {
+ code = code1;
+ }
+
+ API.DeleteAPIInstance(minst);
+ int returnValue = 1;
+ if ((code == 0) || (code == (int)API.GhostscriptErrorCode.e_Quit))
+ {
+ returnValue = 0;
+ }
+ Console.WriteLine("Example3 completed with exit value {0}", returnValue);
+ Console.WriteLine("Press any key to exit.");
+ Console.ReadKey();
+ System.Environment.Exit(returnValue);
+ }
+ }
+}
diff --git a/Examples/GhostscriptSharpExamples/Files/input.ps b/Examples/GhostscriptSharpExamples/Files/input.ps
new file mode 100644
index 0000000..5ea6b91
Binary files /dev/null and b/Examples/GhostscriptSharpExamples/Files/input.ps differ
diff --git a/Examples/GhostscriptSharpExamples/GhostscriptSharpExamples.csproj b/Examples/GhostscriptSharpExamples/GhostscriptSharpExamples.csproj
new file mode 100644
index 0000000..44046c9
--- /dev/null
+++ b/Examples/GhostscriptSharpExamples/GhostscriptSharpExamples.csproj
@@ -0,0 +1,64 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {6B6799EB-0AF5-4AED-8164-A7DA275EFC9D}
+ Exe
+ Properties
+ Examples
+ Examples
+ v2.0
+ 512
+ Examples.Example1
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {56605627-E6FA-4F47-9440-FB877CEA5C84}
+ GhostscriptSharp
+
+
+
+
+ PreserveNewest
+
+
+
+
+
\ No newline at end of file
diff --git a/Examples/GhostscriptSharpExamples/Properties/AssemblyInfo.cs b/Examples/GhostscriptSharpExamples/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..5eee138
--- /dev/null
+++ b/Examples/GhostscriptSharpExamples/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Examples")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Examples")]
+[assembly: AssemblyCopyright("Copyright © 2011")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("289eb845-b037-437a-98d9-1fe7eb6e6791")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/GhostScriptSharp/API.cs b/GhostScriptSharp/API.cs
new file mode 100644
index 0000000..09a55eb
--- /dev/null
+++ b/GhostScriptSharp/API.cs
@@ -0,0 +1,236 @@
+/* ================================= MIT LICENSE =================================
+ *
+ * Copyright (c) 2009 Matthew Ephraim
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ================================= MIT LICENSE ================================= */
+
+/* ===============================================================================
+ *
+ * This code adapted from Matthew Ephraim's GhostscriptSharp February 2011
+ *
+ * https://github.com/mephraim/ghostscriptsharp/blob/master/GhostScriptSharp/GhostscriptSharp.cs
+ *
+ * =============================================================================== */
+
+using System;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace GhostscriptSharp
+{
+ public class API
+ {
+ #region Ghostscript Error Codes
+ public enum GhostscriptErrorCode :int // aka Int32
+ {
+ NoErrors = 0,
+ e_unknownerror = -1,
+ e_dictfull = -2,
+ e_dictstackoverflow = -3,
+ e_dictstackunderflow = -4,
+ e_execstackoverflow = -5,
+ e_interrupt = -6,
+ e_invalidaccess = -7,
+ e_invalidexit = -8,
+ e_invalidfileaccess = -9,
+ e_invalidfont = -10,
+ e_invalidrestore = -11,
+ e_ioerror = -12,
+ e_limitcheck = -13,
+ e_nocurrentpoint = -14,
+ e_rangecheck = -15,
+ e_stackoverflow = -16,
+ e_stackunderflow = -17,
+ e_syntaxerror = -18,
+ e_timeout = -19,
+ e_typecheck = -20,
+ e_undefined = -21,
+ e_undefinedfilename = -22,
+ e_undefinedresult = -23,
+ e_unmatchedmark = -24,
+ e_VMerror = -25,
+ // Level 1 Errors
+ e_configurationerror = -26,
+ e_undefinedresource = -27,
+ e_unregistered = -28,
+ // Level 2 Errors
+ e_invalidcontext = -29,
+ e_invalidid = -30,
+ // Level 3 Errors
+
+ e_Fatal = -100,
+ e_Quit = -101,
+ e_NeedInput = -106,
+ e_Info = -110,
+ UNKNOWN = -9999
+ };
+ #endregion
+
+ #region Constants
+
+ public const String GhostscriptDllName = "gsdll32.dll";
+
+ #endregion
+
+ #region Hooks into Ghostscript DLL
+ ///
+ /// Returns the revision number and strings of the Ghostscript interpreter library.
+ ///
+ ///
+ ///
+ /// 0 for success, something else for error
+ [DllImport(GhostscriptDllName, EntryPoint = "gsapi_revision")]
+ public static extern Int32 GetRevision(out GS_Revision pr, Int32 len);
+
+ ///
+ /// Create a new instance of Ghostscript. The Ghostscript API supports only one instance.
+ ///
+ /// Instance pointer, provided to most other API calls
+ /// Will be provided to callback functions
+ ///
+ [DllImport(GhostscriptDllName, EntryPoint = "gsapi_new_instance")]
+ public static extern Int32 CreateAPIInstance(out IntPtr pinstance, IntPtr caller_handle);
+
+ ///
+ /// Destroy an instance of Ghostscript. If Ghostscript has been initialized with InitAPI, you must call ExitAPI before this.
+ ///
+ /// The instance given by CreateAPIInstance
+ [DllImport(GhostscriptDllName, EntryPoint = "gsapi_delete_instance")]
+ public static extern void DeleteAPIInstance(IntPtr instance);
+
+ ///
+ /// Set the callback functions for stdio
+ ///
+ /// The instance given by CreateAPIInstance
+ /// The callback for stdin reads. Should return the number of characters read, 0 for EOF, or -1 for error.
+ /// The callback for stdout writes. Should return the number of characters written.
+ /// The callback for stderr writes. Should return the number of characters written.
+ ///
+ [DllImport(GhostscriptDllName, EntryPoint = "gsapi_set_stdio")]
+ public static extern Int32 Set_Stdio(IntPtr instance, StdinCallback stdin, StdoutCallback stdout, StdoutCallback stderr);
+
+ ///
+ /// Initialize and run the interpreter with arguments. See Ghostscript API for details on arguments.
+ ///
+ /// The instance given by CreateAPIInstance
+ /// The number of arguments supplied
+ /// Array of arguments supplied. Argv[0] is ignored (as in C programs)
+ ///
+ [DllImport(GhostscriptDllName, EntryPoint = "gsapi_init_with_args")]
+ public static extern Int32 InitAPI(IntPtr instance, Int32 argc, string[] argv);
+
+ ///
+ /// After initializing the interpreter, clients may pass it strings to be interpreted. To pass input in arbitrary chunks, first call RunStringBegin, then RunStringContinue as many times as desired, stopping if it returns anything other than e_NeedInput. Then call RunStringEnd to indicate end of file.
+ ///
+ /// The instance given by CreateAPIInstance
+ /// 0 if errors should be handled normally, if set negative, the function will directly return error codes bypassing the interpreted language
+ /// Set to the exit code for the interpreted in case of quit or fatal error
+ /// Error code corresponding to GhostscriptErrorCode
+ [DllImport(GhostscriptDllName, EntryPoint = "gsapi_run_string_begin")]
+ public static extern Int32 RunStringBegin(IntPtr instance, Int32 user_errors, out Int32 pexit_code);
+
+ ///
+ /// After initializing the interpreter, clients may pass it strings to be interpreted. To pass input in arbitrary chunks, first call RunStringBegin, then RunStringContinue as many times as desired, stopping if it returns anything other than e_NeedInput. Then call RunStringEnd to indicate end of file.
+ ///
+ /// The instance given by CreateAPIInstance
+ /// The string to interpret
+ /// The length of the string to interpret. This must be no greater than 65535
+ /// 0 if errors should be handled normally, if set negative, the function will directly return error codes bypassing the interpreted language
+ /// Set to the exit code for the interpreted in case of quit or fatal error
+ /// Error code corresponding to GhostscriptErrorCode, or e_NeedInput when ready for another string
+ [DllImport(GhostscriptDllName, EntryPoint = "gsapi_run_string_continue")]
+ public static extern Int32 RunStringContinue(IntPtr instance, String str, UInt32 length, Int32 user_errors, out Int32 pexit_code);
+
+ ///
+ /// After initializing the interpreter, clients may pass it strings to be interpreted. To pass input in arbitrary chunks, first call RunStringBegin, then RunStringContinue as many times as desired, stopping if it returns anything other than e_NeedInput. Then call RunStringEnd to indicate end of file.
+ ///
+ /// The instance given by CreateAPIInstance
+ /// 0 if errors should be handled normally, if set negative, the function will directly return error codes bypassing the interpreted language
+ /// Set to the exit code for the interpreted in case of quit or fatal error
+ /// Error code corresponding to GhostscriptErrorCode
+ [DllImport(GhostscriptDllName, EntryPoint = "gsapi_run_string_end")]
+ public static extern Int32 RunStringEnd(IntPtr instance, Int32 user_errors, out Int32 pexit_code);
+
+ ///
+ /// After initializing the interpreter, clients may pass it strings to be interpreted. To pass input in arbitrary chunks, first call RunStringBegin, then RunStringContinue as many times as desired, stopping if it returns anything other than e_NeedInput. Then call RunStringEnd to indicate end of file.
+ ///
+ /// The instance given by CreateAPIInstance
+ /// The string to interpret
+ /// The length of the string to interpret. This must be no greater than 65535
+ /// 0 if errors should be handled normally, if set negative, the function will directly return error codes bypassing the interpreted language
+ /// Set to the exit code for the interpreted in case of quit or fatal error
+ /// Error code corresponding to GhostscriptErrorCode
+ [DllImport(GhostscriptDllName, EntryPoint = "gsapi_run_string_with_length")]
+ public static extern Int32 RunStringWithLength(IntPtr instance, String str, UInt32 length, Int32 user_errors, out Int32 pexit_code);
+
+ ///
+ /// After initializing the interpreter, clients may pass it strings to be interpreted. To pass input in arbitrary chunks, first call RunStringBegin, then RunStringContinue as many times as desired, stopping if it returns anything other than e_NeedInput. Then call RunStringEnd to indicate end of file.
+ ///
+ /// The instance given by CreateAPIInstance
+ /// The string to interpret. There is a 65535 charactere limit
+ /// 0 if errors should be handled normally, if set negative, the function will directly return error codes bypassing the interpreted language
+ /// Set to the exit code for the interpreted in case of quit or fatal error
+ /// Error code corresponding to GhostscriptErrorCode
+ [DllImport(GhostscriptDllName, EntryPoint = "gsapi_run_string")]
+ public static extern Int32 RunString(IntPtr instance, String str, Int32 user_errors, out Int32 pexit_code);
+
+ ///
+ /// After initializing the interpreter, clients may pass it strings to be interpreted. To pass input in arbitrary chunks, first call RunStringBegin, then RunStringContinue as many times as desired, stopping if it returns anything other than e_NeedInput. Then call RunStringEnd to indicate end of file.
+ ///
+ /// The instance given by CreateAPIInstance
+ /// File name of the file to interpret
+ /// 0 if errors should be handled normally, if set negative, the function will directly return error codes bypassing the interpreted language
+ /// Set to the exit code for the interpreted in case of quit or fatal error
+ /// Error code corresponding to GhostscriptErrorCode
+ [DllImport(GhostscriptDllName, EntryPoint = "gsapi_run_file")]
+ public static extern Int32 RunFile(IntPtr instance, String file_name, Int32 user_errors, out Int32 pexit_code);
+
+ ///
+ /// Exit the interpreter. This must be called if InitAPI has been called, just before calling DeleteAPIInstance
+ ///
+ /// The instance given by CreateAPIInstance
+ ///
+ [DllImport(GhostscriptDllName, EntryPoint = "gsapi_exit")]
+ public static extern Int32 ExitAPI(IntPtr instance);
+ #endregion
+
+ #region Handle stdio
+
+ ///
+ /// Callback used by Ghostscript API when reading from stdin
+ ///
+ /// The caller_handle supplied to CreateAPIInstance
+ /// The value to provide to Ghostscript from stdin
+ /// The number of characters provided
+ /// 0 for EOF, or -1 for error, number of characters provided for success
+ public delegate Int32 StdinCallback(IntPtr caller_handle, IntPtr buf, Int32 len);
+
+ ///
+ /// Callback used by Ghostscript API when writing to stdout or stderr
+ ///
+ /// The caller_handle supplied to CreateAPIInstance
+ /// The string output generated by Ghostscript. Note that the buf may be longer than the provided output, use buf.ToString(0, len)
+ /// The length of the generated output
+ ///
+ public delegate Int32 StdoutCallback(IntPtr caller_handle, String buf, Int32 len);
+
+ #endregion
+
+ public const Int32 GS_Revision_Size_Bytes = 16;
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct GS_Revision
+ {
+ public string strProduct;
+ public string strCopyright;
+ public Int32 intRevision;
+ public Int32 intRevisionDate;
+ }
+ }
+}
diff --git a/GhostScriptSharp/EventArgs.cs b/GhostScriptSharp/EventArgs.cs
new file mode 100644
index 0000000..7e7c16c
--- /dev/null
+++ b/GhostScriptSharp/EventArgs.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace GhostscriptSharp
+{
+ public class StdOutputEventArgs : EventArgs
+ {
+ protected readonly String _output;
+ public String Output { get { return _output; } }
+
+ public StdOutputEventArgs(String output)
+ : base()
+ {
+ _output = output;
+ }
+ }
+}
diff --git a/GhostScriptSharp/GhostscriptException.cs b/GhostScriptSharp/GhostscriptException.cs
new file mode 100644
index 0000000..9aac5f6
--- /dev/null
+++ b/GhostScriptSharp/GhostscriptException.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Collections.Generic;
+
+using System.Text;
+using System.Runtime.InteropServices;
+
+namespace GhostscriptSharp
+{
+ public class GhostscriptException : ExternalException
+ {
+ protected readonly API.GhostscriptErrorCode gsErrorCode;
+ public API.GhostscriptErrorCode GsErrorCode
+ {
+ get { return gsErrorCode; }
+ }
+
+ public GhostscriptException()
+ : base()
+ {
+ }
+
+ public GhostscriptException(string message)
+ : base(message)
+ {
+ gsErrorCode = API.GhostscriptErrorCode.UNKNOWN;
+ }
+
+ public GhostscriptException(string message, Exception inner)
+ : base(message, inner)
+ {
+ }
+
+ public GhostscriptException(string message, int errorCode)
+ : base(message, errorCode)
+ {
+ //ex.ErrorCode
+ if (Enum.IsDefined(typeof(API.GhostscriptErrorCode), errorCode))
+ {
+ gsErrorCode = (API.GhostscriptErrorCode)errorCode;
+ }
+ else
+ {
+ gsErrorCode = API.GhostscriptErrorCode.UNKNOWN;
+ }
+ }
+ }
+}
diff --git a/GhostScriptSharp/GhostscriptManager.cs b/GhostScriptSharp/GhostscriptManager.cs
new file mode 100644
index 0000000..257f7e0
--- /dev/null
+++ b/GhostScriptSharp/GhostscriptManager.cs
@@ -0,0 +1,344 @@
+using System;
+using System.Collections.Generic;
+
+using System.Text;
+using System.Runtime.InteropServices;
+using System.IO;
+
+namespace GhostscriptSharp
+{
+ public class GhostscriptManager : IDisposable
+ {
+ #region Constants
+
+ public const String KernelDllName = "kernel32.dll";
+
+ #endregion
+
+ #region Hooks into the kernel32 DLL (for loading unmanaged code)
+ [DllImport(KernelDllName, SetLastError = true)]
+ static extern IntPtr LoadLibrary(string lpFileName);
+
+ [DllImport(KernelDllName, SetLastError = true)]
+ static extern int FreeLibrary(IntPtr hModule);
+
+ [DllImport(KernelDllName, SetLastError = true)]
+ static extern int SetDllDirectory(string lpPathName);
+ #endregion
+
+ #region Globals
+
+ protected static object resourceLock = new object();
+
+ protected static String[] defaultArgs;
+ protected static String[] DefaultArgs
+ {
+ get
+ {
+ if (defaultArgs == null)
+ {
+ defaultArgs = new String[] {
+ "-dPARANOIDSAFER", // Run in safe mode
+ "-dBATCH", // Exit after completing commands
+ "-dNOPAUSE", // Do not pause for each page
+ "-dNOPROMPT" // Don't prompt for user input
+ };
+ }
+ return defaultArgs;
+ }
+ }
+
+ protected static String ghostscriptLibraryPath;
+ public static String GhostscriptLibraryPath
+ {
+ get { return ghostscriptLibraryPath == null ? String.Empty : ghostscriptLibraryPath; }
+ set { ghostscriptLibraryPath = value; }
+ }
+
+ protected static GhostscriptManager _instance;
+ public static GhostscriptManager GetInstance()
+ {
+ lock (resourceLock)
+ {
+ if (_instance == null)
+ {
+ _instance = new GhostscriptManager();
+ }
+ return _instance;
+ }
+ }
+
+ #endregion
+
+ protected IntPtr libraryHandle;
+
+ protected bool revisionInfoLoaded;
+ protected String productName;
+ protected String copyright;
+ protected Int32 revision;
+ protected Int32 revisionDate;
+
+ protected GhostscriptSettings settings;
+ public GhostscriptSettings Settings
+ {
+ get { return settings; }
+ }
+
+ protected GhostscriptManager()
+ {
+ revisionInfoLoaded = false;
+ libraryHandle = IntPtr.Zero;
+
+ LoadGhostscriptLibrary();
+
+ this.settings = new GhostscriptSettings();
+ }
+
+ protected void LoadGhostscriptLibrary()
+ {
+ SetDllDirectory(GhostscriptLibraryPath);
+ libraryHandle = LoadLibrary(API.GhostscriptDllName);
+ }
+
+ protected void UnloadGhostscriptLibrary()
+ {
+ if (libraryHandle != IntPtr.Zero)
+ {
+ FreeLibrary(libraryHandle);
+ libraryHandle = IntPtr.Zero;
+ }
+ }
+
+ ///
+ /// Run the Ghostscript interpreter providing the output file and input file(s)
+ ///
+ /// The path to create the output file. Put '%d' the path to create multiple numbered files, one for each page
+ /// One or more input files
+ public void DoConvert(String outputPath, params String[] inputPaths)
+ {
+ IntPtr gsInstancePtr;
+ lock (resourceLock)
+ {
+ API.CreateAPIInstance(out gsInstancePtr, IntPtr.Zero);
+ try
+ {
+ if (StdOut != null || StdErr != null)
+ {
+ API.StdoutCallback stdout;
+ #region Set StdOut
+ if (StdOut != null)
+ {
+ stdout = (caller_handle, buf, len) =>
+ {
+ StdOut(this, new StdOutputEventArgs(buf.Substring(0, len)));
+ return len;
+ };
+ }
+ else
+ {
+ stdout = EmptyStdoutCallback;
+ }
+ #endregion
+ API.StdoutCallback stderr;
+ #region Set StdErr
+ if (StdErr != null)
+ {
+ stderr = (caller_handle, buf, len) =>
+ {
+ StdOut(this, new StdOutputEventArgs(buf.Substring(0, len)));
+ return len;
+ };
+ }
+ else
+ {
+ stderr = EmptyStdoutCallback;
+ }
+ #endregion
+ API.Set_Stdio(gsInstancePtr, EmptyStdinCallback, stdout, stderr);
+ }
+ String[] args = null;
+ {
+ List lArgs = new List();
+ lArgs.Add("GhostscriptSharp"); // First arg is ignored, corresponds to argv[0]
+ lArgs.AddRange(GhostscriptManager.DefaultArgs);
+ lArgs.AddRange(this.Settings.GetGhostscriptArgs());
+ lArgs.Add(String.Format("-sOutputFile={0}", outputPath));
+ lArgs.AddRange(inputPaths);
+ args = lArgs.ToArray();
+ }
+ int result = API.InitAPI(gsInstancePtr, args.Length, args);
+ if (result < 0)
+ {
+ throw new GhostscriptException("Ghostscript conversion error", result);
+ }
+ }
+ finally
+ {
+ API.ExitAPI(gsInstancePtr);
+ API.DeleteAPIInstance(gsInstancePtr);
+ }
+ }
+ }
+
+ #region Revision Info Properties
+
+ ///
+ /// Name of the product obtained from the Ghostscript DLL e.g. "GPL Ghostscript"
+ ///
+ public String ProductName
+ {
+ get
+ {
+ if (!revisionInfoLoaded)
+ {
+ LoadRevisionInfo();
+ }
+ return productName;
+ }
+ }
+
+ ///
+ /// Copyright Information obtained from the Ghostscript DLL
+ ///
+ public String Copyright
+ {
+ get
+ {
+ if (!revisionInfoLoaded)
+ {
+ LoadRevisionInfo();
+ }
+ return copyright;
+ }
+ }
+
+ ///
+ /// Revision Number of the Ghostscript DLL e.g. 871 for v8.71
+ ///
+ public Int32 Revision
+ {
+ get
+ {
+ if (!revisionInfoLoaded)
+ {
+ LoadRevisionInfo();
+ }
+ return revision;
+ }
+ }
+
+ ///
+ /// Revision Date of the Ghostscript DLL in the format yyyyMMdd
+ ///
+ public Int32 RevisionDate
+ {
+ get
+ {
+ if (!revisionInfoLoaded)
+ {
+ LoadRevisionInfo();
+ }
+ return revisionDate;
+ }
+ }
+
+ ///
+ /// Get Ghostscript Library revision info
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected void LoadRevisionInfo()
+ {
+ API.GS_Revision rev;
+
+ API.GetRevision(out rev, API.GS_Revision_Size_Bytes);
+ this.productName = rev.strProduct;
+ this.copyright = rev.strCopyright;
+ this.revision = rev.intRevision;
+ this.revisionDate = rev.intRevisionDate;
+ this.revisionInfoLoaded = true;
+ }
+
+ #endregion
+
+ #region stdin, stdout, stderr handlers
+
+ //public delegate void StdinReader(StringBuilder input);
+ public delegate void StdOutputHandler(object sender, StdOutputEventArgs args);
+
+ //public event StdinReader StdIn;
+ public event StdOutputHandler StdOut;
+ public event StdOutputHandler StdErr;
+
+ ///
+ /// "Default" implementation of StdinCallback - gives Ghostscript EOF whenever it requests input
+ ///
+ ///
+ ///
+ ///
+ /// 0 (EOF) whenever GS requests input
+ protected API.StdinCallback EmptyStdinCallback = new API.StdinCallback(delegate(IntPtr caller_handle, IntPtr buf, Int32 len)
+ {
+ return 0; // return EOF always
+ });
+ //protected API.StdinCallback EmptyStdinCallback = (caller_handle, buf, len) =>
+ //{
+ // return 0; // return EOF always
+ //};
+
+ ///
+ /// "Default" implementation of StdoutCallback - does nothing with output, returns all characters handled
+ ///
+ ///
+ ///
+ ///
+ /// len (the number of characters handled) whenever GS outputs anything
+ protected API.StdoutCallback EmptyStdoutCallback = (caller_handle, buf, len) =>
+ {
+ return len; // return all bytes handled
+ };
+
+ #endregion
+
+ #region IDisposable Members
+
+ public void Dispose()
+ {
+ UnloadGhostscriptLibrary();
+ }
+
+ #endregion
+
+ #region Convenience Methods
+
+ ///
+ /// Convert a postscript file to a pdf
+ ///
+ /// The path to create the output file. Put '%d' the path to create multiple numbered files, one for each page
+ /// One or more input files
+ public static void PsToPdf(String outputPath, params String[] inputPaths)
+ {
+ GhostscriptManager gsm = GhostscriptManager.GetInstance();
+ bool libraryLoaded = (gsm.libraryHandle != IntPtr.Zero);
+ if (!libraryLoaded)
+ {
+ gsm.LoadGhostscriptLibrary();
+ }
+ GhostscriptSettings oldSettings = gsm.Settings;
+ gsm.settings = new GhostscriptSettings();
+ gsm.Settings.Device = GhostscriptSharp.Settings.GhostscriptDevices.pdfwrite;
+ gsm.Settings.Page.AllPages = true;
+ gsm.Settings.Quiet = true;
+ gsm.DoConvert(outputPath, inputPaths);
+ if (!libraryLoaded)
+ {
+ gsm.UnloadGhostscriptLibrary();
+ }
+ gsm.settings = oldSettings;
+ }
+
+ #endregion
+ }
+}
diff --git a/GhostScriptSharp/GhostscriptSharp.cs b/GhostScriptSharp/GhostscriptSharp.cs
index 581080b..7a8f9c0 100644
--- a/GhostScriptSharp/GhostscriptSharp.cs
+++ b/GhostScriptSharp/GhostscriptSharp.cs
@@ -1,28 +1,36 @@
+/* ================================= MIT LICENSE =================================
+ *
+ * Copyright (c) 2009 Matthew Ephraim
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ================================= MIT LICENSE ================================= */
+
+/* ===============================================================================
+ *
+ * This code taken from Matthew Ephraim's GhostscriptSharp February 2011
+ *
+ * https://github.com/mephraim/ghostscriptsharp/blob/master/GhostScriptSharp/GhostscriptSharp.cs
+ *
+ * =============================================================================== */
+
using System;
+using System.Collections.Generic;
+
using System.Text;
using System.Runtime.InteropServices;
namespace GhostscriptSharp
{
- ///
- /// Wraps the Ghostscript API with a C# interface
- ///
- public class GhostscriptWrapper
- {
- #region Hooks into Ghostscript DLL
- [DllImport("gsdll32.dll", EntryPoint = "gsapi_new_instance")]
- private static extern int CreateAPIInstance(out IntPtr pinstance, IntPtr caller_handle);
-
- [DllImport("gsdll32.dll", EntryPoint = "gsapi_init_with_args")]
- private static extern int InitAPI(IntPtr instance, int argc, string[] argv);
-
- [DllImport("gsdll32.dll", EntryPoint = "gsapi_exit")]
- private static extern int ExitAPI(IntPtr instance);
-
- [DllImport("gsdll32.dll", EntryPoint = "gsapi_delete_instance")]
- private static extern void DeleteAPIInstance(IntPtr instance);
- #endregion
-
+ ///
+ /// Wraps the Ghostscript API with a C# interface
+ ///
+ public class GhostscriptWrapper
+ {
#region Globals
private static readonly string[] ARGS = new string[] {
@@ -84,10 +92,10 @@ private static void CallAPI(string[] args)
IntPtr gsInstancePtr;
lock (resourceLock)
{
- CreateAPIInstance(out gsInstancePtr, IntPtr.Zero);
+ API.CreateAPIInstance(out gsInstancePtr, IntPtr.Zero);
try
{
- int result = InitAPI(gsInstancePtr, args.Length, args);
+ int result = API.InitAPI(gsInstancePtr, args.Length, args);
if (result < 0)
{
@@ -111,8 +119,8 @@ private static void CallAPI(string[] args)
///
private static void Cleanup(IntPtr gsInstancePtr)
{
- ExitAPI(gsInstancePtr);
- DeleteAPIInstance(gsInstancePtr);
+ API.ExitAPI(gsInstancePtr);
+ API.DeleteAPIInstance(gsInstancePtr);
}
///
@@ -136,7 +144,7 @@ private static string[] GetArgs(string inputPath,
s.Page.Start = firstPage;
s.Page.End = lastPage;
s.Resolution = new System.Drawing.Size(width, height);
-
+
Settings.GhostscriptPageSize pageSize = new Settings.GhostscriptPageSize();
pageSize.Native = GhostscriptSharp.Settings.GhostscriptPageSizes.a7;
s.Size = pageSize;
@@ -217,257 +225,4 @@ private static string[] GetArgs(string inputPath,
}
}
-
- ///
- /// Ghostscript settings
- ///
- public class GhostscriptSettings
- {
- private Settings.GhostscriptDevices _device;
- private Settings.GhostscriptPages _pages = new Settings.GhostscriptPages();
- private System.Drawing.Size _resolution;
- private Settings.GhostscriptPageSize _size = new Settings.GhostscriptPageSize();
-
- public Settings.GhostscriptDevices Device
- {
- get { return this._device; }
- set { this._device = value; }
- }
-
- public Settings.GhostscriptPages Page
- {
- get { return this._pages; }
- set { this._pages = value; }
- }
-
- public System.Drawing.Size Resolution
- {
- get { return this._resolution; }
- set { this._resolution = value; }
- }
-
- public Settings.GhostscriptPageSize Size
- {
- get { return this._size; }
- set { this._size = value; }
- }
- }
}
-
-namespace GhostscriptSharp.Settings
-{
- ///
- /// Which pages to output
- ///
- public class GhostscriptPages
- {
- private bool _allPages = true;
- private int _start;
- private int _end;
-
- ///
- /// Output all pages avaialble in document
- ///
- public bool AllPages
- {
- set
- {
- this._start = -1;
- this._end = -1;
- this._allPages = true;
- }
- get
- {
- return this._allPages;
- }
- }
-
- ///
- /// Start output at this page (1 for page 1)
- ///
- public int Start
- {
- set
- {
- this._allPages = false;
- this._start = value;
- }
- get
- {
- return this._start;
- }
- }
-
- ///
- /// Page to stop output at
- ///
- public int End
- {
- set
- {
- this._allPages = false;
- this._end = value;
- }
- get
- {
- return this._end;
- }
- }
- }
-
- ///
- /// Output devices for GhostScript
- ///
- public enum GhostscriptDevices
- {
- UNDEFINED,
- png16m,
- pnggray,
- png256,
- png16,
- pngmono,
- pngalpha,
- jpeg,
- jpeggray,
- tiffgray,
- tiff12nc,
- tiff24nc,
- tiff32nc,
- tiffsep,
- tiffcrle,
- tiffg3,
- tiffg32d,
- tiffg4,
- tifflzw,
- tiffpack,
- faxg3,
- faxg32d,
- faxg4,
- bmpmono,
- bmpgray,
- bmpsep1,
- bmpsep8,
- bmp16,
- bmp256,
- bmp16m,
- bmp32b,
- pcxmono,
- pcxgray,
- pcx16,
- pcx256,
- pcx24b,
- pcxcmyk,
- psdcmyk,
- psdrgb,
- pdfwrite,
- pswrite,
- epswrite,
- pxlmono,
- pxlcolor
- }
-
- ///
- /// Output document physical dimensions
- ///
- public class GhostscriptPageSize
- {
- private GhostscriptPageSizes _fixed;
- private System.Drawing.Size _manual;
-
- ///
- /// Custom document size
- ///
- public System.Drawing.Size Manual
- {
- set
- {
- this._fixed = GhostscriptPageSizes.UNDEFINED;
- this._manual = value;
- }
- get
- {
- return this._manual;
- }
- }
-
- ///
- /// Standard paper size
- ///
- public GhostscriptPageSizes Native
- {
- set
- {
- this._fixed = value;
- this._manual = new System.Drawing.Size(0, 0);
- }
- get
- {
- return this._fixed;
- }
- }
-
- }
-
- ///
- /// Native page sizes
- ///
- ///
- /// Missing 11x17 as enums can't start with a number, and I can't be bothered
- /// to add in logic to handle it - if you need it, do it yourself.
- ///
- public enum GhostscriptPageSizes
- {
- UNDEFINED,
- ledger,
- legal,
- letter,
- lettersmall,
- archE,
- archD,
- archC,
- archB,
- archA,
- a0,
- a1,
- a2,
- a3,
- a4,
- a4small,
- a5,
- a6,
- a7,
- a8,
- a9,
- a10,
- isob0,
- isob1,
- isob2,
- isob3,
- isob4,
- isob5,
- isob6,
- c0,
- c1,
- c2,
- c3,
- c4,
- c5,
- c6,
- jisb0,
- jisb1,
- jisb2,
- jisb3,
- jisb4,
- jisb5,
- jisb6,
- b0,
- b1,
- b2,
- b3,
- b4,
- b5,
- flsa,
- flse,
- halfletter
- }
-}
\ No newline at end of file
diff --git a/GhostScriptSharp/GhostscriptSharp.csproj b/GhostScriptSharp/GhostscriptSharp.csproj
index b58c8a0..a6b9e33 100644
--- a/GhostScriptSharp/GhostscriptSharp.csproj
+++ b/GhostScriptSharp/GhostscriptSharp.csproj
@@ -46,8 +46,16 @@
+
+
+
+
+
+
+
+