ブラウザでローカル画像をリサイズしてアップロード


###【2019/8/20】 多くの方に見ていただいている記事なので、改めてまとめ直しました。
###https://www.mahirokazuko.com/entry/2019/08/20/133713

<br>

### **よくある画像アップロード機能を作ってみた😋**

**◆ 要件**
・ フォルダにある画像を選択すると、小さくリサイズされたサムネが表示される
・ 送信ボタンを押すとリサイズ済みの画像がフォームデータとして送信される

**◆ サンプル**
<img width="200" alt="ss 2017-09-22 16.59.14.png" src="https://qiita-image-store.s3.amazonaws.com/0/80357/0d58225d-7eac-817d-3733-62e8e2eafb79.png">
↓ ファイル選択するとサムネを表示
<img width="450" alt="ss 2017-09-22 16.59.23.png" src="https://qiita-image-store.s3.amazonaws.com/0/80357/c93486f0-a613-5120-cfd4-9204d7e63fbf.png">

上の画像、生データだと横幅6000pxくらいあります。最近のスマホで撮った写真はサイズが大きすぎるので、通信量を抑えるためにもリサイズしてアップロードは必須ですね。

**◆ コード**
ファイル取得→canvas描画→base64取得→Blob作成→Blob送信
という流れ

```html
<!-- ファイル選択ボタン -->
<div style="width: 500px">
  <form enctype="multipart/form-data" method="post">
    <input type="file" name="userfile" accept="image/*">
  </form>
</div>

<!-- サムネイル表示領域 -->
<canvas id="canvas" width="0" height="0"></canvas>

<!-- アップロード開始ボタン -->
<button class="btn btn-primary" id="upload">投稿</button>

<!-- 以下、javascript -->
<script type="text/javascript">
$(function() {
  var file = null; // 選択されるファイル
  var blob = null; // 画像(BLOBデータ)
  const THUMBNAIL_WIDTH = 500; // 画像リサイズ後の横の長さの最大値
  const THUMBNAIL_HEIGHT = 500; // 画像リサイズ後の縦の長さの最大値

  // ファイルが選択されたら
  $('input[type=file]').change(function() {

    // ファイルを取得
    file = $(this).prop('files')[0];
    // 選択されたファイルが画像かどうか判定
    if (file.type != 'image/jpeg' && file.type != 'image/png') {
      // 画像でない場合は終了
      file = null;
      blob = null;
      return;
    }

    // 画像をリサイズする
    var image = new Image();
    var reader = new FileReader();
    reader.onload = function(e) {
      image.onload = function() {
        var width, height;
        if(image.width > image.height){
          // 横長の画像は横のサイズを指定値にあわせる
          var ratio = image.height/image.width;
          width = THUMBNAIL_WIDTH;
          height = THUMBNAIL_WIDTH * ratio;
        } else {
          // 縦長の画像は縦のサイズを指定値にあわせる
          var ratio = image.width/image.height;
          width = THUMBNAIL_HEIGHT * ratio;
          height = THUMBNAIL_HEIGHT;
        }
        // サムネ描画用canvasのサイズを上で算出した値に変更
        var canvas = $('#canvas')
                     .attr('width', width)
                     .attr('height', height);
        var ctx = canvas[0].getContext('2d');
        // canvasに既に描画されている画像をクリア
        ctx.clearRect(0,0,width,height);
        // canvasにサムネイルを描画
        ctx.drawImage(image,0,0,image.width,image.height,0,0,width,height);

        // canvasからbase64画像データを取得
        var base64 = canvas.get(0).toDataURL('image/jpeg');        
        // base64からBlobデータを作成
        var barr, bin, i, len;
        bin = atob(base64.split('base64,')[1]);
        len = bin.length;
        barr = new Uint8Array(len);
        i = 0;
        while (i < len) {
          barr[i] = bin.charCodeAt(i);
          i++;
        }
        blob = new Blob([barr], {type: 'image/jpeg'});
        console.log(blob);
      }
      image.src = e.target.result;
    }
    reader.readAsDataURL(file);
  });


  // アップロード開始ボタンがクリックされたら
  $('#upload').click(function(){

    // ファイルが指定されていなければ何も起こらない
    if(!file || !blob) {
      return;
    }

    var name, fd = new FormData();
    fd.append('file', blob); // ファイルを添付する

    $.ajax({
      url: "http://exapmle.com", // 送信先
      type: 'POST',
      dataType: 'json',
      data: fd,
      processData: false,
      contentType: false
    })
    .done(function( data, textStatus, jqXHR ) {
      // 送信成功
    })
    .fail(function( jqXHR, textStatus, errorThrown ) {
      // 送信失敗
    });  

  });

});
</script>
```

**◆ AWS S3に直接アップロード**

画像をブラウザからAWSに直接アップロードする機能も作りました。こちら↓に書きました。
https://qiita.com/komakomako/items/05ccddb0dbd960279344