Click here to Skip to main content
15,885,366 members
Articles / Programming Languages / C#

How To Convert PDF to Image Using Ghostscript API

Rate me:
Please Sign up or sign in to vote.
4.89/5 (76 votes)
28 Mar 2010CPOL4 min read 2.1M   45.3K   229  
How to use Ghostscript library to create an image (or images) from a PDF file
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Collections;
using System.IO;

namespace ConvertPDF
{
    /// <summary>
    /// Create by : TaGoH
    /// URL of the last version: http://www.codeproject.com/KB/cs/GhostScriptUseWithCSharp.aspx
    /// Description:
    /// Class to convert a pdf to an image using GhostScript DLL
    /// A big Credit for this code go to:Rangel Avulso
    /// I mainly create a better interface and refactor it to made it ready to use!
    /// </summary>
    /// <see cref="http://www.codeproject.com/KB/cs/GhostScriptUseWithCSharp.aspx"/>
    /// <seealso cref="http://www.hrangel.com.br/index.php/2006/12/04/converter-pdf-para-imagem-jpeg-em-c/"/>
    public class PDFConvert
    {
        #region Static
        /// <summary>Use to check for default transformation</summary>
        private static bool useSimpleAnsiConversion = true;
        /// <summary>Thanks to 	tchu_2000 to remind that u should never hardcode strings! :)</summary>
        private const string GS_OutputFileFormat = "-sOutputFile={0}";
        private const string GS_DeviceFormat = "-sDEVICE={0}";
        private const string GS_FirstParameter = "pdf2img";
        private const string GS_ResolutionXFormat = "-r{0}";
        private const string GS_ResolutionXYFormat = "-r{0}x{1}";
        private const string GS_FirstPageFormat = "-dFirstPage={0}";
        private const string GS_LastPageFormat = "-dLastPage={0}";
        private const string GS_FitPage = "-dPDFFitPage";
        private const string GS_PageSizeFormat = "-g{0}x{1}";
        private const string GS_JpegQualityFormat = "-dJPEGQ={0}";
        private const string GS_Fixed1stParameter = "-dNOPAUSE";
        private const string GS_Fixed2ndParameter = "-dBATCH";
        private const string GS_Fixed3rdParameter = "-dSAFER";
        private const string GS_QuiteOperation = "-q";
        private const string GS_StandardOutputDevice = "-";
        private const string GS_MultiplePageCharacter = "%";
        #endregion
        #region Windows Import
        /// <summary>Needed to copy memory from one location to another, used to fill the struct</summary>
        /// <param name="Destination"></param>
        /// <param name="Source"></param>
        /// <param name="Length"></param>
        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        static extern void CopyMemory(IntPtr Destination, IntPtr Source, uint Length);
        #endregion
        #region GhostScript Import

        /// <summary>Create a new instance of Ghostscript. This instance is passed to most other gsapi functions. The caller_handle will be provided to callback functions.
        ///  At this stage, Ghostscript supports only one instance. </summary>
        /// <param name="pinstance"></param>
        /// <param name="caller_handle"></param>
        /// <returns></returns>
        [DllImport("gsdll32.dll", EntryPoint="gsapi_new_instance")]
        private static extern int gsapi_new_instance (out IntPtr pinstance, IntPtr caller_handle);

        /// <summary>This is the important function that will perform the conversion</summary>
        /// <param name="instance"></param>
        /// <param name="argc"></param>
        /// <param name="argv"></param>
        /// <returns></returns>
        [DllImport("gsdll32.dll", EntryPoint="gsapi_init_with_args")]
        private static extern int gsapi_init_with_args (IntPtr instance, int argc, IntPtr argv);
        /// <summary>
        /// Exit the interpreter. This must be called on shutdown if gsapi_init_with_args() has been called, and just before gsapi_delete_instance(). 
        /// </summary>
        /// <param name="instance"></param>
        /// <returns></returns>
        [DllImport("gsdll32.dll", EntryPoint="gsapi_exit")]
        private static extern int gsapi_exit (IntPtr instance);

