SyntaxHighlighter

2011-02-26

本「プログラマが知るべき97のこと」

まともな開発なんてやった事の無い人間ですが、イベント会場で安く売っていたので買ってしまいました。

人によっては食い違ってる気がする部分もあるけど(例えば、ある人は、既に動いているプログラムを軽々しく変更すべきではない、というような事を言っていて、別のある人は、プログラムの修正を躊躇うな的な事を言っているような)、直接、プログラムを書いていない人間でも為になる事があるような気がしました。

まわりにあまりプログラマが居ないので、彼らはどういう事を考えているんだろうなあと気になります。

読むと、テスト駆動開発やアジャイル開発とかいうものに入信したくなる、かも????



プログラマが知るべき97のことプログラマが知るべき97のこと
価格:¥ 1,995(税込)
発売日:2010-12-18

2011-02-20

gaeからpicasaに画像を登録する

WebGLでシェーダーの勉強をしていたら、ふと、canvas上のデータを画像として取り出すにはどうしたら良いのだろうと思いました。調べてみると、toDataURL()という関数を使用すると、DataURLという形式で得られるという事を知りました
toDataURL()で得られた値を、imgタグのsrcに設定すれば、そのまま画像が表示されて、右クリックなりで画像を保存を選択すれば、canvasで描写された画像をローカルに保存できるようです。
とすると、今度はこの画像をどこかイメージ保存サービスに楽に保存するにはどうしようかという事が気になってきましたので、ちょっとやってみました。(ちょっとと言っても、結構時間がかかりましたけど)

https://nekonekopic.appspot.com/
※今うまく動きません。。。

  • 動かなかったらすいません。特に認証部分が不思議動作するかも、です
  • アプリが信用できないなら、Picasa登録部分は使用しない方が良いです。画像表示までなら、ログインなしでも遊べます


google app engineとpicasa

とりあえずWebサーバをgaeとして、そこからpicasaに保存する、という方法にしました。

picasaに保存する理由は、gaeで画像データを持つと、あっという間に容量がいっぱいになりそうだったし、そもそもデータをずっと保存しておく自身なんて全くないです。最終データをpicasaに保存しておけば、いつでもこのアプリケーションを消すことができます(gaeのアプリって消せましたっけ??gaeアプリは消せます。。。)。なので多分必要以上に苦労してます。。。

蛇足ですが、アプリのイメージ図。


picasaとかgoogleサービスのAPIを利用するために、ライブラリが提供されているみたいです。これを使えば、生々しくテキストデータを扱わずに済むようです。
このライブラリを使ってpicasaのAPIを使うチュートリアルがあるので、これを参考にして、アルバムやイメージの登録など、基本的に動作できました。

厄介なのが、picasaへの認証方法でした。AuthSubを使いましたが、この部分が動くようになるまでが一番時間がかかったような気がします。。。正しいTokenじゃないとか、Tokenのスコープが違うと何度も怒られたり。。。

AuthSubを頑張っている部分。これが本当に良いのか全く想像がつきません。。。。

def getClient(uri):
user = users.get_current_user()
if user:
gd_client = gdata.photos.service.PhotosService(email=user.email())
# workaround http://code.google.com/p/gdata-python-client/issues/detail?id=184
else:
gd_client = gdata.photos.service.PhotosService()

gdata.alt.appengine.run_on_appengine(gd_client)

session_token = None
authsub_token = gdata.auth.extract_auth_sub_token_from_url(uri)
if authsub_token:
session_token = gd_client.upgrade_to_session_token(authsub_token)
logging.info("session_token=%s" % (session_token))
if session_token and user:
gd_client.token_store.remove_all_tokens()
gd_client.token_store.add_token(session_token)
logging.info("Already login")
elif session_token:
gd_client.current_token = session_token
logging.info("Not Login")

logging.info("AuthSubToken=%s", gd_client.GetAuthSubToken())
if gd_client.GetAuthSubToken():
return gd_client
else:
return None


画像アップロード

ブラウザからは、画像がdataURL形式と呼ばれる、テキストデータで送られてくるので、バイナリに変換する必要があります(多分・・・)。画像本体部分は、Base64エンコードされているようなので、以下の通りに解析しました。全パターン対応していないみたいですけど。


def convertDataURL(self, url):
m = re.match(r'data:(.*);base64,(.*)', url)
if m:
imagedata = {'type':m.group(1), 'data':base64.b64decode(m.group(2))}
return imagedata
return None


Picasaへの画像アップロードはこんな感じ。

def insertPhoto(self, client, albumid, title, image, image_type):
try:
albumurl = "/data/feed/api/user/default/albumid/%s" % (albumid)
photo = client.InsertPhotoSimple(albumurl, albumurl, title, StringIO(image), image_type)
return photo
except  gdata.photos.service.GooglePhotosException:
logging.info(traceback.format_exc())
self.redirect(PicasaAuth.originalURL)


Picasaへの画像登録方法は、このサイトも参考になりました。


セッション中の画像の渡し方

意外に悩んだのがこれ。いくつかページ遷移する間にどうやって画像を渡していこうかと悩んで、必要になるまでサーバ側に画像を送りたくないなあとか、cookieでセッションとか難しいなあ、memcacheオプション使った方が良いのかなあ、等等考えて、結局、一番後腐れが無いだろうという事で、sessionStorageを使う事にしました。画像がdataURLというテキスト形式になっている事も好都合!

コード自体は、練習問題レベルで、
画像を登録

function uploadToAlbum(canvas, url) {
if (!sessionStorage) {
alert("No SessionStorage");
return;
} else {
sessionStorage.setItem("photo", canvas.toDataURL());
window.open(url, null);
}
}


画像をhiddenパラメータに設定、またはimgタグに設定

