ArtifexSoftware / Ghostscript.NET

Ghostscript.NET - managed wrapper around the Ghostscript library (32-bit & 64-bit)

Home Page:https://ghostscript.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Use stdin and stdout with GhostscriptProcessor

MAButz opened this issue · comments

Hi,
i'am testing to use the stdin and stdout with the GhostscriptProcessor class to avoid to use files...

Now i'am reading testing ... I dont know how.

Here is my Code, have anybody else an idea? Thanks.

            MemoryStream ms = new MemoryStream();

            GhostscriptPipedOutput gsPipedOutput = new GhostscriptPipedOutput();

            string outputPipeHandle = "%handle%" + int.Parse(gsPipedOutput.ClientHandle).ToString("X2");
            
            using (GhostscriptProcessor processor = new GhostscriptProcessor())
            {
                List<string> switches = new List<string>();
                switches.Add("-empty");
                switches.Add("-dQUIET");
                switches.Add("-dNOSAFER"); // >gs9.52
                switches.Add("-dBATCH");
                switches.Add("-dNOPAUSE");
                switches.Add("-dNOPROMPT");
                switches.Add("-r300");
                switches.Add("-dNumRenderingThreads=" + Environment.ProcessorCount);
                switches.Add("-sDEVICE=pnggray");
                switches.Add("-sOutputFile=" + outputPipeHandle);
                switches.Add("-f");
                //switches.Add(inputFile);
                switches.Add("-");

                try
                {
                    StdIOHandler stdio = new StdIOHandler(s_printdatabytes);
                    processor.Process(switches.ToArray(), stdio);
                    byte[] rawDocumentData = gsPipedOutput.Data;
                    ms.Write(rawDocumentData, 0, rawDocumentData.Length);
                }
                catch (Exception e)
                {

                }
                finally
                {
                    gsPipedOutput.Dispose();
                    gsPipedOutput = null;
                }
            }

and the StdIOHandler class

public class StdIOHandler : GhostscriptStdIO
{
    private char[] _input = null;

    public StdIOHandler(string input) : base(true, true, true)
    {
        _input = input.ToCharArray();
    }

    public override void StdIn(out string input, int count)
    {
        count = _input.Length;
        Console.In.ReadBlock(_input, 0, count);
        input = new string(_input);
    }

    public override void StdOut(string output)
    {
        Console.Write(output);
    }

    public override void StdError(string error)
    {
        Console.Write(error);
    }
}

I'll take a look about this on Monday and get back to you.

Hi, thanks for your help in information.
I have addition information out of my new tests.

I have mofivied the StdIOHandler class, new Version ->

public class StdIOHandler : GhostscriptStdIO
{
    private string _input = null;

    public StdIOHandler(string input) : base(true, true, true)
    {
        _input = input;
    }

    public override void StdIn(out string input, int count)
    {
        input = _input;
    }

    public override void StdOut(string output)
    {
        Console.WriteLine("StdOut->" + output);
    }

    public override void StdError(string error)
    {
        Console.WriteLine("StdError->" + error);
    }
}

And at debugging, the GhostscriptStdIO.cs ->

private int gs_std_in(IntPtr handle, IntPtr pointer, int count)

The integer -> count is at every Time at this Point (line 104)->

// ask handler owner for the input data
this.StdIn(out input, count);

count=1;

I have try to set the counter at the length of input, but i can not find the correct point.

In the GhostscriptStdIO.cs at Line 120, the count value should be corrected, but the if statement, does not work
if (count > _input.Length)
I had to change the if statement in ->
if (count < _input.Length)

And now the the count is at the correct value and the input sting is converting character for character to char (at line 130)

But now the Programm is in a endless loop...

There is no point pushing PDF via StdIn. Ghostscript documentation says: The PDF language, unlike the PostScript language, inherently requires random access to the file. If you provide PDF to standard input Ghostscript will copy it to a temporary file before interpreting the PDF.

Here is example for pushing PostScript via StdIn:

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

using Ghostscript.NET;
using Ghostscript.NET.Processor;

namespace ConsoleApp61
{
    class Program
    {
        static void Main(string[] args)
        {
            MemoryStream outputMemoryStream = new MemoryStream();

            GhostscriptPipedOutput gsPipedOutput = new GhostscriptPipedOutput();

            string outputPipeHandle = "%handle%" + int.Parse(gsPipedOutput.ClientHandle).ToString("X2");

            using (GhostscriptProcessor processor = new GhostscriptProcessor())
            {
                List<string> switches = new List<string>();
                switches.Add("-empty");
                switches.Add("-dQUIET");
                switches.Add("-dNOSAFER");
                switches.Add("-dBATCH");
                switches.Add("-dNOPAUSE");
                switches.Add("-dNOPROMPT");
                switches.Add("-dNumRenderingThreads=" + Environment.ProcessorCount);
                switches.Add("-sDEVICE=pdfwrite");
                switches.Add("-sOutputFile=" + outputPipeHandle);
                switches.Add("-f");
                switches.Add("-");

                try
                {
                    string psExample = @"
                        newpath 
                        100 200 moveto 
                        200 250 lineto 
                        100 300 lineto 
                        closepath 
                        gsave 
                        0.5 setgray 
                        fill 
                        grestore 
                        4 setlinewidth 
                        0.75 setgray 
                        stroke 
                        showpage";

                    MemoryStream inputMemoryStream = new MemoryStream(Encoding.UTF8.GetBytes(psExample));

                    StdIOHandler stdio = new StdIOHandler(inputMemoryStream);
                    processor.Process(switches.ToArray(), stdio);
                    byte[] rawDocumentData = gsPipedOutput.Data;
                    outputMemoryStream.Write(rawDocumentData, 0, rawDocumentData.Length);
                }
                catch (Exception e)
                {

                }
                finally
                {
                    gsPipedOutput.Dispose();
                    gsPipedOutput = null;
                }
            }
        }
    }

    public class StdIOHandler : GhostscriptStdIO
    {
        private StreamReader _reader;

        public StdIOHandler(MemoryStream input) : base(true, true, true)
        {
            input.Position = 0;

            _reader = new StreamReader(input);
        }

        public override void StdIn(out string input, int count)
        {
            int counter = 0;

            StringBuilder sb = new StringBuilder();

            while (counter < count)
            {
                var singleByte = _reader.Read();

                if (singleByte == -1)
                {
                    break;
                }

                sb.Append((char)singleByte);
                counter++;
            }

            if (sb.Length == 0)
            {
                input = null;
            }
            else
            {
                input = sb.ToString();
            }
        }

        public override void StdOut(string output)
        {
            Console.WriteLine("StdOut->" + output);
        }

        public override void StdError(string error)
        {
            Console.WriteLine("StdError->" + error);
        }
    }

}

Hi jhabjan,
thanks for your help.
Your StdIOHandler class works perfect.

At this point it use PostScript files (no PDF), i think there should not use temporary file.

Greate Work.