fix: recentrage incorrect si loin du centre d origine

This commit is contained in:
qguillaume
2026-06-11 21:20:46 +02:00
parent 653aa5d5b0
commit 9ffb1025cb
2 changed files with 18 additions and 6 deletions

View File

@@ -407,6 +407,9 @@ class _CropScreenState extends State<CropScreen> {
offsetDy: _offset.dy,
displayPerSourcePx: displayPerSourcePx,
cropSizeDisplay: _cropSize,
// Le zoom sert UNIQUEMENT à viser le bon point (mapping du décalage) ;
// il n'agrandit pas le rendu de sortie.
zoomScale: _scale,
rotationDegrees: _rotation,
);

View File

@@ -105,6 +105,7 @@ class _ViewportCropParams {
final double offsetDy;
final double displayPerSourcePx; // facteur affichage/source (BoxFit.contain)
final double cropSizeDisplay; // côté de la fenêtre de visée, en pixels écran
final double zoomScale; // zoom utilisateur : sert UNIQUEMENT au pointage
final double rotationDegrees;
final int outputSize;
final String outputPath;
@@ -115,6 +116,7 @@ class _ViewportCropParams {
required this.offsetDy,
required this.displayPerSourcePx,
required this.cropSizeDisplay,
required this.zoomScale,
required this.rotationDegrees,
required this.outputSize,
required this.outputPath,
@@ -143,14 +145,19 @@ void _viewportCropIsolateEntry(_ViewportCropParams p) {
}
final double f = p.displayPerSourcePx;
// Côté de la fenêtre de visée, exprimé en pixels source (rotation = même échelle)
// Côté de la fenêtre de visée en pixels source. On utilise f SEUL (pas le
// zoom) → le champ de vision capturé est toujours celui de l'image non
// zoomée : le zoom n'est donc PAS pris en compte dans le rendu de sortie.
final int side = math.max(1, (p.cropSizeDisplay / f).round());
// Centre de la fenêtre de visée, en pixels de l'image (rotated) :
// le centre de l'image est affiché à (centre_viewport + offset), la fenêtre
// est centrée sur le viewport → décalage de -offset/f par rapport au centre.
final double cropCenterX = rotated.width / 2 - p.offsetDx / f;
final double cropCenterY = rotated.height / 2 - p.offsetDy / f;
// Centre de la fenêtre de visée, en pixels de l'image (rotated).
// La translation écran s'applique APRÈS le zoom, donc un déplacement écran
// `offset` vaut `offset / (f * zoom)` pixels source. On inclut donc le zoom
// ICI (uniquement pour le pointage) afin que la croix vise le même point
// quel que soit le niveau de zoom.
final double fz = f * p.zoomScale;
final double cropCenterX = rotated.width / 2 - p.offsetDx / fz;
final double cropCenterY = rotated.height / 2 - p.offsetDy / fz;
final int srcX = (cropCenterX - side / 2).round();
final int srcY = (cropCenterY - side / 2).round();
@@ -212,6 +219,7 @@ class ImageCropService {
required double offsetDy,
required double displayPerSourcePx,
required double cropSizeDisplay,
double zoomScale = 1.0,
double rotationDegrees = 0.0,
int outputSize = maxOutputSize,
}) async {
@@ -224,6 +232,7 @@ class ImageCropService {
offsetDy: offsetDy,
displayPerSourcePx: displayPerSourcePx,
cropSizeDisplay: cropSizeDisplay,
zoomScale: zoomScale <= 0 ? 1.0 : zoomScale,
rotationDegrees: rotationDegrees,
outputSize: outputSize,
outputPath: outputPath,