        /// <summary>
        /// Destroy an instance of Ghostscript. Before you call this, Ghostscript must have finished. If Ghostscript has been initialised, you must call gsapi_exit before gsapi_delete_instance. 
        /// </summary>
        /// <param name="instance"></param>
        [DllImport("gsdll32.dll", EntryPoint="gsapi_delete_instance")]
        private static extern void gsapi_delete_instance (IntPtr instance);
        /// <summary>Get info about the version of Ghostscript i'm using</summary>
        /// <param name="pGSRevisionInfo"></param>
        /// <param name="intLen"></param>
        /// <returns></returns>
        [DllImport("gsdll32.dll", EntryPoint="gsapi_revision")]
        private static extern int gsapi_revision (ref GS_Revision pGSRevisionInfo , int intLen );
        /// <summary>Use a different I/O</summary>
        /// <param name="lngGSInstance"></param>
        /// <param name="gsdll_stdin">Function that menage the Standard INPUT</param>
        /// <param name="gsdll_stdout">Function that menage the Standard OUTPUT</param>
        /// <param name="gsdll_stderr">Function that menage the Standard ERROR output</param>
        /// <returns></returns>
        [DllImport("gsdll32.dll", EntryPoint = "gsapi_set_stdio")]
        private static extern int gsapi_set_stdio(IntPtr lngGSInstance, StdioCallBack gsdll_stdin, StdioCallBack gsdll_stdout, StdioCallBack gsdll_stderr);

        #endregion
        #region Const
        const int e_Quit=-101;
        const int e_NeedInput = -106;
        #endregion
        #region Variables
        private string _sDeviceFormat;
        private string _sParametersUsed;

        private int _iWidth;
        private int _iHeight;
        private int _iResolutionX;
        private int _iResolutionY;
        private int _iJPEGQuality;
        /// <summary>The first page to convert in image</summary>
        private int _iFirstPageToConvert = -1;
        /// <summary>The last page to conver in an image</summary>
        private int _iLastPageToConvert = -1;
        private bool _bFitPage;
        private bool _bThrowOnlyException = false;
        private bool _bRedirectIO = false;
        private IntPtr _objHandle;
        /// <summary>If true i will try to output everypage to a different file!</summary>
        private bool _didOutputToMultipleFile = false;

        private System.Diagnostics.Process myProcess;
        public StringBuilder output;
        //public string output;
        //private List<byte> outputBytes;
        //public string error;
        #endregion
        #region Proprieties
        /// <summary>
        /// What format to use to convert
        /// is suggested to use png256 instead of jpeg for document!
        /// they are smaller and better suited!
        /// </summary>
        /// <see cref="http://pages.cs.wisc.edu/~ghost/doc/cvs/Devices.htm"/>
        public string OutputFormat
        {
            get { return _sDeviceFormat; }
            set { _sDeviceFormat = value; }
        }

        public string ParametersUsed
        {
            get { return _sParametersUsed; }
            set { _sParametersUsed = value; }
        }

        public int Width
        {
            get { return _iWidth; }
            set { _iWidth = value; }
        }

        public int Height
        {
            get { return _iHeight; }
            set { _iHeight = value; }
        }

        public int ResolutionX
        {
            get { return _iResolutionX; }
            set { _iResolutionX = value; }
        }

        public int ResolutionY
        {
            get { return _iResolutionY; }
            set { _iResolutionY = value; }
        }

        public Boolean FitPage
        {
            get { return _bFitPage; }
            set { _bFitPage = value; }
        }
        /// <summary>Quality of compression of JPG</summary>
        public int JPEGQuality
        {
            get { return _iJPEGQuality; }
            set { _iJPEGQuality = value; }
        }
        /// <summary>The first page to convert in image</summary>
        public int FirstPageToConvert
        {
            get { return _iFirstPageToConvert; }
            set { _iFirstPageToConvert = value; }
        }
        /// <summary>The last page to conver in an image</summary>
        public int LastPageToConvert
        {
            get { return _iLastPageToConvert; }
            set { _iLastPageToConvert = value; }
        }
        /// <summary>Set to True if u want the program to never display Messagebox
        /// but otherwise throw exception</summary>
        public Boolean ThrowOnlyException
        {
            get { return _bThrowOnlyException; }
            set { _bThrowOnlyException = value; }
        }
        /// <summary>If i should redirect the Output of Ghostscript library somewhere</summary>
        public bool RedirectIO
        {
            get { return _bRedirectIO; }
            set { _bRedirectIO = value; }
        }
        /// <summary>If true i will try to output everypage to a different file!</summary>
        public bool OutputToMultipleFile
        {
            get { return _didOutputToMultipleFile; }
            set { _didOutputToMultipleFile = value; }
        }
        #endregion
        #region Init
        public PDFConvert(IntPtr objHandle)
        {
            _objHandle = objHandle;
        }

