[Gnuplot] Reads and displays binary data flowing to standard output

1 minute read

Reads and displays binary data flowing to standard output

By directly acquiring the data flowing to the standard output
The method of displaying image data (PNG) without going through a file is described below.

var process = new Process()
{
  StartInfo = new ProcessStartInfo
  {
     FileName = @".\gnuplot.exe",
     Arguments = "",
     CreateNoWindow = true,
     UseShellExecute = false,
     RedirectStandardInput = true,
     RedirectStandardOutput = true,
     RedirectStandardError = false,
  }
};

process.Start();
process.StandardInput.WriteLine("set term png enhanced size 640,480");
process.StandardInput.WriteLine("set output");
process.StandardInput.WriteLine("set palette defined(0'#000090',1'#000fff',2'#0090ff',3'#0fffee',4'#90ff70',5'#ffee00',6'#ff7000',7'#ee0000',8'#7f0000')");
process.StandardInput.WriteLine("set xrange[-2:2]");
process.StandardInput.WriteLine("set yrange[-2:2]");
process.StandardInput.WriteLine("set pm3d at bs");
process.StandardInput.WriteLine("set ticslevel 0.8");
process.StandardInput.WriteLine("set isosample 20,20");
process.StandardInput.WriteLine("set view 60,40");
process.StandardInput.WriteLine("splot exp(-x*x) * exp(-y*y)");

var reader = new BinaryReader(process.StandardOutput.BaseStream);

var iend = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82 };
var list = new List<byte>();

while (list.Skip(list.Count - iend.Length).SequenceEqual(iend) != true)
{
  list.Add(reader.ReadByte());
}

var image = Mat.FromImageData(list.ToArray(), ImreadModes.Color);
pictureBox.Image = BitmapConverter.ToBitmap(image);

//
// [exit]You can plot as many times as you like until you send, and you can get the image data each time.
//

process.StandardInput.WriteLine("exit");

process.Close();

-ReadByte (…) and Read (…) will wait for data forever if the end of the file cannot be recognized.
However, standard output cannot set a timeout, so some processing is required.
Here’s an example, but there may be a smarter way …

Task<byte> task;
while (list.Skip(list.Count - iend.Length).SequenceEqual(iend) != true)
{
  if ((task = Task.Run(() => reader.ReadByte())).Wait(1000) == false)
  {
     break;
  }

  list.Add(task.Result);
}
byte[] buffer = new byte[1024];
Task<IEnumerable<byte>> task = null;
while (list.Skip(list.Count - iend.Length).SequenceEqual(iend) != true)
{
  if ((task = Task.Run(() => buffer.Take(reader.Read(buffer, 0, buffer.Length)))).Wait(1000) == false)
  {
     break;
  }

  list.AddRange(task.Result);
}
var task = Task.Run(() =>
{
  while (list.Skip(list.Count - iend.Length).SequenceEqual(iend) != true)
  {
     list.Add(reader.ReadByte());
  }
});         

var taskTimeout = Task.Run(() =>
{
  int lastCount = -1;
  while(lastCount != list.Count)
  {
     lastCount = list.Count;
     Task.Delay(1000).Wait();
  }
});

Task.WaitAny(task, taskTimeout);

-To cancel the data wait, use the following code.

if (task.IsCompleted == false)
{
  process.StandardInput.WriteLine("exit");
}

Other

-If only one image data is output, the following description is also possible.

// ---abridgement---

process.StandardInput.WriteLine("splot exp(-x*x) * exp(-y*y)");
process.StandardInput.WriteLine("exit");

var reader = new BinaryReader(process.StandardOutput.BaseStream);

var list = new List<byte>();
byte[] buf = new byte[1024];

while (reader.Read(buf, 0, buf.Length) != 0)
{
   list.AddRange(buf);
}

// ---abridgement---

image.png
Gnuplot –graphing utility