/// プレビュー表示領域を表す正規化矩形(不変クラス). /// /// 撮影画像(フル領域)に対する正規化座標(0.0–1.0)で, /// CameraPreview をクロップ表示する領域を表す. /// 撮影画像の出力には影響しない(プレビュー表示のみ). class PreviewRegion { /// 左端(0.0–1.0). final double left; /// 上端(0.0–1.0). final double top; /// 右端(0.0–1.0). final double right; /// 下端(0.0–1.0). final double bottom; const PreviewRegion({ required this.left, required this.top, required this.right, required this.bottom, }); /// クロップなし(フル領域)を表す矩形. /// /// config 読み込み失敗時のフォールバックとして使用する. static const PreviewRegion full = PreviewRegion( left: 0.0, top: 0.0, right: 1.0, bottom: 1.0, ); /// クロップ領域の幅(正規化). double get width => right - left; /// クロップ領域の高さ(正規化). double get height => bottom - top; /// フル領域(クロップ不要)かどうか. bool get isFull => left <= 0.0 && top <= 0.0 && right >= 1.0 && bottom >= 1.0; /// 各値が有効範囲内(0.0–1.0,left left >= 0.0 && left < right && right <= 1.0 && top >= 0.0 && top < bottom && bottom <= 1.0; /// JSON マップから [PreviewRegion] を生成する. /// /// 値が数値でない/欠落している場合はフォールバック値(フル領域)を用いる. factory PreviewRegion.fromJson(Map json) { double parse(Object? value, double fallback) { if (value is num) return value.toDouble(); return fallback; } return PreviewRegion( left: parse(json['left'], full.left), top: parse(json['top'], full.top), right: parse(json['right'], full.right), bottom: parse(json['bottom'], full.bottom), ); } }