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.