ウェブでの画像ファイルの取り扱いについて (Node.js * javascript)

混乱するので必要な情報だけまとめ






画像ファイルについて

画像ファイルは特定のフォーマットに応じてバイナリファイルで表現される
http://www.setsuki.com/hsp/ext/png.htm

例えばpngファイルをテキストエディタで開いてみると
âPNG ... IHDR ....
というふうになっている

Base64について

一部の言語・環境ではバイナリの対応が微妙。
特にhttp通信時は直接バイナリのやりとりができない(はず)ので
base64で変換(エンコード)する必要がある。


受け取り側で自動でデコードされたりbase64のまま使えたりするケースがある。
例えばGET,POST時のパラメータはブラウザからエンコードして送ってもサーバ側でデコードする必要がなかったり
imgタグのsrcは画像ファイルのパスだけでなくbase64でエンコードされた文字列をそのまま使用することもできる。


Node.js のrequestはバイナリを取得する場合、
encodingにnullを設定する。
以下の2/3あたりに記述がある。
https://github.com/request/request


imgタグのsrcは
ファイル名だけでなく
data url scheme という形式で表現できる
http://d.hatena.ne.jp/moogme/20090814/p3
<img src="data:image/png;base64,{base64 encoded data}">

以下で実際に画像を変換できる
https://syncer.jp/base64-encoder


javascript レスポンスタイプをblob形式でリクエストを送ることでバイナリで受け取ることができる
http://kinjouj.github.io/2013/04/xmlhttprequest-load-image-binary.html
http://qiita.com/Yarimizu14/items/f56123c738f12ad1844a


実装例

実装例としてとあるURL http://xxx.png から画像ファイルを取得して、ブラウザに表示(imgタグ)
ということをやってみる。
サーバ環境はNode.js

サーバ側
router.get("/test", (req, res, next) => {
  const options = {
    url: "http://xxx.png",
    method: "GET",
    encoding: "null",
  }

  request(options, (error, response, body) => {
    const result = `data:image/jpeg;base64,${new Buffer(body).toString("base64")}`
  })
  res.send(result)
})

encodingをnullにしてバイナリを取得できるように。
バイナリを取得した後はImgタグ用に変換。base64形式で変換した後先頭に"data:image/jpeg;base64,"を追加している。

クライアント
html

head ...
body ...
<img id="thumbnail" src="" >

表示用にimgタグを記述。それ以外は省略。

js
// 読み込み完了時呼ばれる
window.addEventListener("load", (e) => {

    const xhr = new XMLHttpRequest()
    const async = true
    xhr.open("GET", "/test", async)
    xhr.onreadystatechange = () => {
      switch (xhr.readyState) {
        case 0:
          console.log("uninitialized!")
          break
        case 1:
          console.log("loading...")
          break
        case 2: 
          console.log("loaded.")
          break
        case 3:
          console.log("interactive... ")
          break
        case 4:
          if (xhr.status === 200 || xhr.status === 304) {
           // ここでImgタグに戻り値を入れる
            document.getElementById("thumbnail").src = xhr.response
          } else {
            console.log("Failed. HttpStatus: " + xhr.statusText)
          }
          break
        default:
          console.log("error nop default")
      }
    }
    
    xhr.send()
}

サーバ側で適切にbase64エンコードで出来ていればXMLHttpRequest でリクエストを投げて戻ってきた値をimgタグのsrcへ直接入れるだけでいい。
このままでは動かないと思うけど大体こんなイメージ。


ちなみにPNG画像でもdata:image/jpeg;base64でいけた(あまりよくはないだろうが)


2017年5月30日火曜日