Linuxが動くRaspberry Piを買ったのでUnixBenchを走らせてみた

f:id:haru-komugi:20140719121642j:plain

Linuxが動くRaspberry Piを買ったのでUnixBenchを走らせてみました。

Benchmark Run: 土  7月 19 2014 02:43:42 - 03:12:04
1 CPU in system; running 1 parallel copy of tests

Dhrystone 2 using register variables        1656457.1 lps   (10.0 s, 7 samples)
Double-Precision Whetstone                      265.0 MWIPS (10.0 s, 7 samples)
Execl Throughput                                225.1 lps   (29.9 s, 2 samples)
File Copy 1024 bufsize 2000 maxblocks         39541.8 KBps  (30.0 s, 2 samples)
File Copy 256 bufsize 500 maxblocks           12278.8 KBps  (30.0 s, 2 samples)
File Copy 4096 bufsize 8000 maxblocks         92635.9 KBps  (30.0 s, 2 samples)
Pipe Throughput                              172558.1 lps   (10.0 s, 7 samples)
Pipe-based Context Switching                  22772.6 lps   (10.0 s, 7 samples)
Process Creation                                697.9 lps   (30.0 s, 2 samples)
Shell Scripts (1 concurrent)                    402.0 lpm   (60.1 s, 2 samples)
Shell Scripts (8 concurrent)                     51.0 lpm   (60.6 s, 2 samples)
System Call Overhead                         407265.1 lps   (10.0 s, 7 samples)

System Benchmarks Index Values               BASELINE       RESULT    INDEX
Dhrystone 2 using register variables         116700.0    1656457.1    141.9
Double-Precision Whetstone                       55.0        265.0     48.2
Execl Throughput                                 43.0        225.1     52.3
File Copy 1024 bufsize 2000 maxblocks          3960.0      39541.8     99.9
File Copy 256 bufsize 500 maxblocks            1655.0      12278.8     74.2
File Copy 4096 bufsize 8000 maxblocks          5800.0      92635.9    159.7
Pipe Throughput                               12440.0     172558.1    138.7
Pipe-based Context Switching                   4000.0      22772.6     56.9
Process Creation                                126.0        697.9     55.4
Shell Scripts (1 concurrent)                     42.4        402.0     94.8
Shell Scripts (8 concurrent)                      6.0         51.0     85.0
System Call Overhead                          15000.0     407265.1    271.5
                                                                   ========
System Benchmarks Index Score                                          92.8

SDカードはこちらを使用してます。

ちなみにDTIサーバーのVPS@月額467円のUnixBenchはこちら

Benchmark Run: Sat Jul 19 2014 11:45:48 - 12:16:37
2 CPUs in system; running 1 parallel copy of tests

Dhrystone 2 using register variables        6014289.0 lps   (10.0 s, 7 samples)
Double-Precision Whetstone                     1909.0 MWIPS (9.7 s, 7 samples)
Execl Throughput                               1008.7 lps   (29.7 s, 2 samples)
File Copy 1024 bufsize 2000 maxblocks        162326.4 KBps  (30.0 s, 2 samples)
File Copy 256 bufsize 500 maxblocks           49966.4 KBps  (30.0 s, 2 samples)
File Copy 4096 bufsize 8000 maxblocks        376342.0 KBps  (30.0 s, 2 samples)
Pipe Throughput                              453670.3 lps   (10.0 s, 7 samples)
Pipe-based Context Switching                  63863.0 lps   (10.0 s, 7 samples)
Process Creation                               2641.2 lps   (30.0 s, 2 samples)
Shell Scripts (1 concurrent)                   1037.6 lpm   (60.0 s, 2 samples)
Shell Scripts (8 concurrent)                    136.5 lpm   (60.2 s, 2 samples)
System Call Overhead                         815575.3 lps   (10.0 s, 7 samples)

