import 'dart:math' as math; import 'package:flutter/material.dart'; import 'package:smtias_capture/models/preview_region.dart'; /// 表示向き適用済みの全体コンテンツ [child] を [region](表示後の画面座標 0.0–1.0)で /// 切り出して画面いっぱいに拡大表示する(WYSIWYG). /// /// ライブプレビュー([child] = CameraPreview)と保存中スナップショット /// ([child] = 画像)で共通利用し,同じ領域・同じ拡大で表示を一致させる. class RegionCrop extends StatelessWidget { const RegionCrop({super.key, required this.region, required this.child}); /// クロップ領域(表示後の画面座標 0.0–1.0). final PreviewRegion region; /// クロップ対象(表示向き適用済みで領域全体を埋めるコンテンツ). final Widget child; @override Widget build(BuildContext context) { if (region.isFull) { return child; } return LayoutBuilder( builder: (context, constraints) { final double w = constraints.maxWidth; final double h = constraints.maxHeight; final double roiCx = (region.left + region.right) / 2.0; final double roiCy = (region.top + region.bottom) / 2.0; // ROI 中心を画面中心へ寄せる平行移動量(画面ピクセル) final double dx = (0.5 - roiCx) * w; final double dy = (0.5 - roiCy) * h; // ROI 全体を画面に収める contain ズーム(縦横同一スケールで歪み防止) final double zoom = math.min(1.0 / region.width, 1.0 / region.height); return ClipRect( child: Transform.scale( scale: zoom, alignment: Alignment.center, child: Transform.translate( offset: Offset(dx, dy), child: SizedBox(width: w, height: h, child: child), ), ), ); }, ); } }