ページ 11

FIFOを使ってGNUPLOTとデータを送受信する (Perl)

Posted: 2015年9月05日(土) 10:28
by みけCAT
FIFO(名前付きパイプ)を用いて、(通常の)一時ファイルを用いずにGNUPLOTにプロットするデータを渡し、描画結果を取得します。
Windowsでは動かないかもしれません。
Raspberry Pi 2 Model B上のRaspbian GNU/Linux 7 (/etc/debian_version = 7.8) で動作確認しました。

CGI形式にしてみました。
セキュリティはあまり考えていません。
動作する状態でインターネットへ公開する際は自己責任です。

コード:

#!/usr/bin/perl

use strict;
use POSIX;

my $raw_data = '';
if ($ENV{'REQUEST_METHOD'} eq 'POST') {
	while (<STDIN>) { $raw_data .= $_; }
} else {
	$raw_data = $ENV{'QUERY_STRING'};
}
my @split_data = split(/&/, $raw_data);
my %query_data = {};
for (my $i = 0; $i < @split_data; $i++) {
	my ($key, $value) = split(/=/, $split_data[$i], 2);
	$value =~ s/\+/ /g;
	$value =~ s/%([0-9a-fA-F]{2})/pack('C', hex($1))/eg;
	$query_data{$key} = $value;
}

if ($query_data{'data'} ne '') {
	my $data_fifo = "/tmp/data_";
	my $img_fifo = "/tmp/img_";
	srand;
	for (my $i = 0; $i < 32; $i++) {
		$data_fifo .= chr(ord('a') + int(rand() * 26));
		$img_fifo .= chr(ord('a') + int(rand() * 26));
	}

	my $script = <<EOS;
set terminal pngcairo
set output "$img_fifo"
unset key
plot "$data_fifo"
exit
EOS

	mkfifo($data_fifo, 0600) or die "mkfifo error\n";
	unless (mkfifo($img_fifo, 0600)) {
		unlink($data_fifo);
		die "mkfifo error\n";
	}

	my $pid1 = fork();
	if ($pid1 == -1) {
		unlink($data_fifo);
		unlink($img_fifo);
		die "fork error\n";
	}
	if ($pid1 == 0) {
		open(DATA, "> $data_fifo") or die "data open error\n";
		my $send_data = $query_data{'data'};
		$send_data =~ s/,/ /g;
		print DATA $send_data;
		close(DATA);
		exit;
	}

	my $pid2 = fork();
	if ($pid2 == -1) {
		unlink($data_fifo);
		unlink($img_fifo);
		die "fork error 2\n";
	}
	if ($pid2 == 0) {
		open(GP, "| gnuplot > /dev/null 2>&1") or die "gnuplot open error\n";
		print GP $script;
		close(GP);
		exit;
	}

	unless (open(IMG, "< $img_fifo")) {
		unlink($data_fifo);
		unlink($img_fifo);
		die "img open error\n";
	}
	binmode(IMG);
	my $image_data = '';
	while (<IMG>) { $image_data .= $_; }
	close(IMG);
	
	waitpid($pid1, 0);
	waitpid($pid2, 0);

	unlink($data_fifo);
	unlink($img_fifo);

	print "Content-type: image/png\n\n";
	binmode(STDOUT);
	print $image_data;
} else {
	print <<EOS;
Content-type: text/html;charset=UTF-8

<html lang="ja">
<head>
<meta charset="UTF-8">
<title>GNUPLOTテスト</title>
</head>
<body>
<h2>GNUPLOTテスト</h2>
<p>データは、横軸の値と縦軸の値をこの順番で1行に1組ずつ半角空白、タブ、もしくはコンマ区切りで入力してください。</p>
<form method="POST" action="./" target="_blank">
<p><textarea name="data" cols="30" rows="20" placeholder="データを入力"></textarea></p>
<p><input type="submit" value="描画"></p>
</form>
<hr>
<p><a href="../">戻る</a></p>
</body>
</html>
EOS
}
添付はCGI版と非CGI版です。

仕様、改造、再配布など自由にどうぞ。