JSでExif情報を取得する方法 ② ~iOSの写真の回転~

2016年12月20日

はじめに

前回 JSでExif情報を取得する方法 でExif情報をJSで取得する方法について紹介しました。

iOSでHTML5を使ってカメラ画像を取得して、Canvasへ貼り付けると、変な回転がされて貼り付けられてしまいます。imgタグに貼り付けると回転がなく、ちゃんと張れます。実はこれ、imgタグの画像は、Exif情報を読み取って、ブラウザが適切に回転させて表示してくれているからなんです。Canvasに貼り付けて表示する場合は、Exif情報が欠落するので、変な回転がかかって貼り付けられてしまいます。でも、画像の加工をするには、まずCanvasに貼り付けますよね。

そういうとき、前回のExif情報を取得するして回転情報を得ると、上手に貼り付けられるので紹介します。

まずはソースコード(変に回転してしまうバージョン)

何も考えずにカメラからプレビューを表示するHTML

<!doctype html>
<html lang="ja">

<head>
  <meta charset="utf-8">
  <title>ExifSample</title>
  <script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
</head>

<body>
  <p> カメラから読み取ってプレビュー </p>
  <input type="file" id="photo" accept="image/*;capture=camera" onchange="loadFile()" value="Camera">

  <p> imgタグ きっと回転されない</p>
  <img id="photo_img" src="">

  <p> canvasタグからのコピー iOSだと変に回転する</p>
  <canvas id="mycanvas" ></canvas>

  <script>
    function loadFile() {
      var canvas = document.getElementById('mycanvas');
      var fr = new FileReader();
      fr.onload = function (evt) {
        // imgタグへ画像の貼り付け
        $("#photo_img").attr("src", evt.target.result);

        // canvasへ画像の貼り付け
        var img = new Image();
        img.src = evt.target.result;
        img.onload = function () {
          var width = img.width;
          var height = img.height;
          canvas.width = width;
          canvas.height = height;
          var ctx = canvas.getContext('2d');

          ctx.drawImage(img, 0, 0, width, height);
        };
      };
      var file = $("#photo").prop('files')[0];
      fr.readAsDataURL(file);
    }
  </script>
</body>

</html>

このプログラムのデモはこちら

上のプログラムで、「ファイル」のボタンを押すと、カメラの画像を取り込むことができる。

でも、iOSで取得すると、変な回転がかかってしまいます。
これをExif.jsとCanvasをうまく使って、変更したのが次のコード

改良したコード

<!doctype html>
<html lang="ja">

  <head>
    <meta charset="utf-8">
    <title>ExifSample</title>
    <script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
    <script src="bower_components/exif-js/exif.js"></script>
  </head>

  <body>
    <p> カメラから読み取ってプレビュー </p>
    <input type="file" id="photo" accept="image/*;capture=camera" onchange="loadFile()" value="Camera">

    <p> imgタグ きっと回転されない</p>
    <img id="photo_img" src="">

    <p> canvasタグ iOSでもちゃんと表示される</p>
    <canvas id="mycanvas" ></canvas>

    <script>
      function loadFile() {
        var canvas = document.getElementById('mycanvas');
        var fr = new FileReader();
        fr.onload = function (evt) {
          // imgタグへ画像の貼り付け
          $("#photo_img").attr("src", evt.target.result);

          // canvasへ画像の貼り付け
          var img = new Image();
          img.src = evt.target.result;
          img.onload = function () {
            // Exifの読み取り
            EXIF.getData(img, function () {
              // 幅と高さの取得
              var width = img.width;
              var height = img.height;
              var rotate = 0;

              console.log(EXIF.pretty(this));
              // 回転方向の読み取り
              if (EXIF.pretty(this)) {
                if (EXIF.getAllTags(this).Orientation == 6) {
                  rotate = 90;
                } else if (EXIF.getAllTags(this).Orientation == 3) {
                  rotate = 180;
                } else if (EXIF.getAllTags(this).Orientation == 8) {
                  rotate = 270;
                }
              }
              var ctx = canvas.getContext('2d');
              // Canvasのサイズを指定
              if (rotate == 90 || rotate == 270) {
                canvas.width = height;
                canvas.height = width;
              } else {
                canvas.width = width;
                canvas.height = height;
              }

              // 画像の回転
              if (rotate && rotate > 0) {
                ctx.rotate(rotate * Math.PI / 180);
                if (rotate == 90)
                  ctx.translate(0, -h);
                else if (rotate == 180)
                  ctx.translate(-w, -h);
                else if (rotate == 270)
                  ctx.translate(-w, 0);
              }

              ctx.drawImage(img, 0, 0, width, height);
            });
          };
        };
        var file = $("#photo").prop('files')[0];
        fr.readAsDataURL(file);
      }
    </script>
  </body>

</html>

ちょっと長くてうんざりしそうですね。でも、これでブラウザ上で画像を自動的に回転できます。

それでは、解説です。

Exif-jsのインストール

まず、exif-jsを手に入れます。手動で、手に入れて<script>タグで、読み込んでもいいです。

僕は、bowerを使ってインストールしました。

canvasの設置

画像の回転にcanvasを使用するので、<canvas>タグを用意します。

<canvas id="mycanvas" "></canvas>

EXIFデータの読み取り

EXIFに画像の回転情報が記載されています。

EXIF.getData(img, function () {
  // 幅と高さの取得
  var width = img.width;
  var height = img.height;
  var rotate = 0;

  console.log(EXIF.pretty(this));
  // 回転方向の読み取り
  if (EXIF.pretty(this)) {
    if (EXIF.getAllTags(this).Orientation == 6) {
      rotate = 90;
    } else if (EXIF.getAllTags(this).Orientation == 3) {
      rotate = 180;
    } else if (EXIF.getAllTags(this).Orientation == 8) {
      rotate = 270;
    }
  }

exif-jsのEXIF.getDataにimageを指定してあげると、コールバック関数内では、EXIFデータが読み取れるようになります。

画像の回転情報は、Orientationタグに入っているようです。このタグの状態については、http://qiita.com/minodisk/items/b7bab1b3f351f72d534bで説明されています。

ここで、回転角度を取得します。

Canvasを使った画像の回転

まず、canvasオブジェクトを取得します。

var canvas = document.getElementById('mycanvas');

それから、画像を回転させてcanvasへ貼り付けます


var ctx = canvas.getContext('2d'); // Canvasのサイズを指定 if (rotate == 90 || rotate == 270) { canvas.width = height; canvas.height = width; } else { canvas.width = width; canvas.height = height; } // 画像の回転 if (rotate && rotate > 0) { ctx.rotate(rotate * Math.PI / 180); if (rotate == 90) ctx.translate(0, -h); else if (rotate == 180) ctx.translate(-w, -h); else if (rotate == 270) ctx.translate(-w, 0); } ctx.drawImage(img, 0, 0, width, height);

このプログラムのデモはこちら

まとめ

最近のブラウザ(iOSとかのブラウザ)は画像の回転方向を含めて自動で表示してくれてたんですね。知らなかったので、画像を加工しようと思ったら、はまってしまいました。

この記事も同じようなことで、はまってしまった方の役に立てればと思います