Chromeから画面スクリーンショットを定期的にとる

1分に1度今の画面の様子をスクリーンショットをとって、実際自分の開発のときどういう風な画面を経ているかというのが知りたくなった。
Chrome Extension には、画面のキャプチャをとるAPIが用意されているので、そちらを使ってみることにした。

## manifest.json を用意

[ChromeExtension の Tutorial はこちら](https://developer.chrome.com/extensions/getstarted)

permission には、`desktopCapture` を指定。

```json
{
  "name": "Screen Share",
  "description": "Big Brother is watching you!",
  "version": "0.1",
  "manifest_version": 2,
  "icons": {
    "16": "icon.png",
    "128": "icon_128.png"
  },
  "background": {
    "scripts": [
      "background.js"
    ]
  },
  "permissions": [
    "desktopCapture"
  ],
  "browser_action": {
  }
}
```

同じフォルダに `icon.png` と `icon_128.png` も設置しておく。

## background.js

アイコンがクリックされたら、画面を開くようにする

```js
chrome.browserAction.onClicked.addListener(function () {
  chrome.windows.create({
    url: "index.html",
    focused: true,
    type: "popup"
  });
});
```

## index.html

とりあえず、画面キャプチャのstreamを受けるvideoと、canvasを用意

```html
<video id="video" autoplay style="display: none;"></video>
<canvas id="canvas" height="200" width="300"></canvas>
<button id="start">Start</button>
<script src="app.js"></script>
```

## app.js


```js
var video = document.getElementById('video');
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');

var interval = 60000;

// screenshot をとり、送信
var screenshot = function () {
  context.drawImage(video, 0, 0, canvas.width, canvas.height);
  canvas.toBlob(function (blob) {
    var fd = new FormData();
    fd.append('file', blob, 'screen.png');
    fetch('http://localhost:9999/image.php', {
      method: 'POST',
      body: fd
    })
  });
};

document.getElementById("start").addEventListener("click", function (e) {
  chrome.desktopCapture.chooseDesktopMedia(
    ["screen", "window"], function (streamId) {
      navigator.webkitGetUserMedia(
        {
          audio: false,
          video: {
            mandatory: {
              chromeMediaSource: "desktop",
              chromeMediaSourceId: streamId
            }
          }
        },
        function (stream) {
          video.src = URL.createObjectURL(stream);
          // ちょっと delay を与えないとうまくとれなかった。
          // もうちょっとなんとかなる方法ないか探し中。
          setTimeout(function () {
            screenshot();
          }, 1000);
          setInterval(function () {
            screenshot();
          }, interval);
        },
        function () {
          alert("error");
        }
      );
    }
  );
});
```

## サーバサイド

**セキュリティ対策も何もないPHPスクリプト。本番では使えない。**
将来的にWebアプリにする実験をしようという体で、PHPアプリに転送する実験のために書いた、シンプルなもので、ローカル動作確認以外では、利用してはいけません。
`upload` フォルダにひたすら画像を書いていくだけです。

```php
<?php
// Extension からリクエストを受け入れるため、とりあえずCORSで全許可！
header('Access-Control-Allow-Origin:*');

if($_SERVER["REQUEST_METHOD"] == 'POST') {
    if (isset($_FILES['file'])) {
        $file = $_FILES['file'];
　　　　　　　　　　　　　　　　// 適当。本来は、mime_content_type とかをチェックしたり、
        // gd使ってマジックバイト調べなきゃ。。
        if (preg_match('/\A(.*)\.png\z/', $file['name'], $match)) {
            $tmpFile = $_FILES['file']['tmp_name'];
            $dir = __DIR__.'/upload/'.$match[1];
            // race condition の危険があるので、本来はhttps://twitter.com/symfony_en/status/678882205284855808 とかやらんと。
            if (!file_exists($dir)) {
                mkdir($dir);
            }
            move_uploaded_file($tmpFile, $dir.'/'.date('YmdHis').'.png');
        }
    }
}
```

こちらは適当なサーバで、動作させておく。 (今回は `http://localhost:9999/upload.php` で動作)

## Chromeでパッケージを読み取り

`chrome://extensions/` を開いて、「デベロッパーモード」にする。
そうすると「パッケージ化されていない拡張機能を読み込む...」というのがあるので、今回作った成果物のフォルダを読み取り。

![image](https://qiita-image-store.s3.amazonaws.com/0/61997/7ae053f1-fb88-e1c0-2e6f-88388752fc6a.png)

Chrome にアイコンが追加されると思うので、そこを押す。
Startボタンのあるウィンドウが表示されるので、Startを押下すると、「画面の共有」画面が開き、ウィンドウを選択できる。選択して、共有開始する。

![image](https://qiita-image-store.s3.amazonaws.com/0/61997/1d9beb51-de7f-bbe0-7190-082c16ba4b64.png)


## 結果

こんな感じで、どんどんキャプチャを保管しておく機能ができた。

![image](https://qiita-image-store.s3.amazonaws.com/0/61997/cdbfd9dc-760b-e218-7c72-fe1811f39e24.png)


## まだ解決してない事項

デスクトップキャプチャからとった情報の縦横比を、そのままの比率で保存できていない。
一旦、300x200の canvas に、置いているだけだからである。
stream や video から情報の縦横比を求めなきゃいけないが、まだどうやるか検討がついていない。


## 参考にした記事

- [Chromeアプリ：screen shareを作りたい（DesktopCapture編）](http://qiita.com/simanezumi1989/items/e9e74ecfcf5a3f595502)
- [お疲れさまXMLHttpRequest、こんにちはfetch](http://qiita.com/tomoyukilabs/items/9b464c53450acc0b9574)