class ViewRect { final double left; final double top; final double right; final double bottom; const ViewRect(this.left, this.top, this.right, this.bottom); double get width => right - left; double get height => bottom - top; double get centerX => (left + right) / 2; double get centerY => (top + bottom) / 2; } /// 模型归一化坐标 → 预览视图坐标(含传感器旋转与 FIT_COVER 全屏裁剪)。 class CoordinateMapper { static ViewRect mapToView( double normLeft, double normTop, double normRight, double normBottom, int rotation, int imageW, int imageH, double viewW, double viewH, ) { // 1) 旋转校正:图像方向 → 竖屏视图方向(归一化坐标) late final double x0, y0, x1, y1; switch (rotation) { case 90: x0 = 1 - normBottom; y0 = normLeft; x1 = 1 - normTop; y1 = normRight; case 180: x0 = 1 - normRight; y0 = 1 - normBottom; x1 = 1 - normLeft; y1 = 1 - normTop; case 270: x0 = normTop; y0 = 1 - normRight; x1 = normBottom; y1 = 1 - normLeft; default: x0 = normLeft; y0 = normTop; x1 = normRight; y1 = normBottom; } // 2) 旋转后图像在竖屏方向上的尺寸 final portrait = rotation == 90 || rotation == 270; final portW = portrait ? imageH : imageW; final portH = portrait ? imageW : imageH; // 3) FIT_COVER 缩放与居中裁剪:放大到铺满视图,溢出部分裁掉 final scale = viewW / portW < viewH / portH ? viewH / portH : viewW / portW; final offsetX = (viewW - portW * scale) / 2; final offsetY = (viewH - portH * scale) / 2; return ViewRect( x0 * portW * scale + offsetX, y0 * portH * scale + offsetY, x1 * portW * scale + offsetX, y1 * portH * scale + offsetY, ); } }