        public PDFConvert()
        {
            _objHandle = IntPtr.Zero;
        }
        #endregion

        #region Convert
        /// <summary>Convert a single file!</summary>
        /// <param name="inputFile">The file PDf to convert</param>
        /// <param name="outputFile">The image file that will be created</param>
        /// <remarks>You must pass all the parameter for the conversion
        /// as Proprieties of this class</remarks>
        /// <returns>True if the conversion succed!</returns>
        public bool Convert(string inputFile, string outputFile)
        {
            return Convert(inputFile, outputFile, _bThrowOnlyException,null);
        }

        /// <summary>Convert a single file!</summary>
        /// <param name="inputFile">The file PDf to convert</param>
        /// <param name="outputFile">The image file that will be created</param>
        /// <param name="parameters">You must pass all the parameter for the conversion here</param>
        /// <remarks>Thanks to 	tchu_2000 for the help!</remarks>
        /// <returns>True if the conversion succed!</returns>
        public bool Convert(string inputFile, string outputFile,string parameters)
        {
            return Convert(inputFile, outputFile, _bThrowOnlyException, parameters);
        }

        /// <summary>Convert a single file!</summary>
        /// <param name="inputFile">The file PDf to convert</param>
        /// <param name="outputFile">The image file that will be created</param>
        /// <param name="throwException">if the function should throw an exception
        /// or display a message box</param>
        /// <remarks>You must pass all the parameter for the conversion
        /// as Proprieties of this class</remarks>
        /// <returns>True if the conversion succed!</returns>
        private bool Convert(string inputFile, string outputFile,bool throwException,string options)
        {
            #region Check Input
            //Avoid to work when the file doesn't exist
            if (string.IsNullOrEmpty(inputFile))
            {
                if (throwException)
                    throw new ArgumentNullException("inputFile");
                else
                {
                    System.Windows.Forms.MessageBox.Show("The inputfile is missing");
                    return false;
                }
            }
            if (!System.IO.File.Exists(inputFile))
            {
                if (throwException)
                    throw new ArgumentException(string.Format("The file :'{0}' doesn't exist", inputFile), "inputFile");
                else
                {
                    System.Windows.Forms.MessageBox.Show(string.Format("The file :'{0}' doesn't exist", inputFile));
                    return false;
                }
            }
            if (string.IsNullOrEmpty(_sDeviceFormat))
            {
                if (throwException)
                    throw new ArgumentNullException("Device");
                else
                {
                    System.Windows.Forms.MessageBox.Show("You didn't provide a device for the conversion");
                    return false;
                }
            }
            //be sure that if i specify multiple page outpage i added the % to the filename!
            #endregion
            #region Variables
            int intReturn, intCounter, intElementCount;
            //The pointer to the current istance of the dll
            IntPtr intGSInstanceHandle;
            object[] aAnsiArgs;
            IntPtr[] aPtrArgs;
            GCHandle[] aGCHandle;
            IntPtr callerHandle, intptrArgs;
            GCHandle gchandleArgs;
            #endregion
            //Generate the list of the parameters i need to pass to the dll
            string[] sArgs = GetGeneratedArgs(inputFile, outputFile,options);
            #region Convert Unicode strings to null terminated ANSI byte arrays
            // Convert the Unicode strings to null terminated ANSI byte arrays
            // then get pointers to the byte arrays.
            intElementCount = sArgs.Length;
            aAnsiArgs = new object[intElementCount];
            aPtrArgs = new IntPtr[intElementCount];
            aGCHandle = new GCHandle[intElementCount];
            //Convert the parameters
            for (intCounter = 0; intCounter < intElementCount; intCounter++)
            {
                aAnsiArgs[intCounter] = StringToAnsiZ(sArgs[intCounter]);
                aGCHandle[intCounter] = GCHandle.Alloc(aAnsiArgs[intCounter], GCHandleType.Pinned);
                aPtrArgs[intCounter] = aGCHandle[intCounter].AddrOfPinnedObject();
            }
            gchandleArgs = GCHandle.Alloc(aPtrArgs, GCHandleType.Pinned);
            intptrArgs = gchandleArgs.AddrOfPinnedObject();
            #endregion
            #region Create a new istance of the library!
            intReturn = -1;
            try
            {
                intReturn = gsapi_new_instance(out intGSInstanceHandle, _objHandle);
                //Be sure that we create an istance!
                if (intReturn < 0)
                {
                    ClearParameters(ref aGCHandle, ref gchandleArgs);
                    if (throwException)
                        throw new ApplicationException("I can't create a new istance of Ghostscript please verify no other istance are running!");
                    else
                    {
                        System.Windows.Forms.MessageBox.Show("I can't create a new istance of Ghostscript please verify no other istance are running!");
                        return false;
                    }
                }
            }
            catch (DllNotFoundException ex)
            {//in this case the dll we r using isn't the dll we expect
                ClearParameters(ref aGCHandle, ref gchandleArgs);
                if (throwException)
                    throw new ApplicationException("The gs32dll.dll in the program directory doesn't "+
                        "expose the methods i need!\nplease download the version 8.64 from the original website!");
                else
                {
                    System.Windows.Forms.MessageBox.Show("The gs32dll.dll in the program directory"+
                        " doesn't expose the methods i need!\nPlease download the version 8.64 "+
                        "from the original website!");
                    return false;
                }
            }
            callerHandle = IntPtr.Zero;//remove unwanter handler
            #endregion
            #region Capture the I/O
            //if (_bRedirectIO)
            //{
            //    StdioCallBack stdinCallback = new StdioCallBack(gsdll_stdin);
            //    StdioCallBack stdoutCallback = new StdioCallBack(gsdll_stdout);
            //    StdioCallBack stderrCallback = new StdioCallBack(gsdll_stderr);
            //    intReturn = gsapi_set_stdio(intGSInstanceHandle, stdinCallback, stdoutCallback, stderrCallback);
            //    if (output == null) output = new StringBuilder();
            //    else output.Remove(0, output.Length);
            //    myProcess = System.Diagnostics.Process.GetCurrentProcess();
            //    myProcess.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler(SaveOutputToImage);
            //}
            #endregion
            intReturn = -1;//if nothing change it there is an error!
            //Ok now is time to call the interesting method
            try { intReturn = gsapi_init_with_args(intGSInstanceHandle, intElementCount, intptrArgs); }
            catch (Exception ex)
            {
                if (throwException)
                    throw new ApplicationException(ex.Message, ex);
                else
                    System.Windows.Forms.MessageBox.Show(ex.Message);
            }
            finally//No matter what happen i MUST close the istance!
            {   //free all the memory
                ClearParameters(ref aGCHandle,ref gchandleArgs);
                gsapi_exit(intGSInstanceHandle);//Close the istance
                gsapi_delete_instance(intGSInstanceHandle);//delete it
                //In case i was looking for output now stop
                if (myProcess != null) myProcess.OutputDataReceived -= new System.Diagnostics.DataReceivedEventHandler(SaveOutputToImage);
            }
            //Conversion was successfull if return code was 0 or e_Quit
            return (intReturn == 0) | (intReturn == e_Quit);//e_Quit = -101
        }

