CanvasとWebSocketの実験

http://blog.liris.org/2009/12/websocketchat.html
http://www.html5.jp/canvas/
あたりを参考にVNCクライアントもどきを書いてみた。


Xサーバー→x11vnc→Ultr@VNC Java Viewer改造版→jetty→JavaScriptとかなり回りくどいことをしているせいもあるんだろうけど、それにしてもかなり重い。ボトルネックがCPUでなく通信なら圧縮をサーバー側で展開してJavaScriptに送っているので、処理をクライアント側に移せば通信量は減らせそうではある。

バイナリフレーム対応WebSocketとバイトアレイ対応JavaScriptください。X11 over WebSocketは厳しいか。

HTML/JavaScript周りはどっかで勉強しないとなあ。

<!DOCTYPE html> 
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
		<title>Untitled Document</title>
	</head>
<body>
<p>
<canvas id="mainScreen" width="800" height="600"></canvas>
<p>
<input id="console" type="text"/>
<p>
<div id="message"></div>

<script src="http://www.google.com/jsapi"></script>
<script>google.load("jquery", "1.3")</script>
<script>
	var lastFrame = 0;
	var canvas = document.getElementsByTagName('canvas')[0];
	//var canvas = $('#mainScreen');
	var context = canvas.getContext('2d');
	var total = 0;
	
	var output = context.getImageData(0, 0, canvas.width, canvas.height);
		
	var ws = new WebSocket("ws://127.0.0.1:8080/");
	ws.onmessage = onMessage;

	$(window).unload(function(){
		ws.close();
	});
	$("#mainScreen").mousemove(function(e){
		var ox = $('#mainScreen').offset().left;
		var oy = $('#mainScreen').offset().top;
		var x = e.pageX - ox;
		var y = e.pageY - oy;
		var clientCoords = "" + x + "," + y + "";
		$("#message").text(clientCoords);
		ws.send("a" + clientCoords);
	});
	$("#mainScreen").mousedown(function(e){
		var ox = $('#mainScreen').offset().left;
		var oy = $('#mainScreen').offset().top;
		var x = e.pageX - ox;
		var y = e.pageY - oy;
		var clientCoords = "" + x + "," + y + "";
		$("#message").text(clientCoords);
		ws.send("b" + clientCoords);
	});
	$("#mainScreen").mouseup(function(e){
		var ox = $('#mainScreen').offset().left;
		var oy = $('#mainScreen').offset().top;
		var x = e.pageX - ox;
		var y = e.pageY - oy;
		var clientCoords = "" + x + "," + y + "";
		$("#message").text(clientCoords);
		ws.send("c" + clientCoords);
	});

	function onMessage(m){
		var data = m.data;
		
		if (data.charAt(0) == ">") {
			var canvas = document.getElementsByTagName('canvas')[0];
			var context = canvas.getContext('2d');
			var n = 1;
			
			var frame = (data.charCodeAt(n) << 8) + (data.charCodeAt(n + 1) << 0);
			n += 2;
			if (frame != lastFrame + 1) {
				$('#content').append("error " + lastFrame + '<br>');
			}
			lastFrame = frame;
			
			while (n < data.length) {
				var ox = parseInt("0x" + data.substr(n, 4));
				n += 4;
				
				var y = parseInt("0x" + data.substr(n, 4));
				n += 4;
				var w = parseInt("0x" + data.substr(n, 4));
				n += 4;
				
				var output = context.getImageData(ox, y, w, 1);
				var outputData = output.data;
				for (var x = 0; x < w; x += 1) {
					ptr = x * 4;
					var c = parseInt("0x" + data.substr(n, 6));
					n += 6;
					outputData[ptr + 0] = (c >> 16) & 0xff;
					outputData[ptr + 1] = (c >> 8) & 0xff;
					outputData[ptr + 2] = (c >> 0) & 0xff;
					outputData[ptr + 3] = 255;
				}
				context.putImageData(output, ox, y);
			}
			
			total += data.length;
			
			$('#message').text(data.length + '/' + (total / 1024 / 1024) + 'M');
		}
		if (data.charAt(0) == ">") {
		//		context.putImageData(output, 0, 0);
		}
	}
</script>
</body>
</html>