こんばんわ、isogawaです。
PHP 5.2.2以降には、Windows版限定で一部のスキモノには注目の機能が追加されています。GDライブラリの開発者Pierre-A. Joyeによって実装された、imageGrabScreenとimageGrabWindowのふたつの関数がそれで、それぞれ画面全体と個々のウィンドウをキャプチャーするものです。
これを使えば、例えばInternet Explorerの画面をキャプチャーして、ウェブページのスクリーンショットやサムネイルを簡単に作成できたりします。ウェブページのキャプチャーはすでに色々な方法が知られていますが、標準機能として用意されたことで、(既存の手法と比べて性能面での優劣はさておき)実にお手軽に作成できるようになったわけです。
てなことで、これで遊んでみようと思うのですが。まずもちろん、Windows版PHPの5.2.2以降は必須ですが、これを利用するには、Windowsのサービスとして動作しているウェブサーバに、“デスクトップとの対話をサービスに許可”してやる必要があります。これを設定するには、Windowsコントロールパネルの管理ツールから「サービス」を選び、ウェブサーバがApacheなら、サービスの一覧からApacheを選択して表示される画面の「ログオン」タブで、「デスクトップとの対話をサービスに許可」をチェックして、Apacheを再起動してください。
ではまず試しにInternet Explorerのウィンドウをキャプチャーして、そのサムネイル(ここでは160×120ピクセル)を表示してみましょう。PHPからIEを操作するにはCOMを使用します。
<?php
$url = 'お好みのURLをどーぞ';
if (!extension_loaded('gd')) {
exit('GD library is not loaded.');
} elseif (!function_exists('imagegrabwindow')) {
exit('Function imageGrabWindow is not exist.');
}
try {
$ie = new COM('InternetExplorer.Application');
$handle = $ie->HWND;
$ie->Width = 800;
$ie->Height = 600;
$ie->Visible = true;
$ie->Navigate($url);
while ($ie->Busy) {
com_message_pump(4000);
}
$image = imagegrabwindow($handle);
$ie->Quit();
} catch (Exception $e) {
exit($e->getMessage());
}
if (!$image) {
exit('Failed to grab image.');
}
$thumb = imagecreatetruecolor(160, 120);
imagecopyresampled(
$thumb, $image,
0, 0, 0, 0, 160, 120, 800, 600
);
header('Content-Type: image/jpeg');
imagejpeg($thumb);
ここではIEの起動時のウィンドウサイズを800×600に変更していますが、このようにIE(IWebBrowser2オブジェクト)のプロパティ/メソッドを操作することで、PHPでその動作や見た目を変更できます。IWebBrowser2オブジェクトで利用できるプロパティ/メソッドについてはIWebBrowser2 Interfaceを参照ください。
なお、途中のwhile文では、ページを読み込んでいる最中の画面をキャプチャーしないように、IEがページの読み込みを完了するまで待機しています。
さて、imageGrabScreen/imageGrabWindowが返すのはGDリソースなので、上の例のように、GDを使ってキャプチャー画像をリサイズしたり、あるいは文字や図形を重ねたりと、自由に変形できますが、さてそれではなにをしようかと思ったところで、ここで画像のリサイズコードをだらだらと書いてもしょうがないので、フォト蔵APIを利用して、作成したスクリーンショットをフォト蔵にアップロードしてみることにしました。
以下のスクリプトの実行にはフォト蔵アカウントが必要です。もしまだアカウントをお持ちでなければ是非、登録ページでユーザ登録してください!
- フォト蔵では、写真や動画のアップロードはアルバム単位で行います。以下のスクリプト中で指定するアルバムのIDは、アルバムを表示したページのURL(http://photozou.jp/photo/list/数字/数字)の、末尾のほうの数字になります。例えばこのアルバムの場合、IDは「1771」です。
- 以下ではAPIへのアクセスはPEARのHTTP_Requestで行っています。これがインストールされていない場合は、コマンドプロンプトで「pear install --alldeps HTTP_Request」と叩いてサクっとインストールしてやってください(pearコマンド自体がインストールされていない場合は、まずは「go-pear」を叩いてくださいね)。
<?php
/*
* Photozou username (your email address), password
* and the ID number of the album to which you want to post the image.
*/
$username = 'フォト蔵のユーザ名(メールアドレス)';
$password = 'フォト蔵のパスワード';
$album_id = アップロード先のアルバムのID(数字);
/*
* URL to be displayed in IE.
*/
$url = 'お好みのURLをどーぞ';
/*
* Check if required libraries are available.
*/
require_once 'HTTP/Request.php';
if (!extension_loaded('gd')) {
exit('GD library is not loaded.');
} elseif (!function_exists('imagegrabwindow')) {
exit('Function imageGrabWindow is not exist.');
}
/*
* Launch Internet Explorer and capture the window image.
* Exit if COM throws an exception.
*/
try {
$ie = new COM('InternetExplorer.Application');
$handle = $ie->HWND;
$ie->Width = 800;
$ie->Height = 600;
$ie->Visible = true;
$ie->Navigate($url);
while ($ie->Busy) {
com_message_pump(4000);
}
$image = imagegrabwindow($handle);
$ie->Quit();
} catch (Exception $e) {
exit($e->getMessage());
}
/*
* Save the captured image as a temporary file.
*/
$filename = tempnam(sys_get_temp_dir(), 'tmp');
if (!$image || !$filename || !imagejpeg($image, $filename) || !file_exists($filename)) {
exit('Failed to save image.');
}
imagedestroy($image);
/*
* Post the temporary file to Photozou via API.
*/
$request = new HTTP_Request;
$request->setURL('http://api.photozou.jp/rest/photo_add');
$request->addHeader('User-Agent', 'Hogebot/1.0 (Bogus)');
$request->setBasicAuth($username, $password);
$request->setMethod(HTTP_REQUEST_METHOD_POST);
$request->addPostData('album_id', $album_id);
$request->addFile('photo', $filename, 'image/jpeg');
$result = $request->sendRequest();
/*
* Exit if the API request was failed.
*/
$error_message = '';
$code = $request->getResponseCode();
if (PEAR::isError($result)) {
$error_message = $result->getMessage();
} elseif (!in_array($code, array(200, 401))) {
$error_message = "Responded status code was $code.";
} elseif ('' == $body = $request->getResponseBody()) {
$error_message = 'Responded body was empty.';
} else {
try {
$rsp = new SimpleXMLElement($body);
} catch (Exception $e) {
$error_message = $e->getMessage();
}
if (isset($rsp) and (string) $rsp['stat'] != 'ok') {
$api_error_messages = array();
foreach ($rsp->err as $error) {
$api_error_messages[] = (string) $error['msg'];
}
$error_message = implode("\n", $api_error_messages);
}
}
unlink($filename);
if (!empty($error_message)) {
header('Content-Type: text/plain;charset=UTF-8');
exit($error_message);
}
/*
* Respond HTML if everything went well.
*/
echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<title>Photozou</title>
</head>
<body>
<h1>Image was uploaded.</h1>
<div><?php echo $rsp->large_tag ?></div>
</body>
</html>