        /// <summary>Remove the memory allocated</summary>
        /// <param name="aGCHandle"></param>
        /// <param name="gchandleArgs"></param>
        private void ClearParameters(ref GCHandle[] aGCHandle, ref GCHandle gchandleArgs)
        {
            for (int intCounter = 0; intCounter < aGCHandle.Length; intCounter++)
                aGCHandle[intCounter].Free();
            gchandleArgs.Free();
        }
        #region Test (code not used)
        void SaveOutputToImage(object sender, System.Diagnostics.DataReceivedEventArgs e)
        {
            output.Append(e.Data);
        }

        //public System.Drawing.Image Convert(string inputFile)
        //{
        //    _bRedirectIO = true;
        //    if (Convert(inputFile, "%stdout", _bThrowOnlyException))
        //    {
        //        if ((output != null) && (output.Length > 0))
        //        {
        //            //StringReader sr = new StringReader(output.ToString());
        //            //MemoryStream ms = new MemoryStream(UTF8Encoding.Default.GetBytes(output.ToString()));
        //            System.Drawing.Image returnImage = System.Drawing.Image.FromStream(myProcess.StandardOutput.BaseStream).Clone() as System.Drawing.Image;
        //            //ms.Close();
        //            return returnImage;
        //        }
        //    }
        //    return null;
        //}
        #endregion
        #endregion

