PHP + Mac + Bookmarklet でスクリーンキャプチャしてサムネイルとか

ターミナルを立ち上げて、おもむろに「screencapture test.png」と入力してreturnキーを押下すると画面全体のキャプチャ画像が「test.png」として保存されることになります(PNG形式)。

via: ウノウラボ Unoh Labs: Macでのスクリーンショットの撮り方まとめ

「Command+Shift+3」でスクリーンキャプチャが取れるのは知ってたんだけど、screencapture っていうマンマなコマンドが存在しているのは知りませんでした。
で、コマンドでキャプチャ取れるんならPHPからexecでコマンド実行してWEBページのサムネイル作ったりできるんじゃないか…とか思い付いてしまった。

PHP + Windowsとかなら結構簡単にできちゃうんだよなぁ。
PHP+Windowsでスクリーンショットやサムネイル作成 - Do You PHP はてな
秋元@サイボウズラボ・プログラマー・ブログ: PHP+Windowsでスクリーンショットやサムネイル作成

以下、だらだら続きます。

その1:シェルスクリプトからスクリーンキャプチャ

第1段階として、screencapture コマンドを使ってサイトのキャプチャを取れるようにしてみる。
こんなシェルスクリプト書いてみた。

mac_screencapture.sh
#!/bin/sh

export DYLD_LIBRARY_PATH=""
open -a Safari "$1"
sleep 5
/usr/sbin/screencapture /path/to/save/directory/capture_`date +%Y%m%d%H%M%S`.png

open コマンドで Safari を起動して、ページ読み込みを考えて5秒程スリープ。
で、screencapture コマンドでキャプチャを保存って手順です。
なぜか、DYLD_LIBRARY_PATHという環境変数がエラーになってしまったので無効化してます。
本当は、

unsetenv DYLD_LIBRARY_PATH

とかする気がするんだけどうまくいかなかった。

第1引数でURLを受けるので、

./mac_screencapture.sh http://creazy.net/

とかやると、こういうキャプチャがとれました。

シェルで撮ったキャプチャ
※クリックすると実際のサイズで表示されます。

その2:PHPからスクリーンキャプチャ

さて、その1で撮ったキャプチャはDocやメニューバーなど余計な部分が写ってしまっているので、なんとかブラウザの画面だけ抜き出したいです。
WindowsではCOM経由でウィンドウ情報を取得したりできるのでしょうが、Macではできなそう。
とりあえず、Safariウィンドウの座標XYと縦横幅を自分で調べて切り取るところまでやってくれるPHPスクリプトを書きました。

<?php
if ( $argv ) {             // コマンドモード
    $url = $argv[1];
}
else if ( $_GET['url'] ) { // WEBモード
    $url = $_GET['url'];
}

$file = '/path/to/save/directory/capture_'.date('Ymd_his').'.png';

$cmd  = 'export DYLD_LIBRARY_PATH="";';
$cmd .= 'open -a Safari "'.$url.'";';
$cmd .= 'sleep 5;';
$cmd .= '/usr/sbin/screencapture '.$file.';';
exec($cmd);

$im = imagecreatefrompng($file);

$safari_x = 39;   // SafariウィンドウのX座標
$safari_y = 98;   // SafariウィンドウのY座標
$safari_w = 1225; // Safariウィンドウのドキュメント幅
$safari_h = 685;  // Safariウィンドウのドキュメント高さ

$new_x = 400;     // サムネイルの横幅
$new_y = $safari_h * $new_x / $safari_w;

$newim = imagecreatetruecolor($new_x, $new_y);
imagecopyresampled($newim, $im, 0, 0, $safari_x, $safari_y, $new_x, $new_y, $safari_w, $safari_h);
imagepng($newim, $file);

?>

一応コマンドでも、WEB経由でも実行できるようにしてみました。
下記のように実行すると、

php -f mac_screencapture.php http://creazy.net/

こういうキャプチャがとれました。

PHPで撮ったキャプチャ

おー、ちゃんとサムネイルになってる!

その3:見ているページをスクリーンキャプチャするBookmarklet

その2までの仕組みで、PHPからサムネイルの出力に成功しました。
ということは、サムネイル生成のキューを貯めといて、cronでサムネイル生成スクリプトを実行とかすればSimpleAPIみたいなサムネイルサービスが作れるな。

でも、やっぱりPHP側でWindow情報を取得できていないのでサービスとしてはまだまだ課題が多過ぎるなぁ。
じゃあ、ローカルで動くサムネイラーとしてもっと有効活用できないかと思って考えついたのが見ているページをサムネイル化してくれるBookmarklet

