読者です 読者をやめる 読者になる 読者になる

pblog

pplog.net を作っている @ppworks こと越川直人(Koshikawa Naoto)のブログ。esa LLCで働いてます(\\( ⁰⊖⁰)/)

mixiアプリを作成しました

jOpenSocialを試しつつjQuery事始めを目的としてmixiアプリを作成しました。
何を作ったかというと、うちで飼っている十姉妹のこいつのアテレコする、というとても個人的なアプリです。出来上がった画面がこちら。
f:id:naoto5959:20090504120904j:image
言いたいことも言えないこんな世の中で、心に秘めた叫びをこの小鳥に言わせようというアプリです。機能はこんな感じ。

  • 入力したメッセージを女子高生風のフォントにした画像にして小鳥の画像に重ねて表示
  • メッセージの画像と小鳥の画像を重ね合わせた画像をダウンロード
  • メッセージを音声に変換して再生

画像の重ね合わせイメージ

f:id:naoto5959:20090504141119p:image

アプリの概要図

今回のアプリの概要はこんな感じです。
f:id:naoto5959:20090504134518p:image

  1. javascriptライブラリを読み込む
  2. jOpenSocialを使いOpenSocialコンテナとやりとり
  3. 外部APIを使ってメッセージを画像(base64)に変換
  4. swfにメッセージと変換した画像(base64)を渡す
  5. 外部APIを使ってメッセージを音声に変換

javascriptライブラリに関して

jQueryとjOpenSocialは下記のサイトからダウンロード出来ます。

それぞれのリファレンスはこちらになります。

さて、jOpenSocialjQueryのpluginということで、まずはjQueryから学びます。
一通りの機能を本で学んでから、webサイトのリファレンスを参照するという流れで進めました。参考書籍は

参考サイトは前述の

となります。大抵の機能はこの2つで理解できます。

次に、jQueryを使ってみて気になった点をあげていきます。

jQueryprototype.jsでいうFunction.bindをしたい

opensocial applicationを作っていると、callback関数を指定する場面に頻繁に出くわします。そうした場面で指定するcallback関数のthisを変更したいことがあります。例えば、指定するcallback関数が特定のObjectに結びついていて、callback関数内でそのObjectにひもづく変数にアクセスしたいときなど。これに関しては下記の記事を参考にさせて頂きました。

Cerberus jQueryでprototype.jsのbind()

jQueryを読み込んだ後に以下のような拡張メソッドを定義して利用しました。

/**
 * jQueryでprototype.jsのFunction.bind()と同様の処理を行う拡張
 */
jQuery.scope = function(target,func){ return function() { return func.apply(target,arguments);}};

これでこんなことが出来るようになります。

var FinchEcho = function() {
  var storedKey = "eizokukaNoKey";
  var data = {};

  this.fetchStoredData = function() {
    $.opensocial.data.get(
      storedKey,
      "owner",
      $.scope(this, this.fetchStoredData_Result),
      false
    );
  };
  
  this.fetchStoredData_Result = function(res) {
    data = res;
    this.renderStoredData();
  };

  this.renderStoredData = function() {
    // なんたらかんたら
  };
};
var echo = FinchEcho();
echo.fetchStoredData();
jQueryでjson encodeをつかう

画像のダウンロード部分と音声出力の部分でFlashを使っているのですが、SWFへFlashVarsを渡す際にJSONでencodeしたObjectを渡しています。jQueryでjson encodeするにはjquery-jsonというjQueryのpluginを利用しました。
使い方はこんな感じです。

var flashvars = {
  param1:"hogehoge",
  param2:{
    "さらにオブジェクト"
  }
};
var json = $.toJSON(flashvars);

なお、swfobjectに渡す際にはURIエンコードして渡してあげないとIEで正常に値が渡せないので注意しましょう。

swfobject.embedSWF(
  "http://l.ead.me/echo/1/download.swf", "externalswf", "600", "50", "10.0.0",
  undefined,
  {
    json: encodeURIComponent(json) // URIエンコードしよう
  }, // flashvars
  {
     quality : 'high'
  }, // params
  {
     id : "swf"
  } // attributes
);
jQueryでブラウザ判定

$.browserを使うだけで出来ました。どうやら1.3以降ではサポート外のようです。今回は、叫んだメッセージの画像の表示部分にdata schemeを利用しているのでIEでは元の画像を見にいく判定を付けるために使いました。data schemeのサポート判定が$.supportで出来れば、そちらに移行すべきですかね。

jQuery日本語リファレンス jQuery.browser

jOpenSocialを使いOpenSocialコンテナとやりとり

を読めば使えると思います。標準のOpenSocial JavaScript APIを使ったことがあれば、このラクチンさ加減に衝撃を受けつつ、すぐに使いこなせるようになるかと思います。

気になった点をメモしておきます。

