fix(camera): synchroniser le ratio de visée 3/4 avec le capteur natif et corriger le décalage du crop

This commit is contained in:
qguillaume
2026-05-27 17:44:57 +02:00
parent 730629a031
commit a5d0251545
3 changed files with 76 additions and 7 deletions

View File

@@ -13,7 +13,7 @@ import '../../data/models/target_type.dart';
import '../crop/crop_screen.dart';
import '../session/session_provider.dart';
import 'widgets/image_source_button.dart';
import '../../services/image_crop_service.dart';
class CaptureScreen extends StatefulWidget {
const CaptureScreen({super.key});
@@ -23,10 +23,12 @@ class CaptureScreen extends StatefulWidget {
class _CaptureScreenState extends State<CaptureScreen> with SingleTickerProviderStateMixin {
final ImagePicker _picker = ImagePicker();
final ImageCropService _cropService = ImageCropService();
final TargetType _selectedType = TargetType.concentric;
String? _selectedImagePath;
bool _isLoading = false;
// AJOUT : Variables de gestion du flux caméra en direct
CameraController? _cameraController;
List<CameraDescription>? _cameras;
@@ -76,11 +78,14 @@ class _CaptureScreenState extends State<CaptureScreen> with SingleTickerProvider
if (_cameras != null && _cameras!.isNotEmpty) {
_cameraController = CameraController(
_cameras![0],
ResolutionPreset.high,
ResolutionPreset.max, // Force le 4:3 natif au maximum du capteur
enableAudio: false,
imageFormatGroup: ImageFormatGroup.jpeg,
);
// INITIALISATION UNIQUE ET PROPRE :
await _cameraController!.initialize();
setState(() {
_isCameraInitialized = true;
_showLiveCamera = true;
@@ -215,7 +220,12 @@ class _CaptureScreenState extends State<CaptureScreen> with SingleTickerProvider
fit: StackFit.expand,
children: [
// 1. Le flux vidéo de la caméra
CameraPreview(_cameraController!),
Center(
child: AspectRatio(
aspectRatio: 3 / 4, // Aligné sur le format natif du capteur photo
child: CameraPreview(_cameraController!),
),
),
// 2. L'ASSISTANT DE CADRAGE VIRTUEL (Avec le grand cadre complet et la petite cible)
Center(
@@ -384,15 +394,15 @@ class _CaptureScreenState extends State<CaptureScreen> with SingleTickerProvider
setState(() => _isLoading = true);
try {
// Prise de la photo
// 1. On prend la photo brute normale (sans y toucher)
final XFile photo = await _cameraController!.takePicture();
setState(() {
_selectedImagePath = photo.path;
_showLiveCamera = false; // Quitte la vue caméra
_showLiveCamera = false;
});
// Redirection automatique vers l'écran de Crop
// 2. On l'envoie directement à l'analyse
_analyzeImage();
} catch (e) {
debugPrint('Erreur lors du clic photo: $e');

View File

@@ -237,7 +237,22 @@ class _CropScreenState extends State<CropScreen> {
return LayoutBuilder(
builder: (context, constraints) {
_viewportSize = Size(constraints.maxWidth, constraints.maxHeight);
_cropSize = math.min(constraints.maxWidth, constraints.maxHeight) * 0.95;
// FIX : On calcule d'abord la taille de la photo affichée avant de définir la taille du cadre vert !
final imageAspect = _imageSize != null ? _imageSize!.width / _imageSize!.height : 1.0;
final viewportAspect = _viewportSize.width / _viewportSize.height;
double displayWidth, displayHeight;
if (imageAspect > viewportAspect) {
displayWidth = _viewportSize.width;
displayHeight = _viewportSize.width / imageAspect;
} else {
displayHeight = _viewportSize.height;
displayWidth = _viewportSize.height * imageAspect;
}
// On passe de 0.95 à 0.85 pour matcher parfaitement avec l'appareil photo !
_cropSize = math.min(displayWidth, displayHeight)* 0.85;
if (_scale == 1.0 && _offset == Offset.zero && _rotation == 0.0) {
_initializeImagePosition();
@@ -333,6 +348,7 @@ class _CropScreenState extends State<CropScreen> {
final imageAspect = _imageSize!.width / _imageSize!.height;
final viewportAspect = _viewportSize.width / _viewportSize.height;
// 1. Calcul strict de la taille de l'image affichée en BoxFit.contain
double displayWidth, displayHeight;
if (imageAspect > viewportAspect) {
displayWidth = _viewportSize.width;
@@ -344,11 +360,15 @@ class _CropScreenState extends State<CropScreen> {
final minDisplayDim = math.min(displayWidth, displayHeight);
// 2. Calcul du scale initial basé sur la dimension de l'image (et non du viewport)
_scale = widget.initialScale ?? (_cropSize / minDisplayDim);
if (_scale < 1.0 && widget.initialScale == null) _scale = 1.0;
// 3. Réinitialisation propre de l'offset au centre de la zone d'affichage
if (widget.initialOffset != null) {
_offset = widget.initialOffset!;
} else {
_offset = Offset.zero; // Force l'image à se centrer parfaitement sur la croix verte
}
}