Future rotateAndCropImage(File imageFile) async { Uint8List imageBytes = await imageFile.readAsBytes(); img.Image? original = img.decodeImage(imageBytes); if (original == null) return imageFile; img.Image rotated = img.bakeOrientation(original); int width = rotated.width; int height = rotated.height; bool isPortrait = height > width; int cropWidth, cropHeight; if (isPortrait) { cropHeight = (height * 0.7).toInt(); cropWidth = (cropHeight ~/ 1.59).toInt(); } else { cropWidth = (width * 0.7).toInt(); cropHeight = (cropWidth ~/ 1.59).toInt(); } int left = ((width - cropWidth) ~/ 2).toInt(); int top = ((height - cropHeight) ~/ 2).toInt(); img.Image cropped = img.copyCrop(rotated, x: left, y: top, width: cropWidth, height: cropHeight); File croppedFile = File('${imageFile.path}_cropped.jpg'); await croppedFile.writeAsBytes(img.encodeJpg(cropped)); return croppedFile; } Future rotateImage(File imageFile) async { Uint8List bytes = await imageFile.readAsBytes(); img.Image? image = img.decodeImage(bytes); if (image == null) return imageFile; img.Image rotated = img.copyRotate(image, angle: -90); File rotatedFile = File('${imageFile.path}_rotated.jpg'); await rotatedFile.writeAsBytes(img.encodeJpg(rotated)); return rotatedFile; } Future captureAndCropImage() async { try { isLoading.value = true; await initializeControllerFuture.value; // Ambil gambar dari kamera final image = await cameraController.value!.takePicture(); File cropped = await rotateAndCropImage(File(image.path)); // Rotate gambar setelah cropping File rotatedImage = await rotateImage(cropped); // Simpan hasil yang sudah di-crop dan di-rotate capturedImage.value = image; croppedImage.value = rotatedImage; // post ke BE Uint8List bytes = await croppedImage.value!.readAsBytes(); String base64String = base64Encode(bytes); ref.read(uploadScanProvider.notifier).uploadScan( host: host, base64File: base64String, userId: userId, ); } catch (e) { print("Error capturing image: $e"); } finally { isLoading.value = false; } }