この記事の内容
Processingから外部プロセスを実行する方法についての覚え書き.
環境
OS: Windows 10 Home (1909)
Processing: 3.5.4
参考
https://docs.oracle.com/javase/jp/8/docs/api/java/lang/ProcessBuilder.html
https://www.ne.jp/asahi/hishidama/home/tech/java/process.html
外部プロセスの実行
Runtimeクラスを使う方法が紹介されていることがあるが,JDK1.5以降はProcessBuilderクラスを用いるのがよいとされている.外部プロセスでファイルを扱う場合,実行時の作業ディレクトリを指定することで,ファイルへのアクセスが容易になる.
ProcessBuilderクラスのコンストラクタには,実行ファイルと引数(複数OK)を与える.
ProcessingのdataFile()関数はdataフォルダに入っている引数で与えられた名前のファイルのjava.io.Fileインスタンスを返すものであり,引数に空文字列を与えることでdataフォルダそのものを得ることができる.
以下の例はPythonスクリプトの実行例である.スクリプトsample.pyに引数testdata.csvを与えて処理を開始している.
String python_exe = "py"; // py.exeにはpathが通っている
String python_script = "sample.py";
String data_filename = "testdata.csv";
Process process;
void execExternalProcess() {
try {
ProcessBuilder pb = new ProcessBuilder(python_exe, python_script, data_filename); // 実行するコマンドと引数列
pb.directory(dataFile("")); // 実行時のディレクトリを指定
process = pb.start(); // 実行
} catch (Exception e) {
println(e);
}
}
外部プロセスの終了待ち
プロセスの状況はProcessクラスのisAlive()メソッドで知ることができる.プロセスが実行中は待機メッセージを表示し,プロセスの処理が終了したら結果を得て(ファイル読み込みなど)処理を進めるといったことができる.
以下は外部プロセスが画像を生成する場合の例である.画像生成のためのプロセスが終了するまではメッセージと処理中であることを示すメッセージとアニメーションを表示し,処理が終わったら画像を読み込んで表示している.
String image_filename = "result.jpg";
PImage img;
void draw() {
if (img == null) { // 画像がまだ読み込まれていない場合
background(0);
if (!process.isAlive()) { // プロセスが実行中ではない(つまり,終了した)
File file = dataFile(image_filename);
if (file.exists()) { // 生成された画像ファイルがあれば読み込む
img = loadImage(image_filename);
set(0, 0, img); // 表示する
} else { // プロセスが終了したが画像無し→多分,生成に失敗した
translate(10, 40);
noStroke();
fill(255);
textSize(32);
text("external process failed", 0, 0);
}
} else { // 無ければ画面にメッセージ表示
translate(10, 40);
noStroke();
fill(255);
textSize(32);
String s = "making images...";
text(s, 0, 0);
// ぐるぐるを表示
translate(textWidth(s) + 20, -10);
rotate(TWO_PI * millis() / 1000);
final int n = 12;
for (int i = 0; i < n; i++) {
fill(255 * i / n);
circle(12, 0, 4);
rotate(TWO_PI / n);
}
}
} else { // 画像読み込み済みの場合
set(0, 0, img);
}
}