        #region Accessory Functions
        /// <summary>This function create the list of parameters to pass to the dll with parameters given directly from the program</summary>
        /// <param name="inputFile"></param>
        /// <param name="outputFile"></param>
        /// <param name="otherParameters">The other parameters i could be interested</param>
        /// <remarks>Be very Cautious using this! code provided and modified from tchu_2000</remarks>
        /// <returns></returns>
        private string[] GetGeneratedArgs(string inputFile, string outputFile, string otherParameters)
        {
            if (!string.IsNullOrEmpty(otherParameters))
                return GetGeneratedArgs(inputFile,outputFile,otherParameters.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries));
            else
                return GetGeneratedArgs(inputFile,outputFile,(string[])null);
        }

        /// <summary>This function create the list of parameters to pass to the dll</summary>
        /// <param name="inputFile">the file to convert</param>
        /// <param name="outputFile">where to write the image</param>
        /// <returns>the list of the arguments</returns>
        private string[] GetGeneratedArgs(string inputFile, string outputFile,string[] presetParameters)
        {
            string[] args;
            ArrayList lstExtraArgs = new ArrayList();
            //ok if i haven't been passed a list of parameters create my own
            if ((presetParameters == null) || (presetParameters.Length == 0))
            {
                if (_sDeviceFormat == "jpeg" && _iJPEGQuality > 0 && _iJPEGQuality < 101)
                    lstExtraArgs.Add(string.Format(GS_JpegQualityFormat, _iJPEGQuality));

                if (_iWidth > 0 && _iHeight > 0)
                    lstExtraArgs.Add(string.Format(GS_PageSizeFormat, _iWidth, _iHeight));

                if (_bFitPage) lstExtraArgs.Add(GS_FitPage);

                if (_iResolutionX > 0)
                {
                    if (_iResolutionY > 0)
                        lstExtraArgs.Add(String.Format(GS_ResolutionXYFormat, _iResolutionX, _iResolutionY));
                    else
                        lstExtraArgs.Add(String.Format(GS_ResolutionXFormat, _iResolutionX));
                }
                if (_iFirstPageToConvert > 0)
                    lstExtraArgs.Add(String.Format(GS_FirstPageFormat, _iFirstPageToConvert));
                if (_iLastPageToConvert > 0)
                    lstExtraArgs.Add(String.Format(GS_LastPageFormat, _iLastPageToConvert));
                //If i want to redirect write it to the standard output!
                if (_bRedirectIO)
                {
                    //In this case you must also use the -q switch to prevent Ghostscript
                    //from writing messages to standard output which become
                    //mixed with the intended output stream. 
                    outputFile = GS_StandardOutputDevice;
                    lstExtraArgs.Add(GS_QuiteOperation);
                }
                int iFixedCount = 7;
                int iExtraArgsCount = lstExtraArgs.Count;
                args = new string[iFixedCount + lstExtraArgs.Count];
                args[1] = GS_Fixed1stParameter;//"-dNOPAUSE";//I don't want interruptions
                args[2] = GS_Fixed1stParameter;//"-dBATCH";//stop after
                args[3] = GS_Fixed2ndParameter;//"-dSAFER";
                args[4] = string.Format(GS_DeviceFormat, _sDeviceFormat);//what kind of export format i should provide
                //For a complete list watch here:
                //http://pages.cs.wisc.edu/~ghost/doc/cvs/Devices.htm
                //Fill the remaining parameters
                for (int i = 0; i < iExtraArgsCount; i++)
                    args[5 + i] = (string)lstExtraArgs[i];
            }
            else
            {//3 arguments MUST be added 0 (meaningless) and at the end the output and the inputfile
                args = new string[presetParameters.Length + 3];
                //now use the parameters i receive (thanks CrucialBT to point this out!)
                for (int i = 1; i < presetParameters.Length; i++)
                    args[i] = presetParameters[i - 1];
            }
            args[0]=GS_FirstParameter;//this parameter have little real use
            //Now check if i want to update to 1 file per page i have to be sure do add % to the output filename
            if ((_didOutputToMultipleFile) && (!outputFile.Contains(GS_MultiplePageCharacter)))
            {// Thanks to Spillie to show me the error!
                int lastDotIndex = outputFile.LastIndexOf('.');
                if (lastDotIndex > 0)
                    outputFile = outputFile.Insert(lastDotIndex, "%d");
            }
            //Fill outputfile and inputfile as last 2 arguments!
            args[args.Length - 2] = string.Format(GS_OutputFileFormat, outputFile);
            args[args.Length - 1] = string.Format("{0}", inputFile);
            //Ok now save them to be shown 4 debug use
            _sParametersUsed = "";
            foreach (string arg in args)
                _sParametersUsed += " " + arg;
            return args;
        }

