君はもう見たか!php.netの走る象を

なんとやくタイトルに倒置法を使ってみましたが、深い意味はありません。
というのはおいといて、

コアラのマーチには眉毛コアラがたまに入っていて、見つけるとちょっと嬉しいですが、php.netにもそんな遊びが仕掛けられているようです。
先日先輩から、php.netの右上のロゴが走る象になっている人が隣の席にいるという話をされ、気になったので調べてみました。

通常これが表示されているけど、これが走る象になっていたらしいです。
f:id:y_d:20140611231629p:plain

調査

htmlを読んでみると、この画像のURLは下記となっていて、phpのプログラムから画像を返す作りになっていました。
http://www.php.net/images/logo.php

ググってみたところ、どうやらソースは下記のようです。
https://github.com/php/web-php/blob/master/images/logo.php

このソースを読むとどうやら、およそ64回に1回の確率(実際にはもっと確率は低い)、さらに1日キャッシュが効くので64日に1回以下の確率といったところでしょうか。
私は走る象が表示されているところを見たことがありませんが、ちょくちょくphp.netは覗いているので、確率的に今までに走る象を見ていてもおかしくなさそうに思えます。といっても左上のロゴをまじまじと見ることはないので、もしかしたら見逃していただけでしょうか。

※とりあえず象の画像だけ見たい方はこちらでみれます
http://php.net/images/logos/elephpant-running-78x48.gif
f:id:y_d:20140611231910g:plain

実際に表示してみる

仕組みは分かったものの、どうしても実際に走る象が表示されているところを見てみたい気持ちが抑えられないので、無理やり表示してみようと思います。

手順:
f:id:y_d:20140611231303g:plain

  1. phpのロゴ画像URLに「?refresh」を付けたURLを何度か叩いて、走る象の画像を表示する。
  2. php.netを表示して、右上の画像URLもまた同じく「?refresh」をつける。

※URLは http://www.php.net/images/logo.php?refresh になる
php.netさん、リロード何度もしてごめんなさい

これで走る象の画像になりました!
f:id:y_d:20140611231347g:plain

いつかインチキなしで見てみたいです。

Gifアニメを作るChrome拡張Animated Gif Captureを公開しました

f:id:y_d:20140511200605p:plain

「Animated Gif Capture」というアニメーションGifを作るChrome拡張を公開しました。
Chromeに表示中のWebページをアニメーションGifに変換します。また、オプションページから設定を変更すると、デスクトップやChrome以外のウィンドウもアニメーションGifにすることが出来ます。

Chrome Web Storeに登録してあるので、ここからインストールできます。
Chrome Web Store - Animated Gif Capture - アニメーションGifキャプチャ

キャプチャ例

Flashもキャプチャできます。
http://demouth.net/sketch/016/ 以前私がAS3で作ったやつ
f:id:y_d:20140511224420g:plain


FlashのキャプチャできるのでVimeoでもYouTubeもいけます。
フレームレートを高めると滑らかなアニメーションGifになります。
※これは私のVimeo動画です。著作権違反にはお気をつけください
f:id:y_d:20140511225623g:plain


Chrome拡張ではありますが、Chrome以外のウィンドウや、デスクトップ全体のキャプチャも可能です。
これはフレームレートを落とし、撮影時間を長くして、Illustratorをキャプチャしています。
f:id:y_d:20140511225746g:plain

使い方

詳しい使い方はインストール後のオプションページに書いてありますので、インストール後に拡張アイコンを右クリックしてオプションページを表示してください。

あとYouTubeに動画をアップしてあるので、こっちを見ていただくとだいたいわかると思います。
個人的にChrome拡張を使う時一番心配なのは勝手に個人情報にアクセスしてWebにアップしたりしないかという事なのですが、この拡張はWebアクセスはしませんし余計な事は何もしません(当たり前だけど一応)。


How to use Animated Gif Capture - YouTube



以上がアプリの紹介になります。
以降、作った時の技術的な感想をだらだらと書きます。

技術的なこと

Chrome ExtensionはJavaScriptなので、インストールすればソース見られますが、一応Githubにもソースを公開してます。リファクタリングの時間が取れずにソース汚くなっていますが、ソースを公開することで誰かのお役に立てれば幸いです。
demouth/AnimatedGifCapture

基本的に Chrome Extension APIs にすべて必要な情報はあるので、こちらを見ます。

この拡張はキャプチャする方法を3種類の中から選んで設定出来ます。
今回使ったキャプチャを出来るAPIは下記です(あまり確認してないけど、キャプチャ出来るAPIは多分これ以外には無いと思う)。

  • chrome.tabs.captureVisibleTab(integer windowId, types.ImageDetails options, function callback)
  • chrome.tabCapture.capture(object options, function callback)
  • chrome.desktopCapture.chooseDesktopMedia(array of DesktopCaptureSourceType sources, tabs.Tab targetTab, function callback)