jOpenSocialでOwnerとViewerが一致するか調べる

mixiアプリではUserPrefが使えないので、Ownerのcanvasビューにおいて色々な設定を行うことが多いかと思います。その際に現在のOwnerとViewerが同じであるかの判定が必要となります。その際には$.opensocial.personを使います。Ownerの場合はsetting idで指定された要素を表示するには以下のようにします。便利ですね。

<div id="setting" style="display:none">
<form>
<input type="text" id="message" />
</form>
</div>
<script type="text/javascript">
var isOwner = false;
$.opensocial.person("OWNER", function(data) {
  if (data.isOwner() && data.isViewer()) {
    isOwner = true;
    $('#setting').show();
  }
});
</script>

外部APIを使ってメッセージを画像(base64)に変換

女子高生風のフォントは、

ふい字置き場

から「おひさまフォント」を使わせて頂きました。メッセージを女子高生風のフォントに変換するAPIPHPImageMagickを利用して作成しました。

validationとかを省略したソースはこんな感じ。

<?php
$size = $_REQUEST["size"];
$text = $_REQUEST["text"];
$raw = $_REQUEST["raw"];

$image = new Imagick();
$image->newImage(200, 350, "none");

$draw = new ImagickDraw();
$draw->setFont('OhisamaFontB11.ttf');
$draw->setFontSize($size);
$draw->setFillColor('#ffffff');
$draw->setTextEncoding('UTF-8');

$draw->annotation(0, $size, $text);

$image->drawImage($draw);
$image->setImageFormat('png');

if ($raw) {
    header('Content-type:image/png');
    echo $image;
} else {
    echo json_encode("data:image/png;base64," . base64_encode($image));
}

$draw->destroy();
$image->destroy();
?>

指定した文字列を画像を返す、または画像をbase64に変換して返す、という処理を行っています。data schemeに対応したブラウザでは、base64に変換した文字列をOpenSocialコンテナの永続化データに保存しておけば、毎回APIに変換してもらう必要がなくなります。ただし、data schemaに対応していないブラウザ(IEって知ってますか?)では毎回APIに変換してもらう必要があるため、この処理を行います。

swfにメッセージと変換した画像(base64)を渡す

今回作成したアプリではswfは

  • メッセージのダウンロード
  • メッセージの音声出力

に使います。まずはメッセージのダウンロードについて

メッセージのダウンロード

先に示した通り、今回のアプリでは画像を重ねて表示しているだけなので、それを保存するだけでは別々の画像となってしまいます。そこで、FLASHを使って、base64エンコードされた画像と小鳥の画像を合成して出力してあげます。
そもそも画像を重ねて表示する部分でFLASH使えばいいんですが、今回は色々勉強用に無駄なことをしていることをご理解下さい。
base64エンコードされた画像はFlashVarsを通して、受け取ります。JSONで渡しているのでデコードします。デコードは以下のように行います。JSON.encodeは、adobeのas3corelibを使っています。便利ですね.

var json:String = loaderInfo.parameters.json;
var param:Object = com.adobe.serialization.json.JSON.decode(decodeURIComponent(json));

base64エンコードされた画像の読み込みはLoaderを使います。Base64 classも合わせて。

var _loaderMessage:Loader = new Loader();
_loaderMessage.loadBytes(new Base64(_encodedImage));
class Base64 extends ByteArray {
  private static const BASE64:Array = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,62,0,0,0,63,52,53,54,55,56,57,58,59,60,61,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,0,0,0,0,0,0,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,0,0,0,0,0];
  public function Base64(str:String) {
    var n:int, j:int;
    for(var i:int = 0; i < str.length && str.charAt(i) != "="; i++) {
      j = (j << 6) | BASE64[str.charCodeAt(i)];
      n += 6;
      while(n >= 8) {
        writeByte((j >> (n -= 8)) & 0xFF);
      }
    }
    position = 0;
  }
}

画像の合成では、BitmapDataのdrawとJPEGEncoderを使います。こんな感じ。JPEGEncoderもadobeのas3corelibです。もはや標準ライブラリ。

bitmapData.draw(_base); // _base(:Sprite)には重ね合わせた画像が入っている
var encoder:JPGEncoder = new com.adobe.images.JPGEncoder(80);
_byteArray = encoder.encode(bitmapData);

外部APIを使ってメッセージを音声に変換

これは、矢野さとるさんのAPIを利用しています。

文字音声変換API "TEXT2VOICE"

FLASHの実装は、以下の記事を参考にさせて頂きました。

alt 文字音声変換API「TEXT2VOICE」を使ってみる

まとめ

IEではdata schemeが利用出来ないので、フルFLASHで作った方が良かったのではないかという結論。でも色々勉強になったのでよしとします。
mixiアプリを使ってみようという奇特な方は下記からどうぞ。