ExifUtil.js

ExifUtil.js

Contents

ExifUtil.js とは?

ExifUtil.js は JPEG 形式の画像ファイルに埋め込まれている Exif を Javascript から読み出すためのライブラリです.

通常,デジタル一眼レフやデジカメで撮影した画像には,Exifという規格にそっ て,撮影条件や撮影場所等の様々な情報が記録されています.このページで紹 介している ExifUtil.js を使用すると,サーバ側のプログラム無しで画像に埋 め込まれたそれらの情報にアクセスできます.

具体的にどんなことができるかは 便利な活用方法 を参照してください.気に入れ ばコピペするだけですぐに利用可能です.

ライセンス

Mozilla Public License (Mozilla Public License の翻訳) に従います.

ダウンロード

依存関係

ExifUtil.js の動作には jQuery.js が必要です.

使い方

ライブラリとして使う

もっともシンプルな,単品ライブラリとして使う方法ついてコード例をベース に説明します.

ライブラリの取り込み

HTML の<head>~<head>内に下記を挿入して,ライブラリをロードするようにします.

<script type="text/javascript" src="./js/jquery.js"></script>
<script type="text/javascript" src="./js/exifutil.js"></script>

Exifの読み出し

読み出しは,下記のように ExitUtil.Simple オブジェクトの readURL メソッ ドを使って行います.例では,id=sample の画像ファイルの Exif を読み出しています.

jQuery(document).ready(function() {
    var util = new ExifUtil.Simple();
    util.readURL($('#sample').attr('src'), function(tiffTagMap) {
        // Exif等の情報が tiffTagMap に入っている
    });
});

Exifの表示

読み出した Exif は ExifUtil.Pretty に含まれる関数を使用して分りやすく表 示することができます.例では,ExifUtil の別名である $E を使用しています.

var html = '';
html += 'カメラの型式: ' + $E.Pretty.model(tiffTagMap) + '<br/>';
html += 'レンズの型式: ' + $E.Pretty.lensModel(tiffTagMap) + '<br/>';
html += '写真の解像度: ' + $E.Pretty.resolution(tiffTagMap) + '<br/>';
html += '撮影時の焦点距離: ' + $E.Pretty.focalLength(tiffTagMap) + '<br/>';
html += '撮影時の絞り: ' + $E.Pretty.aperture(tiffTagMap) + '<br/>';
html += '撮影時のシャッター速度: ' + $E.Pretty.exposureTime(tiffTagMap) + '<br/>';
html += '撮影時のISO感度: ' + $E.Pretty.isoSpeed(tiffTagMap) + '<br/>';

全体サンプル

以上をまとめたサンプルソースとその表示例を以下に示します.

<?xml version="1.0" encoding="utf-8" ?>
  <!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" />
    <title>Sample Page 1 for ExifUtil.js</title>
    <script type="text/javascript" src="./js/jquery.js"></script>
    <script type="text/javascript" src="./js/exifutil.js"></script>
    <script type="text/javascript">
    jQuery(document).ready(function() {
        var util = new ExifUtil.Simple();
        util.readURL($('#sample').attr('src'), function(tiffTagMap) {
            var html = '';
            html += 'カメラの型式: ' + $E.Pretty.model(tiffTagMap) + '<br/>';
            html += 'レンズの型式: ' + $E.Pretty.lensModel(tiffTagMap) + '<br/>';
            html += '写真の解像度: ' + $E.Pretty.resolution(tiffTagMap) + '<br/>';
            html += '撮影時の焦点距離: ' + $E.Pretty.focalLength(tiffTagMap) + '<br/>';
            html += '撮影時の絞り: ' + $E.Pretty.aperture(tiffTagMap) + '<br/>';
            html += '撮影時のシャッター速度: ' + $E.Pretty.exposureTime(tiffTagMap) + '<br/>';
            html += '撮影時のISO感度: ' + $E.Pretty.isoSpeed(tiffTagMap) + '<br/>';

            $('#exif').empty();
            $('#exif').append(html);
        });
    });
    </script>
  </head>
  <body>
  <img src="img/sample1.jpg" width="256" height="171" id="sample" />
  <div id="exif" style="font-family: 'Lucida Console'; font-size: 11pt; margin: 1em;" />
</body>
</html>

jQuery plugin として使う

jQuery のプラグインとして使用する場合,loadExif メソッドと exif メソッドを使用します. 実際の使い方は以下を参照してください.