tabCaptureはChromeのバージョン31、desktopCaptureは34から使えるようになったようなのでなかなかタイムリーでした。

chrome.tabs.captureVisibleTab()

chrome.tabs.captureVisibleTab()を使うと、コールバックで画像のdataURLが返ってきます。
このAPIは一瞬ではありますがブラウザが固まるのが難点です。アニメーションGifを作るために何度もキャプチャするとChromeのレスポンスが悪くなります。
あと、このAPIで返ってくる画像には、マウスカーソルやセレクトボックスの中身などは映りこみません。

chrome.tabCapture.capture()

chrome.tabCapture.capture()を使うとコールバックにタブの内容を動画と音声で返すLocalMediaStreamオブジェクトを返します。これを使ってタブの中身のキャプチャを撮ります。これをURL.createObjectURL();でvideo要素のsrcに入れると動画を再生できます。あとはこれをcanvas要素を使ってcontext2dにdrawImage()すれば画像に変換出来ます。

var video = document.createElement('video');
video.src = window.URL.createObjectURL(stream);
video.addEventListener('canplay', this.handler);
video.play();

video.srcにstreamを入れると動画の再生が始まるのかと最初思っていましたが、play()しないとvideoに表示される内容は更新されませんでした。後から考えると当たり前かと思いましたが。
あと、タブの動画の再生が始まるまで多少タイムラグがあるようで、canplayイベントの後でないと真っ暗な画像になってしまいました。canplayイベントでなくてもいいかも知れません。

キャプチャする動画のサイズをchrome.tabCapture.capture()の引数に渡すと、その通りの画像サイズでキャプチャしてくれます。タブの中身をキャプチャしたいのでタブのサイズを取得してから渡します。タブのサイズよりも大きなサイズを指定するとタブよりも大きい部分は黒く塗りつぶされた動画が返ってきます。
なお、このAPIはタブのサイズが奇数になると、偶数に丸められ、同時に動画の品質が落ちるようです。この問題をどうにかしようと頑張りましたがどうにもなりませんでした。何か情報をお持ちの方は教えて頂ければと思います。

ちなみにcanvas要素のtoDataURL()メソッドですが、これはtoDataURL('image/webp')のように画像フォーマットを指定できますが、jpegが一番早かったです。
計測結果メモっておけばよかったのですが、残していないので、参考までにざっくりとした感覚値を残しておきます。おそらく画像の内容によっても変換時間は変わると思うのであくまで参考ということで。

  • toDataURL('image/webp') -> ダントツで遅い
  • toDataURL('image/png') -> 速い gifと変わらない
  • toDataURL('image/gif') -> 速い pngと変わらない
  • toDataURL('image/jpeg',1) -> 1番速いけど、png,gifとそんなに変わらない

あと、このAPIで返ってくる動画には、マウスカーソルやセレクトボックスの中身などは映りこみません。

chrome.desktopCapture.chooseDesktopMedia()

desktopCapture APIchrome.tabCapture.capture()と似ていて、動画でキャプチャするAPIです。
tabCaptureと違うのは、chooseDesktopMedia()を呼ぶとウィンドウやデスクトップを選択する為の下記のウィンドウを表示します。
f:id:y_d:20140511212849p:plain
これを使ってウィンドウやデスクトップをユーザーが選択すると、コールバックにstreamIdが返ってきます。
このstreamIdを使ってnavigator.webkitGetUserMedia()に渡すと、tabCaptureと同じようにstreamを取得できます(もしかしてwebkitのプリフィックスいらないかも)。あとはtabCaptureと同じ要領です。下記のような感じ。

    chrome.desktopCapture.chooseDesktopMedia(
      ["screen", "window"] , //ウィンドウとデスクトップどちらも
      function(streamId) {
        if (!streamId) { /* error */ }
        
        navigator.webkitGetUserMedia(
          {
            audio: false,
            video: {
              mandatory: {
                chromeMediaSource: 'desktop',
                chromeMediaSourceId: streamId,
                minWidth: 10,
                maxWidth: 1920,
                minHeight: 10,
                maxHeight: 1080
              }
            }
          },
          function(stream){
            var video = document.createElement('video');
            video.src = window.URL.createObjectURL(stream);
            video.play();
          }
        );
      }
    );

あと、このAPIで返ってくる動画にはマウスカーソルやセレクトボックスの中身は映りこみます。

アニメーションGIFの変換ライブラリ

antimatter15/jsgif を使いました。
※bytearray.orgのAS3の移植!

