画像ファイルが選択されたらブラウザ上でリサイズしてBase64文字列にして結果をフォームに埋め込んでサーバに送信する(非ajax)


色々と面倒だったので備忘。
アプリケーション設定はplayframework独自ですが、フロント側は素のjavascriptでいけますし、サーバサイドもどんな言語・Webフレームワークでも道具立てが用意されているはずです。

  • アプリケーション設定
    • application.confでBodyParserのデータ上限を緩和する.
  • HTML
    • input[type='file']タグを用意
    • 上記に対応するcanvasを用意する。表示サイズはwidth指定しておく。(役割はファイル選択時のサムネイル表示とBase64文字列取得)
  • 画像ファイル選択
    • 選択されたら、canvasを初期化する(clearRect)。ファイル内容を読み込む。ファイル種別等をチェック。
    • ファイル読み込みが完了(onload)したらその結果(e.target.result)をimg.srcに設定する
    • img.srcの読み込みが完了(onload)したら、その内容を適宜リサイズしてcanvasに描画(drawImage)する
  • フォーム確定(submit)
    • フロントエンド
      • 選択されたファイルが存在する場合、canvasからBase64化された文字列を取得(toDataURL('image/jpeg'))。以降ではイメージ文字列と呼称
      • フォームにhidden属性を追加して値にイメージ文字列を設定する
      • input[type='file']に設定された内容を消す ← 無駄なので。そもそも画像リサイズ要件の背景は「通信遅い」から派生しているので
      • submitする
    • サーバサイド
      • multipartでなく通常のフォームパラメタとして読み出す
      • イメージ文字列のデータ部分を切り出して、BufferedImageに変換する。=> このあとはファイルに戻したり、好きに加工
        • data:image/jpeg;base64,★ここから後=>★/9j/4AAQSkZJRgABAQEASABIAAD/4ge4SUNDX1BST0ZJTEUAAQEAAAeoYFKc5KKbP/2Q==

ポイントとしては、

  • サーバサイドに送信するデータはcanvasに描画したデータで、input[type='file']のデータではないこと
  • 非ajax(フォームに埋め込んでサーバに送信)であること。(こういった処理を行う場合は、Blob化してFormDataに詰めて、ajaxでサーバサイドに送ることが多い模様)

参考