card-recog-demo/lib/widgets/guide_frame.dart
a1518 ccf8eeb21d Initial commit: Flutter card recognition demo
Camera capture, corner detection/refinement, and preview crop pipeline for trading cards.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-12 20:17:32 -07:00

58 lines
1.7 KiB
Dart

import 'dart:math' as math;
import 'dart:ui';
/// Shared capture guide geometry (same as the on-screen shooting frame).
class GuideFrame {
static const double aspect = 63 / 88;
static const double maxHeightFraction = 0.62;
static const double maxWidthFraction = 0.78;
static const double centerYFraction = 0.46;
/// Guide rect inside a viewport (preview overlay coordinates).
static Rect inViewport(Size size) {
final maxH = size.height * maxHeightFraction;
final maxW = size.width * maxWidthFraction;
var h = maxH;
var w = h * aspect;
if (w > maxW) {
w = maxW;
h = w / aspect;
}
return Rect.fromCenter(
center: Offset(size.width / 2, size.height * centerYFraction),
width: w,
height: h,
);
}
/// Map the viewport guide into image pixels when the image is shown with
/// [BoxFit.cover] in [viewport] (camera preview).
static Rect inCoverImage({
required Size viewport,
required Size imageSize,
}) {
final guide = inViewport(viewport);
final scale = math.max(
viewport.width / imageSize.width,
viewport.height / imageSize.height,
);
final dispW = imageSize.width * scale;
final dispH = imageSize.height * scale;
final ox = (viewport.width - dispW) / 2;
final oy = (viewport.height - dispH) / 2;
final mapped = Rect.fromLTRB(
(guide.left - ox) / scale,
(guide.top - oy) / scale,
(guide.right - ox) / scale,
(guide.bottom - oy) / scale,
);
return mapped.intersect(
Rect.fromLTWH(0, 0, imageSize.width, imageSize.height),
);
}
/// Guide applied directly in image space (gallery / no viewport).
static Rect inImage(Size imageSize) => inViewport(imageSize);
}