1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

[Gnuplot] 標準出力に流れるバイナリデータを読み取って表示する

Last updated at Posted at 2020-09-13

標準出力に流れるバイナリデータを読み取って表示する

標準出力に流れるデータを直接取得することによって、
ファイルを経由せずに、画像データ(PNG)を表示する方法を以下に記述します。

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]を送信するまでは何度でもプロットでき、その都度、画像データを取得できます。
//

process.StandardInput.WriteLine("exit");

process.Close();

・ReadByte(...)やRead(...)は、ファイルの終端を認識できなかった場合に永久にデータ待ちをしてしまいます。
しかし、標準出力はタイムアウトを設定できないため、何らかの処理が必要となります。
以下に例を記述しますが、もっとスマートな方法があるかもしれません...

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);

・データ待ちの解除は、以下のようなコードで行います。

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

その他

・画像データの出力が1枚だけの場合は以下の記述でも可能です。

// --- 省略 ---

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);
}

// --- 省略 ---

image.png
gnuplot - graphing utility

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?