System Benchmarks Index Values               BASELINE       RESULT    INDEX
Dhrystone 2 using register variables         116700.0    6014289.0    515.4
Double-Precision Whetstone                       55.0       1909.0    347.1
Execl Throughput                                 43.0       1008.7    234.6
File Copy 1024 bufsize 2000 maxblocks          3960.0     162326.4    409.9
File Copy 256 bufsize 500 maxblocks            1655.0      49966.4    301.9
File Copy 4096 bufsize 8000 maxblocks          5800.0     376342.0    648.9
Pipe Throughput                               12440.0     453670.3    364.7
Pipe-based Context Switching                   4000.0      63863.0    159.7
Process Creation                                126.0       2641.2    209.6
Shell Scripts (1 concurrent)                     42.4       1037.6    244.7
Shell Scripts (8 concurrent)                      6.0        136.5    227.4
System Call Overhead                          15000.0     815575.3    543.7
                                                                   ========
System Benchmarks Index Score                                         322.0

------------------------------------------------------------------------
Benchmark Run: Sat Jul 19 2014 12:16:37 - 12:52:06
2 CPUs in system; running 2 parallel copies of tests

Dhrystone 2 using register variables        5825325.5 lps   (10.0 s, 7 samples)
Double-Precision Whetstone                     3824.0 MWIPS (9.8 s, 7 samples)
Execl Throughput                               1000.8 lps   (29.9 s, 2 samples)
File Copy 1024 bufsize 2000 maxblocks        162407.4 KBps  (30.0 s, 2 samples)
File Copy 256 bufsize 500 maxblocks           46376.8 KBps  (30.0 s, 2 samples)
File Copy 4096 bufsize 8000 maxblocks        407017.7 KBps  (30.0 s, 2 samples)
Pipe Throughput                              455060.2 lps   (10.0 s, 7 samples)
Pipe-based Context Switching                  60265.6 lps   (10.0 s, 7 samples)
Process Creation                               2825.9 lps   (30.0 s, 2 samples)
Shell Scripts (1 concurrent)                   1092.5 lpm   (60.1 s, 2 samples)
Shell Scripts (8 concurrent)                    143.7 lpm   (60.8 s, 2 samples)
System Call Overhead                         814688.2 lps   (10.0 s, 7 samples)

System Benchmarks Index Values               BASELINE       RESULT    INDEX
Dhrystone 2 using register variables         116700.0    5825325.5    499.2
Double-Precision Whetstone                       55.0       3824.0    695.3
Execl Throughput                                 43.0       1000.8    232.7
File Copy 1024 bufsize 2000 maxblocks          3960.0     162407.4    410.1
File Copy 256 bufsize 500 maxblocks            1655.0      46376.8    280.2
File Copy 4096 bufsize 8000 maxblocks          5800.0     407017.7    701.8
Pipe Throughput                               12440.0     455060.2    365.8
Pipe-based Context Switching                   4000.0      60265.6    150.7
Process Creation                                126.0       2825.9    224.3
Shell Scripts (1 concurrent)                     42.4       1092.5    257.7
Shell Scripts (8 concurrent)                      6.0        143.7    239.4
System Call Overhead                          15000.0     814688.2    543.1
                                                                   ========
System Benchmarks Index Score                                         343.5

Raspberry PiはこちらのOSが入れられるようです。
Downloads | Raspberry Pi

値段も安いですしコンパクトなので、遊ぶにはとてもよいです。

Raspberry Pi Type B 512MB

Raspberry Pi Type B 512MB

誰でもできる!Raspberry Piで楽しもう

誰でもできる!Raspberry Piで楽しもう

画像からSVGアニメーションを作成

f:id:haru-komugi:20140718161732j:plain
画像からSVGアニメーションを作成します。
指定する画像はアニメ系のほうが、見てて楽しいと思います。

サンプルはこちら
http://moeten.info/js/20140718_imageToSVGAnimation/

