Electron で画像を表示するのに詰まった
結局 base64 にエンコードした値をレンダープロセスに渡すようにした。
Electron アプリの開発中に起きた出来事。
環境
Electron のバージョンは 16.0.5 である。
webPreferences
は preload
の設定だけしており、他の設定はデフォルト値である。
UI 部分は React を使っている。
最終的にやったこと
画像を base64 でエンコードする。
const image = readFileSync("/path/to/image.jpg");
const encodedImage = image.toString("base64");
img
タグを以下のように書く。
<img src={`data:image/jpg;base64,${encodedImage}`} />
これで画像が表示された。
実際はレンダラープロセスから Node.js の関数を呼ぶことはできない(nodeIntegration: false
の場合)ので、エンコードされた画像を取得するための API を公開する必要がある。
実際の流れ
404 が返る
ローカルにある画像ファイルを表示するため、<src img={'/path/to/image.jpg'} />
のようなコンポーネントを書いた。
アプリを実行してみると、http://localhost:3000/path/to/image.jpg
にリクエストを投げていて 404 エラーが返っていた。
スキーマを file にする
<img src="file:///path/to/image.jpg" />
に変えてみると、404 ではなく Not allowed to load local resource
というエラーに変わった。
webPreferences
の WebSecurity
プロパティを false
にすると良いらしいという情報を得たが false
にするのは非推奨なので別の方法を探すことにした。
protocol.interceptFileProtocol を使う
Electron の issue に今回の件そのままのものがあった。
9.0.0 does not display local images · Issue #23757 · electron/electron · GitHub
解決方法として挙げられていたのが上記の webSecurity
を false
にする方法と、registerFileProtocol
を使って何かする方法である。
後者の方法でなぜうまくいくかはわからないが、とりあえず試してみた。
app.whenReady().then(() => {
protocol.registerFileProtocol('file', (request, callback) => {
const pathname = request.url.replace('file:///', '');
callback(pathname);
});
});
上記のコードを書いて実行してみるが、結果は変わらずエラーも同じ。
console.log
で登録した関数が実行されているか確かめたが、全く実行されなかった。
スキーマを file
から http
に変えてみるとメインプロセスのエントリポイントである index.js
のリクエスト時には動くことが確認できた。
registerHttpProtocol
などで実行してみるも、変わらず。
諦めた
エンコードした画像データを API で取得できるようにした。 もともとレンダラープロセスから API を使って画像のパスを取得していたので、そのような変更をするのには時間がかからなかった。
学び
- Data URLs - HTTP | MDN
- protocol で何かができる