2020-06-21

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

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

Article Image

先日の記事

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

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

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

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

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

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

次のように動作する。

実際の動作

今回やること

今回はわざわざデータを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%削減されるらしい。

非常に簡単だった。

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



この記事のタグ

この記事をシェア


謎の技術研究部 (謎技研)