ソースコードはこちら
index.html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
  <script src="//code.jquery.com/jquery-migrate-1.2.1.min.js"></script>
  <script type="text/javascript" src="./lib/potrace.js"></script>
  <script type="text/javascript" src="./vendor/raphael-min.js"></script>
  <script type="text/javascript" src="./lib/jquery.lazylinepainter-1.4.1.js"></script>
  <script type="text/javascript">

    $(function(){

      //ファイル選択
      /*---------------------------------------------------------------*/
      $("#file").bind("change",function(evt){

        //画像の読み込み
        var files = evt.target.files;
        if(files.length == 0) return;
        var file = files[0];
        if(!file.type.match(/image/)) {
          alert('画像ファイルを選んでください');
          return;
        }
        var reader = new FileReader();
        reader.onload = function(evt) {

          //読み込み画像を設定
          $("#image").attr({"src":reader.result});

          //画像をSVGへ変換
          convertImageToSVG();

        };
        reader.readAsDataURL(file);

      });

      //画像をSVGへ変換
      /*---------------------------------------------------------------*/
      function convertImageToSVG(){

        //画像読み込み
        var img = new Image();
        img.src = $("#image").attr("src");
        img.onload = function(){

          //スタイルの調整
          $("#svg").attr({"width" : img.width ,"height" : img.height});
          $("#demo").css({"width":img.width + "px", "height": img.height + "px"});

          //画像をSVGにして描画
          var result = Potrace.trace( img );
          var path = result._outpath;
          var node = result.toPathElement();
          $("#svg").append(node);

          //アニメーション用パスの作成
          var pathObj = {
            "demo": {
              "strokepath": [
                {
                  "path": path,
                  "duration": 2400
                }
              ],
              "dimensions": {
                "width": img.width,
                "height": img.height
              }
            }
          };
          //console.log(pathObj);

          //SVGアニメーション
          $('#demo').lazylinepainter({
            "svgData": pathObj,
            "strokeWidth": 3,
            "strokeColor": "#e09b99",
            "onComplete" : function(){
              //
            }
          }).lazylinepainter('paint');

        }

      }

    });
  </script>
  <style type="text/css">
    body{
      text-align: center;
    }
    #svg,#demo{
      display: inline;
    }
  </style>
</head>
<body>
<h2>画像からSVGアニメーション</h2>
<input id="file" type="file" name="img"><br/>
<img id="image"/>
<svg id="svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"></svg>
<div id='demo'></div>
</body>
</html>

グーグルプレイスで検索

f:id:haru-komugi:20140718120323j:plain
指定された緯度経度とキーワードを元に、グーグルプレイスで検索し、近い順に表示します。

サンプルはこちら
http://moeten.info/js/20140718_googlePlaceTest/

ソースコードはこちら
index.html

<!DOCTYPE html>
<html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no;" />
  <meta http-equiv="Content-type" content="text/html; charset=utf-8">
  <title></title>
  <script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
  <script src="//code.jquery.com/jquery-migrate-1.2.1.min.js"></script>
  <script type="text/javascript" src="lib/jquery.tmpl.min.js"></script>
  <script type="text/javascript">

    $(function(){

      //初期化
      /*------------------------------------------------------------*/
      function init(){

        //イベントリスナーの登録
        addEventListner();

        //グーグル検索
        getList();

      }

      //イベントリスナーの登録
      /*------------------------------------------------------------*/
      function addEventListner(){

        //タブクリックイベント
        $("#category li").bind("click",function(){

          //選択スタイルの調整
          $("#category li").removeClass("selected");
          $(this).addClass("selected");

          //グーグル検索
          getList();

        });

        //アイテムリストクリックイベント
        $("#resultList li button").live("click",function(){

          //詳細をグーグル検索
          getDetail( $(this).attr("reference") );

        });

      }

      //グーグル検索
      /*------------------------------------------------------------*/
      function getList(){

        //console.log( $("#category .selected").text());

        $.ajax({
          url: "./proxy.php",
          type: "GET",
          data:{
            "keyword": $("#category .selected").text()
          },
          dataType: 'json',
          success: function(data) {

            //console.log( data );
            $("#resultList").html( $("#templateList").tmpl( data.results ) );

          }
        });

      }

      //詳細をグーグル検索
      /*------------------------------------------------------------*/
      function getDetail( reference ){

        $.ajax({
          url: "./proxy2.php",
          type: "GET",
          data:{
            "reference" : reference
          },
          dataType: 'json',
          success: function(data) {

            //console.log( data );
            $("#resultDetail").html( $("#templateDetail").tmpl( data.result ) );

          }
        });

      }

      //初期化
      init();

    });

  </script>
  <style type="text/css">
    .clearfix:after {
      content: ".";
      display: block;
      clear: both;
      height: 0;
      visibility: hidden;
    }
    .clearfix {
      min-height: 1px;
    }
    * html .clearfix {
      height: 1px;
      /*¥*//*/
      height: auto;
      overflow: hidden;
      /**/
    }
    *{
      list-style-type: none;
      padding: 0;
      margin: 0;
      font-size: 14px;
      line-height: 1.5;
    }
    body{
      padding: 10px;
    }
    #category{
      padding-top: 10px;
      padding-bottom: 10px;
    }
    #category li{
      border: 1px solid gray;
      width: 100px;
      text-align: center;
      display: inline;
      padding: 10px;
      border-radius: 5px 5px 0 0;
      cursor: pointer;
    }
    #category .selected{
      background: rgb(255, 250, 229);
    }
    #resultList{
      width: 500px;
      float: left;
      border: 1px solid rgb(184, 184, 184);
      border-radius: 10px;
      padding: 9px;
    }
    #resultList li{
      position: relative;
      border-bottom: 1px solid rgb(184, 184, 184);
      margin-bottom: 9px;
      padding-bottom: 9px;
    }
    #resultList li:last-child{
      border:none;
      padding-bottom: 0;
      margin-bottom: 0;
    }
    #resultList li button{
      position: absolute;
      right: 11px;
      padding: 4px 10px;
      bottom: 23px;
      border-radius: 5px;
      border: 1px solid rgb(206, 206, 206);
      background: rgb(241, 241, 241);
    }
    #resultList li .thum{
      float: left;
      width: 80px;
    }
    #resultList li .info{
      float: left;
      width: 400px;
    }
    #resultDetail{
      float: left;
      border: 1px solid rgb(221, 221, 221);
      padding: 10px;
      border-radius: 10px;
      margin-left: 10px;
      background: rgb(247, 247, 247);
    }
    #resultDetail li .thum{
      float: left;
      width: 80px;
    }
    #resultDetail li .info{
      float: left;
      width: 400px;
    }
  </style>
