docs_auto_sign 0.0.2
docs_auto_sign: ^0.0.2 copied to clipboard
Automatically detect signature fields in a PDF and stamp a PNG signature image onto them.
import 'dart:typed_data';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:file_picker/file_picker.dart';
import 'package:signature/signature.dart';
import 'package:docs_auto_sign/docs_auto_sign.dart';
import 'package:path_provider/path_provider.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Docs Auto Sign Example',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo),
useMaterial3: true,
),
home: const HomeScreen(),
);
}
}
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
File? _pdfFile;
Uint8List? _signatureBytes;
AutoSignResult? _result;
bool _isSigning = false;
final SignatureController _signatureController = SignatureController(
penStrokeWidth: 2,
penColor: Colors.black,
exportBackgroundColor: Colors.white,
);
@override
void dispose() {
_signatureController.dispose();
super.dispose();
}
// Step 1: PDF pick করো
Future<void> _pickPdf() async {
final result = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: ['pdf'],
);
if (result != null && result.files.single.path != null) {
setState(() {
_pdfFile = File(result.files.single.path!);
_result = null;
});
}
}
// Step 2: Signature confirm করো
Future<void> _confirmSignature() async {
if (_signatureController.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Please draw your signature first!')),
);
return;
}
final bytes = await _signatureController.toPngBytes(
width: 400,
height: 200,
);
if (bytes != null) {
setState(() => _signatureBytes = bytes);
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Signature saved! ✅'),
backgroundColor: Colors.green,
),
);
}
}
// Step 3: Sign করো
Future<void> _signDocument() async {
if (_pdfFile == null || _signatureBytes == null) return;
setState(() => _isSigning = true);
try {
final result = await AutoSignService.applySignatureToPdf(
originalPdfFile: _pdfFile!,
signatureBytes: _signatureBytes!,
targetWords: ['signature', 'sign'],
);
// Signed PDF save করো
final dir = await getTemporaryDirectory();
final outFile = File('${dir.path}/signed_output.pdf');
await outFile.writeAsBytes(result.signedPdfBytes);
setState(() {
_result = result;
_isSigning = false;
});
} catch (e) {
setState(() => _isSigning = false);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error: $e'), backgroundColor: Colors.red),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Docs Auto Sign Example'),
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// ── Step 1: PDF Pick ─────────────────────────────────────────
const Text('Step 1: Pick a PDF',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
const SizedBox(height: 8),
SizedBox(
width: double.infinity,
child: ElevatedButton.icon(
onPressed: _pickPdf,
icon: const Icon(Icons.upload_file),
label: const Text('Pick PDF'),
),
),
if (_pdfFile != null) ...[
const SizedBox(height: 8),
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.green[50],
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.green),
),
child: Row(
children: [
const Icon(Icons.check_circle, color: Colors.green),
const SizedBox(width: 8),
Expanded(
child: Text(
_pdfFile!.path.split('/').last,
style: const TextStyle(fontSize: 13),
),
),
],
),
),
],
const SizedBox(height: 24),
// ── Step 2: Draw Signature ───────────────────────────────────
const Text('Step 2: Draw Signature',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
const SizedBox(height: 8),
Container(
height: 200,
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(12),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(12),
child: Signature(
controller: _signatureController,
backgroundColor: Colors.white,
),
),
),
const SizedBox(height: 8),
Row(
children: [
Expanded(
child: OutlinedButton.icon(
onPressed: () => _signatureController.clear(),
icon: const Icon(Icons.clear),
label: const Text('Clear'),
),
),
const SizedBox(width: 12),
Expanded(
child: ElevatedButton.icon(
onPressed: _confirmSignature,
icon: const Icon(Icons.check),
label: const Text('Confirm'),
),
),
],
),
if (_signatureBytes != null) ...[
const SizedBox(height: 8),
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.green[50],
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.green),
),
child: const Row(
children: [
Icon(Icons.check_circle, color: Colors.green),
SizedBox(width: 8),
Text('Signature ready! ✅'),
],
),
),
],
const SizedBox(height: 24),
// ── Step 3: Sign Document ────────────────────────────────────
const Text('Step 3: Sign Document',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
const SizedBox(height: 8),
SizedBox(
width: double.infinity,
height: 52,
child: ElevatedButton.icon(
onPressed: (_pdfFile != null &&
_signatureBytes != null &&
!_isSigning)
? _signDocument
: null,
icon: _isSigning
? const SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(strokeWidth: 2),
)
: const Icon(Icons.draw),
label: Text(_isSigning ? 'Signing...' : 'Sign Document'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.indigo,
foregroundColor: Colors.white,
),
),
),
// ── Result ───────────────────────────────────────────────────
if (_result != null) ...[
const SizedBox(height: 24),
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.indigo[50],
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.indigo),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Row(
children: [
Icon(Icons.check_circle, color: Colors.indigo),
SizedBox(width: 8),
Text('Document Signed Successfully! 🎉',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.indigo)),
],
),
const SizedBox(height: 8),
Text(
'Total signatures added: ${_result!.totalSignaturesAdded}'),
Text('Pages modified: ${_result!.pagesModified}'),
],
),
),
],
],
),
),
);
}
}