The DocumentCameraFrame
package simplifies document scanning by providing a customizable camera
interface for capturing and cropping document images. It’s ideal for applications that require
efficient and user-friendly document capture.
- Document Frame: Customizable dimensions for focused document capture.
- Camera Preview: Real-time camera feed for instant feedback.
-
User-Friendly Controls:
- Capture: Take a snapshot of the document.
- Save: Save the captured image.
- Retake: Retake the image if unsatisfactory.
-
Customizable UI:
- Define frame dimensions, button styles, and positions.
- Add optional titles with alignment and padding options.
-
Event Callbacks: Handle events like
onCaptured
,onSaved
, andonRetake
easily.
Add the package to your Flutter project using:
flutter pub add document_camera_frame
Then run:
flutter pub get
Add the following keys to your ios/Runner/Info.plist
file to request camera and microphone
permissions:
<plist version="1.0">
<dict>
<!-- Add the following keys inside the <dict> section -->
<key>NSCameraUsageDescription</key>
<string>We need camera access to capture documents.</string>
<key>NSMicrophoneUsageDescription</key>
<string>We need microphone access for audio-related features.</string>
</dict>
</plist>
- Update the
minSdkVersion
to 21 or higher inandroid/app/build.gradle
:
android {
defaultConfig {
minSdk 21
}
}
- Add these permissions to your
AndroidManifest.xml
file:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<application android:label="MyApp" android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<!-- Activities and other components -->
</application>
</manifest>
Permission errors may occur when initializing the camera. You must handle them appropriately. Below are the possible error codes:
Error Code | Description |
---|---|
CameraAccessDenied |
User denied camera access permission. |
CameraAccessDeniedWithoutPrompt |
iOS only. User previously denied access and needs to enable it manually via Settings. |
CameraAccessRestricted |
iOS only. Camera access is restricted (e.g., parental controls). |
AudioAccessDenied |
User denied microphone access permission. |
AudioAccessDeniedWithoutPrompt |
iOS only. User previously denied microphone access and needs to enable it manually via Settings. |
AudioAccessRestricted |
iOS only. Microphone access is restricted (e.g., parental controls). |
import 'package:document_camera_frame/document_camera_frame.dart';
import 'package:document_camera_frame/document_camera_frame.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: const HomeScreen(),
);
}
}
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Document Capture Frame')),
body: Center(
child: ElevatedButton(
onPressed: () {
// Navigate to the DocumentCameraFrame example screen when the button is pressed
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => const DocumentCameraFrameExample()),
);
},
child: const Text('Start Document Capture'),
),
),
);
}
}
class DocumentCameraFrameExample extends StatelessWidget {
const DocumentCameraFrameExample({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: DocumentCameraFrame(
// Document frame dimensions
frameWidth: 300.0,
frameHeight: 200.0,
// Title displayed at the top
title: const Text(
'Capture Your Document',
style: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
// Show Close button
showCloseButton: true,
// Callback when the document is captured
onCaptured: (imgPath) {
debugPrint('Captured image path: $imgPath');
},
// Callback when the document is saved
onSaved: (imgPath) {
debugPrint('Saved image path: $imgPath');
},
// Callback when the retake button is pressed
onRetake: () {
debugPrint('Retake button pressed');
},
// Optional: Customize Capture button, Save button, etc. if needed
),
);
}
}
Parameter | Type | Description | Required | Default Value |
---|---|---|---|---|
frameWidth |
double |
Width of the document capture frame. | ✅ | — |
frameHeight |
double |
Height of the document capture frame. | ✅ | — |
title |
Widget? |
Widget to display as the screen's title (optional). | ❌ | null |
screenTitleAlignment |
Alignment? |
Alignment of the screen title (optional). | ❌ | Alignment.topCenter |
screenTitlePadding |
EdgeInsets? |
Padding for the screen title (optional). | ❌ | EdgeInsets.zero |
captureButtonText |
String? |
Text for the "Capture" button. | ❌ | "Capture" |
captureButtonTextStyle |
TextStyle? |
Text style for the "Capture" button text (optional) | ❌ | null |
captureInnerCircleRadius |
double? |
Radius of the inner circle of the capture button (optional). | ❌ | 59 |
captureOuterCircleRadius |
double? |
Radius of the outer circle of the capture button (optional). | ❌ | 70 |
captureButtonStyle |
ButtonStyle? |
Style for the "Capture" button (optional). | ❌ | null |
captureButtonAlignment |
Alignment? |
Alignment of the "Capture" button (optional). | ❌ | Alignment.bottomCenter |
captureButtonPadding |
EdgeInsets? |
Padding for the "Capture" button (optional). | ❌ | null |
captureButtonWidth |
double? |
Width for the "Capture" button (optional). | ❌ | null |
captureButtonHeight |
double? |
Height for the "Capture" button (optional). | ❌ | null |
onCaptured |
Function(String) |
Callback triggered when an image is captured. | ✅ | — |
saveButtonText |
String? |
Text for the "Save" button. | ❌ | "Save" |
saveButtonTextStyle |
TextStyle? |
Text style for the "Save" button text (optional). | ❌ | null |
saveButtonStyle |
ButtonStyle? |
Style for the "Save" button (optional). | ❌ | null |
saveButtonAlignment |
Alignment? |
Alignment of the "Save" button (optional). | ❌ | Alignment.bottomRight |
saveButtonPadding |
EdgeInsets? |
Padding for the "Save" button (optional). | ❌ | null |
saveButtonWidth |
double? |
Width for the "Save" button (optional). | ❌ | null |
saveButtonHeight |
double? |
Height for the "Save" button (optional). | ❌ | null |
onSaved |
Function(String) |
Callback triggered when an image is saved. | ✅ | — |
retakeButtonText |
String? |
Text for the "Retake" button. | ❌ | "Retake" |
retakeButtonTextStyle |
TextStyle? |
Text style for the "Retake" button text (optional). | ❌ | null |
retakeButtonStyle |
ButtonStyle? |
Style for the "Retake" button (optional). | ❌ | null |
retakeButtonAlignment |
Alignment? |
Alignment of the "Retake" button (optional). | ❌ | Alignment.bottomLeft |
retakeButtonPadding |
EdgeInsets? |
Padding for the "Retake" button (optional). | ❌ | null |
retakeButtonWidth |
double? |
Width for the "Retake" button (optional). | ❌ | null |
retakeButtonHeight |
double? |
Height for the "Retake" button (optional). | ❌ | null |
onRetake |
VoidCallback? |
Callback triggered when the "Retake" button is pressed. | ❌ | null |
frameBorder |
BoxBorder? |
Border for the displayed frame (optional). | ❌ | null |
capturingAnimationDuration |
Duration? |
Duration for the capturing animation (optional). | ❌ | Duration(milliseconds: 1000) |
capturingAnimationColor |
Color? |
Color for the capturing animation (optional). | ❌ | Colors.black26 |
capturingAnimationCurve |
Curve? |
Curve for the capturing animation (optional). | ❌ | Curves.easeInOut |
outerFrameBorderRadius |
double |
Radius of the outer border of the frame. | ❌ | 12.0 |
innerCornerBroderRadius |
double |
Radius of the inner corners of the frame. | ❌ | 8.0 |
animatedFrameDuration |
Duration |
Duration for the frame animation (optional). | ❌ | Duration(milliseconds: 400) |
animatedFrameCurve |
Curve |
Curve for the frame animation (optional). | ❌ | Curves.easeIn |
bottomFrameContainerChild |
Widget? |
Custom content for the bottom container (optional). | ❌ | null |
showCloseButton |
bool |
Flag to control the visibility of the CloseButton (optional). | ❌ | false |
This project is licensed under the MIT License. See the LICENSE file for details.