Socket.ioでバイナリ画像を受信してVue.jsで表示

June 21, 2020

先日base64に変換して送信するコードを出したがバイナリで受信してVue.jsに表示するよう改変した

binary_no_base64

先日の記事

Node.jsからVue.jsクライアントへSocket.ioを通して画像を送信して表示 | Blog

先日の記事でやったこと。

Node.jsからVue.jsに画像を送信して表示する。

Expressを使わずにSocket.ioだけで行う。

このときbase64という形式でバイナリデータをテキストファイルに変換して送信した。

実際の動作(見かけは前回も今回も同じ)

次のように動作する。

getImg

今回やること

今回はわざわざデータをbase64に変換せずともfs読み込んだままのバイナリデータをそのままVue.jsへ送信

クライアント側で処理し画像を表示する。

Socket.ioはバイナリ送信に対応している。

サーバー側コード(Node.js)

以前と比べて変換するコードが一切ないので非常にスマートとなった。

import io from 'socket.io'
import fs from 'fs'

const socket = io(7000)

socket.on('connection', function (socket) {
    console.log(`a user connected[id:${socket.id}]`)

    socket.on("get_img", () => {
        const filePath = "./images/test_img.jpg"
        const imgBinary = fs.readFileSync(filePath) //単純に読み込んで
        socket.emit("img_data",(imgBinary)) //そのまま送信
        console.log("a image was sent.")
    })
})

クライアント側コード(Vue.js)

こちらは変換するコードを実装する必要があるがbase64関係のヘッダ処理が全て排除できるためコードが短い。

重要なのは「ここに注目!」と書いてある2行だけ。

<template>
  <v-container>
    <v-btn @click="getImg()">get img</v-btn>
    <v-img :src="imgBlobUrl" v-if="imgBlobUrl" />
  </v-container>
</template>

<script>
import io from "socket.io-client";
export default {
  name: "HelloWorld",
  data: () => ({
    socket: io("localhost:7000"),
    imgBlobUrl: null
  }),
  mounted() {
    this.socket.on("connect", () => {
      console.log("connected");
      this.socket.on("img_data", imgBinary => {
        const blob = new Blob([imgBinary])
        this.imgBlobUrl = window.URL.createObjectURL(blob)
      });
    });
  },
  methods: {
    getImg() {
      this.socket.emit("get_img");
    }
  }
};
</script>

解説(Vue.js側)

まず、fsで画像を読み込んだデータを直接送信するとVue.jsにはArrayBufferという形式で受信することとなる。

ArrayBufferとは要するにバイナリデータなのだが、この生データはブラウザでは直接取り扱うことができない。

当然imgタグのsrcに放り込んでもエラーが出る。

blobに変換

基本的に他サイトでは難しい解説しかされていないのでとにかく分かりやすくする。

const blob = new Blob([imgBinary]) //[]でくくって配列する必要がある

imgBinaryに送られてきたバイナリデータが入っている。

まずこのままでは数字の羅列なのでデータがどういうものなのか分からない。

そこでBlobというオブジェクトとしてをnewすることでこれをブラウザから内部的に取り扱える「ファイル」になったと考えてもらいたい。

つまりユーザーには取り扱えないがブラウザがアクセスできる仮のフォルダの中に送られてきた画像データが入ったような状態。

blobにアクセスするURLを発行

this.imgBinary = window.URL.createObjectURL(blob)

blobデータは生成されたのでimgタグのsrcに入れてやりたい。しかしそもそもsrcには何を入れるものだっただろうか。

srcは基本的にURLを入れるものであり生データを直接いれるものではない。

そこでブラウザ側のAPIであるcreateObjectURLにこのblobを入れてやるとそのblobにアクセスできるURLが発行される。

つまりこれをimgタグのsrcに入れてやればようやくブラウザが画像として取り扱うことができるわけだ。

さいごに

コード量でみれば圧倒的に短くなった。

更にデータ通信量も30%削減されるらしい。

非常に簡単だった。

今後はできる限りこちらでデータを扱っていきたい。

この記事をシェア:

author icon

仮想トイレ @CrypticToilet
仮想通貨のシステムトレードに役立つ情報を配信中。どんな情報を流しても詰まらないトイレ。当BLOGのメインライター。