まずは、サムネイル生成用のPHPを用意しますが基本的にはその2のスクリプトの下記部分がパラメータで渡されるという事だけ違うくらい。
・ウィンドウのX座標
・ウィンドウのY座標
・ウィンドウのドキュメント幅
・ウィンドウのドキュメント高さ
・サムネイルの横幅

ローカルでapache + PHPが起動している状態で下記URLにアクセスできるようにする。
http://localhost/mac_screencapture_bookmarklet.php

・mac_screencapture_bookmarklet.phpのソース
<?php
$file = '/path/to/save/directory/capture_'.date('Ymd_his').'.png';
$cmd  = 'export DYLD_LIBRARY_PATH="";';
$cmd .= '/usr/sbin/screencapture '.$file.';';
exec($cmd);

$im = imagecreatefrompng($file);

$x = $_GET['x']; // ウィンドウのX座標
$y = $_GET['y']; // ウィンドウのY座標
$w = $_GET['w']; // ウィンドウのドキュメント幅
$h = $_GET['h']; // ウィンドウのドキュメント高さ

$new_x = $_GET['size']; // サムネイルの横幅
$new_y = $safari_h * $new_x / $safari_w;

$newim = imagecreatetruecolor($new_x, $new_y);
imagecopyresampled($newim, $im, 0, 0, $x, $y, $new_x, $new_y, $w, $h);
imagepng($newim, $file);

?>
・登録するブックマークレット
javascript:(function(){var win=window,doc=document,ua=navigator.userAgent.toLowerCase(),isua=ua.indexOf('opera')+1||ua.indexOf('safari')+1;if(isua){w=win.innerWidth;h=win.innerHeight;}else{w=doc.documentElement.clientWidth||doc.body.clientWidth||doc.body.scrollWidth;h=doc.documentElement.clientHeight||doc.body.clientHeight||doc.body.scrollHeight;}off=140;x=win.screenX;y=win.screenY+off;size=400;s=doc.createElement('script');s.charset='UTF-8';s.src='http://localhost/mac_screencapture_bookmarklet.php?x='+x+'&y='+y+'&w='+w+'&h='+h+'&size='+size;doc.body.appendChild(s);})();
分かりやすい様に展開
javascript:(function(){
  var win  = window;
  var doc  = document;
  var ua   = navigator.userAgent.toLowerCase();
  var isua = ua.indexOf('opera')+1 || ua.indexOf('safari')+1;
  
  // ドキュメントの縦横サイズを取得
  if ( isua ) { // Safari or Opera
    w = win.innerWidth;
    h = win.innerHeight;
  } else {
    w = doc.documentElement.clientWidth || doc.body.clientWidth || doc.body.scrollWidth;
    h = doc.documentElement.clientHeight || doc.body.clientHeight || doc.body.scrollHeight;
  }
  
  off = 140;             // ブラウザのメニューバーの縦幅(自分で調べる)
  x   = win.screenX;     // ドキュメントのX座標
  y   = win.screenY+off; // ドキュメントのY座標(ブラウザのY座標からメニューバーの高さを引く)
  
  size = 400;            // サムネイルのサイズ(任意)
  s = doc.createElement('script');
  s.charset = 'UTF-8';
  s.src = 'http://localhost/mac_screencapture_bookmarklet.php?x='+x+'&y='+y+'&w='+w+'&h='+h+'&size='+size;
  doc.body.appendChild(s);
})();

ブクマークレットならJavaScriptでブラウザの情報が直接確認できるので、それをPHPスクリプトに渡してやれば良い。
唯一、ブラウザのメニューバーを除いたドキュメントの座標の取り方が分からなかったので自分で調べた。

ものさしで調べる

適当に見つけたものさしツールで簡単に計る事ができた。
Free Ruler for Mac OS X
で、オレのFirefoxは140pxだったのでそれをoff変数に代入してある。

さて、このブックマークレットを実行すると、

bookmarkletで撮ったキャプチャ

うん、成功。

Bookmarklet版はWindowサイズを動的に取得できるので、結構汎用的かも。
それに、PHPで画像保存するなら、GDなりImageMagickなりで自分好みに変形したものなんかも作れそう。

まとめ

思い付きからついカッとなってやってみたわけで、結果一応は成功したんだけども、どうにも変態的なコードを書いてしまったような気がする。
PHPでってところにこだわったせいか、なんかまわりくどいんだよなぁ。しかも、ローカルでApache + PHP動いてないといけないとか。

なんかスマートな方法あったら教えて下さい。>エラい人

ブラウザの見えていない部分もスクロールしてキャプチャーする方法色々(無料のみ)

同じカテゴリーの記事

このページの一番上に戻る
  • Facebook
  • Twitter
  • Tumblr
  • Instagram
  • miil