標準出力に流れるバイナリデータを読み取って表示する
標準出力に流れるデータを直接取得することによって、
ファイルを経由せずに、画像データ(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);
}
// --- 省略 ---