画像アップロードReact用コンポーネント(ドラッグ&ドロップ対応)− react-image-base64

画像アップロードReact用コンポーネント(ドラッグ&ドロップ対応)− react-image-base64

目次

react-image-base64 とは

react-image-base64 は、NPMで公開 されている画像アップロード用のReactコンポーネントです。

特徴

  • Base64にエンコードされた画像データを取得することが出来ます。
  • サイズを指定することで選択した画像をリサイズすることが出来ます。
  • iPhoneで撮影されたHEIC形式の画像をJPEGに変換します。
  • ドラッグ&ドロップでファイルの選択が可能です。

デモ

画像ファイルを選択すると元の画像とリサイズ後の画像が一覧に表示されます。元の画像に比べて、リサイズ後の方がサイズが小さくなっている事が判ると思います。

こちらにデモページを用意しているのでご利用ください。

使い方

$ yarn add -D react-image-base64
const [images, setImages] = useState({data: []});
const [errors, setErrors] = useState([]);
return (
  <div>
    <ReactImageBase64
      maxFileSize={10485760}
      thumbnail_size={100}
      drop={true}
      dropText="ファイルをドラッグ&ドロップもしくは"
      capture="environment"
      multiple={true}
      handleChange={data => {
        if (data.result) {
          let list =images.data
          list.push(data);
          setImages({data: list})
        } else {
          setErrors([...errors, data.messages]);
        }
      }}
    />
    { errors.map((error, index) => 
        <p className="error-message" key={index}>{error}</p>
      )
    }
  </div>
)

画像ファイルのリサイズ機能

最近のスマートフォンで撮影した写真は解像度が高くそのまま送信してしまうとサーバー側の負荷が高くなってしまったり、通信時間がかかってタイムアウトになってしまう問題が発生してしまいます。

その為、クライアント側(javascript側)で画像をリサイズして解像度を小さくしてからサーバー側へ送信する処理は、Webアプリケーションにおいて(特にフロントエンドにおいて)は必須な対応であると考えます。

以下は、読み込んだ画像の縦または横のピクセルが指定したサイズよりも大きい場合は、アスペクト比を維持したまま指定したサイズにリサイズをすることでサーバーへ送信するファイルサイズを小さくしています。

サイズを小さくして解像度を下げすぎると表示される画像の見た目が荒くなりますが、サイズが大きいと画面を表示する際に読み込みが遅くなってしまいます。

画像の見た目が気にならない程度の解像度にサイズをリサイズすることがポイントです。

const image = new Image()
const fr = new FileReader()
fr.onload = function(evt) {
  // リサイズする
  image.onload = function() {
    let width, height
    if (image.width > image.height) {
      // 横長の画像は横のサイズを指定値にあわせる
      const ratio = image.height / image.width
      width = props.thumbnail_size
      height = props.thumbnail_size * ratio
    } else {
      // 縦長の画像は縦のサイズを指定値にあわせる
      const ratio = image.width / image.height
      width = props.thumbnail_size * ratio
      height = props.thumbnail_size
    }
    // サムネ描画用canvasのサイズを上で算出した値に変更
    const canvas = document.createElement('canvas')
    canvas.id = 'canvas'
    canvas.width = width
    canvas.height = height
    const ctx = canvas.getContext('2d')
    if (ctx) {
      // canvasに既に描画されている画像をクリア
      ctx.clearRect(0, 0, width, height)
      // canvasにサムネイルを描画
      ctx.drawImage(image, 0, 0, image.width, image.height, 0, 0, width, height)
    }

    // canvasからbase64画像データを取得
    const base64 = canvas.toDataURL('image/jpeg')
    // base64からBlobデータを作成
    const bin = atob(base64.split('base64,')[1])
    const len = bin.length
    const barr = new Uint8Array(len)
    let i = 0
    while (i < len) {
      barr[i] = bin.charCodeAt(i)
      i++
    }
    const resizeBlob = new Blob([barr], { type: 'image/jpeg' })
    callback({
      fileName: fileName,
      ofileData: evt.target ? evt.target.result : null,
      fileData: base64,
      ofileSize: blob.size,
      fileSize: resizeBlob.size,
      fileType: resizeBlob.type,
    })
  }
  image.onerror = function() {
    errorCallback(['選択されたファイルをロードできません。'])
  }
  image.src = evt.target ? evt.target.result + '' : ''
}
fr.readAsDataURL(blob)

HEIC形式をJPEGに変換する機能

また、iPhone11以降で撮影した写真はHEICというブラウザで表示できない形式の画像ファイルで保存されます。

その為、HEIC形式の画像ファイルの場合はJPEGなどブラウザで表示できる形式に変換する必要があります。

heic2any というライブラリを利用することで、JPEGなどブラウザで表示可能な形式に変換することが可能です

heic2any({
  blob: file,
  toType: 'image/jpeg',
  quality: 1,
})
.then(function(rb) {
  const resultBlob = rb as Blob;
  const errors = validate(resultBlob)
  if (0 < errors.length) {
    errorCallback(errors)
    return
  }
  resize(
    file.name,
    resultBlob,
    function(res: { fileName: string; fileData: string; }) {
      res.fileName = file.name
      successCallback({
        ...res,
        result: true, 
        messages: ['正常終了'],
      })
    },
    function(errors: string[]) {
      errorCallback(errors)
      return
    },
  )
})

コメントを残す

入力エリアすべてが必須項目です。メールアドレスが公開されることはありません。

内容をご確認の上、送信してください。