function setPhoto() {
var input = document.getElementById("photo");
input.value = sessionStorage.getItem("photo");

var img = document.getElementById("capture");
img.src = sessionStorage.getItem("photo");

}


今回思った事。
  • ここまで書いておいてなんですが、このアプリオリジナルって訳ではなくて、似たような事をしているアプリケーションをつい最近、developer summitのHTML5グループの展示でありました。。。
  • 実はPicasaに直接アクセスできるjavascriptがあります、って話になると、この苦労はなんだろうって気になります。
  • 認証系は、場当たり的にやったので怖いです。ちゃんと勉強してからつかいませう。へたにライブラリがあると、よく分からなくても使えてしまうので、危険だなあ・・・
  • 相当我流なので、これが正しいアプリケーションの作り方なのかさっぱり分かりません。ちゃんと勉強しましょう
  • そろそろ3次元も勉強・・・

2011-02-07

webgl+websocket+arduino

先日、webglの勉強会で、kinectをインターフェイスとしてwebglを動かすというデモを見て、感動しました。node.jsやwebsocketを使うと、外部機器からのデータをブラウザに取得出来るようだという事を知ったので、自分も試してみようと思いました。

ここは是非、自分もkinectを!と言いたいところだけど、現在kinectを買うだけの持ち合わせが無いので、とりあえず手元にあるもので、何となく外部機器をwebglを連携してみようかと考え、結局今手元にあるのが、
・Arduino
・ArduinoのEthernetシールド
・ずっと前MTMで買った脈拍センサー
#これ全部そろえると、kinectの半分の値段にはなりそうなんだけどね〜〜〜

とりあえず、今回はこれを使ってみる事にしました。

[Arduino+Ethernetシールド]
node.jsを使ってみようかと思っていたけど、きっとArduino用websocketライブラリがあるに違いないと、探してみたら、cwebsocketというモノが見つかりました。このライブラリのサンプル(echo.pde)を見て、使い方を確認してみた。
120行目あたりにある、

while (!client.available() && client.connected())

が、websocketをopenした後の、クライアントからのデータ待ちを表しているようなので、この部分に、サーバからクライアントへのデータ出力を実施すれば、一方的にクライアントにArduinoが取得したセンサデータを垂れ流せるよう、という事で、以下のようなコードを作成。
while (!client.available() && client.connected()) {
char data[BUF_LEN];
size_t data_len = BUF_LEN;
out_len = BUF_LEN;

HB_GetNextData(&beat_mean, &beat_isbeat, &beat_rate);
HB_toString(beat_mean, beat_isbeat, beat_rate, data, &data_len);
frame_type = ws_make_frame((uint8_t*)data, data_len, buffer, &out_len, WS_TEXT_FRAME);
if (frame_type != WS_TEXT_FRAME) {
terminate();
}
client.write(buffer, out_len);
//        delay(1000);

}; // wait for data


HB_GetNextDataは脈拍センサからデータを取得する(以前自分が勝手に作ったものを少し手直ししただけ)関数で、過去データの平均値と、データが大きく変化したかを表すboolean、計算した心拍数を返します。HB_toStringはそれらデータを文字列に変換する関数でJSON形式にする。以下のような感じになります。

{ "mean":300,"isbeat":false,"rate":60}

これを、websocketで送ります。

このライブラリで複数クライアントへのブロードキャストとかどうするんだろうと気になりますが、気が向いたらやってみたいなあ。。。

[websocket+webgl]

websocketデータの取得は、よくあるサンプルコードそのままです。
var ws;
var heartData;
function initWS() {
ws = new WebSocket("ws://xxx.xxx.xxx.xxx:8080/echo");  #websocketライブラリのechoサンプルを少し改造しただけなので、こんなURLに。。。

ws.onopen = function() {
console.log("Open ws");
};

ws.onmessage = function(evt) {
heartData = JSON.parse(evt.data);
var node = document.getElementById("mean");
node.replaceChild(document.createTextNode(heartData.mean), node.childNodes[0]);
var node = document.getElementById("beat");
node.replaceChild(document.createTextNode(heartData.isbeat), node.childNodes[0]);
var node = document.getElementById("rate");
node.replaceChild(document.createTextNode(heartData.rate), node.childNodes[0]);
}
}


Arduinoからは色々データを送ってみたものの、今回は平均値(mean)に応じて、モデルの大きさを変えるだけの単純なものにしてみました。モデルは単純な球でwebglのプログラムや使用したツール、モデル作成法は以前の記事と大して変わりません。サイズ変更は、球のレンダリングの前に、
function valuemap(value, low1, high1, low2, high2) {
if (value <= low1) return low2;
if (value >= high1) return high2;
return (high2-low2)/(high1-low1) * (value - low1) + low2;
}

if (heartData) {
var s = valuemap(heartData.mean, 200, 700, 0.3, 3);
mvMatrix.scale([s,s,s]);  #現在のモデル行列をスケールするオレオレ関数です。
}

を実行するだけです。heartData.mean値に比例して球のサイズが変わります。

下記のような動画の通り動きます。iPhoneで撮ったので幅が狭いとか、脈拍数低過ぎとか、突っ込みどころは満載ですが。。。



やってみての感想として、Arduino自体がwebsocketのサーバになる今回の構成だとあまり使い道と言うか発展性が無い気がしてます。node.jsとかでサーバを立てておいた方が、細かい事が簡単にできるだろうし(Cはやっぱり文字列とか面倒だし・・・)、複数のArduinoを使いたいとなった場合に、データを集約するサーバにいったん送信して、そのサーバに対してクライアントはアクセスした方が良いんだろうなあと思った次第です。

という事で何の役に立つか分かりませんが、参考までに。
Related Posts Plugin for WordPress, Blogger...