        /// <summary>
        /// Convert a Unicode string to a null terminated Ansi string for Ghostscript.
        /// The result is stored in a byte array
        /// </summary>
        /// <param name="str">The parameter i want to convert</param>
        /// <returns>the byte array that contain the string</returns>
        private static byte[] StringToAnsiZ(string str)
        {
            // Later you will need to convert
            // this byte array to a pointer with
            // GCHandle.Alloc(XXXX, GCHandleType.Pinned)
            // and GSHandle.AddrOfPinnedObject()
            //int intElementCount,intCounter;

            //This with Encoding.Default should work also with Chineese Japaneese
            //Thanks to tchu_2000 I18N related patch
            if (str == null) str = String.Empty;
            return Encoding.Default.GetBytes(str);
        }

        /// <summary>Convert a Pointer to a string to a real string</summary>
        /// <param name="strz">the pointer to the string in memory</param>
        /// <returns>The string</returns>
        public static string AnsiZtoString(IntPtr strz)
        {
            if (strz != IntPtr.Zero)
                return Marshal.PtrToStringAnsi(strz);
            else
                return string.Empty;
        }
        #endregion
        #region Menage Standard Input & Standard Output
        public int gsdll_stdin(IntPtr intGSInstanceHandle, IntPtr strz, int intBytes)
        {
            // This is dumb code that reads one byte at a time
           // Ghostscript doesn't mind this, it is just very slow
            if (intBytes == 0) 
                return 0;
            else
            {
                int ich = Console.Read();
                if (ich == -1)
                    return 0; // EOF
                else
                {
                    byte bch = (byte)ich;
                    GCHandle gcByte = GCHandle.Alloc(bch, GCHandleType.Pinned);
                    IntPtr ptrByte = gcByte.AddrOfPinnedObject();
                    CopyMemory(strz, ptrByte, 1);
                    ptrByte = IntPtr.Zero;
                    gcByte.Free();
                    return 1;
                }
            }
        }

        public int gsdll_stdout(IntPtr intGSInstanceHandle, IntPtr strz , int intBytes)
        {
            if (intBytes > 0)
            {
                Console.Write(Marshal.PtrToStringAnsi(strz));
            }
            return 0;
        }

        public int gsdll_stderr(IntPtr intGSInstanceHandle, IntPtr strz, int intBytes )
        {
            //return gsdll_stdout(intGSInstanceHandle, strz, intBytes);
            Console.Write(Marshal.PtrToStringAnsi(strz));
            return intBytes;
        }
        #endregion
        #region Menage Revision
        public GhostScriptRevision GetRevision()
        {
            // Check revision number of Ghostscript
            int intReturn;
            GS_Revision udtGSRevInfo = new GS_Revision();
            GhostScriptRevision output;
            GCHandle gcRevision;
            gcRevision = GCHandle.Alloc(udtGSRevInfo, GCHandleType.Pinned);
            intReturn = gsapi_revision(ref udtGSRevInfo, 16);
            output.intRevision = udtGSRevInfo.intRevision;
            output.intRevisionDate = udtGSRevInfo.intRevisionDate;
            output.ProductInformation = AnsiZtoString(udtGSRevInfo.strProduct);
            output.CopyrightInformations = AnsiZtoString(udtGSRevInfo.strCopyright);
            gcRevision.Free();
            return output;
        }
        #endregion
    }

    /// <summary>Delegate used by Ghostscript to perform I/O operations</summary>
    /// <param name="handle"></param>
    /// <param name="strptr"></param>
    /// <param name="count"></param>
    /// <returns></returns>
    public delegate int StdioCallBack(IntPtr handle, IntPtr strptr, int count);
    /// <summary>This struct is filled with the information of the version of this ghostscript</summary>
    /// <remarks>Have the layout defined cuz i will fill it with a kernel copy memory</remarks>
    [StructLayout(LayoutKind.Sequential)]
    struct GS_Revision
    {
        public IntPtr strProduct;
        public IntPtr strCopyright;
        public int intRevision;
        public int intRevisionDate;
    }

    public struct GhostScriptRevision
    {
        public string ProductInformation;
        public string CopyrightInformations;
        public int intRevision;
        public int intRevisionDate;
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
Italy Italy
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions