Tauri v2で画像ファイルを表示する

# 1. この記事は何について書くか


Tauriでローカルの画像ファイルをGUIに表示しようとして
かなり苦戦したのでまとめておきます


# 2. Tauriとセキュリティ


TauriのPermission管理については先日書いています


https://qiita.com/studio_haneya/items/e1b2a770e9f57115dd96


TauriはXSSを防ぐためにかなり考えて作られているようで、imgタグで画像を表示する場合でも、対象がローカルディレクトリの画像ファイルである場合はscopeとCSPを設定しておく必要があります


https://v2.tauri.app/security/csp/


# 3. Tauriで画像ファイルを開く方法


ウェブで探すと以下2つの方法が見つかります


・convertFileSrcで表示可能なPATHを生成する
・Base64に変換して表示する


## 3-1. convertFileSrcで表示可能なPATHを生成する


こちらが標準的なやり方だと思います
ローカルパスを変換してTauriフロントエンドがアクセス可能なblobっぽいパスに置き換えます


公式ドキュメントに記載があります
https://tauri.app/reference/javascript/api/namespacecore/#convertfilesrc


こちらの記事の手順が上手く動いてくれました
https://qiita.com/Odashikonbu/items/1505d1ba582286b5bd60


### 3-1-1. プラグインのPermission設定


coreだけあれば動きます


```json:/src-tauri/capability/default.json
{
  "$schema": "../gen/schemas/desktop-schema.json",
  "identifier": "default",
  "description": "Capability for the main window",
  "windows": [
    "main"
  ],
  "permissions": [
    "core:default"
  ]
}
```


### 3-1-2. CSP設定


CSPの設定を/src-tauri/tauri.conf.jsonに書きます


```/src-tauri/tauri.conf.json
  "app": {
    "security": {
      "csp": {
        "img-src": "'self' asset: http://asset.localhost blob: data:"
      },
      "assetProtocol": {
        "enable": true,
        "scope": ["**"]
      }
    }
  }
```


画像以外のCSPについても公式ドキュメントに記載があります
https://v2.tauri.app/security/csp/


### 3-1-3. フロントエンドの書き方


画像ファイルのパスをconvertFileSrc()するとblobにしてくれて、img src={imageUrl}で表示するという書き方になります。少し古い記事ではconvertFileSrc()をawaitしなければならなかったようですが、2025年5月28日時点の最新版v2.5.1ではawait不要になっているようです


```react:/src-tauri/App.tsx
import "./App.css";
import { convertFileSrc } from '@tauri-apps/api/core';

function App() {
  const imagePath = "D:\\20250426_143138049.JPG";
  const imageUrl = convertFileSrc(imagePath);
  console.log("imageUrl", imageUrl);

  return (
    <div className="flex-cols">
      <img src={imageUrl} alt="Image" className="w-1/2 m-4" />
    </div>
  );
}

export default App;
```


タグの中でconvertFileSrc()することもできますので、動的にファイルパスを取得して表示するのもやりやすそうです


```react:/src-tauri/App.tsx
<img src={convertFileSrc(imagePath)} alt="Image" className="w-1/2 m-4" />
```


## 3-2. Base64に変換して表示する


こちらでやってる事例も見つかりますが、convertFileSrcがtauri-coreにあることから考えると推奨されているやり方ではないと思われます


### 3-2-1. プラグインのPermission設定


バイナリファイルとしてファイルを読み込みますのでfs:allow-app-readへのPermissionが必要です。scopeを**にしてしまってますが、実際に開発される際には適切な範囲で設定してください


```json:/src-tauri/capability/default.json
{
  "$schema": "../gen/schemas/desktop-schema.json",
  "identifier": "default",
  "description": "Capability for the main window",
  "windows": [
    "main"
  ],
  "permissions": [
    "core:default",
    "opener:default",
    "dialog:default",
    {
      "identifier": "fs:allow-app-read",
      "allow": [
        { "path": "**" },
      ]
    }
  ]
}
```


### 3-2-2. フロントエンドの書き方


readFileでバイナリファイルとして読み込んでからBase64に変換してimgタグで表示します。以前はバイナリファイル読み込みをreadBinaryFileで実行していましたがTauri v2からはreadFileに変更されましたので、こちらを使います
https://v2.tauri.app/ja/start/migrate/from-tauri-1/


```react:/src-tauri/App.tsx
import { useState } from "react";
import { open } from "@tauri-apps/plugin-dialog";
import { readFile } from '@tauri-apps/plugin-fs';

function App() {
  const [imageDataUrl, setImageDataUrl] = useState<string | null>(null);

  const handleOpenImage = async () => {
    const selected = await open({
      multiple: false,
      filters: [{ name: "Images", extensions: ["png", "jpg", "jpeg", "webp", "bmp"] }],
    });

    if (typeof selected === "string") {
      const bytes = await readFile(selected);
      const base64 = new Uint8Array(bytes)
        .reduce((data, byte) => data + String.fromCharCode(byte), '');
      const mime = selected.endsWith(".png") ? "image/png" : "image/jpeg";
      setImageDataUrl(`data:${mime};base64,${btoa(base64)}`);
    }
  };

  return (
    <div>
      <h1>画像を選択して表示</h1>
      <button onClick={handleOpenImage}>画像を開く</button>
      {imageDataUrl && <img src={imageDataUrl} alt="Selected" style={{ maxWidth: "100%" }} />}
    </div>
  );
}

export default App;
```


<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277233/5eb359a8-3612-42c7-aebd-5260485242b1.png" width=50%>




# 4. まとめ


結構苦戦しました


Tauriのエラーメッセージが何を言ってるか分からないし、公式ドキュメントも分かりにくい、検索して調べようにも最近v2がリリースされたばかりで古い情報が多い、という具合で新たにはじめるのが辛い時期に入門してしまったかもしれません。その分、中身の理解は進んでいるのでこれを乗り越えてモリモリ書いていきたい所存


# 5. おまけ


逆引き用にエラーメッセージを貼っときます


## CSPが設定されていない場合


```console:console
Failed to load resource: net::ERR_CONNECTION_REFUSED
```