<?xml version="1.0" encoding="utf-8" ?>
<!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" />
    <title>Sample Page 2 for ExifUtil.js</title>
    <script type="text/javascript" src="./js/jquery.js"></script>
    <script type="text/javascript" src="./js/exifutil.js"></script>
    <script type="text/javascript">
    jQuery(document).ready(function() {
        $('#sample').loadExif(
            function() {
                var image = $('#sample');
                var html = '';
                html += 'カメラの型式: ' + image.exif().model + '<br/>';
                html += 'レンズの型式: ' + image.exif().lensModel + '<br/>';
                html += '写真の解像度: ' + image.exif().resolution + '<br/>';
                html += '撮影時の焦点距離: ' + image.exif().focalLength + '<br/>';
                html += '撮影時の絞り: ' + image.exif().aperture + '<br/>';
                html += '撮影時のシャッター速度: ' + image.exif().exposureTime + '<br/>';
                html += '撮影時のISO感度: ' + image.exif().isoSpeed + '<br/>';

                $('#exif').empty();
                $('#exif').append(html);
            }
        );
    });
    </script>
  </head>
  <body>
    <img src="img/sample2.jpg" width="360" height="230" id="sample" />
    <div id="exif" style="font-family: 'Lucida Console'; font-size: 10pt; margin: 1em;" />
  </body>
</html>

便利な活用方法

AF ポイントを表示する

MakerNote に記録されている AF ポイントについての情報と HTML5 の Canvas 機能を使えば,写真に AF の情報をオーバレイ表示することができます.

以下の例では,写真にポインタを重ねると AF 情報を表示するようになっています(すぐに表示されない場合,少し待ってみてください). 手間の関係でCanonAFInfo2を含んだ写真のみ対応.

<?xml version="1.0" encoding="utf-8" ?>
<!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" />
    <title>Sample Page 4 for ExifUtil.js</title>
    <!--[if IE]><script type="text/javascript" src="./js/excanvas.js"></script><![endif]-->
    <script type="text/javascript" src="./js/jquery.js"></script>
    <script type="text/javascript" src="./js/exifutil.js"></script>
    <script type="text/javascript">
      var mapList = {};
      jQuery(document).ready(function() {
          var util = new ExifUtil.Simple();
          $('img').each(function() {
              var image = $(this);
              util.readURL(image.attr('src'), function(map) {
                  mapList[image.attr('id')] = map;

                  image.mouseenter(function() {
                      drawFocusInfo(this.id);
                  });
              });
          });
      });
      function drawFocusInfo(id) {
          var afInfo = $E.Pretty.afInfo(mapList[id]);

          var areaDrawing = document.createElement('canvas');
          var labelDrawing = document.createElement('div');

          if (document.uniqueID) {
              areaDrawing = G_vmlCanvasManager.initElement(areaDrawing);
          }

          var image = $('#' + id);

          var labelHeight;
          var lineWidth;

          if ((image.width() < 400) || (image.height() < 400)) {
              labelHeight = 20;
              lineWidth   = 2;
          } else {
              labelHeight = 40;
              lineWidth   = 4;
          }

          drawFocusArea(image, areaDrawing, afInfo, lineWidth);
          drawFocusLabel(image, labelDrawing, afInfo, labelHeight);

          image.parent().append(labelDrawing);
          image.parent().append(areaDrawing);

          $(areaDrawing).mouseleave(function() {
              $(areaDrawing).fadeOut(500, function() { $(this).remove(); });
              $(labelDrawing).fadeOut(500, function() { $(this).remove(); });
          });
          $(areaDrawing).fadeIn(400, function() {
              $(labelDrawing).fadeIn(400);
          });
      }
      function drawFocusLabel(image, div, afInfo, labelHeight) {
          div.width = image.width();
          div.height = labelHeight;
          $(div).css({
              top                : image.position().top + (image.height() - labelHeight),
              left               : image.position().left,
              width              : image.width(),
              'text-align'       : 'center',
              'font-size'        : labelHeight * 2/3,
              'font-family'      : 'Verdana,"BitStream vera Sans",Tahoma,Helvetica,Sans-serif',
              height             : labelHeight,
              'background-color' : '#FFFFFF',
              position           : 'absolute',
              opacity            : 0.75,
              display            : 'none'
          });
          $(div).text('AF MODE: ' + afInfo.mode);
      }
      function drawFocusArea(image, canvas, afInfo, lineWidth) {
          var areaInfo = afInfo.areaInfo;

          canvas.width = image.width();
          canvas.height = image.height();
          $(canvas).css({
              top      : image.position().top,
              left     : image.position().left,
              position : 'absolute',
            display    : 'none'
          });

          var ctx = canvas.getContext('2d');
          var ww = image.width();
          var www2 =  afInfo.width;
          var scale = image.width() / afInfo.width;

          ctx.lineJoin = "round";
          ctx.lineWidth = lineWidth;
          ctx.shadowColor = "#ffffff";

          ctx.shadowBlur = lineWidth;


          for (var i = 0; i < areaInfo.length; i++) {
              if (areaInfo[i].focus) {
                  ctx.strokeStyle  = "red";
              } else if (areaInfo[i].selected) {
                  ctx.strokeStyle  = "black";
              } else {
                  ctx.strokeStyle  = "gray";
              }
              ctx.strokeRect((areaInfo[i].x + afInfo.width/2 - areaInfo[i].width/2)*scale,
                             (-areaInfo[i].y + afInfo.height/2 - areaInfo[i].height/2)*scale,
                             areaInfo[i].width*scale, areaInfo[i].height*scale);
          }
      }
    </script>
  </head>
  <body>
    <img src="img/sample3.jpg" width="259" height="173" id="sample3" />
    <hr />
    <img src="img/sample4.jpg" width="259" height="173" id="sample4" />
  </body>
