capture_helper 1.1.1
capture_helper: ^1.1.1 copied to clipboard
Cross-platform Flutter plugin for advanced document capture, image enhancement, and PDF compression. Uses native VisionKit (iOS) and ML Kit (Android) for optimal results.
Capture Helper #
Un plugin Flutter pour la numérisation de documents avec compression d'images intégrée, utilisant VisionKit (iOS) et ML Kit Document Scanner (Android).
📋 Table des matières #
- Fonctionnalités
- Plateformes supportées
- Installation
- Configuration
- 🚀 Démarrage rapide
- Utilisation
- API
- Limitations
- 📚 Plus d'exemples
📚 Documentation complète #
- CHEATSHEET.md - Aide-mémoire rapide avec toutes les commandes
- EXAMPLES.md - Exemples de code détaillés pour tous les cas d'usage
- TROUBLESHOOTING.md - Guide de résolution des problèmes
- docs/TECHS.md - Documentation technique complète
Fonctionnalités #
- ✅ Numérisation de documents avec détection automatique des bords
- ✅ Support multi-pages en une seule session
- ✅ Compression d'images avec contrôle de la qualité
- ✅ Compression PDF pour réduire la taille des fichiers
- ✅ Interface native sur iOS et Android
- ✅ Gestion automatique des permissions caméra
- ✅ Architecture propre basée sur Pigeon
Plateformes supportées #
| Plateforme | Version minimale | API native |
|---|---|---|
| iOS | 13.0+ | VisionKit |
| Android | API 21+ (5.0) | ML Kit |
Installation #
Ajoutez cette ligne à votre fichier pubspec.yaml :
dependencies:
capture_helper:
path: ../capture_helper
Puis exécutez :
flutter pub get
Configuration #
iOS #
Ajoutez la permission caméra dans votre ios/Runner/Info.plist :
<key>NSCameraUsageDescription</key>
<string>This app needs camera access to scan documents</string>
Android #
Les permissions sont automatiquement ajoutées via le manifest du plugin. Assurez-vous que votre android/build.gradle a les bonnes configurations :
android {
compileSdkVersion 36
minSdkVersion 24
}
⚠️ Important : Version Java
Ce plugin nécessite Java 17, 21 ou 23. Java 24 n'est pas encore compatible avec Gradle 8.12.
# Vérifier votre version Java
flutter doctor -v
# Si vous avez Java 24, installer Java 21 (recommandé)
# macOS avec Homebrew :
brew install openjdk@21
flutter config --jdk-dir=/opt/homebrew/opt/openjdk@21
Pour plus de détails, consultez TROUBLESHOOTING.md.
🚀 Démarrage rapide #
import 'package:capture_helper/capture_helper.dart';
// 1. Scanner un document
final result = await CaptureHelper().scanDocument();
// 2. Compresser l'image
if (result.success && result.imagePaths.isNotEmpty) {
final compressed = await CaptureHelper().compressImage(
imagePath: result.imagePaths.first,
quality: 80,
);
print('Image compressée : ${compressed.outputPath}');
}
Utilisation #
📸 Scanner une image simple #
Scanner un document et récupérer les images sans compression automatique :
import 'package:capture_helper/capture_helper.dart';
final captureHelper = CaptureHelper();
// Vérifier d'abord si le scanner est disponible
final isAvailable = await captureHelper.isScanningAvailable();
if (!isAvailable) {
print('Scanner non disponible sur cet appareil');
return;
}
// Scanner le document
final result = await captureHelper.scanDocument(
options: const CaptureHelperScanOptions(
autoCompress: false, // Pas de compression automatique
compressionQuality: 80,
),
);
// Vérifier le résultat
if (result.success) {
print('✅ Scan réussi ! ${result.imageCount} image(s) scannée(s)');
for (final imagePath in result.imagePaths) {
print('📄 Image : $imagePath');
}
} else if (result.wasCancelled) {
print('❌ Scan annulé par l\'utilisateur');
} else {
print('❌ Erreur : ${result.errorMessage}');
}
📦 Scanner avec compression automatique #
Scanner et compresser automatiquement les images pendant le scan :
final result = await captureHelper.scanDocument(
options: const CaptureHelperScanOptions(
autoCompress: true, // Active la compression automatique
compressionQuality: 70, // Qualité de compression (0-100)
outputFormat: OutputFormat.jpeg, // Format de sortie (jpeg ou png)
),
);
if (result.success) {
print('✅ Images scannées et compressées automatiquement');
print('📁 ${result.imageCount} image(s) dans: ${result.imagePaths}');
}
🎨 Choisir le format de sortie (JPEG vs PNG) #
Le plugin supporte deux formats de sortie :
// Format JPEG (par défaut) - Plus léger, compression avec perte
final resultJPEG = await captureHelper.scanDocument(
options: const CaptureHelperScanOptions(
outputFormat: OutputFormat.jpeg,
compressionQuality: 80,
),
);
// Format PNG - Plus lourd, compression sans perte
// Idéal pour schémas, diagrammes, ou quand la netteté est cruciale
final resultPNG = await captureHelper.scanDocument(
options: const CaptureHelperScanOptions(
outputFormat: OutputFormat.png,
// Note: compressionQuality n'a pas d'effet sur PNG (toujours qualité maximale)
),
);
Quand utiliser PNG ?
- Schémas techniques, diagrammes, graphiques
- Documents avec texte très fin à OCR
- Besoin de qualité maximale sans artefacts
- ⚠️ Fichiers 3-5x plus lourds que JPEG
Quand utiliser JPEG ?
- Documents scannés standards (recommandé)
- Photos de documents
- Fichiers plus légers pour le stockage/partage
- Qualité largement suffisante pour la lecture
🗜️ Compresser une image existante #
Compresser une image déjà scannée pour réduire sa taille :
// Compresser avec qualité moyenne (recommandé pour usage général)
final compressionResult = await captureHelper.compressImage(
imagePath: '/path/to/your/image.jpg',
quality: 80, // Qualité : 0 (min) à 100 (max)
);
if (compressionResult.success) {
print('✅ Compression réussie !');
print('📁 Fichier compressé : ${compressionResult.outputPath}');
print('📊 Statistiques :');
print(' Taille originale : ${compressionResult.formattedOriginalSize}');
print(' Taille compressée : ${compressionResult.formattedCompressedSize}');
print(' Économie : ${compressionResult.formattedSavedBytes}');
print(' Réduction : ${compressionResult.reductionPercentage.toStringAsFixed(1)}%');
} else {
print('❌ Erreur de compression : ${compressionResult.errorMessage}');
}
📏 Scanner avec limite de poids #
Pour contrôler la taille des images scannées, utilisez la compression automatique avec une qualité appropriée :
// Exemple : limiter les images à ~500 KB par page
final result = await captureHelper.scanDocument(
options: const CaptureHelperScanOptions(
autoCompress: true,
compressionQuality: 60, // Ajuster selon la taille souhaitée
),
);
// Vérifier la taille des fichiers générés
if (result.success) {
for (final imagePath in result.imagePaths) {
final file = File(imagePath);
final sizeInBytes = await file.length();
final sizeInKB = sizeInBytes / 1024;
print('📄 Image : ${sizeInKB.toStringAsFixed(0)} KB');
// Si trop grande, compresser davantage
if (sizeInKB > 500) {
final compressed = await captureHelper.compressImage(
imagePath: imagePath,
quality: 50, // Compression plus agressive
);
print(' ➡️ Recompressée à ${compressed.formattedCompressedSize}');
}
}
}
🎯 Guide de qualité de compression #
Choisissez la qualité selon votre cas d'usage :
// Qualité haute (85-100) - Pour impression ou archivage
await captureHelper.compressImage(imagePath: path, quality: 90);
// Qualité moyenne (70-85) - Pour usage général, web
await captureHelper.compressImage(imagePath: path, quality: 80);
// Qualité basse (50-70) - Pour email, partage rapide
await captureHelper.compressImage(imagePath: path, quality: 60);
// Qualité minimale (10-50) - Pour aperçus, miniatures
await captureHelper.compressImage(imagePath: path, quality: 40);
📋 Exemple complet avec gestion d'erreurs #
import 'dart:io';
import 'package:capture_helper/capture_helper.dart';
Future<void> scanAndCompressDocument() async {
final captureHelper = CaptureHelper();
try {
// 1. Vérifier la disponibilité
if (!await captureHelper.isScanningAvailable()) {
throw Exception('Scanner non disponible');
}
// 2. Scanner le document
print('📸 Lancement du scanner...');
final scanResult = await captureHelper.scanDocument(
options: const CaptureHelperScanOptions(
autoCompress: false,
compressionQuality: 80,
),
);
if (!scanResult.success) {
if (scanResult.wasCancelled) {
print('❌ Scan annulé');
return;
}
throw Exception(scanResult.errorMessage);
}
print('✅ ${scanResult.imageCount} image(s) scannée(s)');
// 3. Compresser chaque image
for (int i = 0; i < scanResult.imagePaths.length; i++) {
final imagePath = scanResult.imagePaths[i];
print('\n🗜️ Compression de l\'image ${i + 1}...');
final compressionResult = await captureHelper.compressImage(
imagePath: imagePath,
quality: 75,
);
if (compressionResult.success) {
print(' ✅ Compressée : ${compressionResult.reductionPercentage.toStringAsFixed(1)}% de réduction');
print(' 📁 Fichier : ${compressionResult.outputPath}');
} else {
print(' ⚠️ Échec compression : ${compressionResult.errorMessage}');
}
}
print('\n🎉 Traitement terminé !');
} catch (e) {
print('❌ Erreur : $e');
}
}
📄 Compression de PDF #
Pour compresser un document PDF (iOS uniquement pour l'instant) :
final pdfResult = await captureHelper.compressPdf(
pdfPath: '/path/to/document.pdf',
quality: 75,
);
if (pdfResult.success) {
print('✅ PDF compressé');
print('📁 Nouveau fichier : ${pdfResult.outputPath}');
print('📊 Réduction : ${pdfResult.reductionPercentage.toStringAsFixed(1)}%');
}
API #
CaptureHelper #
La classe principale du plugin (singleton).
Méthodes
Future<bool> isScanningAvailable()- Vérifie si la numérisation est disponibleFuture<CaptureHelperScanResult> scanDocument({CaptureHelperScanOptions options})- Lance la numérisationFuture<CaptureHelperCompressionResult> compressImage({required String imagePath, int quality = 80})- Compresse une imageFuture<CaptureHelperCompressionResult> compressPdf({required String pdfPath, int quality = 80})- Compresse un PDF
CaptureHelperScanOptions #
Options de configuration pour la numérisation.
CaptureHelperScanOptions({
bool autoCompress = false,
int compressionQuality = 80, // 0-100
})
CaptureHelperScanResult #
Résultat d'une numérisation.
Propriétés :
List<String> imagePaths- Chemins des images scannéesbool success- Indique si l'opération a réussiString? errorMessage- Message d'erreur éventuelint imageCount- Nombre d'images scannéesbool wasCancelled- Indique si l'utilisateur a annulé
CaptureHelperCompressionResult #
Résultat d'une compression.
Propriétés :
String? outputPath- Chemin du fichier compresséint originalSize- Taille originale en octetsint compressedSize- Taille compressée en octetsbool success- Indique si l'opération a réussiString? errorMessage- Message d'erreur éventueldouble compressionRatio- Taux de compression (0.0-1.0)double reductionPercentage- Pourcentage de réductionint savedBytes- Octets économisésString formattedOriginalSize- Taille originale formatéeString formattedCompressedSize- Taille compressée formatéeString formattedSavedBytes- Économie formatée
Architecture #
Le plugin utilise Pigeon pour la communication type-safe entre Flutter et le code natif :
lib/
├── capture_helper.dart # API publique
├── src/
│ ├── models/ # Modèles Dart
│ │ ├── scan_options.dart
│ │ ├── scan_result.dart
│ │ └── compression_result.dart
│ └── generated/ # Code généré par Pigeon
│ └── document_scanner_api.g.dart
ios/Classes/
├── CaptureHelperPlugin.swift # Plugin principal iOS
├── Services/
│ ├── DocumentScannerService.swift
│ ├── ImageCompressionService.swift
│ ├── PDFCompressionService.swift
│ └── PermissionManager.swift
└── Generated/ # Code généré par Pigeon
└── DocumentScannerApi.g.swift
android/src/main/kotlin/.../
├── CaptureHelperPlugin.kt # Plugin principal Android
├── services/
│ ├── DocumentScannerService.kt
│ ├── ImageCompressionService.kt
│ ├── PDFCompressionService.kt
│ └── PermissionManager.kt
└── generated/ # Code généré par Pigeon
└── DocumentScannerApi.g.kt
Développement #
Régénérer le code Pigeon #
./scripts/generate_pigeon.sh
ou manuellement :
dart run pigeon --input pigeons/document_scanner_api.dart
Exécuter les tests #
flutter test
Exécuter l'exemple #
cd example
flutter run
Limitations #
iOS #
- Nécessite iOS 13.0 ou supérieur
- La numérisation ne fonctionne pas sur simulateur (nécessite un appareil physique)
- VisionKit requiert l'accès à la caméra
Android #
- Nécessite Android API 21 (5.0) ou supérieur
- Nécessite Google Play Services pour ML Kit
- La numérisation nécessite la permission CAMERA
Qualité de compression recommandée #
| Qualité | Usage recommandé | Taille du fichier |
|---|---|---|
| 85-100 | Impression, archivage | Grande |
| 70-85 | Usage général, web | Moyenne |
| 50-70 | Email, partage | Petite |
| 10-50 | Aperçu, miniatures | Très petite |
📚 Plus d'exemples #
Exemples de code #
Consultez EXAMPLES.md pour des exemples détaillés :
- 📏 Scanner avec limite de poids
- 🔄 Compression en masse
- 📑 Scanner multi-pages
- 🎨 Interface utilisateur complète
- ⚡ Compression en arrière-plan
- Et plus encore !
Application exemple #
Consultez le dossier example pour une application complète avec :
- Page d'accueil avec bouton de scan
- Page de détails avec visualisation d'images
- Slider de qualité de compression
- Affichage des statistiques de compression
Licence #
Ce projet est sous licence MIT.
Auteur #
Author: Alexis Louis Développé avec ❤️ pour faciliter la numérisation de documents dans Flutter.