# 機能設計書 87-メディアプレビュー

## 概要

本ドキュメントは、VS Codeの「メディアプレビュー（media-preview）」機能の設計内容を記載する。画像、動画、音声ファイルをエディタ内でプレビュー表示する機能を提供する。

### 本機能の処理概要

media-preview拡張機能は、画像ファイル（PNG、JPEG、GIF、SVG等）、動画ファイル（MP4、WebM）、音声ファイル（MP3、WAV、OGG）をカスタムエディタとしてプレビュー表示する。画像ではズーム操作やコピー機能を提供する。

**業務上の目的・背景**：開発プロジェクトでは画像や動画などのメディアファイルを扱うことが多い。これらのファイルを外部アプリケーションを開かずにVS Code内で確認できることで、開発効率が向上する。

**機能の利用シーン**：
- プロジェクト内の画像アセットをクリックしてプレビュー確認
- SVGファイルをプレビューとテキスト編集モードで切り替え
- 動画・音声ファイルの再生確認

**主要な処理内容**：
1. ファイル拡張子に基づくカスタムエディタの選択
2. Webviewを使用したメディアコンテンツの表示
3. 画像のズームイン/ズームアウト操作
4. ステータスバーでのサイズ・ズーム情報表示

**関連システム・外部連携**：VS CodeカスタムエディタAPI、Webview API

**権限による制御**：信頼されていないワークスペースでもサポート

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 2 | エディタ領域 | 主画面 | メディアファイルのプレビュー表示 |
| 4 | ステータスバー | 補助表示 | 画像サイズ、ズーム倍率表示 |

## 機能種別

カスタムエディタ / メディア表示 / Webview

## 入力仕様

### 入力パラメータ

サポートするファイル形式：

| カテゴリ | 拡張子 | viewType |
|---------|-------|----------|
| 画像 | jpg, jpe, jpeg, png, bmp, gif, ico, webp, avif, svg | imagePreview.previewEditor |
| 音声 | mp3, wav, ogg, oga | vscode.audioPreview |
| 動画 | mp4, webm | vscode.videoPreview |

### 設定項目

| 設定名 | 型 | 説明 | デフォルト |
|-------|-----|------|----------|
| mediaPreview.video.autoPlay | boolean | 動画の自動再生 | false |
| mediaPreview.video.loop | boolean | 動画のループ再生 | false |

### 入力データソース

- ファイルシステム上のメディアファイル
- ワークスペース設定

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| webviewPanel | WebviewPanel | プレビュー表示用パネル |
| sizeStatusBarEntry | StatusBarItem | 画像サイズ表示 |
| zoomStatusBarEntry | StatusBarItem | ズーム倍率表示 |
| binarySizeStatusBarEntry | StatusBarItem | ファイルサイズ表示 |

### 出力先

- エディタ領域（Webviewパネル）
- ステータスバー

## 処理フロー

### 処理シーケンス

```
1. ファイルを開く
   └─ 拡張子に基づきカスタムエディタを選択

2. カスタムエディタプロバイダー呼び出し
   └─ resolveCustomEditor

3. Webview作成
   └─ HTMLコンテンツを生成

4. メディア表示
   ├─ 画像: img要素で表示、ズーム機能付き
   ├─ 動画: video要素で表示、コントロール付き
   └─ 音声: audio要素で表示、コントロール付き

5. ユーザー操作
   ├─ ズームイン/ズームアウト（画像）
   ├─ 再生/停止（動画・音声）
   └─ SVG: テキストエディタへ切り替え

6. ステータスバー更新
   └─ サイズ・ズーム情報を表示
```

### フローチャート

