/// プレビュー表示領域を表す正規化矩形(不変クラス).
///
/// 撮影画像(フル領域)に対する正規化座標(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<right,top<bottom)かどうか.
bool get isValid =>
left >= 0.0 &&
left < right &&
right <= 1.0 &&
top >= 0.0 &&
top < bottom &&
bottom <= 1.0;
/// JSON マップから [PreviewRegion] を生成する.
///
/// 値が数値でない/欠落している場合はフォールバック値(フル領域)を用いる.
factory PreviewRegion.fromJson(Map<String, Object?> 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),
);
}
}