</head>
<body>
<h1>GooglePlace検索</h1>
<ul id="category">
  <li class="selected">ペットショップ</li>
  <li>ドッグラン</li>
  <li>ドッグカフェ</li>
  <li>ペットホテル</li>
  <li>動物病院</li>
  <li>公園</li>
</ul>
<ul id="resultList"></ul>
<script id="templateList" type="text/x-jquery-tmpl">
<li class="clearfix">
  <div class="thum"><img src="${icon}"></div>
  <div class="info">
    <h3>${name}</h3>
    住所:${vicinity}<br/>
    緯度経度:${geometry.location.lat},${geometry.location.lng}<br/>
    カテゴリー:{{each(key) types}}| ${this} {{/each}}
    <button reference="${reference}" >詳細を見る</button>
  </div>
</li>
</script>
<div id="resultDetail"></div>
<script id="templateDetail" type="text/x-jquery-tmpl">
  <div class="thum"><img src="${icon}"></div>
  <div class="info">
    <h3>${name}</h3>
    住所:${vicinity}<br/>
    緯度経度:${geometry.location.lat},${geometry.location.lng}<br/>
    電話番号:${formatted_phone_number}<br/>
    サイト:<a href="${website}" target="_blank">${website}</a><br/>
    カテゴリー:{{each(key) types}}| ${this} {{/each}}
  </div>
</script>
</body>
</html>

javascriptオンリーですと、クロスドメインに引っかかりますので、PHPなどのプロクシをかませてあげます。

キーワードに該当するお店のリスト取得(プロクシ兼)
proxy.php

<?php
error_reporting(0);

$query = array(
  "language"=>"ja", //言語を日本
  "location"=>"37.4967837,139.9299413", //緯度経度
  "rankby"=>"distance", //距離順に並び替え
  "sensor"=>"false",
  "key"=>"GOOGLE_API_KEY"
);

//javascriptから送られてくるキーワードを設定
$query["keyword"] = $_GET['keyword'];
$url = "https://maps.googleapis.com/maps/api/place/nearbysearch/json?" . http_build_query( $query );

//出力
echo file = file_get_contents( $url );

お店の詳細情報取得(プロクシ兼)
proxy2.php

<?php
error_reporting(0);

$query = array(
  "language"=>"ja", //言語を日本
  "sensor"=>"false",
  "key"=>"GOOGLE_API_KEY"
);