</html>

Goole Maps との連携

位置情報が記録された写真であれば,Google Maps と連携させて,写真を撮影した場所を表示することができます.

以下の例では,撮影場所をマーカで表示しています.

<?xml version="1.0" encoding="utf-8" ?>
<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" />
    <title>Sample Page 5 for ExifUtil.js</title>
    <script type="text/javascript" src="./js/jquery.js"></script>
    <script type="text/javascript" src="./js/exifutil.js"></script>
    <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
    <script type="text/javascript">
      jQuery(document).ready(function() {
          var util = new ExifUtil.Simple();
          util.readURL($('#sample5').attr('src'), function(tiffTagMap) {
              var gpsLocation = $E.Pretty.gpsLocationAsDeg(tiffTagMap);
              var latlng = new google.maps.LatLng(gpsLocation.latitude,
                                                  gpsLocation.longitude);
              var map = new google.maps.Map(
                  document.getElementById('map'),
                  {
                      zoom: 15,
                      center: latlng,
                      mapTypeId: google.maps.MapTypeId.HYBRID
                  }
              );
              var marker = new google.maps.Marker({
                  position : latlng,
                  map      : map,
                  clickable: false
              });
          });
      });
    </script>
  </head>
  <body>
    <div><img src="img/sample5.jpg" width="256" height="171" id="sample5" style="float: left; margin-bottom: 15px" /></div>
    <div id="map" style="width:280; height:180;clear: left;" />
  </body>
</html>

jQuery lightBox plugin との組み合わせ

ExifUtil.js は jQuery lightBox plugin と組み合わせ使用することができます. 例えば jquery.lightbox.js に下記の修正を加えることで,キャプションにカメラの情報を表示することができます.

表示例は, デモページ を参照してください.

@@ -228,8 +228,10 @@
                function _show_image() {
                        $('#lightbox-loading').hide();
                        $('#lightbox-image').fadeIn(function() {
-                               _show_image_data();
-                               _set_navigation();
+                               $('#lightbox-image').loadExif(function() {
+                                       _set_navigation();
+                                       _show_image_data();
+                               });
                        });
                        _preload_neighbor_images();
                };
@@ -240,13 +242,24 @@
                function _show_image_data() {
                        $('#lightbox-container-image-data-box').slideDown('fast');
                        $('#lightbox-image-details-caption').hide();
+                       var caption = '';
+                       var image = $('#lightbox-image');
+                       if ( image.existsExif() ) {
+                               caption += 'カメラ: ' + image.exif().model + '<br/>';
+                               caption += 'レンズ: ' + image.exif().lensModel + '<br/>';
+                               caption += '焦点距離: ' + image.exif().focalLength + '<br/>';
+                               caption += '絞り: ' + image.exif().aperture + '<br/>';
+                               caption += 'シャッター: ' + image.exif().exposureTime + '<br/>';
+                               caption += '感度: ' + image.exif().isoSpeed + '<br/>';
+                       }
                        if ( settings.imageArray[settings.activeImage][1] ) {
-                               $('#lightbox-image-details-caption').html(settings.imageArray[settings.activeImage][1  ]).show();
+                               caption += settings.imageArray[settings.activeImage][1];
                        }
+                       $('#lightbox-image-details-caption').html(caption).show();

jQuery lightBox Exif plugin

jQuery lightBox Exif version 0.0.5 をベースに上記の修正を行ったものは下記からダウンロード可能です.

使い方等は,元となった jQuery lightBox plugin と同じで す.jquery.lightbox.js の替わりに,jquery.lightbox_exif.js と exifutil.js を読み込んでください.

Javascript EXIF Reader との違い

ExifUtil.js は Javascript EXIF Reader のコードをベースとしてつくられ ています.基本的な機能は同等ですが下記の点が異なります.

参考文献

プログラムの作成にあたってお世話になった文献を紹介します.

デジタルスチルカメラ用 画像フォーマット規格 Exif 2.3
現時点(2010/10/3)で一番新しい Exif の規格.以前のバージョン 2.21 と比較して レンズ情報等が記録できる ようになっています.PDF にロックがかけられており,ページ中の文字列がコピーできないので使い買ってはいまひとつ.
Exchangeable image file format for digital still cameras: Exif Version 2.2
Exif 2.21 の規格.ページ中の文字列が普通にコピーできるので便利.
ExifTool Tag Names
メーカ独自の MakerNote の解析は ExifTool のこのページを参照して実装しました. 情報量が凄いです.