JavaScriptだけで画像ファイル容量を減らす方法

Browser Image Compressionで容量削減

Browser Image Compressionとは画像圧縮のためにブラウザで実行可能なJavaScriptモジュールです。

Webサイトで画像をアップロードする場合、ファイル容量の上限が決まっています。

Webサイトのサーバーにはパソコンと同様に保存容量は有限なのでアップロード可能な画像ファイル容量は必ず上限が設定されている。

ファイル容量が大きい場合はサーバー側でファイルの圧縮などを行いファイルサイズを小さくしていることが多い。

しかし、ファイル容量が大きい画像をサーバーで小さくするファイルが多いと、サーバーへの負荷が増加してしまう。

そのためWebサイトによってはBrowser Image Compressionを使用してフロントサイド(ブラウザ)側で画像のファイル容量を減らしている場合がある。

Browser Image Compressionの使い方

まずは npm or CDN でBrowser Image Compressionを読み込む。

npm install browser-image-compression
import imageCompression from 'browser-image-compression';

or

<script src="https://cdn.jsdelivr.net/npm/browser-image-compression@latest/dist/browser-image-compression.js"></script>

フォームの送信にはaxiosを使用しているので「npm install axios」or CDNで読み込んでください。

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

次に画像をアップロードするためのHTMLを用意する。

<form name="fileinfo">
  <div>
      <label>ユーザー名</label>
      <input type="text" name="user">
  </div>
  <div>
      <label>メールアドレス</label>
      <input type="email" name="email">
  </div>
  <div>
    <label for="web-worker">
      <input id="web-worker" type="file" name="image" accept="image/*" onchange="compressImage(event);">
      <span id="web-worker-progress"></span>
    </label>
    <p id="web-worker-result"></p>
  </div>
  <button type="submit">送信</button>
</form>

formはJavaScriptで送信するのでformタグにはnameしか付けていないです。

type="file" のonchangeイベントで画像圧縮を行います。

最後にJavaScriptは以下の通り。

function compressImage(event) {
  const file = event.target.files[0]
  const result = document.getElementById('web-worker-result')
  const progressDom = document.getElementById('web-worker-progress')

  result.innerHTML = (file.size / 1024 / 1024).toFixed(2) + 'MB => '

  const options = {
    maxSizeMB: 1,
    maxWidthOrHeight: 1000,
    onProgress: onProgress,
  }
  imageCompression(file, options)
    .then(function(output) {
      const img = URL.createObjectURL(output)
      result.innerHTML += (output.size / 1024 / 1024).toFixed(2) + 'MB<br>'
      result.innerHTML += `
        <a href="${img}" target="_blank">
          <img src="${img}" width="200" alt="">
        </a>`
      return setSubmitEvent(output)
    })
    .catch(function(error) {
      console.error(error.message)
    })

  function onProgress(percent) {
    progressDom.innerHTML = `(${percent}%)`
    if (percent === 100) {
      progressDom.innerHTML = ''
    }
  }
}

function setSubmitEvent(file) {
  const form = document.forms.namedItem('fileinfo')
  const formData = new FormData(form)
  const url = '/post/foo/bar/'

  formData.append('image', file, file.name)

  form.addEventListener('submit', function(e) {
    axios
      .post(url, formData, {
          headers: {
            'content-type': 'multipart/form-data'
          }
        }
      )
      .then((res) => console.log(res))
      e.preventDefault();
  })
}

optionsに最大ファイルサイズ、最大の長さ、処理中の関数(onProgress)を設定している。

onProgressの引数は進行度をパーセントで返します。

これを使えば100(%)になったらローディング表示を消すみたいな処理も可能です。

JavaScriptだけで画像ファイル容量を減らす方法

Browser Image Compression Sample