//javascriptから送られてくる参照IDを設定
$query["reference"] = $_GET['reference'];
$url = "https://maps.googleapis.com/maps/api/place/details/json?" . http_build_query( $query );

//出力
echo file = file_get_contents( $url );

グーグルに結構な情報がありますので、うまくすれば簡単にポータルサイトが作れそうですね。

javascriptでQRコードを認識

f:id:haru-komugi:20140717193332j:plain
javascriptQRコードを認識します。

http://moeten.info/js/20140717_qrcodeDetectTest/

ソースコードはこちら

<html>
<head>
  <title>QRCODE</title>
  <script type="text/javascript" src="lib/grid.js"></script>
  <script type="text/javascript" src="lib/version.js"></script>
  <script type="text/javascript" src="lib/detector.js"></script>
  <script type="text/javascript" src="lib/formatinf.js"></script>
  <script type="text/javascript" src="lib/errorlevel.js"></script>
  <script type="text/javascript" src="lib/bitmat.js"></script>
  <script type="text/javascript" src="lib/datablock.js"></script>
  <script type="text/javascript" src="lib/bmparser.js"></script>
  <script type="text/javascript" src="lib/datamask.js"></script>
  <script type="text/javascript" src="lib/rsdecoder.js"></script>
  <script type="text/javascript" src="lib/gf256poly.js"></script>
  <script type="text/javascript" src="lib/gf256.js"></script>
  <script type="text/javascript" src="lib/decoder.js"></script>
  <script type="text/javascript" src="lib/qrcode.js"></script>
  <script type="text/javascript" src="lib/findpat.js"></script>
  <script type="text/javascript" src="lib/alignpat.js"></script>
  <script type="text/javascript" src="lib/databr.js"></script>
  <script type="text/javascript">

    //
    function init() {

      //コールバックの指定
      qrcode.callback = read;

      //QRコードの解析
      qrcode.decode( document.getElementById("qrImage").src );

    }

    //コールバック
    function read( result ){
      alert( result );
    }

  </script>
  <style type="text/css">
    body{
      text-align: center;
    }
  </style>
</head>
<body>
<p><img id="qrImage" src="qr.gif"/></p>
<button onclick="init()">解析</button>
</body>
</html>

日本語が文字化けしたり、表示されなかったりするのはどうやったら修正できるんだろうか・・・

バーコードから商品を検索

f:id:haru-komugi:20140715183939j:plain
バーコードから商品を検索します。

サンプルはこちら
http://moeten.info/js/20140715_barcodeDetectTest/

ソースはこちら
index.html

