JavaScript
base64
three.js
CORS
NCCDay 14

画像の外部URLからbase64を取得する

More than 1 year has passed since last update.

three.jsをいじっていたら

three.js の TextureLoader にある load ( url, onLoad, onProgress, onError ) に外部URLを直接入れてもCORSに関するエラーが出てきてしまいました。

var url = 'https://example.com/image.png';
(new TextureLoader()).load(url, (texture) => {
  // texture は three.js の Texture
  // https://threejs.org/docs/#api/textures/Texture
});

サーバ側から叩けば問題ない

CORSについて理解ができていなかった私は (今もまだわかっていない) サーバ側からリクエストすれば回避できるということを知りませんでした。
というわけで express を使ってサーバを立ててしまいましょう。
TextureLoader.loadurl<img> タグの src にはbase64を指定できるので、今回はbase64を使っています。

ディレクトリツリー
main
├── server
│   └── index.js
└── src
    └── index.html

server/index.js
const express = require('express')

let defaultPort = 8000

let app = express()
let server = app.listen(process.env.PORT || defaultPort, () => {
    console.log('start server listening', process.env.PORT || defaultPort)
    console.log('http://localhost:' + (process.env.PORT || defaultPort))
})
app.use(express.static(__dirname + './../src'))

// GETリクエストで画像の外部URLを受取り、base64を返す
app.get('/url2base64', function(req, res) {
    const url = decodeURIComponent(req.query.url);
    request.get(url, function(error, response, body) {
        if (!error && response.statusCode == 200) {
            data = "data:" + response.headers["content-type"] + ";base64," + new Buffer(body).toString('base64');
            res.send(data);
        } else {
            // 画像がなかったら透過gifを返しておく
            res.send("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEHAAEALAAAAAABAAEAAAICTAEAOw==");
        }
    });
});

src/index.html
<img src="" alt="">
<script>
    var url = "https://www.google.co.jp/images/nav_logo242.png";
    var xhr = new XMLHttpRequest();
    xhr.open('GET', './url2base64?url=' + encodeURIComponent(url));
    xhr.addEventListener("load", function(e) {
        document.getElementsByTagName('img')[0].src = xhr.responseText;
    });
    xhr.send(null);
</script>

あとは main ディレクトリ配下で

npm install express
node server

とすれば http://localhost:8000/index.html にて、指定したURLの画像が表示されるはずです。
デベロッパーツールで <img> タグの src を見てみるとbase64で指定されていることがわかると思います。