さすがにGIF画像を作るのは処理時間がかかります。このライブラリの中でWebWorkerを使っているので対象早くなっているかもしれませんが、さすがに画像サイズやアニメーション枚数が多いと数十秒間処理時間がかかります。WebWorkerについてあまり調べていませんが、ライブラリの中を少し覗いてみたところ1スレッドにGIF生成の処理を流し込んでいるようなのでこの辺を書き換えればマルチコアのCPUの時に多少早くなるのかも知れません(たぶん)。

jsgifを使うとgifのdataURLを取得できます。
しかしdataURLは大変重く、ファイルサイズが大きくなった場合ブラウザが死んでしまうこともあるので、バイナリに変換してダウンロードさせています。

http://blog.agektmr.com/2013/09/canvas-png-blob.html
こちらを参考に下記のようなコードでBlobに変換し、ブラウザにダウンロードさせています。

// 空の Uint8Array ビューを作る
var buffer = new Uint8Array(rawData.length);
// Uint8Array ビューに 1 バイトずつ値を埋める
for (var i = 0; i < rawData.length; i++) {
  buffer[i] = rawData.charCodeAt(i);
}
// Uint8Array ビューのバッファーを抜き出し、それを元に Blob を作る
var blob = new Blob([buffer.buffer], {type: 'image/gif'});

var a = document.createElement('A');
a.href = window.URL.createObjectURL(blob);
a.setAttribute('download', filename);
a.click();

Chrome拡張の公開にあたって

f:id:y_d:20140511214654p:plain

Chrome拡張の公開

Chrome拡張をChromeウェブストアに公開する手順は下記を参考にしました。
アイコンの作り方などが紹介されていました(あまり読んでいない)。
https://developer.chrome.com/webstore/publish

デベロッパー ダッシュボードでは言語毎に説明文や画像を設定したり出来ます。

画像について

アプリの画像は下記があると良いです。
試していませんが、おそらく最低限アイコン用の128x128の画像と、ストア用のスクリーンショットが1枚あればいいと思います。

  • アプリ内のアイコン画像 16,19,32,48,128の正方形。manifest.jsonで設定する。
  • ストア用のアイコン画像 128x128である必要がありますが、96x96のアイコンを作って、上下左右に16pxの透明な領域をつける必要があるそうです。
  • ストア用のスクリーンショット1280x800 または 640x400を最大5枚、もしくはYouTube動画。
  • ストア用のプロモーションタイル画像 440x280,920x680,1400x560を1枚ずつ。



以上です。

HappyのPVを1時間で見る

f:id:y_d:20140411065731p:plain

合計24時間あるPharrell WilliamsのHappyのPVを1時間で見られる、24 Hours of Happy in an Hourというページを作りました。

http://demouth.net/sketch/24hoursofhappy-inanhour/

使い方

まず、Google Chromeがインストールされた、ある程度性能のいいデスクトップPC(Mac)を用意します。
用意できなければ諦めます。
※24個の埋込み型YouTubeを再生しますので、性能が低かったりFirefoxだったりすると動きがギクシャクします。


次にこのURLにアクセスします。
http://demouth.net/sketch/24hoursofhappy-inanhour/


しばらくloading表示されるので待ちます。
待ち時間は環境毎に異なりますが、10秒から30秒程ほど待ちます。
※24個の(ry
f:id:y_d:20140411065918p:plain


startボタンが表示されたら、クリックします。
もしも10秒程度待ってもボタンが表示されなければリロードして見て下さい。
※24個(ry
f:id:y_d:20140411065853p:plain


再生開始です。
ZOOMボタンがあるので、モニタサイズに合わせて調整して見て下さい。
f:id:y_d:20140411065731p:plain

経緯

現在4/12付けビルボードで6週連続No.1獲得中のPharrell WilliamsのHappyですが*1、この曲のPVは24時間もある世界初の試みとしても話題になりました。*2

実際このPVを見てみると、異様にテンション高い人やTyler the Creatorなどのミュージシャンが出てたり、なかなか面白く、時間を忘れて見続けてしまいました。

YouTubeだと1動画1時間で区切られていて、それが24動画あるので、1時間単位でしか見られません(プレイリスト使えば連続で見れるけど)。
そこで、24動画を連続で流し続けるページを作ろうと考えましたが、公式サイトで既にそんな事をやってました 。*3

とはいえ折角なのでHappyにまつわる何かを作ろうということで、この24時間あるPVを1時間で見られるページを作りました。
単純にYouTubeの動画24個を並べて再生するだけです。
色やフォントは 24hoursofhappy.com に似せてます。

※去年の曲なので今更感はありますね




以上です。


Girl

Girl

*1:ファレル「ハッピー」が6週連続全米No.1獲得、年間TOP10入りもほぼ確実 http://www.billboard-japan.com/d_news/detail/19110

*2:Pharrell Williams「Happy (The World's First 24 Hour Music Video)」 http://www.iloud.jp/video/pharrell_williamshappy_the_wor.php

*3:http://24hoursofhappy.com/