fix: recentrage incorrect si loin du centre d origine

This commit is contained in:
qguillaume
2026-06-11 20:47:47 +02:00
parent 8e64839fc6
commit fec33a327a
2 changed files with 128 additions and 51 deletions

View File

@@ -389,19 +389,24 @@ class _CropScreenState extends State<CropScreen> {
Future<void> _onCropConfirm() async {
setState(() => _isLoading = true);
try {
// La zone de découpe doit refléter le DÉPLACEMENT (pan) et la ROTATION,
// mais PAS le ZOOM. On neutralise donc temporairement _scale à 1.0 pour
// le calcul, tout en conservant _offset. La rotation est appliquée à part
// par cropToSquare(rotationDegrees: _rotation).
final savedScale = _scale;
_scale = 1.0;
final cropRect = _calculateCropRect();
_scale = savedScale; // on restaure pour l'affichage (retour arrière)
// Facteur d'échelle affichage/source (BoxFit.contain) — identique à
// celui utilisé pour afficher l'image dans l'aperçu.
final imageAspect = _imageSize!.width / _imageSize!.height;
final viewportAspect = _viewportSize.width / _viewportSize.height;
final double displayWidth = imageAspect > viewportAspect
? _viewportSize.width
: _viewportSize.height * imageAspect;
final double displayPerSourcePx = displayWidth / _imageSize!.width;
// AJOUT DE LA DECOUPE ET DU REDRESSEMENT GÉOMÉTRIQUE PHYSIQUE
final croppedImagePath = await _cropService.cropToSquare(
widget.imagePath,
cropRect,
// Découpe calée sur la fenêtre de visée : le DÉPLACEMENT (pan) et la
// ROTATION sont pris en compte, le ZOOM est ignoré, et les débordements
// sont remplis en noir → la position choisie est respectée à l'identique.
final croppedImagePath = await _cropService.cropViewport(
sourcePath: widget.imagePath,
offsetDx: _offset.dx,
offsetDy: _offset.dy,
displayPerSourcePx: displayPerSourcePx,
cropSizeDisplay: _cropSize,
rotationDegrees: _rotation,
);
@@ -438,43 +443,4 @@ class _CropScreenState extends State<CropScreen> {
}
}
CropRect _calculateCropRect() {
if (_imageSize == null) return const CropRect(x: 0, y: 0, width: 1, height: 1);
final imageAspect = _imageSize!.width / _imageSize!.height;
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;
}
final scaledWidth = displayWidth * _scale;
final scaledHeight = displayHeight * _scale;
final imageCenterX = _viewportSize.width / 2 + _offset.dx;
final imageCenterY = _viewportSize.height / 2 + _offset.dy;
final imageLeft = imageCenterX - scaledWidth / 2;
final imageTop = imageCenterY - scaledHeight / 2;
final cropLeft = (_viewportSize.width - _cropSize) / 2;
final cropTop = (_viewportSize.height - _cropSize) / 2;
final relCropLeft = (cropLeft - imageLeft) / scaledWidth;
final relCropTop = (cropTop - imageTop) / scaledHeight;
final relCropWidth = _cropSize / scaledWidth;
final relCropHeight = _cropSize / scaledHeight;
return CropRect(
x: relCropLeft.clamp(0.0, 1.0),
y: relCropTop.clamp(0.0, 1.0),
width: relCropWidth.clamp(0.0, 1.0),
height: relCropHeight.clamp(0.0, 1.0),
);
}
}