<!DOCTYPE html>
<html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no;" />
  <meta http-equiv="Content-type" content="text/html; charset=utf-8">
  <title></title>
  <script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
  <script type="text/javascript" src="lib/jquery.tmpl.min.js"></script>
  <script type="text/javascript">

    $(function(){

      //
      var resultArray = [];
      var workerCount = 0;
      var DecodeWorker = new Worker("lib/DecoderWorker.js");
      DecodeWorker.onmessage = function(e){

        //
        if(e.data.success === "log") {
          console.log(e.data.result);
          return;
        }

        //終了して、結果が0の場合はもう一度実行する
        if(e.data.finished) {

          workerCount--;
          if(workerCount) {

            if(resultArray.length == 0) {

              //回転してもう一度実行する
              DecodeWorker.postMessage({
                ImageData: ctx.getImageData(0,0,Canvas.width,Canvas.height).data,
                Width: Canvas.width,
                Height: Canvas.height,
                cmd: "right"
              });

            } else {

              workerCount--;

            }

          }

        }

        //成功イベント
        if(e.data.success){

          var tempArray = e.data.result;
          console.log( tempArray );
          for(var i = 0; i < tempArray.length; i++) {
            if(resultArray.indexOf(tempArray[i]) == -1) {
              resultArray.push(tempArray[i]);

              //
              detectISBN(  (tempArray[i]).split(":")[1].trim() );

            }
          }
          $("#result").html( resultArray.join("<br />") );

        }else{

          if(resultArray.length === 0 && workerCount === 0) {
            $("#result").html("Decoding failed.");
          }

        }

      };

      //
      function DecodeBar(){

        //
        Canvas = document.createElement("canvas");
        Canvas.width=640;
        Canvas.height=480;
        ctx = Canvas.getContext("2d");

        showPicture = document.getElementById("picture");

        ctx.drawImage(showPicture,0,0,Canvas.width,Canvas.height);

        //
        resultArray = [];
        workerCount = 2;
        DecodeWorker.postMessage({
          ImageData: ctx.getImageData(0,0,Canvas.width,Canvas.height).data,
          Width: Canvas.width,
          Height: Canvas.height,
          cmd: "normal"
        });

      }

      //
      function detectISBN( isbnNumber ){

        $.ajax({
          url: "https://www.googleapis.com/books/v1/volumes?q="+isbnNumber+"+isbn",
          type: "GET",
          dataType: 'json',
          success: function(data) {

            //console.log( data );
            $("#resultTable").html( $("#template").tmpl( data.items[0] ) );

          }
        });

      }

      //
      $("#file").bind("change", function(){

        var showPicture = document.querySelector("#picture");
        var files  = event.target.files;
        var file = files[0];
        var URL = window.URL || window.webkitURL;
        var imgURL = URL.createObjectURL(file);
        showPicture.src = imgURL;
        URL.revokeObjectURL(imgURL);
        showPicture.onload = function(){
          DecodeBar();
        }

      });

    });
  </script>
  <style type="text/css">
    *{
      padding: 0;
      margin: 0;
      font-size: 14px;
    }
    body{
      text-align: center;
      padding: 10px;;
    }
    #file{
      background: #ffc578; /* Old browsers */
      background: -moz-linear-gradient(left,  #ffc578 0%, #fb9d23 100%); /* FF3.6+ */
      background: -webkit-gradient(linear, left top, right top, color-stop(0%,#ffc578), color-stop(100%,#fb9d23)); /* Chrome,Safari4+ */
      background: -webkit-linear-gradient(left,  #ffc578 0%,#fb9d23 100%); /* Chrome10+,Safari5.1+ */
      background: -o-linear-gradient(left,  #ffc578 0%,#fb9d23 100%); /* Opera 11.10+ */
      background: -ms-linear-gradient(left,  #ffc578 0%,#fb9d23 100%); /* IE10+ */
      background: linear-gradient(to right,  #ffc578 0%,#fb9d23 100%); /* W3C */
      filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffc578', endColorstr='#fb9d23',GradientType=1 ); /* IE6-9 */
      padding: 10px;
      border-radius: 4px;
      border: 1px solid gray;
      font-weight: bold;
      margin-bottom: 13px;
    }
    #picture{
      max-width: 340px;
      border: 1px solid gray;
      border-radius: 10px;
      box-shadow: 0 0 3px gray;
      margin-bottom: 13px;
    }
    #result{
      border: 1px solid rgb(240, 213, 196);
      border-radius: 4px;
      padding: 10px;
      background: rgb(255, 247, 223);
      margin-bottom: 13px;
    }
    #resultTable{
    }
    #resultTable th{
      width: 20%;
      background: lightgray;
      font-weight: bold;
      padding: 4px;
      border-radius: 4px;
      border: 1px solid rgb(199, 199, 199);
    }
    #resultTable td{
      width: 80%;
      text-align: left;
      padding: 4px;
      border: 1px solid rgb(218, 218, 218);
      border-radius: 3px;
    }
  </style>
</head>
<body>
<input id="file" type="file" accept="image/*" capture="camera">
<div><img alt="" id="picture" width="90%"></div>
<div id="result"></div>
<table id="resultTable"></table>
<script id="template" type="text/x-jquery-tmpl">
  <tr><th>タイトル</th><td>${volumeInfo.title}</td></tr>
  <tr><th>ページ数</th><td>${volumeInfo.pageCount}</td></tr>
  <tr><th>著者</th><td>${volumeInfo.authors}</td></tr>
  <tr><th>出版日</th><td>${volumeInfo.publishedDate}</td></tr>
  <tr><th>説明</th><td>${volumeInfo.description}</td></tr>
  <tr><th>画像</th><td><img src="${volumeInfo.imageLinks.smallThumbnail}"></td></tr>
</script>
</body>
</html>

本棚の書籍管理システムとかいいかもしれませんね。