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>