# カメラ・撮影仕様書 (Camera & Capture Specification)

本ドキュメントでは，MiniTIAS のカメラ制御・撮影フロー・保存ファイルの仕様を定義する．

- 画面・UI・パーミッションは [SPEC_01 画面機能仕様書](SPEC_01_画面機能仕様書.md) を参照
- アーキテクチャ・非機能要件は [SPEC_03 アーキテクチャと非機能](SPEC_03_アーキテクチャと非機能.md) を参照
- 定量モードの設計経緯・合意（SHADING_MODE 等の根拠）は [05_TECH](../05_TECH/TECH_01_定量モード設計の経緯と合意.md) を参照

## カメラ制御仕様 (Camera Control)

### プレビュー設定（フレーミング用）

| 項目 | 値 |
| --- | --- |
| 使用カメラ | フロントカメラ（インカメラ） |
| 解像度 | `ResolutionPreset.max` |
| 制御方式 | `camera` パッケージ（オート任せ） |
| フラッシュ | OFF（LED ライトはアタッチメント側で制御） |

プレビューは見やすさ重視．撮影時は別の Camera2 セッションが走る．

### 撮影設定（定量モード．Camera2 API マニュアル制御）

| 項目 | 値 |
| --- | --- |
| 使用カメラ | フロントカメラ（インカメラ） |
| 解像度 | 3264×2448（センサ最大） |
| 画像フォーマット | `RAW_SENSOR`（10-bit BGGR Bayer）．`DngCreator` で DNG ファイル出力 |
| `CONTROL_MODE` | OFF（マニュアル全制御） |
| `CONTROL_AE_MODE` | OFF |
| `SENSOR_EXPOSURE_TIME` | 8,333,333 ns（1/120 s）固定（アタッチメント + LED 環境で線形領域中央狙い．定量モード合意の目標 mean G = 400〜600 達成済み．05_TECH 参照） |
| `SENSOR_SENSITIVITY` | 40（センサ最低 ISO）固定 |
| `SENSOR_FRAME_DURATION` | 33,333,333 ns（30fps 相当） |
| `BLACK_LEVEL_LOCK` | true |
| `CONTROL_AWB_MODE` | OFF |
| `COLOR_CORRECTION_GAINS` | (1.0, 1.0, 1.0, 1.0) |
| `COLOR_CORRECTION_TRANSFORM` | 単位行列 |
| `NOISE_REDUCTION_MODE` | OFF |
| `EDGE_MODE` | OFF |
| `TONEMAP_MODE` | `CONTRAST_CURVE` 線形 `[(0,0),(1,1)]` |
| `SHADING_MODE` | HIGH_QUALITY（LSC マップ実値取得のため．画像は LSC 補正済み．PC 側で逆適用可） |
| `STATISTICS_LENS_SHADING_MAP_MODE` | ON |
| `CONTROL_AF_MODE` | OFF（AQUOS sense3 は固定焦点） |
| `FLASH_MODE` | OFF |

### 既存 PNG 撮影パス（無効化済み・コードは温存）

旧 YUV→BT.601→PNG 経路は `RawCapturePlugin.captureFullResolutionPng` として残存．現状の `takePicture` フローからは呼ばれない．差分比較やフォールバック用に保持．

### プレビュー表示

- `camera` パッケージの `CameraPreview` ウィジェットを使用する
- UI 全体を `Transform.rotate(angle: pi)` で 180° 回転する
- カメラ映像に `Matrix4.diagonal3Values(-scale, -scale, 1.0)` を適用する
  - X 軸反転: 鏡像表示（操作者が自然に見える向き）
  - Y 軸反転: 端末が逆さのため上下を補正
- プレビューは画面いっぱいに拡大し，はみ出す部分はクロップする（`ClipRect` + スケール計算）

### 撮影フロー（定量モード）

```text
シャッターボタンタップ
    │
    ▼
プレビュー停止（CameraController.dispose()）
    │
    ▼
baseName 生成（MiniTIAS_QM_YYYYMMDD_HHmmss．重複時 _1, _2 ...）
    │
    ▼
Camera2 API でフロントカメラを開く（RAW_SENSOR，3264×2448）
    │
    ▼
上記マニュアル制御パラメータを CaptureRequest に適用
    │
    ▼
連続 3 枚キャプチャ（設定反映のため最初の 2 枚は破棄）
    │
    ▼
3 枚目の Image + TotalCaptureResult を取得
    │
    ▼
DngCreator で DNG ファイルを直接書き込み（FileOutputStream）
  → Pictures/MiniTIAS/{baseName}.dng（約 16 MB）
    │
    ▼
LSC マップ取得（CaptureResult.STATISTICS_LENS_SHADING_CORRECTION_MAP）
    │
    ▼
メタデータ Map 構築（settings / actual / sensorCharacteristics / lscMap / image_statistics / hot_pixel_map）
    │
    ▼
Dart 側で JSON 保存
  → Pictures/MiniTIAS/{baseName}.meta.json
    │
    ▼
[並行] シャッター押下時に取得済みのライブプレビュースナップショット JPEG を保存
  → Pictures/MiniTIAS/{baseName}.preview.jpg
  ※ スナップショット取得失敗時は preview.jpg を保存しない（撮影全体は失敗扱いにしない）
    │
    ▼
MediaStore 通知（DNG / meta.json / preview.jpg すべて scanFile）
    │
    ▼
Camera2 を閉じ，プレビューを再開
    │
    ▼
スナックバーで保存完了を通知
```

### ライフサイクル管理

- `WidgetsBindingObserver` を使用し，アプリのライフサイクルを監視する
- **バックグラウンド遷移時**（`paused`）: カメラリソースを解放する（`CameraController.dispose()`）
- **フォアグラウンド復帰時**（`resumed`）: カメラを再初期化する
- 画面遷移でカメラを使用しない画面に移動した場合もカメラリソースを解放する

## ファイル管理仕様 (File Management)

### 保存先

- パス: `Pictures/MiniTIAS/`（Android 共有ストレージ）
- ネイティブ側で共有ストレージに直接書き込み，保存後に `MediaScannerConnection.scanFile`（MethodChannel `scanFile`）で MediaStore に登録する
- ディレクトリが存在しない場合は自動作成する

### ファイル命名規則

撮影 1 回で 3 ファイルを生成する（baseName は共通．重複時 `_1`, `_2` ...）：

| 種別 | ファイル名 | 概要 |
| --- | --- | --- |
| RAW 画像 | `MiniTIAS_QM_YYYYMMDD_HHmmss.dng` | 解析の本体（10-bit BGGR Bayer，約 16 MB） |
| メタデータ | `MiniTIAS_QM_YYYYMMDD_HHmmss.meta.json` | 撮影設定 + 実適用値 + LSC マップ + センサ特性（約 24 KB） |
| プレビュー | `MiniTIAS_QM_YYYYMMDD_HHmmss.preview.jpg` | アプリ内表示用の縮小プレビュー．シャッター瞬間のライブプレビュー（自動 ISP 処理済み YUV→JPEG）をそのまま保存．解像度はプレビューストリーム依存（おそらく 1280×720 程度） |

- タイムスタンプはデバイスのローカル時刻を使用する
- 旧通常モードの `MiniTIAS_YYYYMMDD_HHmmss.png` は引き続き一覧に表示可能（後方互換）．新規撮影は QM 形式で行われる

### 重複回避ロジック

```text
baseName = "MiniTIAS_QM_{timestamp}"

IF "{baseName}.dng" が存在しない:
    RETURN baseName

suffix = 1
WHILE "{baseName}_{suffix}.dng" が存在する:
    suffix += 1

RETURN "{baseName}_{suffix}"
```

※ baseName をもとに `.dng` / `.meta.json` / `.preview.jpg` の 3 ファイルを共通名で生成する．

### 削除

- 一覧画面の詳細表示オーバーレイから削除を実行する
- 削除前に確認ダイアログを表示する
  - `.preview.jpg` の場合：「この画像を削除しますか？(DNG ファイルとメタデータも一緒に削除されます)」
  - `.png`（旧通常モード）の場合：「この画像を削除しますか？」
- `.preview.jpg` 削除時は同 baseName の `.dng` と `.meta.json` も**連動削除**する
- ファイルシステムから物理削除する（ゴミ箱機能なし）
- 削除後，MediaStore からも当該エントリを除去する