```mermaid
flowchart TD
    A[ファイルを開く] --> B{ファイル種別}
    B -->|画像| C[ImagePreviewManager]
    B -->|動画| D[VideoPreviewProvider]
    B -->|音声| E[AudioPreviewProvider]
    C --> F[resolveCustomEditor]
    D --> F
    E --> F
    F --> G[Webview作成]
    G --> H[HTMLコンテンツ生成]
    H --> I{種別}
    I -->|画像| J[img要素 + ズームコントロール]
    I -->|動画| K[video要素 + コントロール]
    I -->|音声| L[audio要素 + コントロール]
    J --> M[ステータスバー更新]
    K --> M
    L --> M
    M --> N[ユーザー操作待ち]
    N --> O{操作種別}
    O -->|ズーム| P[ズーム処理]
    O -->|再生| Q[再生/停止]
    O -->|SVG切替| R[テキストエディタで開く]
    P --> M
    Q --> M
    R --> S[終了]
    M --> N
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-87-1 | ズームレベル | fit、実サイズ、200%、100%、50%等 | 画像プレビュー |
| BR-87-2 | SVG切り替え | SVGファイルはプレビュー/テキスト切替可能 | .svg |
| BR-87-3 | ビルトイン優先 | メディアプレビューはビルトイン優先度 | カスタムエディタ選択 |
| BR-87-4 | キャッシュバスト | ファイル変更時にクエリパラメータで再読み込み | 画像URL |

### ズーム倍率

```typescript
type Scale = 'fit' | 'actualSize' | '200%' | '100%' | '50%' | '25%' | '10%';
```

## データベース操作仕様

本機能はデータベース操作を行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | エラー表示 | 画像読み込み失敗 | エラーメッセージとテキストで開くリンク表示 |
| - | 情報 | gitスキームで空ファイル | 空のPNGデータURL表示 |

### リトライ仕様

リトライは行わない。ファイル変更時にWebviewを更新。

## トランザクション仕様

該当なし

## パフォーマンス要件

- 大きな画像でもスムーズなズーム操作
- Webview asWebviewUri()でセキュアなリソースアクセス

## セキュリティ考慮事項

- 信頼されていないワークスペースでもサポート
- 仮想ワークスペースでもサポート
- CSP（Content Security Policy）でコンテンツ制限

## 備考

- テレメトリ送信あり（@vscode/extension-telemetry）
- vscode-uriライブラリ使用

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | package.json | `extensions/media-preview/package.json` | customEditors定義（46-76行目） |
| 1-2 | zoomStatusBarEntry.ts | `extensions/media-preview/src/imagePreview/zoomStatusBarEntry.ts` | Scaleタイプ定義 |

**読解のコツ**: package.jsonのcontributes.customEditorsで3つのプレビュータイプ（image, audio, video）を定義。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | extension.ts | `extensions/media-preview/src/extension.ts` | activate関数 |

**主要処理フロー**:
1. **13行目**: BinarySizeStatusBarEntry作成
2. **16行目**: registerImagePreviewSupport呼び出し
3. **17行目**: registerAudioPreviewSupport呼び出し
4. **18行目**: registerVideoPreviewSupport呼び出し

#### Step 3: 画像プレビューを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | imagePreview/index.ts | `extensions/media-preview/src/imagePreview/index.ts` | ImagePreviewManagerクラス |
| 3-2 | imagePreview/index.ts | `extensions/media-preview/src/imagePreview/index.ts` | ImagePreviewクラス（73-241行目） |

**主要処理フロー**:
- **29-31行目**: openCustomDocument()
- **33-49行目**: resolveCustomEditor()
- **177-216行目**: getWebviewContents()でHTML生成

### プログラム呼び出し階層図

```
activate() [extension.ts 12行目]
    │
    ├─ BinarySizeStatusBarEntry() [13行目]
    │
    ├─ registerImagePreviewSupport() [16行目]
    │      │
    │      ├─ SizeStatusBarEntry() [247行目]
    │      ├─ ZoomStatusBarEntry() [250行目]
    │      ├─ ImagePreviewManager() [253行目]
    │      │
    │      └─ registerCustomEditorProvider() [255行目]
    │             │
    │             ├─ openCustomDocument() [29行目]
    │             │
    │             └─ resolveCustomEditor() [33行目]
    │                    │
    │                    └─ new ImagePreview() [37行目]
    │                           │
    │                           ├─ updateBinarySize() [127行目]
    │                           ├─ render() [177行目]
    │                           │      └─ getWebviewContents() [182行目]
    │                           │
    │                           └─ zoomIn/zoomOut() [142-152行目]
    │
    ├─ registerAudioPreviewSupport() [17行目]
    │
    └─ registerVideoPreviewSupport() [18行目]
```

### データフロー図

```
[入力]                    [処理]                         [出力]

ファイルURI          ──▶ resolveCustomEditor()
                            │
                            ▼
                      new ImagePreview() [37行目]
                            │
                            ├──▶ getWebviewContents()      ──▶ HTML文字列
                            │         │
                            │         ▼
                            │    asWebviewUri() [186行目]  ──▶ リソースURL
                            │
                            ├──▶ updateBinarySize()        ──▶ ステータスバー
                            │
                            └──▶ updateState()             ──▶ ズーム/サイズ表示
                                       │
Webviewメッセージ    ──▶ onDidReceiveMessage [90-106行目]
(size, zoom)               │
                           ▼
                      ステータスバー更新 [161-175行目]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| extension.ts | `extensions/media-preview/src/extension.ts` | ソース | エントリーポイント |
| imagePreview/index.ts | `extensions/media-preview/src/imagePreview/index.ts` | ソース | 画像プレビューロジック |
| audioPreview.ts | `extensions/media-preview/src/audioPreview.ts` | ソース | 音声プレビューロジック |
| videoPreview.ts | `extensions/media-preview/src/videoPreview.ts` | ソース | 動画プレビューロジック |
| mediaPreview.ts | `extensions/media-preview/src/mediaPreview.ts` | ソース | 基底クラス |
| binarySizeStatusBarEntry.ts | `extensions/media-preview/src/binarySizeStatusBarEntry.ts` | ソース | ファイルサイズ表示 |
| sizeStatusBarEntry.ts | `extensions/media-preview/src/imagePreview/sizeStatusBarEntry.ts` | ソース | 画像サイズ表示 |
| zoomStatusBarEntry.ts | `extensions/media-preview/src/imagePreview/zoomStatusBarEntry.ts` | ソース | ズーム倍率表示 |
| package.json | `extensions/media-preview/package.json` | 設定 | マニフェスト、カスタムエディタ定義 |
| media/imagePreview.js | `extensions/media-preview/media/imagePreview.js` | スクリプト | Webview内スクリプト |
| media/imagePreview.css | `extensions/media-preview/media/imagePreview.css` | スタイル | Webview内スタイル |
