/// Overlay visuel pour le recadrage d'image. /// /// Affiche un masque semi-transparent avec une zone carrée transparente /// au centre pour indiquer la zone de recadrage. library; import 'package:flutter/material.dart'; class CropOverlay extends StatelessWidget { /// Taille du carré de recadrage (côté en pixels) final double cropSize; /// Afficher la grille des tiers final bool showGrid; const CropOverlay({ super.key, required this.cropSize, this.showGrid = true, }); @override Widget build(BuildContext context) { return CustomPaint( size: Size.infinite, painter: _CropOverlayPainter( cropSize: cropSize, showGrid: showGrid, ), ); } } class _CropOverlayPainter extends CustomPainter { final double cropSize; final bool showGrid; _CropOverlayPainter({ required this.cropSize, required this.showGrid, }); @override void paint(Canvas canvas, Size size) { // Calculer la position du carré centré final cropRect = Rect.fromCenter( center: Offset(size.width / 2, size.height / 2), width: cropSize, height: cropSize, ); // Dessiner le masque semi-transparent final maskPaint = Paint() ..color = Colors.black.withValues(alpha: 0.6) ..style = PaintingStyle.fill; // Créer un path pour le masque (tout sauf le carré central) final maskPath = Path() ..addRect(Rect.fromLTWH(0, 0, size.width, size.height)) ..addRect(cropRect) ..fillType = PathFillType.evenOdd; canvas.drawPath(maskPath, maskPaint); // Dessiner la bordure du carré de recadrage final borderPaint = Paint() ..color = Colors.white ..style = PaintingStyle.stroke ..strokeWidth = 2; canvas.drawRect(cropRect, borderPaint); // Dessiner les coins accentués _drawCorners(canvas, cropRect); // Dessiner la grille des tiers si activée if (showGrid) { _drawGrid(canvas, cropRect); } } void _drawCorners(Canvas canvas, Rect rect) { final cornerPaint = Paint() ..color = Colors.white ..style = PaintingStyle.stroke ..strokeWidth = 4 ..strokeCap = StrokeCap.round; const cornerLength = 20.0; // Coin supérieur gauche canvas.drawLine( Offset(rect.left, rect.top + cornerLength), Offset(rect.left, rect.top), cornerPaint, ); canvas.drawLine( Offset(rect.left, rect.top), Offset(rect.left + cornerLength, rect.top), cornerPaint, ); // Coin supérieur droit canvas.drawLine( Offset(rect.right - cornerLength, rect.top), Offset(rect.right, rect.top), cornerPaint, ); canvas.drawLine( Offset(rect.right, rect.top), Offset(rect.right, rect.top + cornerLength), cornerPaint, ); // Coin inférieur gauche canvas.drawLine( Offset(rect.left, rect.bottom - cornerLength), Offset(rect.left, rect.bottom), cornerPaint, ); canvas.drawLine( Offset(rect.left, rect.bottom), Offset(rect.left + cornerLength, rect.bottom), cornerPaint, ); // Coin inférieur droit canvas.drawLine( Offset(rect.right - cornerLength, rect.bottom), Offset(rect.right, rect.bottom), cornerPaint, ); canvas.drawLine( Offset(rect.right, rect.bottom), Offset(rect.right, rect.bottom - cornerLength), cornerPaint, ); } void _drawGrid(Canvas canvas, Rect rect) { final gridPaint = Paint() ..color = Colors.white.withValues(alpha: 0.4) ..style = PaintingStyle.stroke ..strokeWidth = 1; final thirdWidth = rect.width / 3; final thirdHeight = rect.height / 3; // Lignes verticales canvas.drawLine( Offset(rect.left + thirdWidth, rect.top), Offset(rect.left + thirdWidth, rect.bottom), gridPaint, ); canvas.drawLine( Offset(rect.left + thirdWidth * 2, rect.top), Offset(rect.left + thirdWidth * 2, rect.bottom), gridPaint, ); // Lignes horizontales canvas.drawLine( Offset(rect.left, rect.top + thirdHeight), Offset(rect.right, rect.top + thirdHeight), gridPaint, ); canvas.drawLine( Offset(rect.left, rect.top + thirdHeight * 2), Offset(rect.right, rect.top + thirdHeight * 2), gridPaint, ); } @override bool shouldRepaint(covariant _CropOverlayPainter oldDelegate) { return cropSize != oldDelegate.cropSize || showGrid != oldDelegate.showGrid; } }