49
47

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ブラウザ側でサイズ圧縮(リサイズ)して画像表示やアップロードを行う(Vue.js)

Last updated at Posted at 2019-06-07

概要

Webアプリでクライアントサイド(ブラウザ)で画像を圧縮(リサイズ)する方法の紹介です。
サンプルとして下図のような入力した画像をプレビュー表示した上で、確定時にサーバーに画像をアップロードするまでのサンプルコードを紹介します。

※今回はvue.jsとvuetifyによるサンプルになりますが、UIのレイアウト部分以外は基本的に一般的なjavascirptですので
他のフレームワークを使用している場合等でも参考にはなるかと思います

sample.png

動くデモとGitHubのサンプルコードは下記です。
Demo
GitHub

背景

Webアプリで、画像ファイルをアップロードするといったシチュエーションはよくあると思います。
スマホ等で撮影した写真等だと、解像度やファイルサイズも大きいため、そのまま使用せず一度リサイズしたりする事が多いかと思います。
アップロード後にサーバ側で処理するといった手法もありますが、今回はWEBブラウザ側でリサイズする方法とします。

実現方法

当初はCanvasにリサイズした画像を描画して、再度データ化する方法を使用していました。
参考

しかしながら、もっとお手軽にかつファイルサイズも小さくしてアップできる、Browser Image Compression といったものがあるのでそちらを使用します。

画面レイアウト

以下のような、3つの領域を作成します。

  • 画像のプレビュー領域
     入力した画像のプレビュー表示します。サンプルではvuetifyのv-imgタグを使用していますが、imgタグに相当するもの配置します。合わせてファイル名も表示します。

  • 画像の入力
     ファイルを入力するinputタグです。ファイル選択対アログで画像を選択するとプレビュー領域に表示されます。

  • Submitボタン
     プレビュー表示した画像をサーバにアップロードするためのボタン。画像入力中(リサイズ中)はプレビュー表示されるまでは押せなくします。

これらをvue.jsのコンポーネントで書くと下記のようになります。
処理等は無く、まだレイアウトだけです。

ImageUpload.vue
<template>
  <v-container>
    <v-layout text-xs-center wrap>
      <v-flex xs12>
        <!-- 画像のプレビュー表示領域 -->
        <v-img :src="upimage.fileUrl" aspect-ratio="2" :contain="true"></v-img>
        <p>{{ upimage.fileName }}</p>
        <p>圧縮前サイズ(MB):{{ fileInfo.before.size }}</p>
        <p>圧縮後サイズ(MB):{{ fileInfo.after.size }}</p>
      </v-flex>
      <v-flex xs12>
        <!-- ファイルの選択 -->
        <input @change="selectedFile" type="file" accept="image/jpeg, image/jpg, image/png">
      </v-flex>
      <v-flex xs12>
        <!-- Submitボタン -->
        <v-btn color="primary" :disabled="isUploading">submit</v-btn>
      </v-flex>
    </v-layout>
  </v-container>
</template>
<script>
export default {
  data() {
    return {
      isUploading: false, // 画像ファイルアップロード中の判断フラグ
      upimage: { fileUrl: "", fileName: "", blob: null } // 画像ファイル
    };
  },
  methods: {
    async selectedFile(e) {
      // ファイル入力時の処理 
      // e.target.filesにファイルの情報が格納
    },
    async submit() {
      // 画像をサーバに送信する処理
    }
  }
};
</script>

画面のリサイズ

入力された画像をプレビュー表示前にリサイズする処理を作成します。
まずは、npmかyarnでbrowser-image-compressionをインストールします。

npm install browser-image-compression --save
or
yarn add browser-image-compression

次に以下の2つの処理を作成します。

  1. 入力された画像ファイルの圧縮を行う処理
  2. プレビュー表示用にDataUrlを取得する処理

DataUrlにするのはimgタグにおいてプレビュー表示を行うためですので、直接アップロードしたい場合は不要です。
画像の圧縮時には最大のファイルサイズおよび、解像度を指定します。
今回は最大サイズは1MB, 解像度を800に指定しています。
その他にもオプションがありますので、詳細はbrowser-image-compressionのGitHubを参照してください。

ImageUtil.js
import imageCompression from "browser-image-compression";

export default {
  // アップロードされた画像ファイルを取得
  async getCompressImageFileAsync(file) {
    const options = {
      maxSizeMB: 1, // 最大ファイルサイズ
      maxWidthOrHeight: 800 // 最大画像幅もしくは高さ
    };
    try {
      // 圧縮画像の生成
      return await imageCompression(file, options);
    } catch (error) {
      console.error("getCompressImageFileAsync is error", error);
      throw error;
    }
  },
  // プレビュー表示用のdataurlを取得
  async getDataUrlFromFile(file) {
    try {
      return await imageCompression.getDataUrlFromFile(file);
    } catch (error) {
      console.error("getDataUrlFromFile is error", error);
      throw error;
    }
  }
};

画面への処理の取り込み

この画像処理を先ほどのレイアウト内で呼び出せば終了です。

ImageUpload.vue
// 略
<script>
import ImageUtil from "../lib/imageUtil";
export default {
  // 略
  methods: {
    async selectedFile(e) {
      this.isUploading = true;

      const file = e.target.files[0];
      if (!file) {
        return;
      }

      try {
        // 圧縮した画像を取得
        const compFile = await ImageUtil.getCompressImageFileAsync(file);

        //ファイルサイズの表示
        this.fileInfo.before.size = (file.size / 1024 / 1024).toFixed(4);
        this.fileInfo.after.size = (compFile.size / 1024 / 1024).toFixed(4);
        // 画像情報の設定
        this.upimage.blob = compFile;
        this.upimage.fileUrl = await ImageUtil.getDataUrlFromFile(compFile);
        this.upimage.fileName = file.name;
      } catch (err) {
        // エラーメッセージ等を表示
      } finally {
        this.isUploading = false;
      }
    },
    submit() {
      const fd = new FormData();
      try {
        fd.append(this.upimage.fileName, this.upimage.blob, this.upimage.fileName);
        // ここにサーバーへのアップロード処理を実装する
      } catch (err) {
        // エラーメッセージ等を表示
      }
    }
  }
};
</script>

まとめ

ということで、browser-image-compressionを使うことで、お手軽に画像の圧縮及び表示が可能となります。
是非試してみてください。

49
47
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
49
47

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?