Perché uno scanner di documenti?
Molte app moderne - dalle utility per l'ufficio ai gestionali fino alle piattaforme fintech - hanno bisogno di acquisire documenti cartacei: fatture, contratti, ricevute, carte d'identità. Fotografare un foglio con la fotocamera standard produce quasi sempre immagini storte, con bordi tagliati e prospettiva deformata. Uno scanner dedicato risolve il problema rilevando automaticamente i bordi del documento, correggendo la prospettiva e restituendo un'immagine pulita e leggibile.
In questo articolo vedremo come integrare la funzionalità di scansione documenti in Flutter usando il pacchetto cunning_document_scanner, che si appoggia alle API native di Android (ML Kit Document Scanner) e iOS (VisionKit), garantendo un'esperienza fluida e di qualità professionale con poche righe di codice.
Installazione
Aggiungi la dipendenza al tuo pubspec.yaml:
dependencies:
cunning_document_scanner: ^1.2.3
Esegui poi il classico comando:
flutter pub get
Configurazione Android
Il pacchetto richiede un minSdkVersion di almeno 21. Verifica nel file android/app/build.gradle:
defaultConfig {
minSdkVersion 21
}
Lo scanner utilizza il modulo Google Play Services per ML Kit, quindi assicurati che il dispositivo abbia i Google Play Services aggiornati.
Configurazione iOS
Su iOS devi dichiarare il motivo dell'accesso alla fotocamera nel file ios/Runner/Info.plist:
<key>NSCameraUsageDescription</key>
<string>L'app usa la fotocamera per scansionare documenti</string>
Lo scanner richiede iOS 13 o superiore, poiché si basa su VisionKit.
Utilizzo di base
L'API è volutamente minimale. Il metodo principale CunningDocumentScanner.getPictures() apre l'interfaccia nativa di scansione e restituisce una lista di percorsi ai file delle immagini acquisite:
import 'package:cunning_document_scanner/cunning_document_scanner.dart';
Future<List<String>?> scansionaDocumenti() async {
try {
final List<String>? immagini = await CunningDocumentScanner.getPictures(
noOfPages: 5, // numero massimo di pagine acquisibili
isGalleryImportAllowed: true, // consenti import dalla galleria
);
return immagini;
} catch (e) {
debugPrint('Errore durante la scansione: $e');
return null;
}
}
Ogni elemento della lista è il path di un file immagine (JPEG) già ritagliato e corretto prospetticamente dallo scanner nativo.
Un widget completo
Vediamo un esempio pratico che avvia lo scanner e mostra le immagini acquisite in una griglia:
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:cunning_document_scanner/cunning_document_scanner.dart';
class ScannerPage extends StatefulWidget {
const ScannerPage({super.key});
@override
State<ScannerPage> createState() => _ScannerPageState();
}
class _ScannerPageState extends State<ScannerPage> {
List<String> _paths = [];
bool _loading = false;
Future<void> _avviaScansione() async {
setState(() => _loading = true);
try {
final risultato = await CunningDocumentScanner.getPictures(
noOfPages: 10,
isGalleryImportAllowed: true,
);
if (risultato != null) {
setState(() => _paths = risultato);
}
} catch (e) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Errore: $e')),
);
}
} finally {
if (mounted) setState(() => _loading = false);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Scanner documenti')),
floatingActionButton: FloatingActionButton.extended(
onPressed: _loading ? null : _avviaScansione,
icon: const Icon(Icons.document_scanner),
label: const Text('Scansiona'),
),
body: _loading
? const Center(child: CircularProgressIndicator())
: _paths.isEmpty
? const Center(child: Text('Nessun documento acquisito'))
: GridView.builder(
padding: const EdgeInsets.all(8),
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 0.7,
crossAxisSpacing: 8,
mainAxisSpacing: 8,
),
itemCount: _paths.length,
itemBuilder: (context, index) {
return ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Image.file(
File(_paths[index]),
fit: BoxFit.cover,
),
);
},
),
);
}
}
Generare un PDF dalle scansioni
Uno degli usi più comuni è esportare le pagine acquisite in un unico file PDF. Possiamo combinare cunning_document_scanner con il pacchetto pdf:
dependencies:
pdf: ^3.10.8
path_provider: ^2.1.2
Ecco la funzione per assemblare le immagini in un PDF:
import 'dart:io';
import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;
import 'package:path_provider/path_provider.dart';
Future<File> creaPdf(List<String> percorsiImmagini) async {
final pdf = pw.Document();
for (final percorso in percorsiImmagini) {
final bytes = await File(percorso).readAsBytes();
final immagine = pw.MemoryImage(bytes);
pdf.addPage(
pw.Page(
pageFormat: PdfPageFormat.a4,
build: (context) => pw.Center(
child: pw.Image(immagine, fit: pw.BoxFit.contain),
),
),
);
}
final dir = await getApplicationDocumentsDirectory();
final file = File('${dir.path}/documento_scansionato.pdf');
await file.writeAsBytes(await pdf.save());
return file;
}
A questo punto puoi condividere il PDF con share_plus o caricarlo su un server.
Buone pratiche
- Gestisci sempre le eccezioni: l'utente può annullare la scansione, e in tal caso
getPictures()potrebbe lanciare un'eccezione o restituirenull. Prevedi entrambi i casi. - Pulizia dei file temporanei: le immagini vengono salvate nella cache del sistema. Se ne generi molte, valuta di eliminarle dopo l'elaborazione per non riempire lo spazio del dispositivo.
- Controlla i permessi runtime: anche se il pacchetto gestisce l'apertura della fotocamera, su alcuni dispositivi Android conviene verificare i permessi con
permission_handlerper evitare fallimenti silenziosi. - Feedback all'utente: mostra sempre un indicatore di caricamento e messaggi chiari in caso di errore, perché l'apertura dell'interfaccia nativa può richiedere qualche istante.
Conclusioni
Con cunning_document_scanner puoi aggiungere una funzionalità di scansione documenti di livello professionale alla tua app Flutter senza scrivere codice nativo. Il rilevamento automatico dei bordi e la correzione prospettica sono gestiti dalle API native di ML Kit e VisionKit, mentre l'integrazione con il pacchetto pdf ti permette di produrre file pronti da archiviare o condividere. Una combinazione ideale per gestionali, app di produttività e soluzioni documentali.